diff --git a/.cursor/rules/vars-usage.mdc b/.cursor/rules/vars-usage.mdc new file mode 100644 index 00000000..233e0aba --- /dev/null +++ b/.cursor/rules/vars-usage.mdc @@ -0,0 +1,18 @@ +--- +description: Restricts usage of the global Mineflayer `bot` variable to only src/ files; prohibits usage in renderer/. Specifies correct usage of player state and appViewer globals. +globs: src/**/*.ts,renderer/**/*.ts +alwaysApply: false +--- +Ask AI + +- The global variable `bot` refers to the Mineflayer bot instance. +- You may use `bot` directly in any file under the `src/` directory (e.g., `src/mineflayer/playerState.ts`). +- Do **not** use `bot` directly in any file under the `renderer/` directory or its subfolders (e.g., `renderer/viewer/three/worldrendererThree.ts`). +- In renderer code, all bot/player state and events must be accessed via explicit interfaces, state managers, or passed-in objects, never by referencing `bot` directly. +- In renderer code (such as in `WorldRendererThree`), use the `playerState` property (e.g., `worldRenderer.playerState.gameMode`) to access player state. The implementation for `playerState` lives in `src/mineflayer/playerState.ts`. +- In `src/` code, you may use the global variable `appViewer` from `src/appViewer.ts` directly. Do **not** import `appViewer` or use `window.appViewer`; use the global `appViewer` variable as-is. +- Some other global variables that can be used without window prefixes are listed in src/globals.d.ts + +Rationale: This ensures a clean separation between the Mineflayer logic (server-side/game logic) and the renderer (client-side/view logic), making the renderer portable and testable, and maintains proper usage of global state. + +For more general project contributing guides see CONTRIBUTING.md on like how to setup the project. Use pnpm tsc if needed to validate result with typechecking the whole project. 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/.eslintignore b/.eslintignore index 3c3629e6..9aa16166 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,9 @@ node_modules +rsbuild.config.ts +*.module.css.d.ts +*.generated.ts +generated +dist +public +**/*/rsbuildSharedConfig.ts +src/mcDataTypes.ts \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index 98388260..63f6749a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,32 +1,76 @@ { - "extends": "zardoy", + "extends": [ + "zardoy", + "plugin:@stylistic/disable-legacy" + ], "ignorePatterns": [ - "!*.js", - "prismarine-viewer/" + "!*.js" + ], + "plugins": [ + "@stylistic" ], "rules": { - "space-infix-ops": "error", - "no-multi-spaces": "error", - "space-before-function-paren": "error", - "space-in-parens": [ + // style + "@stylistic/space-infix-ops": "error", + "@stylistic/no-multi-spaces": "error", + "@stylistic/no-trailing-spaces": "error", + "@stylistic/space-before-function-paren": "error", + "@stylistic/array-bracket-spacing": "error", + // would be great to have but breaks TS code like (url?) => ... + // "@stylistic/arrow-parens": [ + // "error", + // "as-needed" + // ], + "@stylistic/arrow-spacing": "error", + "@stylistic/block-spacing": "error", + "@typescript-eslint/no-this-alias": "off", + "@stylistic/brace-style": [ + "error", + "1tbs", + { + "allowSingleLine": true + } + ], + // too annoying to be forced to multi-line, probably should be enforced to never + // "@stylistic/comma-dangle": [ + // "error", + // "always-multiline" + // ], + "@stylistic/computed-property-spacing": "error", + "@stylistic/dot-location": [ + "error", + "property" + ], + "@stylistic/eol-last": "error", + "@stylistic/function-call-spacing": "error", + "@stylistic/function-paren-newline": [ + "error", + "consistent" + ], + "@stylistic/generator-star-spacing": "error", + "@stylistic/implicit-arrow-linebreak": "error", + "@stylistic/indent-binary-ops": [ + "error", + 2 + ], + "@stylistic/function-call-argument-newline": [ + "error", + "consistent" + ], + "@stylistic/space-in-parens": [ "error", "never" ], - "object-curly-spacing": [ + "@stylistic/object-curly-spacing": [ "error", "always" ], - "comma-spacing": "error", - "semi": [ + "@stylistic/comma-spacing": "error", + "@stylistic/semi": [ "error", "never" ], - "comma-dangle": [ - "error", - // todo maybe "always-multiline"? - "only-multiline" - ], - "indent": [ + "@stylistic/indent": [ "error", 2, { @@ -36,13 +80,72 @@ ] } ], - "quotes": [ + "@stylistic/quotes": [ "error", "single", { "allowTemplateLiterals": true } ], + "@stylistic/key-spacing": "error", + "@stylistic/keyword-spacing": "error", + // "@stylistic/line-comment-position": "error", // not needed + // "@stylistic/lines-around-comment": "error", // also not sure if needed + // "@stylistic/max-len": "error", // also not sure if needed + // "@stylistic/linebreak-style": "error", // let git decide + "@stylistic/max-statements-per-line": [ + "error", + { + "max": 5 + } + ], + // "@stylistic/member-delimiter-style": "error", + // "@stylistic/multiline-ternary": "error", // not needed + // "@stylistic/newline-per-chained-call": "error", // not sure if needed + "@stylistic/new-parens": "error", + "@typescript-eslint/class-literal-property-style": "off", + "@stylistic/no-confusing-arrow": "error", + "@stylistic/wrap-iife": "error", + "@stylistic/space-before-blocks": "error", + "@stylistic/type-generic-spacing": "error", + "@stylistic/template-tag-spacing": "error", + "@stylistic/template-curly-spacing": "error", + "@stylistic/type-annotation-spacing": "error", + "@stylistic/jsx-child-element-spacing": "error", + // buggy + // "@stylistic/jsx-closing-bracket-location": "error", + // "@stylistic/jsx-closing-tag-location": "error", + "@stylistic/jsx-curly-brace-presence": "error", + "@stylistic/jsx-curly-newline": "error", + "@stylistic/jsx-curly-spacing": "error", + "@stylistic/jsx-equals-spacing": "error", + "@stylistic/jsx-first-prop-new-line": "error", + "@stylistic/jsx-function-call-newline": "error", + "@stylistic/jsx-max-props-per-line": [ + "error", + { + "maximum": 7 + } + ], + "@stylistic/jsx-pascal-case": "error", + "@stylistic/jsx-props-no-multi-spaces": "error", + "@stylistic/jsx-self-closing-comp": "error", + // "@stylistic/jsx-sort-props": [ + // "error", + // { + // "callbacksLast": false, + // "shorthandFirst": true, + // "shorthandLast": false, + // "multiline": "ignore", + // "ignoreCase": true, + // "noSortAlphabetically": true, + // "reservedFirst": [ + // "key", + // "className" + // ], + // "locale": "auto" + // } + // ], // perf "import/no-deprecated": "off", // --- @@ -52,6 +155,7 @@ // intentional: improve readability in some cases "no-else-return": "off", "@typescript-eslint/padding-line-between-statements": "off", + "@typescript-eslint/no-dynamic-delete": "off", "arrow-body-style": "off", "unicorn/prefer-ternary": "off", "unicorn/switch-case-braces": "off", @@ -88,13 +192,32 @@ "@typescript-eslint/no-confusing-void-expression": "off", "unicorn/no-empty-file": "off", "unicorn/prefer-event-target": "off", + "@typescript-eslint/member-ordering": "off", // needs to be fixed actually "complexity": "off", "@typescript-eslint/no-floating-promises": "warn", "no-async-promise-executor": "off", "no-bitwise": "off", "unicorn/filename-case": "off", - "max-depth": "off" + "max-depth": "off", + "unicorn/no-typeof-undefined": "off" }, + "overrides": [ + { + "files": [ + "*.js" + ], + "rules": { + "@stylistic/space-before-function-paren": [ + "error", + { + "anonymous": "always", + "named": "never", + "asyncArrow": "always" + } + ] + } + } + ], "root": true } diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 00000000..e80b7100 --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,59 @@ +name: Benchmark +on: + issue_comment: + types: [created] + push: + branches: + - perf-test +jobs: + deploy: + runs-on: ubuntu-latest + if: >- + (github.event_name == 'push' && github.ref == 'refs/heads/perf-test') || + ( + github.event_name == 'issue_comment' && + github.event.issue.pull_request != '' && + (startsWith(github.event.comment.body, '/benchmark')) + ) + permissions: + pull-requests: write + steps: + - run: lscpu + + - name: Checkout + uses: actions/checkout@v2 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: "pnpm" + - name: Move Cypress to dependencies + run: | + jq '.dependencies.cypress = .optionalDependencies.cypress | del(.optionalDependencies.cypress)' package.json > package.json.tmp + mv package.json.tmp package.json + - run: pnpm install --no-frozen-lockfile + + - run: pnpm build + - run: nohup pnpm prod-start & + + - run: pnpm test:benchmark + id: benchmark + continue-on-error: true + # read benchmark results from stdout + - run: | + if [ -f benchmark.txt ]; then + # Format the benchmark results for GitHub comment + BENCHMARK_RESULT=$(cat benchmark.txt | sed 's/^/- /') + echo "BENCHMARK_RESULT<> $GITHUB_ENV + echo "$BENCHMARK_RESULT" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + else + echo "BENCHMARK_RESULT=Benchmark failed to run or produce results" >> $GITHUB_ENV + fi + + - uses: mshick/add-pr-comment@v2 + with: + allow-repeats: true + message: | + Benchmark result: ${{ env.BENCHMARK_RESULT }} diff --git a/.github/workflows/build-single-file.yml b/.github/workflows/build-single-file.yml new file mode 100644 index 00000000..5f9800db --- /dev/null +++ b/.github/workflows/build-single-file.yml @@ -0,0 +1,33 @@ +name: build-single-file + +on: + workflow_dispatch: + +jobs: + build-and-bundle: + runs-on: ubuntu-latest + permissions: write-all + steps: + - name: Checkout repository + uses: actions/checkout@master + + - uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Install dependencies + run: pnpm install + + - name: Build single-file version - minecraft.html + run: pnpm build-single-file && mv dist/single/index.html minecraft.html + env: + LOCAL_CONFIG_FILE: config.mcraft-only.json + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: minecraft.html + path: minecraft.html diff --git a/.github/workflows/build-zip.yml b/.github/workflows/build-zip.yml new file mode 100644 index 00000000..76ca65ca --- /dev/null +++ b/.github/workflows/build-zip.yml @@ -0,0 +1,45 @@ +name: Make Self Host Zip + +on: + workflow_dispatch: + +jobs: + build-and-bundle: + runs-on: ubuntu-latest + permissions: write-all + steps: + - name: Checkout repository + uses: actions/checkout@master + + - uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Install dependencies + run: pnpm install + + - name: Build project + run: pnpm build + env: + LOCAL_CONFIG_FILE: config.mcraft-only.json + + - name: Bundle server.js + run: | + pnpm esbuild server.js --bundle --platform=node --outfile=bundled-server.js --define:process.env.NODE_ENV="'production'" + + - name: Create distribution package + run: | + mkdir -p package + cp -r dist package/ + cp bundled-server.js package/server.js + cd package + zip -r ../self-host.zip . + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: self-host + path: self-host.zip diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0663fce7..8fc56ea9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,28 +8,170 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@master - - name: Install pnpm - run: npm i -g pnpm@9.0.4 + - name: Setup Java JDK + uses: actions/setup-java@v1.4.3 + with: + java-version: 17 + java-package: jre - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 22 # cache: "pnpm" + - name: Install pnpm + uses: pnpm/action-setup@v4 - run: pnpm install + - run: pnpm build-single-file + - name: Store minecraft.html size + run: | + SIZE_BYTES=$(du -s dist/single/minecraft.html 2>/dev/null | cut -f1) + echo "SIZE_BYTES=$SIZE_BYTES" >> $GITHUB_ENV - run: pnpm check-build + - name: Create zip package for size comparison + run: | + mkdir -p package + cp -r dist package/ + cd package + zip -r ../self-host.zip . + - run: pnpm build-playground + # - run: pnpm build-storybook - run: pnpm test-unit - run: pnpm lint - - run: pnpm tsx scripts/buildNpmReact.ts + + - name: Parse Bundle Stats + run: | + GZIP_BYTES=$(du -s self-host.zip 2>/dev/null | cut -f1) + SIZE=$(echo "scale=2; $SIZE_BYTES/1024/1024" | bc) + GZIP_SIZE=$(echo "scale=2; $GZIP_BYTES/1024/1024" | bc) + echo "{\"total\": ${SIZE}, \"gzipped\": ${GZIP_SIZE}}" > /tmp/bundle-stats.json + + # - name: Compare Bundle Stats + # id: compare + # uses: actions/github-script@v6 + # env: + # GITHUB_TOKEN: ${{ secrets.GIST_TOKEN }} + # with: + # script: | + # const gistId = '${{ secrets.BUNDLE_STATS_GIST_ID }}'; + + # async function getGistContent() { + # const { data } = await github.rest.gists.get({ + # gist_id: gistId, + # headers: { + # authorization: `token ${process.env.GITHUB_TOKEN}` + # } + # }); + # return JSON.parse(data.files['bundle-stats.json'].content || '{}'); + # } + + # const content = await getGistContent(); + # const baseStats = content['${{ github.event.pull_request.base.ref }}']; + # const newStats = require('/tmp/bundle-stats.json'); + + # const comparison = `minecraft.html (normal build gzip)\n${baseStats.total}MB (${baseStats.gzipped}MB compressed) -> ${newStats.total}MB (${newStats.gzipped}MB compressed)`; + # core.setOutput('stats', comparison); + + # - run: pnpm tsx scripts/buildNpmReact.ts - run: nohup pnpm prod-start & - run: nohup pnpm test-mc-server & - uses: cypress-io/github-action@v5 with: install: false - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: failure() 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 }} + path: cypress/screenshots/ + # - run: node scripts/outdatedGitPackages.mjs + # if: ${{ github.event.pull_request.base.ref == 'release' }} + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # - name: Store Bundle Stats + # if: github.event.pull_request.base.ref == 'next' + # uses: actions/github-script@v6 + # env: + # GITHUB_TOKEN: ${{ secrets.GIST_TOKEN }} + # with: + # script: | + # const gistId = '${{ secrets.BUNDLE_STATS_GIST_ID }}'; + + # async function getGistContent() { + # const { data } = await github.rest.gists.get({ + # gist_id: gistId, + # headers: { + # authorization: `token ${process.env.GITHUB_TOKEN}` + # } + # }); + # return JSON.parse(data.files['bundle-stats.json'].content || '{}'); + # } + + # async function updateGistContent(content) { + # await github.rest.gists.update({ + # gist_id: gistId, + # headers: { + # authorization: `token ${process.env.GITHUB_TOKEN}` + # }, + # files: { + # 'bundle-stats.json': { + # content: JSON.stringify(content, null, 2) + # } + # } + # }); + # } + + # const stats = require('/tmp/bundle-stats.json'); + # const content = await getGistContent(); + # content['${{ github.event.pull_request.base.ref }}'] = stats; + # await updateGistContent(content); + + # - name: Update PR Description + # uses: actions/github-script@v6 + # with: + # script: | + # const { data: pr } = await github.rest.pulls.get({ + # owner: context.repo.owner, + # repo: context.repo.repo, + # pull_number: context.issue.number + # }); + + # let body = pr.body || ''; + # const statsMarker = '### Bundle Size'; + # const comparison = '${{ steps.compare.outputs.stats }}'; + + # if (body.includes(statsMarker)) { + # body = body.replace( + # new RegExp(`${statsMarker}[^\n]*\n[^\n]*`), + # `${statsMarker}\n${comparison}` + # ); + # } else { + # body += `\n\n${statsMarker}\n${comparison}`; + # } + + # await github.rest.pulls.update({ + # owner: context.repo.owner, + # repo: context.repo.repo, + # pull_number: context.issue.number, + # body + # }); + # dedupe-check: + # runs-on: ubuntu-latest + # if: github.event.pull_request.head.ref == 'next' + # steps: + # - name: Checkout repository + # uses: actions/checkout@v2 + + # - name: Install pnpm + # run: npm install -g pnpm@9.0.4 + + # - name: Run pnpm dedupe + # run: pnpm dedupe + + # - name: Check for changes + # run: | + # if ! git diff --exit-code --quiet pnpm-lock.yaml; then + # echo "pnpm dedupe introduced changes:" + # git diff --color=always pnpm-lock.yaml + # exit 1 + # else + # echo "No changes detected after pnpm dedupe in pnpm-lock.yaml" + # fi diff --git a/.github/workflows/fix-lint.yml b/.github/workflows/fix-lint.yml new file mode 100644 index 00000000..da2cf87d --- /dev/null +++ b/.github/workflows/fix-lint.yml @@ -0,0 +1,29 @@ +name: Fix Lint Command +on: + issue_comment: + types: [created] +jobs: + deploy: + runs-on: ubuntu-latest + if: >- + github.event.issue.pull_request != '' && + ( + contains(github.event.comment.body, '/fix') + ) + permissions: + pull-requests: write + steps: + - uses: actions/checkout@v2 + with: + ref: refs/pull/${{ github.event.issue.number }}/head + - uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Install pnpm + uses: pnpm/action-setup@v4 + - run: pnpm install + - run: pnpm lint --fix + - name: Push Changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/merge-next.yml b/.github/workflows/merge-next.yml new file mode 100644 index 00000000..ee02789b --- /dev/null +++ b/.github/workflows/merge-next.yml @@ -0,0 +1,28 @@ +name: Update Base Branch Command +on: + issue_comment: + types: [created] +jobs: + deploy: + runs-on: ubuntu-latest + if: >- + github.event.issue.pull_request != '' && + ( + contains(github.event.comment.body, '/update') + ) + permissions: + pull-requests: write + contents: write + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 # Fetch all history so we can merge branches + ref: refs/pull/${{ github.event.issue.number }}/head + - name: Fetch All Branches + run: git fetch --all + # - name: Checkout PR + # run: git checkout ${{ github.event.issue.pull_request.head.ref }} + - name: Merge From Next + run: git merge origin/next --strategy-option=theirs + - name: Push Changes + run: git push diff --git a/.github/workflows/next-deploy.yml b/.github/workflows/next-deploy.yml index e3919625..75b39f6c 100644 --- a/.github/workflows/next-deploy.yml +++ b/.github/workflows/next-deploy.yml @@ -3,6 +3,7 @@ env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} ALIASES: ${{ vars.ALIASES }} + MAIN_MENU_LINKS: ${{ vars.MAIN_MENU_LINKS }} on: push: branches: @@ -15,25 +16,76 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Install pnpm + uses: pnpm/action-setup@v4 - name: Install Global Dependencies - run: npm install --global vercel pnpm@9.0.4 + run: pnpm add -g vercel + - name: Install Dependencies + run: pnpm install - name: Pull Vercel Environment Information run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} - - name: Build Project Artifacts - run: vercel build --token=${{ secrets.VERCEL_TOKEN }} - - run: pnpm build-storybook - - name: Copy playground files - run: node prismarine-viewer/esbuild.mjs && cp prismarine-viewer/public/index.html .vercel/output/static/playground.html && cp prismarine-viewer/public/playground.js .vercel/output/static/playground.js + - name: Write Release Info + run: | + echo "{\"latestTag\": \"$(git rev-parse --short $GITHUB_SHA)\", \"isCommit\": true}" > assets/release.json - name: Download Generated Sounds map run: node scripts/downloadSoundsMap.mjs + - name: Build Project Artifacts + run: vercel build --token=${{ secrets.VERCEL_TOKEN }} + env: + CONFIG_JSON_SOURCE: BUNDLED + LOCAL_CONFIG_FILE: config.mcraft-only.json + - name: Copy playground files + run: | + mkdir -p .vercel/output/static/playground + pnpm build-playground + cp -r renderer/dist/* .vercel/output/static/playground/ - name: Deploy Project Artifacts to Vercel uses: mathiasvr/command-output@v2.0.0 with: run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} id: deploy - - 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 - # with: - # message: | - # Deployed to Vercel Preview: ${{ steps.deploy.outputs.stdout }} + - name: Start servers for testing + run: | + nohup pnpm prod-start & + nohup pnpm test-mc-server & + - name: Run Cypress smoke tests + uses: cypress-io/github-action@v5 + with: + install: false + spec: cypress/e2e/smoke.spec.ts + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: cypress-smoke-test-screenshots + path: cypress/screenshots/ + - name: Set deployment aliases + run: | + for alias in $(echo ${{ secrets.TEST_PREVIEW_DOMAIN }} | tr "," "\n"); do + vercel alias set ${{ steps.deploy.outputs.stdout }} $alias --token=${{ secrets.VERCEL_TOKEN }} --scope=zaro + done + + - name: Create Release Pull Request + uses: actions/github-script@v6 + with: + script: | + const { data: pulls } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + head: `${context.repo.owner}:next`, + base: 'release', + state: 'open' + }); + + if (pulls.length === 0) { + await github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: 'Release', + head: 'next', + base: 'release', + body: 'PR was created automatically by the release workflow, hope you release it as soon as possible!', + }); + } diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 9da50d0a..89fd6698 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -1,4 +1,4 @@ -name: Vercel Deploy Preview +name: Vercel PR Deploy (Preview) env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} @@ -6,57 +6,109 @@ env: on: issue_comment: types: [created] + pull_request_target: jobs: deploy: runs-on: ubuntu-latest - # todo skip already created deploys on that commit if: >- - github.event.issue.pull_request != '' && ( - contains(github.event.comment.body, '/deploy') + ( + github.event_name == 'issue_comment' && + contains(github.event.comment.body, '/deploy') && + github.event.issue.pull_request != null + ) || + ( + github.event_name == 'pull_request_target' && + contains(fromJson(vars.AUTO_DEPLOY_PRS), github.event.pull_request.number) + ) ) permissions: pull-requests: write steps: - - name: Checkout + - name: Checkout Base To Temp uses: actions/checkout@v2 + with: + path: temp-base-repo + - name: Get deployment alias + run: node temp-base-repo/scripts/githubActions.mjs getAlias + id: alias + env: + ALIASES: ${{ env.ALIASES }} + PULL_URL: ${{ github.event.issue.pull_request.url || github.event.pull_request.url }} + - name: Checkout PR (comment) + uses: actions/checkout@v2 + if: github.event_name == 'issue_comment' with: ref: refs/pull/${{ github.event.issue.number }}/head - - run: npm i -g pnpm@9.0.4 + - name: Checkout PR (pull_request) + uses: actions/checkout@v2 + if: github.event_name == 'pull_request_target' + with: + ref: refs/pull/${{ github.event.pull_request.number }}/head + + - name: Install pnpm + uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 22 cache: "pnpm" + - name: Update deployAlwaysUpdate packages + run: | + if [ -f package.json ]; then + PACKAGES=$(node -e "const pkg = require('./package.json'); if (pkg.deployAlwaysUpdate) console.log(pkg.deployAlwaysUpdate.join(' '))") + if [ ! -z "$PACKAGES" ]; then + echo "Updating packages: $PACKAGES" + pnpm up -L $PACKAGES + else + echo "No deployAlwaysUpdate packages found in package.json" + fi + else + echo "package.json not found" + fi - name: Install Global Dependencies - run: npm install --global vercel + run: pnpm add -g vercel - name: Pull Vercel Environment Information run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} - - name: Build Project Artifacts - run: vercel build --token=${{ secrets.VERCEL_TOKEN }} - - run: pnpm build-storybook - - name: Copy playground files - run: node prismarine-viewer/esbuild.mjs && cp prismarine-viewer/public/index.html .vercel/output/static/playground.html && cp prismarine-viewer/public/playground.js .vercel/output/static/playground.js + - name: Write Release Info + run: | + echo "{\"latestTag\": \"$(git rev-parse --short ${{ github.event.pull_request.head.sha }})\", \"isCommit\": true}" > assets/release.json - name: Download Generated Sounds map run: node scripts/downloadSoundsMap.mjs + - name: Build Project Artifacts + run: vercel build --token=${{ secrets.VERCEL_TOKEN }} + env: + CONFIG_JSON_SOURCE: BUNDLED + LOCAL_CONFIG_FILE: config.mcraft-only.json + - name: Copy playground files + run: | + mkdir -p .vercel/output/static/playground + pnpm build-playground + cp -r renderer/dist/* .vercel/output/static/playground/ + - name: Write pr redirect index.html + run: | + mkdir -p .vercel/output/static/pr + echo "" > .vercel/output/static/pr/index.html + - name: Write commit redirect index.html + run: | + mkdir -p .vercel/output/static/commit + echo "" > .vercel/output/static/commit/index.html - name: Deploy Project Artifacts to Vercel uses: mathiasvr/command-output@v2.0.0 with: run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} id: deploy - uses: mshick/add-pr-comment@v2 + # if: github.event_name == 'issue_comment' with: allow-repeats: true message: | Deployed to Vercel Preview: ${{ steps.deploy.outputs.stdout }} - [Playground](${{ steps.deploy.outputs.stdout }}/playground.html) + [Playground](${{ steps.deploy.outputs.stdout }}/playground/) [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.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 + run: | + for alias in $(echo ${{ steps.alias.outputs.alias }} | tr "," "\n"); do + vercel alias set ${{ steps.deploy.outputs.stdout }} $alias --token=${{ secrets.VERCEL_TOKEN }} --scope=zaro + done diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index 18c1a9bf..00000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Deploy to GitHub pages -env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} -on: - push: - branches: [release] -jobs: - build-and-deploy: - runs-on: ubuntu-latest - permissions: write-all - steps: - - name: Checkout repository - uses: actions/checkout@master - - name: Install pnpm - run: npm i -g vercel pnpm@9.0.4 - # - run: pnpm install - # - run: pnpm build - - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - # will install + build to .vercel/output/static - - run: vercel build --token=${{ secrets.VERCEL_TOKEN }} --prod - - run: pnpm build-storybook - - name: Copy playground files - run: node prismarine-viewer/esbuild.mjs && cp prismarine-viewer/public/index.html .vercel/output/static/playground.html && cp prismarine-viewer/public/playground.js .vercel/output/static/playground.js - - name: Download Generated Sounds map - run: node scripts/downloadSoundsMap.mjs - - name: Deploy Project to Vercel - uses: mathiasvr/command-output@v2.0.0 - with: - run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} --prod - id: deploy - - run: | - 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 ${{ steps.release.outputs.tag }} - if: steps.release.outputs.tag - env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..3e8c4136 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,116 @@ +name: Release +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + MAIN_MENU_LINKS: ${{ vars.MAIN_MENU_LINKS }} +on: + push: + branches: [release] +jobs: + build-and-deploy: + runs-on: ubuntu-latest + permissions: write-all + steps: + - name: Checkout repository + uses: actions/checkout@master + - uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Install pnpm + uses: pnpm/action-setup@v4 + - name: Install Global Dependencies + run: pnpm add -g vercel + # - run: pnpm install + # - run: pnpm build + - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} + - run: node scripts/replaceFavicon.mjs ${{ secrets.FAVICON_MAIN }} + # will install + build to .vercel/output/static + - name: Get Release Info + run: pnpx zardoy-release empty --skip-github --output-file assets/release.json + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Download Generated Sounds map + run: node scripts/downloadSoundsMap.mjs + - run: vercel build --token=${{ secrets.VERCEL_TOKEN }} --prod + env: + CONFIG_JSON_SOURCE: BUNDLED + LOCAL_CONFIG_FILE: config.mcraft-only.json + - name: Copy playground files + run: | + mkdir -p .vercel/output/static/playground + pnpm build-playground + cp -r renderer/dist/* .vercel/output/static/playground/ + + # publish to github + - 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 + + # Create CNAME file for custom domain + - name: Create CNAME file + run: echo "github.mcraft.fun" > .vercel/output/static/CNAME + + - name: Deploy to mwc-mcraft-pages repository + uses: peaceiris/actions-gh-pages@v3 + with: + personal_token: ${{ secrets.MCW_MCRAFT_PAGE_DEPLOY_TOKEN }} + external_repository: ${{ github.repository_owner }}/mwc-mcraft-pages + publish_dir: .vercel/output/static + publish_branch: main + destination_dir: docs + force_orphan: true + + - name: Change index.html title + run: | + # change Minecraft Web Client to Minecraft Web Client — Free Online Browser Version + sed -i 's/Minecraft Web Client<\/title>/<title>Minecraft Web Client — Free Online Browser Version<\/title>/' .vercel/output/static/index.html + + - name: Deploy Project to Vercel + uses: mathiasvr/command-output@v2.0.0 + with: + run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} --prod + id: deploy + - name: Get releasing alias + run: node scripts/githubActions.mjs getReleasingAlias + id: alias + - name: Set deployment alias + run: | + for alias in $(echo ${{ steps.alias.outputs.alias }} | tr "," "\n"); do + vercel alias set ${{ steps.deploy.outputs.stdout }} $alias --token=${{ secrets.VERCEL_TOKEN }} --scope=zaro + done + + - name: Build single-file version - minecraft.html + run: pnpm build-single-file && mv dist/single/index.html minecraft.html + - name: Build self-host version + run: pnpm build + - name: Bundle server.js + run: | + pnpm esbuild server.js --bundle --platform=node --outfile=bundled-server.js --define:process.env.NODE_ENV="'production'" + + - name: Create zip package + run: | + mkdir -p package + cp -r dist package/ + cp bundled-server.js package/server.js + cd package + zip -r ../self-host.zip . + + - run: | + pnpx zardoy-release node --footer "This release URL: https://$(echo ${{ steps.alias.outputs.alias }} | cut -d',' -f1) (Vercel URL: ${{ steps.deploy.outputs.stdout }})" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # has possible output: tag + id: release + + # has output + - name: Set publishing config + run: pnpm config set '//registry.npmjs.org/:_authToken' "${NODE_AUTH_TOKEN}" + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + # - run: pnpm tsx scripts/buildNpmReact.ts ${{ steps.release.outputs.tag }} + # if: steps.release.outputs.tag + # env: + # NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 240b751a..33734572 100644 --- a/.gitignore +++ b/.gitignore @@ -10,12 +10,15 @@ localSettings.mjs dist* .DS_Store .idea/ -world +/world data*.json out *.iml .vercel generated storybook-static +server-jar +config.local.json +logs/ src/react/npmReactComponents.ts diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index a8a219f1..05c36eba 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -1,9 +1,10 @@ import React from 'react' -import type { Preview } from "@storybook/react"; +import type { Preview } from "@storybook/react" -import '../src/styles.css' import './storybook.css' +import '../src/styles.css' +import '../src/scaleInterface' const preview: Preview = { decorators: [ @@ -11,7 +12,7 @@ const preview: Preview = { const noScaling = c.parameters.noScaling return <div id={noScaling ? '' : 'ui-root'}> <Story /> - </div>; + </div> }, ], parameters: { @@ -23,6 +24,6 @@ const preview: Preview = { }, }, }, -}; +} -export default preview; +export default preview diff --git a/.vscode/launch.json b/.vscode/launch.json index 6bbd4198..dec88163 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,5 @@ { "configurations": [ - // UPDATED: all configs below are misconfigured and will crash vscode, open dist/index.html and use live preview debug instead // recommended as much faster { // to launch "C:\Program Files\Google\Chrome Beta\Application\chrome.exe" --remote-debugging-port=9222 @@ -29,7 +28,7 @@ "type": "chrome", "name": "Launch Chrome", "request": "launch", - "url": "http://localhost:8080/", + "url": "http://localhost:3000/", "pathMapping": { "/": "${workspaceFolder}/dist" }, @@ -50,7 +49,7 @@ "name": "Attach Firefox", "request": "attach", // comment if using webpack - "url": "http://localhost:8080/", + "url": "http://localhost:3000/", "webRoot": "${workspaceFolder}/", "skipFiles": [ // "<node_internals>/**/*vendors*" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 253b2a52..a5a3482d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,26 +2,84 @@ After forking the repository, run the following commands to get started: -0. Ensure you have [Node.js](https://nodejs.org) and `pnpm` installed. To install pnpm run `npm i -g pnpm@9.0.4`. +0. Ensure you have [Node.js](https://nodejs.org) installed. Enable corepack with `corepack enable` *(1). 1. Install dependencies: `pnpm i` -2. Start the project in development mode: `pnpm start` +2. Start the project in development mode: `pnpm start` or build the project for production: `pnpm build` +3. Read the [Tasks Categories](#tasks-categories) and [Workflow](#workflow) sections below +4. Let us know if you are working on something and be sure to open a PR if you got any changes. Happy coding! + +*(1): If you are getting `Cannot find matching keyid` update corepack to the latest version with `npm i -g corepack`. + +*(2): If still something doesn't work ensure you have the right nodejs version with `node -v` (tested on 22.x) + +<!-- *(3): For GitHub codespaces (cloud ide): Run `pnpm i @rsbuild/core@1.2.4 @rsbuild/plugin-node-polyfill@1.3.0 @rsbuild/plugin-react@1.1.0 @rsbuild/plugin-typed-css-modules@1.0.2` command to avoid crashes because of limited ram --> ## Project Structure +There are 3 main parts of the project: + +### Core (`src`) + +This is the main app source code which reuses all the other parts of the project. + +> The first version used Webpack, then was migrated to Esbuild and now is using Rsbuild! + +- Scripts: + - Start: `pnpm start`, `pnpm dev-rsbuild` (if you don't need proxy server also running) + - Build: `pnpm build` (note that `build` script builds only the core app, not the whole project!) + +Paths: + - `src` - main app source code - `src/react` - React components - almost all UI is in this folder. Almost every component has its base (reused in app and storybook) and `Provider` - which is a component that provides context to its children. Consider looking at DeathScreen component to see how it's used. -- `src/menus` - Old Lit Element GUI. In the process of migration to React. -- `prismarine-viewer` - Improved version of <https://github.com/prismarineJS/prismarine-viewer>. Here is everything related to rendering the game world itself (no ui at all). Two most important parts here are: -- `prismarine-viewer/viewer/lib/worldrenderer.ts` - adding new objects to three.js happens here (sections) -- `prismarine-viewer/viewer/lib/models.ts` - preparing data for rendering (blocks) - happens in worker: out file - `worker.js`, building - `prismarine-viewer/buildWorker.mjs` -- `prismarine-viewer/examples/playground.ts` - Playground (source of <mcraft.fun/playground.html>) Use this for testing render changes. You can also modify playground code. +### Renderer: Playground & Mesher (`renderer`) + +- Playground Scripts: + - Start: `pnpm run-playground` (playground, mesher + server) or `pnpm watch-playground` + - Build: `pnpm build-playground` or `node renderer/esbuild.mjs` + +- Mesher Scripts: + - Start: `pnpm watch-mesher` + - Build: `pnpm build-mesher` + +Paths: + +- `renderer` - Improved and refactored version of <https://github.com/PrismarineJS/prismarine-viewer>. Here is everything related to rendering the game world itself (no ui at all). Two most important parts here are: +- `renderer/viewer/lib/worldrenderer.ts` - adding new objects to three.js happens here (sections) +- `renderer/viewer/lib/models.ts` - preparing data for rendering (blocks) - happens in worker: out file - `worker.js`, building - `renderer/buildWorker.mjs` +- `renderer/playground/playground.ts` - Playground (source of <mcraft.fun/playground.html>) Use this for testing any rendering changes. You can also modify the playground code. + +### Storybook (`.storybook`) + +Storybook is a tool for easier developing and testing React components. +Path of all Storybook stories is `src/react/**/*.stories.tsx`. + +- Scripts: + - Start: `pnpm storybook` + - Build: `pnpm build-storybook` + +## Core-related How different modules are used: - `mineflayer` - provider `bot` variable and as mineflayer states it is a wrapper for the `node-minecraft-protocol` module and is used to connect and interact with real Java Minecraft servers. However not all events & properties are exposed and sometimes you have to use `bot._client.on('packet_name', data => ...)` to handle packets that are not handled via mineflayer API. Also you can use almost any mineflayer plugin. -## Making protocol changes +## Running Main App + Playground + +To start the main web app and playground, run `pnpm run-all`. Note is doesn't start storybook and tests. + +## Cypress Tests (E2E) + +Cypress tests are located in `cypress` folder. To run them, run `pnpm test-mc-server` and then `pnpm test:cypress` when the `pnpm prod-start` is running (or change the port to 3000 to test with the dev server). Usually you don't need to run these until you get issues on the CI. + +## Unit Tests + +There are not many unit tests for now (which we are trying to improve). +Location of unit tests: `**/*.test.ts` files in `src` folder and `renderer` folder. +Start them with `pnpm test-unit`. + +## Making protocol-related changes You can get a description of packets for the latest protocol version from <https://wiki.vg/Protocol> and for previous protocol versions from <https://wiki.vg/Protocol_version_numbers> (look for *Page* links that have *Protocol* in URL). @@ -37,6 +95,100 @@ Also there are [src/generatedClientPackets.ts](src/generatedClientPackets.ts) an - Some data are cached between restarts. If you see something doesn't work after upgrading dependencies, try to clear the by simply removing the `dist` folder. - The same folder `dist` is used for both development and production builds, so be careful when deploying the project. - Use `start-prod` script to start the project in production mode after running the `build` script to build the project. +- If CI is failing on the next branch for some reason, feel free to use the latest commit for release branch. We will update the base branch asap. Please, always make sure to allow maintainers do changes when opening PRs. + +## Tasks Categories + +(most important for now are on top). + +## 1. Client-side Logic (most important right now) + +Everything related to the client side packets. Investigate issues when something goes wrong with some server. It's much easier to work on these types of tasks when you have experience in Java with Minecraft, a deep understanding of the original client, and know how to debug it (which is not hard actually). Right now the client is easily detectable by anti-cheat plugins, and the main goal is to fix it (mostly because of wrong physics implementation). + +Priority tasks: + +- Rewrite or fix the physics logic (Botcraft or Grim can be used as a reference as well) +- Implement basic minecart / boat / horse riding +- Fix auto jump module (false triggers, performance issues) +- Investigate connection issues to some servers +- Setup a platform for automatic cron testing against the latest version of the anti-cheat plugins +- ... + +Goals: + +- Make more servers playable. Right now on hypixel-like servers (servers with minigames), only tnt run (and probably ) is fully playable. + +Notes: + +- You can see the incoming/outgoing packets in the console (F12 in Chrome) by enabling `options.debugLogNotFrequentPackets = true`. However, if you need a FULL log of all packets, you can start recording the packets by going into `Settings` > `Advanced` > `Enable Packets Replay` and then you can download the file and use it to replay the packets. +- You can use mcraft-e2e studio to send the same packets over and over again (which is useful for testing) or use the packets replayer (which is useful for debugging). + +## 2. Three.js Renderer + +Example tasks: + +- Improve / fix entity rendering +- Better update entities on specific packets +- Investigate performance issues under different conditions (instructions provided) +- Work on the playground code + +Goals: + +- Fix a lot of entity rendering issues (including position updates) +- Implement switching camera mode (first person, third person, etc) +- Animated blocks +- Armor rendering +- ... + +Note: + +- It's useful to know how to use helpers & additional cameras (e.g. setScissor) + +## 3. Server-side Logic + +Flying squid fork (space-squid). +Example tasks: + +- Add missing commands (e.g. /scoreboard) +- Basic physics (player fall damage, falling blocks & entities) +- Basic entities AI (spawning, attacking) +- Pvp +- Emit more packets on some specific events (e.g. when a player uses an item) +- Make more maps playable (e.g. fix when something is not implemented in both server and client and blocking map interaction) +- ... + +Long Term Goals: + +- Make most adventure maps playable +- Make a way to complete the game from the scratch (crafting, different dimensions, terrain generation, etc) +- Make bedwars playable! +Most of the tasks are straightforward to implement, just be sure to use a debugger ;). If you feel you are stuck, ask for help on Discord. Absolutely any tests / refactor suggestions are welcome! + +## 4. Frontend + +New React components, improve UI (including mobile support). + +## Workflow + +1. Locate the problem on the public test server & make an easily reproducible environment (you can also use local packets replay server or your custom server setup). Dm me for details on public test server / replay server +2. Debug the code, find an issue in the code, isolate the problem +3. Develop, try to fix and test. Finally we should find a way to fix it. It's ideal to have an automatic test but it's not necessary for now +3. Repeat step 1 to make sure the task is done and the problem is fixed (or the feature is implemented) + +## Updating Dependencies + +1. Use `pnpm update-git-deps` to check and update git dependencies (like mineflayer fork, prismarine packages etc). The script will: + - Show which git dependencies have updates available + - Ask if you want to update them + - Skip dependencies listed in `pnpm.updateConfig.ignoreDependencies` + +2. Update PrismarineJS dependencies to the latest version: `minecraft-data` (be sure to replace the version twice in the package.json), `mineflayer`, `minecraft-protocol`, `prismarine-block`, `prismarine-chunk`, `prismarine-item`, ... + +3. If `minecraft-protocol` patch fails, do this: + 1. Remove the patch from `patchedDependencies` in `package.json` + 2. Run `pnpm patch minecraft-protocol`, open patch directory + 3. Apply the patch manually in this directory: `patch -p1 < minecraft-protocol@<version>.patch` + 4. Run the suggested command from `pnpm patch ...` (previous step) to update the patch ### Would be useful to have diff --git a/Dockerfile b/Dockerfile index aa9eb3dc..22bcfac6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,43 @@ -FROM node:14-alpine +# ---- Build Stage ---- +FROM node:18-alpine AS build # 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 -ENTRYPOINT ["npm", "run", "prod-start"] +# install pnpm with corepack +RUN corepack enable +# Build arguments +ARG DOWNLOAD_SOUNDS=false +ARG DISABLE_SERVICE_WORKER=false +ARG CONFIG_JSON_SOURCE=REMOTE +# TODO need flat --no-root-optional +RUN node ./scripts/dockerPrepare.mjs +RUN pnpm i +# Download sounds if flag is enabled +RUN if [ "$DOWNLOAD_SOUNDS" = "true" ] ; then node scripts/downloadSoundsMap.mjs ; fi + +# TODO for development +# EXPOSE 9090 +# VOLUME /app/src +# VOLUME /app/renderer +# ENTRYPOINT ["pnpm", "run", "run-all"] + +# only for prod +RUN DISABLE_SERVICE_WORKER=$DISABLE_SERVICE_WORKER \ + CONFIG_JSON_SOURCE=$CONFIG_JSON_SOURCE \ + 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@10.8.0 +RUN npm init -yp +RUN pnpm i express github:zardoy/prismarinejs-net-browserify compression cors +EXPOSE 8080 +VOLUME /app/public +ENTRYPOINT ["node", "server.js", "--prod"] 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 689250ce..018784e3 100644 --- a/README.MD +++ b/README.MD @@ -2,31 +2,65 @@ ![banner](./docs-assets/banner.jpg) -A true Minecraft client running in your browser! A port of the original game to the web, written in JavaScript using modern web technologies. +Minecraft **clone** rewritten in TypeScript using the best modern web technologies. Minecraft vanilla-compatible client and integrated server packaged into a single web app. -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 default (`develop`) branch is deployed to [s.mcraft.fun](https://s.mcraft.fun/) and [s.pcm.gg](https://s.pcm.gg/) - so it's usually newer, but might be less stable. -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. +> For Turkey/Russia use [ru.mcraft.fun](https://ru.mcraft.fun/) (since Cloudflare is blocked) + +Don't confuse with [Eaglercraft](https://git.eaglercraft.rip/eaglercraft/eaglercraft-1.8) which is a REAL vanilla Minecraft Java edition port to the web (but with its own limitations). Eaglercraft is a fully playable solution, meanwhile this project is aimed for *device-compatiiblity* and better performance so it feels portable, flexible and lightweight. It's also a very strong example on how to build true HTML games for the web at scale entirely with the JS ecosystem. Have fun! + +For building the project yourself / contributing, see [Development, Debugging & Contributing](#development-debugging--contributing). For reference at what and how web technologies / frameworks are used, see [TECH.md](./TECH.md) (also for comparison with Eaglercraft). + +> **Note**: You can deploy it on your own server in less than a minute using a one-liner script from [Minecraft Everywhere repo](https://github.com/zardoy/minecraft-everywhere) ### Big Features +- Official Mineflayer [plugin integration](https://github.com/zardoy/mcraft-fun-mineflayer-plugin)! View / Control your bot remotely. - 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) +- Integrated JS server clone capable of opening Java world saves in any way (folders, zip, web chunks streaming, etc) - Singleplayer mode with simple world generations! - Works offline -- Play with friends over internet! (P2P is powered by Peer.js discovery servers) - First-class touch (mobile) & controller support -- Resource pack support +- First-class keybindings configuration +- Advanced Resource pack support: Custom GUI, all textures. Server resource packs are supported with proper CORS configuration. +- Builtin JEI with recipes & descriptions for almost every item (JEI is creative inventory replacement) +- Custom protocol channel extensions (eg for custom block models in the world) +- Play with friends over internet! (P2P is powered by Peer.js discovery servers) +- ~~Google Drive support for reading / saving worlds back to the cloud~~ +- Support for custom rendering 3D engines. Modular architecture. - 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) +All components that are in [Storybook](https://minimap.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 - Controls -> **Touch Controls Type** -> **Joystick** - Controls -> **Auto Full Screen** -> **On** - To avoid ctrl+w issue -- Interface -> **Chat Select** -> **On** - To select chat messages +- Interface -> **Enable Minimap** -> **Always** - To enable useful minimap (why not?) +- Controls -> **Raw Input** -> **On** - This will make the controls more precise (UPD: already enabled by default) +- Interface -> **Chat Select** -> **On** - To select chat messages (UPD: already enabled by default) + +### Browser Notes + +This project is tested with BrowserStack. Special thanks to [BrowserStack](https://www.browserstack.com/) for providing testing infrastructure! + +Howerver, it's known that these browsers have issues: + +**Opera Mini**: Disable *mouse gestures* in browsre settings to avoid opening new tab on right click hold + +**Vivaldi**: Disable Controls -> *Raw Input* in game settings if experiencing issues + +### Versions Support + +Server versions 1.8 - 1.21.5 are supported. +First class versions (most of the features are tested on these versions): + +- 1.19.4 +- 1.21.4 + +Versions below 1.13 are not tested currently and may not work correctly. ### World Loading @@ -36,12 +70,37 @@ Whatever offline mode you used (zip, folder, just single player), you can always ![docs-assets/singleplayer-future-city-1-10-2.jpg](./docs-assets/singleplayer-future-city-1-10-2.jpg) -### Servers +### Servers & Proxy -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. -MS account authentication will be supported soon. +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. Or you can deploy it to the cloud service: + +[![Deploy to Koyeb](https://www.koyeb.com/static/images/deploy/button.svg)](https://app.koyeb.com/deploy?name=minecraft-web-client&type=git&repository=zardoy%2Fminecraft-web-client&branch=next&builder=dockerfile&env%5B%5D=&ports=8080%3Bhttp%3B%2F) + +> **Note**: If you want to make **your own** Minecraft server accessible to web clients (without our proxies), you can use [mwc-proxy](https://github.com/zardoy/mwc-proxy) - a lightweight JS WebSocket proxy that runs on the same server as your Minecraft server, allowing players to connect directly via `wss://play.example.com`. `?client_mcraft` is added to the URL, so the proxy will know that it's this client. + +Proxy servers are used to connect to Minecraft servers which use TCP protocol. When you connect connect to a server with a proxy, websocket connection is created between you (browser client) and the proxy server located in Europe, then the proxy connects to the Minecraft server and sends the data to the client (you) without any packet deserialization to avoid any additional delays. That said all the Minecraft protocol packets are processed by the client, right in your browser. + +```mermaid +graph LR + A[Web App - Client] --> C[Proxy Server] + C --> B[Minecraft Server] + style A fill:#f9d,stroke:#333,stroke-width:2px + style B fill:#fc0,stroke:#333,stroke-width:2px + style C fill:#fff,stroke:#333,stroke-width:2px +``` + +So if the server is located in Europe and you are connecting from Europe, you will have ~40ms ping (~180ms with residential proxy version), however if you are in the US and connecting to the server located in US, you will have >200ms ping, which is the worst case scenario. + +Again, the proxy server is not a part of the client, it is a separate service that you can host yourself. + +### 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 @@ -52,42 +111,37 @@ MS account authentication will be supported soon. - Supports resource packs - Doesn't support occlusion culling -<!-- TODO proxy server communication graph --> - -### 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.<setting_name> = <value>`. ### Console -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). +To open the console, press `F12`, or if you are on mobile, you can type `#dev` 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 & Contributing -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)). +There is world renderer playground ([link](https://mcon.vercel.app/playground/)). -However, there are many things that can be done in online version. You can access some global variables in the console and useful examples: +However, there are many things that can be done in online production version (like debugging actual source code). Also you can access some global variables in the console and there are a few useful examples: -- `localStorage.debug = '*'` - Enables all debug messages! Warning: this will start all packets spam. +- If you type `debugToggle`, press enter in console - It will enables all debug messages! Warning: this will start all packets spam. Instead I recommend setting `options.debugLogNotFrequentPackets`. Also you can use `debugTopPackets` (with JSON.stringify) to see what packets were received/sent by name - `bot` - Mineflayer bot instance. See Mineflayer documentation for more. -- `viewer` - Three.js viewer instance, basically does all the rendering. -- `viewer.world.sectionObjects` - Object with all active chunk sections (geometries) in the world. Each chunk section is a Three.js mesh or group. +- `world` - Three.js world instance, basically does all the rendering (part of renderer backend). +- `world.sectionObjects` - Object with all active chunk sections (geometries) in the world. Each chunk section is a Three.js mesh or group. - `debugSceneChunks` - The same as above, but relative to current bot position (e.g. 0,0 is the current chunk). - `debugChangedOptions` - See what options are changed. Don't change options here. - `localServer`/`server` - Only for singleplayer mode/host. Flying Squid server instance, see it's documentation for more. - `localServer.overworld.storageProvider.regions` - See ALL LOADED region files with all raw data. +- `localServer.levelData.LevelName = 'test'; localServer.writeLevelDat()` - Change name of the world - `nbt.simplify(someNbt)` - Simplifies nbt data, so it's easier to read. -The most useful thing in devtools is the watch expression. You can add any expression there and it will be re-evaluated in real time. For example, you can add `viewer.camera.position` to see the camera position and so on. +The most useful thing in devtools is the watch expression. You can add any expression there and it will be re-evaluated in real time. For example, you can add `world.getCameraPosition()` to see the camera position and so on. <img src="./docs-assets/watch-expr.png" alt="Watch expression" width="480"/> @@ -106,19 +160,62 @@ 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=<server_address>` - Display connect screen to the server on load -- `?username=<username>` - Set the username for server -- `?proxy=<proxy_address>` - Set the proxy server address to use for server -- `?version=<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. -<!-- - `?password=<password>` - Set the password on load --> -- `?loadSave=<save_name>` - 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 +There are some parameters you can set in the url to archive some specific behaviors: -- `?map=<map_url>` - Load the map from ZIP. You can use any url, but it must be CORS enabled. -- `?setting=<setting_name>:<setting_value>` - 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=<setting_name>:<setting_value>`** - Set and lock the setting on load. You can set multiple settings by separating them with `&` e.g. `?setting=autoParkour:true&setting=renderDistance:4` +- `?modal=<modal>` - Open specific modal on page load eg `keybindings`. Very useful on UI changes testing during dev. For path use `,` as separator. To get currently opened modal type this in the console: `activeModalStack.at(-1).reactType` +- `?replayFileUrl=<url>` - Load and start a packet replay session from a URL with a integrated server. For debugging / previewing recorded sessions. The file must be CORS enabled. + +Server specific: + +- `?ip=<server_address>` - Display connect screen to the server on load with predefined server ip. `:<port>` is optional and can be added to the ip. +- `?name=<name>` - Set the server name for saving to the server list +- `?version=<version>` - Set the version for the server +- `?proxy=<proxy_address>` - Set the proxy server address to use for the server +- `?username=<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. +- `?autoConnect=true` - Only works then `ip` and `version` parameters are set and `allowAutoConnect` is `true` in config.json! Directly connects to the specified server. Useful for integrates iframes. +- `?serversList=<list_or_url>` - `<list_or_url>` can be a list of servers in the format `ip:version,ip` or a url to a json file with the same format (array) or a txt file with line-delimited list of server IPs. +- `?addPing=<ping>` - Add a latency to both sides of the connection. Useful for testing ping issues. For example `?addPing=100` will add 200ms to your ping. + +Single player specific: + +- `?loadSave=<save_name>` - Load the save on load with the specified folder name (not title) +- `?singleplayer=1` or `?sp=1` - Create empty world on load. Nothing will be saved +- `?version=<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. +- `?serverSetting=<key>:<value>` - Set local server [options](https://github.com/zardoy/space-squid/tree/everything/src/modules.ts#L51). For example `?serverSetting=noInitialChunksSend:true` will disable initial chunks loading on the loading screen. +- `?map=<map_url>` - Load the map from ZIP. You can use any url, but it must be **CORS enabled**. +- `?mapDir=<index_file_url>` - Load the map from a file descriptor. It's recommended and the fastest way to load world but requires additional setup. The file must be in the following format: + +```json +{ + "baseUrl": "<url>", + "index": { + "level.dat": null, + "region": { + "r.-1.-1.mca": null, + "r.-1.0.mca": null, + "r.0.-1.mca": null, + "r.0.0.mca": null, + } + } +} +``` + +Note that `mapDir` also accepts base64 encoded JSON like so: +`?mapDir=data:application/json;base64,...` where `...` is the base64 encoded JSON of the index file. +In this case you must use `?mapDirBaseUrl` to specify the base URL to fetch the files from index. + +- `?mapDirBaseUrl` - See above. + +Only during development: + +- `?reconnect=true` - Reconnect to the server on page reloads. Very useful on server testing. + +<!-- - `?mapDirGuess=<base_url>` - Load the map from the provided URL and paths will be guessed with a few additional fetch requests. --> ### Notable Things that Power this Project @@ -130,6 +227,12 @@ 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) +- [https://m.eaglercraft.com/](EaglerCraft) - Eaglercraft runnable on mobile (real Minecraft in the browser) +- [js-minecraft](https://github.com/LabyStudio/js-minecraft) - An insanely well done clone from the graphical side that inspired many features here diff --git a/README.NPM.MD b/README.NPM.MD index 24c90bc9..dc2c7c72 100644 --- a/README.NPM.MD +++ b/README.NPM.MD @@ -1,9 +1,13 @@ # Minecraft React +Minecraft UI components for React extracted from [mcraft.fun](https://mcraft.fun) project. + ```bash -yarn add minecraft-react +pnpm i minecraft-react ``` +![demo](./docs-assets/npm-banner.jpeg) + ## Usage ```jsx @@ -24,7 +28,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/TECH.md b/TECH.md new file mode 100644 index 00000000..2d15993a --- /dev/null +++ b/TECH.md @@ -0,0 +1,58 @@ +### Eaglercraft Comparison + +This project uses proxies so you can connect to almost any vanilla server. Though proxies have some limitations such as increased latency and servers will complain about using VPN (though we have a workaround for that, but ping will be much higher). +This client generally has better performance but some features reproduction might be inaccurate eg its less stable and more buggy in some cases. + +| Feature | This project | Eaglercraft | Description | +| --------------------------------- | ----------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| General | | | | +| Mobile Support (touch) | ✅(+) | ✅ | | +| Gamepad Support | ✅ | ❌ | | +| A11Y | ✅ | ❌ | We have DOM for almost all UI so your extensions and other browser features will work natively like on any other web page (but maybe it's not needed) | +| Game Features | | | | +| Servers Support (quality) | ❌(+) | ✅ | Eaglercraft is vanilla Minecraft, while this project tries to emulate original game behavior at protocol level (Mineflayer is used) | +| Servers Support (any version, ip) | ✅ | ❌ | We support almost all Minecraft versions, only important if you connect to a server where you need new content like blocks or if you play with friends. And you can connect to almost any server using proxy servers! | +| Servers Support (online mode) | ✅ | ❌ | Join to online servers like Hypixel using your Microsoft account without additional proxies | +| Singleplayer Survival Features | ❌ | ✅ | Just like Eaglercraft this project can generate and save worlds, but generator is simple and only a few survival features are supported (look here for [supported features list](https://github.com/zardoy/space-squid)) | +| Singleplayer Maps | ✅ | ✅ | We support any version, but adventure maps won't work, but simple parkour and build maps might be interesting to explore... | +| Singleplayer Maps World Streaming | ✅ | ❌ | Thanks to Browserfs, saves can be loaded to local singleplayer server using multiple ways: from local folder, server directory (not zip), dropbox or other cloud *backend* etc... | +| P2P Multiplayer | ✅ | ✅ | A way to connect to other browser running the project. But it's almost useless here since many survival features are not implemented. Maybe only to build / explore maps together... | +| Voice Chat | ❌(+) | ✅ | Eaglercraft has custom WebRTC voice chat implementation, though it could also be easily implemented there | +| Online Servers | ✅ | ❌ | We have custom implementation (including integration on proxy side) for joining to servers | +| Plugin Features | ✅ | ❌ | We have Mineflayer plugins support, like Auto Jump & Auto Parkour was added here that way | +| Direct Connection | ✅ | ✅ | We have DOM for almost all UI so your extensions and other browser features will work natively like on any other web page | +| Moding | ✅(own js mods) | ❌ | This project will support mods for singleplayer. In theory its possible to implement support for modded servers on protocol level (including all needed mods) | +| Video Recording | ❌ | ✅ | Doesn't feel needed | +| Metaverse Features | ✅(50%) | ❌ | We have videos / images support inside world, but not iframes (custom protocol channel) | +| Sounds | ✅ | ✅ | | +| Resource Packs | ✅(+extras) | ✅ | This project has very limited support for them (only textures images are loadable for now) | +| Assets Compressing & Splitting | ✅ | ❌ | We have advanced Minecraft data processing and good code chunk splitting so the web app will open much faster and use less memory | +| Graphics | | | | +| Fancy Graphics | ❌ | ✅ | While Eaglercraft has top-level shaders we don't even support lighting | +| Fast & Efficient Graphics | ❌(+) | ❌ | Feels like no one needs to have 64 rendering distance work smoothly | +| VR | ✅(-) | ❌ | Feels like not needed feature. UI is missing in this project since DOM can't be rendered in VR so Eaglercraft could be better in that aspect | +| AR | ❌ | ❌ | Would be the most useless feature | +| Minimap & Waypoints | ✅(-) | ❌ | We have buggy minimap, which can be enabled in settings and full map is opened by pressing `M` key | + +Features available to only this project: + +- CSS & JS Customization +- JS Real Time Debugging & Console Scripting (eg Devtools) + +### Tech Stack + +Bundler: Rsbuild! +UI: powered by React and css modules. Storybook helps with UI development. + +### Rare WEB Features + +There are a number of web features that are not commonly used but you might be interested in them if you decide to build your own game in the web. + +TODO + +| API | Usage & Description | +| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | +| `Crypto` API | Used to make chat features work when joining online servers with authentication. | +| `requestPointerLock({ unadjustedMovement: true })` API | Required for games. Disables system mouse acceleration (important for Mac users). Aka mouse raw input | +| `navigator.keyboard.lock()` | (only in Chromium browsers) When entering fullscreen it allows to use any key combination like ctrl+w in the game | +| `navigator.keyboard.getLayoutMap()` | (only in Chromium browsers) To display the right keyboard symbol for the key keybinding on different keyboard layouts (e.g. QWERTY vs AZERTY) | diff --git a/assets/extra-textures/background/panorama_0.png b/assets/background/panorama_0.png similarity index 100% rename from assets/extra-textures/background/panorama_0.png rename to assets/background/panorama_0.png diff --git a/assets/extra-textures/background/panorama_1.png b/assets/background/panorama_1.png similarity index 100% rename from assets/extra-textures/background/panorama_1.png rename to assets/background/panorama_1.png diff --git a/assets/extra-textures/background/panorama_2.png b/assets/background/panorama_2.png similarity index 100% rename from assets/extra-textures/background/panorama_2.png rename to assets/background/panorama_2.png diff --git a/assets/extra-textures/background/panorama_3.png b/assets/background/panorama_3.png similarity index 100% rename from assets/extra-textures/background/panorama_3.png rename to assets/background/panorama_3.png diff --git a/assets/extra-textures/background/panorama_4.png b/assets/background/panorama_4.png similarity index 100% rename from assets/extra-textures/background/panorama_4.png rename to assets/background/panorama_4.png diff --git a/assets/extra-textures/background/panorama_5.png b/assets/background/panorama_5.png similarity index 100% rename from assets/extra-textures/background/panorama_5.png rename to assets/background/panorama_5.png diff --git a/assets/config.html b/assets/config.html new file mode 100644 index 00000000..9bd2dd8e --- /dev/null +++ b/assets/config.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Configure client + + + +
+ + + + + +
+ + + diff --git a/assets/customTextures/readme.md b/assets/customTextures/readme.md new file mode 100644 index 00000000..e2a78c20 --- /dev/null +++ b/assets/customTextures/readme.md @@ -0,0 +1,2 @@ +here you can place custom textures for bundled files (blocks/items) e.g. blocks/stone.png +get file names from here (blocks/items) https://zardoy.github.io/mc-assets/ diff --git a/assets/debug-inputs.html b/assets/debug-inputs.html new file mode 100644 index 00000000..584fe4d7 --- /dev/null +++ b/assets/debug-inputs.html @@ -0,0 +1,237 @@ + + + + + + Web Input Debugger + + + +
+ +
+ +
+
W
+
A
+
S
+
D
+
+ +
+
Ctrl
+
+ +
+
Space
+
+ + + + diff --git a/assets/destroy_stage_0.png b/assets/destroy_stage_0.png new file mode 100644 index 00000000..f65b7ede Binary files /dev/null and b/assets/destroy_stage_0.png differ diff --git a/assets/destroy_stage_1.png b/assets/destroy_stage_1.png new file mode 100644 index 00000000..7c915961 Binary files /dev/null and b/assets/destroy_stage_1.png differ diff --git a/assets/destroy_stage_2.png b/assets/destroy_stage_2.png new file mode 100644 index 00000000..dadd6b05 Binary files /dev/null and b/assets/destroy_stage_2.png differ diff --git a/assets/destroy_stage_3.png b/assets/destroy_stage_3.png new file mode 100644 index 00000000..52a40b65 Binary files /dev/null and b/assets/destroy_stage_3.png differ diff --git a/assets/destroy_stage_4.png b/assets/destroy_stage_4.png new file mode 100644 index 00000000..e37c88a2 Binary files /dev/null and b/assets/destroy_stage_4.png differ diff --git a/assets/destroy_stage_5.png b/assets/destroy_stage_5.png new file mode 100644 index 00000000..9590d2f7 Binary files /dev/null and b/assets/destroy_stage_5.png differ diff --git a/assets/destroy_stage_6.png b/assets/destroy_stage_6.png new file mode 100644 index 00000000..fb00ade5 Binary files /dev/null and b/assets/destroy_stage_6.png differ diff --git a/assets/destroy_stage_7.png b/assets/destroy_stage_7.png new file mode 100644 index 00000000..0b40c789 Binary files /dev/null and b/assets/destroy_stage_7.png differ diff --git a/assets/destroy_stage_8.png b/assets/destroy_stage_8.png new file mode 100644 index 00000000..c0bf1dec Binary files /dev/null and b/assets/destroy_stage_8.png differ diff --git a/assets/destroy_stage_9.png b/assets/destroy_stage_9.png new file mode 100644 index 00000000..e3185f82 Binary files /dev/null and b/assets/destroy_stage_9.png differ diff --git a/assets/extra-textures/edition.png b/assets/edition.png similarity index 100% rename from assets/extra-textures/edition.png rename to assets/edition.png diff --git a/assets/extra-textures/loading.png b/assets/extra-textures/loading.png deleted file mode 100644 index 4f6a121a..00000000 Binary files a/assets/extra-textures/loading.png and /dev/null differ diff --git a/assets/favicon.png b/assets/favicon.png index 4f0db721..046cacd0 100644 Binary files a/assets/favicon.png and b/assets/favicon.png differ diff --git a/assets/extra-textures/gui.png b/assets/gui.png similarity index 100% rename from assets/extra-textures/gui.png rename to assets/gui.png diff --git a/assets/invsprite.png b/assets/invsprite.png deleted file mode 100644 index d3022e5e..00000000 Binary files a/assets/invsprite.png and /dev/null differ diff --git a/assets/manifest.json b/assets/manifest.json index 9ec96f08..4310ae7f 100644 --- a/assets/manifest.json +++ b/assets/manifest.json @@ -1,6 +1,6 @@ { - "name": "Prismarine Web Client", - "short_name": "Prismarine Web Client", + "name": "Minecraft Web Client", + "short_name": "Minecraft Web Client", "scope": "./", "start_url": "./", "icons": [ diff --git a/assets/playground.html b/assets/playground.html new file mode 100644 index 00000000..8c394f91 --- /dev/null +++ b/assets/playground.html @@ -0,0 +1,4 @@ + + diff --git a/config.json b/config.json index 1bbbfd47..2bfa9cfe 100644 --- a/config.json +++ b/config.json @@ -1,23 +1,80 @@ { "version": 1, "defaultHost": "", - "defaultProxy": "proxy.mcraft.fun", + "defaultProxy": "https://proxy.mcraft.fun", "mapsProvider": "https://maps.mcraft.fun/", + "skinTexturesProxy": "", + "peerJsServer": "", + "peerJsServerFallback": "https://p2p.mcraft.fun", "promoteServers": [ + { + "ip": "wss://play.mcraft.fun" + }, + { + "ip": "wss://play.webmc.fun", + "name": "WebMC" + }, + { + "ip": "wss://ws.fuchsmc.net" + }, + { + "ip": "wss://play2.mcraft.fun" + }, + { + "ip": "wss://play-creative.mcraft.fun", + "description": "Might be available soon, stay tuned!" + }, { "ip": "kaboom.pw", - "version": "1.18.2", - "description": "Chaos and destruction server. Free for everyone." + "version": "1.20.3", + "description": "Very nice a polite server. Must try for everyone!" + } + ], + "rightSideText": "A Minecraft client clone in the browser!", + "splashText": "The sunset is coming!", + "splashTextFallback": "Welcome!", + "pauseLinks": [ + [ + { + "type": "github" + }, + { + "type": "discord" + } + ] + ], + "defaultUsername": "mcrafter{0-9999}", + "mobileButtons": [ + { + "action": "general.drop", + "actionHold": "general.dropStack", + "label": "Q" }, { - "ip": "go.mineberry.org", - "version": "1.18.2", - "description": "One of the best servers here. Join now!" + "action": "general.selectItem", + "actionHold": "", + "label": "S" }, { - "ip": "play.minemalia.com", - "version": "1.18.2", - "description": "Only login with existing accounts." + "action": "general.debugOverlay", + "actionHold": "general.debugOverlayHelpMenu", + "label": "F3" + }, + { + "action": "general.playersList", + "actionHold": "", + "icon": "pixelarticons:users", + "label": "TAB" + }, + { + "action": "general.chat", + "actionHold": "", + "label": "" + }, + { + "action": "ui.pauseMenu", + "actionHold": "", + "label": "" } ] } diff --git a/config.mcraft-only.json b/config.mcraft-only.json new file mode 100644 index 00000000..52a3aa2c --- /dev/null +++ b/config.mcraft-only.json @@ -0,0 +1,5 @@ +{ + "alwaysReconnectButton": true, + "reportBugButtonWithReconnect": true, + "allowAutoConnect": true +} diff --git a/cypress.config.ts b/cypress.config.ts index f9bd9478..3bf2c720 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -1,8 +1,11 @@ import { defineConfig } from 'cypress' +const isPerformanceTest = process.env.PERFORMANCE_TEST === 'true' + export default defineConfig({ video: false, chromeWebSecurity: false, + screenshotOnRunFailure: true, // Enable screenshots on test failures e2e: { // We've imported your old cypress plugins here. // You may want to clean this up later by importing these. @@ -31,7 +34,7 @@ export default defineConfig({ return require('./cypress/plugins/index.js')(on, config) }, baseUrl: 'http://localhost:8080', - specPattern: 'cypress/e2e/**/*.spec.ts', + specPattern: !isPerformanceTest ? 'cypress/e2e/smoke.spec.ts' : 'cypress/e2e/rendering_performance.spec.ts', excludeSpecPattern: ['**/__snapshots__/*', '**/__image_snapshots__/*'], }, }) diff --git a/cypress/e2e/index.spec.ts b/cypress/e2e/index.spec.ts deleted file mode 100644 index 05b50211..00000000 --- a/cypress/e2e/index.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -/// -import { setOptions, cleanVisit, visit } from './shared' - -// todo use ssl - -const compareRenderedFlatWorld = () => { - // wait for render - // cy.wait(6000) - // cy.get('body').toMatchImageSnapshot({ - // name: 'superflat-world', - // }) -} - -const testWorldLoad = () => { - cy.document().then({ timeout: 20_000 }, doc => { - return new Cypress.Promise(resolve => { - doc.addEventListener('cypress-world-ready', resolve) - }) - }).then(() => { - compareRenderedFlatWorld() - }) -} - -it('Loads & renders singleplayer', () => { - cleanVisit('/?singleplayer=1') - setOptions({ - localServerOptions: { - generation: { - name: 'superflat', - // eslint-disable-next-line unicorn/numeric-separators-style - options: { seed: 250869072 } - }, - }, - renderDistance: 2 - }) - testWorldLoad() -}) - -it('Joins to server', () => { - visit('/?ip=localhost&version=1.16.1') - window.localStorage.version = '' - // todo replace with data-test - // 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"]').click({ shiftKey: true }) - cy.get('input[type="file"]').selectFile('cypress/superflat.zip', { force: true }) - testWorldLoad() -}) diff --git a/cypress/e2e/rendering_performance.spec.ts b/cypress/e2e/rendering_performance.spec.ts new file mode 100644 index 00000000..2ca85329 --- /dev/null +++ b/cypress/e2e/rendering_performance.spec.ts @@ -0,0 +1,32 @@ +/// +import { BenchmarkAdapterInfo, getAllInfoLines } from '../../src/benchmarkAdapter' +import { cleanVisit } from './shared' + +it('Benchmark rendering performance', () => { + cleanVisit('/?openBenchmark=true&renderDistance=5') + // wait for render end event + return cy.document().then({ timeout: 180_000 }, doc => { + return new Cypress.Promise(resolve => { + cy.log('Waiting for world to load') + doc.addEventListener('cypress-world-ready', resolve) + }).then(() => { + cy.log('World loaded') + }) + }).then(() => { + cy.window().then(win => { + const adapter = win.benchmarkAdapter as BenchmarkAdapterInfo + + const messages = getAllInfoLines(adapter) + // wait for 10 seconds + cy.wait(10_000) + const messages2 = getAllInfoLines(adapter, true) + for (const message of messages) { + cy.log(message) + } + for (const message of messages2) { + cy.log(message) + } + cy.writeFile('benchmark.txt', [...messages, ...messages2].join('\n')) + }) + }) +}) 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/e2e/smoke.spec.ts b/cypress/e2e/smoke.spec.ts new file mode 100644 index 00000000..ae110155 --- /dev/null +++ b/cypress/e2e/smoke.spec.ts @@ -0,0 +1,108 @@ +/* eslint-disable max-nested-callbacks */ +/// +import supportedVersions from '../../src/supportedVersions.mjs' +import { setOptions, cleanVisit, visit } from './shared' + +// todo use ssl + +const compareRenderedFlatWorld = () => { + // wait for render + // cy.wait(6000) + // cy.get('body').toMatchImageSnapshot({ + // name: 'superflat-world', + // }) +} + +const testWorldLoad = () => { + return cy.document().then({ timeout: 35_000 }, doc => { + return new Cypress.Promise(resolve => { + doc.addEventListener('cypress-world-ready', resolve) + }) + }).then(() => { + compareRenderedFlatWorld() + }) +} + +it('Loads & renders singleplayer', () => { + cleanVisit('/?singleplayer=1') + setOptions({ + localServerOptions: { + generation: { + name: 'superflat', + // eslint-disable-next-line unicorn/numeric-separators-style + options: { seed: 250869072 } + }, + }, + renderDistance: 2 + }) + testWorldLoad() +}) + +it.skip('Joins to local flying-squid server', () => { + visit('/?ip=localhost&version=1.16.1') + window.localStorage.version = '' + // todo replace with data-test + // 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() // todo! cypress sometimes doesn't click + testWorldLoad() +}) + +it.skip('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/minecraft-server.mjs b/cypress/minecraft-server.mjs index 18f4e3db..ea7bbcd1 100644 --- a/cypress/minecraft-server.mjs +++ b/cypress/minecraft-server.mjs @@ -1,7 +1,8 @@ //@ts-check import mcServer from 'flying-squid' -import defaultOptions from 'flying-squid/config/default-settings.json' assert { type: 'json' } +import defaultOptions from 'flying-squid/config/default-settings.json' with { type: 'json' } +/** @type {Options} */ const serverOptions = { ...defaultOptions, 'online-mode': false, 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/ops.json b/cypress/plugins/ops.json new file mode 100644 index 00000000..ade5aaa5 --- /dev/null +++ b/cypress/plugins/ops.json @@ -0,0 +1,8 @@ +[ + { + "uuid": "67128b5b-2e6b-3ad1-baa0-1b937b03e5c5", + "name": "bot", + "level": 4, + "bypassesPlayerLimit": false + } +] 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/docs-assets/handled-packets.md b/docs-assets/handled-packets.md new file mode 100644 index 00000000..497ec5ec --- /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 +❌ hurt_animation +✅ damage_event +✅ 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/docs-assets/npm-banner.jpeg b/docs-assets/npm-banner.jpeg new file mode 100644 index 00000000..95de07b8 Binary files /dev/null and b/docs-assets/npm-banner.jpeg differ diff --git a/esbuild.mjs b/esbuild.mjs deleted file mode 100644 index d68693d8..00000000 --- a/esbuild.mjs +++ /dev/null @@ -1,135 +0,0 @@ -//@ts-check -import * as esbuild from 'esbuild' -import fs from 'fs' -// import htmlPlugin from '@chialab/esbuild-plugin-html' -import server from './server.js' -import { clients, plugins, startWatchingHmr } from './scripts/esbuildPlugins.mjs' -import { generateSW } from 'workbox-build' -import { getSwAdditionalEntries } from './scripts/build.js' -import { build } from 'esbuild' - -//@ts-ignore -try { await import('./localSettings.mjs') } catch { } - -const entrypoint = 'index.ts' - -fs.writeFileSync('dist/index.html', fs.readFileSync('index.html', 'utf8').replace('', ``), 'utf8') - -const watch = process.argv.includes('--watch') || process.argv.includes('-w') -const prod = process.argv.includes('--prod') -if (prod) process.env.PROD = 'true' -const dev = !prod - -const banner = [ - 'window.global = globalThis;', -] - -const buildingVersion = new Date().toISOString().split(':')[0] - -/** @type {import('esbuild').BuildOptions} */ -const buildOptions = { - bundle: true, - entryPoints: [`src/${entrypoint}`], - target: ['es2020'], - jsx: 'automatic', - jsxDev: dev, - // logLevel: 'debug', - logLevel: 'info', - platform: 'browser', - sourcemap: prod ? true : 'linked', - outdir: 'dist', - mainFields: [ - 'browser', 'module', 'main' - ], - keepNames: true, - banner: { - // using \n breaks sourcemaps! - js: banner.join(';'), - }, - external: [ - 'sharp' - ], - alias: { - events: 'events', // make explicit - buffer: 'buffer', - 'fs': 'browserfs/dist/shims/fs.js', - http: 'http-browserify', - perf_hooks: './src/perf_hooks_replacement.js', - crypto: './src/crypto.js', - stream: 'stream-browserify', - net: 'net-browserify', - assert: 'assert', - dns: './src/dns.js', - // todo write advancedAliases plugin - }, - inject: [ - './src/shims.js' - ], - metafile: true, - plugins, - sourcesContent: !process.argv.includes('--no-sources'), - minify: process.argv.includes('--minify'), - define: { - 'process.env.NODE_ENV': JSON.stringify(dev ? 'development' : 'production'), - 'process.env.BUILD_VERSION': JSON.stringify(!dev ? buildingVersion : 'undefined'), - 'process.env.GITHUB_URL': - JSON.stringify(`https://github.com/${process.env.GITHUB_REPOSITORY || `${process.env.VERCEL_GIT_REPO_OWNER}/${process.env.VERCEL_GIT_REPO_SLUG}`}`), - 'process.env.DEPS_VERSIONS': JSON.stringify({}) - }, - loader: { - // todo use external or resolve issues with duplicating - '.png': 'dataurl', - '.svg': 'dataurl', - '.map': 'empty', - '.vert': 'text', - '.frag': 'text', - '.obj': 'text', - }, - write: false, - // todo would be better to enable? - // preserveSymlinks: true, -} - -if (watch) { - const ctx = await esbuild.context(buildOptions) - await ctx.watch() - startWatchingHmr() - server.app.get('/esbuild', (req, res, next) => { - res.writeHead(200, { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache', - Connection: 'keep-alive', - }) - - // Send a comment to keep the connection alive - res.write(': ping\n\n') - - // Add the client response to the clients array - clients.push(res) - - // Handle any client disconnection logic - res.on('close', () => { - const index = clients.indexOf(res) - if (index !== -1) { - clients.splice(index, 1) - } - }) - }) -} else { - const result = await build(buildOptions) - // console.log(await esbuild.analyzeMetafile(result.metafile)) - - if (prod) { - fs.writeFileSync('dist/version.txt', buildingVersion, 'utf-8') - - const { count, size, warnings } = await generateSW({ - // dontCacheBustURLsMatching: [new RegExp('...')], - globDirectory: 'dist', - skipWaiting: true, - clientsClaim: true, - additionalManifestEntries: getSwAdditionalEntries(), - globPatterns: [], - swDest: 'dist/service-worker.js', - }) - } -} diff --git a/experiments/decode.html b/experiments/decode.html new file mode 100644 index 00000000..fd55e622 --- /dev/null +++ b/experiments/decode.html @@ -0,0 +1 @@ + diff --git a/experiments/decode.ts b/experiments/decode.ts new file mode 100644 index 00000000..6d0f876d --- /dev/null +++ b/experiments/decode.ts @@ -0,0 +1,26 @@ +// Include the pako library +import pako from 'pako'; +import compressedJsRaw from './compressed.js?raw' + +function decompressFromBase64(input) { + // Decode the Base64 string + const binaryString = atob(input); + const len = binaryString.length; + const bytes = new Uint8Array(len); + + // Convert the binary string to a byte array + for (let i = 0; i < len; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + + // Decompress the byte array + const decompressedData = pako.inflate(bytes, { to: 'string' }); + + return decompressedData; +} + +// Use the function +console.time('decompress'); +const decompressedData = decompressFromBase64(compressedJsRaw); +console.timeEnd('decompress') +console.log(decompressedData) diff --git a/experiments/state.html b/experiments/state.html new file mode 100644 index 00000000..7a5282b7 --- /dev/null +++ b/experiments/state.html @@ -0,0 +1 @@ + diff --git a/experiments/state.ts b/experiments/state.ts new file mode 100644 index 00000000..b01523fc --- /dev/null +++ b/experiments/state.ts @@ -0,0 +1,37 @@ +import { SmoothSwitcher } from '../renderer/viewer/lib/smoothSwitcher' + +const div = document.createElement('div') +div.style.width = '100px' +div.style.height = '100px' +div.style.backgroundColor = 'red' +document.body.appendChild(div) + +const pos = {x: 0, y: 0} + +const positionSwitcher = new SmoothSwitcher(() => pos, (key, value) => { + pos[key] = value +}) +globalThis.positionSwitcher = positionSwitcher + +document.body.addEventListener('keydown', e => { + if (e.code === 'ArrowLeft' || e.code === 'ArrowRight') { + const to = { + x: e.code === 'ArrowLeft' ? -100 : 100 + } + console.log(pos, to) + positionSwitcher.transitionTo(to, e.code === 'ArrowLeft' ? 'Left' : 'Right', () => { + console.log('Switched to ', e.code === 'ArrowLeft' ? 'Left' : 'Right') + }) + } + if (e.code === 'Space') { + pos.x = 200 + } +}) + +const render = () => { + positionSwitcher.update() + div.style.transform = `translate(${pos.x}px, ${pos.y}px)` + requestAnimationFrame(render) +} + +render() diff --git a/experiments/texture-render.html b/experiments/texture-render.html deleted file mode 100644 index be406102..00000000 --- a/experiments/texture-render.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - Document - - - - - - - diff --git a/experiments/three-item.html b/experiments/three-item.html new file mode 100644 index 00000000..70155c50 --- /dev/null +++ b/experiments/three-item.html @@ -0,0 +1,13 @@ + + + + Minecraft Item Viewer + + + + + + diff --git a/experiments/three-item.ts b/experiments/three-item.ts new file mode 100644 index 00000000..b9d492fe --- /dev/null +++ b/experiments/three-item.ts @@ -0,0 +1,108 @@ +import * as THREE from 'three' +import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' +import itemsAtlas from 'mc-assets/dist/itemsAtlasLegacy.png' +import { createItemMeshFromCanvas, createItemMesh } from '../renderer/viewer/three/itemMesh' + +// Create scene, camera and renderer +const scene = new THREE.Scene() +const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) +const renderer = new THREE.WebGLRenderer({ antialias: true }) +renderer.setSize(window.innerWidth, window.innerHeight) +document.body.appendChild(renderer.domElement) + +// Setup camera and controls +camera.position.set(0, 0, 3) +const controls = new OrbitControls(camera, renderer.domElement) +controls.enableDamping = true + +// Background and lights +scene.background = new THREE.Color(0x333333) +const ambientLight = new THREE.AmbientLight(0xffffff, 0.7) +scene.add(ambientLight) + +// Animation loop +function animate () { + requestAnimationFrame(animate) + controls.update() + renderer.render(scene, camera) +} + +async function setupItemMesh () { + try { + const loader = new THREE.TextureLoader() + const atlasTexture = await loader.loadAsync(itemsAtlas) + + // Pixel-art configuration + atlasTexture.magFilter = THREE.NearestFilter + atlasTexture.minFilter = THREE.NearestFilter + atlasTexture.generateMipmaps = false + atlasTexture.wrapS = atlasTexture.wrapT = THREE.ClampToEdgeWrapping + + // Extract the tile at x=2, y=0 (16x16) + const tileSize = 16 + const tileX = 2 + const tileY = 0 + + const canvas = document.createElement('canvas') + canvas.width = tileSize + canvas.height = tileSize + const ctx = canvas.getContext('2d')! + + ctx.imageSmoothingEnabled = false + ctx.drawImage( + atlasTexture.image, + tileX * tileSize, + tileY * tileSize, + tileSize, + tileSize, + 0, + 0, + tileSize, + tileSize + ) + + // Test both approaches - working manual extraction: + const meshOld = createItemMeshFromCanvas(canvas, { depth: 0.1 }) + meshOld.position.x = -1 + meshOld.rotation.x = -Math.PI / 12 + meshOld.rotation.y = Math.PI / 12 + scene.add(meshOld) + + // And new unified function: + const atlasWidth = atlasTexture.image.width + const atlasHeight = atlasTexture.image.height + const u = (tileX * tileSize) / atlasWidth + const v = (tileY * tileSize) / atlasHeight + const sizeX = tileSize / atlasWidth + const sizeY = tileSize / atlasHeight + + console.log('Debug texture coords:', {u, v, sizeX, sizeY, atlasWidth, atlasHeight}) + + const resultNew = createItemMesh(atlasTexture, { + u, v, sizeX, sizeY + }, { + faceCamera: false, + use3D: true, + depth: 0.1 + }) + + resultNew.mesh.position.x = 1 + resultNew.mesh.rotation.x = -Math.PI / 12 + resultNew.mesh.rotation.y = Math.PI / 12 + scene.add(resultNew.mesh) + + animate() + } catch (err) { + console.error('Failed to create item mesh:', err) + } +} + +// Handle window resize +window.addEventListener('resize', () => { + camera.aspect = window.innerWidth / window.innerHeight + camera.updateProjectionMatrix() + renderer.setSize(window.innerWidth, window.innerHeight) +}) + +// Start +setupItemMesh() diff --git a/experiments/three-labels.html b/experiments/three-labels.html new file mode 100644 index 00000000..2b25bc23 --- /dev/null +++ b/experiments/three-labels.html @@ -0,0 +1,5 @@ + + diff --git a/experiments/three-labels.ts b/experiments/three-labels.ts new file mode 100644 index 00000000..b69dc95b --- /dev/null +++ b/experiments/three-labels.ts @@ -0,0 +1,67 @@ +import * as THREE from 'three' +import { FirstPersonControls } from 'three/addons/controls/FirstPersonControls.js' +import { createWaypointSprite, WAYPOINT_CONFIG } from '../renderer/viewer/three/waypointSprite' + +// Create scene, camera and renderer +const scene = new THREE.Scene() +const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) +const renderer = new THREE.WebGLRenderer({ antialias: true }) +renderer.setSize(window.innerWidth, window.innerHeight) +document.body.appendChild(renderer.domElement) + +// Add FirstPersonControls +const controls = new FirstPersonControls(camera, renderer.domElement) +controls.lookSpeed = 0.1 +controls.movementSpeed = 10 +controls.lookVertical = true +controls.constrainVertical = true +controls.verticalMin = 0.1 +controls.verticalMax = Math.PI - 0.1 + +// Position camera +camera.position.y = 1.6 // Typical eye height +camera.lookAt(0, 1.6, -1) + +// Create a helper grid and axes +const grid = new THREE.GridHelper(20, 20) +scene.add(grid) +const axes = new THREE.AxesHelper(5) +scene.add(axes) + +// Create waypoint sprite via utility +const waypoint = createWaypointSprite({ + position: new THREE.Vector3(0, 0, -5), + color: 0xff0000, + label: 'Target', +}) +scene.add(waypoint.group) + +// Use built-in offscreen arrow from utils +waypoint.enableOffscreenArrow(true) +waypoint.setArrowParent(scene) + +// Animation loop +function animate() { + requestAnimationFrame(animate) + + const delta = Math.min(clock.getDelta(), 0.1) + controls.update(delta) + + // Unified camera update (size, distance text, arrow, visibility) + const sizeVec = renderer.getSize(new THREE.Vector2()) + waypoint.updateForCamera(camera.position, camera, sizeVec.width, sizeVec.height) + + renderer.render(scene, camera) +} + +// Handle window resize +window.addEventListener('resize', () => { + camera.aspect = window.innerWidth / window.innerHeight + camera.updateProjectionMatrix() + renderer.setSize(window.innerWidth, window.innerHeight) +}) + +// Add clock for controls +const clock = new THREE.Clock() + +animate() diff --git a/experiments/three.html b/experiments/three.html new file mode 100644 index 00000000..8765081b --- /dev/null +++ b/experiments/three.html @@ -0,0 +1 @@ + diff --git a/experiments/three.ts b/experiments/three.ts new file mode 100644 index 00000000..21142b5f --- /dev/null +++ b/experiments/three.ts @@ -0,0 +1,60 @@ +import * as THREE from 'three' + +// Create scene, camera and renderer +const scene = new THREE.Scene() +const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) +const renderer = new THREE.WebGLRenderer() +renderer.setSize(window.innerWidth, window.innerHeight) +document.body.appendChild(renderer.domElement) + +// Position camera +camera.position.z = 5 + +// Create a canvas with some content +const canvas = document.createElement('canvas') +canvas.width = 256 +canvas.height = 256 +const ctx = canvas.getContext('2d') + +scene.background = new THREE.Color(0x444444) + +// Draw something on the canvas +ctx.fillStyle = '#444444' +// ctx.fillRect(0, 0, 256, 256) +ctx.fillStyle = 'red' +ctx.font = '48px Arial' +ctx.textAlign = 'center' +ctx.textBaseline = 'middle' +ctx.fillText('Hello!', 128, 128) + +// Create bitmap and texture +async function createTexturedBox() { + const canvas2 = new OffscreenCanvas(256, 256) + const ctx2 = canvas2.getContext('2d')! + ctx2.drawImage(canvas, 0, 0) + const texture = new THREE.Texture(canvas2) + texture.magFilter = THREE.NearestFilter + texture.minFilter = THREE.NearestFilter + texture.needsUpdate = true + texture.flipY = false + + // Create box with texture + const geometry = new THREE.BoxGeometry(2, 2, 2) + const material = new THREE.MeshBasicMaterial({ + map: texture, + side: THREE.DoubleSide, + premultipliedAlpha: false, + }) + const cube = new THREE.Mesh(geometry, material) + scene.add(cube) +} + +// Create the textured box +createTexturedBox() + +// Animation loop +function animate() { + requestAnimationFrame(animate) + renderer.render(scene, camera) +} +animate() diff --git a/index.html b/index.html index 3e921855..b2fa3dbd 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,22 @@ + --> - Prismarine Web Client - - - - - + Minecraft Web Client + + - + - + - -
-
- -
+
diff --git a/package.json b/package.json index 9451b266..ff673726 100644 --- a/package.json +++ b/package.json @@ -1,34 +1,49 @@ { - "name": "prismarine-web-client", + "name": "minecraft-web-client", "version": "0.0.0-dev", "description": "A minecraft client running in a browser", "scripts": { - "start": "node scripts/build.js copyFilesDev && node scripts/prepareData.mjs && node esbuild.mjs --watch", - "start-watch-script": "nodemon -w esbuild.mjs --watch", - "build": "node scripts/build.js copyFiles && node scripts/prepareData.mjs -f && node esbuild.mjs --minify --prod", - "check-build": "tsc && pnpm build", + "dev-rsbuild": "rsbuild dev", + "dev-proxy": "node server.js", + "start": "run-p dev-proxy dev-rsbuild watch-mesher", + "start2": "run-p dev-rsbuild watch-mesher", + "start-metrics": "ENABLE_METRICS=true rsbuild dev", + "build": "pnpm build-other-workers && rsbuild build", + "build-analyze": "BUNDLE_ANALYZE=true rsbuild build && pnpm build-other-workers", + "build-single-file": "SINGLE_FILE_BUILD=true rsbuild build", + "prepare-project": "tsx scripts/genShims.ts && tsx scripts/makeOptimizedMcData.mjs && tsx scripts/genLargeDataAliases.ts", + "check-build": "pnpm prepare-project && tsc && pnpm build", "test:cypress": "cypress run", + "test:benchmark": "PERFORMANCE_TEST=true cypress run", + "test:cypress:open": "cypress open", "test-unit": "vitest", "test:e2e": "start-test http-get://localhost:8080 test:cypress", - "prod-start": "node server.js", - "postinstall": "node scripts/gen-texturepack-files.mjs && tsx scripts/optimizeBlockCollisions.ts", + "prod-start": "node server.js --prod", "test-mc-server": "tsx cypress/minecraft-server.mjs", - "lint": "eslint \"{src,cypress}/**/*.{ts,js,jsx,tsx}\"", + "lint": "eslint \"{src,cypress,renderer}/**/*.{ts,js,jsx,tsx}\"", + "lint-fix": "pnpm lint --fix", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build && node scripts/build.js moveStorybookFiles", "start-experiments": "vite --config experiments/vite.config.ts --host", "watch-other-workers": "echo NOT IMPLEMENTED", - "watch-mesher": "node prismarine-viewer/buildMesherWorker.mjs -w", - "run-playground": "run-p watch-mesher watch-other-workers playground-server watch-playground", + "build-other-workers": "echo NOT IMPLEMENTED", + "build-mesher": "node renderer/buildMesherWorker.mjs", + "watch-mesher": "pnpm build-mesher -w", + "run-playground": "run-p watch-mesher watch-other-workers watch-playground", "run-all": "run-p start run-playground", - "playground-server": "live-server --port=9090 prismarine-viewer/public", - "watch-playground": "node prismarine-viewer/esbuild.mjs -w" + "build-playground": "rsbuild build --config renderer/rsbuild.config.ts", + "watch-playground": "rsbuild dev --config renderer/rsbuild.config.ts", + "update-git-deps": "tsx scripts/updateGitDeps.ts", + "request-data": "tsx scripts/requestData.ts" }, "keywords": [ "prismarine", "web", "client" ], + "release": { + "attachReleaseFiles": "{self-host.zip,minecraft.html}" + }, "publish": { "preset": { "publishOnlyIfChanged": true, @@ -39,16 +54,17 @@ "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", + "@monaco-editor/react": "^4.7.0", + "@nxg-org/mineflayer-auto-jump": "^0.7.18", + "@nxg-org/mineflayer-tracker": "1.3.0", "@react-oauth/google": "^0.12.1", + "@stylistic/eslint-plugin": "^2.6.1", "@types/gapi": "^0.0.47", "@types/react": "^18.2.20", "@types/react-dom": "^18.2.7", "@types/wicg-file-system-access": "^2023.10.2", "@xmcl/text-component": "^2.1.3", - "@zardoy/react-util": "^0.2.0", + "@zardoy/react-util": "^0.2.4", "@zardoy/utils": "^0.0.11", "adm-zip": "^0.5.12", "browserfs": "github:zardoy/browserfs#build", @@ -56,27 +72,29 @@ "classnames": "^2.5.1", "compression": "^1.7.4", "cors": "^2.8.5", - "cypress-plugin-snapshots": "^1.4.4", "debug": "^4.3.4", + "deepslate": "^0.23.5", + "diff-match-patch": "^1.0.5", "eruda": "^3.0.1", "esbuild": "^0.19.3", "esbuild-plugin-polyfill-node": "^0.3.0", "express": "^4.18.2", "filesize": "^10.0.12", - "flying-squid": "npm:@zardoy/flying-squid@^0.0.24", + "flying-squid": "npm:@zardoy/flying-squid@^0.0.104", + "framer-motion": "^12.9.2", "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", - "minecraft-data": "3.65.0", - "minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol", + "mcraft-fun-mineflayer": "^0.1.23", + "minecraft-data": "3.98.0", + "minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol#master", "mineflayer-item-map-downloader": "github:zardoy/mineflayer-item-map-downloader", "mojangson": "^2.0.4", "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", @@ -87,7 +105,8 @@ "qrcode.react": "^3.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-transition-group": "^4.4.5", + "react-select": "^5.8.0", + "react-zoom-pan-pinch": "3.4.4", "remark": "^15.0.1", "sanitize-filename": "^1.6.3", "skinview3d": "^3.0.1", @@ -100,74 +119,124 @@ "use-typed-event-listener": "^4.0.2", "valtio": "^1.11.1", "vec3": "^0.1.7", + "wait-on": "^7.2.0", "workbox-build": "^7.0.0" }, "devDependencies": { + "@rsbuild/core": "1.3.5", + "@rsbuild/plugin-node-polyfill": "1.3.0", + "@rsbuild/plugin-react": "1.2.0", + "@rsbuild/plugin-type-check": "1.2.1", + "@rsbuild/plugin-typed-css-modules": "1.0.2", "@storybook/addon-essentials": "^7.4.6", "@storybook/addon-links": "^7.4.6", "@storybook/blocks": "^7.4.6", "@storybook/react": "^7.4.6", "@storybook/react-vite": "^7.4.6", + "@types/diff-match-patch": "^1.0.36", "@types/lodash-es": "^4.17.9", - "@types/react-transition-group": "^4.4.7", "@types/stats.js": "^0.17.1", "@types/three": "0.154.0", "@types/ua-parser-js": "^0.7.39", + "@types/wait-on": "^5.3.4", "@xmcl/installer": "^5.1.0", "assert": "^2.0.0", "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", "constants-browserify": "^1.0.0", - "contro-max": "^0.1.8", + "contro-max": "^0.1.9", "crypto-browserify": "^3.12.0", - "cypress": "^10.11.0", "cypress-esbuild-preprocessor": "^1.0.2", "eslint": "^8.50.0", "eslint-config-zardoy": "^0.2.17", "events": "^3.3.0", + "gzip-size": "^7.0.0", "http-browserify": "^1.7.0", "http-server": "^14.1.1", "https-browserify": "^1.0.0", + "mc-assets": "^0.2.62", "minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next", - "mineflayer": "github:PrismarineJS/mineflayer", - "mineflayer-pathfinder": "^2.4.4", + "mineflayer": "github:zardoy/mineflayer#gen-the-master", + "mineflayer-mouse": "^0.1.21", "npm-run-all": "^4.1.5", "os-browserify": "^0.3.0", "path-browserify": "^1.0.1", "path-exists-cli": "^2.0.0", - "prismarine-viewer": "link:prismarine-viewer", "process": "github:PrismarineJS/node-process", + "renderer": "link:renderer", "rimraf": "^5.0.1", "storybook": "^7.4.6", "stream-browserify": "^3.0.0", "three": "0.154.0", "timers-browserify": "^2.0.12", - "typescript": "5.5.0-beta", + "typescript": "5.5.4", "vitest": "^0.34.6", "yaml": "^2.3.2" }, "optionalDependencies": { + "cypress": "^10.11.0", + "cypress-plugin-snapshots": "^1.4.4", + "sharp": "^0.33.5", "systeminformation": "^5.21.22" }, + "browserslist": { + "production": [ + "iOS >= 14", + "Android >= 13", + "Chrome >= 103", + "not dead", + "not ie <= 11", + "not op_mini all", + "> 0.5%" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, "pnpm": { "overrides": { - "@nxg-org/mineflayer-physics-util": "1.5.8", + "mineflayer": "github:zardoy/mineflayer#gen-the-master", + "@nxg-org/mineflayer-physics-util": "1.8.10", + "buffer": "^6.0.3", + "vec3": "0.1.10", "three": "0.154.0", "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.65.0", + "minecraft-data": "3.98.0", "prismarine-provider-anvil": "github:zardoy/prismarine-provider-anvil#everything", - "minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol", + "prismarine-physics": "github:zardoy/prismarine-physics", + "minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol#master", "react": "^18.2.0", - "prismarine-chunk": "github:zardoy/prismarine-chunk" + "prismarine-chunk": "github:zardoy/prismarine-chunk#master", + "prismarine-item": "latest" }, "updateConfig": { - "ignoreDependencies": [] + "ignoreDependencies": [ + "browserfs", + "google-drive-browserfs" + ] }, "patchedDependencies": { - "minecraft-protocol@1.47.0": "patches/minecraft-protocol@1.47.0.patch" - } + "pixelarticons@1.8.1": "patches/pixelarticons@1.8.1.patch", + "mineflayer-item-map-downloader@1.2.0": "patches/mineflayer-item-map-downloader@1.2.0.patch", + "minecraft-protocol": "patches/minecraft-protocol.patch" + }, + "ignoredBuiltDependencies": [ + "canvas", + "core-js", + "gl" + ], + "onlyBuiltDependencies": [ + "sharp", + "cypress", + "esbuild", + "fsevents" + ], + "ignorePatchFailures": false, + "allowUnusedPatches": false }, - "packageManager": "pnpm@9.0.4" + "packageManager": "pnpm@10.8.0+sha512.0e82714d1b5b43c74610193cb20734897c1d00de89d0e18420aebc5977fa13d780a9cb05734624e81ebd81cc876cd464794850641c48b9544326b5622ca29971" } diff --git a/package.npm.json b/package.npm.json index bae8b60f..4853780f 100644 --- a/package.npm.json +++ b/package.npm.json @@ -3,7 +3,13 @@ "description": "A Minecraft-like React UI library", "keywords": [ "minecraft", - "minecraft style" + "minecraft style", + "minecraft ui", + "minecraft components", + "minecraft react", + "minecraft library", + "minecraft web", + "minecraft browser" ], "license": "MIT", "sideEffects": false, @@ -26,7 +32,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/patches/minecraft-protocol.patch b/patches/minecraft-protocol.patch new file mode 100644 index 00000000..e29f87d9 --- /dev/null +++ b/patches/minecraft-protocol.patch @@ -0,0 +1,138 @@ +diff --git a/src/client/chat.js b/src/client/chat.js +index 0021870994fc59a82f0ac8aba0a65a8be43ef2f4..a53fceb843105ea2a1d88722b3fc7c3b43cb102a 100644 +--- a/src/client/chat.js ++++ b/src/client/chat.js +@@ -116,7 +116,7 @@ module.exports = function (client, options) { + for (const player of packet.data) { + if (player.chatSession) { + client._players[player.uuid] = { +- publicKey: crypto.createPublicKey({ key: player.chatSession.publicKey.keyBytes, format: 'der', type: 'spki' }), ++ // publicKey: crypto.createPublicKey({ key: player.chatSession.publicKey.keyBytes, format: 'der', type: 'spki' }), + publicKeyDER: player.chatSession.publicKey.keyBytes, + sessionUuid: player.chatSession.uuid + } +@@ -126,7 +126,7 @@ module.exports = function (client, options) { + + if (player.crypto) { + client._players[player.uuid] = { +- publicKey: crypto.createPublicKey({ key: player.crypto.publicKey, format: 'der', type: 'spki' }), ++ // publicKey: crypto.createPublicKey({ key: player.crypto.publicKey, format: 'der', type: 'spki' }), + publicKeyDER: player.crypto.publicKey, + signature: player.crypto.signature, + displayName: player.displayName || player.name +@@ -196,7 +196,7 @@ module.exports = function (client, options) { + if (mcData.supportFeature('useChatSessions')) { + const tsDelta = BigInt(Date.now()) - packet.timestamp + const expired = !packet.timestamp || tsDelta > messageExpireTime || tsDelta < 0 +- const verified = !packet.unsignedChatContent && updateAndValidateSession(packet.senderUuid, packet.plainMessage, packet.signature, packet.index, packet.previousMessages, packet.salt, packet.timestamp) && !expired ++ const verified = false && !packet.unsignedChatContent && updateAndValidateSession(packet.senderUuid, packet.plainMessage, packet.signature, packet.index, packet.previousMessages, packet.salt, packet.timestamp) && !expired + if (verified) client._signatureCache.push(packet.signature) + client.emit('playerChat', { + globalIndex: packet.globalIndex, +@@ -362,7 +362,7 @@ module.exports = function (client, options) { + } + } + +- client._signedChat = (message, options = {}) => { ++ client._signedChat = async (message, options = {}) => { + options.timestamp = options.timestamp || BigInt(Date.now()) + options.salt = options.salt || 1n + +@@ -407,7 +407,7 @@ module.exports = function (client, options) { + message, + timestamp: options.timestamp, + salt: options.salt, +- signature: (client.profileKeys && client._session) ? client.signMessage(message, options.timestamp, options.salt, undefined, acknowledgements) : undefined, ++ signature: (client.profileKeys && client._session) ? await client.signMessage(message, options.timestamp, options.salt, undefined, acknowledgements) : undefined, + offset: client._lastSeenMessages.pending, + checksum: computeChatChecksum(client._lastSeenMessages), // 1.21.5+ + acknowledged +@@ -422,7 +422,7 @@ module.exports = function (client, options) { + message, + timestamp: options.timestamp, + salt: options.salt, +- signature: client.profileKeys ? client.signMessage(message, options.timestamp, options.salt, options.preview) : Buffer.alloc(0), ++ signature: client.profileKeys ? await client.signMessage(message, options.timestamp, options.salt, options.preview) : Buffer.alloc(0), + signedPreview: options.didPreview, + previousMessages: client._lastSeenMessages.map((e) => ({ + messageSender: e.sender, +diff --git a/src/client/encrypt.js b/src/client/encrypt.js +index 63cc2bd9615100bd2fd63dfe14c094aa6b8cd1c9..36df57d1196af9761d920fa285ac48f85410eaef 100644 +--- a/src/client/encrypt.js ++++ b/src/client/encrypt.js +@@ -25,7 +25,11 @@ module.exports = function (client, options) { + if (packet.serverId !== '-') { + debug('This server appears to be an online server and you are providing no password, the authentication will probably fail') + } +- sendEncryptionKeyResponse() ++ client.end('This server appears to be an online server and you are providing no authentication. Try authenticating first.') ++ // sendEncryptionKeyResponse() ++ // client.once('set_compression', () => { ++ // clearTimeout(loginTimeout) ++ // }) + } + + function onJoinServerResponse (err) { +diff --git a/src/client/pluginChannels.js b/src/client/pluginChannels.js +index 671eb452f31e6b5fcd57d715f1009d010160c65f..7f69f511c8fb97d431ec5125c851b49be8e2ab76 100644 +--- a/src/client/pluginChannels.js ++++ b/src/client/pluginChannels.js +@@ -57,7 +57,7 @@ module.exports = function (client, options) { + try { + packet.data = proto.parsePacketBuffer(channel, packet.data).data + } catch (error) { +- client.emit('error', error) ++ client.emit('error', error, { customPayload: packet }) + return + } + } +diff --git a/src/client.js b/src/client.js +index e369e77d055ba919e8f9da7b8e8b5dc879c74cf4..54bb9e6644388e9b6bd42b3012951875989cdf0c 100644 +--- a/src/client.js ++++ b/src/client.js +@@ -111,7 +111,13 @@ class Client extends EventEmitter { + this._hasBundlePacket = false + } + } else { +- emitPacket(parsed) ++ try { ++ emitPacket(parsed) ++ } catch (err) { ++ console.log('Client incorrectly handled packet ' + parsed.metadata.name) ++ console.error(err) ++ // todo investigate why it doesn't close the stream even if unhandled there ++ } + } + }) + } +@@ -169,7 +175,10 @@ class Client extends EventEmitter { + } + + const onFatalError = (err) => { +- this.emit('error', err) ++ // todo find out what is trying to write after client disconnect ++ if(err.code !== 'ECONNABORTED') { ++ this.emit('error', err) ++ } + endSocket() + } + +@@ -198,6 +207,10 @@ class Client extends EventEmitter { + serializer -> framer -> socket -> splitter -> deserializer */ + if (this.serializer) { + this.serializer.end() ++ setTimeout(() => { ++ this.socket?.end() ++ this.socket?.emit('end') ++ }, 2000) // allow the serializer to finish writing + } else { + if (this.socket) this.socket.end() + } +@@ -243,6 +256,7 @@ class Client extends EventEmitter { + debug('writing packet ' + this.state + '.' + name) + debug(params) + } ++ this.emit('writePacket', name, params) + this.serializer.write({ name, params }) + } + diff --git a/patches/minecraft-protocol@1.47.0.patch b/patches/minecraft-protocol@1.47.0.patch deleted file mode 100644 index 02bbdd5d..00000000 --- a/patches/minecraft-protocol@1.47.0.patch +++ /dev/null @@ -1,130 +0,0 @@ -diff --git a/src/client/autoVersion.js b/src/client/autoVersion.js -index c437ecf3a0e4ab5758a48538c714b7e9651bb5da..d9c9895ae8614550aa09ad60a396ac32ffdf1287 100644 ---- a/src/client/autoVersion.js -+++ b/src/client/autoVersion.js -@@ -9,7 +9,7 @@ module.exports = function (client, options) { - client.wait_connect = true // don't let src/client/setProtocol proceed on socket 'connect' until 'connect_allowed' - debug('pinging', options.host) - // TODO: use 0xfe ping instead for better compatibility/performance? https://github.com/deathcap/node-minecraft-ping -- ping(options, function (err, response) { -+ ping(options, async function (err, response) { - if (err) { return client.emit('error', err) } - debug('ping response', response) - // TODO: could also use ping pre-connect to save description, type, max players, etc. -@@ -40,6 +40,7 @@ module.exports = function (client, options) { - - // Reinitialize client object with new version TODO: move out of its constructor? - client.version = minecraftVersion -+ await options.versionSelectedHook?.(client) - client.state = states.HANDSHAKING - - // Let other plugins such as Forge/FML (modinfo) respond to the ping response -diff --git a/src/client/encrypt.js b/src/client/encrypt.js -index b9d21bab9faccd5dbf1975fc423fc55c73e906c5..99ffd76527b410e3a393181beb260108f4c63536 100644 ---- a/src/client/encrypt.js -+++ b/src/client/encrypt.js -@@ -25,7 +25,11 @@ module.exports = function (client, options) { - if (packet.serverId !== '-') { - debug('This server appears to be an online server and you are providing no password, the authentication will probably fail') - } -- sendEncryptionKeyResponse() -+ client.end('This server appears to be an online server and you are providing no authentication. Try authenticating first.') -+ // sendEncryptionKeyResponse() -+ // client.once('set_compression', () => { -+ // clearTimeout(loginTimeout) -+ // }) - } - - function onJoinServerResponse (err) { -diff --git a/src/client.js b/src/client.js -index c89375e32babbf3559655b1e95f6441b9a30796f..f24cd5dc8fa9a0a4000b184fb3c79590a3ad8b8a 100644 ---- a/src/client.js -+++ b/src/client.js -@@ -88,10 +88,12 @@ class Client extends EventEmitter { - parsed.metadata.name = parsed.data.name - parsed.data = parsed.data.params - parsed.metadata.state = state -- debug('read packet ' + state + '.' + parsed.metadata.name) -- if (debug.enabled) { -- const s = JSON.stringify(parsed.data, null, 2) -- debug(s && s.length > 10000 ? parsed.data : s) -+ if (!globalThis.excludeCommunicationDebugEvents?.includes(parsed.metadata.name)) { -+ debug('read packet ' + state + '.' + parsed.metadata.name) -+ if (debug.enabled) { -+ const s = JSON.stringify(parsed.data, null, 2) -+ debug(s && s.length > 10000 ? parsed.data : s) -+ } - } - if (this._hasBundlePacket && parsed.metadata.name === 'bundle_delimiter') { - if (this._mcBundle.length) { // End bundle -@@ -109,7 +111,13 @@ class Client extends EventEmitter { - this._hasBundlePacket = false - } - } else { -- emitPacket(parsed) -+ try { -+ emitPacket(parsed) -+ } catch (err) { -+ console.log('Client incorrectly handled packet ' + parsed.metadata.name) -+ console.error(err) -+ // todo investigate why it doesn't close the stream even if unhandled there -+ } - } - }) - } -@@ -166,7 +174,10 @@ class Client extends EventEmitter { - } - - const onFatalError = (err) => { -- this.emit('error', err) -+ // todo find out what is trying to write after client disconnect -+ if(err.code !== 'ECONNABORTED') { -+ this.emit('error', err) -+ } - endSocket() - } - -@@ -195,6 +206,8 @@ class Client extends EventEmitter { - serializer -> framer -> socket -> splitter -> deserializer */ - if (this.serializer) { - this.serializer.end() -+ this.socket?.end() -+ this.socket?.emit('end') - } else { - if (this.socket) this.socket.end() - } -@@ -236,8 +249,11 @@ class Client extends EventEmitter { - - write (name, params) { - if (!this.serializer.writable) { return } -- debug('writing packet ' + this.state + '.' + name) -- debug(params) -+ if (!globalThis.excludeCommunicationDebugEvents?.includes(name)) { -+ debug(`[${this.state}] from ${this.isServer ? 'server' : 'client'}: ` + name) -+ debug(params) -+ } -+ this.emit('writePacket', name, params) - this.serializer.write({ name, params }) - } - -diff --git a/src/index.d.ts b/src/index.d.ts -index 0a5821c32d735e11205a280aa5a503c13533dc14..94a49f661d922478b940d853169b6087e6ec3df5 100644 ---- a/src/index.d.ts -+++ b/src/index.d.ts -@@ -121,6 +121,7 @@ declare module 'minecraft-protocol' { - sessionServer?: string - keepAlive?: boolean - closeTimeout?: number -+ closeTimeout?: number - noPongTimeout?: number - checkTimeoutInterval?: number - version?: string -@@ -141,6 +142,8 @@ declare module 'minecraft-protocol' { - disableChatSigning?: boolean - /** Pass custom client implementation if needed. */ - Client?: Client -+ /** Can be used to prepare mc data on autoVersion (client.version has selected version) */ -+ versionSelectedHook?: (client: Client) => Promise | void - } - - export class Server extends EventEmitter { diff --git a/patches/mineflayer-item-map-downloader@1.2.0.patch b/patches/mineflayer-item-map-downloader@1.2.0.patch new file mode 100644 index 00000000..97813cc1 --- /dev/null +++ b/patches/mineflayer-item-map-downloader@1.2.0.patch @@ -0,0 +1,16 @@ +diff --git a/package.json b/package.json +index 2a7aff75a9f1c7fe4eebb657002e58f4581dad0e..cd3490983353336efeb13f24f0af69c6c1d16444 100644 +--- a/package.json ++++ b/package.json +@@ -9,10 +9,7 @@ + "keywords": [], + "author": "Ic3Tank", + "license": "ISC", +- "dependencies": { +- "mineflayer": "^4.3.0", +- "sharp": "^0.30.6" +- }, ++ "dependencies": {}, + "devDependencies": { + "mineflayer-item-map-downloader": "file:./" + } diff --git a/patches/pixelarticons@1.8.1.patch b/patches/pixelarticons@1.8.1.patch new file mode 100644 index 00000000..b65b6f2b --- /dev/null +++ b/patches/pixelarticons@1.8.1.patch @@ -0,0 +1,28 @@ +diff --git a/fonts/pixelart-icons-font.css b/fonts/pixelart-icons-font.css +index 3b2ebe839370d96bf93ef5ca94a827f07e49378d..4f8d76be2ca6e4ddc43c68d0a6f0f69979165ab4 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- */ ++ url('pixelart-icons-font.ttf?t=1711815892278') format('truetype'); /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ + } + + [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 6fdf4afa..5bcd74a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,21 +5,32 @@ settings: excludeLinksFromLockfile: false overrides: - '@nxg-org/mineflayer-physics-util': 1.5.8 + mineflayer: github:zardoy/mineflayer#gen-the-master + '@nxg-org/mineflayer-physics-util': 1.8.10 + buffer: ^6.0.3 + vec3: 0.1.10 three: 0.154.0 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.65.0 + minecraft-data: 3.98.0 prismarine-provider-anvil: github:zardoy/prismarine-provider-anvil#everything - minecraft-protocol: github:PrismarineJS/node-minecraft-protocol + prismarine-physics: github:zardoy/prismarine-physics + minecraft-protocol: github:PrismarineJS/node-minecraft-protocol#master react: ^18.2.0 - prismarine-chunk: github:zardoy/prismarine-chunk + prismarine-chunk: github:zardoy/prismarine-chunk#master + prismarine-item: latest patchedDependencies: - minecraft-protocol@1.47.0: - hash: 2uxevyasyasdavsxuehfavgkjq - path: patches/minecraft-protocol@1.47.0.patch + minecraft-protocol: + hash: 4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b + path: patches/minecraft-protocol.patch + mineflayer-item-map-downloader@1.2.0: + hash: a731ebbace2d8790c973ab3a5ba33494a6e9658533a9710dd8ba36f86db061ad + path: patches/mineflayer-item-map-downloader@1.2.0.patch + pixelarticons@1.8.1: + hash: 533230072bc402f425c86abd3d0356fe087b14cab2a254d93f419b083f2d8dfa + path: patches/pixelarticons@1.8.1.patch importers: @@ -27,136 +38,145 @@ importers: dependencies: '@dimaka/interface': specifier: 0.0.3-alpha.0 - version: 0.0.3-alpha.0(@babel/core@7.22.11)(@popperjs/core@2.11.8)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 0.0.3-alpha.0(@babel/core@7.26.9)(@popperjs/core@2.11.8)(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@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) + version: 0.26.28(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@monaco-editor/react': + specifier: ^4.7.0 + version: 4.7.0(monaco-editor@0.52.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@nxg-org/mineflayer-auto-jump': - specifier: ^0.7.7 - version: 0.7.7 + specifier: ^0.7.18 + version: 0.7.18 '@nxg-org/mineflayer-tracker': - specifier: ^1.2.1 - version: 1.2.1 + specifier: 1.3.0 + version: 1.3.0(encoding@0.1.13) '@react-oauth/google': specifier: ^0.12.1 - version: 0.12.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 0.12.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@stylistic/eslint-plugin': + specifier: ^2.6.1 + version: 2.13.0(eslint@8.57.1)(typescript@5.5.4) '@types/gapi': specifier: ^0.0.47 version: 0.0.47 '@types/react': specifier: ^18.2.20 - version: 18.2.20 + version: 18.3.18 '@types/react-dom': specifier: ^18.2.7 - version: 18.2.7 + version: 18.3.5(@types/react@18.3.18) '@types/wicg-file-system-access': specifier: ^2023.10.2 - version: 2023.10.2 + version: 2023.10.5 '@xmcl/text-component': specifier: ^2.1.3 version: 2.1.3 '@zardoy/react-util': - specifier: ^0.2.0 - version: 0.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + specifier: ^0.2.4 + version: 0.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@zardoy/utils': specifier: ^0.0.11 version: 0.0.11 adm-zip: specifier: ^0.5.12 - version: 0.5.12 + version: 0.5.16 browserfs: specifier: github:zardoy/browserfs#build version: https://codeload.github.com/zardoy/browserfs/tar.gz/e60ca69e74888e057a96a468afe1d62347d3f56f change-case: specifier: ^5.1.2 - version: 5.1.2 + version: 5.4.4 classnames: specifier: ^2.5.1 version: 2.5.1 compression: specifier: ^1.7.4 - version: 1.7.4 + version: 1.8.0 cors: specifier: ^2.8.5 version: 2.8.5 - cypress-plugin-snapshots: - specifier: ^1.4.4 - version: 1.4.4(cypress@10.11.0) debug: specifier: ^4.3.4 - version: 4.3.4(supports-color@8.1.1) + version: 4.4.0(supports-color@8.1.1) + deepslate: + specifier: ^0.23.5 + version: 0.23.5 + diff-match-patch: + specifier: ^1.0.5 + version: 1.0.5 eruda: specifier: ^3.0.1 - version: 3.0.1 + version: 3.4.1 esbuild: specifier: ^0.19.3 - version: 0.19.3 + version: 0.19.12 esbuild-plugin-polyfill-node: specifier: ^0.3.0 - version: 0.3.0(esbuild@0.19.3) + version: 0.3.0(esbuild@0.19.12) express: specifier: ^4.18.2 - version: 4.18.2 + version: 4.21.2 filesize: specifier: ^10.0.12 - version: 10.0.12 + version: 10.1.6 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.104 + version: '@zardoy/flying-squid@0.0.104(encoding@0.1.13)' + framer-motion: + specifier: ^12.9.2 + version: 12.9.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) fs-extra: specifier: ^11.1.1 - version: 11.1.1 + version: 11.3.0 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 lodash-es: specifier: ^4.17.21 version: 4.17.21 - minecraft-assets: - specifier: ^1.12.2 - version: 1.12.2 + mcraft-fun-mineflayer: + specifier: ^0.1.23 + version: 0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13)) minecraft-data: - specifier: 3.65.0 - version: 3.65.0 + specifier: 3.98.0 + version: 3.98.0 minecraft-protocol: - specifier: github:PrismarineJS/node-minecraft-protocol - version: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) + specifier: github:PrismarineJS/node-minecraft-protocol#master + version: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13) mineflayer-item-map-downloader: specifier: github:zardoy/mineflayer-item-map-downloader - version: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7(encoding@0.1.13) + version: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824(patch_hash=a731ebbace2d8790c973ab3a5ba33494a6e9658533a9710dd8ba36f86db061ad)(encoding@0.1.13) 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 + version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e754999ffdea67853bc9b10553b5e9908b40f618 node-gzip: specifier: ^1.1.2 version: 1.1.2 peerjs: specifier: ^1.5.0 - version: 1.5.0 + version: 1.5.4 + pixelarticons: + specifier: ^1.8.1 + version: 1.8.1(patch_hash=533230072bc402f425c86abd3d0356fe087b14cab2a254d93f419b083f2d8dfa) pretty-bytes: specifier: ^6.1.1 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/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.98.0) prosemirror-example-setup: specifier: ^1.2.2 - version: 1.2.2 + version: 1.2.3 prosemirror-markdown: specifier: ^1.12.0 - version: 1.12.0 + version: 1.13.1 prosemirror-menu: specifier: ^1.2.4 version: 1.2.4 @@ -165,19 +185,22 @@ importers: version: 1.4.3 prosemirror-view: specifier: ^1.33.1 - version: 1.33.1 + version: 1.38.1 qrcode.react: specifier: ^3.1.0 - version: 3.1.0(react@18.2.0) + version: 3.2.0(react@18.3.1) react: specifier: ^18.2.0 - version: 18.2.0 + version: 18.3.1 react-dom: specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) - react-transition-group: - specifier: ^4.4.5 - version: 4.4.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 18.3.1(react@18.3.1) + react-select: + specifier: ^5.8.0 + version: 5.10.1(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-zoom-pan-pinch: + specifier: 3.4.4 + version: 3.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) remark: specifier: ^15.0.1 version: 15.0.1 @@ -186,13 +209,13 @@ importers: version: 1.6.3 skinview3d: specifier: ^3.0.1 - version: 3.0.1 + version: 3.1.0 source-map-js: specifier: ^1.0.2 - version: 1.0.2 + version: 1.2.1 stats-gl: specifier: ^1.0.5 - version: 1.0.5 + version: 1.0.7 stats.js: specifier: ^0.17.0 version: 0.17.0 @@ -204,60 +227,77 @@ importers: version: 3.0.3 ua-parser-js: specifier: ^1.0.37 - version: 1.0.37 + version: 1.0.40 use-typed-event-listener: specifier: ^4.0.2 - version: 4.0.2(react@18.2.0)(typescript@5.5.0-beta) + version: 4.0.2(react@18.3.1)(typescript@5.5.4) valtio: specifier: ^1.11.1 - version: 1.11.2(@types/react@18.2.20)(react@18.2.0) + version: 1.13.2(@types/react@18.3.18)(react@18.3.1) vec3: - specifier: ^0.1.7 - version: 0.1.8 + specifier: 0.1.10 + version: 0.1.10 + wait-on: + specifier: ^7.2.0 + version: 7.2.0(debug@4.4.0) workbox-build: specifier: ^7.0.0 - version: 7.0.0(@types/babel__core@7.20.2) - optionalDependencies: - systeminformation: - specifier: ^5.21.22 - version: 5.22.7 + version: 7.3.0(@types/babel__core@7.20.5) devDependencies: + '@rsbuild/core': + specifier: 1.3.5 + version: 1.3.5 + '@rsbuild/plugin-node-polyfill': + specifier: 1.3.0 + version: 1.3.0(@rsbuild/core@1.3.5) + '@rsbuild/plugin-react': + specifier: 1.2.0 + version: 1.2.0(@rsbuild/core@1.3.5) + '@rsbuild/plugin-type-check': + specifier: 1.2.1 + version: 1.2.1(@rsbuild/core@1.3.5)(@rspack/core@1.3.3(@swc/helpers@0.5.15))(typescript@5.5.4) + '@rsbuild/plugin-typed-css-modules': + specifier: 1.0.2 + version: 1.0.2(@rsbuild/core@1.3.5) '@storybook/addon-essentials': specifier: ^7.4.6 - version: 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/addon-links': specifier: ^7.4.6 - version: 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 7.6.20(react@18.3.1) '@storybook/blocks': specifier: ^7.4.6 - version: 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@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.5.0-beta) + version: 7.6.20(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) '@storybook/react-vite': specifier: ^7.4.6 - version: 7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(rollup@2.79.1)(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) + version: 7.6.20(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@2.79.2)(typescript@5.5.4)(vite@6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)) + '@types/diff-match-patch': + specifier: ^1.0.36 + version: 1.0.36 '@types/lodash-es': specifier: ^4.17.9 - version: 4.17.9 - '@types/react-transition-group': - specifier: ^4.4.7 - version: 4.4.7 + version: 4.17.12 '@types/stats.js': specifier: ^0.17.1 - version: 0.17.1 + version: 0.17.3 '@types/three': specifier: 0.154.0 version: 0.154.0 '@types/ua-parser-js': specifier: ^0.7.39 version: 0.7.39 + '@types/wait-on': + specifier: ^5.3.4 + version: 5.3.4 '@xmcl/installer': specifier: ^5.1.0 - version: 5.1.0 + version: 5.4.0 assert: specifier: ^2.0.0 - version: 2.0.0 + version: 2.1.0 browserify-zlib: specifier: ^0.2.0 version: 0.2.0 @@ -268,44 +308,47 @@ importers: specifier: ^1.0.0 version: 1.0.0 contro-max: - specifier: ^0.1.8 - version: 0.1.8(typescript@5.5.0-beta) + specifier: ^0.1.9 + version: 0.1.9(typescript@5.5.4) crypto-browserify: specifier: ^3.12.0 - version: 3.12.0 - cypress: - specifier: ^10.11.0 - version: 10.11.0 + version: 3.12.1 cypress-esbuild-preprocessor: specifier: ^1.0.2 version: 1.0.2 eslint: specifier: ^8.50.0 - version: 8.50.0 + version: 8.57.1 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.5.0-beta) + version: 0.2.17(eslint-plugin-react-hooks@5.2.0(eslint@8.57.1))(eslint-plugin-react@7.37.4(eslint@8.57.1))(eslint@8.57.1)(typescript@5.5.4) events: specifier: ^3.3.0 version: 3.3.0 + gzip-size: + specifier: ^7.0.0 + version: 7.0.0 http-browserify: specifier: ^1.7.0 version: 1.7.0 http-server: specifier: ^14.1.1 - version: 14.1.1(debug@4.3.4) + version: 14.1.1(debug@4.4.0) https-browserify: specifier: ^1.0.0 version: 1.0.0 + mc-assets: + specifier: ^0.2.62 + version: 0.2.62 minecraft-inventory-gui: 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) + version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/89c33d396f3fde4804c71f4be3c203ade1833b41(@types/react@18.3.18)(react@18.3.1) mineflayer: - specifier: github:PrismarineJS/mineflayer - version: https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f(encoding@0.1.13) - mineflayer-pathfinder: - specifier: ^2.4.4 - version: 2.4.4 + specifier: github:zardoy/mineflayer#gen-the-master + version: https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13) + mineflayer-mouse: + specifier: ^0.1.21 + version: 0.1.21 npm-run-all: specifier: ^4.1.5 version: 4.1.5 @@ -318,18 +361,18 @@ importers: path-exists-cli: specifier: ^2.0.0 version: 2.0.0 - prismarine-viewer: - specifier: link:prismarine-viewer - version: link:prismarine-viewer process: specifier: github:PrismarineJS/node-process version: https://codeload.github.com/PrismarineJS/node-process/tar.gz/380d0b4f4c86f1b65b216c311bf00431f314e88e + renderer: + specifier: link:renderer + version: link:renderer rimraf: specifier: ^5.0.1 - version: 5.0.1 + version: 5.0.10 storybook: specifier: ^7.4.6 - version: 7.4.6(encoding@0.1.13) + version: 7.6.20(encoding@0.1.13) stream-browserify: specifier: ^3.0.0 version: 3.0.0 @@ -340,99 +383,109 @@ importers: specifier: ^2.0.12 version: 2.0.12 typescript: - specifier: 5.5.0-beta - version: 5.5.0-beta + specifier: 5.5.4 + version: 5.5.4 vitest: specifier: ^0.34.6 - version: 0.34.6(terser@5.19.2) + version: 0.34.6(terser@5.39.0) yaml: specifier: ^2.3.2 - version: 2.3.2 + version: 2.7.0 + optionalDependencies: + cypress: + specifier: ^10.11.0 + version: 10.11.0 + cypress-plugin-snapshots: + specifier: ^1.4.4 + version: 1.4.4(cypress@10.11.0)(debug@4.4.0) + sharp: + specifier: ^0.33.5 + version: 0.33.5 + systeminformation: + specifier: ^5.21.22 + version: 5.25.11 - prismarine-viewer: + renderer: dependencies: '@tweenjs/tween.js': specifier: ^20.0.3 version: 20.0.3 assert: specifier: ^2.0.0 - version: 2.0.0 + version: 2.1.0 buffer: specifier: ^6.0.3 version: 6.0.3 - canvas: - specifier: ^2.11.2 - version: 2.11.2(encoding@0.1.13) filesize: specifier: ^10.0.12 - version: 10.0.12 + version: 10.1.6 fs-extra: specifier: ^11.0.0 - version: 11.1.1 + version: 11.3.0 lil-gui: specifier: ^0.18.2 version: 0.18.2 - looks-same: - specifier: ^8.2.3 - version: 8.2.3 minecraft-wrap: specifier: ^1.3.0 - version: 1.5.1(encoding@0.1.13) + version: 1.6.0(encoding@0.1.13) minecrafthawkeye: specifier: ^1.3.6 - version: 1.3.6 + version: 1.3.9 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/853c559bff2b402863ee9a75b125a3ca320838f9 prismarine-chunk: - specifier: github:zardoy/prismarine-chunk - version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + specifier: github:zardoy/prismarine-chunk#master + version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0) prismarine-schematic: specifier: ^1.2.0 version: 1.2.3 - prismarine-viewer: - specifier: link:./ - version: 'link:' process: specifier: ^0.11.10 version: 0.11.10 + renderer: + specifier: link:./ + version: 'link:' socket.io: specifier: ^4.0.0 - version: 4.7.2 + version: 4.8.1 socket.io-client: specifier: ^4.0.0 - version: 4.7.2 + version: 4.8.1 three-stdlib: specifier: ^2.26.11 - version: 2.28.5(three@0.154.0) + version: 2.35.14(three@0.154.0) three.meshline: specifier: ^1.3.0 version: 1.4.0 tsx: specifier: ^4.7.0 - version: 4.7.0 + version: 4.19.3 vec3: - specifier: ^0.1.7 - version: 0.1.8 + specifier: 0.1.10 + version: 0.1.10 + devDependencies: + live-server: + specifier: ^1.2.2 + version: 1.2.2 optionalDependencies: + canvas: + specifier: ^2.11.2 + version: 2.11.2(encoding@0.1.13) node-canvas-webgl: specifier: ^0.3.0 version: 0.3.0(encoding@0.1.13) - prismarine-viewer/viewer/sign-renderer: + renderer/viewer/sign-renderer: dependencies: vite: specifier: ^4.4.9 - version: 4.4.10(@types/node@20.12.8)(terser@5.19.2) + version: 4.5.9(@types/node@22.13.9)(terser@5.39.0) packages: - '@aashutoshrathi/word-wrap@1.2.6': - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} - - '@ampproject/remapping@2.2.1': - resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} '@apideck/better-ajv-errors@0.3.6': @@ -445,210 +498,147 @@ packages: resolution: {integrity: sha512-Xk1sIhyNC/esHGGVjL/niHLowM0csl/kFO5uawBy4IrWwy0o1G8LGt3jP6nmWGz+USxeeqbihAmp/oVZju6wug==} hasBin: true - '@azure/msal-common@14.9.0': - resolution: {integrity: sha512-yzBPRlWPnTBeixxLNI3BBIgF5/bHpbhoRVuuDBnYjCyWRavaPUsKAHUDYLqpGkBLDciA6TCc6GOxN4/S3WiSxg==} + '@azure/msal-common@14.16.0': + resolution: {integrity: sha512-1KOZj9IpcDSwpNiQNjt0jDYZpQvNZay7QAEi/5DLubay40iGYtLzya/jbjRPLyOTZhEKyL1MzPuw2HqBCjceYA==} engines: {node: '>=0.8.0'} - '@azure/msal-node@2.7.0': - resolution: {integrity: sha512-wXD8LkUvHICeSWZydqg6o8Yvv+grlBEcmLGu+QEI4FcwFendbTEZrlSygnAXXSOCVaGAirWLchca35qrgpO6Jw==} + '@azure/msal-node@2.16.2': + resolution: {integrity: sha512-An7l1hEr0w1HMMh1LU+rtDtqL7/jw74ORlc9Wnh06v7TU/xpG39/Zdr1ZJu3QpjUfKJ+E0/OXMW8DRSWTlh7qQ==} engines: {node: '>=16'} - '@babel/code-frame@7.22.13': - resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.22.9': - resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==} + '@babel/compat-data@7.26.8': + resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==} engines: {node: '>=6.9.0'} - '@babel/core@7.22.11': - resolution: {integrity: sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ==} + '@babel/core@7.26.9': + resolution: {integrity: sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.22.10': - resolution: {integrity: sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==} + '@babel/generator@7.26.9': + resolution: {integrity: sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==} engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.22.5': - resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} + '@babel/helper-annotate-as-pure@7.25.9': + resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} engines: {node: '>=6.9.0'} - '@babel/helper-builder-binary-assignment-operator-visitor@7.22.10': - resolution: {integrity: sha512-Av0qubwDQxC56DoUReVDeLfMEjYYSN1nZrTUrWkXd7hpU73ymRANkbuDm3yni9npkn+RXy9nNbEJZEzXr7xrfQ==} + '@babel/helper-compilation-targets@7.26.5': + resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.22.10': - resolution: {integrity: sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-create-class-features-plugin@7.22.11': - resolution: {integrity: sha512-y1grdYL4WzmUDBRGK0pDbIoFd7UZKoDurDzWEoNMYoj1EL+foGRQNyPWDcC+YyegN5y1DUsFFmzjGijB3nSVAQ==} + '@babel/helper-create-class-features-plugin@7.26.9': + resolution: {integrity: sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-class-features-plugin@7.22.15': - resolution: {integrity: sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==} + '@babel/helper-create-regexp-features-plugin@7.26.3': + resolution: {integrity: sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-regexp-features-plugin@7.22.9': - resolution: {integrity: sha512-+svjVa/tFwsNSG4NEy1h85+HQ5imbT92Q5/bgtS7P0GTQlP8WuFdqsiABmQouhiFGyV66oGxZFpeYHza1rNsKw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-define-polyfill-provider@0.4.2': - resolution: {integrity: sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==} + '@babel/helper-define-polyfill-provider@0.6.3': + resolution: {integrity: sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - '@babel/helper-environment-visitor@7.22.20': - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + '@babel/helper-member-expression-to-functions@7.25.9': + resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} engines: {node: '>=6.9.0'} - '@babel/helper-environment-visitor@7.22.5': - resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} engines: {node: '>=6.9.0'} - '@babel/helper-function-name@7.22.5': - resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-hoist-variables@7.22.5': - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-member-expression-to-functions@7.22.5': - resolution: {integrity: sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-member-expression-to-functions@7.23.0': - resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.22.15': - resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.22.5': - resolution: {integrity: sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.22.9': - resolution: {integrity: sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==} + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-module-transforms@7.23.0': - resolution: {integrity: sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==} + '@babel/helper-optimise-call-expression@7.25.9': + resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.26.5': + resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-remap-async-to-generator@7.25.9': + resolution: {integrity: sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-optimise-call-expression@7.22.5': - resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-plugin-utils@7.22.5': - resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-remap-async-to-generator@7.22.9': - resolution: {integrity: sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==} + '@babel/helper-replace-supers@7.26.5': + resolution: {integrity: sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-replace-supers@7.22.9': - resolution: {integrity: sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-simple-access@7.22.5': - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==} engines: {node: '>=6.9.0'} - '@babel/helper-skip-transparent-expression-wrappers@7.22.5': - resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} engines: {node: '>=6.9.0'} - '@babel/helper-split-export-declaration@7.22.6': - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.22.5': - resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.22.20': - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + '@babel/helper-wrap-function@7.25.9': + resolution: {integrity: sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.22.5': - resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} + '@babel/helpers@7.26.9': + resolution: {integrity: sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.22.15': - resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.22.5': - resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-wrap-function@7.22.10': - resolution: {integrity: sha512-OnMhjWjuGYtdoO3FmsEFWvBStBAe2QOgwOLsLNDjN+aaiMD8InJk1/O3HSD8lkqTjCgg5YI34Tz15KNNA3p+nQ==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.22.11': - resolution: {integrity: sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==} - engines: {node: '>=6.9.0'} - - '@babel/highlight@7.22.13': - resolution: {integrity: sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.22.13': - resolution: {integrity: sha512-3l6+4YOvc9wx7VlCSw4yQfcBo01ECA8TicQfbnCPuCEpRQrf+gTUyGdxNw+pyTUyywp6JRD1w0YQs9TpBXYlkw==} + '@babel/parser@7.26.9': + resolution: {integrity: sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.22.5': - resolution: {integrity: sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ==} + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9': + resolution: {integrity: sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.22.5': - resolution: {integrity: sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g==} + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9': + resolution: {integrity: sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9': + resolution: {integrity: sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9': + resolution: {integrity: sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 - '@babel/plugin-proposal-class-properties@7.18.6': - resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9': + resolution: {integrity: sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==} engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead. peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6': - resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} - engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead. - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-proposal-optional-chaining@7.21.0': - resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} - engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead. - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.0.0 '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} @@ -656,110 +646,32 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-async-generators@7.8.4': - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-class-properties@7.12.13': - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-class-static-block@7.14.5': - resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + '@babel/plugin-syntax-flow@7.26.0': + resolution: {integrity: sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-dynamic-import@7.8.3': - resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-export-namespace-from@7.8.3': - resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-flow@7.22.5': - resolution: {integrity: sha512-9RdCl0i+q0QExayk2nOS7853w08yLucnnPML6EN9S8fgMPVtdLDCdx/cOQ/i44Lb9UeQX9A35yaqBBOMMZxPxQ==} + '@babel/plugin-syntax-import-assertions@7.26.0': + resolution: {integrity: sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.22.5': - resolution: {integrity: sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==} + '@babel/plugin-syntax-import-attributes@7.26.0': + resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.22.5': - resolution: {integrity: sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==} + '@babel/plugin-syntax-jsx@7.25.9': + resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-meta@7.10.4': - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-json-strings@7.8.3': - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-jsx@7.22.5': - resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-logical-assignment-operators@7.10.4': - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-numeric-separator@7.10.4': - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-object-rest-spread@7.8.3': - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-optional-catch-binding@7.8.3': - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-optional-chaining@7.8.3': - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-private-property-in-object@7.14.5': - resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-top-level-await@7.14.5': - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-typescript@7.22.5': - resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} + '@babel/plugin-syntax-typescript@7.25.9': + resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -770,332 +682,338 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-arrow-functions@7.22.5': - resolution: {integrity: sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==} + '@babel/plugin-transform-arrow-functions@7.25.9': + resolution: {integrity: sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-generator-functions@7.22.11': - resolution: {integrity: sha512-0pAlmeRJn6wU84zzZsEOx1JV1Jf8fqO9ok7wofIJwUnplYo247dcd24P+cMJht7ts9xkzdtB0EPHmOb7F+KzXw==} + '@babel/plugin-transform-async-generator-functions@7.26.8': + resolution: {integrity: sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-to-generator@7.22.5': - resolution: {integrity: sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==} + '@babel/plugin-transform-async-to-generator@7.25.9': + resolution: {integrity: sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoped-functions@7.22.5': - resolution: {integrity: sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==} + '@babel/plugin-transform-block-scoped-functions@7.26.5': + resolution: {integrity: sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.22.10': - resolution: {integrity: sha512-1+kVpGAOOI1Albt6Vse7c8pHzcZQdQKW+wJH+g8mCaszOdDVwRXa/slHPqIw+oJAJANTKDMuM2cBdV0Dg618Vg==} + '@babel/plugin-transform-block-scoping@7.25.9': + resolution: {integrity: sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-properties@7.22.5': - resolution: {integrity: sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==} + '@babel/plugin-transform-class-properties@7.25.9': + resolution: {integrity: sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-static-block@7.22.11': - resolution: {integrity: sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==} + '@babel/plugin-transform-class-static-block@7.26.0': + resolution: {integrity: sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 - '@babel/plugin-transform-classes@7.22.6': - resolution: {integrity: sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==} + '@babel/plugin-transform-classes@7.25.9': + resolution: {integrity: sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-computed-properties@7.22.5': - resolution: {integrity: sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==} + '@babel/plugin-transform-computed-properties@7.25.9': + resolution: {integrity: sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.22.10': - resolution: {integrity: sha512-dPJrL0VOyxqLM9sritNbMSGx/teueHF/htMKrPT7DNxccXxRDPYqlgPFFdr8u+F+qUZOkZoXue/6rL5O5GduEw==} + '@babel/plugin-transform-destructuring@7.25.9': + resolution: {integrity: sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-dotall-regex@7.22.5': - resolution: {integrity: sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==} + '@babel/plugin-transform-dotall-regex@7.25.9': + resolution: {integrity: sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-keys@7.22.5': - resolution: {integrity: sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==} + '@babel/plugin-transform-duplicate-keys@7.25.9': + resolution: {integrity: sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-dynamic-import@7.22.11': - resolution: {integrity: sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-exponentiation-operator@7.22.5': - resolution: {integrity: sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-export-namespace-from@7.22.11': - resolution: {integrity: sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-flow-strip-types@7.22.5': - resolution: {integrity: sha512-tujNbZdxdG0/54g/oua8ISToaXTFBf8EnSb5PgQSciIXWOWKX3S4+JR7ZE9ol8FZwf9kxitzkGQ+QWeov/mCiA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-for-of@7.22.5': - resolution: {integrity: sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-function-name@7.22.5': - resolution: {integrity: sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-json-strings@7.22.11': - resolution: {integrity: sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-literals@7.22.5': - resolution: {integrity: sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-logical-assignment-operators@7.22.11': - resolution: {integrity: sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-member-expression-literals@7.22.5': - resolution: {integrity: sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-amd@7.22.5': - resolution: {integrity: sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-commonjs@7.22.11': - resolution: {integrity: sha512-o2+bg7GDS60cJMgz9jWqRUsWkMzLCxp+jFDeDUT5sjRlAxcJWZ2ylNdI7QQ2+CH5hWu7OnN+Cv3htt7AkSf96g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-commonjs@7.23.0': - resolution: {integrity: sha512-32Xzss14/UVc7k9g775yMIvkVK8xwKE0DPdP5JTapr3+Z9w4tzeOuLNY6BXDQR6BdnzIlXnCGAzsk/ICHBLVWQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-systemjs@7.22.11': - resolution: {integrity: sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-umd@7.22.5': - resolution: {integrity: sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-named-capturing-groups-regex@7.22.5': - resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9': + resolution: {integrity: sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-new-target@7.22.5': - resolution: {integrity: sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==} + '@babel/plugin-transform-dynamic-import@7.25.9': + resolution: {integrity: sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-nullish-coalescing-operator@7.22.11': - resolution: {integrity: sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==} + '@babel/plugin-transform-exponentiation-operator@7.26.3': + resolution: {integrity: sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-numeric-separator@7.22.11': - resolution: {integrity: sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==} + '@babel/plugin-transform-export-namespace-from@7.25.9': + resolution: {integrity: sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-rest-spread@7.22.11': - resolution: {integrity: sha512-nX8cPFa6+UmbepISvlf5jhQyaC7ASs/7UxHmMkuJ/k5xSHvDPPaibMo+v3TXwU/Pjqhep/nFNpd3zn4YR59pnw==} + '@babel/plugin-transform-flow-strip-types@7.26.5': + resolution: {integrity: sha512-eGK26RsbIkYUns3Y8qKl362juDDYK+wEdPGHGrhzUl6CewZFo55VZ7hg+CyMFU4dd5QQakBN86nBMpRsFpRvbQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-super@7.22.5': - resolution: {integrity: sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==} + '@babel/plugin-transform-for-of@7.26.9': + resolution: {integrity: sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-catch-binding@7.22.11': - resolution: {integrity: sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==} + '@babel/plugin-transform-function-name@7.25.9': + resolution: {integrity: sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.22.12': - resolution: {integrity: sha512-7XXCVqZtyFWqjDsYDY4T45w4mlx1rf7aOgkc/Ww76xkgBiOlmjPkx36PBLHa1k1rwWvVgYMPsbuVnIamx2ZQJw==} + '@babel/plugin-transform-json-strings@7.25.9': + resolution: {integrity: sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-parameters@7.22.5': - resolution: {integrity: sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==} + '@babel/plugin-transform-literals@7.25.9': + resolution: {integrity: sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-methods@7.22.5': - resolution: {integrity: sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==} + '@babel/plugin-transform-logical-assignment-operators@7.25.9': + resolution: {integrity: sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-property-in-object@7.22.11': - resolution: {integrity: sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==} + '@babel/plugin-transform-member-expression-literals@7.25.9': + resolution: {integrity: sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-property-literals@7.22.5': - resolution: {integrity: sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==} + '@babel/plugin-transform-modules-amd@7.25.9': + resolution: {integrity: sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-self@7.22.5': - resolution: {integrity: sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==} + '@babel/plugin-transform-modules-commonjs@7.26.3': + resolution: {integrity: sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-source@7.22.5': - resolution: {integrity: sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==} + '@babel/plugin-transform-modules-systemjs@7.25.9': + resolution: {integrity: sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.22.10': - resolution: {integrity: sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==} + '@babel/plugin-transform-modules-umd@7.25.9': + resolution: {integrity: sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-reserved-words@7.22.5': - resolution: {integrity: sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-shorthand-properties@7.22.5': - resolution: {integrity: sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-spread@7.22.5': - resolution: {integrity: sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-sticky-regex@7.22.5': - resolution: {integrity: sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-template-literals@7.22.5': - resolution: {integrity: sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-typeof-symbol@7.22.5': - resolution: {integrity: sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-typescript@7.22.15': - resolution: {integrity: sha512-1uirS0TnijxvQLnlv5wQBwOX3E1wCFX7ITv+9pBV2wKEk4K+M5tqDaoNXnTH8tjEIYHLO98MwiTWO04Ggz4XuA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-escapes@7.22.10': - resolution: {integrity: sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-property-regex@7.22.5': - resolution: {integrity: sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-regex@7.22.5': - resolution: {integrity: sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-sets-regex@7.22.5': - resolution: {integrity: sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==} + '@babel/plugin-transform-named-capturing-groups-regex@7.25.9': + resolution: {integrity: sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.22.10': - resolution: {integrity: sha512-riHpLb1drNkpLlocmSyEg4oYJIQFeXAK/d7rI6mbD0XsvoTOOweXDmQPG/ErxsEhWk3rl3Q/3F6RFQlVFS8m0A==} + '@babel/plugin-transform-new-target@7.25.9': + resolution: {integrity: sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/preset-flow@7.22.15': - resolution: {integrity: sha512-dB5aIMqpkgbTfN5vDdTRPzjqtWiZcRESNR88QYnoPR+bmdYoluOzMX9tQerTv0XzSgZYctPfO1oc0N5zdog1ew==} + '@babel/plugin-transform-nullish-coalescing-operator@7.26.6': + resolution: {integrity: sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-numeric-separator@7.25.9': + resolution: {integrity: sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-rest-spread@7.25.9': + resolution: {integrity: sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-super@7.25.9': + resolution: {integrity: sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-catch-binding@7.25.9': + resolution: {integrity: sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-chaining@7.25.9': + resolution: {integrity: sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-parameters@7.25.9': + resolution: {integrity: sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-methods@7.25.9': + resolution: {integrity: sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-property-in-object@7.25.9': + resolution: {integrity: sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-property-literals@7.25.9': + resolution: {integrity: sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-self@7.25.9': + resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.25.9': + resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regenerator@7.25.9': + resolution: {integrity: sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regexp-modifiers@7.26.0': + resolution: {integrity: sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-reserved-words@7.25.9': + resolution: {integrity: sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-shorthand-properties@7.25.9': + resolution: {integrity: sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-spread@7.25.9': + resolution: {integrity: sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-sticky-regex@7.25.9': + resolution: {integrity: sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-template-literals@7.26.8': + resolution: {integrity: sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typeof-symbol@7.26.7': + resolution: {integrity: sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.26.8': + resolution: {integrity: sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-escapes@7.25.9': + resolution: {integrity: sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-property-regex@7.25.9': + resolution: {integrity: sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-regex@7.25.9': + resolution: {integrity: sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-sets-regex@7.25.9': + resolution: {integrity: sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/preset-env@7.26.9': + resolution: {integrity: sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-flow@7.25.9': + resolution: {integrity: sha512-EASHsAhE+SSlEzJ4bzfusnXSHiU+JfAYzj+jbw2vgQKgq5HrUr8qs+vgtiEL5dOH6sEweI+PNt2D7AqrDSHyqQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1105,81 +1023,37 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - '@babel/preset-typescript@7.23.0': - resolution: {integrity: sha512-6P6VVa/NM/VlAYj5s2Aq/gdVg8FSENCg3wlZ6Qau9AcPaoF5LbN1nyGlR9DTRIw9PpxI94e+ReydsJHcjwAweg==} + '@babel/preset-typescript@7.26.0': + resolution: {integrity: sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/register@7.22.15': - resolution: {integrity: sha512-V3Q3EqoQdn65RCgTLwauZaTfd1ShhwPmbBv+1dkZV/HpCGMKVyn6oFcRlI7RaKqiDQjX2Qd3AuoEguBgdjIKlg==} + '@babel/register@7.25.9': + resolution: {integrity: sha512-8D43jXtGsYmEeDvm4MWHYUpWf8iiXgWYx3fW7E7Wb7Oe6FWqJPl5K6TuFW0dOwNZzEE5rjlaSJYH9JjrUKJszA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/regjsgen@0.8.0': - resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} - - '@babel/runtime@7.22.11': - resolution: {integrity: sha512-ee7jVNlWN09+KftVOu9n7S8gQzD/Z6hN/I8VBRXW4P1+Xe7kJGXMwu8vds4aGIMHZnNbdpSWCfZZtinytpcAvA==} + '@babel/runtime@7.26.9': + resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.24.5': - resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==} + '@babel/template@7.26.9': + resolution: {integrity: sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==} engines: {node: '>=6.9.0'} - '@babel/template@7.22.5': - resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} + '@babel/traverse@7.26.9': + resolution: {integrity: sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.22.11': - resolution: {integrity: sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.22.11': - resolution: {integrity: sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.23.0': - resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==} + '@babel/types@7.26.9': + resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} engines: {node: '>=6.9.0'} '@base2/pretty-print-object@1.0.1': resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==} - '@bcoe/v8-coverage@0.2.3': - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - - '@cbor-extract/cbor-extract-darwin-arm64@2.2.0': - resolution: {integrity: sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==} - cpu: [arm64] - os: [darwin] - - '@cbor-extract/cbor-extract-darwin-x64@2.2.0': - resolution: {integrity: sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==} - cpu: [x64] - os: [darwin] - - '@cbor-extract/cbor-extract-linux-arm64@2.2.0': - resolution: {integrity: sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==} - cpu: [arm64] - os: [linux] - - '@cbor-extract/cbor-extract-linux-arm@2.2.0': - resolution: {integrity: sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==} - cpu: [arm] - os: [linux] - - '@cbor-extract/cbor-extract-linux-x64@2.2.0': - resolution: {integrity: sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==} - cpu: [x64] - os: [linux] - - '@cbor-extract/cbor-extract-win32-x64@2.2.0': - resolution: {integrity: sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==} - cpu: [x64] - os: [win32] - '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -1200,11 +1074,14 @@ packages: resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} - '@emotion/babel-plugin@11.11.0': - resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} + '@emnapi/runtime@1.3.1': + resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} - '@emotion/cache@11.11.0': - resolution: {integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==} + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} '@emotion/css@11.5.0': resolution: {integrity: sha512-mqjz/3aqR9rp40M+pvwdKYWxlQK4Nj3cnNjo3Tx6SM14dSsEn7q/4W2/I7PlgG+mb27iITHugXuBIHH/QwUBVQ==} @@ -1214,53 +1091,68 @@ packages: '@babel/core': optional: true - '@emotion/hash@0.9.1': - resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} - '@emotion/memoize@0.8.1': - resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} - '@emotion/serialize@1.1.2': - resolution: {integrity: sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==} + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + peerDependencies: + '@types/react': '*' + react: ^18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true - '@emotion/sheet@1.2.2': - resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==} + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} - '@emotion/unitless@0.8.1': - resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} - '@emotion/use-insertion-effect-with-fallbacks@1.0.1': - resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==} + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} peerDependencies: react: ^18.2.0 - '@emotion/utils@1.2.1': - resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==} + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} - '@emotion/weak-memoize@0.3.1': - resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==} + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@esbuild/aix-ppc64@0.19.11': - resolution: {integrity: sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==} + '@esbuild/aix-ppc64@0.19.12': + resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.25.0': + resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.18.20': resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.19.11': - resolution: {integrity: sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==} + '@esbuild/android-arm64@0.19.12': + resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} engines: {node: '>=12'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.19.3': - resolution: {integrity: sha512-w+Akc0vv5leog550kjJV9Ru+MXMR2VuMrui3C61mnysim0gkFCPOUTAfzTP0qX+HpN9Syu3YA3p1hf3EPqObRw==} - engines: {node: '>=12'} + '@esbuild/android-arm64@0.25.0': + resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==} + engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -1270,15 +1162,15 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.19.11': - resolution: {integrity: sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==} + '@esbuild/android-arm@0.19.12': + resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} engines: {node: '>=12'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.19.3': - resolution: {integrity: sha512-Lemgw4io4VZl9GHJmjiBGzQ7ONXRfRPHcUEerndjwiSkbxzrpq0Uggku5MxxrXdwJ+pTj1qyw4jwTu7hkPsgIA==} - engines: {node: '>=12'} + '@esbuild/android-arm@0.25.0': + resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==} + engines: {node: '>=18'} cpu: [arm] os: [android] @@ -1288,15 +1180,15 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.19.11': - resolution: {integrity: sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==} + '@esbuild/android-x64@0.19.12': + resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} engines: {node: '>=12'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.19.3': - resolution: {integrity: sha512-FKQJKkK5MXcBHoNZMDNUAg1+WcZlV/cuXrWCoGF/TvdRiYS4znA0m5Il5idUwfxrE20bG/vU1Cr5e1AD6IEIjQ==} - engines: {node: '>=12'} + '@esbuild/android-x64@0.25.0': + resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==} + engines: {node: '>=18'} cpu: [x64] os: [android] @@ -1306,15 +1198,15 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.19.11': - resolution: {integrity: sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==} + '@esbuild/darwin-arm64@0.19.12': + resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.19.3': - resolution: {integrity: sha512-kw7e3FXU+VsJSSSl2nMKvACYlwtvZB8RUIeVShIEY6PVnuZ3c9+L9lWB2nWeeKWNNYDdtL19foCQ0ZyUL7nqGw==} - engines: {node: '>=12'} + '@esbuild/darwin-arm64@0.25.0': + resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -1324,15 +1216,15 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.19.11': - resolution: {integrity: sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==} + '@esbuild/darwin-x64@0.19.12': + resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.19.3': - resolution: {integrity: sha512-tPfZiwF9rO0jW6Jh9ipi58N5ZLoSjdxXeSrAYypy4psA2Yl1dAMhM71KxVfmjZhJmxRjSnb29YlRXXhh3GqzYw==} - engines: {node: '>=12'} + '@esbuild/darwin-x64@0.25.0': + resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -1342,15 +1234,15 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.19.11': - resolution: {integrity: sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==} + '@esbuild/freebsd-arm64@0.19.12': + resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.19.3': - resolution: {integrity: sha512-ERDyjOgYeKe0Vrlr1iLrqTByB026YLPzTytDTz1DRCYM+JI92Dw2dbpRHYmdqn6VBnQ9Bor6J8ZlNwdZdxjlSg==} - engines: {node: '>=12'} + '@esbuild/freebsd-arm64@0.25.0': + resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -1360,15 +1252,15 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.19.11': - resolution: {integrity: sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==} + '@esbuild/freebsd-x64@0.19.12': + resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.19.3': - resolution: {integrity: sha512-nXesBZ2Ad1qL+Rm3crN7NmEVJ5uvfLFPLJev3x1j3feCQXfAhoYrojC681RhpdOph8NsvKBBwpYZHR7W0ifTTA==} - engines: {node: '>=12'} + '@esbuild/freebsd-x64@0.25.0': + resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -1378,15 +1270,15 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.19.11': - resolution: {integrity: sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==} + '@esbuild/linux-arm64@0.19.12': + resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.19.3': - resolution: {integrity: sha512-qXvYKmXj8GcJgWq3aGvxL/JG1ZM3UR272SdPU4QSTzD0eymrM7leiZH77pvY3UetCy0k1xuXZ+VPvoJNdtrsWQ==} - engines: {node: '>=12'} + '@esbuild/linux-arm64@0.25.0': + resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -1396,15 +1288,15 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.19.11': - resolution: {integrity: sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==} + '@esbuild/linux-arm@0.19.12': + resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} engines: {node: '>=12'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.19.3': - resolution: {integrity: sha512-zr48Cg/8zkzZCzDHNxXO/89bf9e+r4HtzNUPoz4GmgAkF1gFAFmfgOdCbR8zMbzFDGb1FqBBhdXUpcTQRYS1cQ==} - engines: {node: '>=12'} + '@esbuild/linux-arm@0.25.0': + resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==} + engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -1414,15 +1306,15 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.19.11': - resolution: {integrity: sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==} + '@esbuild/linux-ia32@0.19.12': + resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} engines: {node: '>=12'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.19.3': - resolution: {integrity: sha512-7XlCKCA0nWcbvYpusARWkFjRQNWNGlt45S+Q18UeS///K6Aw8bB2FKYe9mhVWy/XLShvCweOLZPrnMswIaDXQA==} - engines: {node: '>=12'} + '@esbuild/linux-ia32@0.25.0': + resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -1432,15 +1324,15 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.19.11': - resolution: {integrity: sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==} + '@esbuild/linux-loong64@0.19.12': + resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.19.3': - resolution: {integrity: sha512-qGTgjweER5xqweiWtUIDl9OKz338EQqCwbS9c2Bh5jgEH19xQ1yhgGPNesugmDFq+UUSDtWgZ264st26b3de8A==} - engines: {node: '>=12'} + '@esbuild/linux-loong64@0.25.0': + resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -1450,15 +1342,15 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.19.11': - resolution: {integrity: sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==} + '@esbuild/linux-mips64el@0.19.12': + resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.19.3': - resolution: {integrity: sha512-gy1bFskwEyxVMFRNYSvBauDIWNggD6pyxUksc0MV9UOBD138dKTzr8XnM2R4mBsHwVzeuIH8X5JhmNs2Pzrx+A==} - engines: {node: '>=12'} + '@esbuild/linux-mips64el@0.25.0': + resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -1468,15 +1360,15 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.19.11': - resolution: {integrity: sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==} + '@esbuild/linux-ppc64@0.19.12': + resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.19.3': - resolution: {integrity: sha512-UrYLFu62x1MmmIe85rpR3qou92wB9lEXluwMB/STDzPF9k8mi/9UvNsG07Tt9AqwPQXluMQ6bZbTzYt01+Ue5g==} - engines: {node: '>=12'} + '@esbuild/linux-ppc64@0.25.0': + resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -1486,15 +1378,15 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.19.11': - resolution: {integrity: sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==} + '@esbuild/linux-riscv64@0.19.12': + resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.19.3': - resolution: {integrity: sha512-9E73TfyMCbE+1AwFOg3glnzZ5fBAFK4aawssvuMgCRqCYzE0ylVxxzjEfut8xjmKkR320BEoMui4o/t9KA96gA==} - engines: {node: '>=12'} + '@esbuild/linux-riscv64@0.25.0': + resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -1504,15 +1396,15 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.19.11': - resolution: {integrity: sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==} + '@esbuild/linux-s390x@0.19.12': + resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} engines: {node: '>=12'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.19.3': - resolution: {integrity: sha512-LlmsbuBdm1/D66TJ3HW6URY8wO6IlYHf+ChOUz8SUAjVTuaisfuwCOAgcxo3Zsu3BZGxmI7yt//yGOxV+lHcEA==} - engines: {node: '>=12'} + '@esbuild/linux-s390x@0.25.0': + resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -1522,51 +1414,63 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.19.11': - resolution: {integrity: sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==} + '@esbuild/linux-x64@0.19.12': + resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} engines: {node: '>=12'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.19.3': - resolution: {integrity: sha512-ogV0+GwEmvwg/8ZbsyfkYGaLACBQWDvO0Kkh8LKBGKj9Ru8VM39zssrnu9Sxn1wbapA2qNS6BiLdwJZGouyCwQ==} - engines: {node: '>=12'} + '@esbuild/linux-x64@0.25.0': + resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==} + engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/netbsd-arm64@0.25.0': + resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.18.20': resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.19.11': - resolution: {integrity: sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==} + '@esbuild/netbsd-x64@0.19.12': + resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.19.3': - resolution: {integrity: sha512-o1jLNe4uzQv2DKXMlmEzf66Wd8MoIhLNO2nlQBHLtWyh2MitDG7sMpfCO3NTcoTMuqHjfufgUQDFRI5C+xsXQw==} - engines: {node: '>=12'} + '@esbuild/netbsd-x64@0.25.0': + resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/openbsd-arm64@0.25.0': + resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.18.20': resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.19.11': - resolution: {integrity: sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==} + '@esbuild/openbsd-x64@0.19.12': + resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.19.3': - resolution: {integrity: sha512-AZJCnr5CZgZOdhouLcfRdnk9Zv6HbaBxjcyhq0StNcvAdVZJSKIdOiPB9az2zc06ywl0ePYJz60CjdKsQacp5Q==} - engines: {node: '>=12'} + '@esbuild/openbsd-x64@0.25.0': + resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -1576,15 +1480,15 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.19.11': - resolution: {integrity: sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==} + '@esbuild/sunos-x64@0.19.12': + resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} engines: {node: '>=12'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.19.3': - resolution: {integrity: sha512-Acsujgeqg9InR4glTRvLKGZ+1HMtDm94ehTIHKhJjFpgVzZG9/pIcWW/HA/DoMfEyXmANLDuDZ2sNrWcjq1lxw==} - engines: {node: '>=12'} + '@esbuild/sunos-x64@0.25.0': + resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -1594,15 +1498,15 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.19.11': - resolution: {integrity: sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==} + '@esbuild/win32-arm64@0.19.12': + resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.19.3': - resolution: {integrity: sha512-FSrAfjVVy7TifFgYgliiJOyYynhQmqgPj15pzLyJk8BUsnlWNwP/IAy6GAiB1LqtoivowRgidZsfpoYLZH586A==} - engines: {node: '>=12'} + '@esbuild/win32-arm64@0.25.0': + resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -1612,15 +1516,15 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.19.11': - resolution: {integrity: sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==} + '@esbuild/win32-ia32@0.19.12': + resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} engines: {node: '>=12'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.19.3': - resolution: {integrity: sha512-xTScXYi12xLOWZ/sc5RBmMN99BcXp/eEf7scUC0oeiRoiT5Vvo9AycuqCp+xdpDyAU+LkrCqEpUS9fCSZF8J3Q==} - engines: {node: '>=12'} + '@esbuild/win32-ia32@0.25.0': + resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -1630,86 +1534,190 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.19.11': - resolution: {integrity: sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==} + '@esbuild/win32-x64@0.19.12': + resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} engines: {node: '>=12'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.19.3': - resolution: {integrity: sha512-FbUN+0ZRXsypPyWE2IwIkVjDkDnJoMJARWOcFZn4KPPli+QnKqF0z1anvfaYe3ev5HFCpRDLLBDHyOALLppWHw==} - engines: {node: '>=12'} + '@esbuild/win32-x64@0.25.0': + resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==} + engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + '@eslint-community/eslint-utils@4.4.1': + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.8.0': - resolution: {integrity: sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==} + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/eslintrc@2.1.2': - resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/js@8.50.0': - resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==} + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} '@fal-works/esbuild-plugin-global-externals@2.1.2': resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==} - '@fastify/busboy@2.0.0': - resolution: {integrity: sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==} + '@fastify/busboy@2.1.1': + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} - '@floating-ui/core@1.5.0': - resolution: {integrity: sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==} + '@floating-ui/core@1.6.9': + resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} - '@floating-ui/dom@1.5.3': - resolution: {integrity: sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==} + '@floating-ui/dom@1.6.13': + resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==} - '@floating-ui/react-dom@2.0.2': - resolution: {integrity: sha512-5qhlDvjaLmAst/rKb3VdlCinwTF4EYMiVxuuc/HVUjs46W0zgtbMmAZ1UTsDrRTxRmUEzl92mOtWbeeXL26lSQ==} + '@floating-ui/react-dom@2.1.2': + resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} peerDependencies: 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==} + '@floating-ui/react@0.26.28': + resolution: {integrity: sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==} 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: - react: ^18.2.0 - react-dom: '>=16.8.0' - - '@floating-ui/utils@0.1.6': - resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} + '@floating-ui/utils@0.2.9': + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} '@gar/promisify@1.1.3': resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} - '@humanwhocodes/config-array@0.11.11': - resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@hapi/topo@5.1.0': + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/object-schema@1.2.1': - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead - '@iconify/types@2.0.0': - resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + '@img/sharp-darwin-arm64@0.33.5': + resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.33.5': + resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.0.4': + resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.0.4': + resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.0.4': + resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.0.5': + resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.0.4': + resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.0.4': + resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.33.5': + resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.33.5': + resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-s390x@0.33.5': + resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.33.5': + resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.33.5': + resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.33.5': + resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.33.5': + resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-ia32@0.33.5': + resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.33.5': + resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -1900,42 +1908,63 @@ packages: '@jimp/utils@0.10.3': resolution: {integrity: sha512-VcSlQhkil4ReYmg1KkN+WqHyYfZ2XfZxDsKAHSfST1GEz/RQHxKZbX+KhFKtKflnL0F4e6DlNQj3vznMNXCR2w==} - '@joshwooding/vite-plugin-react-docgen-typescript@0.2.1': - resolution: {integrity: sha512-ou4ZJSXMMWHqGS4g8uNRbC5TiTWxAgQZiVucoUrOCWuPrTbkpJbmVyIi9jU72SBry7gQtuMEDp4YR8EEXAg7VQ==} + '@joshwooding/vite-plugin-react-docgen-typescript@0.3.0': + resolution: {integrity: sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA==} peerDependencies: typescript: '>= 4.3.x' - vite: ^3.0.0 || ^4.0.0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 peerDependenciesMeta: typescript: optional: true - '@jridgewell/gen-mapping@0.3.3': - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} - '@jridgewell/resolve-uri@3.1.1': - resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/set-array@1.1.2': - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.5': - resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} + '@jridgewell/source-map@0.3.6': + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} - '@jridgewell/sourcemap-codec@1.4.15': - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/trace-mapping@0.3.19': - resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@jspm/core@2.0.1': - resolution: {integrity: sha512-Lg3PnLp0QXpxwLIAuuJboLeRaIhrgJjeuh797QADg3xz8wGLugQOS5DpsE8A6i6Adgzf+bacllkKZG3J0tGfDw==} + '@jsonjoy.com/base64@1.1.2': + resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pack@1.2.0': + resolution: {integrity: sha512-io1zEbbYcElht3tdlqEOFxZ0dMTYrHz9iMf0gqn1pPjZFTCgM5R4R5IMA20Chb2UPYYsxjzs8CgZ7Nb5n2K2rA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/util@1.5.0': + resolution: {integrity: sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jspm/core@2.1.0': + resolution: {integrity: sha512-3sRl+pkyFY/kLmHl0cgHiFp2xEqErA8N3ECjMs7serSUBmoJ70lBa0PG5t0IM6WJgdZNyyI0R8YFfi5wM8+mzg==} '@juggle/resize-observer@3.3.1': resolution: {integrity: sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==} + '@juggle/resize-observer@3.4.0': + resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==} + '@mapbox/node-pre-gyp@1.0.11': resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} hasBin: true @@ -1945,39 +1974,38 @@ packages: peerDependencies: react: ^18.2.0 + '@module-federation/error-codes@0.11.2': + resolution: {integrity: sha512-ik1Qnn0I+WyEdprTck9WGlH41vGsVdUg8cfO+ZM02qOb2cZm5Vu3SlxGAobj6g7uAj0g8yINnd7h7Dci40BxQA==} + + '@module-federation/runtime-core@0.11.2': + resolution: {integrity: sha512-dia5kKybi6MFU0s5PgglJwN27k7n9Sf69Cy5xZ4BWaP0qlaXTsxHKO0PECHNt2Pt8jDdyU29sQ4DwAQfxpnXJQ==} + + '@module-federation/runtime-tools@0.11.2': + resolution: {integrity: sha512-4MJTGAxVq6vxQRkTtTlH7Mm9AVqgn0X9kdu+7RsL7T/qU+jeYsbrntN2CWG3GVVA8r5JddXyTI1iJ0VXQZLV1w==} + + '@module-federation/runtime@0.11.2': + resolution: {integrity: sha512-Ya9u/L6z2LvhgpqxuKCB7LcigIIRf1BbaxAZIH7mzbq/A7rZtTP7v+73E433jvgiAlbAfPSZkeoYGele6hfRwA==} + + '@module-federation/sdk@0.11.2': + resolution: {integrity: sha512-SBFe5xOamluT900J4AGBx+2/kCH/JbfqXoUwPSAC6PRzb8Y7LB0posnOGzmqYsLZXT37vp3d6AmJDsVoajDqxw==} + + '@module-federation/webpack-bundler-runtime@0.11.2': + resolution: {integrity: sha512-WdwIE6QF+MKs/PdVu0cKPETF743JB9PZ62/qf7Uo3gU4fjsUMc37RnbJZ/qB60EaHHfjwp1v6NnhZw1r4eVsnw==} + + '@monaco-editor/loader@1.5.0': + resolution: {integrity: sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==} + + '@monaco-editor/react@4.7.0': + resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==} + peerDependencies: + monaco-editor: '>= 0.25.0 < 1' + react: ^18.2.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@msgpack/msgpack@2.8.0': 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==} @@ -2002,20 +2030,20 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} deprecated: This functionality has been moved to @npmcli/fs - '@nxg-org/mineflayer-auto-jump@0.7.7': - resolution: {integrity: sha512-50FYsz5rxBuLzOh7wqmg9iN9zdVGD+QjuaPcw/mD7q8Bq6Bq+o1/DfXfpoNGIHaDag80q6FJSpc73MI3Scid8g==} + '@nxg-org/mineflayer-auto-jump@0.7.18': + resolution: {integrity: sha512-O/nRCyWrRwFpcCXXSJhmt844c4a8KhkK4OJPAOKSc63tExIIQU/sipHgjgpy0B+gVDjSmLMPYXe71CN0W327Wg==} - '@nxg-org/mineflayer-physics-util@1.5.8': - resolution: {integrity: sha512-KmCkAqpUo8BbuRdIBs6+V2hWHehz++PRz3lRwIsb47CuG0u4sgLYh37RY3ifAznC6uWvmPK+q3B4ZXwJzPy1MQ==} + '@nxg-org/mineflayer-physics-util@1.8.10': + resolution: {integrity: sha512-JGIJEPauVmqoBFQ0I8ZtbaYo3mKn2N00srnDrWkCEt1qozyZWie4sYR0khjjwYubFCljMoWtoEA0+DLsHZLNFg==} - '@nxg-org/mineflayer-tracker@1.2.1': - resolution: {integrity: sha512-SI1ffF8zvg3/ZNE021Ja2W0FZPN+WbQDZf8yFqOcXtPRXAtM9W6HvoACdzXep8BZid7WYgYLIgjKpB+9RqvCNQ==} + '@nxg-org/mineflayer-tracker@1.3.0': + resolution: {integrity: sha512-HINrv51l2aZ/lDrcL77gSWDvf3Z3trd6kdiifXitCMDNdBT0FpWnXq9bi5Fr7yPpFGQ3fqGUIq5DQYYY84E9IA==} - '@nxg-org/mineflayer-trajectories@1.1.1': - resolution: {integrity: sha512-X103KXlX8+L3uMeK4jQxMUdTizv01sQRSfBizAF/iOAdfQZehRLXr3CYKeJzfwPYGLN0X0JCl++cMEcZVn4vbg==} + '@nxg-org/mineflayer-trajectories@1.2.0': + resolution: {integrity: sha512-yTDHn96fyWLKwdHdOGIrnt8nss4SJmxXwJn101o7aNI4sgdnUmwaX4FoNbmrEa9eZn6IwxaXIxDf+fJmKj9RIw==} - '@nxg-org/mineflayer-util-plugin@1.8.3': - resolution: {integrity: sha512-YlIbzCDs9822xuvmYlD0vXZz0iye9buqp9NK4nNn15gYybdqBtC/YxK6BLqXtwNohZCKoZdKgei7Xd5Bt2/rUg==} + '@nxg-org/mineflayer-util-plugin@1.8.4': + resolution: {integrity: sha512-hPaCZxU0Aq+gUSi/l6x7n32hUG6bnDugAMoQXD2dFE/gyNkmRSpmgH5+Y6G41w3H8P3Nl++upGCOlaxvZ7RuoA==} '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} @@ -2030,6 +2058,9 @@ packages: '@radix-ui/primitive@1.0.1': resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} + '@radix-ui/primitive@1.1.1': + resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} + '@radix-ui/react-arrow@1.0.3': resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} peerDependencies: @@ -2056,6 +2087,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-collection@1.1.2': + resolution: {integrity: sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^18.2.0 + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-compose-refs@1.0.1': resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: @@ -2065,6 +2109,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-compose-refs@1.1.1': + resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} + peerDependencies: + '@types/react': '*' + react: ^18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-context@1.0.1': resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} peerDependencies: @@ -2074,6 +2127,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-context@1.1.1': + resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} + peerDependencies: + '@types/react': '*' + react: ^18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-direction@1.0.1': resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} peerDependencies: @@ -2083,6 +2145,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-direction@1.1.0': + resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} + peerDependencies: + '@types/react': '*' + react: ^18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-dismissable-layer@1.0.4': resolution: {integrity: sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==} peerDependencies: @@ -2127,6 +2198,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-id@1.1.0': + resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} + peerDependencies: + '@types/react': '*' + react: ^18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-popper@1.1.2': resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==} peerDependencies: @@ -2166,13 +2246,26 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-roving-focus@1.0.4': - resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==} + '@radix-ui/react-primitive@2.0.2': + resolution: {integrity: sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' react: ^18.2.0 - react-dom: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.2': + resolution: {integrity: sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^18.2.0 + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2192,13 +2285,13 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-separator@1.0.3': - resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==} + '@radix-ui/react-separator@1.1.2': + resolution: {integrity: sha512-oZfHcaAp2Y6KFBX6I5P1u7CQoy4lheCGiYj+pGFrHy8E/VNRb5E39TkTr3JrV520csPBTZjkuKFdEsjS5EUNKQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' react: ^18.2.0 - react-dom: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2214,39 +2307,48 @@ packages: '@types/react': optional: true - '@radix-ui/react-toggle-group@1.0.4': - resolution: {integrity: sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==} + '@radix-ui/react-slot@1.1.2': + resolution: {integrity: sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==} + peerDependencies: + '@types/react': '*' + react: ^18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-toggle-group@1.1.2': + resolution: {integrity: sha512-JBm6s6aVG/nwuY5eadhU2zDi/IwYS0sDM5ZWb4nymv/hn3hZdkw+gENn0LP4iY1yCd7+bgJaCwueMYJIU3vk4A==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' react: ^18.2.0 - react-dom: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true '@types/react-dom': optional: true - '@radix-ui/react-toggle@1.0.3': - resolution: {integrity: sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==} + '@radix-ui/react-toggle@1.1.2': + resolution: {integrity: sha512-lntKchNWx3aCHuWKiDY+8WudiegQvBpDRAYL8dKLRvKEH8VOpl0XX6SSU/bUBqIRJbcTy4+MW06Wv8vgp10rzQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' react: ^18.2.0 - react-dom: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true '@types/react-dom': optional: true - '@radix-ui/react-toolbar@1.0.4': - resolution: {integrity: sha512-tBgmM/O7a07xbaEkYJWYTXkIdU/1pW4/KZORR43toC/4XWyBCURK0ei9kMUdp+gTPPKBgYLxXmRSH1EVcIDp8Q==} + '@radix-ui/react-toolbar@1.1.2': + resolution: {integrity: sha512-wT20eQ7ScFk+kBMDmHp+lMk18cgxhu35b2Bn5deUcPxiVwfn5vuZgi7NGcHu8ocdkinahmp4FaSZysKDyRVPWQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' react: ^18.2.0 - react-dom: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2262,6 +2364,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-callback-ref@1.1.0': + resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} + peerDependencies: + '@types/react': '*' + react: ^18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-controllable-state@1.0.1': resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} peerDependencies: @@ -2271,6 +2382,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-controllable-state@1.1.0': + resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} + peerDependencies: + '@types/react': '*' + react: ^18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-escape-keydown@1.0.3': resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} peerDependencies: @@ -2289,6 +2409,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-layout-effect@1.1.0': + resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} + peerDependencies: + '@types/react': '*' + react: ^18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-previous@1.0.1': resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} peerDependencies: @@ -2349,25 +2478,37 @@ packages: '@types/babel__core': optional: true - '@rollup/plugin-node-resolve@11.2.1': - resolution: {integrity: sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==} - engines: {node: '>= 10.0.0'} + '@rollup/plugin-node-resolve@15.3.1': + resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} + engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^1.20.0||^2.0.0 + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true '@rollup/plugin-replace@2.4.2': resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==} peerDependencies: rollup: ^1.20.0 || ^2.0.0 + '@rollup/plugin-terser@0.4.4': + resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/pluginutils@3.1.0': resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} engines: {node: '>= 8.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0 - '@rollup/pluginutils@5.0.5': - resolution: {integrity: sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==} + '@rollup/pluginutils@5.1.4': + resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 @@ -2375,133 +2516,285 @@ packages: rollup: optional: true - '@rushstack/eslint-patch@1.4.0': - resolution: {integrity: sha512-cEjvTPU32OM9lUFegJagO0mRnIn+rbqrG89vV8/xLnLFX0DoR0r1oy5IlTga71Q7uT3Qus7qm7wgeiMT/+Irlg==} + '@rollup/rollup-android-arm-eabi@4.34.9': + resolution: {integrity: sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.34.9': + resolution: {integrity: sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.34.9': + resolution: {integrity: sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.34.9': + resolution: {integrity: sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.34.9': + resolution: {integrity: sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.34.9': + resolution: {integrity: sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.34.9': + resolution: {integrity: sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.34.9': + resolution: {integrity: sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.34.9': + resolution: {integrity: sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.34.9': + resolution: {integrity: sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.34.9': + resolution: {integrity: sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.34.9': + resolution: {integrity: sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.34.9': + resolution: {integrity: sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.34.9': + resolution: {integrity: sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.34.9': + resolution: {integrity: sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.34.9': + resolution: {integrity: sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.34.9': + resolution: {integrity: sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.34.9': + resolution: {integrity: sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.34.9': + resolution: {integrity: sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==} + cpu: [x64] + os: [win32] + + '@rsbuild/core@1.3.5': + resolution: {integrity: sha512-Fn6nJ4YvLO2UtFcoSPxgJoiUdS0Iix7X1BsyZ+DCj3SGpVCxp3Td9x58F5uhcRraMZFPB91wvcS/OabYwT3N2w==} + engines: {node: '>=16.7.0'} + hasBin: true + + '@rsbuild/plugin-node-polyfill@1.3.0': + resolution: {integrity: sha512-KvckyUg9wq3F1Iv/y4+mlcnO/E7vDklvMY7kF6CxnUYImroQVw/EDS0zDezkPvcm7aKTH5b0Jaa0iIcTNFzhVw==} + peerDependencies: + '@rsbuild/core': 1.x + peerDependenciesMeta: + '@rsbuild/core': + optional: true + + '@rsbuild/plugin-react@1.2.0': + resolution: {integrity: sha512-TXd0cvcLPF7OrO215vlGSyRXD6Fc3KQWhFuXFKOtRYp+C1Vc9oeW0GopUIStv2pI2/xtv2XX8GOAdJsnsc6lkA==} + peerDependencies: + '@rsbuild/core': 1.x + + '@rsbuild/plugin-type-check@1.2.1': + resolution: {integrity: sha512-PtbjeMqDQy8IiPDTuaj8ZmvR42b0AsRq6RUF6wxa8dDsOzD0Dl1GcvemVGCto+/Dh8frLUmnlWF+T8riBw5rtA==} + peerDependencies: + '@rsbuild/core': 1.x + peerDependenciesMeta: + '@rsbuild/core': + optional: true + + '@rsbuild/plugin-typed-css-modules@1.0.2': + resolution: {integrity: sha512-QX376pBXWeBrZBvYLP2HGGrHiWA5O0SDHwRoBNto5BqYDXhi6y+Eol2Hb/cY+h2ARKZVanMfUiJRABULOJ/FCQ==} + peerDependencies: + '@rsbuild/core': 1.x || ^1.0.1-beta.0 + peerDependenciesMeta: + '@rsbuild/core': + optional: true + + '@rspack/binding-darwin-arm64@1.3.3': + resolution: {integrity: sha512-vbzEdpRCZl5+HXWsVjzSDqB9ZVIlqldV+udHp4YDD8qiwdQznVaBZke0eMzZ7kaInqRPsZ+UHQuVk6JaH/JkMQ==} + cpu: [arm64] + os: [darwin] + + '@rspack/binding-darwin-x64@1.3.3': + resolution: {integrity: sha512-OXtY2s4nlYtUXkeJt8TQKKNIcN7PI8yDq0nqI75OfJoS4u1ZmRXJ8IMeSALLo8I+xD2RAF79tf7yhM/Y/AaiKQ==} + cpu: [x64] + os: [darwin] + + '@rspack/binding-linux-arm64-gnu@1.3.3': + resolution: {integrity: sha512-Lluq3RLYzyCMdXr/HyALKEPGsr+196x8Ccuy5AmIRosOdWuwtSiomSRH1Ka8REUFNHfYy5y9SzfmIZo/E0QEmg==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-arm64-musl@1.3.3': + resolution: {integrity: sha512-PIsicXWjOqzmoOutUqxpMNkCoKo+8/wxDyKxHFeu+5WIAxVFphe2d3H5qvEjc2MasWSdRmAVn9XiuIj2LIXFzA==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-x64-gnu@1.3.3': + resolution: {integrity: sha512-BtksK73ZFdny2T/wU1x0kxBF4ruYUUArZDyeGfpO+vd/1nNYqzzdhGvOksKmtdvsO38ETr2gZ9+XZyr1vpy9uQ==} + cpu: [x64] + os: [linux] + + '@rspack/binding-linux-x64-musl@1.3.3': + resolution: {integrity: sha512-jx86CxkTmyBz/eHDqZp1mCqBwY+UTEtaPlPoWFyGkJUR5ey6nQnxS+fhG34Rqz63chW+q/afwpGNGyALYdgc8g==} + cpu: [x64] + os: [linux] + + '@rspack/binding-win32-arm64-msvc@1.3.3': + resolution: {integrity: sha512-uXAdDzajFToVrH3fCNVDP/uKQ9i5FQjJc2aYxsnhS9Su/CZB+UQsOecbq6MnIN2s0B9GBKBG8QdQEtS3RtC6Hg==} + cpu: [arm64] + os: [win32] + + '@rspack/binding-win32-ia32-msvc@1.3.3': + resolution: {integrity: sha512-VBE6XsJ3IiAlozAywAIxAZ1Aqc2QVnEwBo0gP9998KkwL7wxB6Bg/OJnPbH3Q0ZaNWAQViC99rPC+5hSIdeSxw==} + cpu: [ia32] + os: [win32] + + '@rspack/binding-win32-x64-msvc@1.3.3': + resolution: {integrity: sha512-rOsNz4/DFgSENjEh0t9kFn89feuXK14/9wbmmFlT8VMpYOCcj4tKcAHjWg+Nzzj4FL+NSOC/81SrUF9J+C2R7w==} + cpu: [x64] + os: [win32] + + '@rspack/binding@1.3.3': + resolution: {integrity: sha512-zdwJ801tyC8k+Gu5RjNoc7bEtX0MgJzzVv9qpaMwcAUfUfwZgCzXPTqcGMDoNI+Z47Fw59/2fKCmgZhZn60AgA==} + + '@rspack/core@1.3.3': + resolution: {integrity: sha512-+mXVlFcYr0tWezZfJ/gR0fj8njRc7pzEMtTFa2NO5cfsNAKPF/SXm4rb55kfa63r0b3U3N7f2nKrJG9wyG7zMQ==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@rspack/tracing': ^1.x + '@swc/helpers': '>=0.5.1' + peerDependenciesMeta: + '@rspack/tracing': + optional: true + '@swc/helpers': + optional: true + + '@rspack/lite-tapable@1.0.1': + resolution: {integrity: sha512-VynGOEsVw2s8TAlLf/uESfrgfrq2+rcXB1muPJYBWbsm1Oa6r5qVQhjA5ggM6z/coYPrsVMgovl3Ff7Q7OCp1w==} + engines: {node: '>=16.0.0'} + + '@rspack/plugin-react-refresh@1.2.0': + resolution: {integrity: sha512-DTsbtggCfsiXE5QQtYMS8rKfEF8GIjwPDbgIT6Kg8BlAjpJY4jT5IisyhfIi7YOT3d5RIvu60iFB6Kr9sSMsnA==} + peerDependencies: + react-refresh: '>=0.10.0 <1.0.0' + webpack-hot-middleware: 2.x + peerDependenciesMeta: + webpack-hot-middleware: + optional: true + + '@rushstack/eslint-patch@1.10.5': + resolution: {integrity: sha512-kkKUDVlII2DQiKy7UstOR1ErJP8kUKAQ4oa+SQtM0K+lPdmmjj0YnnxBgtTVYH7mUKtbsxeFC9y0AmK7Yb78/A==} + + '@sideway/address@4.1.5': + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + + '@sideway/formula@3.0.1': + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + + '@sideway/pinpoint@2.0.0': + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - '@socket.io/component-emitter@3.1.0': - resolution: {integrity: sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==} + '@socket.io/component-emitter@3.1.2': + resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - '@storybook/addon-actions@7.4.6': - resolution: {integrity: sha512-SsqZr3js5NinKPnC8AeNI7Ij+Q6fIl9tRdRmSulEgjksjOg7E5S1/Wsn5Bb2CCgj7MaX6VxGyC7s3XskQtDiIQ==} + '@storybook/addon-actions@7.6.20': + resolution: {integrity: sha512-c/GkEQ2U9BC/Ew/IMdh+zvsh4N6y6n7Zsn2GIhJgcu9YEAa5aF2a9/pNgEGBMOABH959XE8DAOMERw/5qiLR8g==} + + '@storybook/addon-backgrounds@7.6.20': + resolution: {integrity: sha512-a7ukoaXT42vpKsMxkseIeO3GqL0Zst2IxpCTq5dSlXiADrcemSF/8/oNpNW9C4L6F1Zdt+WDtECXslEm017FvQ==} + + '@storybook/addon-controls@7.6.20': + resolution: {integrity: sha512-06ZT5Ce1sZW52B0s6XuokwjkKO9GqHlTUHvuflvd8wifxKlCmRvNUxjBvwh+ccGJ49ZS73LbMSLFgtmBEkCxbg==} + + '@storybook/addon-docs@7.6.20': + resolution: {integrity: sha512-XNfYRhbxH5JP7B9Lh4W06PtMefNXkfpV39Gaoih5HuqngV3eoSL4RikZYOMkvxRGQ738xc6axySU3+JKcP1OZg==} peerDependencies: react: ^18.2.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + + '@storybook/addon-essentials@7.6.20': + resolution: {integrity: sha512-hCupSOiJDeOxJKZSgH0x5Mb2Xqii6mps21g5hpxac1XjhQtmGflShxi/xOHhK3sNqrbgTSbScfpUP3hUlZO/2Q==} + peerDependencies: + react: ^18.2.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + + '@storybook/addon-highlight@7.6.20': + resolution: {integrity: sha512-7/x7xFdFyqCki5Dm3uBePldUs9l98/WxJ7rTHQuYqlX7kASwyN5iXPzuhmMRUhlMm/6G6xXtLabIpzwf1sFurA==} + + '@storybook/addon-links@7.6.20': + resolution: {integrity: sha512-iomSnBD90CA4MinesYiJkFX2kb3P1Psd/a1Y0ghlFEsHD4uMId9iT6sx2s16DYMja0SlPkrbWYnGukqaCjZpRw==} + peerDependencies: + react: ^18.2.0 peerDependenciesMeta: react: optional: true - react-dom: - optional: true - '@storybook/addon-backgrounds@7.4.6': - resolution: {integrity: sha512-+LHTZB/ZYMAzkyD5ZxSriBsqmsrvIaW/Nnd/BeuXGbkrVKKqM0qAKiFZAfjc2WchA1piVNy0/1Rsf+kuYCEiJw==} - peerDependencies: - react: ^18.2.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + '@storybook/addon-measure@7.6.20': + resolution: {integrity: sha512-i2Iq08bGfI7gZbG6Lb8uF/L287tnaGUR+2KFEmdBjH6+kgjWLiwfpanoPQpy4drm23ar0gUjX+L3Ri03VI5/Xg==} - '@storybook/addon-controls@7.4.6': - resolution: {integrity: sha512-4lq3sycEUIsK8SUWDYc60QgF4vV9FZZ3lDr6M7j2W9bOnvGw49d2fbdlnq+bX1ZprZZ9VgglQpBAorQB3BXZRw==} - peerDependencies: - react: ^18.2.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + '@storybook/addon-outline@7.6.20': + resolution: {integrity: sha512-TdsIQZf/TcDsGoZ1XpO+9nBc4OKqcMIzY4SrI8Wj9dzyFLQ37s08gnZr9POci8AEv62NTUOVavsxcafllkzqDQ==} - '@storybook/addon-docs@7.4.6': - resolution: {integrity: sha512-dLaub+XWFq4hChw+xfuF9yYg0Txp77FUawKoAigccfjWXx+OOhRV3XTuAcknpXkYq94GWynHgUFXosXT9kbDNA==} + '@storybook/addon-toolbars@7.6.20': + resolution: {integrity: sha512-5Btg4i8ffWTDHsU72cqxC8nIv9N3E3ObJAc6k0llrmPBG/ybh3jxmRfs8fNm44LlEXaZ5qrK/petsXX3UbpIFg==} + + '@storybook/addon-viewport@7.6.20': + resolution: {integrity: sha512-i8mIw8BjLWAVHEQsOTE6UPuEGQvJDpsu1XZnOCkpfTfPMz73m+3td/PmLG7mMT2wPnLu9IZncKLCKTAZRbt/YQ==} + + '@storybook/blocks@7.6.20': + resolution: {integrity: sha512-xADKGEOJWkG0UD5jbY4mBXRlmj2C+CIupDL0/hpzvLvwobxBMFPKZIkcZIMvGvVnI/Ui+tJxQxLSuJ5QsPthUw==} peerDependencies: react: ^18.2.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@storybook/addon-essentials@7.4.6': - resolution: {integrity: sha512-dWodufrt71TK7ELkeIvVae/x4PzECUlbOm57Iqqt4yQCyR291CgvI4PjeB8un2HbpcXCGZ+N/Oj3YkytvzBi4A==} - peerDependencies: - react: ^18.2.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@storybook/builder-manager@7.6.20': + resolution: {integrity: sha512-e2GzpjLaw6CM/XSmc4qJRzBF8GOoOyotyu3JrSPTYOt4RD8kjUsK4QlismQM1DQRu8i39aIexxmRbiJyD74xzQ==} - '@storybook/addon-highlight@7.4.6': - resolution: {integrity: sha512-zCufxxD2KS5VwczxfkcBxe1oR/juTTn2H1Qm8kYvWCJQx3UxzX0+G9cwafbpV7eivqaufLweEwROkH+0KjAtkQ==} - - '@storybook/addon-links@7.4.6': - resolution: {integrity: sha512-BPygElZKX+CPI9Se6GJNk1dYc5oxuhA+vHigO1tBqhiM6VkHyFP3cvezJNQvpNYhkUnu3cxnZXb3UJnlRbPY3g==} - peerDependencies: - react: ^18.2.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - - '@storybook/addon-measure@7.4.6': - resolution: {integrity: sha512-nCymMLaHnxv8TE3yEM1A9Tulb1NuRXRNmtsdHTkjv7P1aWCxZo8A/GZaottKe/GLT8jSRjZ+dnpYWrbAhw6wTQ==} - peerDependencies: - react: ^18.2.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - - '@storybook/addon-outline@7.4.6': - resolution: {integrity: sha512-errNUblRVDLpuEaHQPr/nsrnsUkD2ARmXawkRvizgDWLIDMDJYjTON3MUCaVx3x+hlZ3I6X//G5TVcma8tCc8A==} - peerDependencies: - react: ^18.2.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - - '@storybook/addon-toolbars@7.4.6': - resolution: {integrity: sha512-L9m2FBcKeteGq7qIYsMJr0LEfiH7Wdrv5IDcldZTn68eZUJTh1p4GdJZcOmzX1P5IFRr76hpu03iWsNlWQjpbQ==} - peerDependencies: - react: ^18.2.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - - '@storybook/addon-viewport@7.4.6': - resolution: {integrity: sha512-INDtk54j7bi7NgxMfd2ATmbA0J7nAd6X8itMkLIyPuPJtx8bYHPDORyemDOd0AojgmAdTOAyUtDYdI/PFeo4Cw==} - peerDependencies: - react: ^18.2.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - - '@storybook/blocks@7.4.6': - resolution: {integrity: sha512-HxBSAeOiTZW2jbHQlo1upRWFgoMsaAyKijUFf5MwwMNIesXCuuTGZDJ3xTABwAVLK2qC9Ektfbo0CZCiPVuDRQ==} - peerDependencies: - react: ^18.2.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - - '@storybook/builder-manager@7.4.6': - resolution: {integrity: sha512-zylZCD2rmyLOOFBFmUgtJg6UNUKmRNgXiig1XApzS2TkIbTZP827DsVEUl0ey/lskCe0uArkrEBR6ICba8p/Rw==} - - '@storybook/builder-vite@7.4.6': - resolution: {integrity: sha512-xV9STYK+TkqWWTf2ydm6jx+7P70fjD2UPd1XTUw08uKszIjhuuxk+bG/OF5R1E25mPunAKXm6kBFh351AKejBg==} + '@storybook/builder-vite@7.6.20': + resolution: {integrity: sha512-q3vf8heE7EaVYTWlm768ewaJ9lh6v/KfoPPeHxXxzSstg4ByP9kg4E1mrfAo/l6broE9E9zo3/Q4gsM/G/rw8Q==} peerDependencies: '@preact/preset-vite': '*' typescript: '>= 4.3.x' - vite: ^3.0.0 || ^4.0.0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 vite-plugin-glimmerx: '*' peerDependenciesMeta: '@preact/preset-vite': @@ -2511,95 +2804,92 @@ packages: vite-plugin-glimmerx: optional: true - '@storybook/channels@7.4.6': - resolution: {integrity: sha512-yPv/sfo2c18fM3fvG0i1xse63vG8l33Al/OU0k/dtovltPu001/HVa1QgBgsb/QrEfZtvGjGhmtdVeYb39fv3A==} + '@storybook/channels@7.6.20': + resolution: {integrity: sha512-4hkgPSH6bJclB2OvLnkZOGZW1WptJs09mhQ6j6qLjgBZzL/ZdD6priWSd7iXrmPiN5TzUobkG4P4Dp7FjkiO7A==} - '@storybook/cli@7.4.6': - resolution: {integrity: sha512-rRwaH8pOL+FHz/pJMEkNpMH2xvZvWsrl7obBYw26NQiHmiVSAkfHJicndSN1mwc+p5w+9iXthrgzbLtSAOSvkA==} + '@storybook/cli@7.6.20': + resolution: {integrity: sha512-ZlP+BJyqg7HlnXf7ypjG2CKMI/KVOn03jFIiClItE/jQfgR6kRFgtjRU7uajh427HHfjv9DRiur8nBzuO7vapA==} hasBin: true - '@storybook/client-logger@7.4.6': - resolution: {integrity: sha512-XDw31ZziU//86PKuMRnmc+L/G0VopaGKENQOGEpvAXCU9IZASwGKlKAtcyosjrpi+ZiUXlMgUXCpXM7x3b1Ehw==} + '@storybook/client-logger@7.6.20': + resolution: {integrity: sha512-NwG0VIJQCmKrSaN5GBDFyQgTAHLNishUPLW1NrzqTDNAhfZUoef64rPQlinbopa0H4OXmlB+QxbQIb3ubeXmSQ==} - '@storybook/codemod@7.4.6': - resolution: {integrity: sha512-lxmwEpwksCaAq96APN2YlooSDfKjJ1vKzN5Ni2EqQzf2TEXl7XQjLacHd7OOaII1kfsy+D5gNG4N5wBo7Ub30g==} + '@storybook/codemod@7.6.20': + resolution: {integrity: sha512-8vmSsksO4XukNw0TmqylPmk7PxnfNfE21YsxFa7mnEBmEKQcZCQsNil4ZgWfG0IzdhTfhglAN4r++Ew0WE+PYA==} - '@storybook/components@7.4.6': - resolution: {integrity: sha512-nIRBhewAgrJJVafyCzuaLx1l+YOfvvD5dOZ0JxZsxJsefOdw1jFpUqUZ5fIpQ2moyvrR0mAUFw378rBfMdHz5Q==} + '@storybook/components@7.6.20': + resolution: {integrity: sha512-0d8u4m558R+W5V+rseF/+e9JnMciADLXTpsILrG+TBhwECk0MctIWW18bkqkujdCm8kDZr5U2iM/5kS1Noy7Ug==} peerDependencies: react: ^18.2.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@storybook/core-client@7.4.6': - resolution: {integrity: sha512-tfgxAHeCvMcs6DsVgtb4hQSDaCHeAPJOsoyhb47eDQfk4OmxzriM0qWucJV5DePSMi+KutX/rN2u0JxfOuN68g==} + '@storybook/core-client@7.6.20': + resolution: {integrity: sha512-upQuQQinLmlOPKcT8yqXNtwIucZ4E4qegYZXH5HXRWoLAL6GQtW7sUVSIuFogdki8OXRncr/dz8OA+5yQyYS4w==} - '@storybook/core-common@7.4.6': - resolution: {integrity: sha512-05MJFmOM86qvTLtgDskokIFz9txe0Lbhq4L3by1FtF0GwgH+p+W6I94KI7c6ANER+kVZkXQZhiRzwBFnVTW+Cg==} + '@storybook/core-common@7.6.20': + resolution: {integrity: sha512-8H1zPWPjcmeD4HbDm4FDD0WLsfAKGVr566IZ4hG+h3iWVW57II9JW9MLBtiR2LPSd8u7o0kw64lwRGmtCO1qAw==} - '@storybook/core-events@7.4.6': - resolution: {integrity: sha512-r5vrE+32lwrJh1NGFr1a0mWjvxo7q8FXYShylcwRWpacmL5NTtLkrXOoJSeGvJ4yKNYkvxQFtOPId4lzDxa32w==} + '@storybook/core-events@7.6.20': + resolution: {integrity: sha512-tlVDuVbDiNkvPDFAu+0ou3xBBYbx9zUURQz4G9fAq0ScgBOs/bpzcRrFb4mLpemUViBAd47tfZKdH4MAX45KVQ==} - '@storybook/core-server@7.4.6': - resolution: {integrity: sha512-jqmRTGCJ1W0WReImivkisPVaLFT5sjtLnFoAk0feHp6QS5j7EYOPN7CYzliyQmARWTLUEXOVaFf3VD6nJZQhJQ==} + '@storybook/core-server@7.6.20': + resolution: {integrity: sha512-qC5BdbqqwMLTdCwMKZ1Hbc3+3AaxHYWLiJaXL9e8s8nJw89xV8c8l30QpbJOGvcDmsgY6UTtXYaJ96OsTr7MrA==} - '@storybook/csf-plugin@7.4.6': - resolution: {integrity: sha512-yi7Qa4NSqKOyiJTWCxlB0ih2ijXq6oY5qZKW6MuMMBP14xJNRGLbH5KabpfXgN2T7YECcOWG1uWaGj2veJb1KA==} + '@storybook/csf-plugin@7.6.20': + resolution: {integrity: sha512-dzBzq0dN+8WLDp6NxYS4G7BCe8+vDeDRBRjHmM0xb0uJ6xgQViL8SDplYVSGnk3bXE/1WmtvyRzQyTffBnaj9Q==} - '@storybook/csf-tools@7.4.6': - resolution: {integrity: sha512-ocKpcIUtTBy6hlLY34RUFQyX403cWpB2gGfqvkHbpGe2BQj7EyV0zpWnjsfVxvw+M9OWlCdxHWDOPUgXM33ELw==} + '@storybook/csf-tools@7.6.20': + resolution: {integrity: sha512-rwcwzCsAYh/m/WYcxBiEtLpIW5OH1ingxNdF/rK9mtGWhJxXRDV8acPkFrF8rtFWIVKoOCXu5USJYmc3f2gdYQ==} - '@storybook/csf@0.1.1': - resolution: {integrity: sha512-4hE3AlNVxR60Wc5KSC68ASYzUobjPqtSKyhV6G+ge0FIXU55N5nTY7dXGRZHQGDBPq+XqchMkIdlkHPRs8nTHg==} + '@storybook/csf@0.1.13': + resolution: {integrity: sha512-7xOOwCLGB3ebM87eemep89MYRFTko+D8qE7EdAAq74lgdqRR5cOUtYWJLjO2dLtP94nqoOdHJo6MdLLKzg412Q==} '@storybook/docs-mdx@0.1.0': resolution: {integrity: sha512-JDaBR9lwVY4eSH5W8EGHrhODjygPd6QImRbwjAuJNEnY0Vw4ie3bPkeGfnacB3OBW6u/agqPv2aRlR46JcAQLg==} - '@storybook/docs-tools@7.4.6': - resolution: {integrity: sha512-nZj1L/8WwKWWJ41FW4MaKGajZUtrhnr9UwflRCkQJaWhAKmDfOb5M5TqI93uCOULpFPOm5wpoMBz2IHInQ2Lrg==} + '@storybook/docs-tools@7.6.20': + resolution: {integrity: sha512-Bw2CcCKQ5xGLQgtexQsI1EGT6y5epoFzOINi0FSTGJ9Wm738nRp5LH3dLk1GZLlywIXcYwOEThb2pM+pZeRQxQ==} '@storybook/global@5.0.0': resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} - '@storybook/manager-api@7.4.6': - resolution: {integrity: sha512-inrm3DIbCp8wjXSN/wK6e6i2ysQ/IEmtC7IN0OJ7vdrp+USCooPT448SQTUmVctUGCFmOU3fxXByq8g77oIi7w==} - peerDependencies: - react: ^18.2.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@storybook/manager-api@7.6.20': + resolution: {integrity: sha512-gOB3m8hO3gBs9cBoN57T7jU0wNKDh+hi06gLcyd2awARQlAlywnLnr3s1WH5knih6Aq+OpvGBRVKkGLOkaouCQ==} - '@storybook/manager@7.4.6': - resolution: {integrity: sha512-kA1hUDxpn1i2SO9OinvLvVXDeL4xgJkModp+pbE8IXv4NJWReNq1ecMeQCzPLS3Sil2gnrullQ9uYXsnZ9bxxA==} + '@storybook/manager@7.6.20': + resolution: {integrity: sha512-0Cf6WN0t7yEG2DR29tN5j+i7H/TH5EfPppg9h9/KiQSoFHk+6KLoy2p5do94acFU+Ro4+zzxvdCGbcYGKuArpg==} '@storybook/mdx2-csf@1.1.0': resolution: {integrity: sha512-TXJJd5RAKakWx4BtpwvSNdgTDkKM6RkXU8GK34S/LhidQ5Pjz3wcnqb0TxEkfhK/ztbP8nKHqXFwLfa2CYkvQw==} - '@storybook/node-logger@7.4.6': - resolution: {integrity: sha512-djZb310Q27GviDug1XBv0jOEDLCiwr4hhDE0aifCEKZpfNCi/EaP31nbWimFzZwxu4hE/YAPWExzScruR1zw9Q==} + '@storybook/node-logger@7.6.20': + resolution: {integrity: sha512-l2i4qF1bscJkOplNffcRTsgQWYR7J51ewmizj5YrTM8BK6rslWT1RntgVJWB1RgPqvx6VsCz1gyP3yW1oKxvYw==} - '@storybook/postinstall@7.4.6': - resolution: {integrity: sha512-TqI5BucPAGRWrkh55BYiG2/gHLFtC0In4cuu0GsUzB/1jc4i51npLRorCwhmT7r7YliGl5F7JaP0Bni/qHN3Lg==} + '@storybook/postinstall@7.6.20': + resolution: {integrity: sha512-AN4WPeNma2xC2/K/wP3I/GMbBUyeSGD3+86ZFFJFO1QmE/Zea6E+1aVlTd1iKHQUcNkZ9bZTrqkhPGVYx10pIw==} - '@storybook/preview-api@7.4.6': - resolution: {integrity: sha512-byUS/Opt3ytWD4cWz3sNEKw5Yks8MkQgRN+GDSyIomaEAQkLAM0rchPC0MYjwCeUSecV7IIQweNX5RbV4a34BA==} + '@storybook/preview-api@7.6.20': + resolution: {integrity: sha512-3ic2m9LDZEPwZk02wIhNc3n3rNvbi7VDKn52hDXfAxnL5EYm7yDICAkaWcVaTfblru2zn0EDJt7ROpthscTW5w==} - '@storybook/preview@7.4.6': - resolution: {integrity: sha512-2RPXusJ4CTDrIipIKKvbotD7fP0+8VzoFjImunflIrzN9rni+2rq5eMjqlXAaB+77w064zIR4uDUzI9fxsMDeQ==} + '@storybook/preview@7.6.20': + resolution: {integrity: sha512-cxYlZ5uKbCYMHoFpgleZqqGWEnqHrk5m5fT8bYSsDsdQ+X5wPcwI/V+v8dxYAdQcMphZVIlTjo6Dno9WG8qmVA==} - '@storybook/react-dom-shim@7.4.6': - resolution: {integrity: sha512-DSq8l9FDocUF1ooVI+TF83pddj1LynE/Hv0/y8XZhc3IgJ/HkuOQuUmfz29ezgfAi9gFYUR8raTIBi3/xdoRmw==} + '@storybook/react-dom-shim@7.6.20': + resolution: {integrity: sha512-SRvPDr9VWcS24ByQOVmbfZ655y5LvjXRlsF1I6Pr9YZybLfYbu3L5IicfEHT4A8lMdghzgbPFVQaJez46DTrkg==} peerDependencies: react: ^18.2.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@storybook/react-vite@7.4.6': - resolution: {integrity: sha512-jkjnrf3FxzR5wcmebXRPflrsM4WIDjWyW/NVFJwxi5PeIOk7fE7/QAPrm4NFRUu2Q7DeuH3oLKsw8bigvUI9RA==} + '@storybook/react-vite@7.6.20': + resolution: {integrity: sha512-uKuBFyGPZxpfR8vpDU/2OE9v7iTaxwL7ldd7k1swYd1rTSAPacTnEHSMl1R5AjUhkdI7gRmGN9q7qiVfK2XJCA==} engines: {node: '>=16'} peerDependencies: react: ^18.2.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - vite: ^3.0.0 || ^4.0.0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 - '@storybook/react@7.4.6': - resolution: {integrity: sha512-w0dVo64baFFPTGpUOWFqkKsu6pQincoymegSNgqaBd5DxEyMDRiRoTWSJHMKE9BwgE8SyWhRkP1ak1mkccSOhQ==} + '@storybook/react@7.6.20': + resolution: {integrity: sha512-i5tKNgUbTNwlqBWGwPveDhh9ktlS0wGtd97A1ZgKZc3vckLizunlAFc7PRC1O/CMq5PTyxbuUb4RvRD2jWKwDA==} engines: {node: '>=16.0.0'} peerDependencies: react: ^18.2.0 @@ -2609,27 +2899,33 @@ packages: typescript: optional: true - '@storybook/router@7.4.6': - resolution: {integrity: sha512-Vl1esrHkcHxDKqc+HY7+6JQpBPW3zYvGk0cQ2rxVMhWdLZTAz1hss9DqzN9tFnPyfn0a1Q77EpMySkUrvWKKNQ==} + '@storybook/router@7.6.20': + resolution: {integrity: sha512-mCzsWe6GrH47Xb1++foL98Zdek7uM5GhaSlrI7blWVohGa0qIUYbfJngqR4ZsrXmJeeEvqowobh+jlxg3IJh+w==} + + '@storybook/telemetry@7.6.20': + resolution: {integrity: sha512-dmAOCWmOscYN6aMbhCMmszQjoycg7tUPRVy2kTaWg6qX10wtMrvEtBV29W4eMvqdsoRj5kcvoNbzRdYcWBUOHQ==} + + '@storybook/theming@7.6.20': + resolution: {integrity: sha512-iT1pXHkSkd35JsCte6Qbanmprx5flkqtSHC6Gi6Umqoxlg9IjiLPmpHbaIXzoC06DSW93hPj5Zbi1lPlTvRC7Q==} peerDependencies: react: ^18.2.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@storybook/telemetry@7.4.6': - resolution: {integrity: sha512-c8p/C1NIH8EMBviZkBCx8MMDk6rrITJ+b29DEp5MaWSRlklIVyhGiC4RPIRv6sxJwlD41PnqWVFtfu2j2eXLdQ==} + '@storybook/types@7.6.20': + resolution: {integrity: sha512-GncdY3x0LpbhmUAAJwXYtJDUQEwfF175gsjH0/fxPkxPoV7Sef9TM41jQLJW/5+6TnZoCZP/+aJZTJtq3ni23Q==} - '@storybook/theming@7.4.6': - resolution: {integrity: sha512-HW77iJ9ptCMqhoBOYFjRQw7VBap+38fkJGHP5KylEJCyYCgIAm2dEcQmtWpMVYFssSGcb6djfbtAMhYU4TL4Iw==} + '@stylistic/eslint-plugin@2.13.0': + resolution: {integrity: sha512-RnO1SaiCFHn666wNz2QfZEFxvmiNRqhzaMXHXxXXKt+MEP7aajlPxUSMIQpKAaJfverpovEYqjBOXDq6dDcaOQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - react: ^18.2.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - - '@storybook/types@7.4.6': - resolution: {integrity: sha512-6QLXtMVsFZFpzPkdGWsu/iuc8na9dnS67AMOBKm5qCLPwtUJOYkwhMdFRSSeJthLRpzV7JLAL8Kwvl7MFP3QSw==} + eslint: '>=8.40.0' '@surma/rollup-plugin-off-main-thread@2.2.3': resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} @@ -2640,56 +2936,61 @@ packages: '@tweenjs/tween.js@20.0.3': resolution: {integrity: sha512-SYUe1UgY5HM05EB4+0B4arq2IPjvyzKXoklXKxSYrc2IFxGm1cBrqg5XbiB5uwbs0xY5j+rj986NAJMM0KZaUw==} - '@types/babel__core@7.20.2': - resolution: {integrity: sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==} + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - '@types/babel__generator@7.6.5': - resolution: {integrity: sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==} + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} - '@types/babel__template@7.4.2': - resolution: {integrity: sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==} + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - '@types/babel__traverse@7.20.2': - resolution: {integrity: sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==} + '@types/babel__traverse@7.20.6': + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} - '@types/body-parser@1.19.3': - resolution: {integrity: sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==} + '@types/body-parser@1.19.5': + resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} - '@types/chai-subset@1.3.3': - resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} + '@types/chai-subset@1.3.6': + resolution: {integrity: sha512-m8lERkkQj+uek18hXOZuec3W/fCRTrU4hrnXjH3qhHy96ytuPaPiWGgu7sJb7tZxZonO75vYAjCvpe/e4VUwRw==} + peerDependencies: + '@types/chai': <5.2.0 - '@types/chai@4.3.6': - resolution: {integrity: sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==} + '@types/chai@4.3.20': + resolution: {integrity: sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==} - '@types/connect@3.4.36': - resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==} + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - '@types/cookie@0.4.1': - resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} + '@types/cors@2.8.17': + resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} - '@types/cors@2.8.15': - resolution: {integrity: sha512-n91JxbNLD8eQIuXDIChAN1tCKNWCEgpceU9b7ZMbFA+P+Q4yIeh80jizFLEvolRPc1ES0VdwFlGv+kJTSirogw==} - - '@types/cross-spawn@6.0.3': - resolution: {integrity: sha512-BDAkU7WHHRHnvBf5z89lcvACsvkz/n7Tv+HyD/uW76O29HoH1Tk/W6iQrepaZVbisvlEek4ygwT8IW7ow9XLAA==} + '@types/cross-spawn@6.0.6': + resolution: {integrity: sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==} '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - '@types/detect-port@1.3.3': - resolution: {integrity: sha512-bV/jQlAJ/nPY3XqSatkGpu+nGzou+uSwrH1cROhn+jBFg47yaNH+blW4C7p9KhopC7QxCv/6M86s37k8dMk0Yg==} + '@types/detect-port@1.3.5': + resolution: {integrity: sha512-Rf3/lB9WkDfIL9eEKaSYKc+1L/rNVYBjThk22JTqQw0YozXarX8YljFAz+HCoC6h4B4KwCMsBPZHaFezwT4BNA==} + + '@types/diff-match-patch@1.0.36': + resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==} '@types/doctrine@0.0.3': resolution: {integrity: sha512-w5jZ0ee+HaPOaX25X2/2oGR/7rgAQSYII7X7pp0m9KgBfMP7uKfMfTvcpl5Dj+eDBbpxKGiqE+flqDr6XTd2RA==} - '@types/draco3d@1.4.7': - resolution: {integrity: sha512-sjx6hQ8UArRZf+2ZhpPkjJW8iCkyxar69/IElc9NHuGE40n0U9SuvxX59CHvF4xUH7qfJDQ2lIbANZ0HHJg+BQ==} + '@types/doctrine@0.0.9': + resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==} - '@types/ejs@3.1.3': - resolution: {integrity: sha512-mv5T/JI/bu+pbfz1o+TLl1NF0NIBbjS0Vl6Ppz1YY9DkXfzZT0lelXpfS5i3ZS3U/p90it7uERQpBvLYoK8e4A==} + '@types/draco3d@1.4.10': + resolution: {integrity: sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==} - '@types/emscripten@1.39.8': - resolution: {integrity: sha512-Rk0HKcMXFUuqT32k1kXHZWgxiMvsyYsmlnjp0rLKa0MMoqXLE3T9dogDBTRfuc3SAsXu97KD3k4SKR1lHqd57w==} + '@types/ejs@3.1.5': + resolution: {integrity: sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==} + + '@types/emscripten@1.40.0': + resolution: {integrity: sha512-MD2JJ25S4tnjnhjWyalMS6K6p0h+zQV6+Ylm+aGbiS8tSn/aHLSGNzBgduj6FB4zH0ax2GRMGYi/8G1uOxhXWA==} '@types/escodegen@0.0.6': resolution: {integrity: sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==} @@ -2700,14 +3001,14 @@ packages: '@types/estree@0.0.51': resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==} - '@types/estree@1.0.2': - resolution: {integrity: sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==} + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/express-serve-static-core@4.17.37': - resolution: {integrity: sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==} + '@types/express-serve-static-core@4.19.6': + resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} - '@types/express@4.17.18': - resolution: {integrity: sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ==} + '@types/express@4.17.21': + resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} '@types/find-cache-dir@3.2.1': resolution: {integrity: sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==} @@ -2718,149 +3019,150 @@ packages: '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} - '@types/graceful-fs@4.1.7': - resolution: {integrity: sha512-MhzcwU8aUygZroVwL2jeYk6JisJrPl/oov/gsgGCue9mkgl9wjGbzReYQClxiUgFDnib9FuHqTndccKeZKxTRw==} + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - '@types/http-cache-semantics@4.0.2': - resolution: {integrity: sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==} + '@types/http-cache-semantics@4.0.4': + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} - '@types/http-errors@2.0.2': - resolution: {integrity: sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==} + '@types/http-errors@2.0.4': + resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} - '@types/istanbul-lib-coverage@2.0.4': - resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - '@types/istanbul-lib-report@3.0.1': - resolution: {integrity: sha512-gPQuzaPR5h/djlAv2apEG1HVOyj1IUs7GpfMZixU0/0KXT3pm64ylHuMUI1/Akh+sq/iikxg6Z2j+fcMDXaaTQ==} + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} - '@types/istanbul-reports@3.0.2': - resolution: {integrity: sha512-kv43F9eb3Lhj+lr/Hn6OcLCs/sSM8bt+fIaP11rCYngfV6NVjzWXJ17owQtDQTL9tQ8WSLUrGsSJ6rJz0F1w1A==} + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} '@types/js-cookie@2.2.7': resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==} - '@types/json-schema@7.0.12': - resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/lodash-es@4.17.9': - resolution: {integrity: sha512-ZTcmhiI3NNU7dEvWLZJkzG6ao49zOIjEgIE0RgV7wbPxU0f2xT3VSAHw2gmst8swH6V0YkLRGp4qPlX/6I90MQ==} + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} - '@types/lodash@4.14.199': - resolution: {integrity: sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg==} + '@types/lodash-es@4.17.12': + resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} - '@types/mdast@4.0.3': - resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==} + '@types/lodash@4.17.16': + resolution: {integrity: sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==} - '@types/mdx@2.0.8': - resolution: {integrity: sha512-r7/zWe+f9x+zjXqGxf821qz++ld8tp6Z4jUS6qmPZUXH6tfh4riXOhAqb12tWGWAevCFtMt1goLWkQMqIJKpsA==} + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} - '@types/mime-types@2.1.2': - resolution: {integrity: sha512-q9QGHMGCiBJCHEvd4ZLdasdqXv570agPsUW0CeIm/B8DzhxsYMerD0l3IlI+EQ1A2RWHY2mmM9x1YIuuWxisCg==} + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - '@types/mime@1.3.3': - resolution: {integrity: sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg==} + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} - '@types/mime@3.0.2': - resolution: {integrity: sha512-Wj+fqpTLtTbG7c0tH47dkahefpLKEbB+xAZuLq7b4/IDHPl/n6VoXcyUQ2bypFlbSwvCr0y+bD4euTTqTJsPxQ==} + '@types/mdx@2.0.13': + resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} + + '@types/mime-types@2.1.4': + resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==} + + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} '@types/minimatch@5.1.2': resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - '@types/minimist@1.2.3': - resolution: {integrity: sha512-ZYFzrvyWUNhaPomn80dsMNgMeXxNWZBdkuG/hWlUvXvbdUH8ZERNBGXnU87McuGcWDsyzX2aChCv/SVN348k3A==} + '@types/minimist@1.2.5': + resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} - '@types/ms@0.7.34': - resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node-fetch@2.6.6': - resolution: {integrity: sha512-95X8guJYhfqiuVVhRFxVQcf4hW/2bCuoPwDasMf/531STFoNoWTT7YDnWdXHEZKqAGUigmpG31r2FE70LwnzJw==} + '@types/node-fetch@2.6.12': + resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} - '@types/node@14.18.56': - resolution: {integrity: sha512-+k+57NVS9opgrEn5l9c0gvD1r6C+PtyhVE4BTnMMRwiEA8ZO8uFcs6Yy2sXIy0eC95ZurBtRSvhZiHXBysbl6w==} + '@types/node-rsa@1.1.4': + resolution: {integrity: sha512-dB0ECel6JpMnq5ULvpUTunx3yNm8e/dIkv8Zu9p2c8me70xIRUUG3q+qXRwcSf9rN3oqamv4116iHy90dJGRpA==} - '@types/node@16.18.58': - resolution: {integrity: sha512-YGncyA25/MaVtQkjWW9r0EFBukZ+JulsLcVZBlGUfIb96OBMjkoRWwQo5IEWJ8Fj06Go3GHw+bjYDitv6BaGsA==} + '@types/node@14.18.63': + resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} - '@types/node@20.11.19': - resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==} + '@types/node@18.19.79': + resolution: {integrity: sha512-90K8Oayimbctc5zTPHPfZloc/lGVs7f3phUAAMcTgEPtg8kKquGZDERC8K4vkBYkQQh48msiYUslYtxTWvqcAg==} - '@types/node@20.12.8': - resolution: {integrity: sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==} + '@types/node@22.13.9': + resolution: {integrity: sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==} - '@types/node@20.8.0': - resolution: {integrity: sha512-LzcWltT83s1bthcvjBmiBvGJiiUe84NWRHkw+ZV6Fr41z2FbIzvc815dk2nQ3RAKMuN2fkenM/z3Xv2QzEpYxQ==} + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} - '@types/node@20.8.10': - resolution: {integrity: sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==} + '@types/offscreencanvas@2019.7.3': + resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==} - '@types/normalize-package-data@2.4.2': - resolution: {integrity: sha512-lqa4UEhhv/2sjjIQgjX8B+RBjj47eo0mzGasklVJ78UKGQY1r0VpB9XHDaZZO9qzEFDdy4MrXLuEaSmPrPSe/A==} + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/offscreencanvas@2019.7.2': - resolution: {integrity: sha512-ujCjOxeA07IbEBQYAkoOI+XFw5sT3nhWJ/xZfPR6reJppDG7iPQPZacQiLTtWH1b3a2NYXWlxvYqa40y/LAixQ==} + '@types/pretty-hrtime@1.0.3': + resolution: {integrity: sha512-nj39q0wAIdhwn7DGUyT9irmsKK1tV0bd5WFEhgpqNTMFZ8cE+jieuTphCW0tfdm47S2zVT5mr09B28b1chmQMA==} - '@types/parse-json@4.0.0': - resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} + '@types/prop-types@15.7.14': + resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} - '@types/pretty-hrtime@1.0.1': - resolution: {integrity: sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==} + '@types/qs@6.9.18': + resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==} - '@types/prop-types@15.7.12': - resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/prop-types@15.7.5': - resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} + '@types/rbush@3.0.4': + resolution: {integrity: sha512-knSt9cCW8jj1ZSFcFeBZaX++OucmfPxxHiRwTahZfJlnQsek7O0bazTJHWD2RVj9LEoejUYF2de3/stf+QXcXw==} - '@types/qs@6.9.8': - resolution: {integrity: sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==} + '@types/react-dom@18.3.5': + resolution: {integrity: sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==} + peerDependencies: + '@types/react': ^18.0.0 - '@types/range-parser@1.2.5': - resolution: {integrity: sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==} + '@types/react-transition-group@4.4.12': + resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} + peerDependencies: + '@types/react': '*' - '@types/rbush@3.0.1': - resolution: {integrity: sha512-0LecKcQjuJ/PclmThftzePIKXaKt7OMjoZZ3Xf17Ebd28ZU6OFUu1mObbvV74YXS1W3APdZO5GRHyD/ezGK4Vg==} + '@types/react@18.3.18': + resolution: {integrity: sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==} - '@types/react-dom@18.2.7': - resolution: {integrity: sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==} + '@types/readable-stream@4.0.18': + resolution: {integrity: sha512-21jK/1j+Wg+7jVw1xnSwy/2Q1VgVjWuFssbYGTREPUBeZ+rqVFl2udq0IkxzPC0ZhOzVceUbyIACFZKLqKEBlA==} - '@types/react-transition-group@4.4.7': - resolution: {integrity: sha512-ICCyBl5mvyqYp8Qeq9B5G/fyBSRC0zx3XM3sCC6KkcMsNeAHqXBKkmat4GqdJET5jtYUpZXrxI5flve5qhi2Eg==} + '@types/resolve@1.20.2': + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} - '@types/react@18.2.20': - resolution: {integrity: sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw==} - - '@types/readable-stream@4.0.12': - resolution: {integrity: sha512-SCaw+bs9o/HCX1eTa3glTcQgW1oPxof49mqP2Qikik3xzTimNv2M4p43BQHhBuf7CwOJdQW0s1SrWU3MZxz6lw==} - - '@types/resolve@1.17.1': - resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} + '@types/resolve@1.20.6': + resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} '@types/sat@0.0.31': resolution: {integrity: sha512-P4SVw79XheP1p92useDVpLYYOUQ6lpw2L7IdQz4dD23DZ8DiC1STgPOh72hjR5IZJBPQbzlICAbmjCKbwyYuxg==} - '@types/scheduler@0.16.3': - resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==} + '@types/semver@7.5.8': + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - '@types/semver@7.5.3': - resolution: {integrity: sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==} + '@types/send@0.17.4': + resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} - '@types/send@0.17.2': - resolution: {integrity: sha512-aAG6yRf6r0wQ29bkS+x97BIs64ZLxeE/ARwyS6wrldMm3C1MdKwCcnnEwMC1slI8wuxJOpiUH9MioC0A0i+GJw==} - - '@types/serve-static@1.15.3': - resolution: {integrity: sha512-yVRvFsEMrv7s0lGhzrggJjNOSmZCdgCjw9xWrPr/kNNLp6FaDfMC1KaYl3TSJ0c58bECwNBMoQrZJ8hA8E1eFg==} + '@types/serve-static@1.15.7': + resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} '@types/sinonjs__fake-timers@8.1.1': resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} - '@types/sizzle@2.3.3': - resolution: {integrity: sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==} + '@types/sizzle@2.3.9': + resolution: {integrity: sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==} - '@types/stats.js@0.17.1': - resolution: {integrity: sha512-OgfYE1x2w1jRUXzzKABX+kOdwz2y9PE0uSwnZabkWfJTWOzm7Pvfm4JI2xqRE0q2nwUe2jZLWcrcnhd9lQU63w==} + '@types/stats.js@0.17.3': + resolution: {integrity: sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==} '@types/three@0.154.0': resolution: {integrity: sha512-IioqpGhch6FdLDh4zazRn3rXHj6Vn2nVOziJdXVbJFi9CaI65LtP9qqUtpzbsHK2Ezlox8NtsLNHSw3AQzucjA==} @@ -2868,32 +3170,35 @@ packages: '@types/three@0.156.0': resolution: {integrity: sha512-733bXDSRdlrxqOmQuOmfC1UBRuJ2pREPk8sWnx9MtIJEVDQMx8U0NQO5MVVaOrjzDPyLI+cFPim2X/ss9v0+LQ==} - '@types/trusted-types@2.0.3': - resolution: {integrity: sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} '@types/ua-parser-js@0.7.39': resolution: {integrity: sha512-P/oDfpofrdtF5xw433SPALpdSchtJmY7nsJItf8h3KXqOslkbySh8zq4dSWXH2oTjRvJ5PczVEoCZPow6GicLg==} - '@types/unist@2.0.8': - resolution: {integrity: sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==} + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} - '@types/unist@3.0.2': - resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@types/webxr@0.5.7': - resolution: {integrity: sha512-Rcgs5c2eNFnHp53YOjgtKfl/zWX1Y+uFGUwlSXrWcZWu3yhANRezmph4MninmqybUYT6g9ZE0aQ9QIdPkLR3Kg==} + '@types/uuid@9.0.8': + resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} - '@types/wicg-file-system-access@2023.10.2': - resolution: {integrity: sha512-nSiK8qt0O7sQmDcW3HYfvya7GDoD6ipgdcUFzk3QN+UBIqXeNg38Nh6VnKv7EIPfkVETRiquyMskCbpxUzgX1Q==} + '@types/wait-on@5.3.4': + resolution: {integrity: sha512-EBsPjFMrFlMbbUFf9D1Fp+PAB2TwmUn7a3YtHyD9RLuTIk1jDd8SxXVAoez2Ciy+8Jsceo2MYEYZzJ/DvorOKw==} - '@types/yargs-parser@21.0.1': - resolution: {integrity: sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ==} + '@types/webxr@0.5.21': + resolution: {integrity: sha512-geZIAtLzjGmgY2JUi6VxXdCrTb99A7yP49lxLr2Nm/uIK0PkkxcEi4OGhoGDO4pxCf3JwGz2GiJL2Ej4K2bKaA==} - '@types/yargs@17.0.28': - resolution: {integrity: sha512-N3e3fkS86hNhtk6BEnc0rj3zcehaxx8QWhCROJkqpl5Zaoi7nAic3jH8q94jVD3zu5LGk+PUB6KAiDmimYOEQw==} + '@types/wicg-file-system-access@2023.10.5': + resolution: {integrity: sha512-e9kZO9kCdLqT2h9Tw38oGv9UNzBBWaR1MzuAavxPcsV/7FJ3tWbU6RI3uB+yKIDPGLkGVbplS52ub0AcRLvrhA==} - '@types/yauzl@2.10.1': - resolution: {integrity: sha512-CHzgNU3qYBnp/O4S3yv2tXPlvMTq0YWSTVg2/JYLqWZGHwwgJGAwd00poay/11asPq8wLFwHzubyInqHIFmmiw==} + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} @@ -2909,8 +3214,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@6.7.3': - resolution: {integrity: sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==} + '@typescript-eslint/parser@6.21.0': + resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -2923,10 +3228,14 @@ packages: resolution: {integrity: sha512-AxjgxDn27hgPpe2rQe19k0tXw84YCOsjDJ2r61cIebq1t+AIxbgiXKvD4999Wk49GVaAcdJ/d49FYel+Pp3jjw==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/scope-manager@6.7.3': - resolution: {integrity: sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==} + '@typescript-eslint/scope-manager@6.21.0': + resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/scope-manager@8.26.0': + resolution: {integrity: sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/type-utils@6.1.0': resolution: {integrity: sha512-kFXBx6QWS1ZZ5Ni89TyT1X9Ag6RXVIVhqDs0vZE/jUeWlBv/ixq2diua6G7ece6+fXw3TvNRxP77/5mOMusx2w==} engines: {node: ^16.0.0 || >=18.0.0} @@ -2941,10 +3250,14 @@ packages: resolution: {integrity: sha512-+Gfd5NHCpDoHDOaU/yIF3WWRI2PcBRKKpP91ZcVbL0t5tQpqYWBs3z/GGhvU+EV1D0262g9XCnyqQh19prU0JQ==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/types@6.7.3': - resolution: {integrity: sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==} + '@typescript-eslint/types@6.21.0': + resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/types@8.26.0': + resolution: {integrity: sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@6.1.0': resolution: {integrity: sha512-nUKAPWOaP/tQjU1IQw9sOPCDavs/iU5iYLiY/6u7gxS7oKQoi4aUxXS1nrrVGTyBBaGesjkcwwHkbkiD5eBvcg==} engines: {node: ^16.0.0 || >=18.0.0} @@ -2954,8 +3267,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@6.7.3': - resolution: {integrity: sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==} + '@typescript-eslint/typescript-estree@6.21.0': + resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -2963,20 +3276,40 @@ packages: typescript: optional: true + '@typescript-eslint/typescript-estree@8.26.0': + resolution: {integrity: sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/utils@6.1.0': resolution: {integrity: sha512-wp652EogZlKmQoMS5hAvWqRKplXvkuOnNzZSE0PVvsKjpexd/XznRVHAtrfHFYmqaJz0DFkjlDsGYC9OXw+OhQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 + '@typescript-eslint/utils@8.26.0': + resolution: {integrity: sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/visitor-keys@6.1.0': resolution: {integrity: sha512-yQeh+EXhquh119Eis4k0kYhj9vmFzNpbhM3LftWQVwqVjipCkwHBQOZutcYW+JVkjtTG9k8nrZU1UoNedPDd1A==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/visitor-keys@6.7.3': - resolution: {integrity: sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==} + '@typescript-eslint/visitor-keys@6.21.0': + resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/visitor-keys@8.26.0': + resolution: {integrity: sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@vitejs/plugin-react@3.1.0': resolution: {integrity: sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==} engines: {node: ^14.18.0 || >=16.0.0} @@ -3008,24 +3341,24 @@ packages: resolution: {integrity: sha512-7vCVgm1E1IZ2cujiitFk9550Vgu2XAOn1ff90di638fMmTK0XkFMXKsSR/nGZmYKt+XiTMI/0B3TvreqbVjOug==} engines: {node: '>=16'} - '@xmcl/core@2.12.0': - resolution: {integrity: sha512-rcxy29i2fjGFpe6sEvaJxYHFGlfYMcJwElbk6TIUCrKNOiMhyLZeBtCJSk38hvaYF0kiROA3c4EJeWNGHf2zVw==} + '@xmcl/core@2.13.0': + resolution: {integrity: sha512-1BslEWUr234zZZTq9Q3QDm8APReYx7phy6PY5fodiztwblYbgipsd89vfx+Qvjc1xWpGtjei0AvxubUDeMFTgA==} engines: {node: '>=16.0'} - '@xmcl/file-transfer@1.0.3': - resolution: {integrity: sha512-p5JsUQpNShqW4VpqaKXcQzYSO9o/9UGjXZfb5aNt/24Ty+j9qepQyPo4P1CFwfzgFuf9GGhH5cPUi6nShlKS+g==} + '@xmcl/file-transfer@1.0.6': + resolution: {integrity: sha512-WVnCTyHTqUUIMsqgGnkmQqov9/qxKWWBj+wjn6pMotpCJHu3gKkLqVoD76IQeTgUBIoh5sGgGbYMZmpRlqCGzw==} engines: {node: '>=16.0'} '@xmcl/forge-site-parser@2.0.9': resolution: {integrity: sha512-OHKG2KYE+F6TSeOQmymuGoqEifxbJb3w3X/hmxMNeqtewiYukJldPmKO559ZFnZnOuMQEnr+X0dMbTQwWs5dFg==} engines: {node: '>=16'} - '@xmcl/installer@5.1.0': - resolution: {integrity: sha512-KpoxpfYdUWH4U4Yat7RifS1JZajArOdfgsJ/LdU90y6Fc3hKhHSJsiRudk1VxASTyMXKCM0lWVxH5JzywRHBDw==} + '@xmcl/installer@5.4.0': + resolution: {integrity: sha512-Y4UK6WWogDdgvcAUQnUPoJidlkuVQP5dSV5QueJhKeEJAA3lmGklwV8Dp8z0/92ITQ45OBsB7g08qV3eec4G6w==} engines: {node: '>=16.0'} - '@xmcl/task@4.0.6': - resolution: {integrity: sha512-h0AR7DQm6xxBgROPnRi0EY8DlaDQwuGzPA5lFRMD4EsnpHJ/3fPdzwbMLb81ZxKJlLSCn3hVR2yI0mSKIm5Heg==} + '@xmcl/task@4.1.0': + resolution: {integrity: sha512-5Gqo/gltcenXTvRUz3H1Q2tNw9wWbOjeOVd9TeRNtBAOaKmdTD7iMhOIbdei71BSZ9FkVEhcUjO+PL+y+WNHoQ==} '@xmcl/text-component@2.1.3': resolution: {integrity: sha512-LdUZgC5+8F23J2ZkZi7aZb87QBNfxwJqhUyts8YBQYwxQPwei20TOBm2hr69euoAeDo7NDfbLXssD4mUvsAS0Q==} @@ -3054,17 +3387,29 @@ 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.104': + resolution: {integrity: sha512-jGhQ7fn7o8UN+mUwZbt9674D37YLuBi+Au4TwKcopCA6huIQdHTFNl2e+0ZSTI5mnhN+NpyVoR3vmtH6L58vHQ==} engines: {node: '>=8'} hasBin: true - '@zardoy/react-util@0.2.0': - resolution: {integrity: sha512-glABtx54mh4XSaK6BNALWE3mlshPjcPwPsRj/GnOXEA7WJY/6n43iJoukbaYF3758mGZRU5Fq6gklyFjBg0yHQ==} + '@zardoy/flying-squid@0.0.49': + resolution: {integrity: sha512-Kt4wr5/R+44tcLU9gjuNG2an9weWeKEpIoKXfsgJN2GGQqdnbd5nBpxfGDdgZ9aMdFugsVW8BsyPZNhj9vbMXA==} + engines: {node: '>=8'} + hasBin: true + + '@zardoy/maxrects-packer@2.7.4': + resolution: {integrity: sha512-ZIDcSdtSg6EhKFxGYWCcTnA/0YVbpixBL+psUS6ncw4IvdDF5hWauMU3XeCfYwrT/88QFgAq/Pafxt+P9OJyoQ==} + + '@zardoy/react-util@0.2.7': + resolution: {integrity: sha512-LJOml3y8wa5OxvNgDKMceP7kaFHkw2nX9y/RQGMv2sijTEnc4gCd3yNtc4fibu1PFWZlupb6UvsNe45o7UwElg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: + '@nextui-org/react': ^2.4.6 react: ^18.2.0 - react-dom: ^18.0.0 + react-dom: '>=18.0.0' + peerDependenciesMeta: + '@nextui-org/react': + optional: true '@zardoy/utils@0.0.11': resolution: {integrity: sha512-d6xBnSFCOa98HcL52xSBflJKjKpxfRhtr1eVexy89YujeCHSQhUMmSz9h07xyrulfW60k9tSeYH5reuqoh4l4w==} @@ -3093,8 +3438,8 @@ packages: resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} engines: {node: '>=0.4.0'} - acorn-walk@8.2.0: - resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} acorn@7.4.1: @@ -3102,8 +3447,8 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - acorn@8.10.0: - resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + acorn@8.14.1: + resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} engines: {node: '>=0.4.0'} hasBin: true @@ -3111,9 +3456,9 @@ packages: resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} engines: {node: '>= 10.0.0'} - adm-zip@0.5.12: - resolution: {integrity: sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==} - engines: {node: '>=6.0'} + adm-zip@0.5.16: + resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} + engines: {node: '>=12.0'} aes-js@3.1.2: resolution: {integrity: sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==} @@ -3129,12 +3474,8 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} - agent-base@7.1.0: - resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} - engines: {node: '>= 14'} - - agentkeepalive@4.5.0: - resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} engines: {node: '>= 8.0.0'} aggregate-error@3.1.0: @@ -3144,8 +3485,8 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} animejs@3.2.1: resolution: {integrity: sha512-sWno3ugFryK5nhiDm/2BKeFCpZv7vzerWUcUPyAZLDhMek3+S/p418ldZJbJXo5ZUOpfm2kP2XRO4NJcULMy9A==} @@ -3162,8 +3503,8 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.0.1: - resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} engines: {node: '>=12'} ansi-styles@3.2.1: @@ -3188,10 +3529,21 @@ packages: any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + anymatch@2.0.0: + resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + apache-crypt@1.2.6: + resolution: {integrity: sha512-072WetlM4blL8PREJVeY+WHiUh1R5VNt2HfceGS8aKqttPHcmqE5pkKuXPz/ULmJOFkc8Hw3kfKl6vy7Qka6DA==} + engines: {node: '>=8'} + + apache-md5@1.1.8: + resolution: {integrity: sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA==} + engines: {node: '>=8'} + app-root-dir@1.0.2: resolution: {integrity: sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==} @@ -3204,10 +3556,12 @@ packages: are-we-there-yet@2.0.0: resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} engines: {node: '>=10'} + deprecated: This package is no longer supported. are-we-there-yet@3.0.1: resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -3215,56 +3569,63 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - aria-hidden@1.2.3: - resolution: {integrity: sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==} + aria-hidden@1.2.4: + resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} engines: {node: '>=10'} - array-buffer-byte-length@1.0.0: - resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + arr-diff@4.0.0: + resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} + engines: {node: '>=0.10.0'} - array-buffer-byte-length@1.0.1: - resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + arr-flatten@1.1.0: + resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} + engines: {node: '>=0.10.0'} + + arr-union@3.1.0: + resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} + engines: {node: '>=0.10.0'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - array-includes@3.1.7: - resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} - engines: {node: '>= 0.4'} - array-includes@3.1.8: resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + array-unique@0.3.2: + resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} + engines: {node: '>=0.10.0'} + array.prototype.findlast@1.2.5: resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} - array.prototype.flat@1.3.2: - resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} engines: {node: '>= 0.4'} - array.prototype.flatmap@1.3.2: - resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} engines: {node: '>= 0.4'} - array.prototype.toreversed@1.1.2: - resolution: {integrity: sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==} - - array.prototype.tosorted@1.1.3: - resolution: {integrity: sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==} - - arraybuffer.prototype.slice@1.0.2: - resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} engines: {node: '>= 0.4'} - arraybuffer.prototype.slice@1.0.3: - resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} arraybuffer.slice@0.0.7: @@ -3274,8 +3635,8 @@ packages: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} - asn1.js@5.4.1: - resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} + asn1.js@4.10.1: + resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} asn1@0.2.3: resolution: {integrity: sha512-6i37w/+EhlWlGUJff3T/Q8u1RGmP5wgbiwYnOnbOqvtrPxT63/sYFyP9RcpxtxGymtfA075IvmOnL7ycNOWl3w==} @@ -3287,19 +3648,15 @@ packages: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} - assert@2.0.0: - resolution: {integrity: sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==} + assert@2.1.0: + resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - ast-types@0.14.2: - resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==} - engines: {node: '>=4'} - - ast-types@0.15.2: - resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} - engines: {node: '>=4'} + assign-symbols@1.0.0: + resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} + engines: {node: '>=0.10.0'} ast-types@0.16.1: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} @@ -3309,14 +3666,21 @@ packages: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} + async-each@1.0.6: + resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + async-limiter@1.0.1: resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} async@2.6.4: resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} - async@3.2.5: - resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -3325,9 +3689,10 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - available-typed-arrays@1.0.5: - resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} - engines: {node: '>= 0.4'} + atob@2.1.2: + resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} + engines: {node: '>= 4.5.0'} + hasBin: true available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} @@ -3336,12 +3701,15 @@ packages: aws-sign2@0.7.0: resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} - aws4@1.12.0: - resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==} + aws4@1.13.2: + resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} axios@0.21.4: resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} + axios@1.8.2: + resolution: {integrity: sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==} + babel-core@7.0.0-bridge.0: resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} peerDependencies: @@ -3355,18 +3723,18 @@ packages: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} - babel-plugin-polyfill-corejs2@0.4.5: - resolution: {integrity: sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==} + babel-plugin-polyfill-corejs2@0.4.12: + resolution: {integrity: sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-polyfill-corejs3@0.8.3: - resolution: {integrity: sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==} + babel-plugin-polyfill-corejs3@0.11.1: + resolution: {integrity: sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-polyfill-regenerator@0.5.2: - resolution: {integrity: sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==} + babel-plugin-polyfill-regenerator@0.6.3: + resolution: {integrity: sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 @@ -3390,23 +3758,37 @@ packages: resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} engines: {node: ^4.5.0 || >= 5.9} + base@0.11.2: + resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} + engines: {node: '>=0.10.0'} + basic-auth@2.0.1: resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} engines: {node: '>= 0.8'} + batch@0.6.1: + resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} + bcrypt-pbkdf@1.0.2: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + bcryptjs@2.4.3: + resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} + better-opn@3.0.2: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} - big-integer@1.6.51: - resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} + big-integer@1.6.52: + resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} - binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + binary-extensions@1.13.1: + resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} + engines: {node: '>=0.10.0'} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} bindings@1.5.0: @@ -3430,18 +3812,14 @@ packages: bmp-js@0.1.0: resolution: {integrity: sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==} - bn.js@4.12.0: - resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + bn.js@4.12.1: + resolution: {integrity: sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==} bn.js@5.2.1: resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - body-parser@1.20.1: - resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - - body-parser@1.20.2: - resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} boolbase@1.0.0: @@ -3457,8 +3835,12 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + braces@2.3.2: + resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} + engines: {node: '>=0.10.0'} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} brorand@1.1.0: @@ -3485,11 +3867,13 @@ packages: browserify-des@1.0.2: resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} - browserify-rsa@4.1.0: - resolution: {integrity: sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==} + browserify-rsa@4.1.1: + resolution: {integrity: sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==} + engines: {node: '>= 0.10'} - browserify-sign@4.2.1: - resolution: {integrity: sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==} + browserify-sign@4.2.3: + resolution: {integrity: sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==} + engines: {node: '>= 0.12'} browserify-zlib@0.1.4: resolution: {integrity: sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==} @@ -3497,8 +3881,8 @@ packages: browserify-zlib@0.2.0: resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} - browserslist@4.21.10: - resolution: {integrity: sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==} + browserslist@4.24.4: + resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -3525,9 +3909,6 @@ packages: buffer-xor@1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -3535,19 +3916,13 @@ packages: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} - bytes@3.0.0: - resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} - engines: {node: '>= 0.8'} + builtin-status-codes@3.0.0: + resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - c8@7.14.0: - resolution: {integrity: sha512-i04rtkkcNcCf7zsQcSv/T9EbUn4RXQ6mropeMcjFOsQXQ0iGLAr/xT6TImQg4+U9hmNpN9XdvPkjUL1IzbgxJw==} - engines: {node: '>=10.12.0'} - hasBin: true - cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -3556,15 +3931,24 @@ packages: resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + cache-base@1.0.1: + resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} + engines: {node: '>=0.10.0'} + cachedir@2.4.0: resolution: {integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==} engines: {node: '>=6'} - call-bind@1.0.2: - resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} - call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} callsites@3.1.0: @@ -3586,8 +3970,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001524: - resolution: {integrity: sha512-Jj917pJtYg9HSJBF95HVX3Cdr89JUyLT4IZ8SvM5aDRni95swKgYi3TgYLH5hnGfPE/U1dg6IfZ50UsIlLkwSA==} + caniuse-lite@1.0.30001713: + resolution: {integrity: sha512-wCIWIg+A4Xr7NfhTuHdX+/FKh3+Op3LBbSp2N5Pfx6T/LhdQy3GTyoTg48BReaW/MyMNZAkTadsBtai3ldWK0Q==} canvas@2.11.2: resolution: {integrity: sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==} @@ -3599,15 +3983,11 @@ packages: caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} - cbor-extract@2.2.0: - resolution: {integrity: sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==} - hasBin: true + centra@2.7.0: + resolution: {integrity: sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==} - cbor-x@1.5.4: - resolution: {integrity: sha512-PVKILDn+Rf6MRhhcyzGXi5eizn1i0i3F8Fe6UMMxXBnWkalq9+C5+VTmlIjAYM4iF2IYF2N+zToqAfYOp+3rfw==} - - chai@4.3.10: - resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==} + chai@4.5.0: + resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} engines: {node: '>=4'} chalk@2.4.2: @@ -3618,15 +3998,22 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + change-case@4.1.2: resolution: {integrity: sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==} - change-case@5.1.2: - resolution: {integrity: sha512-CAtbGEDulyjzs05RXy3uKcwqeztz/dMEuAc1Xu9NQBsbrhuGMneL0u9Dj5SoutLKBFYun8txxYIwhjtLNfUmCA==} + change-case@5.4.4: + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + charenc@0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} @@ -3634,8 +4021,11 @@ packages: resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} engines: {node: '>= 0.8.0'} - chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + chokidar@2.1.8: + resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} chownr@1.1.4: @@ -3645,12 +4035,20 @@ packages: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} - ci-info@3.8.0: - resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - cipher-base@1.0.4: - resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + cipher-base@1.0.6: + resolution: {integrity: sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==} + engines: {node: '>= 0.10'} + + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + class-utils@0.3.6: + resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} + engines: {node: '>=0.10.0'} classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} @@ -3667,21 +4065,18 @@ packages: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} - cli-spinners@2.9.1: - resolution: {integrity: sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==} + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - cli-table3@0.6.3: - resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} engines: {node: 10.* || >= 12.*} cli-truncate@2.1.0: resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} engines: {node: '>=8'} - cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -3698,12 +4093,9 @@ 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==} + collection-visit@1.0.0: + resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} + engines: {node: '>=0.10.0'} color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -3712,9 +4104,6 @@ packages: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - color-diff@1.4.0: - resolution: {integrity: sha512-4oDB/o78lNdppbaqrg0HjOp7pHmUc+dfCxWKWFnQg6AB/1dkjtBDop3RZht5386cq9xBUDRvDvSCA7WUlM9Jqw==} - color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} @@ -3767,8 +4156,8 @@ packages: component-emitter@1.2.1: resolution: {integrity: sha512-jPatnhd33viNplKjqXKRkGU345p263OIWzDL2wH3LGIGp5Kojo+uXizHmOADRvhGFFTnJqX3jBAKP6vvmSDKcA==} - component-emitter@1.3.0: - resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==} + component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} component-inherit@0.0.3: resolution: {integrity: sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA==} @@ -3777,8 +4166,8 @@ packages: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} - compression@1.7.4: - resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} + compression@1.8.0: + resolution: {integrity: sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==} engines: {node: '>= 0.8.0'} concat-map@0.0.1: @@ -3788,9 +4177,23 @@ packages: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} engines: {'0': node >= 0.8} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + confusing-browser-globals@1.0.11: resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} + connect@3.7.0: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + engines: {node: '>= 0.10.0'} + + consola@3.4.0: + resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==} + engines: {node: ^14.18.0 || >=16.10.0} + + console-browserify@1.2.0: + resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} + console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} @@ -3808,8 +4211,8 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - contro-max@0.1.8: - resolution: {integrity: sha512-5SoeudO8Zzfj/gbFTDrMRFJny02+MY1lBtb2NyCNiBLtHAfvhWZxZs/Z3yJvKL2rY/qKUZs9gTQOIDygBcBrdw==} + contro-max@0.1.9: + resolution: {integrity: sha512-zH9FB60EzhHKublD92d11QuarYRTdYci5rvDgwDr5XXwUqae5mr6IgzXGcr78T2odnO/Aeqmrf32RDwJIl5GfQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} convert-source-map@1.9.0: @@ -3825,18 +4228,26 @@ packages: resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} engines: {node: '>= 0.6'} - cookie@0.5.0: - resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + copy-descriptor@0.1.1: + resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} + engines: {node: '>=0.10.0'} + copy-to-clipboard@3.3.3: resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} - core-js-compat@3.32.1: - resolution: {integrity: sha512-GSvKDv4wE0bPnQtjklV101juQ85g6H3rm5PDP20mqlS5j0kXF3pP97YvAu5hl+uFHqMictp3b2VxOHljWMAtuA==} + core-js-compat@3.41.0: + resolution: {integrity: sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==} - core-js@3.32.1: - resolution: {integrity: sha512-lqufgNn9NLnESg5mQeYsxQP5w7wrViSj0jr/kv6ECQiByzQkrn1MKvV0L3acttpDqfQrHLwr2KCMgX5b8X+lyQ==} + core-js@3.41.0: + resolution: {integrity: sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA==} core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} @@ -3868,16 +4279,20 @@ packages: crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} - cross-spawn@6.0.5: - resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} + cross-spawn@6.0.6: + resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==} engines: {node: '>=4.8'} - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - crypto-browserify@3.12.0: - resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} + crypt@0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + + crypto-browserify@3.12.1: + resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==} + engines: {node: '>= 0.10'} crypto-random-string@2.0.0: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} @@ -3897,8 +4312,8 @@ packages: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} - csstype@3.1.2: - resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} cypress-esbuild-preprocessor@1.0.2: resolution: {integrity: sha512-JsFnm6fBQt/OEzstknJ1KLMTuUERUaG0ZB9fk0KdNUlZqxaVEoQ9/pFvKmqRfzUe2y00cWD++ptccQA4tNAAlQ==} @@ -3918,20 +4333,20 @@ packages: resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} engines: {node: '>=0.10'} - data-view-buffer@1.0.1: - resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} - data-view-byte-length@1.0.1: - resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} engines: {node: '>= 0.4'} - data-view-byte-offset@1.0.0: - resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} - dayjs@1.11.9: - resolution: {integrity: sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==} + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} debounce@1.2.1: resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} @@ -3969,8 +4384,26 @@ packages: supports-color: optional: true - debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -3990,8 +4423,12 @@ packages: resolution: {integrity: sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==} engines: {node: '>=10'} - decode-named-character-reference@1.0.2: - resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} + decode-named-character-reference@1.1.0: + resolution: {integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==} + + decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} decompress-response@4.2.1: resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==} @@ -4001,8 +4438,8 @@ packages: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} - deep-eql@4.1.3: - resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + deep-eql@4.1.4: + resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} engines: {node: '>=6'} deep-extend@0.6.0: @@ -4016,6 +4453,9 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + deepslate@0.23.5: + resolution: {integrity: sha512-FjBBbuPUI1Y/dXtUc4WiCJSA7s7yRAXepD7qWRF6wX5m/q7AVRauMEShu8lphRvqCtJyxcYFZmISwX5OOH/tWw==} + default-browser-id@3.0.0: resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==} engines: {node: '>=12'} @@ -4023,10 +4463,6 @@ packages: defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - define-data-property@1.1.0: - resolution: {integrity: sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==} - engines: {node: '>= 0.4'} - define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -4039,8 +4475,20 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - defu@6.1.2: - resolution: {integrity: sha512-+uO4+qr7msjNNWKYPHqN/3+Dx3NFkmIzayk2L1MyZQlvgZb/J1A0fo410dpKrN2SnqFjt8n4JL8fDJE0wIgjFQ==} + define-property@0.2.5: + resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} + engines: {node: '>=0.10.0'} + + define-property@1.0.0: + resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} + engines: {node: '>=0.10.0'} + + define-property@2.0.2: + resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} + engines: {node: '>=0.10.0'} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} del@6.1.1: resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} @@ -4053,18 +4501,23 @@ packages: delegates@1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + depd@1.1.2: + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} - dequal@1.0.0: - resolution: {integrity: sha512-/Nd1EQbQbI9UbSHrMiKZjFLrXSnU328iQdZKPQf78XQI6C+gutkFUeoHpG5J08Ioa6HeRbRNFpSIclh1xyG0mw==} - engines: {node: '>=6'} - dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + derive-valtio@0.1.0: + resolution: {integrity: sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A==} + peerDependencies: + valtio: '*' + des.js@1.1.0: resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} @@ -4079,8 +4532,8 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} - detect-libc@2.0.2: - resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + detect-libc@2.0.3: + resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} detect-node-es@1.1.0: @@ -4090,17 +4543,21 @@ packages: resolution: {integrity: sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==} engines: {node: '>=12'} - detect-port@1.5.1: - resolution: {integrity: sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==} + detect-port@1.6.1: + resolution: {integrity: sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==} + engines: {node: '>= 4.0.0'} hasBin: true 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/cfaad2d1d5909fdfa63c8cc7bc05fb5e87782d71: + resolution: {tarball: https://codeload.github.com/zardoy/diamond-square/tar.gz/cfaad2d1d5909fdfa63c8cc7bc05fb5e87782d71} version: 1.3.0 + diff-match-patch@1.0.5: + resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} + diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4144,6 +4601,10 @@ packages: dom-walk@0.1.2: resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} + domain-browser@5.7.0: + resolution: {integrity: sha512-edTFu0M/7wO1pXY6GDxVNVW086uqwWYIHP98txhcPyV995X21JIH2DtYp33sQJOupYoXKe9RwTw2Ya2vWaquTQ==} + engines: {node: '>=4'} + domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} @@ -4151,8 +4612,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - domutils@3.1.0: - resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} @@ -4161,12 +4622,19 @@ packages: resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} engines: {node: '>=12'} - dotenv@16.3.1: - resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} + dotenv@16.4.7: + resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} engines: {node: '>=12'} - draco3d@1.5.6: - resolution: {integrity: sha512-+3NaRjWktb5r61ZFoDejlykPEFKT5N/LkbXsaddlw6xNSXBanUYpFc2AXXpbJDilPHazcSreU/DpQIaxfX0NfQ==} + draco3d@1.5.7: + resolution: {integrity: sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} duplexify@3.7.1: resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} @@ -4183,16 +4651,16 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - ejs@3.1.9: - resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==} + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.4.504: - resolution: {integrity: sha512-cSMwIAd8yUh54VwitVRVvHK66QqHWE39C3DRj8SWiXitEpVSY3wNPD9y1pxQtLIi4w3UdzF9klLsmuPshz09DQ==} + electron-to-chromium@1.5.113: + resolution: {integrity: sha512-wjT2O4hX+wdWPJ76gWSkMhcHAV2PTMX+QetUCPYEdCIe+cxmgzzSSiGRCKW8nuh4mwKZlpv0xvoW7OF2X+wmHg==} - elliptic@6.5.4: - resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} emit-then@2.0.0: resolution: {integrity: sha512-y5JHnrygHnCndtqVHHDhCr0ZzzWHK5RBTczWRlGSIR5UnGHBXuxpoaE0UB5E82qym8ma2dI799wDSSJN2e4VSg==} @@ -4208,6 +4676,10 @@ packages: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} @@ -4217,25 +4689,25 @@ packages: endian-toggle@0.0.0: resolution: {integrity: sha512-ShfqhXeHRE4TmggSlHXG8CMGIcsOsqDw/GcoPcosToE59Rm9e4aXaMhEQf2kPBsBRrKem1bbOAv5gOKnkliMFQ==} - engine.io-client@3.5.3: - resolution: {integrity: sha512-qsgyc/CEhJ6cgMUwxRRtOndGVhIu5hpL5tR4umSpmX/MvkFoIxUTM7oFMDQumHNzlNLwSVy6qhstFPoWTf7dOw==} + engine.io-client@3.5.4: + resolution: {integrity: sha512-ydc8uuMMDxC5KCKNJN3zZKYJk2sgyTuTZQ7Aj1DJSsLKAcizA/PzWivw8fZMIjJVBo2CJOYzntv4FSjY/Lr//g==} - engine.io-client@6.5.2: - resolution: {integrity: sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==} + engine.io-client@6.6.3: + resolution: {integrity: sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==} engine.io-parser@2.2.1: resolution: {integrity: sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==} - engine.io-parser@5.2.1: - resolution: {integrity: sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==} + engine.io-parser@5.2.3: + resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} engines: {node: '>=10.0.0'} - engine.io@3.6.1: - resolution: {integrity: sha512-dfs8EVg/i7QjFsXxn7cCRQ+Wai1G1TlEvHhdYEi80fxn5R1vZ2K661O6v/rezj1FP234SZ14r9CmJke99iYDGg==} + engine.io@3.6.2: + resolution: {integrity: sha512-C4JjGQZLY3kWlIDx0BQNKizbrfpb7NahxDztGdN5jrPK2ghmXiNDN+E/t0JzDeNRZxPVaszxEng42Pmj27X/0w==} engines: {node: '>=8.0.0'} - engine.io@6.5.3: - resolution: {integrity: sha512-IML/R4eG/pUS5w7OfcDE0jKrljWS9nwnEfsxWCIJF5eO6AHo6+Hlv+lQbdlAYsiJPHzUthLm1RUjnBzWOs45cw==} + engine.io@6.6.4: + resolution: {integrity: sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==} engines: {node: '>=10.2.0'} enquirer@2.4.1: @@ -4250,8 +4722,8 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} - envinfo@7.10.0: - resolution: {integrity: sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==} + envinfo@7.14.0: + resolution: {integrity: sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==} engines: {node: '>=4'} hasBin: true @@ -4264,57 +4736,48 @@ packages: error-stack-parser@2.1.4: resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} - eruda@3.0.1: - resolution: {integrity: sha512-6q1Xdwga4JTr1mKSW4mzuWSSbmXgqpm/8Wa1QGFGfCWRjC0bCQjbS4u06M1te1moucIS3hBLlbSTPWYH2W0qbQ==} + eruda@3.4.1: + resolution: {integrity: sha512-RmaO5yD97URY/9Q0lye3cmmNPoXNKreeePIw7c/zllbscR92CjGFZFuQ70+0fLIvLcKW3Xha8DS8NFhmeNbEBQ==} - es-abstract@1.22.2: - resolution: {integrity: sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==} + es-abstract@1.23.9: + resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} engines: {node: '>= 0.4'} - es-abstract@1.23.3: - resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} engines: {node: '>= 0.4'} - es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-iterator-helpers@1.0.19: - resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} es-module-lexer@0.9.3: resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} - es-object-atoms@1.0.0: - resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} - es-set-tostringtag@2.0.1: - resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - es-set-tostringtag@2.0.3: - resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} engines: {node: '>= 0.4'} - es-shim-unscopables@1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} - - es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} - - es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es6-object-assign@1.1.0: - resolution: {integrity: sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==} - es6-promise@4.2.8: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} @@ -4329,8 +4792,8 @@ packages: peerDependencies: esbuild: '*' - esbuild-register@3.5.0: - resolution: {integrity: sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==} + esbuild-register@3.6.0: + resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} peerDependencies: esbuild: '>=0.12 <1' @@ -4339,18 +4802,18 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.19.11: - resolution: {integrity: sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==} + esbuild@0.19.12: + resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} engines: {node: '>=12'} hasBin: true - esbuild@0.19.3: - resolution: {integrity: sha512-UlJ1qUUA2jL2nNib1JTSkifQTcYTroFqRjwCFW4QYEKEsixXD5Tik9xML7zh2gTxkYTBKGHNH9y7txMwVyPbjw==} - engines: {node: '>=12'} + esbuild@0.25.0: + resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} + engines: {node: '>=18'} hasBin: true - escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} escape-html@1.0.3: @@ -4415,8 +4878,8 @@ packages: eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - eslint-module-utils@2.8.0: - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + eslint-module-utils@2.12.0: + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -4464,17 +4927,17 @@ packages: peerDependencies: eslint: '>=5.16.0' - eslint-plugin-react-hooks@4.6.0: - resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} engines: {node: '>=10'} peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - eslint-plugin-react@7.34.1: - resolution: {integrity: sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==} + eslint-plugin-react@7.37.4: + resolution: {integrity: sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==} engines: {node: '>=4'} peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 eslint-plugin-sonarjs@0.19.0: resolution: {integrity: sha512-6+s5oNk5TFtVlbRxqZN7FIGmjdPCYQKaTzFPmqieCmsU1kBYDzndTeQav0xtQNwZJWu5awWfTGe8Srq9xFOGnw==} @@ -4504,11 +4967,20 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint@8.50.0: - resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4518,8 +4990,8 @@ packages: engines: {node: '>=4'} hasBin: true - esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -4530,10 +5002,6 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} - estree-to-babel@3.2.1: - resolution: {integrity: sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==} - engines: {node: '>=8.3.0'} - estree-walker@1.0.1: resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} @@ -4548,6 +5016,9 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + event-stream@3.3.4: + resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} + event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -4584,12 +5055,16 @@ packages: resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} engines: {node: '>=6'} + expand-brackets@2.1.4: + resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} + engines: {node: '>=0.10.0'} + expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} - exponential-backoff@3.1.1: - resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} + exponential-backoff@3.1.2: + resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} express-ws@4.0.0: resolution: {integrity: sha512-KEyUw8AwRET2iFjFsI1EJQrJ/fHeGiJtgpYgEWG3yDv4l/To/m3a2GaYfeGyB3lsWdvbesjF5XCMx+SVBgAAYw==} @@ -4597,13 +5072,25 @@ packages: peerDependencies: express: ^4.0.0 || ^5.0.0-alpha.1 - express@4.18.2: - resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} + express@4.21.2: + resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend-shallow@3.0.2: + resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} + engines: {node: '>=0.10.0'} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + extglob@2.0.4: + resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} + engines: {node: '>=0.10.0'} + extract-zip@1.7.0: resolution: {integrity: sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==} hasBin: true @@ -4620,8 +5107,8 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} fast-json-stable-stringify@2.1.0: @@ -4630,17 +5117,21 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-loops@1.1.3: - resolution: {integrity: sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g==} - fast-shallow-equal@1.0.0: resolution: {integrity: sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==} + fast-uri@3.0.6: + resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + fastest-stable-stringify@2.0.2: resolution: {integrity: sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==} - fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + faye-websocket@0.11.4: + resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} + engines: {node: '>=0.8.0'} fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} @@ -4675,16 +5166,24 @@ packages: filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} - filesize@10.0.12: - resolution: {integrity: sha512-6RS9gDchbn+qWmtV2uSjo5vmKizgfCQeb5jKmqx8HyzA3MoLqqyQxN+QcjkGBJt7FjJ9qFce67Auyya5rRRbpw==} + filesize@10.1.6: + resolution: {integrity: sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==} engines: {node: '>= 10.4.0'} - fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + fill-range@4.0.0: + resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} + engines: {node: '>=0.10.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@1.2.0: - resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} + finalhandler@1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} + + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} find-cache-dir@2.1.0: @@ -4710,22 +5209,22 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - flat-cache@3.1.0: - resolution: {integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==} - engines: {node: '>=12.0.0'} + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} flatmap@0.0.3: resolution: {integrity: sha512-OuR+o7kHVe+x9RtIujPay7Uw3bvDZBZFSBXClEphZuSDLmZTqMdclasf4vFSsogC8baDz0eaC2NdO/2dlXHBKQ==} - flatted@3.2.7: - resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - flow-parser@0.218.0: - resolution: {integrity: sha512-mk4e7UK4P/W3tjrJyto6oxPuCjwvRMyzBh72hTl8T0dOcTzkP0M2JJHpncgyhKphMFi9pnjwHfc8e0oe4Uk3LA==} + flow-parser@0.263.0: + resolution: {integrity: sha512-F0Tr7SUvZ4BQYglFOkr8rCTO5FPjCwMhm/6i57h40F80Oz/hzzkqte4lGO0vGJ7THQonuXcTyYqCdKkAwt5d2w==} engines: {node: '>=0.4.0'} - follow-redirects@1.15.3: - resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==} + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -4733,24 +5232,16 @@ packages: debug: optional: true - follow-redirects@1.15.6: - resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} - for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + for-in@1.0.2: + resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} + engines: {node: '>=0.10.0'} - foreground-child@2.0.0: - resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} - engines: {node: '>=8.0.0'} - - foreground-child@3.1.1: - resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} forever-agent@0.6.1: @@ -4760,18 +5251,43 @@ packages: resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} engines: {node: '>= 0.12'} - form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + form-data@4.0.2: + resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} engines: {node: '>= 6'} forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} + fragment-cache@0.2.1: + resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} + engines: {node: '>=0.10.0'} + + framer-motion@12.9.2: + resolution: {integrity: sha512-R0O3Jdqbfwywpm45obP+8sTgafmdEcUoShQTAV+rB5pi+Y1Px/FYL5qLLRe5tPtBdN1J4jos7M+xN2VV2oEAbQ==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.2.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + from@0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -4779,14 +5295,14 @@ packages: resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} engines: {node: '>=14.14'} + fs-extra@11.3.0: + resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} + engines: {node: '>=14.14'} + fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} - fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - fs-extra@9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -4798,19 +5314,22 @@ packages: fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@1.2.13: + resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} + engines: {node: '>= 4.0'} + os: [darwin] + deprecated: Upgrade to fsevents v2 to mitigate potential security issues + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.1.6: - resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} engines: {node: '>= 0.4'} functions-have-names@1.2.3: @@ -4819,10 +5338,12 @@ packages: gauge@3.0.2: resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} engines: {node: '>=10'} + deprecated: This package is no longer supported. gauge@4.0.4: resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} @@ -4835,19 +5356,16 @@ packages: get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - get-intrinsic@1.2.1: - resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} - - get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} - get-npm-tarball-url@2.0.3: - resolution: {integrity: sha512-R/PW6RqyaBQNWYaSyfrh54/qtcnOp22FHCCiRhSSZj0FP3KQWCsxxt0DzIdVTbwTqe9CtQfvl/FPD4UIPt4pqw==} + get-npm-tarball-url@2.1.0: + resolution: {integrity: sha512-ro+DiMu5DXgRBabqXupW38h7WPZ9+Ad8UjwhvsmmN8w1sU7ab0nzAXvVZ4kqYg57OrqomRtJvepX5/xvFKNtjA==} engines: {node: '>=12.17'} get-own-enumerable-property-symbols@3.0.2: @@ -4861,6 +5379,10 @@ packages: resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} engines: {node: '>=8'} + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-stream@5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} @@ -4869,16 +5391,16 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - get-symbol-description@1.0.0: - resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-symbol-description@1.0.2: - resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} - engines: {node: '>= 0.4'} + get-tsconfig@4.10.0: + resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} - get-tsconfig@4.7.2: - resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + get-value@2.0.6: + resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} + engines: {node: '>=0.10.0'} getos@3.2.1: resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} @@ -4886,8 +5408,8 @@ packages: getpass@0.1.7: resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} - giget@1.1.3: - resolution: {integrity: sha512-zHuCeqtfgqgDwvXlR84UNgnJDuUHQcNI5OqWqFxxuk2BshuKbYhJWdxBsEo4PvKqoGh23lUAIvBNpChMLv7/9Q==} + giget@1.2.5: + resolution: {integrity: sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug==} hasBin: true github-from-package@0.0.0: @@ -4896,10 +5418,16 @@ packages: github-slugger@1.5.0: resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==} + gl-matrix@3.4.3: + resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==} + gl@6.0.2: resolution: {integrity: sha512-yBbfpChOtFvg5D+KtMaBFvj6yt3vUnheNAH+UrQH2TfDB8kr0tERdL0Tjhe0W7xJ6jR6ftQBluTZR9jXUnKe8g==} engines: {node: '>=14.0.0'} + glob-parent@3.1.0: + resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -4917,17 +5445,18 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.3.3: - resolution: {integrity: sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==} - engines: {node: '>=16 || 14 >=14.17'} + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} + deprecated: Glob versions prior to v9 are no longer supported global-dirs@3.0.1: resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} @@ -4940,14 +5469,10 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - globals@13.21.0: - resolution: {integrity: sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==} + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} - globalthis@1.0.3: - 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'} @@ -4959,8 +5484,9 @@ packages: glsl-tokenizer@2.1.5: resolution: {integrity: sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA==} - gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -4972,6 +5498,10 @@ packages: resolution: {integrity: sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==} hasBin: true + gzip-size@7.0.0: + resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + handlebars@4.7.8: resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} engines: {node: '>=0.4.7'} @@ -4981,8 +5511,9 @@ packages: resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} engines: {node: '>=6'} - has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} has-binary2@1.0.3: resolution: {integrity: sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==} @@ -4998,26 +5529,15 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - has-property-descriptors@1.0.0: - resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} - has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} engines: {node: '>= 0.4'} - has-proto@1.0.3: - resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} - engines: {node: '>= 0.4'} - - has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} has-tostringtag@1.0.2: @@ -5027,21 +5547,33 @@ packages: has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + has-value@0.3.1: + resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} + engines: {node: '>=0.10.0'} + + has-value@1.0.0: + resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} + engines: {node: '>=0.10.0'} + + has-values@0.1.4: + resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} + engines: {node: '>=0.10.0'} + + has-values@1.0.0: + resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} + engines: {node: '>=0.10.0'} + + has@1.0.4: + resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} engines: {node: '>= 0.4.0'} - hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} + hash-base@3.0.5: + resolution: {integrity: sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==} + engines: {node: '>= 0.10'} hash.js@1.1.7: resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - hasown@2.0.1: - resolution: {integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==} - engines: {node: '>= 0.4'} - hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -5060,6 +5592,9 @@ packages: resolution: {integrity: sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==} hasBin: true + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -5071,23 +5606,34 @@ packages: resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} engines: {node: '>=12'} - html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + html-entities@2.6.0: + resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} html-tags@3.3.1: resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} engines: {node: '>=8'} + http-auth@3.1.3: + resolution: {integrity: sha512-Jbx0+ejo2IOx+cRUYAGS1z6RGc6JfYUNkysZM4u4Sfk1uLlGv814F7/PIjQQAuThLdAWxb74JMGd5J8zex1VQg==} + engines: {node: '>=4.6.1'} + http-browserify@1.7.0: resolution: {integrity: sha512-Irf/LJXmE3cBzU1eaR4+NEX6bmVLqt1wkmDiA7kBwH7zmb0D8kBAXsDmQ88hhj/qv9iEZKlyGx/hrMcFi8sOHw==} http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + http-errors@1.6.3: + resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} + engines: {node: '>= 0.6'} + http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} + http-parser-js@0.5.9: + resolution: {integrity: sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==} + http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} @@ -5116,10 +5662,6 @@ packages: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} - https-proxy-agent@7.0.2: - resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==} - engines: {node: '>= 14'} - human-signals@1.1.1: resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} engines: {node: '>=8.12.0'} @@ -5131,11 +5673,12 @@ packages: humanize-ms@1.2.1: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} - hyphenate-style-name@1.0.4: - resolution: {integrity: sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==} + hyperdyperid@1.2.0: + resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==} + engines: {node: '>=10.18'} - iconify-icon@1.0.8: - resolution: {integrity: sha512-jvbUKHXf8EnGGArmhlP2IG8VqQLFFyTvTqb9LVL2TKTh7/eCCD1o2HHE9thpbJJb6B8hzhcFb6rOKhvo7reNKA==} + hyphenate-style-name@1.1.0: + resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==} iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} @@ -5151,8 +5694,8 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - ignore@5.2.4: - resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} image-size@0.7.5: @@ -5163,12 +5706,12 @@ packages: immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} - import-meta-resolve@3.0.0: - resolution: {integrity: sha512-4IwhLhNNA8yy445rPjD/lWh++7hMDOml2eHtd58eG7h+qK3EryMuuRbsHGPikCoAgIkkDnckKfWSk2iDla/ejg==} + import-meta-resolve@3.1.1: + resolution: {integrity: sha512-qeywsE/KC3w9Fd2ORrRDUw6nS/nLwZpXgfrOc2IILvZYnCaEMd+D56Vfg9k4G29gIeVi3XKql1RQatME8iYsiw==} imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} @@ -5190,6 +5733,10 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -5201,22 +5748,16 @@ packages: resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} engines: {node: '>=10'} - inline-style-prefixer@6.0.4: - resolution: {integrity: sha512-FwXmZC2zbeeS7NzGjJ6pAiqRhXR0ugUShSNb6GApMl6da0/XGc4MOJsoWAywia52EEWbXNSy0pzkwz/+Y+swSg==} + inline-style-prefixer@7.0.1: + resolution: {integrity: sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==} - internal-slot@1.0.5: - resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} - internal-slot@1.0.7: - resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} - engines: {node: '>= 0.4'} - - invariant@2.2.4: - resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - - ip@2.0.0: - resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} + ip-address@9.0.5: + resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + engines: {node: '>= 12'} ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} @@ -5226,15 +5767,16 @@ packages: resolution: {integrity: sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==} engines: {node: '>=8'} - is-arguments@1.1.1: - resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + is-accessor-descriptor@1.0.1: + resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} + engines: {node: '>= 0.10'} + + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} engines: {node: '>= 0.4'} - is-array-buffer@3.0.2: - resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} - - is-array-buffer@3.0.4: - resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} is-arrayish@0.2.1: @@ -5243,21 +5785,29 @@ packages: is-arrayish@0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-async-function@2.0.0: - resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} - is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-binary-path@1.0.1: + resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==} + engines: {node: '>=0.10.0'} is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} - is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + is-builtin-module@3.2.1: resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} engines: {node: '>=6'} @@ -5270,34 +5820,53 @@ packages: resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true - is-core-module@2.13.0: - resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} - - is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - - is-data-view@1.0.1: - resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} - is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + is-data-descriptor@1.0.1: + resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} is-deflate@1.0.0: resolution: {integrity: sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==} + is-descriptor@0.1.7: + resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==} + engines: {node: '>= 0.4'} + + is-descriptor@1.0.3: + resolution: {integrity: sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==} + engines: {node: '>= 0.4'} + is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} hasBin: true + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + + is-extendable@1.0.1: + resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} + engines: {node: '>=0.10.0'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - is-finalizationregistry@1.0.2: - resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} @@ -5306,10 +5875,14 @@ packages: is-function@1.0.2: resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==} - is-generator-function@1.0.10: - resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} engines: {node: '>= 0.4'} + is-glob@3.1.0: + resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} + engines: {node: '>=0.10.0'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -5340,18 +5913,18 @@ packages: resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} engines: {node: '>= 0.4'} - is-negative-zero@2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} - engines: {node: '>= 0.4'} - is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} - is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} + is-number@3.0.0: + resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} + engines: {node: '>=0.10.0'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -5384,8 +5957,8 @@ packages: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} - is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} is-regexp@1.0.0: @@ -5396,31 +5969,24 @@ packages: resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} engines: {node: '>= 0.4'} - is-shared-array-buffer@1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} - - is-shared-array-buffer@1.0.3: - resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} - is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} engines: {node: '>= 0.4'} - is-typed-array@1.1.12: - resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} - engines: {node: '>= 0.4'} - - is-typed-array@1.1.13: - resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} is-typedarray@1.0.0: @@ -5434,13 +6000,22 @@ packages: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} - is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - - is-weakset@2.0.3: - resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} engines: {node: '>= 0.4'} + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + is-wsl@1.1.0: + resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} + engines: {node: '>=4'} + is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} @@ -5460,6 +6035,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isobject@2.1.0: + resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} + engines: {node: '>=0.10.0'} + isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} @@ -5467,31 +6046,23 @@ packages: isstream@0.1.2: resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} - istanbul-lib-coverage@3.2.0: - resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} istanbul-lib-instrument@5.2.1: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} - istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} - istanbul-reports@3.1.6: - resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} - engines: {node: '>=8'} + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - iterator.prototype@1.1.2: - resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} - - jackspeak@2.3.0: - resolution: {integrity: sha512-uKmsITSsF4rUWQHzqaRUuyAir3fZfW3f202Ee34lz/gZCi970CPZwyQXLGNgWJvvZbvFyzeyGq0+4fcG/mBKZg==} - engines: {node: '>=14'} - - jake@10.8.7: - resolution: {integrity: sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==} + jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} engines: {node: '>=10'} hasBin: true @@ -5507,10 +6078,6 @@ packages: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-worker@26.6.2: - resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} - engines: {node: '>= 10.13.0'} - jest-worker@29.7.0: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -5518,8 +6085,12 @@ packages: jimp@0.10.3: resolution: {integrity: sha512-meVWmDMtyUG5uYjFkmzu0zBgnCvvxwWNi27c4cg55vWNVC9ES4Lcwb+ogx+uBBQE3Q+dLKjXaLl0JVW+nUNwbQ==} - jose@4.15.5: - resolution: {integrity: sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==} + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + + joi@17.13.3: + resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} jpeg-js@0.3.7: resolution: {integrity: sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==} @@ -5530,10 +6101,6 @@ packages: js-cookie@2.2.1: resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} - js-graph-algorithms@1.0.18: - resolution: {integrity: sha512-Gu1wtWzXBzGeye/j9BuyplGHscwqKRZodp/0M1vyBc19RJpblSwKGu099KwwaTx9cRIV+Qupk8xUMfEiGfFqSA==} - hasBin: true - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -5548,26 +6115,32 @@ packages: jsbn@0.1.1: resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} - jscodeshift@0.14.0: - resolution: {integrity: sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA==} + jsbn@1.1.0: + resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + + jscodeshift@0.15.2: + resolution: {integrity: sha512-FquR7Okgmc4Sd0aEDwqho3rEiKR3BdvuG9jfdHjLJ6JQoWSMpavug3AoIfnfWhxFlf+5pzQh8qjqz0DWFrNQzA==} hasBin: true peerDependencies: '@babel/preset-env': ^7.1.6 + peerDependenciesMeta: + '@babel/preset-env': + optional: true jsesc@0.5.0: resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} hasBin: true - jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} engines: {node: '>=6'} hasBin: true + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -5601,9 +6174,6 @@ packages: engines: {node: '>=6'} hasBin: true - jsonc-parser@3.2.0: - resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} - jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -5635,8 +6205,16 @@ packages: jws@3.2.2: resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} - keyv@4.5.3: - resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==} + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kind-of@3.2.2: + resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} + engines: {node: '>=0.10.0'} + + kind-of@4.0.0: + resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} + engines: {node: '>=0.10.0'} kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} @@ -5686,8 +6264,13 @@ packages: enquirer: optional: true - load-bmfont@1.4.1: - resolution: {integrity: sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA==} + live-server@1.2.2: + resolution: {integrity: sha512-t28HXLjITRGoMSrCOv4eZ88viHaBVIjKjdI5PO92Vxlu+twbk6aE0t7dVIaz6ZWkjPilYFV6OSdMYl9ybN2B4w==} + engines: {node: '>=0.10.0'} + hasBin: true + + load-bmfont@1.4.2: + resolution: {integrity: sha512-qElWkmjW9Oq1F9EI5Gt7aD9zcdHb9spJCW1L/dmPf7KzCCEJxq8nhHz5eCgI9aMf7vrG/wyaCqdsI+Iy9ZTlog==} load-json-file@4.0.0: resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} @@ -5720,6 +6303,7 @@ packages: lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} @@ -5762,29 +6346,24 @@ packages: resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} engines: {node: '>=10'} - long@5.2.3: - resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} + long@5.3.1: + resolution: {integrity: sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==} longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - looks-same@8.2.3: - resolution: {integrity: sha512-0LK5r4+9t2D56XPVNH3hhG4o0yBYUdeu9FEd8z0ZCs/2fR9zJQj+6ob6ued8iHk3yddrSAdUA+9YGVK2FBMGUw==} - engines: {node: '>= 12.0.0'} - loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - loupe@2.3.6: - resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} + loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} - lru-cache@10.0.1: - resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==} - engines: {node: 14 || >=16.14} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -5807,9 +6386,8 @@ packages: resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} engines: {node: '>=12'} - magic-string@0.30.4: - resolution: {integrity: sha512-Q/TKtsC5BPm0kGqgBIF9oXAs/xEf2vRKiIB4wCRQTJOQIByZ1d+NnUOotvJOvNpi5RNIgVOMC3pOuaP1ZTDlVg==} - engines: {node: '>=12'} + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} @@ -5819,10 +6397,6 @@ packages: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} - make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} - make-fetch-happen@10.2.1: resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -5830,6 +6404,10 @@ packages: makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + map-cache@0.2.2: + resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} + engines: {node: '>=0.10.0'} + map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -5841,16 +6419,48 @@ packages: map-or-similar@1.5.0: resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} - markdown-it@14.0.0: - resolution: {integrity: sha512-seFjF0FIcPt4P9U39Bq1JYblX0KZCjDLFFQPHpL5AzHpqPEKtosxmdq/LTVZnjfH7tjt9BxStm+wXcDBNuYmzw==} + map-stream@0.1.0: + resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + + map-visit@1.0.0: + resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} + engines: {node: '>=0.10.0'} + + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true - markdown-to-jsx@7.3.2: - resolution: {integrity: sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q==} + markdown-to-jsx@7.7.4: + resolution: {integrity: sha512-1bSfXyBKi+EYS3YY+e0Csuxf8oZ3decdfhOav/Z7Wrk89tjudyL5FOmwZQUoy0/qVXGUl+6Q3s2SWtpDEWITfQ==} engines: {node: '>= 10'} peerDependencies: react: ^18.2.0 + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mc-assets@0.2.62: + resolution: {integrity: sha512-RYZeD1+joNlPuUpi+tIWkbP0ieVJr+R6IFkI6/8juhSxx9zE4osoSmteybrfspGm8A6u+YbbY1epqRKEMwVR6Q==} + engines: {node: '>=18.0.0'} + + mc-bridge@0.1.3: + resolution: {integrity: sha512-H9jPt2xEU77itC27dSz3qazHYqN9qVsv4HgMPozg7RqQ1uwgXmEa+ojKIlDtXf/TLJsG6Kv4EbzGa8a1Wh72uA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + minecraft-data: 3.98.0 + + mcraft-fun-mineflayer@0.1.23: + resolution: {integrity: sha512-qmI1rQQ0Ro5zJdi99rClWLF+mS9JZffgNX2vyWWesS3Hsk3Xblp/8swYTJKHSaFpNgzkVfXV92fEIrBqeH6iKA==} + version: 0.1.23 + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + '@roamhq/wrtc': '*' + mineflayer: '>=4.x' + peerDependenciesMeta: + '@roamhq/wrtc': + optional: true + md5-file@4.0.0: resolution: {integrity: sha512-UC0qFwyAjn4YdPpKaDNw6gNxRf7Mcx7jC1UGCY4boCzgvU2Aoc1mOGzTtrjjLKhM5ivsnhoKpQVxKPp+1j1qwg==} engines: {node: '>=6.0'} @@ -5859,17 +6469,20 @@ packages: md5.js@1.3.5: resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + md5@2.3.0: + resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + mdast-util-definitions@4.0.0: resolution: {integrity: sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==} - mdast-util-from-markdown@2.0.0: - resolution: {integrity: sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==} + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} mdast-util-phrasing@4.1.0: resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} - mdast-util-to-markdown@2.1.0: - resolution: {integrity: sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==} + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} mdast-util-to-string@1.1.0: resolution: {integrity: sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==} @@ -5887,6 +6500,13 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + memfs@4.17.0: + resolution: {integrity: sha512-4eirfZ7thblFmqFjywlTmuWVSvccHAJbn1r8qQLzmTO11qcqpohOjmY2mFce6x7x7WtskzRqApPD0hv+Oa74jg==} + engines: {node: '>= 4.0.0'} + + memoize-one@6.0.0: + resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} + memoizerific@1.11.3: resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} @@ -5898,8 +6518,8 @@ packages: resolution: {integrity: sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - merge-descriptors@1.0.1: - resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -5918,71 +6538,75 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - micromark-core-commonmark@2.0.0: - resolution: {integrity: sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==} + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} - micromark-factory-destination@2.0.0: - resolution: {integrity: sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==} + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} - micromark-factory-label@2.0.0: - resolution: {integrity: sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==} + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} - micromark-factory-space@2.0.0: - resolution: {integrity: sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==} + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} - micromark-factory-title@2.0.0: - resolution: {integrity: sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==} + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} - micromark-factory-whitespace@2.0.0: - resolution: {integrity: sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==} + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} - micromark-util-character@2.1.0: - resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==} + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} - micromark-util-chunked@2.0.0: - resolution: {integrity: sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==} + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} - micromark-util-classify-character@2.0.0: - resolution: {integrity: sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==} + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} - micromark-util-combine-extensions@2.0.0: - resolution: {integrity: sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==} + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} - micromark-util-decode-numeric-character-reference@2.0.1: - resolution: {integrity: sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==} + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} - micromark-util-decode-string@2.0.0: - resolution: {integrity: sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==} + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} - micromark-util-encode@2.0.0: - resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==} + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} - micromark-util-html-tag-name@2.0.0: - resolution: {integrity: sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==} + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} - micromark-util-normalize-identifier@2.0.0: - resolution: {integrity: sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==} + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} - micromark-util-resolve-all@2.0.0: - resolution: {integrity: sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==} + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} - micromark-util-sanitize-uri@2.0.0: - resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==} + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} - micromark-util-subtokenize@2.0.0: - resolution: {integrity: sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==} + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} - micromark-util-symbol@2.0.0: - resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==} + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} - micromark-util-types@2.0.0: - resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==} + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} - micromark@4.0.0: - resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==} + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + micromatch@3.1.10: + resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} + engines: {node: '>=0.10.0'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} miller-rabin@4.0.1: @@ -5993,10 +6617,18 @@ packages: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -6026,55 +6658,40 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - minecraft-assets@1.12.2: - resolution: {integrity: sha512-/eMxh3LNjCXOnU6KnQMjBM8dRnoJNpWIg7mD2m2RthraYiQK2FNzPWIKxWm2j3Ufcf5nzFXupgABledE86r4fQ==} - - minecraft-data@3.65.0: - resolution: {integrity: sha512-9K8dOrdrcpUklTdqKBtRcKur0gLZnguTvhM/1Xv52qzh8Unkto4290RJc4ueRIYo1VqN4zzQrRxO8lnqtkERDQ==} + minecraft-data@3.98.0: + resolution: {integrity: sha512-JAPqJ/TZoxMUlAPPdWUh1v5wdqvYGFSZ4rW9bUtmaKBkGpomDSjw4V02ocBqbxKJvcTtmc5nM/LfN9/0DDqHrQ==} minecraft-folder-path@1.2.0: resolution: {integrity: sha512-qaUSbKWoOsH9brn0JQuBhxNAzTDMwrOXorwuRxdJKKKDYvZhtml+6GVCUrY5HRiEsieBEjCUnhVpDuQiKsiFaw==} - 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} + minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/89c33d396f3fde4804c71f4be3c203ade1833b41: + resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/89c33d396f3fde4804c71f4be3c203ade1833b41} 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/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9: + resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9} + version: 1.62.0 + engines: {node: '>=22'} - 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 - engines: {node: '>=14'} - - minecraft-wrap@1.5.1: - resolution: {integrity: sha512-7DZ2WhrcRD3fUMau84l9Va0KWzV92SHNdB7mnNdNhgXID2aW6pjWuYPZi8MepEBemA4XKKdnDx7HmhTbkoiR8A==} + minecraft-wrap@1.6.0: + resolution: {integrity: sha512-A1GjIR72x9H9cEaxAQsXZe5uhw7CPgq1pGwYkdbPe6mQraePinmj/jRIuntXYWEKrYamwQFT3igIafA+PEG11w==} hasBin: true - minecrafthawkeye@1.3.6: - resolution: {integrity: sha512-SlRlorxQs6nNzMiiIQ5z47wzbAI27UaCdbRB82CE8jqj4C8m3Gqk5TlgN+PSThxx8EDPXySzd8Vk+/wNigAd5A==} + minecrafthawkeye@1.3.9: + resolution: {integrity: sha512-YIDHTvljQjsJH4cEcbF02/ehNRUrbzEiL/quQmdEU8ruv69R4bwHqmBB8O9FyhpQgNppmNTs3pK8h4J0/MYGpQ==} - mineflayer-item-map-downloader@https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7: - resolution: {tarball: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7} + mineflayer-item-map-downloader@https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824: + resolution: {tarball: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824} version: 1.2.0 - mineflayer-pathfinder@2.4.4: - resolution: {integrity: sha512-HAXakZrJRb1UC+5dv8EaDrqjW3ZnBnBk3nkb6x/YWyhHCUKn/E7VU0FO+UN9whuqPlkSaVumEdXJdydE6lSYxQ==} + mineflayer-mouse@0.1.21: + resolution: {integrity: sha512-1XTVuw3twIrEcqQ1QRSB8NcStIUEZ+tbxiAG6rOrN/9M4thhtlS5PTJzFdmdrcYgWEBLvuOdJszaKE5zFfiXhg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - mineflayer@4.20.1: - 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} - version: 4.20.1 - engines: {node: '>=18'} + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659: + resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659} + version: 8.0.0 + engines: {node: '>=22'} minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} @@ -6093,6 +6710,10 @@ packages: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + minimist-options@4.1.0: resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} engines: {node: '>= 6'} @@ -6128,14 +6749,18 @@ packages: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} - minipass@7.0.3: - resolution: {integrity: sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==} + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} + mixin-deep@1.3.2: + resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} + engines: {node: '>=0.10.0'} + mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} @@ -6157,52 +6782,57 @@ packages: engines: {node: '>=10'} hasBin: true - mlly@1.4.2: - resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} + mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} mojangson@2.0.4: resolution: {integrity: sha512-HYmhgDjr1gzF7trGgvcC/huIg2L8FsVbi/KacRe6r1AswbboGVZDS47SOZlomPuMWvZLas8m9vuHHucdZMwTmQ==} + monaco-editor@0.52.2: + resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==} + moo@0.5.2: resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==} - mri@1.2.0: - resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} - engines: {node: '>=4'} + morgan@1.10.0: + resolution: {integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==} + engines: {node: '>= 0.8.0'} + + motion-dom@12.9.1: + resolution: {integrity: sha512-xqXEwRLDYDTzOgXobSoWtytRtGlf7zdkRfFbrrdP7eojaGQZ5Go4OOKtgnx7uF8sAkfr1ZjMvbCJSCIT2h6fkQ==} + + motion-utils@12.8.3: + resolution: {integrity: sha512-GYVauZEbca8/zOhEiYOY9/uJeedYQld6co/GJFKOy//0c/4lDqk0zB549sBYqqV2iMuX+uHrY1E5zd8A2L+1Lw==} ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nan@2.18.0: - resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==} + nan@2.22.2: + resolution: {integrity: sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==} - nano-css@5.3.5: - resolution: {integrity: sha512-vSB9X12bbNu4ALBu7nigJgRViZ6ja3OU7CeuiV1zMIbXOdmkLahgtPmh3GBOlDxbKY0CitqlPdOReGlBLSp+yg==} + nano-css@5.6.2: + resolution: {integrity: sha512-+6bHaC8dSDGALM1HJjOHVXpuastdu2xFoZlC77Jh4cg+33Zcgm+Gxd+1xsnpZK14eyHObSp82+ll5y3SX75liw==} peerDependencies: react: ^18.2.0 react-dom: '*' - nanoid@3.3.6: - resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + nanoid@3.3.9: + resolution: {integrity: sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true + nanomatch@1.2.13: + resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} + engines: {node: '>=0.10.0'} - napi-build-utils@1.0.2: - resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} @@ -6218,14 +6848,15 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} + negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - nested-error-stacks@2.1.1: - resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} - - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/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/e754999ffdea67853bc9b10553b5e9908b40f618: + resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e754999ffdea67853bc9b10553b5e9908b40f618} version: 0.2.4 nice-try@1.0.5: @@ -6234,8 +6865,8 @@ packages: no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - node-abi@3.47.0: - resolution: {integrity: sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A==} + node-abi@3.74.0: + resolution: {integrity: sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==} engines: {node: '>=10'} node-addon-api@5.1.0: @@ -6248,8 +6879,8 @@ packages: resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} engines: {node: '>= 0.10.5'} - node-fetch-native@1.4.0: - resolution: {integrity: sha512-F5kfEj95kX8tkDhUCYdV8dg3/8Olx/94zB8+ZNthFs6Bz31UpUi8Xh40TN3thLwXgrwXry1pEg9lJ++tLWTcqA==} + node-fetch-native@1.6.6: + resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==} node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} @@ -6260,10 +6891,6 @@ packages: encoding: optional: true - node-gyp-build-optional-packages@5.1.1: - resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==} - hasBin: true - node-gyp@9.4.1: resolution: {integrity: sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==} engines: {node: ^12.13 || ^14.13 || >=16} @@ -6272,14 +6899,14 @@ packages: node-gzip@1.1.2: resolution: {integrity: sha512-ZB6zWpfZHGtxZnPMrJSKHVPrRjURoUzaDbLFj3VO70mpLTW5np96vXyHwft4Id0o+PYIzgDkBUjIzaNHhQ8srw==} - node-html-parser@6.1.10: - resolution: {integrity: sha512-6/uWdWxjQWQ7tMcFK2wWlrflsQUzh1HsEzlIf2j5+TtzfhT2yUvg3DwZYAmjEHeR3uX74ko7exjHW69J0tOzIg==} + node-html-parser@6.1.13: + resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.13: - resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} node-rsa@0.4.2: resolution: {integrity: sha512-Bvso6Zi9LY4otIZefYrscsUpo2mUpiAVIEmSZV2q41sP8tHZoert3Yu6zv4f/RXJqMNZQKCtnhDugIuCma23YA==} @@ -6308,6 +6935,10 @@ packages: resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} engines: {node: '>=10'} + normalize-path@2.1.1: + resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} + engines: {node: '>=0.10.0'} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -6323,63 +6954,72 @@ packages: npmlog@5.0.1: resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + deprecated: This package is no longer supported. npmlog@6.0.2: resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nypm@0.5.4: + resolution: {integrity: sha512-X0SNNrZiGU8/e/zAB7sCTtdxWTMSIO73q+xuKgglm2Yvzwlo8UoC5FNySQFCvl84uPaeADkqHUZUkWy4aH4xOA==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - object-inspect@1.12.3: - resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + object-copy@0.1.0: + resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} + engines: {node: '>=0.10.0'} - object-inspect@1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} - object-is@1.1.5: - resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} engines: {node: '>= 0.4'} object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - object.assign@4.1.4: - resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + object-visit@1.0.1: + resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} + engines: {node: '>=0.10.0'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} - object.assign@4.1.5: - resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} - engines: {node: '>= 0.4'} - - object.entries@1.1.8: - resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} engines: {node: '>= 0.4'} object.fromentries@2.0.8: resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} - object.hasown@1.1.4: - resolution: {integrity: sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==} - engines: {node: '>= 0.4'} + object.pick@1.3.0: + resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} + engines: {node: '>=0.10.0'} - object.values@1.1.7: - resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} - engines: {node: '>= 0.4'} - - object.values@1.2.0: - resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} omggif@1.0.10: resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==} + on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -6403,8 +7043,13 @@ packages: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true - optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + opn@6.0.0: + resolution: {integrity: sha512-I9PKfIZC+e4RXZ/qr1RhgyCnGgYX0UEIlXgWnCOVACIvFgaC9rz6Won7xbdhoHrd8IIhV7YEpHjreNUNkqCGkQ==} + engines: {node: '>=8'} + deprecated: The package has been renamed to `open` + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} ora@5.4.1: @@ -6420,6 +7065,10 @@ packages: ospath@1.2.2: resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -6452,12 +7101,18 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + pako@0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} @@ -6465,8 +7120,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parse-asn1@5.1.6: - resolution: {integrity: sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==} + parse-asn1@5.1.7: + resolution: {integrity: sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==} + engines: {node: '>= 0.10'} parse-bmfont-ascii@1.0.6: resolution: {integrity: sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==} @@ -6474,11 +7130,8 @@ packages: parse-bmfont-binary@1.0.6: resolution: {integrity: sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==} - parse-bmfont-xml@1.1.4: - resolution: {integrity: sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==} - - parse-color@1.0.0: - resolution: {integrity: sha512-fuDHYgFHJGbpGMgw9skY/bj3HL/Jrn4l/5rSspy00DoT4RyLnDcRvPxdZ+r6OFwIsgAuhDh4I09tAId4mI12bw==} + parse-bmfont-xml@1.1.6: + resolution: {integrity: sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==} parse-headers@2.0.5: resolution: {integrity: sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==} @@ -6504,12 +7157,19 @@ packages: pascal-case@3.1.2: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + pascalcase@0.1.1: + resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} + engines: {node: '>=0.10.0'} + path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} path-case@3.0.4: resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==} + path-dirname@1.0.2: + resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} + path-exists-cli@2.0.0: resolution: {integrity: sha512-qGr0A87KYCznmvabblxyxnzA/MtPZ28wH+4SCMP4tjTFAbzqwvs5xpUZExAYzq5OgHe5vIswzdH5iosCb8YF/Q==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6542,12 +7202,12 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-scurry@1.10.1: - resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} - engines: {node: '>=16 || 14 >=14.17'} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} - path-to-regexp@0.1.7: - resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} path-type@3.0.0: resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} @@ -6557,12 +7217,18 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - pathe@1.1.1: - resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + pbkdf2@3.1.2: resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} engines: {node: '>=0.12'} @@ -6570,12 +7236,12 @@ packages: peek-stream@1.1.3: resolution: {integrity: sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==} - peerjs-js-binarypack@2.0.0: - resolution: {integrity: sha512-wu+L0Qeg4IH2DXm3B6xKP5ODeCIovwEEO/Fu3MVqApPQeVLzSdZpFzQzPobh+sdhUWMQGEO7YxHeiwpPngLjqQ==} + peerjs-js-binarypack@2.1.0: + resolution: {integrity: sha512-YIwCC+pTzp3Bi8jPI9UFKO0t0SLo6xALnHkiNt/iUFmUUZG0fEEmEyFKvjsDKweiFitzHRyhuh6NvyJZ4nNxMg==} engines: {node: '>= 14.0.0'} - peerjs@1.5.0: - resolution: {integrity: sha512-NLZ73jRNE4aLq2pmVTiSkWmwf6cvt9cH72qJHnzaLH+I2CtoWVvY42U9/O0/tYE6UYwRYJ1ktKRs2DdZ1Jrgcg==} + peerjs@1.5.4: + resolution: {integrity: sha512-yFsoLMnurJKlQbx6kVSBpOp+AlNldY1JQS2BrSsHLKCZnq6t7saHleuHM5svuLNbQkUJXHLF3sKOJB1K0xulOw==} engines: {node: '>= 14'} pend@1.2.0: @@ -6586,14 +7252,23 @@ packages: phin@2.9.3: resolution: {integrity: sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + phin@3.7.1: + resolution: {integrity: sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==} + engines: {node: '>= 8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + pidtree@0.3.1: resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==} engines: {node: '>=0.10'} @@ -6615,6 +7290,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 @@ -6631,8 +7309,8 @@ packages: resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} engines: {node: '>=10'} - pkg-types@1.0.3: - resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} @@ -6642,34 +7320,34 @@ packages: resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} engines: {node: '>=4.0.0'} - polished@4.2.2: - resolution: {integrity: sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==} + polished@4.3.1: + resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==} engines: {node: '>=10'} poly-decomp@0.3.0: resolution: {integrity: sha512-hWeBxGzPYiybmI4548Fca7Up/0k1qS5+79cVHI9+H33dKya5YNb9hxl0ZnDaDgvrZSuYFBhkCK/HOnqN7gefkQ==} - portfinder@1.0.32: - resolution: {integrity: sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==} + portfinder@1.0.33: + resolution: {integrity: sha512-+2jndHT63cL5MdQOwDm9OT2dIe11zVpjV+0GGRXdtO1wpPxv260NfVqoEXtYAi/shanmm3W4+yLduIe55ektTw==} engines: {node: '>= 0.12.0'} - possible-typed-array-names@1.0.0: - resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + posix-character-classes@0.1.1: + resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} + engines: {node: '>=0.10.0'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} - - postcss@8.4.38: - resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + postcss@8.5.3: + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} potpack@1.0.2: resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==} - prebuild-install@7.1.1: - resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} engines: {node: '>=10'} hasBin: true @@ -6703,53 +7381,43 @@ packages: resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} engines: {node: '>= 0.8'} - prismarine-auth@2.4.2: - resolution: {integrity: sha512-Cq4woGobnFYYfMBDh1WITW+Vs98toN91qAFBvBitwV7IwJaiSAh2Nl+WPUEGeg5eLBoSPpSyCVT8P2oi7Cav8g==} + prismarine-auth@2.7.0: + resolution: {integrity: sha512-L8wTF6sdtnN6hViPNy+Nx39a8iQBwR5iO92AWCiym5cSXp/92pmnuwnTdcmNDWyqq6zY4hbibVGYhgLA1Ox8sQ==} prismarine-biome@1.3.0: resolution: {integrity: sha512-GY6nZxq93mTErT7jD7jt8YS1aPrOakbJHh39seYsJFXvueIOdHAmW16kYQVrTVMW5MlWLQVxV/EquRwOgr4MnQ==} peerDependencies: - minecraft-data: 3.65.0 + minecraft-data: 3.98.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} - version: 1.17.1 + prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9} + version: 1.21.0 - prismarine-chat@1.10.1: - resolution: {integrity: sha512-XukYcuueuhDxzEXG7r8BZyt6jOObrPPB4JESCgb+/XenB9nExoSHF8eTQWWj8faKPLqm1dRQaYwFJlNBlJZJUw==} + prismarine-chat@1.11.0: + resolution: {integrity: sha512-VJT/MWYB3qoiznUhrgvSQh76YFpzpCZpY85kJKxHLbd3UVoM0wsfs43Eg8dOltiZG92wc5/DTMLlT07TEeoa9w==} - 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 + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f} + version: 1.38.1 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 - engines: {node: '>=14'} + prismarine-entity@2.5.0: + resolution: {integrity: sha512-nRPCawUwf9r3iKqi4I7mZRlir1Ix+DffWYdWq6p/KNnmiXve+xHE5zv8XCdhZlUmOshugHv5ONl9o6ORAkCNIA==} - prismarine-entity@2.3.1: - resolution: {integrity: sha512-HOv8l7IetHNf4hwZ7V/W4vM3GNl+e6VCtKDkH9h02TRq7jWngsggKtJV+VanCce/sNwtJUhJDjORGs728ep4MA==} + prismarine-item@1.17.0: + resolution: {integrity: sha512-wN1OjP+f+Uvtjo3KzeCkVSy96CqZ8yG7cvuvlGwcYupQ6ct7LtNkubHp0AHuLMJ0vbbfAC0oZ2bWOgI1DYp8WA==} - prismarine-item@1.14.0: - resolution: {integrity: sha512-udQHYGJ05klFe8Kkc0TOmwoXj5Xl1ZPgHVoMbGUAFB9exN4TFxEa1A39vkSYhxP5Et9PNufQQvFBFVom0nXikA==} + prismarine-nbt@2.7.0: + resolution: {integrity: sha512-Du9OLQAcCj3y29YtewOJbbV4ARaSUEJiTguw0PPQbPBy83f+eCyDRkyBpnXTi/KPyEpgYCzsjGzElevLpFoYGQ==} - prismarine-nbt@2.2.1: - resolution: {integrity: sha512-Mb50c58CPnuZ+qvM31DBa08tf9UumlTq1LkvpMoUpKfCuN05GZHTqCUwER3lxTSHLL0GZKghIPbYR/JQkINijQ==} + prismarine-physics@https://codeload.github.com/zardoy/prismarine-physics/tar.gz/353e25b800149393f40539ec381218be44cbb03b: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-physics/tar.gz/353e25b800149393f40539ec381218be44cbb03b} + version: 1.9.0 - prismarine-nbt@2.5.0: - resolution: {integrity: sha512-F0/8UAa9SDDnAGrBYqZc4nG8h2zj5cE2eAJU5xlDR/IsQQ3moVxkOjE3h3nMv6SbvZrvAcgX7waA/nd9LLHYdA==} - - 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/1d548fac63fe977c8281f0a9a522b37e4d92d0b7: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7} + version: 2.8.0 prismarine-realms@1.3.2: resolution: {integrity: sha512-5apl9Ru8veTj5q2OozRc4GZOuSIcs3yY4UEtALiLKHstBe8bRw8vNlaz4Zla3jsQ8yP/ul1b1IJINTRbocuA6g==} @@ -6759,8 +7427,8 @@ packages: peerDependencies: prismarine-registry: ^1.4.0 - prismarine-registry@1.7.0: - resolution: {integrity: sha512-yyva0FpWI078nNeMhx8ekVza5uUTYhEv+C+ADu3wUQXiG8qhXkvrf0uzsnhTgZL8BLdsi2axgCEiKw9qSKIuxQ==} + prismarine-registry@1.11.0: + resolution: {integrity: sha512-uTvWE+bILxYv4i5MrrlxPQ0KYWINv1DJ3P2570GLC8uCdByDiDLBFfVyk4BrqOZBlDBft9CnaJMeOsC1Ly1iXw==} prismarine-schematic@1.2.3: resolution: {integrity: sha512-Mwpn43vEHhm3aw3cPhJjWqztkW+nX+QLajDHlTask8lEOTGl1WmpvFja4iwiws4GIvaC8x0Foptf4uvDsnjrAg==} @@ -6768,9 +7436,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/ab2146c9933eef3247c3f64446de4ccc2c484c7c: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c} + version: 3.6.3 engines: {node: '>=8.0.0'} process-nextick-args@2.0.1: @@ -6812,20 +7480,20 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - prosemirror-commands@1.5.2: - resolution: {integrity: sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==} + prosemirror-commands@1.7.0: + resolution: {integrity: sha512-6toodS4R/Aah5pdsrIwnTYPEjW70SlO5a66oo5Kk+CIrgJz3ukOoS+FYDGqvQlAX5PxoGWDX1oD++tn5X3pyRA==} prosemirror-dropcursor@1.8.1: resolution: {integrity: sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==} - prosemirror-example-setup@1.2.2: - resolution: {integrity: sha512-pHJc656IgYm249RNp0eQaWNmnyWGk6OrzysWfYI4+NwE14HQ7YNYOlRBLErUS6uCAHIYJLNXf0/XCmf1OCtNbQ==} + prosemirror-example-setup@1.2.3: + resolution: {integrity: sha512-+hXZi8+xbFvYM465zZH3rdZ9w7EguVKmUYwYLZjIJIjPK+I0nPTwn8j0ByW2avchVczRwZmOJGNvehblyIerSQ==} prosemirror-gapcursor@1.3.2: resolution: {integrity: sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==} - prosemirror-history@1.3.2: - resolution: {integrity: sha512-/zm0XoU/N/+u7i5zepjmZAEnpvjDtzoPWW6VmKptcAnPadN/SStsBjMImdCEbb3seiNTpveziPTIrXQbHLtU1g==} + prosemirror-history@1.4.1: + resolution: {integrity: sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==} prosemirror-inputrules@1.4.0: resolution: {integrity: sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==} @@ -6833,33 +7501,33 @@ packages: prosemirror-keymap@1.2.2: resolution: {integrity: sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==} - prosemirror-markdown@1.12.0: - resolution: {integrity: sha512-6F5HS8Z0HDYiS2VQDZzfZP6A0s/I0gbkJy8NCzzDMtcsz3qrfqyroMMeoSjAmOhDITyon11NbXSzztfKi+frSQ==} + prosemirror-markdown@1.13.1: + resolution: {integrity: sha512-Sl+oMfMtAjWtlcZoj/5L/Q39MpEnVZ840Xo330WJWUvgyhNmLBLN7MsHn07s53nG/KImevWHSE6fEj4q/GihHw==} prosemirror-menu@1.2.4: resolution: {integrity: sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==} - prosemirror-model@1.19.4: - resolution: {integrity: sha512-RPmVXxUfOhyFdayHawjuZCxiROsm9L4FCUA6pWI+l7n2yCBsWy9VpdE1hpDHUS8Vad661YLY9AzqfjLhAKQ4iQ==} + prosemirror-model@1.24.1: + resolution: {integrity: sha512-YM053N+vTThzlWJ/AtPtF1j0ebO36nvbmDy4U7qA2XQB8JVaQp1FmB9Jhrps8s+z+uxhhVTny4m20ptUvhk0Mg==} - prosemirror-schema-list@1.3.0: - resolution: {integrity: sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A==} + prosemirror-schema-list@1.5.1: + resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} prosemirror-state@1.4.3: resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==} - prosemirror-transform@1.8.0: - resolution: {integrity: sha512-BaSBsIMv52F1BVVMvOmp1yzD3u65uC3HTzCBQV1WDPqJRQ2LuHKcyfn0jwqodo8sR9vVzMzZyI+Dal5W9E6a9A==} + prosemirror-transform@1.10.3: + resolution: {integrity: sha512-Nhh/+1kZGRINbEHmVu39oynhcap4hWTs/BlU7NnxWj3+l0qi8I1mu67v6mMdEe/ltD8hHvU4FV6PHiCw2VSpMw==} - prosemirror-view@1.33.1: - resolution: {integrity: sha512-62qkYgSJIkwIMMCpuGuPzc52DiK1Iod6TWoIMxP4ja6BTD4yO8kCUL64PZ/WhH/dJ9fW0CDO39FhH1EMyhUFEg==} + prosemirror-view@1.38.1: + resolution: {integrity: sha512-4FH/uM1A4PNyrxXbD+RAbAsf0d/mM0D/wAKSVVWK7o0A9Q/oOXJBrw786mBf2Vnrs/Edly6dH6Z2gsb7zWwaUw==} - protodef-validator@1.3.1: - resolution: {integrity: sha512-lZ5FWKZYR9xOjpMw1+EfZRfCjzNRQWPq+Dk+jki47Sikl2EeWEPnTfnJERwnU/EwFq6us+0zqHHzSsmLeYX+Lg==} + protodef-validator@1.4.0: + resolution: {integrity: sha512-2y2coBolqCEuk5Kc3QwO7ThR+/7TZiOit4FrpAgl+vFMvq8w76nDhh09z08e2NQOdrgPLsN2yzXsvRvtADgUZQ==} hasBin: true - protodef@1.15.0: - resolution: {integrity: sha512-bZ2Omw8dT+DACjJHLrBWZlqN4MlT9g9oSpJDdkUAJOStUzgJp+Zn42FJfPUdwutUxjaxA0PftN0PDlNa2XbneA==} + protodef@1.18.0: + resolution: {integrity: sha512-jO64lkzkh0dYc0AVWCU/GzCKwqhFFIz1kfEz0NBf0RUuRNcmvgKbopabJdfZ6W8NvALdySUXgEhvKDZPhdBwrg==} engines: {node: '>=14'} proxy-addr@2.0.7: @@ -6869,11 +7537,21 @@ packages: proxy-compare@2.5.1: resolution: {integrity: sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA==} + proxy-compare@2.6.0: + resolution: {integrity: sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==} + proxy-from-env@1.0.0: resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} - psl@1.9.0: - resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + proxy-middleware@0.15.0: + resolution: {integrity: sha512-EGCG8SeoIRVMhsqHQUdDigB2i7qU7fCsWASwn54+nPutYO8n4q6EiwMzyfWlC+dzRFExP+kvcnDFdBDHoZBU7Q==} + engines: {node: '>=0.8.0'} + + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} public-encrypt@4.0.3: resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} @@ -6881,8 +7559,8 @@ packages: pump@2.0.1: resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} - pump@3.0.0: - resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} pumpify@1.5.1: resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} @@ -6891,9 +7569,8 @@ packages: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} - punycode@2.3.0: - resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} - engines: {node: '>=6'} + punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} @@ -6903,8 +7580,8 @@ packages: resolution: {integrity: sha512-n13AWriBMPYxnpbb6bnaY5YoY6rGj8vPLrz6CZF3o0qJNEwlcfJVxBzYZ0NJsQ21UbdJoijPCDrM++SUVEz7+w==} engines: {node: '>=8.16.0'} - qrcode.react@3.1.0: - resolution: {integrity: sha512-oyF+Urr3oAMUG/OiOuONL3HXM+53wvuH3mtIWQrYmsXoAq0DkvZp2RYUWFSMFtbdOpuS++9v+WAkzNVkMlNW6Q==} + qrcode.react@3.2.0: + resolution: {integrity: sha512-YietHHltOHA4+l5na1srdaMx4sVSOjV9tamHs+mwiLWAMr6QVACRUw1Neax5CptFILcNoITctJY0Ipyn5enQ8g==} peerDependencies: react: ^18.2.0 @@ -6912,14 +7589,18 @@ packages: resolution: {integrity: sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==} engines: {node: '>=0.6'} - qs@6.11.0: - resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} - qs@6.11.2: - resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} + querystring-es3@0.2.1: + resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} + engines: {node: '>=0.4.x'} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -6939,8 +7620,8 @@ packages: rambda@6.9.0: resolution: {integrity: sha512-yosVdGg1hNGkXPzqGiOYNEpXKjEOxzUCg2rB0l+NKdyCaSf4z+i5ojbN0IqDSezMMf71YEglI+ZUTgTffn5afw==} - rambda@9.2.0: - resolution: {integrity: sha512-RjM8TBNPR+iSvWLqbBpFveDfEf2RPRKHuwBHjQdXsYFDwn3MIvgmJiqVVC1CIQKnOwzeDQd44zqDFgSKQ7RT1Q==} + rambda@9.4.2: + resolution: {integrity: sha512-++euMfxnl7OgaEKwXh9QqThOjMeta2HH001N1v4mYQzBjJBnmXBh2BCK6dZAbICFVXOFUVD3xFG0R3ZPU0mxXw==} ramda@0.29.0: resolution: {integrity: sha512-BBea6L67bYLtdbOqfp8f58fPMqEwx0doL+pAi8TZyp2YWz8R9G8z9x75CZI8W+ftqhFHCpEX2cRnUUXK130iKA==} @@ -6966,10 +7647,7 @@ packages: range@0.0.3: resolution: {integrity: sha512-OxK2nY2bmeEB4NxoBraQIBOOeOIxoBvm6yt8MA1kLappgkG3SyLf173iOtT5woWycrtESDD2g0Nl2yt8YPoUnw==} engines: {node: '>=0.8'} - - raw-body@2.5.1: - resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} - engines: {node: '>= 0.8'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. raw-body@2.5.2: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} @@ -6993,13 +7671,12 @@ packages: peerDependencies: typescript: '>= 4.3.x' - react-docgen@6.0.0-alpha.3: - resolution: {integrity: sha512-DDLvB5EV9As1/zoUsct6Iz2Cupw9FObEGD3DMcIs3EDFIoSKyz8FZtoWj3Wj+oodrU4/NfidN0BL5yrapIcTSA==} - engines: {node: '>=12.0.0'} - hasBin: true + react-docgen@7.1.1: + resolution: {integrity: sha512-hlSJDQ2synMPKFZOsKo9Hi8WWZTC7POR8EmWvTSjow+VDgKzkmjQvFm2fk0tmRw+f0vTOIYKlarR0iL4996pdg==} + engines: {node: '>=16.14.0'} - react-dom@18.2.0: - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: react: ^18.2.0 @@ -7012,8 +7689,9 @@ packages: react-fast-compare@3.2.2: resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} - react-inspector@6.0.2: - resolution: {integrity: sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==} + react-hook-form@7.54.2: + resolution: {integrity: sha512-eHpAUgUjWbZocoQYUHposymRb4ZP6d0uwUnooL2uOybA9/3tPUvoAKqEWK1WaSiTxxOfTpffNZP7QwlnM3/gEg==} + engines: {node: '>=18.0.0'} peerDependencies: react: ^18.2.0 @@ -7023,8 +7701,8 @@ packages: react-is@18.1.0: resolution: {integrity: sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==} - react-is@18.2.0: - resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} react-popper@2.3.0: resolution: {integrity: sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==} @@ -7039,15 +7717,19 @@ packages: react: ^18.2.0 react-dom: ^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0 - react-refresh@0.14.0: - resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} - react-remove-scroll-bar@2.3.4: - resolution: {integrity: sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==} + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' react: ^18.2.0 peerDependenciesMeta: '@types/react': @@ -7063,11 +7745,17 @@ packages: '@types/react': optional: true - react-style-singleton@2.2.1: - resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} + react-select@5.10.1: + resolution: {integrity: sha512-roPEZUL4aRZDx6DcsD+ZNreVl+fM8VsKn0Wtex1v4IazH60ILp5xhdlp464IsEAlJdXeD+BhDAFsBVMfvLQueA==} + peerDependencies: + react: ^18.2.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' react: ^18.2.0 peerDependenciesMeta: '@types/react': @@ -7097,8 +7785,15 @@ packages: react: ^18.2.0 react-dom: ^16.8.0 || ^17.0.0 - react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + react-zoom-pan-pinch@3.4.4: + resolution: {integrity: sha512-lGTu7D9lQpYEQ6sH+NSlLA7gicgKRW8j+D/4HO1AbSV2POvKRFzdWQ8eI0r3xmOsl4dYQcY+teV6MhULeg1xBw==} + engines: {node: '>=8', npm: '>=5'} + peerDependencies: + react: ^18.2.0 + react-dom: '*' + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} read-pkg-up@7.0.1: @@ -7131,10 +7826,14 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readable-stream@4.5.2: - resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + readdirp@2.2.1: + resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} + engines: {node: '>=0.10'} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -7142,24 +7841,23 @@ packages: readline@1.3.0: resolution: {integrity: sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==} - recast@0.21.5: - resolution: {integrity: sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==} - engines: {node: '>= 4'} - - recast@0.23.4: - resolution: {integrity: sha512-qtEDqIZGVcSZCHniWwZWbRy79Dc6Wp3kT/UmDA2RJKBPg7+7k51aQBZirHmUGn5uvHf2rg8DkjizrN26k61ATw==} + recast@0.23.11: + resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} engines: {node: '>= 4'} redent@4.0.0: resolution: {integrity: sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==} engines: {node: '>=12'} - reflect.getprototypeof@1.0.6: - resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} + reduce-configs@1.1.0: + resolution: {integrity: sha512-DQxy6liNadHfrLahZR7lMdc227NYVaQZhY5FMsxLEjX8X0SCuH+ESHSLCoz2yDZFq1/CLMDOAHdsEHwOEXKtvg==} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} - regenerate-unicode-properties@10.1.0: - resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} + regenerate-unicode-properties@10.2.0: + resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} engines: {node: '>=4'} regenerate@1.4.2: @@ -7168,38 +7866,41 @@ packages: regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - regenerator-runtime@0.14.0: - resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} regenerator-transform@0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} + regex-not@1.0.2: + resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} + engines: {node: '>=0.10.0'} + regexp-tree@0.1.27: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true - regexp.prototype.flags@1.5.1: - resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} - engines: {node: '>= 0.4'} - - regexp.prototype.flags@1.5.2: - resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} regexpp@3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} - regexpu-core@5.3.2: - resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} + regexpu-core@6.2.0: + resolution: {integrity: sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==} engines: {node: '>=4'} + regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + regjsparser@0.10.0: resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==} hasBin: true - regjsparser@0.9.1: - resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} + regjsparser@0.12.0: + resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==} hasBin: true remark-external-links@8.0.0: @@ -7217,6 +7918,17 @@ packages: remark@15.0.1: resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==} + remove-trailing-separator@1.1.0: + resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} + + repeat-element@1.1.4: + resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} + engines: {node: '>=0.10.0'} + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + request-progress@3.0.0: resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} @@ -7245,8 +7957,13 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.4: - resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} + resolve-url@0.2.1: + resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} + deprecated: https://github.com/lydell/resolve-url#deprecated + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} hasBin: true resolve@2.0.0-next.5: @@ -7265,49 +7982,50 @@ packages: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rfdc@1.3.0: - resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@2.7.1: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rimraf@5.0.1: - resolution: {integrity: sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg==} - engines: {node: '>=14'} + rimraf@5.0.10: + resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} hasBin: true ripemd160@2.0.2: resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} - rollup-plugin-terser@7.0.2: - resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} - deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser - peerDependencies: - rollup: ^2.0.0 - - rollup@2.79.1: - resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} + rollup@2.79.2: + resolution: {integrity: sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==} engines: {node: '>=10.0.0'} hasBin: true - rollup@3.29.4: - resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} + rollup@3.29.5: + resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true + rollup@4.34.9: + resolution: {integrity: sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + rope-sequence@1.3.4: resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} @@ -7317,15 +8035,11 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rxjs@7.8.1: - resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - safe-array-concat@1.0.1: - resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} - engines: {node: '>=0.4'} - - safe-array-concat@1.1.2: - resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} safe-buffer@5.1.2: @@ -7334,13 +8048,17 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-regex-test@1.0.0: - resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} - - safe-regex-test@1.0.3: - resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safe-regex@1.1.0: + resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -7350,11 +8068,11 @@ packages: sat@0.9.0: resolution: {integrity: sha512-mxdv5RZJO4tdMnUURGU3gAMcnDUEwcNJwE+lPO0/V+rBeDvFLH3wEZEOR0fH7cTN0zQaNxBEbHnyQL9DzupwQQ==} - sax@1.3.0: - resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} + sax@1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} - scheduler@0.23.0: - resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} screenfull@5.2.0: resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==} @@ -7374,39 +8092,38 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} engines: {node: '>=10'} hasBin: true - semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} - engines: {node: '>=10'} - hasBin: true - - send@0.18.0: - resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} + send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + sentence-case@3.0.4: resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} - serialize-javascript@4.0.0: - resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - serve-static@1.15.0: - resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + serve-index@1.9.1: + resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} + engines: {node: '>= 0.8.0'} + + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - set-function-length@1.2.1: - resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==} - engines: {node: '>= 0.4'} - - set-function-name@2.0.1: - resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} set-function-name@2.0.2: @@ -7417,9 +8134,20 @@ packages: resolution: {integrity: sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==} engines: {node: '>=6.9'} + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + set-value@2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + setprototypeof@1.1.0: + resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} + setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -7435,6 +8163,10 @@ packages: resolution: {integrity: sha512-G+MY2YW33jgflKPTXXptVO28HvNOo9G3j0MybYAHeEmby+QuD2U98dT6ueht9cv/XDqZspSpIhoSW+BAKJ7Hig==} engines: {node: '>=12.13.0'} + sharp@0.33.5: + resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} @@ -7451,18 +8183,24 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shell-quote@1.8.1: - resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} - - side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} - - side-channel@1.0.5: - resolution: {integrity: sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==} + shell-quote@1.8.2: + resolution: {integrity: sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==} engines: {node: '>= 0.4'} - side-channel@1.0.6: - resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} siginfo@2.0.0: @@ -7487,18 +8225,14 @@ packages: simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - simple-update-notifier@2.0.0: - resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} - engines: {node: '>=10'} - sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} skinview-utils@0.7.1: resolution: {integrity: sha512-4eLrMqR526ehlZbsd8SuZ/CHpS9GiH0xUMoV+PYlJVi95ZFz5HJu7Spt5XYa72DRS7wgt5qquvHZf0XZJgmu9Q==} - skinview3d@3.0.1: - resolution: {integrity: sha512-2LUSkzGxlZrTQelGT10jcW4TLiFTg5aZqXMEuqAFoWtk3qtaNu0qRFtwK5dN8zEXyKUJ3xlxah5eGtKY/NifQg==} + skinview3d@3.1.0: + resolution: {integrity: sha512-L+HXXAP4qYjLcY3YHasXKie9KXQpv/mPTMxgLOEd+hVQRdQkPs5xdWaKuOmlZY8UnyZzecQM7yrWRzgT/e7HZw==} slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} @@ -7516,24 +8250,39 @@ packages: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + smob@1.5.0: + resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} + snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + snapdragon-node@2.1.1: + resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} + engines: {node: '>=0.10.0'} + + snapdragon-util@3.0.1: + resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} + engines: {node: '>=0.10.0'} + + snapdragon@0.8.2: + resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} + engines: {node: '>=0.10.0'} + socket.io-adapter@1.1.2: resolution: {integrity: sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==} - socket.io-adapter@2.5.2: - resolution: {integrity: sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==} + socket.io-adapter@2.5.5: + resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==} socket.io-client@2.5.0: resolution: {integrity: sha512-lOO9clmdgssDykiOmVQQitwBAF3I6mYcQAo7hQ7AM6Ny5X7fp8hIJ3HcQs3Rjz4SoggoxA1OgrQyY8EgTbcPYw==} - socket.io-client@4.7.2: - resolution: {integrity: sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==} + socket.io-client@4.8.1: + resolution: {integrity: sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==} engines: {node: '>=10.0.0'} - socket.io-parser@3.3.3: - resolution: {integrity: sha512-qOg87q1PMWWTeO01768Yh9ogn7chB9zkKtQnya41Y355S0UmpXgpcrFwAgjYJxu9BdKug5r5e9YtVSeWhKBUZg==} + socket.io-parser@3.3.4: + resolution: {integrity: sha512-z/pFQB3x+EZldRRzORYW1vwVO8m/3ILkswtnpoeU6Ve3cbMWkmHEWDAVJn4QJtchiiFTo5j7UG2QvwxvaA9vow==} socket.io-parser@3.4.3: resolution: {integrity: sha512-1rE4dZN3kCI/E5wixd393hmbqa78vVpkKmnEJhLeWoS/C5hbFYAbcSfnWoaVH43u9ToUVtzKjguxEZq+1XZfCQ==} @@ -7543,32 +8292,36 @@ packages: resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} engines: {node: '>=10.0.0'} - socket.io@2.5.0: - resolution: {integrity: sha512-gGunfS0od3VpwDBpGwVkzSZx6Aqo9uOcf1afJj2cKnKFAoyl16fvhpsUhmUFd4Ldbvl5JvRQed6eQw6oQp6n8w==} + socket.io@2.5.1: + resolution: {integrity: sha512-eaTE4tBKRD6RFoetquMbxgvcpvoDtRyIlkIMI/SMK2bsKvbENTsDeeu4GJ/z9c90yOWxB7b/eC+yKLPbHnH6bA==} - socket.io@4.7.2: - resolution: {integrity: sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==} + socket.io@4.8.1: + resolution: {integrity: sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==} engines: {node: '>=10.2.0'} socks-proxy-agent@7.0.0: resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} engines: {node: '>= 10'} - socks@2.7.1: - resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==} - engines: {node: '>= 10.13.0', npm: '>= 3.0.0'} + socks@2.8.4: + resolution: {integrity: sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - source-map-js@1.0.2: - resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} - engines: {node: '>=0.10.0'} + source-map-resolve@0.5.3: + resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} + deprecated: See https://github.com/lydell/source-map-resolve#deprecated source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map-url@0.4.1: + resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} + deprecated: See https://github.com/lydell/source-map-url#deprecated + source-map@0.5.6: resolution: {integrity: sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==} engines: {node: '>=0.10.0'} @@ -7584,6 +8337,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} @@ -7595,20 +8349,30 @@ packages: spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - spdx-exceptions@2.3.0: - resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - spdx-license-ids@3.0.13: - resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} + spdx-license-ids@3.0.21: + resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} + + split-string@3.1.0: + resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} + engines: {node: '>=0.10.0'} + + split@0.3.3: + resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - sshpk@1.17.0: - resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==} + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + + sshpk@1.18.0: + resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} engines: {node: '>=0.10.0'} hasBin: true @@ -7631,31 +8395,56 @@ packages: stacktrace-js@2.0.2: resolution: {integrity: sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==} - stats-gl@1.0.5: - resolution: {integrity: sha512-XimMxvwnf1Qf5KwebhcoA34kcX+fWEkIl0QjNkCbu4IpoyDMMsOajExn7FIq5w569k45+LhmsuRlGSrsvmGdNw==} + state-local@1.0.7: + resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + + static-extend@0.1.2: + resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} + engines: {node: '>=0.10.0'} + + stats-gl@1.0.7: + resolution: {integrity: sha512-vZI82CjefSxLC1bjw36z28v0+QE9rJKymGlXtfWu+ipW70ZEAwa4EbO4LxluAfLfpqiaAS04NzpYBRLDeAwYWQ==} stats.js@0.17.0: resolution: {integrity: sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==} + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} - std-env@3.4.3: - resolution: {integrity: sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} - store2@2.14.2: - resolution: {integrity: sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==} + std-env@3.8.1: + resolution: {integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==} - storybook@7.4.6: - resolution: {integrity: sha512-YkFSpnR47j5zz7yElA+2axLjXN7K7TxDGJRHHlqXmG5iQ0PXzmjrj2RxMDKFz4Ybp/QjEUoJ4rx//ESEY0Nb5A==} + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + store2@2.14.4: + resolution: {integrity: sha512-srTItn1GOvyvOycgxjAnPA63FZNwy0PTyUBFMHRM+hVFltAeoh0LmNBz9SZqUS9mMqGk8rfyWyXn3GH5ReJ8Zw==} + + storybook@7.6.20: + resolution: {integrity: sha512-Wt04pPTO71pwmRmsgkyZhNo4Bvdb/1pBAMsIFb9nQLykEdzzpXjvingxFFvdOG4nIowzwgxD+CLlyRqVJqnATw==} hasBin: true stream-browserify@3.0.0: resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} - stream-shift@1.0.1: - resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==} + stream-combiner@0.0.4: + resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} + + stream-http@3.2.0: + resolution: {integrity: sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==} + + stream-shift@1.0.3: + resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} strict-event-emitter-types@2.0.0: resolution: {integrity: sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==} @@ -7668,34 +8457,25 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} - string.prototype.matchall@4.0.10: - resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} - - string.prototype.matchall@4.0.11: - resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} - string.prototype.padend@3.1.4: - resolution: {integrity: sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw==} + string.prototype.padend@3.1.6: + resolution: {integrity: sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==} engines: {node: '>= 0.4'} - string.prototype.trim@1.2.8: - resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} engines: {node: '>= 0.4'} - string.prototype.trim@1.2.9: - resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} engines: {node: '>= 0.4'} - string.prototype.trimend@1.0.7: - resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} - - string.prototype.trimend@1.0.8: - resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} - - string.prototype.trimstart@1.0.7: - resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} - string.prototype.trimstart@1.0.8: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} @@ -7755,6 +8535,9 @@ packages: stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -7774,8 +8557,8 @@ packages: synchronous-promise@2.0.17: resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==} - systeminformation@5.22.7: - resolution: {integrity: sha512-AWxlP05KeHbpGdgvZkcudJpsmChc2Y5Eo/GvxG/iUA/Aws5LZKHAMSeAo+V+nD+nxWZaxrwpWcnx4SH3oxNL3A==} + systeminformation@5.25.11: + resolution: {integrity: sha512-jI01fn/t47rrLTQB0FTlMCC+5dYx8o0RRF+R4BPiUNsvg5OdY0s9DKMFmJGrx5SwMZQ4cag0Gl6v8oycso9b/g==} engines: {node: '>=8.0.0'} os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] hasBin: true @@ -7783,15 +8566,15 @@ packages: tabbable@6.2.0: resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} - tar-fs@2.1.1: - resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + tar-fs@2.1.2: + resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==} tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} - tar@6.2.0: - resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==} + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} telejson@7.2.0: @@ -7813,8 +8596,8 @@ packages: resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==} engines: {node: '>=10'} - terser@5.19.2: - resolution: {integrity: sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==} + terser@5.39.0: + resolution: {integrity: sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==} engines: {node: '>=10'} hasBin: true @@ -7832,8 +8615,14 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - three-stdlib@2.28.5: - resolution: {integrity: sha512-JdLMhkpT+1ZWeQPyKQNW1zqUwISI2hsUljS6u3vB9lp5EvwsayaAzGnbVeR35895udOF+zxcTiQY3psk+qqlxg==} + thingies@1.21.0: + resolution: {integrity: sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==} + engines: {node: '>=10.18'} + peerDependencies: + tslib: ^2 + + three-stdlib@2.35.14: + resolution: {integrity: sha512-kpCaEg59M9usFTgHC+YZNKvx7nMoLI2zQxZBV8pjoNW6vNZmGyXpaLBL09A2oLCsS3KepgMFkOuk6lRoebTNvA==} peerDependencies: three: 0.154.0 @@ -7847,8 +8636,8 @@ packages: resolution: {integrity: sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==} engines: {node: '>=10'} - throttleit@1.0.0: - resolution: {integrity: sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==} + throttleit@1.0.1: + resolution: {integrity: sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==} through2@0.6.5: resolution: {integrity: sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==} @@ -7866,29 +8655,32 @@ packages: timm@1.7.1: resolution: {integrity: sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==} - tiny-invariant@1.3.1: - resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - tinybench@2.5.1: - resolution: {integrity: sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} tinycolor2@1.6.0: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinypool@0.7.0: resolution: {integrity: sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==} engines: {node: '>=14.0.0'} - tinyspy@2.2.0: - resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==} + tinyspy@2.2.1: + resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} engines: {node: '>=14.0.0'} title-case@3.0.3: resolution: {integrity: sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA==} - tmp@0.2.1: - resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} - engines: {node: '>=8.17.0'} + tmp@0.2.3: + resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + engines: {node: '>=14.14'} tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -7896,16 +8688,24 @@ packages: to-array@0.1.4: resolution: {integrity: sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A==} - to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} + to-object-path@0.3.0: + resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} + engines: {node: '>=0.10.0'} + + to-regex-range@2.1.1: + resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} + engines: {node: '>=0.10.0'} to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - tocbot@4.21.2: - resolution: {integrity: sha512-R5Muhi/TUu4i4snWVrMgNoXyJm2f8sJfdgIkQvqb+cuIXQEIMAiWGWgCgYXHqX4+XiS/Bnm7IYZ9Zy6NVe6lhw==} + to-regex@3.0.2: + resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} + engines: {node: '>=0.10.0'} + + tocbot@4.35.0: + resolution: {integrity: sha512-i8FoSaP3u60D94e/dtzCk23PIEBnc/l8XqvlK4g8gUCa9XFY4RmyMLYP6X+yN+ljcEijFbmCtNHtBoeTsQkCPg==} toggle-selection@1.0.6: resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} @@ -7914,8 +8714,8 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - tough-cookie@4.1.3: - resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} engines: {node: '>=6'} tr46@0.0.3: @@ -7924,6 +8724,12 @@ packages: tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + tree-dump@1.0.2: + resolution: {integrity: sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + trim-newlines@4.1.1: resolution: {integrity: sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==} engines: {node: '>=12'} @@ -7934,12 +8740,28 @@ packages: truncate-utf8-bytes@1.0.2: resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} - ts-api-utils@1.0.3: - resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} - engines: {node: '>=16.13.0'} + ts-api-utils@1.4.3: + resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} + engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' + ts-api-utils@2.0.1: + resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-checker-rspack-plugin@1.1.1: + resolution: {integrity: sha512-BlpPqnfAmV0TcDg58H+1qV8Zb57ilv0x+ajjnxrVQ6BWgC8HzAdc+TycqDOJ4sZZYIV+hywQGozZFGklzbCR6A==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@rspack/core': ^1.0.0 + typescript: '>=3.8.0' + peerDependenciesMeta: + '@rspack/core': + optional: true + ts-dedent@2.2.0: resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} engines: {node: '>=6.10'} @@ -7947,20 +8769,23 @@ packages: ts-easing@0.2.0: resolution: {integrity: sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==} - tsconfig-paths@3.14.2: - resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.7.0: - resolution: {integrity: sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==} + tsx@4.19.3: + resolution: {integrity: sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==} engines: {node: '>=18.0.0'} hasBin: true + tty-browserify@0.0.1: + resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==} + tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -7971,8 +8796,8 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + type-detect@4.1.0: + resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} engines: {node: '>=4'} type-fest@0.16.0: @@ -8007,35 +8832,20 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - typed-array-buffer@1.0.0: - resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} - typed-array-buffer@1.0.2: - resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} engines: {node: '>= 0.4'} - typed-array-byte-length@1.0.0: - resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} engines: {node: '>= 0.4'} - typed-array-byte-length@1.0.1: - resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.0: - resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.2: - resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.4: - resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} - - typed-array-length@1.0.6: - resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} typed-emitter@1.4.0: @@ -8047,48 +8857,53 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript@5.5.0-beta: - resolution: {integrity: sha512-FRg3e/aQg3olEG3ff8YjHOERsO4IM0m4qGrsE4UMvILaq4TdDZ6gQX4+2Rq9SjTpfSe/ebwiHcsjm/7FfWWQ6Q==} + typescript@5.5.4: + resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} engines: {node: '>=14.17'} hasBin: true - ua-parser-js@1.0.37: - resolution: {integrity: sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==} + ua-parser-js@1.0.40: + resolution: {integrity: sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==} + hasBin: true uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - ufo@1.3.1: - resolution: {integrity: sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==} + ufo@1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} - uglify-js@3.17.4: - resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} + uglify-js@3.19.3: + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} engines: {node: '>=0.8.0'} hasBin: true uint4@0.1.2: resolution: {integrity: sha512-lhEx78gdTwFWG+mt6cWAZD/R6qrIj0TTBeH5xwyuDJyswLNlGe+KVlUPQ6+mx5Ld332pS0AMUTo9hIly7YsWxQ==} - unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - undici@5.25.4: - resolution: {integrity: sha512-450yJxT29qKMf3aoudzFpIciqpx6Pji3hEWaXqXmanbXF58LTAGCKxcJjxMXWu3iG+Mudgo3ZUfDB6YDFd/dAw==} - engines: {node: '>=14.0'} + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - unicode-canonical-property-names-ecmascript@2.0.0: - resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} + undici@6.0.1: + resolution: {integrity: sha512-eZFYQLeS9BiXpsU0cuFhCwfeda2MnC48EVmmOz/eCjsTgmyTdaHdVsPSC/kwC2GtW2e0uH0HIPbadf3/bRWSxw==} + engines: {node: '>=18.0'} + + unicode-canonical-property-names-ecmascript@2.0.1: + resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} unicode-match-property-ecmascript@2.0.0: resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} engines: {node: '>=4'} - unicode-match-property-value-ecmascript@2.1.0: - resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} + unicode-match-property-value-ecmascript@2.2.0: + resolution: {integrity: sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==} engines: {node: '>=4'} unicode-property-aliases-ecmascript@2.1.0: @@ -8098,8 +8913,12 @@ packages: unidiff@1.0.2: resolution: {integrity: sha512-2sbEzki5fBmjgAqoafwxRenfMcumMlmVAoJDwYJa3CI4ZVugkdR6qjTw5sVsl29/4JfBBXhWEAd5ars8nRdqXg==} - unified@11.0.4: - resolution: {integrity: sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==} + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + union-value@1.0.1: + resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + engines: {node: '>=0.10.0'} union@0.5.0: resolution: {integrity: sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==} @@ -8146,16 +8965,24 @@ packages: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} - universalify@2.0.0: - resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + unix-crypt-td-js@1.1.4: + resolution: {integrity: sha512-8rMeVYWSIyccIJscb9NdCfZKSRBKYTeVnwmiRYT2ulE3qd1RaDQ0xQDP+rI3ccIWbhu/zuo5cgN8z73belNZgw==} + unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - unplugin@1.5.0: - resolution: {integrity: sha512-9ZdRwbh/4gcm1JTOkp9lAkIDrtOyOxgHmY7cjuwI8L/2RTikMcVG25GsZwNAgRuap3iDw2jeq7eoqtAsz5rW3A==} + unplugin@1.16.1: + resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} + engines: {node: '>=14.0.0'} + + unset-value@1.0.0: + resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} + engines: {node: '>=0.10.0'} untildify@4.0.0: resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} @@ -8165,8 +8992,8 @@ packages: resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} engines: {node: '>=4'} - update-browserslist-db@1.0.11: - resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==} + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -8180,38 +9007,55 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + urix@0.1.0: + resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} + deprecated: Please see https://github.com/lydell/urix#deprecated + url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - use-callback-ref@1.3.0: - resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==} + url@0.11.4: + resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} + engines: {node: '>= 0.4'} + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' react: ^18.2.0 peerDependenciesMeta: '@types/react': optional: true - use-deep-compare@1.1.0: - resolution: {integrity: sha512-6yY3zmKNCJ1jjIivfZMZMReZjr8e6iC6Uqtp701jvWJ6ejC/usXD+JjmslZDPJQgX8P4B1Oi5XSLHkOLeYSJsA==} + use-deep-compare@1.3.0: + resolution: {integrity: sha512-94iG+dEdEP/Sl3WWde+w9StIunlV8Dgj+vkt5wTwMoFQLaijiEZSXXy8KtcStpmEDtIptRJiNeD4ACTtVvnIKA==} peerDependencies: react: ^18.2.0 + use-isomorphic-layout-effect@1.2.0: + resolution: {integrity: sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==} + peerDependencies: + '@types/react': '*' + react: ^18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + use-resize-observer@9.1.0: resolution: {integrity: sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==} peerDependencies: react: ^18.2.0 react-dom: 16.8.0 - 18 - use-sidecar@1.1.2: - resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} engines: {node: '>=10'} peerDependencies: - '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' react: ^18.2.0 peerDependenciesMeta: '@types/react': @@ -8232,8 +9076,12 @@ packages: typescript: optional: true - utf8-byte-length@1.0.4: - resolution: {integrity: sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==} + use@3.1.1: + resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} + engines: {node: '>=0.10.0'} + + utf8-byte-length@1.0.5: + resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} utif@2.0.1: resolution: {integrity: sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg==} @@ -8251,6 +9099,11 @@ packages: uuid-1345@1.0.2: resolution: {integrity: sha512-bA5zYZui+3nwAc0s3VdGQGBfbVsJLVX7Np7ch2aqcEWFi5lsAEcmO3+lx3djM1npgpZI8KY2FITZ2uYTnYUYyw==} + uuid@3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true @@ -8259,10 +9112,6 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - v8-to-istanbul@9.1.3: - resolution: {integrity: sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==} - engines: {node: '>=10.12.0'} - validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} @@ -8278,12 +9127,24 @@ packages: react: optional: true + valtio@1.13.2: + resolution: {integrity: sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=16.8' + react: ^18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vec3@0.1.8: - resolution: {integrity: sha512-LfKrP625Bsg/Tj52YdYPsHmpsJuo+tc6fLxZxXjEo9k2xSspKlPvoYTHehykKhp1FvV9nm+XU3Ehej5/9tpDCg==} + vec3@0.1.10: + resolution: {integrity: sha512-Sr1U3mYtMqCOonGd3LAN9iqy0qF6C+Gjil92awyK/i2OwiUo9bm7PnLgFpafymun50mOjnDcg4ToTgRssrlTcw==} verror@1.10.0: resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} @@ -8292,16 +9153,16 @@ packages: vfile-message@4.0.2: resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} - vfile@6.0.1: - resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==} + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} vite-node@0.34.6: resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==} engines: {node: '>=v14.18.0'} hasBin: true - vite@4.4.10: - resolution: {integrity: sha512-TzIjiqx9BEXF8yzYdF2NTf1kFFbjMjUSV0LFZ3HyHoI3SGSPLnnFUKiIQtL3gl2AjHvMrprOvQ3amzaHgQlAxw==} + vite@4.5.9: + resolution: {integrity: sha512-qK9W4xjgD3gXbC0NmdNFFnVFLMWSNiR3swj957yutwzzN16xF/E7nmtAyp1rT9hviDroQANjE4HK3H4WqWdFtw==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: @@ -8328,33 +9189,45 @@ packages: terser: optional: true - vite@4.5.3: - resolution: {integrity: sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==} - engines: {node: ^14.18.0 || >=16.0.0} + vite@6.2.1: + resolution: {integrity: sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: - '@types/node': '>= 14' + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' less: '*' lightningcss: ^1.21.0 sass: '*' + sass-embedded: '*' stylus: '*' sugarss: '*' - terser: ^5.4.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: '@types/node': optional: true + jiti: + optional: true less: optional: true lightningcss: optional: true sass: optional: true + sass-embedded: + optional: true stylus: optional: true sugarss: optional: true terser: optional: true + tsx: + optional: true + yaml: + optional: true vitest@0.34.6: resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==} @@ -8387,17 +9260,25 @@ packages: webdriverio: optional: true + vm-browserify@1.1.2: + resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} + w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + wait-on@7.2.0: + resolution: {integrity: sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==} + engines: {node: '>=12.0.0'} + hasBin: true + walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} warning@4.0.3: resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} - watchpack@2.4.0: - resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} + watchpack@2.4.2: + resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} engines: {node: '>=10.13.0'} wcwidth@1.0.1: @@ -8409,23 +9290,27 @@ packages: webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - webpack-sources@3.2.3: - resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} - engines: {node: '>=10.13.0'} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - webpack-virtual-modules@0.5.0: - resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==} - - webrtc-adapter@8.2.3: - resolution: {integrity: sha512-gnmRz++suzmvxtp3ehQts6s2JtAGPuDPjA1F3a9ckNpG1kYdYuHWYpazoAnL9FS5/B21tKlhkorbdCXat0+4xQ==} + webrtc-adapter@9.0.1: + resolution: {integrity: sha512-1AQO+d4ElfVSXyzNVTOewgGT/tAomwwztX/6e3totvyyzXPvXIIuUUjAmyZGbKBKbZOXauuJooZm3g6IuFuiNQ==} engines: {node: '>=6.0.0', npm: '>=3.10.0'} + websocket-driver@0.7.4: + resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} + engines: {node: '>=0.8.0'} + + websocket-extensions@0.1.4: + resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} + engines: {node: '>=0.8.0'} + whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'} - whatwg-fetch@3.6.18: - resolution: {integrity: sha512-ltN7j66EneWn5TFDO4L9inYC1D+Czsxlrw2SalgjMmEMkLfA5SIZxEFdE6QtHFiiM6Q7WL32c7AkI3w6yxM84Q==} + whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -8433,23 +9318,24 @@ packages: whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} - which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} - which-builtin-type@1.1.3: - resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} engines: {node: '>= 0.4'} which-collection@1.0.2: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} - which-typed-array@1.1.11: - resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==} + which-typed-array@1.1.18: + resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} engines: {node: '>= 0.4'} - which-typed-array@1.1.15: - resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} engines: {node: '>= 0.4'} which@1.3.1: @@ -8461,65 +9347,69 @@ packages: engines: {node: '>= 8'} hasBin: true - why-is-node-running@2.2.2: - resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} hasBin: true wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - workbox-background-sync@7.0.0: - resolution: {integrity: sha512-S+m1+84gjdueM+jIKZ+I0Lx0BDHkk5Nu6a3kTVxP4fdj3gKouRNmhO8H290ybnJTOPfBDtTMXSQA/QLTvr7PeA==} + workbox-background-sync@7.3.0: + resolution: {integrity: sha512-PCSk3eK7Mxeuyatb22pcSx9dlgWNv3+M8PqPaYDokks8Y5/FX4soaOqj3yhAZr5k6Q5JWTOMYgaJBpbw11G9Eg==} - workbox-broadcast-update@7.0.0: - resolution: {integrity: sha512-oUuh4jzZrLySOo0tC0WoKiSg90bVAcnE98uW7F8GFiSOXnhogfNDGZelPJa+6KpGBO5+Qelv04Hqx2UD+BJqNQ==} + workbox-broadcast-update@7.3.0: + resolution: {integrity: sha512-T9/F5VEdJVhwmrIAE+E/kq5at2OY6+OXXgOWQevnubal6sO92Gjo24v6dCVwQiclAF5NS3hlmsifRrpQzZCdUA==} - workbox-build@7.0.0: - resolution: {integrity: sha512-CttE7WCYW9sZC+nUYhQg3WzzGPr4IHmrPnjKiu3AMXsiNQKx+l4hHl63WTrnicLmKEKHScWDH8xsGBdrYgtBzg==} + workbox-build@7.3.0: + resolution: {integrity: sha512-JGL6vZTPlxnlqZRhR/K/msqg3wKP+m0wfEUVosK7gsYzSgeIxvZLi1ViJJzVL7CEeI8r7rGFV973RiEqkP3lWQ==} engines: {node: '>=16.0.0'} - workbox-cacheable-response@7.0.0: - resolution: {integrity: sha512-0lrtyGHn/LH8kKAJVOQfSu3/80WDc9Ma8ng0p2i/5HuUndGttH+mGMSvOskjOdFImLs2XZIimErp7tSOPmu/6g==} + workbox-cacheable-response@7.3.0: + resolution: {integrity: sha512-eAFERIg6J2LuyELhLlmeRcJFa5e16Mj8kL2yCDbhWE+HUun9skRQrGIFVUagqWj4DMaaPSMWfAolM7XZZxNmxA==} - workbox-core@7.0.0: - resolution: {integrity: sha512-81JkAAZtfVP8darBpfRTovHg8DGAVrKFgHpOArZbdFd78VqHr5Iw65f2guwjE2NlCFbPFDoez3D3/6ZvhI/rwQ==} + workbox-core@7.3.0: + resolution: {integrity: sha512-Z+mYrErfh4t3zi7NVTvOuACB0A/jA3bgxUN3PwtAVHvfEsZxV9Iju580VEETug3zYJRc0Dmii/aixI/Uxj8fmw==} - workbox-expiration@7.0.0: - resolution: {integrity: sha512-MLK+fogW+pC3IWU9SFE+FRStvDVutwJMR5if1g7oBJx3qwmO69BNoJQVaMXq41R0gg3MzxVfwOGKx3i9P6sOLQ==} + workbox-expiration@7.3.0: + resolution: {integrity: sha512-lpnSSLp2BM+K6bgFCWc5bS1LR5pAwDWbcKt1iL87/eTSJRdLdAwGQznZE+1czLgn/X05YChsrEegTNxjM067vQ==} - workbox-google-analytics@7.0.0: - resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==} + workbox-google-analytics@7.3.0: + resolution: {integrity: sha512-ii/tSfFdhjLHZ2BrYgFNTrb/yk04pw2hasgbM70jpZfLk0vdJAXgaiMAWsoE+wfJDNWoZmBYY0hMVI0v5wWDbg==} - workbox-navigation-preload@7.0.0: - resolution: {integrity: sha512-juWCSrxo/fiMz3RsvDspeSLGmbgC0U9tKqcUPZBCf35s64wlaLXyn2KdHHXVQrb2cqF7I0Hc9siQalainmnXJA==} + workbox-navigation-preload@7.3.0: + resolution: {integrity: sha512-fTJzogmFaTv4bShZ6aA7Bfj4Cewaq5rp30qcxl2iYM45YD79rKIhvzNHiFj1P+u5ZZldroqhASXwwoyusnr2cg==} - workbox-precaching@7.0.0: - resolution: {integrity: sha512-EC0vol623LJqTJo1mkhD9DZmMP604vHqni3EohhQVwhJlTgyKyOkMrZNy5/QHfOby+39xqC01gv4LjOm4HSfnA==} + workbox-precaching@7.3.0: + resolution: {integrity: sha512-ckp/3t0msgXclVAYaNndAGeAoWQUv7Rwc4fdhWL69CCAb2UHo3Cef0KIUctqfQj1p8h6aGyz3w8Cy3Ihq9OmIw==} - workbox-range-requests@7.0.0: - resolution: {integrity: sha512-SxAzoVl9j/zRU9OT5+IQs7pbJBOUOlriB8Gn9YMvi38BNZRbM+RvkujHMo8FOe9IWrqqwYgDFBfv6sk76I1yaQ==} + workbox-range-requests@7.3.0: + resolution: {integrity: sha512-EyFmM1KpDzzAouNF3+EWa15yDEenwxoeXu9bgxOEYnFfCxns7eAxA9WSSaVd8kujFFt3eIbShNqa4hLQNFvmVQ==} - workbox-recipes@7.0.0: - resolution: {integrity: sha512-DntcK9wuG3rYQOONWC0PejxYYIDHyWWZB/ueTbOUDQgefaeIj1kJ7pdP3LZV2lfrj8XXXBWt+JDRSw1lLLOnww==} + workbox-recipes@7.3.0: + resolution: {integrity: sha512-BJro/MpuW35I/zjZQBcoxsctgeB+kyb2JAP5EB3EYzePg8wDGoQuUdyYQS+CheTb+GhqJeWmVs3QxLI8EBP1sg==} - workbox-routing@7.0.0: - resolution: {integrity: sha512-8YxLr3xvqidnbVeGyRGkaV4YdlKkn5qZ1LfEePW3dq+ydE73hUUJJuLmGEykW3fMX8x8mNdL0XrWgotcuZjIvA==} + workbox-routing@7.3.0: + resolution: {integrity: sha512-ZUlysUVn5ZUzMOmQN3bqu+gK98vNfgX/gSTZ127izJg/pMMy4LryAthnYtjuqcjkN4HEAx1mdgxNiKJMZQM76A==} - workbox-strategies@7.0.0: - resolution: {integrity: sha512-dg3qJU7tR/Gcd/XXOOo7x9QoCI9nk74JopaJaYAQ+ugLi57gPsXycVdBnYbayVj34m6Y8ppPwIuecrzkpBVwbA==} + workbox-strategies@7.3.0: + resolution: {integrity: sha512-tmZydug+qzDFATwX7QiEL5Hdf7FrkhjaF9db1CbB39sDmEZJg3l9ayDvPxy8Y18C3Y66Nrr9kkN1f/RlkDgllg==} - workbox-streams@7.0.0: - resolution: {integrity: sha512-moVsh+5to//l6IERWceYKGiftc+prNnqOp2sgALJJFbnNVpTXzKISlTIsrWY+ogMqt+x1oMazIdHj25kBSq/HQ==} + workbox-streams@7.3.0: + resolution: {integrity: sha512-SZnXucyg8x2Y61VGtDjKPO5EgPUG5NDn/v86WYHX+9ZqvAsGOytP0Jxp1bl663YUuMoXSAtsGLL+byHzEuMRpw==} - workbox-sw@7.0.0: - resolution: {integrity: sha512-SWfEouQfjRiZ7GNABzHUKUyj8pCoe+RwjfOIajcx6J5mtgKkN+t8UToHnpaJL5UVVOf5YhJh+OHhbVNIHe+LVA==} + workbox-sw@7.3.0: + resolution: {integrity: sha512-aCUyoAZU9IZtH05mn0ACUpyHzPs0lMeJimAYkQkBsOWiqaJLgusfDCR+yllkPkFRxWpZKF8vSvgHYeG7LwhlmA==} - workbox-window@7.0.0: - resolution: {integrity: sha512-j7P/bsAWE/a7sxqTzXo3P2ALb1reTfZdvVp6OJ/uLr/C2kZAMvjeWGm8V4htQhor7DOvYg0sSbFN2+flT5U0qA==} + workbox-window@7.3.0: + resolution: {integrity: sha512-qW8PDy16OV1UBaUNGlTVcepzrlzyzNW/ZJvFQQs2j2TzGsg6IKjcpZC1RSquqQnTOafl5pCj5bGfAHlCjOOjdA==} wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} @@ -8543,8 +9433,8 @@ packages: resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - ws@5.2.3: - resolution: {integrity: sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==} + ws@5.2.4: + resolution: {integrity: sha512-fFCejsuC8f9kOSu9FYaOw8CdO68O3h5v0lg4p74o8JqWpwTf9tniOD+nOB78aWoVSS6WptVUmDrp/KPsMVBWFQ==} peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -8554,8 +9444,8 @@ packages: utf-8-validate: optional: true - ws@6.2.2: - resolution: {integrity: sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==} + ws@6.2.3: + resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -8565,8 +9455,8 @@ packages: utf-8-validate: optional: true - ws@7.4.6: - resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} engines: {node: '>=8.3.0'} peerDependencies: bufferutil: ^4.0.1 @@ -8577,12 +9467,24 @@ packages: utf-8-validate: optional: true - ws@8.11.0: - resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.18.1: + resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' peerDependenciesMeta: bufferutil: optional: true @@ -8595,8 +9497,8 @@ packages: xml-parse-from-string@1.0.1: resolution: {integrity: sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==} - xml2js@0.4.23: - resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==} + xml2js@0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} engines: {node: '>=4.0.0'} xmlbuilder@11.0.1: @@ -8607,8 +9509,8 @@ packages: resolution: {integrity: sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==} engines: {node: '>=0.4.0'} - xmlhttprequest-ssl@2.0.0: - resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==} + xmlhttprequest-ssl@2.1.2: + resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} engines: {node: '>=0.4.0'} xtend@4.0.2: @@ -8632,12 +9534,8 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} - yaml@2.3.2: - resolution: {integrity: sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==} - engines: {node: '>= 14'} - - yaml@2.4.1: - resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} + yaml@2.7.0: + resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} engines: {node: '>= 14'} hasBin: true @@ -8649,10 +9547,6 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -8660,6 +9554,9 @@ packages: yauzl@2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yazl@2.5.1: + resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==} + yeast@0.1.2: resolution: {integrity: sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==} @@ -8670,10 +9567,13 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yocto-queue@1.0.0: - resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + yocto-queue@1.2.0: + resolution: {integrity: sha512-KHBC7z61OJeaMGnF3wqNZj+GGNXOyypZviiKpQeiHirG5Ib1ImwcLBH70rbMSkKfSmUNBsdf2PwaEJtKvgmkNw==} engines: {node: '>=12.20'} + zod@3.24.2: + resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==} + zustand@3.6.5: resolution: {integrity: sha512-/WfLJuXiEJimt61KGMHebrFBwckkCHGhAgVXTgPQHl6IMzjqm6MREb1OnDSnCRiSmRdhgdFCctceg6tSm79hiw==} engines: {node: '>=12.7.0'} @@ -8688,16 +9588,14 @@ packages: snapshots: - '@aashutoshrathi/word-wrap@1.2.6': {} - - '@ampproject/remapping@2.2.1': + '@ampproject/remapping@2.3.0': dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.19 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 - '@apideck/better-ajv-errors@0.3.6(ajv@8.12.0)': + '@apideck/better-ajv-errors@0.3.6(ajv@8.17.1)': dependencies: - ajv: 8.12.0 + ajv: 8.17.1 json-schema: 0.4.0 jsonpointer: 5.0.1 leven: 3.1.0 @@ -8706,875 +9604,731 @@ snapshots: dependencies: default-browser-id: 3.0.0 - '@azure/msal-common@14.9.0': {} + '@azure/msal-common@14.16.0': {} - '@azure/msal-node@2.7.0': + '@azure/msal-node@2.16.2': dependencies: - '@azure/msal-common': 14.9.0 + '@azure/msal-common': 14.16.0 jsonwebtoken: 9.0.2 uuid: 8.3.2 - '@babel/code-frame@7.22.13': + '@babel/code-frame@7.26.2': dependencies: - '@babel/highlight': 7.22.13 - chalk: 2.4.2 + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 - '@babel/compat-data@7.22.9': {} + '@babel/compat-data@7.26.8': {} - '@babel/core@7.22.11': + '@babel/core@7.26.9': dependencies: - '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.22.13 - '@babel/generator': 7.22.10 - '@babel/helper-compilation-targets': 7.22.10 - '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.11) - '@babel/helpers': 7.22.11 - '@babel/parser': 7.22.13 - '@babel/template': 7.22.5 - '@babel/traverse': 7.22.11 - '@babel/types': 7.22.11 - convert-source-map: 1.9.0 - debug: 4.3.4(supports-color@8.1.1) + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.9 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9) + '@babel/helpers': 7.26.9 + '@babel/parser': 7.26.9 + '@babel/template': 7.26.9 + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 + convert-source-map: 2.0.0 + debug: 4.4.0(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/generator@7.22.10': + '@babel/generator@7.26.9': dependencies: - '@babel/types': 7.22.11 - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.19 - jsesc: 2.5.2 + '@babel/parser': 7.26.9 + '@babel/types': 7.26.9 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 - '@babel/helper-annotate-as-pure@7.22.5': + '@babel/helper-annotate-as-pure@7.25.9': dependencies: - '@babel/types': 7.22.11 + '@babel/types': 7.26.9 - '@babel/helper-builder-binary-assignment-operator-visitor@7.22.10': + '@babel/helper-compilation-targets@7.26.5': dependencies: - '@babel/types': 7.22.11 - - '@babel/helper-compilation-targets@7.22.10': - dependencies: - '@babel/compat-data': 7.22.9 - '@babel/helper-validator-option': 7.22.5 - browserslist: 4.21.10 + '@babel/compat-data': 7.26.8 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.4 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.22.11(@babel/core@7.22.11)': + '@babel/helper-create-class-features-plugin@7.26.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-function-name': 7.22.5 - '@babel/helper-member-expression-to-functions': 7.22.5 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.22.9(@babel/core@7.22.11) - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 + '@babel/core': 7.26.9 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.9) + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/traverse': 7.26.9 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-regexp-features-plugin@7.26.3(@babel/core@7.26.9)': + dependencies: + '@babel/core': 7.26.9 + '@babel/helper-annotate-as-pure': 7.25.9 + regexpu-core: 6.2.0 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.22.15(@babel/core@7.22.11)': + '@babel/helper-define-polyfill-provider@0.6.3(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-function-name': 7.22.5 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.22.9(@babel/core@7.22.11) - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - semver: 6.3.1 - - '@babel/helper-create-regexp-features-plugin@7.22.9(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-annotate-as-pure': 7.22.5 - regexpu-core: 5.3.2 - semver: 6.3.1 - - '@babel/helper-define-polyfill-provider@0.4.2(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-compilation-targets': 7.22.10 - '@babel/helper-plugin-utils': 7.22.5 - debug: 4.3.4(supports-color@8.1.1) + '@babel/core': 7.26.9 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-plugin-utils': 7.26.5 + debug: 4.4.1 lodash.debounce: 4.0.8 - resolve: 1.22.4 + resolve: 1.22.10 transitivePeerDependencies: - supports-color - '@babel/helper-environment-visitor@7.22.20': {} - - '@babel/helper-environment-visitor@7.22.5': {} - - '@babel/helper-function-name@7.22.5': + '@babel/helper-member-expression-to-functions@7.25.9': dependencies: - '@babel/template': 7.22.5 - '@babel/types': 7.22.11 - - '@babel/helper-hoist-variables@7.22.5': - dependencies: - '@babel/types': 7.22.11 - - '@babel/helper-member-expression-to-functions@7.22.5': - dependencies: - '@babel/types': 7.22.11 - - '@babel/helper-member-expression-to-functions@7.23.0': - dependencies: - '@babel/types': 7.23.0 - - '@babel/helper-module-imports@7.22.15': - dependencies: - '@babel/types': 7.23.0 - - '@babel/helper-module-imports@7.22.5': - dependencies: - '@babel/types': 7.22.11 - - '@babel/helper-module-transforms@7.22.9(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-module-imports': 7.22.5 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.5 - - '@babel/helper-module-transforms@7.23.0(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 - - '@babel/helper-optimise-call-expression@7.22.5': - dependencies: - '@babel/types': 7.22.11 - - '@babel/helper-plugin-utils@7.22.5': {} - - '@babel/helper-remap-async-to-generator@7.22.9(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-wrap-function': 7.22.10 - - '@babel/helper-replace-supers@7.22.9(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-member-expression-to-functions': 7.22.5 - '@babel/helper-optimise-call-expression': 7.22.5 - - '@babel/helper-simple-access@7.22.5': - dependencies: - '@babel/types': 7.22.11 - - '@babel/helper-skip-transparent-expression-wrappers@7.22.5': - dependencies: - '@babel/types': 7.22.11 - - '@babel/helper-split-export-declaration@7.22.6': - dependencies: - '@babel/types': 7.22.11 - - '@babel/helper-string-parser@7.22.5': {} - - '@babel/helper-validator-identifier@7.22.20': {} - - '@babel/helper-validator-identifier@7.22.5': {} - - '@babel/helper-validator-option@7.22.15': {} - - '@babel/helper-validator-option@7.22.5': {} - - '@babel/helper-wrap-function@7.22.10': - dependencies: - '@babel/helper-function-name': 7.22.5 - '@babel/template': 7.22.5 - '@babel/types': 7.22.11 - - '@babel/helpers@7.22.11': - dependencies: - '@babel/template': 7.22.5 - '@babel/traverse': 7.22.11 - '@babel/types': 7.22.11 + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 transitivePeerDependencies: - supports-color - '@babel/highlight@7.22.13': + '@babel/helper-module-imports@7.25.9': dependencies: - '@babel/helper-validator-identifier': 7.22.5 - chalk: 2.4.2 - js-tokens: 4.0.0 + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 + transitivePeerDependencies: + - supports-color - '@babel/parser@7.22.13': + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.9)': dependencies: - '@babel/types': 7.22.11 + '@babel/core': 7.26.9 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.26.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.22.5(@babel/core@7.22.11)': + '@babel/helper-optimise-call-expression@7.25.9': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/types': 7.26.9 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.22.5(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-optional-chaining': 7.22.12(@babel/core@7.22.11) + '@babel/helper-plugin-utils@7.26.5': {} - '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.22.11)': + '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-create-class-features-plugin': 7.22.11(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-wrap-function': 7.25.9 + '@babel/traverse': 7.26.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.22.11)': + '@babel/helper-replace-supers@7.26.5(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/traverse': 7.26.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.22.11)': + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.11) + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 + '@babel/helper-string-parser@7.25.9': {} - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-identifier@7.25.9': {} - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option@7.25.9': {} - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.22.11)': + '@babel/helper-wrap-function@7.25.9': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/template': 7.26.9 + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.22.11)': + '@babel/helpers@7.26.9': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/template': 7.26.9 + '@babel/types': 7.26.9 - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.22.11)': + '@babel/parser@7.26.9': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/types': 7.26.9 - '@babel/plugin-syntax-flow@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/traverse': 7.26.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-syntax-import-assertions@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-import-attributes@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.22.11)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.9) + transitivePeerDependencies: + - supports-color - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.22.11)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/traverse': 7.26.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.22.11)': + '@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.22.11)': + '@babel/plugin-syntax-import-assertions@7.26.0(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.22.11)': + '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.22.11)': + '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.22.11)': + '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.11)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.22.11)': + '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.22.11)': + '@babel/plugin-transform-async-generator-functions@7.26.8(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.9) + '@babel/traverse': 7.26.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.9) + transitivePeerDependencies: + - supports-color - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.22.11)': + '@babel/plugin-transform-block-scoped-functions@7.26.5(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-create-regexp-features-plugin': 7.22.9(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-arrow-functions@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-async-generator-functions@7.22.11(@babel/core@7.22.11)': + '@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-remap-async-to-generator': 7.22.9(@babel/core@7.22.11) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-async-to-generator@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-class-static-block@7.26.0(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-module-imports': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-remap-async-to-generator': 7.22.9(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-block-scoped-functions@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-classes@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - - '@babel/plugin-transform-block-scoping@7.22.10(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - - '@babel/plugin-transform-class-properties@7.22.5(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-create-class-features-plugin': 7.22.11(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 - - '@babel/plugin-transform-class-static-block@7.22.11(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-create-class-features-plugin': 7.22.11(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.11) - - '@babel/plugin-transform-classes@7.22.6(@babel/core@7.22.11)': - dependencies: - '@babel/core': 7.22.11 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-compilation-targets': 7.22.10 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-function-name': 7.22.5 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-replace-supers': 7.22.9(@babel/core@7.22.11) - '@babel/helper-split-export-declaration': 7.22.6 + '@babel/core': 7.26.9 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.9) + '@babel/traverse': 7.26.9 globals: 11.12.0 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-computed-properties@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/template': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/template': 7.26.9 - '@babel/plugin-transform-destructuring@7.22.10(@babel/core@7.22.11)': + '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-dotall-regex@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-dotall-regex@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-create-regexp-features-plugin': 7.22.9(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-duplicate-keys@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-duplicate-keys@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-dynamic-import@7.22.11(@babel/core@7.22.11)': + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-exponentiation-operator@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-dynamic-import@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.10 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-export-namespace-from@7.22.11(@babel/core@7.22.11)': + '@babel/plugin-transform-exponentiation-operator@7.26.3(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-flow-strip-types@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-export-namespace-from@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-flow': 7.22.5(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-for-of@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-flow-strip-types@7.26.5(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.9) - '@babel/plugin-transform-function-name@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-for-of@7.26.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-compilation-targets': 7.22.10 - '@babel/helper-function-name': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-json-strings@7.22.11(@babel/core@7.22.11)': + '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/traverse': 7.26.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-literals@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-json-strings@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-logical-assignment-operators@7.22.11(@babel/core@7.22.11)': + '@babel/plugin-transform-literals@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-member-expression-literals@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-modules-amd@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-member-expression-literals@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-modules-commonjs@7.22.11(@babel/core@7.22.11)': + '@babel/plugin-transform-modules-amd@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-simple-access': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-modules-commonjs@7.23.0(@babel/core@7.22.11)': + '@babel/plugin-transform-modules-commonjs@7.26.3(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-module-transforms': 7.23.0(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-simple-access': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-modules-systemjs@7.22.11(@babel/core@7.22.11)': + '@babel/plugin-transform-modules-systemjs@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-identifier': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.26.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-modules-umd@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-modules-umd@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-create-regexp-features-plugin': 7.22.9(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-new-target@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-new-target@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-nullish-coalescing-operator@7.22.11(@babel/core@7.22.11)': + '@babel/plugin-transform-nullish-coalescing-operator@7.26.6(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-numeric-separator@7.22.11(@babel/core@7.22.11)': + '@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-object-rest-spread@7.22.11(@babel/core@7.22.11)': + '@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/compat-data': 7.22.9 - '@babel/core': 7.22.11 - '@babel/helper-compilation-targets': 7.22.10 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-transform-parameters': 7.22.5(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-object-super@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-object-super@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-replace-supers': 7.22.9(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.9) + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-optional-catch-binding@7.22.11(@babel/core@7.22.11)': + '@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-optional-chaining@7.22.12(@babel/core@7.22.11)': + '@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-parameters@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-private-methods@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-create-class-features-plugin': 7.22.11(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-private-property-in-object@7.22.11(@babel/core@7.22.11)': + '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.22.11(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-property-literals@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-property-literals@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-react-jsx-self@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-react-jsx-source@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-regenerator@7.22.10(@babel/core@7.22.11)': + '@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 regenerator-transform: 0.15.2 - '@babel/plugin-transform-reserved-words@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-regexp-modifiers@7.26.0(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-shorthand-properties@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-reserved-words@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-spread@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-sticky-regex@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-spread@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-template-literals@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-typeof-symbol@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-template-literals@7.26.8(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-typescript@7.22.15(@babel/core@7.22.11)': + '@babel/plugin-transform-typeof-symbol@7.26.7(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-unicode-escapes@7.22.10(@babel/core@7.22.11)': + '@babel/plugin-transform-typescript@7.26.8(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.9) + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-unicode-property-regex@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-unicode-escapes@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-create-regexp-features-plugin': 7.22.9(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-unicode-regex@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-unicode-property-regex@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-create-regexp-features-plugin': 7.22.9(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-unicode-sets-regex@7.22.5(@babel/core@7.22.11)': + '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-create-regexp-features-plugin': 7.22.9(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.9 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 - '@babel/preset-env@7.22.10(@babel/core@7.22.11)': + '@babel/plugin-transform-unicode-sets-regex@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/compat-data': 7.22.9 - '@babel/core': 7.22.11 - '@babel/helper-compilation-targets': 7.22.10 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.22.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.22.11) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.11) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.11) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.11) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-import-assertions': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-syntax-import-attributes': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.22.11) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.11) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.11) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.11) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.11) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.22.11) - '@babel/plugin-transform-arrow-functions': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-async-generator-functions': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-async-to-generator': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-block-scoped-functions': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-block-scoping': 7.22.10(@babel/core@7.22.11) - '@babel/plugin-transform-class-properties': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-class-static-block': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-classes': 7.22.6(@babel/core@7.22.11) - '@babel/plugin-transform-computed-properties': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-destructuring': 7.22.10(@babel/core@7.22.11) - '@babel/plugin-transform-dotall-regex': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-duplicate-keys': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-dynamic-import': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-exponentiation-operator': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-export-namespace-from': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-for-of': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-function-name': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-json-strings': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-literals': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-logical-assignment-operators': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-member-expression-literals': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-modules-amd': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-modules-commonjs': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-modules-systemjs': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-modules-umd': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-new-target': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-nullish-coalescing-operator': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-numeric-separator': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-object-rest-spread': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-object-super': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-optional-catch-binding': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-optional-chaining': 7.22.12(@babel/core@7.22.11) - '@babel/plugin-transform-parameters': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-private-methods': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-private-property-in-object': 7.22.11(@babel/core@7.22.11) - '@babel/plugin-transform-property-literals': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-regenerator': 7.22.10(@babel/core@7.22.11) - '@babel/plugin-transform-reserved-words': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-shorthand-properties': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-spread': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-sticky-regex': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-template-literals': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-typeof-symbol': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-unicode-escapes': 7.22.10(@babel/core@7.22.11) - '@babel/plugin-transform-unicode-property-regex': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-unicode-regex': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-unicode-sets-regex': 7.22.5(@babel/core@7.22.11) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.22.11) - '@babel/types': 7.22.11 - babel-plugin-polyfill-corejs2: 0.4.5(@babel/core@7.22.11) - babel-plugin-polyfill-corejs3: 0.8.3(@babel/core@7.22.11) - babel-plugin-polyfill-regenerator: 0.5.2(@babel/core@7.22.11) - core-js-compat: 3.32.1 + '@babel/core': 7.26.9 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/preset-env@7.26.9(@babel/core@7.26.9)': + dependencies: + '@babel/compat-data': 7.26.8 + '@babel/core': 7.26.9 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.9) + '@babel/plugin-syntax-import-assertions': 7.26.0(@babel/core@7.26.9) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.9) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.26.9) + '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-async-generator-functions': 7.26.8(@babel/core@7.26.9) + '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-block-scoped-functions': 7.26.5(@babel/core@7.26.9) + '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-class-static-block': 7.26.0(@babel/core@7.26.9) + '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-dotall-regex': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-duplicate-keys': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-dynamic-import': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-exponentiation-operator': 7.26.3(@babel/core@7.26.9) + '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-for-of': 7.26.9(@babel/core@7.26.9) + '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-json-strings': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-member-expression-literals': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-modules-amd': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.9) + '@babel/plugin-transform-modules-systemjs': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-modules-umd': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-new-target': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-nullish-coalescing-operator': 7.26.6(@babel/core@7.26.9) + '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-object-super': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-property-literals': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-regexp-modifiers': 7.26.0(@babel/core@7.26.9) + '@babel/plugin-transform-reserved-words': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-template-literals': 7.26.8(@babel/core@7.26.9) + '@babel/plugin-transform-typeof-symbol': 7.26.7(@babel/core@7.26.9) + '@babel/plugin-transform-unicode-escapes': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-unicode-property-regex': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-unicode-sets-regex': 7.25.9(@babel/core@7.26.9) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.26.9) + babel-plugin-polyfill-corejs2: 0.4.12(@babel/core@7.26.9) + babel-plugin-polyfill-corejs3: 0.11.1(@babel/core@7.26.9) + babel-plugin-polyfill-regenerator: 0.6.3(@babel/core@7.26.9) + core-js-compat: 3.41.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-flow@7.22.15(@babel/core@7.22.11)': + '@babel/preset-flow@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.22.15 - '@babel/plugin-transform-flow-strip-types': 7.22.5(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-transform-flow-strip-types': 7.26.5(@babel/core@7.26.9) - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.22.11)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/types': 7.22.11 + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/types': 7.26.9 esutils: 2.0.3 - '@babel/preset-typescript@7.23.0(@babel/core@7.22.11)': + '@babel/preset-typescript@7.26.0(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.22.15 - '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-modules-commonjs': 7.23.0(@babel/core@7.22.11) - '@babel/plugin-transform-typescript': 7.22.15(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.9) + '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.9) + transitivePeerDependencies: + - supports-color - '@babel/register@7.22.15(@babel/core@7.22.11)': + '@babel/register@7.25.9(@babel/core@7.26.9)': dependencies: - '@babel/core': 7.22.11 + '@babel/core': 7.26.9 clone-deep: 4.0.1 find-cache-dir: 2.1.0 make-dir: 2.1.0 pirates: 4.0.6 source-map-support: 0.5.21 - '@babel/regjsgen@0.8.0': {} - - '@babel/runtime@7.22.11': + '@babel/runtime@7.26.9': dependencies: - regenerator-runtime: 0.14.0 + regenerator-runtime: 0.14.1 - '@babel/runtime@7.24.5': + '@babel/template@7.26.9': dependencies: - regenerator-runtime: 0.14.0 + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.9 + '@babel/types': 7.26.9 - '@babel/template@7.22.5': + '@babel/traverse@7.26.9': dependencies: - '@babel/code-frame': 7.22.13 - '@babel/parser': 7.22.13 - '@babel/types': 7.22.11 - - '@babel/traverse@7.22.11': - dependencies: - '@babel/code-frame': 7.22.13 - '@babel/generator': 7.22.10 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-function-name': 7.22.5 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.22.13 - '@babel/types': 7.22.11 - debug: 4.3.4(supports-color@8.1.1) + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.9 + '@babel/parser': 7.26.9 + '@babel/template': 7.26.9 + '@babel/types': 7.26.9 + debug: 4.4.1 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/types@7.22.11': + '@babel/types@7.26.9': dependencies: - '@babel/helper-string-parser': 7.22.5 - '@babel/helper-validator-identifier': 7.22.5 - to-fast-properties: 2.0.0 - - '@babel/types@7.23.0': - dependencies: - '@babel/helper-string-parser': 7.22.5 - '@babel/helper-validator-identifier': 7.22.20 - to-fast-properties: 2.0.0 + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 '@base2/pretty-print-object@1.0.1': {} - '@bcoe/v8-coverage@0.2.3': {} - - '@cbor-extract/cbor-extract-darwin-arm64@2.2.0': - optional: true - - '@cbor-extract/cbor-extract-darwin-x64@2.2.0': - optional: true - - '@cbor-extract/cbor-extract-linux-arm64@2.2.0': - optional: true - - '@cbor-extract/cbor-extract-linux-arm@2.2.0': - optional: true - - '@cbor-extract/cbor-extract-linux-x64@2.2.0': - optional: true - - '@cbor-extract/cbor-extract-win32-x64@2.2.0': - optional: true - '@colors/colors@1.5.0': optional: true '@cypress/request@2.88.12': dependencies: aws-sign2: 0.7.0 - aws4: 1.12.0 + aws4: 1.13.2 caseless: 0.12.0 combined-stream: 1.0.8 extend: 3.0.2 @@ -9588,9 +10342,10 @@ snapshots: performance-now: 2.1.0 qs: 6.10.4 safe-buffer: 5.2.1 - tough-cookie: 4.1.3 + tough-cookie: 4.1.4 tunnel-agent: 0.6.0 uuid: 8.3.2 + optional: true '@cypress/xvfb@1.2.4(supports-color@8.1.1)': dependencies: @@ -9598,359 +10353,468 @@ snapshots: lodash.once: 4.1.1 transitivePeerDependencies: - supports-color + optional: true - '@dimaka/interface@0.0.3-alpha.0(@babel/core@7.22.11)(@popperjs/core@2.11.8)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@dimaka/interface@0.0.3-alpha.0(@babel/core@7.26.9)(@popperjs/core@2.11.8)(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@emotion/css': 11.5.0(@babel/core@7.22.11) + '@emotion/css': 11.5.0(@babel/core@7.26.9) '@juggle/resize-observer': 3.3.1 animejs: 3.2.1 clsx: 1.1.1 - react: 18.2.0 - react-popper: 2.3.0(@popperjs/core@2.11.8)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react-portal: 4.2.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react-use: 17.3.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react-use-measure: 2.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - valtio: 1.11.2(@types/react@18.2.20)(react@18.2.0) - zustand: 3.6.5(react@18.2.0) + react: 18.3.1 + react-popper: 2.3.0(@popperjs/core@2.11.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-portal: 4.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-use: 17.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-use-measure: 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + valtio: 1.11.2(@types/react@18.3.18)(react@18.3.1) + zustand: 3.6.5(react@18.3.1) transitivePeerDependencies: - '@babel/core' - '@popperjs/core' - '@types/react' - react-dom + - supports-color '@discoveryjs/json-ext@0.5.7': {} - '@emotion/babel-plugin@11.11.0': + '@emnapi/runtime@1.3.1': dependencies: - '@babel/helper-module-imports': 7.22.5 - '@babel/runtime': 7.22.11 - '@emotion/hash': 0.9.1 - '@emotion/memoize': 0.8.1 - '@emotion/serialize': 1.1.2 + tslib: 2.8.1 + optional: true + + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.25.9 + '@babel/runtime': 7.26.9 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 babel-plugin-macros: 3.1.0 convert-source-map: 1.9.0 escape-string-regexp: 4.0.0 find-root: 1.1.0 source-map: 0.5.7 stylis: 4.2.0 + transitivePeerDependencies: + - supports-color - '@emotion/cache@11.11.0': + '@emotion/cache@11.14.0': dependencies: - '@emotion/memoize': 0.8.1 - '@emotion/sheet': 1.2.2 - '@emotion/utils': 1.2.1 - '@emotion/weak-memoize': 0.3.1 + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 stylis: 4.2.0 - '@emotion/css@11.5.0(@babel/core@7.22.11)': + '@emotion/css@11.5.0(@babel/core@7.26.9)': dependencies: - '@emotion/babel-plugin': 11.11.0 - '@emotion/cache': 11.11.0 - '@emotion/serialize': 1.1.2 - '@emotion/sheet': 1.2.2 - '@emotion/utils': 1.2.1 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 optionalDependencies: - '@babel/core': 7.22.11 + '@babel/core': 7.26.9 + transitivePeerDependencies: + - supports-color - '@emotion/hash@0.9.1': {} + '@emotion/hash@0.9.2': {} - '@emotion/memoize@0.8.1': {} + '@emotion/memoize@0.9.0': {} - '@emotion/serialize@1.1.2': + '@emotion/react@11.14.0(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@emotion/hash': 0.9.1 - '@emotion/memoize': 0.8.1 - '@emotion/unitless': 0.8.1 - '@emotion/utils': 1.2.1 - csstype: 3.1.2 + '@babel/runtime': 7.26.9 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + transitivePeerDependencies: + - supports-color - '@emotion/sheet@1.2.2': {} - - '@emotion/unitless@0.8.1': {} - - '@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0)': + '@emotion/serialize@1.3.3': dependencies: - react: 18.2.0 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.1.3 - '@emotion/utils@1.2.1': {} + '@emotion/sheet@1.4.0': {} - '@emotion/weak-memoize@0.3.1': {} + '@emotion/unitless@0.10.0': {} - '@esbuild/aix-ppc64@0.19.11': + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + + '@esbuild/aix-ppc64@0.19.12': + optional: true + + '@esbuild/aix-ppc64@0.25.0': optional: true '@esbuild/android-arm64@0.18.20': optional: true - '@esbuild/android-arm64@0.19.11': + '@esbuild/android-arm64@0.19.12': optional: true - '@esbuild/android-arm64@0.19.3': + '@esbuild/android-arm64@0.25.0': optional: true '@esbuild/android-arm@0.18.20': optional: true - '@esbuild/android-arm@0.19.11': + '@esbuild/android-arm@0.19.12': optional: true - '@esbuild/android-arm@0.19.3': + '@esbuild/android-arm@0.25.0': optional: true '@esbuild/android-x64@0.18.20': optional: true - '@esbuild/android-x64@0.19.11': + '@esbuild/android-x64@0.19.12': optional: true - '@esbuild/android-x64@0.19.3': + '@esbuild/android-x64@0.25.0': optional: true '@esbuild/darwin-arm64@0.18.20': optional: true - '@esbuild/darwin-arm64@0.19.11': + '@esbuild/darwin-arm64@0.19.12': optional: true - '@esbuild/darwin-arm64@0.19.3': + '@esbuild/darwin-arm64@0.25.0': optional: true '@esbuild/darwin-x64@0.18.20': optional: true - '@esbuild/darwin-x64@0.19.11': + '@esbuild/darwin-x64@0.19.12': optional: true - '@esbuild/darwin-x64@0.19.3': + '@esbuild/darwin-x64@0.25.0': optional: true '@esbuild/freebsd-arm64@0.18.20': optional: true - '@esbuild/freebsd-arm64@0.19.11': + '@esbuild/freebsd-arm64@0.19.12': optional: true - '@esbuild/freebsd-arm64@0.19.3': + '@esbuild/freebsd-arm64@0.25.0': optional: true '@esbuild/freebsd-x64@0.18.20': optional: true - '@esbuild/freebsd-x64@0.19.11': + '@esbuild/freebsd-x64@0.19.12': optional: true - '@esbuild/freebsd-x64@0.19.3': + '@esbuild/freebsd-x64@0.25.0': optional: true '@esbuild/linux-arm64@0.18.20': optional: true - '@esbuild/linux-arm64@0.19.11': + '@esbuild/linux-arm64@0.19.12': optional: true - '@esbuild/linux-arm64@0.19.3': + '@esbuild/linux-arm64@0.25.0': optional: true '@esbuild/linux-arm@0.18.20': optional: true - '@esbuild/linux-arm@0.19.11': + '@esbuild/linux-arm@0.19.12': optional: true - '@esbuild/linux-arm@0.19.3': + '@esbuild/linux-arm@0.25.0': optional: true '@esbuild/linux-ia32@0.18.20': optional: true - '@esbuild/linux-ia32@0.19.11': + '@esbuild/linux-ia32@0.19.12': optional: true - '@esbuild/linux-ia32@0.19.3': + '@esbuild/linux-ia32@0.25.0': optional: true '@esbuild/linux-loong64@0.18.20': optional: true - '@esbuild/linux-loong64@0.19.11': + '@esbuild/linux-loong64@0.19.12': optional: true - '@esbuild/linux-loong64@0.19.3': + '@esbuild/linux-loong64@0.25.0': optional: true '@esbuild/linux-mips64el@0.18.20': optional: true - '@esbuild/linux-mips64el@0.19.11': + '@esbuild/linux-mips64el@0.19.12': optional: true - '@esbuild/linux-mips64el@0.19.3': + '@esbuild/linux-mips64el@0.25.0': optional: true '@esbuild/linux-ppc64@0.18.20': optional: true - '@esbuild/linux-ppc64@0.19.11': + '@esbuild/linux-ppc64@0.19.12': optional: true - '@esbuild/linux-ppc64@0.19.3': + '@esbuild/linux-ppc64@0.25.0': optional: true '@esbuild/linux-riscv64@0.18.20': optional: true - '@esbuild/linux-riscv64@0.19.11': + '@esbuild/linux-riscv64@0.19.12': optional: true - '@esbuild/linux-riscv64@0.19.3': + '@esbuild/linux-riscv64@0.25.0': optional: true '@esbuild/linux-s390x@0.18.20': optional: true - '@esbuild/linux-s390x@0.19.11': + '@esbuild/linux-s390x@0.19.12': optional: true - '@esbuild/linux-s390x@0.19.3': + '@esbuild/linux-s390x@0.25.0': optional: true '@esbuild/linux-x64@0.18.20': optional: true - '@esbuild/linux-x64@0.19.11': + '@esbuild/linux-x64@0.19.12': optional: true - '@esbuild/linux-x64@0.19.3': + '@esbuild/linux-x64@0.25.0': + optional: true + + '@esbuild/netbsd-arm64@0.25.0': optional: true '@esbuild/netbsd-x64@0.18.20': optional: true - '@esbuild/netbsd-x64@0.19.11': + '@esbuild/netbsd-x64@0.19.12': optional: true - '@esbuild/netbsd-x64@0.19.3': + '@esbuild/netbsd-x64@0.25.0': + optional: true + + '@esbuild/openbsd-arm64@0.25.0': optional: true '@esbuild/openbsd-x64@0.18.20': optional: true - '@esbuild/openbsd-x64@0.19.11': + '@esbuild/openbsd-x64@0.19.12': optional: true - '@esbuild/openbsd-x64@0.19.3': + '@esbuild/openbsd-x64@0.25.0': optional: true '@esbuild/sunos-x64@0.18.20': optional: true - '@esbuild/sunos-x64@0.19.11': + '@esbuild/sunos-x64@0.19.12': optional: true - '@esbuild/sunos-x64@0.19.3': + '@esbuild/sunos-x64@0.25.0': optional: true '@esbuild/win32-arm64@0.18.20': optional: true - '@esbuild/win32-arm64@0.19.11': + '@esbuild/win32-arm64@0.19.12': optional: true - '@esbuild/win32-arm64@0.19.3': + '@esbuild/win32-arm64@0.25.0': optional: true '@esbuild/win32-ia32@0.18.20': optional: true - '@esbuild/win32-ia32@0.19.11': + '@esbuild/win32-ia32@0.19.12': optional: true - '@esbuild/win32-ia32@0.19.3': + '@esbuild/win32-ia32@0.25.0': optional: true '@esbuild/win32-x64@0.18.20': optional: true - '@esbuild/win32-x64@0.19.11': + '@esbuild/win32-x64@0.19.12': optional: true - '@esbuild/win32-x64@0.19.3': + '@esbuild/win32-x64@0.25.0': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@8.50.0)': + '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)': dependencies: - eslint: 8.50.0 + eslint: 8.57.1 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.8.0': {} + '@eslint-community/regexpp@4.12.1': {} - '@eslint/eslintrc@2.1.2': + '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) espree: 9.6.1 - globals: 13.21.0 - ignore: 5.2.4 - import-fresh: 3.3.0 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.1 js-yaml: 4.1.0 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - '@eslint/js@8.50.0': {} + '@eslint/js@8.57.1': {} '@fal-works/esbuild-plugin-global-externals@2.1.2': {} - '@fastify/busboy@2.0.0': {} + '@fastify/busboy@2.1.1': {} - '@floating-ui/core@1.5.0': + '@floating-ui/core@1.6.9': dependencies: - '@floating-ui/utils': 0.1.6 + '@floating-ui/utils': 0.2.9 - '@floating-ui/dom@1.5.3': + '@floating-ui/dom@1.6.13': dependencies: - '@floating-ui/core': 1.5.0 - '@floating-ui/utils': 0.1.6 + '@floating-ui/core': 1.6.9 + '@floating-ui/utils': 0.2.9 - '@floating-ui/react-dom@2.0.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@floating-ui/react-dom@2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@floating-ui/dom': 1.5.3 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@floating-ui/dom': 1.6.13 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) - '@floating-ui/react-dom@2.0.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@floating-ui/react@0.26.28(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': 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) - '@floating-ui/utils': 0.1.6 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@floating-ui/utils': 0.2.9 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) tabbable: 6.2.0 - '@floating-ui/utils@0.1.6': {} + '@floating-ui/utils@0.2.9': {} '@gar/promisify@1.1.3': optional: true - '@humanwhocodes/config-array@0.11.11': + '@hapi/hoek@9.3.0': {} + + '@hapi/topo@5.1.0': dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4(supports-color@8.1.1) + '@hapi/hoek': 9.3.0 + + '@humanwhocodes/config-array@0.13.0': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.0(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@1.2.1': {} + '@humanwhocodes/object-schema@2.0.3': {} - '@iconify/types@2.0.0': {} + '@img/sharp-darwin-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.0.4 + optional: true + + '@img/sharp-darwin-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.0.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.0.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.0.5': + optional: true + + '@img/sharp-libvips-linux-s390x@1.0.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.0.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + optional: true + + '@img/sharp-linux-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.0.4 + optional: true + + '@img/sharp-linux-arm@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.0.5 + optional: true + + '@img/sharp-linux-s390x@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.0.4 + optional: true + + '@img/sharp-linux-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.0.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + optional: true + + '@img/sharp-wasm32@0.33.5': + dependencies: + '@emnapi/runtime': 1.3.1 + optional: true + + '@img/sharp-win32-ia32@0.33.5': + optional: true + + '@img/sharp-win32-x64@0.33.5': + optional: true '@isaacs/cliui@8.0.2': dependencies: @@ -9977,9 +10841,9 @@ snapshots: '@jest/transform@29.7.0': dependencies: - '@babel/core': 7.22.11 + '@babel/core': 7.26.9 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.19 + '@jridgewell/trace-mapping': 0.3.25 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 2.0.0 @@ -9988,7 +10852,7 @@ snapshots: jest-haste-map: 29.7.0 jest-regex-util: 29.6.3 jest-util: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 pirates: 4.0.6 slash: 3.0.0 write-file-atomic: 4.0.2 @@ -9998,375 +10862,441 @@ snapshots: '@jest/types@29.6.3': dependencies: '@jest/schemas': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.4 - '@types/istanbul-reports': 3.0.2 - '@types/node': 20.12.8 - '@types/yargs': 17.0.28 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.13.9 + '@types/yargs': 17.0.33 chalk: 4.1.2 - '@jimp/bmp@0.10.3(@jimp/custom@0.10.3)': + '@jimp/bmp@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 bmp-js: 0.1.0 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/core@0.10.3': + '@jimp/core@0.10.3(debug@4.4.0)': dependencies: - '@babel/runtime': 7.22.11 + '@babel/runtime': 7.26.9 '@jimp/utils': 0.10.3 any-base: 1.1.0 - buffer: 5.7.1 - core-js: 3.32.1 + buffer: 6.0.3 + core-js: 3.41.0 exif-parser: 0.1.12 file-type: 9.0.0 - load-bmfont: 1.4.1 + load-bmfont: 1.4.2(debug@4.4.0) mkdirp: 0.5.6 phin: 2.9.3 pixelmatch: 4.0.2 tinycolor2: 1.6.0 + transitivePeerDependencies: + - debug + optional: true - '@jimp/custom@0.10.3': + '@jimp/custom@0.10.3(debug@4.4.0)': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/core': 0.10.3 - core-js: 3.32.1 + '@babel/runtime': 7.26.9 + '@jimp/core': 0.10.3(debug@4.4.0) + core-js: 3.41.0 + transitivePeerDependencies: + - debug + optional: true - '@jimp/gif@0.10.3(@jimp/custom@0.10.3)': + '@jimp/gif@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 omggif: 1.0.10 + optional: true - '@jimp/jpeg@0.10.3(@jimp/custom@0.10.3)': + '@jimp/jpeg@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 jpeg-js: 0.3.7 + optional: true - '@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-blur@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-blur@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-circle@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-circle@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-color@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-color@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 tinycolor2: 1.6.0 + optional: true - '@jimp/plugin-contain@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)))': + '@jimp/plugin-contain@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 - '@jimp/plugin-blit': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-scale': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)) + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) + '@jimp/plugin-blit': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-scale': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-cover@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)))': + '@jimp/plugin-cover@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 - '@jimp/plugin-crop': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-scale': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)) + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) + '@jimp/plugin-crop': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-scale': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-displace@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-displace@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-dither@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-dither@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-fisheye@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-fisheye@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-flip@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-rotate@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)))': + '@jimp/plugin-flip@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-rotate@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 - '@jimp/plugin-rotate': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)) + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) + '@jimp/plugin-rotate': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-gaussian@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-gaussian@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-invert@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-invert@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-mask@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-mask@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-normalize@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-normalize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-print@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))': + '@jimp/plugin-print@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(debug@4.4.0)': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 - '@jimp/plugin-blit': 0.10.3(@jimp/custom@0.10.3) + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) + '@jimp/plugin-blit': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) '@jimp/utils': 0.10.3 - core-js: 3.32.1 - load-bmfont: 1.4.1 + core-js: 3.41.0 + load-bmfont: 1.4.2(debug@4.4.0) + transitivePeerDependencies: + - debug + optional: true - '@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-rotate@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))': + '@jimp/plugin-rotate@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 - '@jimp/plugin-blit': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-crop': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3) + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) + '@jimp/plugin-blit': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-crop': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))': + '@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 - '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3) + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) + '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-shadow@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blur@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))': + '@jimp/plugin-shadow@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-blur@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 - '@jimp/plugin-blur': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3) + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) + '@jimp/plugin-blur': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugin-threshold@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-color@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))': + '@jimp/plugin-threshold@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-color@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 - '@jimp/plugin-color': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3) + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) + '@jimp/plugin-color': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 + optional: true - '@jimp/plugins@0.10.3(@jimp/custom@0.10.3)': + '@jimp/plugins@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(debug@4.4.0)': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 - '@jimp/plugin-blit': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-blur': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-circle': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-color': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-contain': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))) - '@jimp/plugin-cover': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))) - '@jimp/plugin-crop': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-displace': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-dither': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-fisheye': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-flip': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-rotate@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))) - '@jimp/plugin-gaussian': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-invert': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-mask': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-normalize': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-print': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3)) - '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3) - '@jimp/plugin-rotate': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)) - '@jimp/plugin-scale': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)) - '@jimp/plugin-shadow': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blur@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)) - '@jimp/plugin-threshold': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-color@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)) - core-js: 3.32.1 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) + '@jimp/plugin-blit': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-blur': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-circle': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-color': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-contain': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))) + '@jimp/plugin-cover': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))) + '@jimp/plugin-crop': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-displace': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-dither': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-fisheye': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-flip': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-rotate@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))) + '@jimp/plugin-gaussian': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-invert': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-mask': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-normalize': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-print': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(debug@4.4.0) + '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/plugin-rotate': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))) + '@jimp/plugin-scale': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))) + '@jimp/plugin-shadow': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-blur@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))) + '@jimp/plugin-threshold': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(@jimp/plugin-color@0.10.3(@jimp/custom@0.10.3(debug@4.4.0)))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))) + core-js: 3.41.0 timm: 1.7.1 + transitivePeerDependencies: + - debug + optional: true - '@jimp/png@0.10.3(@jimp/custom@0.10.3)': + '@jimp/png@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) '@jimp/utils': 0.10.3 - core-js: 3.32.1 + core-js: 3.41.0 pngjs: 3.4.0 + optional: true - '@jimp/tiff@0.10.3(@jimp/custom@0.10.3)': + '@jimp/tiff@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 - core-js: 3.32.1 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) + core-js: 3.41.0 utif: 2.0.1 + optional: true - '@jimp/types@0.10.3(@jimp/custom@0.10.3)': + '@jimp/types@0.10.3(@jimp/custom@0.10.3(debug@4.4.0))': dependencies: - '@babel/runtime': 7.22.11 - '@jimp/bmp': 0.10.3(@jimp/custom@0.10.3) - '@jimp/custom': 0.10.3 - '@jimp/gif': 0.10.3(@jimp/custom@0.10.3) - '@jimp/jpeg': 0.10.3(@jimp/custom@0.10.3) - '@jimp/png': 0.10.3(@jimp/custom@0.10.3) - '@jimp/tiff': 0.10.3(@jimp/custom@0.10.3) - core-js: 3.32.1 + '@babel/runtime': 7.26.9 + '@jimp/bmp': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/custom': 0.10.3(debug@4.4.0) + '@jimp/gif': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/jpeg': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/png': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + '@jimp/tiff': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + core-js: 3.41.0 timm: 1.7.1 + optional: true '@jimp/utils@0.10.3': dependencies: - '@babel/runtime': 7.22.11 - core-js: 3.32.1 + '@babel/runtime': 7.26.9 + core-js: 3.41.0 regenerator-runtime: 0.13.11 + optional: true - '@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))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.5.4)(vite@6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))': dependencies: glob: 7.2.3 glob-promise: 4.2.2(glob@7.2.3) magic-string: 0.27.0 - react-docgen-typescript: 2.2.2(typescript@5.5.0-beta) - vite: 4.5.3(@types/node@20.8.0)(terser@5.19.2) + react-docgen-typescript: 2.2.2(typescript@5.5.4) + vite: 6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0) optionalDependencies: - typescript: 5.5.0-beta + typescript: 5.5.4 - '@jridgewell/gen-mapping@0.3.3': + '@jridgewell/gen-mapping@0.3.8': dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.19 + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 - '@jridgewell/resolve-uri@3.1.1': {} + '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/set-array@1.1.2': {} + '@jridgewell/set-array@1.2.1': {} - '@jridgewell/source-map@0.3.5': + '@jridgewell/source-map@0.3.6': dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.19 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 - '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/trace-mapping@0.3.19': + '@jridgewell/trace-mapping@0.3.25': dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 - '@jspm/core@2.0.1': {} + '@jsonjoy.com/base64@1.1.2(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/json-pack@1.2.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/base64': 1.1.2(tslib@2.8.1) + '@jsonjoy.com/util': 1.5.0(tslib@2.8.1) + hyperdyperid: 1.2.0 + thingies: 1.21.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/util@1.5.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jspm/core@2.1.0': {} '@juggle/resize-observer@3.3.1': {} + '@juggle/resize-observer@3.4.0': {} + '@mapbox/node-pre-gyp@1.0.11(encoding@0.1.13)': dependencies: - detect-libc: 2.0.2 + detect-libc: 2.0.3 https-proxy-agent: 5.0.1 make-dir: 3.1.0 node-fetch: 2.7.0(encoding@0.1.13) nopt: 5.0.0 npmlog: 5.0.1 rimraf: 3.0.2 - semver: 7.5.4 - tar: 6.2.0 + semver: 7.7.1 + tar: 6.2.1 transitivePeerDependencies: - encoding - supports-color + optional: true - '@mdx-js/react@2.3.0(react@18.2.0)': + '@mdx-js/react@2.3.0(react@18.3.1)': dependencies: - '@types/mdx': 2.0.8 - '@types/react': 18.2.20 - react: 18.2.0 + '@types/mdx': 2.0.13 + '@types/react': 18.3.18 + react: 18.3.1 + + '@module-federation/error-codes@0.11.2': {} + + '@module-federation/runtime-core@0.11.2': + dependencies: + '@module-federation/error-codes': 0.11.2 + '@module-federation/sdk': 0.11.2 + + '@module-federation/runtime-tools@0.11.2': + dependencies: + '@module-federation/runtime': 0.11.2 + '@module-federation/webpack-bundler-runtime': 0.11.2 + + '@module-federation/runtime@0.11.2': + dependencies: + '@module-federation/error-codes': 0.11.2 + '@module-federation/runtime-core': 0.11.2 + '@module-federation/sdk': 0.11.2 + + '@module-federation/sdk@0.11.2': {} + + '@module-federation/webpack-bundler-runtime@0.11.2': + dependencies: + '@module-federation/runtime': 0.11.2 + '@module-federation/sdk': 0.11.2 + + '@monaco-editor/loader@1.5.0': + dependencies: + state-local: 1.0.7 + + '@monaco-editor/react@4.7.0(monaco-editor@0.52.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@monaco-editor/loader': 1.5.0 + monaco-editor: 0.52.2 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) '@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 - pump: 3.0.0 - tar-fs: 2.1.1 + pump: 3.0.2 + tar-fs: 2.1.2 '@nodelib/fs.scandir@2.1.5': dependencies: @@ -10378,12 +11308,12 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 + fastq: 1.19.1 '@npmcli/fs@2.1.2': dependencies: '@gar/promisify': 1.1.3 - semver: 7.6.0 + semver: 7.7.1 optional: true '@npmcli/move-file@2.0.1': @@ -10392,25 +11322,38 @@ snapshots: rimraf: 3.0.2 optional: true - '@nxg-org/mineflayer-auto-jump@0.7.7': + '@nxg-org/mineflayer-auto-jump@0.7.18': dependencies: - '@nxg-org/mineflayer-physics-util': 1.5.8 + '@nxg-org/mineflayer-physics-util': 1.8.10 strict-event-emitter-types: 2.0.0 - '@nxg-org/mineflayer-physics-util@1.5.8': + '@nxg-org/mineflayer-physics-util@1.8.10': dependencies: - '@nxg-org/mineflayer-util-plugin': 1.8.3 + '@nxg-org/mineflayer-util-plugin': 1.8.4 - '@nxg-org/mineflayer-tracker@1.2.1': + '@nxg-org/mineflayer-tracker@1.3.0(encoding@0.1.13)': dependencies: - '@nxg-org/mineflayer-trajectories': 1.1.1 - '@nxg-org/mineflayer-util-plugin': 1.8.3 + '@nxg-org/mineflayer-physics-util': 1.8.10 + '@nxg-org/mineflayer-trajectories': 1.2.0(encoding@0.1.13) + '@nxg-org/mineflayer-util-plugin': 1.8.4 + transitivePeerDependencies: + - encoding + - supports-color - '@nxg-org/mineflayer-trajectories@1.1.1': + '@nxg-org/mineflayer-trajectories@1.2.0(encoding@0.1.13)': dependencies: - '@nxg-org/mineflayer-util-plugin': 1.8.3 + '@nxg-org/mineflayer-util-plugin': 1.8.4 + minecraft-data: 3.98.0 + mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13) + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-item: 1.17.0 + prismarine-physics: https://codeload.github.com/zardoy/prismarine-physics/tar.gz/353e25b800149393f40539ec381218be44cbb03b + vec3: 0.1.10 + transitivePeerDependencies: + - encoding + - supports-color - '@nxg-org/mineflayer-util-plugin@1.8.3': {} + '@nxg-org/mineflayer-util-plugin@1.8.4': {} '@pkgjs/parseargs@0.11.0': optional: true @@ -10419,451 +11362,674 @@ snapshots: '@radix-ui/number@1.0.1': dependencies: - '@babel/runtime': 7.22.11 + '@babel/runtime': 7.26.9 '@radix-ui/primitive@1.0.1': dependencies: - '@babel/runtime': 7.22.11 + '@babel/runtime': 7.26.9 - '@radix-ui/react-arrow@1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/primitive@1.1.1': {} + + '@radix-ui/react-arrow@1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@babel/runtime': 7.26.9 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-collection@1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.20)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@babel/runtime': 7.26.9 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-collection@1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - react: 18.2.0 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.2(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-context@1.0.1(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - react: 18.2.0 + '@babel/runtime': 7.26.9 + react: 18.3.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@radix-ui/react-direction@1.0.1(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-compose-refs@1.1.1(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - react: 18.2.0 + react: 18.3.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-context@1.0.1(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 + '@babel/runtime': 7.26.9 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + + '@radix-ui/react-context@1.1.1(@types/react@18.3.18)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + + '@radix-ui/react-direction@1.0.1(@types/react@18.3.18)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.9 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + + '@radix-ui/react-direction@1.1.0(@types/react@18.3.18)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + + '@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.9 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.20)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-focus-guards@1.0.1(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - react: 18.2.0 + '@babel/runtime': 7.26.9 + react: 18.3.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@radix-ui/react-focus-scope@1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-focus-scope@1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.20)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@babel/runtime': 7.26.9 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-id@1.0.1(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-id@1.0.1(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.20)(react@18.2.0) - react: 18.2.0 + '@babel/runtime': 7.26.9 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@radix-ui/react-popper@1.1.2(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-id@1.1.0(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@floating-ui/react-dom': 2.0.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.20)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + + '@radix-ui/react-popper@1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.9 + '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-use-rect': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.3.18)(react@18.3.1) '@radix-ui/rect': 1.0.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-portal@1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-portal@1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@babel/runtime': 7.26.9 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.20)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@babel/runtime': 7.26.9 + '@radix-ui/react-slot': 1.0.2(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-primitive@2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-id': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.20)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@radix-ui/react-slot': 1.1.2(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-select@1.2.2(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-roving-focus@1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) + + '@radix-ui/react-select@1.2.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.9 '@radix-ui/number': 1.0.1 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-dismissable-layer': 1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-focus-scope': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-id': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-popper': 1.1.2(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-portal': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - aria-hidden: 1.2.3 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-remove-scroll: 2.5.5(@types/react@18.2.20)(react@18.2.0) + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-direction': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.0.4(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-popper': 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-use-previous': 1.0.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + aria-hidden: 1.2.4 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.5.5(@types/react@18.3.18)(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-separator@1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-separator@1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-slot@1.0.2(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-slot@1.0.2(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.20)(react@18.2.0) - react: 18.2.0 + '@babel/runtime': 7.26.9 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-slot@1.1.2(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-context': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-toggle': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.20)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 - '@radix-ui/react-toggle@1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-toggle-group@1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.20)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-context': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-roving-focus': 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-toggle': 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-toolbar@1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-toggle@1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-context': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.20)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-separator': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-toggle-group': 1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-toolbar@1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - react: 18.2.0 + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-context': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-roving-focus': 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-separator': 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-toggle-group': 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) - '@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.20)(react@18.2.0) - react: 18.2.0 + '@babel/runtime': 7.26.9 + react: 18.3.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.20)(react@18.2.0) - react: 18.2.0 + react: 18.3.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - react: 18.2.0 + '@babel/runtime': 7.26.9 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@radix-ui/react-use-previous@1.0.1(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - react: 18.2.0 + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@radix-ui/react-use-rect@1.0.1(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 + '@babel/runtime': 7.26.9 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + + '@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.3.18)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.9 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + + '@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.18)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + + '@radix-ui/react-use-previous@1.0.1(@types/react@18.3.18)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.9 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + + '@radix-ui/react-use-rect@1.0.1(@types/react@18.3.18)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.9 '@radix-ui/rect': 1.0.1 - react: 18.2.0 + react: 18.3.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@radix-ui/react-use-size@1.0.1(@types/react@18.2.20)(react@18.2.0)': + '@radix-ui/react-use-size@1.0.1(@types/react@18.3.18)(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.20)(react@18.2.0) - react: 18.2.0 + '@babel/runtime': 7.26.9 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.22.11 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@babel/runtime': 7.26.9 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - '@types/react-dom': 18.2.7 + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) '@radix-ui/rect@1.0.1': dependencies: - '@babel/runtime': 7.22.11 + '@babel/runtime': 7.26.9 - '@react-oauth/google@0.12.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@react-oauth/google@0.12.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) - '@rollup/plugin-babel@5.3.1(@babel/core@7.22.11)(@types/babel__core@7.20.2)(rollup@2.79.1)': + '@rollup/plugin-babel@5.3.1(@babel/core@7.26.9)(@types/babel__core@7.20.5)(rollup@2.79.2)': dependencies: - '@babel/core': 7.22.11 - '@babel/helper-module-imports': 7.22.5 - '@rollup/pluginutils': 3.1.0(rollup@2.79.1) - rollup: 2.79.1 + '@babel/core': 7.26.9 + '@babel/helper-module-imports': 7.25.9 + '@rollup/pluginutils': 3.1.0(rollup@2.79.2) + rollup: 2.79.2 optionalDependencies: - '@types/babel__core': 7.20.2 + '@types/babel__core': 7.20.5 + transitivePeerDependencies: + - supports-color - '@rollup/plugin-node-resolve@11.2.1(rollup@2.79.1)': + '@rollup/plugin-node-resolve@15.3.1(rollup@2.79.2)': dependencies: - '@rollup/pluginutils': 3.1.0(rollup@2.79.1) - '@types/resolve': 1.17.1 - builtin-modules: 3.3.0 + '@rollup/pluginutils': 5.1.4(rollup@2.79.2) + '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 - resolve: 1.22.4 - rollup: 2.79.1 + resolve: 1.22.10 + optionalDependencies: + rollup: 2.79.2 - '@rollup/plugin-replace@2.4.2(rollup@2.79.1)': + '@rollup/plugin-replace@2.4.2(rollup@2.79.2)': dependencies: - '@rollup/pluginutils': 3.1.0(rollup@2.79.1) + '@rollup/pluginutils': 3.1.0(rollup@2.79.2) magic-string: 0.25.9 - rollup: 2.79.1 + rollup: 2.79.2 - '@rollup/pluginutils@3.1.0(rollup@2.79.1)': + '@rollup/plugin-terser@0.4.4(rollup@2.79.2)': + dependencies: + serialize-javascript: 6.0.2 + smob: 1.5.0 + terser: 5.39.0 + optionalDependencies: + rollup: 2.79.2 + + '@rollup/pluginutils@3.1.0(rollup@2.79.2)': dependencies: '@types/estree': 0.0.39 estree-walker: 1.0.1 picomatch: 2.3.1 - rollup: 2.79.1 + rollup: 2.79.2 - '@rollup/pluginutils@5.0.5(rollup@2.79.1)': + '@rollup/pluginutils@5.1.4(rollup@2.79.2)': dependencies: - '@types/estree': 1.0.2 + '@types/estree': 1.0.6 estree-walker: 2.0.2 - picomatch: 2.3.1 + picomatch: 4.0.2 optionalDependencies: - rollup: 2.79.1 + rollup: 2.79.2 - '@rushstack/eslint-patch@1.4.0': {} + '@rollup/rollup-android-arm-eabi@4.34.9': + optional: true + + '@rollup/rollup-android-arm64@4.34.9': + optional: true + + '@rollup/rollup-darwin-arm64@4.34.9': + optional: true + + '@rollup/rollup-darwin-x64@4.34.9': + optional: true + + '@rollup/rollup-freebsd-arm64@4.34.9': + optional: true + + '@rollup/rollup-freebsd-x64@4.34.9': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.34.9': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.34.9': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.34.9': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.34.9': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.34.9': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.34.9': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.34.9': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.34.9': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.34.9': + optional: true + + '@rollup/rollup-linux-x64-musl@4.34.9': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.34.9': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.34.9': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.34.9': + optional: true + + '@rsbuild/core@1.3.5': + dependencies: + '@rspack/core': 1.3.3(@swc/helpers@0.5.15) + '@rspack/lite-tapable': 1.0.1 + '@swc/helpers': 0.5.15 + core-js: 3.41.0 + jiti: 2.4.2 + transitivePeerDependencies: + - '@rspack/tracing' + + '@rsbuild/plugin-node-polyfill@1.3.0(@rsbuild/core@1.3.5)': + dependencies: + assert: 2.1.0 + browserify-zlib: 0.2.0 + buffer: 6.0.3 + console-browserify: 1.2.0 + constants-browserify: 1.0.0 + crypto-browserify: 3.12.1 + domain-browser: 5.7.0 + events: 3.3.0 + https-browserify: 1.0.0 + os-browserify: 0.3.0 + path-browserify: 1.0.1 + process: 0.11.10 + punycode: 2.3.1 + querystring-es3: 0.2.1 + readable-stream: 4.7.0 + stream-browserify: 3.0.0 + stream-http: 3.2.0 + string_decoder: 1.3.0 + timers-browserify: 2.0.12 + tty-browserify: 0.0.1 + url: 0.11.4 + util: 0.12.5 + vm-browserify: 1.1.2 + optionalDependencies: + '@rsbuild/core': 1.3.5 + + '@rsbuild/plugin-react@1.2.0(@rsbuild/core@1.3.5)': + dependencies: + '@rsbuild/core': 1.3.5 + '@rspack/plugin-react-refresh': 1.2.0(react-refresh@0.17.0) + react-refresh: 0.17.0 + transitivePeerDependencies: + - webpack-hot-middleware + + '@rsbuild/plugin-type-check@1.2.1(@rsbuild/core@1.3.5)(@rspack/core@1.3.3(@swc/helpers@0.5.15))(typescript@5.5.4)': + dependencies: + deepmerge: 4.3.1 + json5: 2.2.3 + reduce-configs: 1.1.0 + ts-checker-rspack-plugin: 1.1.1(@rspack/core@1.3.3(@swc/helpers@0.5.15))(typescript@5.5.4) + optionalDependencies: + '@rsbuild/core': 1.3.5 + transitivePeerDependencies: + - '@rspack/core' + - typescript + + '@rsbuild/plugin-typed-css-modules@1.0.2(@rsbuild/core@1.3.5)': + optionalDependencies: + '@rsbuild/core': 1.3.5 + + '@rspack/binding-darwin-arm64@1.3.3': + optional: true + + '@rspack/binding-darwin-x64@1.3.3': + optional: true + + '@rspack/binding-linux-arm64-gnu@1.3.3': + optional: true + + '@rspack/binding-linux-arm64-musl@1.3.3': + optional: true + + '@rspack/binding-linux-x64-gnu@1.3.3': + optional: true + + '@rspack/binding-linux-x64-musl@1.3.3': + optional: true + + '@rspack/binding-win32-arm64-msvc@1.3.3': + optional: true + + '@rspack/binding-win32-ia32-msvc@1.3.3': + optional: true + + '@rspack/binding-win32-x64-msvc@1.3.3': + optional: true + + '@rspack/binding@1.3.3': + optionalDependencies: + '@rspack/binding-darwin-arm64': 1.3.3 + '@rspack/binding-darwin-x64': 1.3.3 + '@rspack/binding-linux-arm64-gnu': 1.3.3 + '@rspack/binding-linux-arm64-musl': 1.3.3 + '@rspack/binding-linux-x64-gnu': 1.3.3 + '@rspack/binding-linux-x64-musl': 1.3.3 + '@rspack/binding-win32-arm64-msvc': 1.3.3 + '@rspack/binding-win32-ia32-msvc': 1.3.3 + '@rspack/binding-win32-x64-msvc': 1.3.3 + + '@rspack/core@1.3.3(@swc/helpers@0.5.15)': + dependencies: + '@module-federation/runtime-tools': 0.11.2 + '@rspack/binding': 1.3.3 + '@rspack/lite-tapable': 1.0.1 + caniuse-lite: 1.0.30001713 + optionalDependencies: + '@swc/helpers': 0.5.15 + + '@rspack/lite-tapable@1.0.1': {} + + '@rspack/plugin-react-refresh@1.2.0(react-refresh@0.17.0)': + dependencies: + error-stack-parser: 2.1.4 + html-entities: 2.6.0 + react-refresh: 0.17.0 + + '@rushstack/eslint-patch@1.10.5': {} + + '@sideway/address@4.1.5': + dependencies: + '@hapi/hoek': 9.3.0 + + '@sideway/formula@3.0.1': {} + + '@sideway/pinpoint@2.0.0': {} '@sinclair/typebox@0.27.8': {} - '@socket.io/component-emitter@3.1.0': {} + '@socket.io/component-emitter@3.1.2': {} - '@storybook/addon-actions@7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@storybook/addon-actions@7.6.20': dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/core-events': 7.4.6 + '@storybook/core-events': 7.6.20 '@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/theming': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/types': 7.4.6 + '@types/uuid': 9.0.8 dequal: 2.0.3 - lodash: 4.17.21 - polished: 4.2.2 - prop-types: 15.8.1 - react-inspector: 6.0.2(react@18.2.0) - telejson: 7.2.0 - ts-dedent: 2.2.0 + polished: 4.3.1 uuid: 9.0.1 - optionalDependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - '@storybook/addon-backgrounds@7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@storybook/addon-backgrounds@7.6.20': dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/core-events': 7.4.6 '@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/theming': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/types': 7.4.6 memoizerific: 1.11.3 ts-dedent: 2.2.0 - optionalDependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - '@storybook/addon-controls@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/addon-controls@7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@storybook/blocks': 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/client-logger': 7.4.6 - '@storybook/components': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/core-common': 7.4.6(encoding@0.1.13) - '@storybook/core-events': 7.4.6 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/node-logger': 7.4.6 - '@storybook/preview-api': 7.4.6 - '@storybook/theming': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/blocks': 7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) lodash: 4.17.21 ts-dedent: 2.2.0 - optionalDependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) transitivePeerDependencies: - '@types/react' - '@types/react-dom' - encoding + - react + - react-dom - supports-color - '@storybook/addon-docs@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/addon-docs@7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@jest/transform': 29.7.0 - '@mdx-js/react': 2.3.0(react@18.2.0) - '@storybook/blocks': 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/client-logger': 7.4.6 - '@storybook/components': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/csf-plugin': 7.4.6 - '@storybook/csf-tools': 7.4.6 + '@mdx-js/react': 2.3.0(react@18.3.1) + '@storybook/blocks': 7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/client-logger': 7.6.20 + '@storybook/components': 7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/csf-plugin': 7.6.20 + '@storybook/csf-tools': 7.6.20 '@storybook/global': 5.0.0 '@storybook/mdx2-csf': 1.1.0 - '@storybook/node-logger': 7.4.6 - '@storybook/postinstall': 7.4.6 - '@storybook/preview-api': 7.4.6 - '@storybook/react-dom-shim': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/theming': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/types': 7.4.6 - fs-extra: 11.1.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@storybook/node-logger': 7.6.20 + '@storybook/postinstall': 7.6.20 + '@storybook/preview-api': 7.6.20 + '@storybook/react-dom-shim': 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/theming': 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 7.6.20 + fs-extra: 11.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) remark-external-links: 8.0.0 remark-slug: 6.1.0 ts-dedent: 2.2.0 @@ -10873,23 +12039,23 @@ snapshots: - encoding - supports-color - '@storybook/addon-essentials@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/addon-essentials@7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@storybook/addon-actions': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/addon-backgrounds': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/addon-controls': 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/addon-docs': 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/addon-highlight': 7.4.6 - '@storybook/addon-measure': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/addon-outline': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/addon-toolbars': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/addon-viewport': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/core-common': 7.4.6(encoding@0.1.13) - '@storybook/manager-api': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/node-logger': 7.4.6 - '@storybook/preview-api': 7.4.6 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@storybook/addon-actions': 7.6.20 + '@storybook/addon-backgrounds': 7.6.20 + '@storybook/addon-controls': 7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/addon-docs': 7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/addon-highlight': 7.6.20 + '@storybook/addon-measure': 7.6.20 + '@storybook/addon-outline': 7.6.20 + '@storybook/addon-toolbars': 7.6.20 + '@storybook/addon-viewport': 7.6.20 + '@storybook/core-common': 7.6.20(encoding@0.1.13) + '@storybook/manager-api': 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/node-logger': 7.6.20 + '@storybook/preview-api': 7.6.20 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' @@ -10897,119 +12063,59 @@ snapshots: - encoding - supports-color - '@storybook/addon-highlight@7.4.6': + '@storybook/addon-highlight@7.6.20': dependencies: - '@storybook/core-events': 7.4.6 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.4.6 - '@storybook/addon-links@7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@storybook/addon-links@7.6.20(react@18.3.1)': dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/core-events': 7.4.6 - '@storybook/csf': 0.1.1 + '@storybook/csf': 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/router': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/types': 7.4.6 - prop-types: 15.8.1 ts-dedent: 2.2.0 optionalDependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 - '@storybook/addon-measure@7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@storybook/addon-measure@7.6.20': dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/core-events': 7.4.6 '@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 - tiny-invariant: 1.3.1 - optionalDependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' + tiny-invariant: 1.3.3 - '@storybook/addon-outline@7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@storybook/addon-outline@7.6.20': dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/core-events': 7.4.6 '@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 ts-dedent: 2.2.0 - optionalDependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - '@storybook/addon-toolbars@7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': - dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.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/theming': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - optionalDependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' + '@storybook/addon-toolbars@7.6.20': {} - '@storybook/addon-viewport@7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@storybook/addon-viewport@7.6.20': dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/core-events': 7.4.6 - '@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/theming': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) memoizerific: 1.11.3 - prop-types: 15.8.1 - optionalDependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - '@storybook/blocks@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/blocks@7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@storybook/channels': 7.4.6 - '@storybook/client-logger': 7.4.6 - '@storybook/components': 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/core-events': 7.4.6 - '@storybook/csf': 0.1.1 - '@storybook/docs-tools': 7.4.6(encoding@0.1.13) + '@storybook/channels': 7.6.20 + '@storybook/client-logger': 7.6.20 + '@storybook/components': 7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/core-events': 7.6.20 + '@storybook/csf': 0.1.13 + '@storybook/docs-tools': 7.6.20(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/theming': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/types': 7.4.6 - '@types/lodash': 4.14.199 + '@storybook/manager-api': 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/preview-api': 7.6.20 + '@storybook/theming': 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 7.6.20 + '@types/lodash': 4.17.16 color-convert: 2.0.1 dequal: 2.0.3 lodash: 4.17.21 - markdown-to-jsx: 7.3.2(react@18.2.0) + markdown-to-jsx: 7.7.4(react@18.3.1) memoizerific: 1.11.3 - polished: 4.2.2 - react: 18.2.0 - react-colorful: 5.6.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react-dom: 18.2.0(react@18.2.0) + polished: 4.3.1 + react: 18.3.1 + react-colorful: 5.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-dom: 18.3.1(react@18.3.1) telejson: 7.2.0 - tocbot: 4.21.2 + tocbot: 4.35.0 ts-dedent: 2.2.0 util-deprecate: 1.0.2 transitivePeerDependencies: @@ -11018,104 +12124,100 @@ snapshots: - encoding - supports-color - '@storybook/builder-manager@7.4.6(encoding@0.1.13)': + '@storybook/builder-manager@7.6.20(encoding@0.1.13)': dependencies: '@fal-works/esbuild-plugin-global-externals': 2.1.2 - '@storybook/core-common': 7.4.6(encoding@0.1.13) - '@storybook/manager': 7.4.6 - '@storybook/node-logger': 7.4.6 - '@types/ejs': 3.1.3 + '@storybook/core-common': 7.6.20(encoding@0.1.13) + '@storybook/manager': 7.6.20 + '@storybook/node-logger': 7.6.20 + '@types/ejs': 3.1.5 '@types/find-cache-dir': 3.2.1 '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.18.20) browser-assert: 1.2.1 - ejs: 3.1.9 + ejs: 3.1.10 esbuild: 0.18.20 esbuild-plugin-alias: 0.2.1 - express: 4.18.2 + express: 4.21.2 find-cache-dir: 3.3.2 - fs-extra: 11.1.1 + fs-extra: 11.3.0 process: 0.11.10 util: 0.12.5 transitivePeerDependencies: - encoding - supports-color - '@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/builder-vite@7.6.20(encoding@0.1.13)(typescript@5.5.4)(vite@6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))': dependencies: - '@storybook/channels': 7.4.6 - '@storybook/client-logger': 7.4.6 - '@storybook/core-common': 7.4.6(encoding@0.1.13) - '@storybook/csf-plugin': 7.4.6 - '@storybook/mdx2-csf': 1.1.0 - '@storybook/node-logger': 7.4.6 - '@storybook/preview': 7.4.6 - '@storybook/preview-api': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/channels': 7.6.20 + '@storybook/client-logger': 7.6.20 + '@storybook/core-common': 7.6.20(encoding@0.1.13) + '@storybook/csf-plugin': 7.6.20 + '@storybook/node-logger': 7.6.20 + '@storybook/preview': 7.6.20 + '@storybook/preview-api': 7.6.20 + '@storybook/types': 7.6.20 '@types/find-cache-dir': 3.2.1 browser-assert: 1.2.1 es-module-lexer: 0.9.3 - express: 4.18.2 + express: 4.21.2 find-cache-dir: 3.3.2 - fs-extra: 11.1.1 - magic-string: 0.30.4 - remark-external-links: 8.0.0 - remark-slug: 6.1.0 - rollup: 3.29.4 - vite: 4.5.3(@types/node@20.8.0)(terser@5.19.2) + fs-extra: 11.3.0 + magic-string: 0.30.17 + rollup: 3.29.5 + vite: 6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0) optionalDependencies: - typescript: 5.5.0-beta + typescript: 5.5.4 transitivePeerDependencies: - encoding - supports-color - '@storybook/channels@7.4.6': + '@storybook/channels@7.6.20': dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/core-events': 7.4.6 + '@storybook/client-logger': 7.6.20 + '@storybook/core-events': 7.6.20 '@storybook/global': 5.0.0 - qs: 6.11.2 + qs: 6.14.0 telejson: 7.2.0 - tiny-invariant: 1.3.1 + tiny-invariant: 1.3.3 - '@storybook/cli@7.4.6(encoding@0.1.13)': + '@storybook/cli@7.6.20(encoding@0.1.13)': dependencies: - '@babel/core': 7.22.11 - '@babel/preset-env': 7.22.10(@babel/core@7.22.11) - '@babel/types': 7.22.11 + '@babel/core': 7.26.9 + '@babel/preset-env': 7.26.9(@babel/core@7.26.9) + '@babel/types': 7.26.9 '@ndelangen/get-tarball': 3.0.9 - '@storybook/codemod': 7.4.6 - '@storybook/core-common': 7.4.6(encoding@0.1.13) - '@storybook/core-events': 7.4.6 - '@storybook/core-server': 7.4.6(encoding@0.1.13) - '@storybook/csf-tools': 7.4.6 - '@storybook/node-logger': 7.4.6 - '@storybook/telemetry': 7.4.6(encoding@0.1.13) - '@storybook/types': 7.4.6 - '@types/semver': 7.5.3 + '@storybook/codemod': 7.6.20 + '@storybook/core-common': 7.6.20(encoding@0.1.13) + '@storybook/core-events': 7.6.20 + '@storybook/core-server': 7.6.20(encoding@0.1.13) + '@storybook/csf-tools': 7.6.20 + '@storybook/node-logger': 7.6.20 + '@storybook/telemetry': 7.6.20(encoding@0.1.13) + '@storybook/types': 7.6.20 + '@types/semver': 7.5.8 '@yarnpkg/fslib': 2.10.3 '@yarnpkg/libzip': 2.3.0 chalk: 4.1.2 commander: 6.2.1 - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 detect-indent: 6.1.0 - envinfo: 7.10.0 + envinfo: 7.14.0 execa: 5.1.1 - express: 4.18.2 + express: 4.21.2 find-up: 5.0.0 - fs-extra: 11.1.1 - get-npm-tarball-url: 2.0.3 + fs-extra: 11.3.0 + get-npm-tarball-url: 2.1.0 get-port: 5.1.1 - giget: 1.1.3 + giget: 1.2.5 globby: 11.1.0 - jscodeshift: 0.14.0(@babel/preset-env@7.22.10(@babel/core@7.22.11)) + jscodeshift: 0.15.2(@babel/preset-env@7.26.9(@babel/core@7.26.9)) leven: 3.1.0 ora: 5.4.1 prettier: 2.8.8 prompts: 2.4.2 puppeteer-core: 2.1.1 read-pkg-up: 7.0.1 - semver: 7.5.4 - simple-update-notifier: 2.0.0 + semver: 7.7.1 strip-json-comments: 3.1.1 tempy: 1.0.1 ts-dedent: 2.2.0 @@ -11126,69 +12228,69 @@ snapshots: - supports-color - utf-8-validate - '@storybook/client-logger@7.4.6': + '@storybook/client-logger@7.6.20': dependencies: '@storybook/global': 5.0.0 - '@storybook/codemod@7.4.6': + '@storybook/codemod@7.6.20': dependencies: - '@babel/core': 7.22.11 - '@babel/preset-env': 7.22.10(@babel/core@7.22.11) - '@babel/types': 7.22.11 - '@storybook/csf': 0.1.1 - '@storybook/csf-tools': 7.4.6 - '@storybook/node-logger': 7.4.6 - '@storybook/types': 7.4.6 - '@types/cross-spawn': 6.0.3 - cross-spawn: 7.0.3 + '@babel/core': 7.26.9 + '@babel/preset-env': 7.26.9(@babel/core@7.26.9) + '@babel/types': 7.26.9 + '@storybook/csf': 0.1.13 + '@storybook/csf-tools': 7.6.20 + '@storybook/node-logger': 7.6.20 + '@storybook/types': 7.6.20 + '@types/cross-spawn': 6.0.6 + cross-spawn: 7.0.6 globby: 11.1.0 - jscodeshift: 0.14.0(@babel/preset-env@7.22.10(@babel/core@7.22.11)) + jscodeshift: 0.15.2(@babel/preset-env@7.26.9(@babel/core@7.26.9)) lodash: 4.17.21 prettier: 2.8.8 - recast: 0.23.4 + recast: 0.23.11 transitivePeerDependencies: - supports-color - '@storybook/components@7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@storybook/components@7.6.20(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-select': 1.2.2(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-toolbar': 1.0.4(@types/react-dom@18.2.7)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/client-logger': 7.4.6 - '@storybook/csf': 0.1.1 + '@radix-ui/react-select': 1.2.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-toolbar': 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/client-logger': 7.6.20 + '@storybook/csf': 0.1.13 '@storybook/global': 5.0.0 - '@storybook/theming': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/theming': 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 7.6.20 memoizerific: 1.11.3 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - use-resize-observer: 9.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + use-resize-observer: 9.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) util-deprecate: 1.0.2 transitivePeerDependencies: - '@types/react' - '@types/react-dom' - '@storybook/core-client@7.4.6': + '@storybook/core-client@7.6.20': dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/preview-api': 7.4.6 + '@storybook/client-logger': 7.6.20 + '@storybook/preview-api': 7.6.20 - '@storybook/core-common@7.4.6(encoding@0.1.13)': + '@storybook/core-common@7.6.20(encoding@0.1.13)': dependencies: - '@storybook/core-events': 7.4.6 - '@storybook/node-logger': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/core-events': 7.6.20 + '@storybook/node-logger': 7.6.20 + '@storybook/types': 7.6.20 '@types/find-cache-dir': 3.2.1 - '@types/node': 16.18.58 - '@types/node-fetch': 2.6.6 - '@types/pretty-hrtime': 1.0.1 + '@types/node': 18.19.79 + '@types/node-fetch': 2.6.12 + '@types/pretty-hrtime': 1.0.3 chalk: 4.1.2 esbuild: 0.18.20 - esbuild-register: 3.5.0(esbuild@0.18.20) + esbuild-register: 3.6.0(esbuild@0.18.20) file-system-cache: 2.3.0 find-cache-dir: 3.3.2 find-up: 5.0.0 - fs-extra: 11.1.1 - glob: 10.3.3 + fs-extra: 11.3.0 + glob: 10.4.5 handlebars: 4.7.8 lazy-universal-dotenv: 4.0.0 node-fetch: 2.7.0(encoding@0.1.13) @@ -11201,92 +12303,92 @@ snapshots: - encoding - supports-color - '@storybook/core-events@7.4.6': + '@storybook/core-events@7.6.20': dependencies: ts-dedent: 2.2.0 - '@storybook/core-server@7.4.6(encoding@0.1.13)': + '@storybook/core-server@7.6.20(encoding@0.1.13)': dependencies: '@aw-web-design/x-default-browser': 1.4.126 '@discoveryjs/json-ext': 0.5.7 - '@storybook/builder-manager': 7.4.6(encoding@0.1.13) - '@storybook/channels': 7.4.6 - '@storybook/core-common': 7.4.6(encoding@0.1.13) - '@storybook/core-events': 7.4.6 - '@storybook/csf': 0.1.1 - '@storybook/csf-tools': 7.4.6 + '@storybook/builder-manager': 7.6.20(encoding@0.1.13) + '@storybook/channels': 7.6.20 + '@storybook/core-common': 7.6.20(encoding@0.1.13) + '@storybook/core-events': 7.6.20 + '@storybook/csf': 0.1.13 + '@storybook/csf-tools': 7.6.20 '@storybook/docs-mdx': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/manager': 7.4.6 - '@storybook/node-logger': 7.4.6 - '@storybook/preview-api': 7.4.6 - '@storybook/telemetry': 7.4.6(encoding@0.1.13) - '@storybook/types': 7.4.6 - '@types/detect-port': 1.3.3 - '@types/node': 16.18.58 - '@types/pretty-hrtime': 1.0.1 - '@types/semver': 7.5.3 + '@storybook/manager': 7.6.20 + '@storybook/node-logger': 7.6.20 + '@storybook/preview-api': 7.6.20 + '@storybook/telemetry': 7.6.20(encoding@0.1.13) + '@storybook/types': 7.6.20 + '@types/detect-port': 1.3.5 + '@types/node': 18.19.79 + '@types/pretty-hrtime': 1.0.3 + '@types/semver': 7.5.8 better-opn: 3.0.2 chalk: 4.1.2 - cli-table3: 0.6.3 - compression: 1.7.4 - detect-port: 1.5.1 - express: 4.18.2 - fs-extra: 11.1.1 + cli-table3: 0.6.5 + compression: 1.8.0 + detect-port: 1.6.1 + express: 4.21.2 + fs-extra: 11.3.0 globby: 11.1.0 - ip: 2.0.0 lodash: 4.17.21 open: 8.4.2 pretty-hrtime: 1.0.3 prompts: 2.4.2 read-pkg-up: 7.0.1 - semver: 7.5.4 + semver: 7.7.1 telejson: 7.2.0 - tiny-invariant: 1.3.1 + tiny-invariant: 1.3.3 ts-dedent: 2.2.0 util: 0.12.5 util-deprecate: 1.0.2 - watchpack: 2.4.0 - ws: 8.11.0 + watchpack: 2.4.2 + ws: 8.18.1 transitivePeerDependencies: - bufferutil - encoding - supports-color - utf-8-validate - '@storybook/csf-plugin@7.4.6': + '@storybook/csf-plugin@7.6.20': dependencies: - '@storybook/csf-tools': 7.4.6 - unplugin: 1.5.0 + '@storybook/csf-tools': 7.6.20 + unplugin: 1.16.1 transitivePeerDependencies: - supports-color - '@storybook/csf-tools@7.4.6': + '@storybook/csf-tools@7.6.20': dependencies: - '@babel/generator': 7.22.10 - '@babel/parser': 7.22.13 - '@babel/traverse': 7.22.11 - '@babel/types': 7.22.11 - '@storybook/csf': 0.1.1 - '@storybook/types': 7.4.6 - fs-extra: 11.1.1 - recast: 0.23.4 + '@babel/generator': 7.26.9 + '@babel/parser': 7.26.9 + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 + '@storybook/csf': 0.1.13 + '@storybook/types': 7.6.20 + fs-extra: 11.3.0 + recast: 0.23.11 ts-dedent: 2.2.0 transitivePeerDependencies: - supports-color - '@storybook/csf@0.1.1': + '@storybook/csf@0.1.13': dependencies: type-fest: 2.19.0 '@storybook/docs-mdx@0.1.0': {} - '@storybook/docs-tools@7.4.6(encoding@0.1.13)': + '@storybook/docs-tools@7.6.20(encoding@0.1.13)': dependencies: - '@storybook/core-common': 7.4.6(encoding@0.1.13) - '@storybook/preview-api': 7.4.6 - '@storybook/types': 7.4.6 + '@storybook/core-common': 7.6.20(encoding@0.1.13) + '@storybook/preview-api': 7.6.20 + '@storybook/types': 7.6.20 '@types/doctrine': 0.0.3 + assert: 2.1.0 doctrine: 3.0.0 lodash: 4.17.21 transitivePeerDependencies: @@ -11295,71 +12397,70 @@ snapshots: '@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/manager-api@7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@storybook/channels': 7.4.6 - '@storybook/client-logger': 7.4.6 - '@storybook/core-events': 7.4.6 - '@storybook/csf': 0.1.1 + '@storybook/channels': 7.6.20 + '@storybook/client-logger': 7.6.20 + '@storybook/core-events': 7.6.20 + '@storybook/csf': 0.1.13 '@storybook/global': 5.0.0 - '@storybook/router': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/theming': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/router': 7.6.20 + '@storybook/theming': 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 7.6.20 dequal: 2.0.3 lodash: 4.17.21 memoizerific: 1.11.3 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - semver: 7.5.4 - store2: 2.14.2 + store2: 2.14.4 telejson: 7.2.0 ts-dedent: 2.2.0 + transitivePeerDependencies: + - react + - react-dom - '@storybook/manager@7.4.6': {} + '@storybook/manager@7.6.20': {} '@storybook/mdx2-csf@1.1.0': {} - '@storybook/node-logger@7.4.6': {} + '@storybook/node-logger@7.6.20': {} - '@storybook/postinstall@7.4.6': {} + '@storybook/postinstall@7.6.20': {} - '@storybook/preview-api@7.4.6': + '@storybook/preview-api@7.6.20': dependencies: - '@storybook/channels': 7.4.6 - '@storybook/client-logger': 7.4.6 - '@storybook/core-events': 7.4.6 - '@storybook/csf': 0.1.1 + '@storybook/channels': 7.6.20 + '@storybook/client-logger': 7.6.20 + '@storybook/core-events': 7.6.20 + '@storybook/csf': 0.1.13 '@storybook/global': 5.0.0 - '@storybook/types': 7.4.6 - '@types/qs': 6.9.8 + '@storybook/types': 7.6.20 + '@types/qs': 6.9.18 dequal: 2.0.3 lodash: 4.17.21 memoizerific: 1.11.3 - qs: 6.11.2 + qs: 6.14.0 synchronous-promise: 2.0.17 ts-dedent: 2.2.0 util-deprecate: 1.0.2 - '@storybook/preview@7.4.6': {} + '@storybook/preview@7.6.20': {} - '@storybook/react-dom-shim@7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@storybook/react-dom-shim@7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) - '@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))': + '@storybook/react-vite@7.6.20(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@2.79.2)(typescript@5.5.4)(vite@6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))': dependencies: - '@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.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 - react: 18.2.0 - react-docgen: 6.0.0-alpha.3 - react-dom: 18.2.0(react@18.2.0) - vite: 4.5.3(@types/node@20.8.0)(terser@5.19.2) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.5.4)(vite@6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)) + '@rollup/pluginutils': 5.1.4(rollup@2.79.2) + '@storybook/builder-vite': 7.6.20(encoding@0.1.13)(typescript@5.5.4)(vite@6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)) + '@storybook/react': 7.6.20(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) + '@vitejs/plugin-react': 3.1.0(vite@6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)) + magic-string: 0.30.17 + react: 18.3.1 + react-docgen: 7.1.1 + react-dom: 18.3.1(react@18.3.1) + vite: 6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0) transitivePeerDependencies: - '@preact/preset-vite' - encoding @@ -11368,18 +12469,18 @@ 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.5.0-beta)': + '@storybook/react@7.6.20(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)': dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/core-client': 7.4.6 - '@storybook/docs-tools': 7.4.6(encoding@0.1.13) + '@storybook/client-logger': 7.6.20 + '@storybook/core-client': 7.6.20 + '@storybook/docs-tools': 7.6.20(encoding@0.1.13) '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.4.6 - '@storybook/react-dom-shim': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/types': 7.4.6 + '@storybook/preview-api': 7.6.20 + '@storybook/react-dom-shim': 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 7.6.20 '@types/escodegen': 0.0.6 '@types/estree': 0.0.51 - '@types/node': 16.18.58 + '@types/node': 18.19.79 acorn: 7.4.1 acorn-jsx: 5.3.2(acorn@7.4.1) acorn-walk: 7.2.0 @@ -11387,62 +12488,76 @@ snapshots: html-tags: 3.3.1 lodash: 4.17.21 prop-types: 15.8.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-element-to-jsx-string: 15.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-element-to-jsx-string: 15.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) ts-dedent: 2.2.0 type-fest: 2.19.0 util-deprecate: 1.0.2 optionalDependencies: - typescript: 5.5.0-beta + typescript: 5.5.4 transitivePeerDependencies: - encoding - supports-color - '@storybook/router@7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@storybook/router@7.6.20': dependencies: - '@storybook/client-logger': 7.4.6 + '@storybook/client-logger': 7.6.20 memoizerific: 1.11.3 - qs: 6.11.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + qs: 6.14.0 - '@storybook/telemetry@7.4.6(encoding@0.1.13)': + '@storybook/telemetry@7.6.20(encoding@0.1.13)': dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/core-common': 7.4.6(encoding@0.1.13) - '@storybook/csf-tools': 7.4.6 + '@storybook/client-logger': 7.6.20 + '@storybook/core-common': 7.6.20(encoding@0.1.13) + '@storybook/csf-tools': 7.6.20 chalk: 4.1.2 detect-package-manager: 2.0.1 fetch-retry: 5.0.6 - fs-extra: 11.1.1 + fs-extra: 11.3.0 read-pkg-up: 7.0.1 transitivePeerDependencies: - encoding - supports-color - '@storybook/theming@7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@storybook/theming@7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0) - '@storybook/client-logger': 7.4.6 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1) + '@storybook/client-logger': 7.6.20 '@storybook/global': 5.0.0 memoizerific: 1.11.3 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) - '@storybook/types@7.4.6': + '@storybook/types@7.6.20': dependencies: - '@storybook/channels': 7.4.6 - '@types/babel__core': 7.20.2 - '@types/express': 4.17.18 + '@storybook/channels': 7.6.20 + '@types/babel__core': 7.20.5 + '@types/express': 4.17.21 file-system-cache: 2.3.0 + '@stylistic/eslint-plugin@2.13.0(eslint@8.57.1)(typescript@5.5.4)': + dependencies: + '@typescript-eslint/utils': 8.26.0(eslint@8.57.1)(typescript@5.5.4) + eslint: 8.57.1 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + estraverse: 5.3.0 + picomatch: 4.0.2 + transitivePeerDependencies: + - supports-color + - typescript + '@surma/rollup-plugin-off-main-thread@2.2.3': dependencies: - ejs: 3.1.9 + ejs: 3.1.10 json5: 2.2.3 magic-string: 0.25.9 - string.prototype.matchall: 4.0.10 + string.prototype.matchall: 4.0.12 + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 '@tootallnate/once@2.0.0': {} @@ -11450,65 +12565,67 @@ snapshots: '@tweenjs/tween.js@20.0.3': {} - '@types/babel__core@7.20.2': + '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.22.13 - '@babel/types': 7.22.11 - '@types/babel__generator': 7.6.5 - '@types/babel__template': 7.4.2 - '@types/babel__traverse': 7.20.2 + '@babel/parser': 7.26.9 + '@babel/types': 7.26.9 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 - '@types/babel__generator@7.6.5': + '@types/babel__generator@7.6.8': dependencies: - '@babel/types': 7.22.11 + '@babel/types': 7.26.9 - '@types/babel__template@7.4.2': + '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.22.13 - '@babel/types': 7.22.11 + '@babel/parser': 7.26.9 + '@babel/types': 7.26.9 - '@types/babel__traverse@7.20.2': + '@types/babel__traverse@7.20.6': dependencies: - '@babel/types': 7.22.11 + '@babel/types': 7.26.9 - '@types/body-parser@1.19.3': + '@types/body-parser@1.19.5': dependencies: - '@types/connect': 3.4.36 - '@types/node': 20.8.0 + '@types/connect': 3.4.38 + '@types/node': 22.13.9 - '@types/chai-subset@1.3.3': + '@types/chai-subset@1.3.6(@types/chai@4.3.20)': dependencies: - '@types/chai': 4.3.6 + '@types/chai': 4.3.20 - '@types/chai@4.3.6': {} + '@types/chai@4.3.20': {} - '@types/connect@3.4.36': + '@types/connect@3.4.38': dependencies: - '@types/node': 20.8.10 + '@types/node': 22.13.9 - '@types/cookie@0.4.1': {} - - '@types/cors@2.8.15': + '@types/cors@2.8.17': dependencies: - '@types/node': 20.12.8 + '@types/node': 22.13.9 - '@types/cross-spawn@6.0.3': + '@types/cross-spawn@6.0.6': dependencies: - '@types/node': 20.12.8 + '@types/node': 22.13.9 '@types/debug@4.1.12': dependencies: - '@types/ms': 0.7.34 + '@types/ms': 2.1.0 - '@types/detect-port@1.3.3': {} + '@types/detect-port@1.3.5': {} + + '@types/diff-match-patch@1.0.36': {} '@types/doctrine@0.0.3': {} - '@types/draco3d@1.4.7': {} + '@types/doctrine@0.0.9': {} - '@types/ejs@3.1.3': {} + '@types/draco3d@1.4.10': {} - '@types/emscripten@1.39.8': {} + '@types/ejs@3.1.5': {} + + '@types/emscripten@1.40.0': {} '@types/escodegen@0.0.6': {} @@ -11516,21 +12633,21 @@ snapshots: '@types/estree@0.0.51': {} - '@types/estree@1.0.2': {} + '@types/estree@1.0.6': {} - '@types/express-serve-static-core@4.17.37': + '@types/express-serve-static-core@4.19.6': dependencies: - '@types/node': 20.8.0 - '@types/qs': 6.9.8 - '@types/range-parser': 1.2.5 - '@types/send': 0.17.2 + '@types/node': 22.13.9 + '@types/qs': 6.9.18 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.4 - '@types/express@4.17.18': + '@types/express@4.17.21': dependencies: - '@types/body-parser': 1.19.3 - '@types/express-serve-static-core': 4.17.37 - '@types/qs': 6.9.8 - '@types/serve-static': 1.15.3 + '@types/body-parser': 1.19.5 + '@types/express-serve-static-core': 4.19.6 + '@types/qs': 6.9.18 + '@types/serve-static': 1.15.7 '@types/find-cache-dir@3.2.1': {} @@ -11539,218 +12656,219 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.8.0 + '@types/node': 22.13.9 - '@types/graceful-fs@4.1.7': + '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 20.12.8 + '@types/node': 22.13.9 - '@types/http-cache-semantics@4.0.2': {} + '@types/http-cache-semantics@4.0.4': {} - '@types/http-errors@2.0.2': {} + '@types/http-errors@2.0.4': {} - '@types/istanbul-lib-coverage@2.0.4': {} + '@types/istanbul-lib-coverage@2.0.6': {} - '@types/istanbul-lib-report@3.0.1': + '@types/istanbul-lib-report@3.0.3': dependencies: - '@types/istanbul-lib-coverage': 2.0.4 + '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports@3.0.2': + '@types/istanbul-reports@3.0.4': dependencies: - '@types/istanbul-lib-report': 3.0.1 + '@types/istanbul-lib-report': 3.0.3 '@types/js-cookie@2.2.7': {} - '@types/json-schema@7.0.12': {} + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} - '@types/lodash-es@4.17.9': + '@types/linkify-it@5.0.0': {} + + '@types/lodash-es@4.17.12': dependencies: - '@types/lodash': 4.14.199 + '@types/lodash': 4.17.16 - '@types/lodash@4.14.199': {} + '@types/lodash@4.17.16': {} - '@types/mdast@4.0.3': + '@types/markdown-it@14.1.2': dependencies: - '@types/unist': 2.0.8 + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 - '@types/mdx@2.0.8': {} + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 - '@types/mime-types@2.1.2': {} + '@types/mdurl@2.0.0': {} - '@types/mime@1.3.3': {} + '@types/mdx@2.0.13': {} - '@types/mime@3.0.2': {} + '@types/mime-types@2.1.4': {} + + '@types/mime@1.3.5': {} '@types/minimatch@5.1.2': {} - '@types/minimist@1.2.3': {} + '@types/minimist@1.2.5': {} - '@types/ms@0.7.34': {} + '@types/ms@2.1.0': {} - '@types/node-fetch@2.6.6': + '@types/node-fetch@2.6.12': dependencies: - '@types/node': 20.8.0 - form-data: 4.0.0 + '@types/node': 22.13.9 + form-data: 4.0.2 - '@types/node@14.18.56': {} - - '@types/node@16.18.58': {} - - '@types/node@20.11.19': + '@types/node-rsa@1.1.4': dependencies: - undici-types: 5.26.5 + '@types/node': 22.13.9 + + '@types/node@14.18.63': optional: true - '@types/node@20.12.8': + '@types/node@18.19.79': dependencies: undici-types: 5.26.5 - '@types/node@20.8.0': {} - - '@types/node@20.8.10': + '@types/node@22.13.9': dependencies: - undici-types: 5.26.5 + undici-types: 6.20.0 - '@types/normalize-package-data@2.4.2': {} + '@types/normalize-package-data@2.4.4': {} - '@types/offscreencanvas@2019.7.2': {} + '@types/offscreencanvas@2019.7.3': {} - '@types/parse-json@4.0.0': {} + '@types/parse-json@4.0.2': {} - '@types/pretty-hrtime@1.0.1': {} + '@types/pretty-hrtime@1.0.3': {} - '@types/prop-types@15.7.12': {} + '@types/prop-types@15.7.14': {} - '@types/prop-types@15.7.5': {} + '@types/qs@6.9.18': {} - '@types/qs@6.9.8': {} + '@types/range-parser@1.2.7': {} - '@types/range-parser@1.2.5': {} + '@types/rbush@3.0.4': {} - '@types/rbush@3.0.1': {} - - '@types/react-dom@18.2.7': + '@types/react-dom@18.3.5(@types/react@18.3.18)': dependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@types/react-transition-group@4.4.7': + '@types/react-transition-group@4.4.12(@types/react@18.3.18)': dependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - '@types/react@18.2.20': + '@types/react@18.3.18': dependencies: - '@types/prop-types': 15.7.5 - '@types/scheduler': 0.16.3 - csstype: 3.1.2 + '@types/prop-types': 15.7.14 + csstype: 3.1.3 - '@types/readable-stream@4.0.12': + '@types/readable-stream@4.0.18': dependencies: - '@types/node': 20.12.8 + '@types/node': 22.13.9 safe-buffer: 5.1.2 - '@types/resolve@1.17.1': - dependencies: - '@types/node': 20.12.8 + '@types/resolve@1.20.2': {} + + '@types/resolve@1.20.6': {} '@types/sat@0.0.31': {} - '@types/scheduler@0.16.3': {} + '@types/semver@7.5.8': {} - '@types/semver@7.5.3': {} - - '@types/send@0.17.2': + '@types/send@0.17.4': dependencies: - '@types/mime': 1.3.3 - '@types/node': 20.12.8 + '@types/mime': 1.3.5 + '@types/node': 22.13.9 - '@types/serve-static@1.15.3': + '@types/serve-static@1.15.7': dependencies: - '@types/http-errors': 2.0.2 - '@types/mime': 3.0.2 - '@types/node': 20.8.0 + '@types/http-errors': 2.0.4 + '@types/node': 22.13.9 + '@types/send': 0.17.4 - '@types/sinonjs__fake-timers@8.1.1': {} + '@types/sinonjs__fake-timers@8.1.1': + optional: true - '@types/sizzle@2.3.3': {} + '@types/sizzle@2.3.9': + optional: true - '@types/stats.js@0.17.1': {} + '@types/stats.js@0.17.3': {} '@types/three@0.154.0': dependencies: '@tweenjs/tween.js': 18.6.4 - '@types/stats.js': 0.17.1 - '@types/webxr': 0.5.7 + '@types/stats.js': 0.17.3 + '@types/webxr': 0.5.21 fflate: 0.6.10 lil-gui: 0.17.0 meshoptimizer: 0.18.1 '@types/three@0.156.0': dependencies: - '@types/stats.js': 0.17.1 - '@types/webxr': 0.5.7 + '@types/stats.js': 0.17.3 + '@types/webxr': 0.5.21 fflate: 0.6.10 meshoptimizer: 0.18.1 - '@types/trusted-types@2.0.3': {} + '@types/trusted-types@2.0.7': {} '@types/ua-parser-js@0.7.39': {} - '@types/unist@2.0.8': {} + '@types/unist@2.0.11': {} - '@types/unist@3.0.2': {} + '@types/unist@3.0.3': {} - '@types/webxr@0.5.7': {} + '@types/uuid@9.0.8': {} - '@types/wicg-file-system-access@2023.10.2': {} - - '@types/yargs-parser@21.0.1': {} - - '@types/yargs@17.0.28': + '@types/wait-on@5.3.4': dependencies: - '@types/yargs-parser': 21.0.1 + '@types/node': 22.13.9 - '@types/yauzl@2.10.1': + '@types/webxr@0.5.21': {} + + '@types/wicg-file-system-access@2023.10.5': {} + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.33': dependencies: - '@types/node': 20.8.0 + '@types/yargs-parser': 21.0.3 '@types/yauzl@2.10.3': dependencies: - '@types/node': 20.11.19 - optional: true + '@types/node': 22.13.9 - '@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/eslint-plugin@6.1.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4)': dependencies: - '@eslint-community/regexpp': 4.8.0 - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.5.0-beta) + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.5.4) '@typescript-eslint/scope-manager': 6.1.0 - '@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/type-utils': 6.1.0(eslint@8.57.1)(typescript@5.5.4) + '@typescript-eslint/utils': 6.1.0(eslint@8.57.1)(typescript@5.5.4) '@typescript-eslint/visitor-keys': 6.1.0 - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.50.0 + debug: 4.4.0(supports-color@8.1.1) + eslint: 8.57.1 graphemer: 1.4.0 - ignore: 5.2.4 + ignore: 5.3.2 natural-compare: 1.4.0 natural-compare-lite: 1.4.0 - semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.5.0-beta) + semver: 7.7.1 + ts-api-utils: 1.4.3(typescript@5.5.4) optionalDependencies: - typescript: 5.5.0-beta + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta)': + '@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.5.4)': dependencies: - '@typescript-eslint/scope-manager': 6.7.3 - '@typescript-eslint/types': 6.7.3 - '@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 + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.4.0(supports-color@8.1.1) + eslint: 8.57.1 optionalDependencies: - typescript: 5.5.0-beta + typescript: 5.5.4 transitivePeerDependencies: - supports-color @@ -11759,87 +12877,127 @@ snapshots: '@typescript-eslint/types': 6.1.0 '@typescript-eslint/visitor-keys': 6.1.0 - '@typescript-eslint/scope-manager@6.7.3': + '@typescript-eslint/scope-manager@6.21.0': dependencies: - '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/visitor-keys': 6.7.3 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 - '@typescript-eslint/type-utils@6.1.0(eslint@8.50.0)(typescript@5.5.0-beta)': + '@typescript-eslint/scope-manager@8.26.0': dependencies: - '@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.5.0-beta) + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/visitor-keys': 8.26.0 + + '@typescript-eslint/type-utils@6.1.0(eslint@8.57.1)(typescript@5.5.4)': + dependencies: + '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.5.4) + '@typescript-eslint/utils': 6.1.0(eslint@8.57.1)(typescript@5.5.4) + debug: 4.4.1 + eslint: 8.57.1 + ts-api-utils: 1.4.3(typescript@5.5.4) optionalDependencies: - typescript: 5.5.0-beta + typescript: 5.5.4 transitivePeerDependencies: - supports-color '@typescript-eslint/types@6.1.0': {} - '@typescript-eslint/types@6.7.3': {} + '@typescript-eslint/types@6.21.0': {} - '@typescript-eslint/typescript-estree@6.1.0(typescript@5.5.0-beta)': + '@typescript-eslint/types@8.26.0': {} + + '@typescript-eslint/typescript-estree@6.1.0(typescript@5.5.4)': dependencies: '@typescript-eslint/types': 6.1.0 '@typescript-eslint/visitor-keys': 6.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.1 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.6.0 - ts-api-utils: 1.0.3(typescript@5.5.0-beta) + semver: 7.7.1 + ts-api-utils: 1.4.3(typescript@5.5.4) optionalDependencies: - typescript: 5.5.0-beta + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@6.7.3(typescript@5.5.0-beta)': + '@typescript-eslint/typescript-estree@6.21.0(typescript@5.5.4)': dependencies: - '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/visitor-keys': 6.7.3 - debug: 4.3.4(supports-color@8.1.1) + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.4.1 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.6.0 - ts-api-utils: 1.0.3(typescript@5.5.0-beta) + minimatch: 9.0.3 + semver: 7.7.1 + ts-api-utils: 1.4.3(typescript@5.5.4) optionalDependencies: - typescript: 5.5.0-beta + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@6.1.0(eslint@8.50.0)(typescript@5.5.0-beta)': + '@typescript-eslint/typescript-estree@8.26.0(typescript@5.5.4)': 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/types': 8.26.0 + '@typescript-eslint/visitor-keys': 8.26.0 + debug: 4.4.1 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.1 + ts-api-utils: 2.0.1(typescript@5.5.4) + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@6.1.0(eslint@8.57.1)(typescript@5.5.4)': + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 6.1.0 '@typescript-eslint/types': 6.1.0 - '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.5.0-beta) - eslint: 8.50.0 - semver: 7.6.0 + '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.5.4) + eslint: 8.57.1 + semver: 7.7.1 transitivePeerDependencies: - supports-color - typescript + '@typescript-eslint/utils@8.26.0(eslint@8.57.1)(typescript@5.5.4)': + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@typescript-eslint/scope-manager': 8.26.0 + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.5.4) + eslint: 8.57.1 + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/visitor-keys@6.1.0': dependencies: '@typescript-eslint/types': 6.1.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@6.7.3': + '@typescript-eslint/visitor-keys@6.21.0': dependencies: - '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/types': 6.21.0 eslint-visitor-keys: 3.4.3 - '@vitejs/plugin-react@3.1.0(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': + '@typescript-eslint/visitor-keys@8.26.0': dependencies: - '@babel/core': 7.22.11 - '@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.22.11) - '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.22.11) + '@typescript-eslint/types': 8.26.0 + eslint-visitor-keys: 4.2.0 + + '@ungap/structured-clone@1.3.0': {} + + '@vitejs/plugin-react@3.1.0(vite@6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))': + dependencies: + '@babel/core': 7.26.9 + '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.9) magic-string: 0.27.0 - react-refresh: 0.14.0 - vite: 4.5.3(@types/node@20.8.0)(terser@5.19.2) + react-refresh: 0.14.2 + vite: 6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0) transitivePeerDependencies: - supports-color @@ -11847,75 +13005,76 @@ snapshots: dependencies: '@vitest/spy': 0.34.6 '@vitest/utils': 0.34.6 - chai: 4.3.10 + chai: 4.5.0 '@vitest/runner@0.34.6': dependencies: '@vitest/utils': 0.34.6 p-limit: 4.0.0 - pathe: 1.1.1 + pathe: 1.1.2 '@vitest/snapshot@0.34.6': dependencies: - magic-string: 0.30.4 - pathe: 1.1.1 + magic-string: 0.30.17 + pathe: 1.1.2 pretty-format: 29.7.0 '@vitest/spy@0.34.6': dependencies: - tinyspy: 2.2.0 + tinyspy: 2.2.1 '@vitest/utils@0.34.6': dependencies: diff-sequences: 29.6.3 - loupe: 2.3.6 + loupe: 2.3.7 pretty-format: 29.7.0 '@xboxreplay/errors@0.1.0': {} - '@xboxreplay/xboxlive-auth@3.3.3(debug@4.3.4)': + '@xboxreplay/xboxlive-auth@3.3.3(debug@4.4.0)': dependencies: '@xboxreplay/errors': 0.1.0 - axios: 0.21.4(debug@4.3.4) + axios: 0.21.4(debug@4.4.0) transitivePeerDependencies: - debug '@xmcl/asm@1.0.1': {} - '@xmcl/core@2.12.0(yauzl@2.10.0)': + '@xmcl/core@2.13.0(yauzl@2.10.0)': dependencies: '@xmcl/unzip': 2.1.2(yauzl@2.10.0) transitivePeerDependencies: - yauzl - '@xmcl/file-transfer@1.0.3': + '@xmcl/file-transfer@1.0.6': dependencies: - '@types/http-cache-semantics': 4.0.2 + '@types/http-cache-semantics': 4.0.4 http-cache-semantics: 4.1.1 - undici: 5.25.4 + undici: 6.0.1 '@xmcl/forge-site-parser@2.0.9': dependencies: - node-html-parser: 6.1.10 + node-html-parser: 6.1.13 - '@xmcl/installer@5.1.0': + '@xmcl/installer@5.4.0': dependencies: '@xmcl/asm': 1.0.1 - '@xmcl/core': 2.12.0(yauzl@2.10.0) - '@xmcl/file-transfer': 1.0.3 + '@xmcl/core': 2.13.0(yauzl@2.10.0) + '@xmcl/file-transfer': 1.0.6 '@xmcl/forge-site-parser': 2.0.9 - '@xmcl/task': 4.0.6 + '@xmcl/task': 4.1.0 '@xmcl/unzip': 2.1.2(yauzl@2.10.0) - undici: 5.25.4 + undici: 6.0.1 yauzl: 2.10.0 + yazl: 2.5.1 - '@xmcl/task@4.0.6': {} + '@xmcl/task@4.1.0': {} '@xmcl/text-component@2.1.3': {} '@xmcl/unzip@2.1.2(yauzl@2.10.0)': dependencies: - '@types/yauzl': 2.10.1 + '@types/yauzl': 2.10.3 yauzl: 2.10.0 '@xobotyi/scrollbar-width@1.9.5': {} @@ -11923,7 +13082,7 @@ snapshots: '@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15(esbuild@0.18.20)': dependencies: esbuild: 0.18.20 - tslib: 2.6.2 + tslib: 2.8.1 '@yarnpkg/fslib@2.10.3': dependencies: @@ -11932,49 +13091,91 @@ snapshots: '@yarnpkg/libzip@2.3.0': dependencies: - '@types/emscripten': 1.39.8 + '@types/emscripten': 1.40.0 tslib: 1.14.1 - '@zardoy/flying-squid@0.0.24(encoding@0.1.13)': + '@zardoy/flying-squid@0.0.104(encoding@0.1.13)': dependencies: '@tootallnate/once': 2.0.0 + chalk: 5.4.1 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/cfaad2d1d5909fdfa63c8cc7bc05fb5e87782d71 emit-then: 2.0.0 exit-hook: 2.2.1 flatmap: 0.0.3 - long: 5.2.3 - minecraft-data: 3.65.0 - minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) + long: 5.3.1 + mc-bridge: 0.1.3(minecraft-data@3.98.0) + minecraft-data: 3.98.0 + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(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/eb39a905761a36f733a456110e6b49d655bf5c16(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-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0) + prismarine-entity: 2.5.0 + prismarine-item: 1.17.0 + prismarine-nbt: 2.7.0 + prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.98.0) prismarine-windows: 2.9.0 - prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 - rambda: 9.2.0 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c + rambda: 9.4.2 random-seed: 0.3.0 range: 0.0.3 readline: 1.3.0 + sanitize-filename: 1.6.3 typed-emitter: 1.4.0 uuid-1345: 1.0.2 - vec3: 0.1.8 - yaml: 2.4.1 + vec3: 0.1.10 + yaml: 2.7.0 yargs: 17.7.2 transitivePeerDependencies: - encoding - supports-color - '@zardoy/react-util@0.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@zardoy/flying-squid@0.0.49(encoding@0.1.13)': + dependencies: + '@tootallnate/once': 2.0.0 + chalk: 5.4.1 + change-case: 4.1.2 + diamond-square: https://codeload.github.com/zardoy/diamond-square/tar.gz/cfaad2d1d5909fdfa63c8cc7bc05fb5e87782d71 + emit-then: 2.0.0 + exit-hook: 2.2.1 + flatmap: 0.0.3 + long: 5.3.1 + minecraft-data: 3.98.0 + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(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/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0) + prismarine-entity: 2.5.0 + prismarine-item: 1.17.0 + prismarine-nbt: 2.7.0 + prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.98.0) + prismarine-windows: 2.9.0 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c + rambda: 9.4.2 + random-seed: 0.3.0 + range: 0.0.3 + readline: 1.3.0 + sanitize-filename: 1.6.3 + typed-emitter: 1.4.0 + uuid-1345: 1.0.2 + vec3: 0.1.10 + yaml: 2.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - encoding + - supports-color + + '@zardoy/maxrects-packer@2.7.4': {} + + '@zardoy/react-util@0.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: classnames: 2.5.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-hook-form: 7.54.2(react@18.3.1) '@zardoy/utils@0.0.11': dependencies: @@ -11985,7 +13186,8 @@ snapshots: Base64@0.2.1: {} - abbrev@1.1.1: {} + abbrev@1.1.1: + optional: true abort-controller@3.0.0: dependencies: @@ -12000,41 +13202,39 @@ snapshots: dependencies: acorn: 7.4.1 - acorn-jsx@5.3.2(acorn@8.10.0): + acorn-jsx@5.3.2(acorn@8.14.1): dependencies: - acorn: 8.10.0 + acorn: 8.14.1 acorn-walk@7.2.0: {} - acorn-walk@8.2.0: {} + acorn-walk@8.3.4: + dependencies: + acorn: 8.14.1 acorn@7.4.1: {} - acorn@8.10.0: {} + acorn@8.14.1: {} address@1.2.2: {} - adm-zip@0.5.12: {} + adm-zip@0.5.16: {} aes-js@3.1.2: {} - after@0.8.2: {} + after@0.8.2: + optional: true agent-base@5.1.1: {} agent-base@6.0.2: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.1 transitivePeerDependencies: - supports-color + optional: true - agent-base@7.1.0: - dependencies: - debug: 4.3.4(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - - agentkeepalive@4.5.0: + agentkeepalive@4.6.0: dependencies: humanize-ms: 1.2.1 optional: true @@ -12051,24 +13251,26 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.12.0: + ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 + fast-uri: 3.0.6 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - uri-js: 4.4.1 animejs@3.2.1: {} - ansi-colors@4.1.3: {} + ansi-colors@4.1.3: + optional: true ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 + optional: true ansi-regex@5.0.1: {} - ansi-regex@6.0.1: {} + ansi-regex@6.1.0: {} ansi-styles@3.2.1: dependencies: @@ -12082,25 +13284,42 @@ snapshots: ansi-styles@6.2.1: {} - any-base@1.1.0: {} + any-base@1.1.0: + optional: true any-promise@1.3.0: {} + anymatch@2.0.0: + dependencies: + micromatch: 3.1.10 + normalize-path: 2.1.1 + transitivePeerDependencies: + - supports-color + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 + apache-crypt@1.2.6: + dependencies: + unix-crypt-td-js: 1.1.4 + + apache-md5@1.1.8: {} + app-root-dir@1.0.2: {} - aproba@2.0.0: {} + aproba@2.0.0: + optional: true - arch@2.2.0: {} + arch@2.2.0: + optional: true are-we-there-yet@2.0.0: dependencies: delegates: 1.0.0 readable-stream: 3.6.2 + optional: true are-we-there-yet@3.0.1: dependencies: @@ -12114,110 +13333,98 @@ snapshots: argparse@2.0.1: {} - aria-hidden@1.2.3: + aria-hidden@1.2.4: dependencies: - tslib: 2.6.2 + tslib: 2.8.1 - array-buffer-byte-length@1.0.0: - dependencies: - call-bind: 1.0.2 - is-array-buffer: 3.0.2 + arr-diff@4.0.0: {} - array-buffer-byte-length@1.0.1: + arr-flatten@1.1.0: {} + + arr-union@3.1.0: {} + + array-buffer-byte-length@1.0.2: dependencies: - call-bind: 1.0.7 - is-array-buffer: 3.0.4 + call-bound: 1.0.4 + is-array-buffer: 3.0.5 array-flatten@1.1.1: {} - array-includes@3.1.7: - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.1 - es-abstract: 1.22.2 - get-intrinsic: 1.2.1 - is-string: 1.0.7 - array-includes@3.1.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 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 + es-abstract: 1.23.9 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 array-union@2.1.0: {} + array-unique@0.3.2: {} + array.prototype.findlast@1.2.5: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.24.0 es-errors: 1.3.0 - es-object-atoms: 1.0.0 - es-shim-unscopables: 1.0.2 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 - array.prototype.flat@1.3.2: + array.prototype.flat@1.3.3: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.22.2 - es-shim-unscopables: 1.0.0 + es-abstract: 1.23.9 + es-shim-unscopables: 1.1.0 - array.prototype.flatmap@1.3.2: + array.prototype.flatmap@1.3.3: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.22.2 - es-shim-unscopables: 1.0.0 + es-abstract: 1.23.9 + es-shim-unscopables: 1.1.0 - array.prototype.toreversed@1.1.2: + array.prototype.tosorted@1.1.4: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 - es-shim-unscopables: 1.0.2 - - array.prototype.tosorted@1.1.3: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.24.0 es-errors: 1.3.0 - es-shim-unscopables: 1.0.2 + es-shim-unscopables: 1.1.0 - arraybuffer.prototype.slice@1.0.2: + arraybuffer.prototype.slice@1.0.4: dependencies: - array-buffer-byte-length: 1.0.0 - call-bind: 1.0.2 + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.22.2 - get-intrinsic: 1.2.1 - is-array-buffer: 3.0.2 - is-shared-array-buffer: 1.0.2 - - arraybuffer.prototype.slice@1.0.3: - dependencies: - array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.9 es-errors: 1.3.0 - get-intrinsic: 1.2.4 - is-array-buffer: 3.0.4 - is-shared-array-buffer: 1.0.3 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 - arraybuffer.slice@0.0.7: {} + arraybuffer.slice@0.0.7: + optional: true arrify@1.0.1: {} - asn1.js@5.4.1: + asn1.js@4.10.1: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.1 inherits: 2.0.4 minimalistic-assert: 1.0.1 - safer-buffer: 2.1.2 asn1@0.2.3: {} @@ -12225,30 +13432,31 @@ snapshots: dependencies: safer-buffer: 2.1.2 - assert-plus@1.0.0: {} + assert-plus@1.0.0: + optional: true - assert@2.0.0: + assert@2.1.0: dependencies: - es6-object-assign: 1.1.0 + call-bind: 1.0.8 is-nan: 1.3.2 - object-is: 1.1.5 + object-is: 1.1.6 + object.assign: 4.1.7 util: 0.12.5 assertion-error@1.1.0: {} - ast-types@0.14.2: - dependencies: - tslib: 2.6.2 - - ast-types@0.15.2: - dependencies: - tslib: 2.6.2 + assign-symbols@1.0.0: {} ast-types@0.16.1: dependencies: - tslib: 2.6.2 + tslib: 2.8.1 - astral-regex@2.0.0: {} + astral-regex@2.0.0: + optional: true + + async-each@1.0.6: {} + + async-function@1.0.0: {} async-limiter@1.0.1: {} @@ -12256,35 +13464,45 @@ snapshots: dependencies: lodash: 4.17.21 - async@3.2.5: {} + async@3.2.6: {} asynckit@0.4.0: {} at-least-node@1.0.0: {} - available-typed-arrays@1.0.5: {} + atob@2.1.2: {} available-typed-arrays@1.0.7: dependencies: - possible-typed-array-names: 1.0.0 + possible-typed-array-names: 1.1.0 - aws-sign2@0.7.0: {} + aws-sign2@0.7.0: + optional: true - aws4@1.12.0: {} + aws4@1.13.2: + optional: true - axios@0.21.4(debug@4.3.4): + axios@0.21.4(debug@4.4.0): dependencies: - follow-redirects: 1.15.6(debug@4.3.4) + follow-redirects: 1.15.9(debug@4.4.0) transitivePeerDependencies: - debug - babel-core@7.0.0-bridge.0(@babel/core@7.22.11): + axios@1.8.2(debug@4.4.0): dependencies: - '@babel/core': 7.22.11 + follow-redirects: 1.15.9(debug@4.4.0) + form-data: 4.0.2 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + babel-core@7.0.0-bridge.0(@babel/core@7.26.9): + dependencies: + '@babel/core': 7.26.9 babel-plugin-istanbul@6.1.1: dependencies: - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-plugin-utils': 7.26.5 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-instrument: 5.2.1 @@ -12294,61 +13512,80 @@ snapshots: babel-plugin-macros@3.1.0: dependencies: - '@babel/runtime': 7.22.11 + '@babel/runtime': 7.26.9 cosmiconfig: 7.1.0 - resolve: 1.22.4 + resolve: 1.22.10 - babel-plugin-polyfill-corejs2@0.4.5(@babel/core@7.22.11): + babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.26.9): dependencies: - '@babel/compat-data': 7.22.9 - '@babel/core': 7.22.11 - '@babel/helper-define-polyfill-provider': 0.4.2(@babel/core@7.22.11) + '@babel/compat-data': 7.26.8 + '@babel/core': 7.26.9 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.9) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.8.3(@babel/core@7.22.11): + babel-plugin-polyfill-corejs3@0.11.1(@babel/core@7.26.9): dependencies: - '@babel/core': 7.22.11 - '@babel/helper-define-polyfill-provider': 0.4.2(@babel/core@7.22.11) - core-js-compat: 3.32.1 + '@babel/core': 7.26.9 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.9) + core-js-compat: 3.41.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.5.2(@babel/core@7.22.11): + babel-plugin-polyfill-regenerator@0.6.3(@babel/core@7.26.9): dependencies: - '@babel/core': 7.22.11 - '@babel/helper-define-polyfill-provider': 0.4.2(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.9) transitivePeerDependencies: - supports-color - backo2@1.0.2: {} + backo2@1.0.2: + optional: true bail@2.0.2: {} balanced-match@1.0.2: {} - base64-arraybuffer@0.1.4: {} + base64-arraybuffer@0.1.4: + optional: true base64-js@1.5.1: {} base64id@2.0.0: {} + base@0.11.2: + dependencies: + cache-base: 1.0.1 + class-utils: 0.3.6 + component-emitter: 1.3.1 + define-property: 1.0.0 + isobject: 3.0.1 + mixin-deep: 1.3.2 + pascalcase: 0.1.1 + basic-auth@2.0.1: dependencies: safe-buffer: 5.1.2 + batch@0.6.1: {} + bcrypt-pbkdf@1.0.2: dependencies: tweetnacl: 0.14.5 + optional: true + + bcryptjs@2.4.3: {} better-opn@3.0.2: dependencies: open: 8.4.2 - big-integer@1.6.51: {} + big-integer@1.6.52: {} - binary-extensions@2.2.0: {} + binary-extensions@1.13.1: {} + + binary-extensions@2.3.0: {} bindings@1.5.0: dependencies: @@ -12360,23 +13597,27 @@ snapshots: bl@4.1.0: dependencies: - buffer: 5.7.1 + buffer: 6.0.3 inherits: 2.0.4 readable-stream: 3.6.2 - blob-util@2.0.2: {} + blob-util@2.0.2: + optional: true - blob@0.0.5: {} + blob@0.0.5: + optional: true - bluebird@3.7.2: {} + bluebird@3.7.2: + optional: true - bmp-js@0.1.0: {} + bmp-js@0.1.0: + optional: true - bn.js@4.12.0: {} + bn.js@4.12.1: {} bn.js@5.2.1: {} - body-parser@1.20.1: + body-parser@1.20.3: dependencies: bytes: 3.1.2 content-type: 1.0.5 @@ -12386,24 +13627,7 @@ snapshots: http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.11.0 - raw-body: 2.5.1 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - body-parser@1.20.2: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.11.0 + qs: 6.13.0 raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 @@ -12414,7 +13638,7 @@ snapshots: bplist-parser@0.2.0: dependencies: - big-integer: 1.6.51 + big-integer: 1.6.52 brace-expansion@1.1.11: dependencies: @@ -12425,9 +13649,24 @@ snapshots: dependencies: balanced-match: 1.0.2 - braces@3.0.2: + braces@2.3.2: dependencies: - fill-range: 7.0.1 + arr-flatten: 1.1.0 + array-unique: 0.3.2 + extend-shallow: 2.0.1 + fill-range: 4.0.0 + isobject: 3.0.1 + repeat-element: 1.1.4 + snapdragon: 0.8.2 + snapdragon-node: 2.1.1 + split-string: 3.1.0 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 brorand@1.1.0: {} @@ -12442,7 +13681,7 @@ snapshots: browserify-aes@1.2.0: dependencies: buffer-xor: 1.0.3 - cipher-base: 1.0.4 + cipher-base: 1.0.6 create-hash: 1.2.0 evp_bytestokey: 1.0.3 inherits: 2.0.4 @@ -12456,26 +13695,28 @@ snapshots: browserify-des@1.0.2: dependencies: - cipher-base: 1.0.4 + cipher-base: 1.0.6 des.js: 1.1.0 inherits: 2.0.4 safe-buffer: 5.2.1 - browserify-rsa@4.1.0: + browserify-rsa@4.1.1: dependencies: bn.js: 5.2.1 randombytes: 2.1.0 + safe-buffer: 5.2.1 - browserify-sign@4.2.1: + browserify-sign@4.2.3: dependencies: bn.js: 5.2.1 - browserify-rsa: 4.1.0 + browserify-rsa: 4.1.1 create-hash: 1.2.0 create-hmac: 1.1.7 - elliptic: 6.5.4 + elliptic: 6.6.1 + hash-base: 3.0.5 inherits: 2.0.4 - parse-asn1: 5.1.6 - readable-stream: 3.6.2 + parse-asn1: 5.1.7 + readable-stream: 2.3.8 safe-buffer: 5.2.1 browserify-zlib@0.1.4: @@ -12486,12 +13727,12 @@ snapshots: dependencies: pako: 1.0.11 - browserslist@4.21.10: + browserslist@4.24.4: dependencies: - caniuse-lite: 1.0.30001524 - electron-to-chromium: 1.4.504 - node-releases: 2.0.13 - update-browserslist-db: 1.0.11(browserslist@4.21.10) + caniuse-lite: 1.0.30001713 + electron-to-chromium: 1.5.113 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.24.4) bser@2.1.1: dependencies: @@ -12501,7 +13742,8 @@ snapshots: buffer-equal-constant-time@1.0.1: {} - buffer-equal@0.0.1: {} + buffer-equal@0.0.1: + optional: true buffer-equal@1.0.1: {} @@ -12509,11 +13751,6 @@ snapshots: buffer-xor@1.0.3: {} - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - buffer@6.0.3: dependencies: base64-js: 1.5.1 @@ -12521,25 +13758,10 @@ snapshots: builtin-modules@3.3.0: {} - bytes@3.0.0: {} + builtin-status-codes@3.0.0: {} bytes@3.1.2: {} - c8@7.14.0: - dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@istanbuljs/schema': 0.1.3 - find-up: 5.0.0 - foreground-child: 2.0.0 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-report: 3.0.1 - istanbul-reports: 3.1.6 - rimraf: 3.0.2 - test-exclude: 6.0.0 - v8-to-istanbul: 9.1.3 - yargs: 16.2.0 - yargs-parser: 20.2.9 - cac@6.7.14: {} cacache@16.1.3: @@ -12560,33 +13782,50 @@ snapshots: promise-inflight: 1.0.1 rimraf: 3.0.2 ssri: 9.0.1 - tar: 6.2.0 + tar: 6.2.1 unique-filename: 2.0.1 transitivePeerDependencies: - bluebird optional: true - cachedir@2.4.0: {} - - call-bind@1.0.2: + cache-base@1.0.1: dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.2.1 + collection-visit: 1.0.0 + component-emitter: 1.3.1 + get-value: 2.0.6 + has-value: 1.0.0 + isobject: 3.0.1 + set-value: 2.0.1 + to-object-path: 0.3.0 + union-value: 1.0.1 + unset-value: 1.0.0 - call-bind@1.0.7: + cachedir@2.4.0: + optional: true + + call-bind-apply-helpers@1.0.2: dependencies: - es-define-property: 1.0.0 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - set-function-length: 1.2.1 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 callsites@3.1.0: {} camel-case@4.1.2: dependencies: pascal-case: 3.1.2 - tslib: 2.6.2 + tslib: 2.8.1 camelcase-keys@7.0.2: dependencies: @@ -12599,50 +13838,43 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001524: {} + caniuse-lite@1.0.30001713: {} canvas@2.11.2(encoding@0.1.13): dependencies: '@mapbox/node-pre-gyp': 1.0.11(encoding@0.1.13) - nan: 2.18.0 + nan: 2.22.2 simple-get: 3.1.1 transitivePeerDependencies: - encoding - supports-color + optional: true capital-case@1.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.8.1 upper-case-first: 2.0.2 - caseless@0.12.0: {} - - cbor-extract@2.2.0: - dependencies: - node-gyp-build-optional-packages: 5.1.1 - optionalDependencies: - '@cbor-extract/cbor-extract-darwin-arm64': 2.2.0 - '@cbor-extract/cbor-extract-darwin-x64': 2.2.0 - '@cbor-extract/cbor-extract-linux-arm': 2.2.0 - '@cbor-extract/cbor-extract-linux-arm64': 2.2.0 - '@cbor-extract/cbor-extract-linux-x64': 2.2.0 - '@cbor-extract/cbor-extract-win32-x64': 2.2.0 + caseless@0.12.0: optional: true - cbor-x@1.5.4: - optionalDependencies: - cbor-extract: 2.2.0 + centra@2.7.0(debug@4.4.0): + dependencies: + follow-redirects: 1.15.9(debug@4.4.0) + transitivePeerDependencies: + - debug + optional: true - chai@4.3.10: + chai@4.5.0: dependencies: assertion-error: 1.1.0 check-error: 1.0.3 - deep-eql: 4.1.3 + deep-eql: 4.1.4 get-func-name: 2.0.2 - loupe: 2.3.6 + loupe: 2.3.7 pathval: 1.1.1 - type-detect: 4.0.8 + type-detect: 4.1.0 chalk@2.4.2: dependencies: @@ -12655,6 +13887,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.4.1: {} + change-case@4.1.2: dependencies: camel-case: 4.1.2 @@ -12668,22 +13902,43 @@ snapshots: path-case: 3.0.4 sentence-case: 3.0.4 snake-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.8.1 - change-case@5.1.2: {} + change-case@5.4.4: {} character-entities@2.0.2: {} + charenc@0.0.2: {} + check-error@1.0.3: dependencies: get-func-name: 2.0.2 - check-more-types@2.24.0: {} + check-more-types@2.24.0: + optional: true - chokidar@3.5.3: + chokidar@2.1.8: + dependencies: + anymatch: 2.0.0 + async-each: 1.0.6 + braces: 2.3.2 + glob-parent: 3.1.0 + inherits: 2.0.4 + is-binary-path: 1.0.1 + is-glob: 4.0.3 + normalize-path: 3.0.0 + path-is-absolute: 1.0.1 + readdirp: 2.2.1 + upath: 1.2.0 + optionalDependencies: + fsevents: 1.2.13 + transitivePeerDependencies: + - supports-color + + chokidar@3.6.0: dependencies: anymatch: 3.1.3 - braces: 3.0.2 + braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 @@ -12696,13 +13951,24 @@ snapshots: chownr@2.0.0: {} - ci-info@3.8.0: {} + ci-info@3.9.0: {} - cipher-base@1.0.4: + cipher-base@1.0.6: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 + citty@0.1.6: + dependencies: + consola: 3.4.0 + + class-utils@0.3.6: + dependencies: + arr-union: 3.1.0 + define-property: 0.2.5 + isobject: 3.0.1 + static-extend: 0.1.2 + classnames@2.5.1: {} clean-regexp@1.0.0: @@ -12715,9 +13981,9 @@ snapshots: dependencies: restore-cursor: 3.1.0 - cli-spinners@2.9.1: {} + cli-spinners@2.9.2: {} - cli-table3@0.6.3: + cli-table3@0.6.5: dependencies: string-width: 4.2.3 optionalDependencies: @@ -12727,12 +13993,7 @@ snapshots: dependencies: slice-ansi: 3.0.0 string-width: 4.2.3 - - cliui@7.0.4: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 + optional: true cliui@8.0.1: dependencies: @@ -12750,9 +14011,10 @@ snapshots: clsx@1.1.1: {} - clsx@2.1.1: {} - - color-convert@0.5.3: {} + collection-visit@1.0.0: + dependencies: + map-visit: 1.0.0 + object-visit: 1.0.1 color-convert@1.9.3: dependencies: @@ -12762,8 +14024,6 @@ snapshots: dependencies: color-name: 1.1.4 - color-diff@1.4.0: {} - color-name@1.1.3: {} color-name@1.1.4: {} @@ -12773,14 +14033,16 @@ snapshots: color-name: 1.1.4 simple-swizzle: 0.2.2 - color-support@1.1.3: {} + color-support@1.1.3: + optional: true color@4.2.3: dependencies: color-convert: 2.0.1 color-string: 1.9.1 - colorette@2.0.20: {} + colorette@2.0.20: + optional: true colors@1.4.0: {} @@ -12790,7 +14052,8 @@ snapshots: commander@2.20.3: {} - commander@5.1.0: {} + commander@5.1.0: + optional: true commander@6.2.1: {} @@ -12798,26 +14061,29 @@ snapshots: commondir@1.0.1: {} - component-bind@1.0.0: {} + component-bind@1.0.0: + optional: true - component-emitter@1.2.1: {} + component-emitter@1.2.1: + optional: true - component-emitter@1.3.0: {} + component-emitter@1.3.1: {} - component-inherit@0.0.3: {} + component-inherit@0.0.3: + optional: true compressible@2.0.18: dependencies: - mime-db: 1.52.0 + mime-db: 1.54.0 - compression@1.7.4: + compression@1.8.0: dependencies: - accepts: 1.3.8 - bytes: 3.0.0 + bytes: 3.1.2 compressible: 2.0.18 debug: 2.6.9 + negotiator: 0.6.4 on-headers: 1.0.2 - safe-buffer: 5.1.2 + safe-buffer: 5.2.1 vary: 1.1.2 transitivePeerDependencies: - supports-color @@ -12831,14 +14097,30 @@ snapshots: readable-stream: 2.3.8 typedarray: 0.0.6 + confbox@0.1.8: {} + confusing-browser-globals@1.0.11: {} - console-control-strings@1.1.0: {} + connect@3.7.0: + dependencies: + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + transitivePeerDependencies: + - supports-color + + consola@3.4.0: {} + + console-browserify@1.2.0: {} + + console-control-strings@1.1.0: + optional: true constant-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.8.1 upper-case: 2.0.2 constants-browserify@1.0.0: {} @@ -12849,14 +14131,14 @@ snapshots: content-type@1.0.5: {} - contro-max@0.1.8(typescript@5.5.0-beta): + contro-max@0.1.9(typescript@5.5.4): dependencies: events: 3.3.0 lodash-es: 4.17.21 typed-emitter: 2.1.0 optionalDependencies: - react: 18.2.0 - use-typed-event-listener: 4.0.2(react@18.2.0)(typescript@5.5.0-beta) + react: 18.3.1 + use-typed-event-listener: 4.0.2(react@18.3.1)(typescript@5.5.4) transitivePeerDependencies: - typescript @@ -12866,21 +14148,27 @@ snapshots: cookie-signature@1.0.6: {} - cookie@0.4.2: {} + cookie@0.4.2: + optional: true - cookie@0.5.0: {} + cookie@0.7.1: {} + + cookie@0.7.2: {} + + copy-descriptor@0.1.1: {} copy-to-clipboard@3.3.3: dependencies: toggle-selection: 1.0.6 - core-js-compat@3.32.1: + core-js-compat@3.41.0: dependencies: - browserslist: 4.21.10 + browserslist: 4.24.4 - core-js@3.32.1: {} + core-js@3.41.0: {} - core-util-is@1.0.2: {} + core-util-is@1.0.2: + optional: true core-util-is@1.0.3: {} @@ -12893,20 +14181,20 @@ snapshots: cosmiconfig@7.1.0: dependencies: - '@types/parse-json': 4.0.0 - import-fresh: 3.3.0 + '@types/parse-json': 4.0.2 + import-fresh: 3.3.1 parse-json: 5.2.0 path-type: 4.0.0 yaml: 1.10.2 create-ecdh@4.0.4: dependencies: - bn.js: 4.12.0 - elliptic: 6.5.4 + bn.js: 4.12.1 + elliptic: 6.6.1 create-hash@1.2.0: dependencies: - cipher-base: 1.0.4 + cipher-base: 1.0.6 inherits: 2.0.4 md5.js: 1.3.5 ripemd160: 2.0.2 @@ -12914,7 +14202,7 @@ snapshots: create-hmac@1.1.7: dependencies: - cipher-base: 1.0.4 + cipher-base: 1.0.6 create-hash: 1.2.0 inherits: 2.0.4 ripemd160: 2.0.2 @@ -12923,7 +14211,7 @@ snapshots: crelt@1.0.6: {} - cross-spawn@6.0.5: + cross-spawn@6.0.6: dependencies: nice-try: 1.0.5 path-key: 2.0.1 @@ -12931,20 +14219,23 @@ snapshots: shebang-command: 1.2.0 which: 1.3.1 - cross-spawn@7.0.3: + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - crypto-browserify@3.12.0: + crypt@0.0.2: {} + + crypto-browserify@3.12.1: dependencies: browserify-cipher: 1.0.1 - browserify-sign: 4.2.1 + browserify-sign: 4.2.3 create-ecdh: 4.0.4 create-hash: 1.2.0 create-hmac: 1.1.7 diffie-hellman: 5.0.3 + hash-base: 3.0.5 inherits: 2.0.4 pbkdf2: 3.1.2 public-encrypt: 4.0.3 @@ -12955,14 +14246,14 @@ snapshots: css-in-js-utils@3.1.0: dependencies: - hyphenate-style-name: 1.0.4 + hyphenate-style-name: 1.1.0 css-select@5.1.0: dependencies: boolbase: 1.0.0 css-what: 6.1.0 domhandler: 5.0.3 - domutils: 3.1.0 + domutils: 3.2.2 nth-check: 2.1.1 css-tree@1.1.3: @@ -12972,17 +14263,17 @@ snapshots: css-what@6.1.0: {} - csstype@3.1.2: {} + csstype@3.1.3: {} cypress-esbuild-preprocessor@1.0.2: {} - cypress-plugin-snapshots@1.4.4(cypress@10.11.0): + cypress-plugin-snapshots@1.4.4(cypress@10.11.0)(debug@4.4.0): dependencies: cypress: 10.11.0 diff2html: 2.12.2 fs-extra: 7.0.1 image-size: 0.7.5 - jimp: 0.10.3 + jimp: 0.10.3(debug@4.4.0) js-base64: 2.6.4 lodash: 4.17.21 pixelmatch: 4.0.2 @@ -12990,35 +14281,37 @@ snapshots: prettier: 1.19.1 rimraf: 2.7.1 sanitize-filename: 1.6.3 - socket.io: 2.5.0 + socket.io: 2.5.1 socket.io-client: 2.5.0 source-map-support: 0.5.21 unidiff: 1.0.2 transitivePeerDependencies: - bufferutil + - debug - supports-color - utf-8-validate + optional: true cypress@10.11.0: dependencies: '@cypress/request': 2.88.12 '@cypress/xvfb': 1.2.4(supports-color@8.1.1) - '@types/node': 14.18.56 + '@types/node': 14.18.63 '@types/sinonjs__fake-timers': 8.1.1 - '@types/sizzle': 2.3.3 + '@types/sizzle': 2.3.9 arch: 2.2.0 blob-util: 2.0.2 bluebird: 3.7.2 - buffer: 5.7.1 + buffer: 6.0.3 cachedir: 2.4.0 chalk: 4.1.2 check-more-types: 2.24.0 cli-cursor: 3.1.0 - cli-table3: 0.6.3 + cli-table3: 0.6.5 commander: 5.1.0 common-tags: 1.8.2 - dayjs: 1.11.9 - debug: 4.3.4(supports-color@8.1.1) + dayjs: 1.11.13 + debug: 4.4.0(supports-color@8.1.1) enquirer: 2.4.1 eventemitter2: 6.4.7 execa: 4.1.0 @@ -13038,35 +14331,38 @@ snapshots: pretty-bytes: 5.6.0 proxy-from-env: 1.0.0 request-progress: 3.0.0 - semver: 7.6.0 + semver: 7.7.1 supports-color: 8.1.1 - tmp: 0.2.1 + tmp: 0.2.3 untildify: 4.0.0 yauzl: 2.10.0 + optional: true dashdash@1.14.1: dependencies: assert-plus: 1.0.0 + optional: true - data-view-buffer@1.0.1: + data-view-buffer@1.0.2: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - is-data-view: 1.0.1 + is-data-view: 1.0.2 - data-view-byte-length@1.0.1: + data-view-byte-length@1.0.2: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - is-data-view: 1.0.1 + is-data-view: 1.0.2 - data-view-byte-offset@1.0.0: + data-view-byte-offset@1.0.1: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - is-data-view: 1.0.1 + is-data-view: 1.0.2 - dayjs@1.11.9: {} + dayjs@1.11.13: + optional: true debounce@1.2.1: {} @@ -13077,6 +14373,7 @@ snapshots: debug@3.1.0: dependencies: ms: 2.0.0 + optional: true debug@3.2.7(supports-color@8.1.1): dependencies: @@ -13087,13 +14384,22 @@ snapshots: debug@4.1.1: dependencies: ms: 2.1.3 + optional: true - debug@4.3.4(supports-color@8.1.1): + debug@4.3.7: dependencies: - ms: 2.1.2 + ms: 2.1.3 + + debug@4.4.0(supports-color@8.1.1): + dependencies: + ms: 2.1.3 optionalDependencies: supports-color: 8.1.1 + debug@4.4.1: + dependencies: + ms: 2.1.3 + decamelize-keys@1.1.1: dependencies: decamelize: 1.2.0 @@ -13103,21 +14409,24 @@ snapshots: decamelize@5.0.1: {} - decode-named-character-reference@1.0.2: + decode-named-character-reference@1.1.0: dependencies: character-entities: 2.0.2 + decode-uri-component@0.2.2: {} + decompress-response@4.2.1: dependencies: mimic-response: 2.1.0 + optional: true decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 - deep-eql@4.1.3: + deep-eql@4.1.4: dependencies: - type-detect: 4.0.8 + type-detect: 4.1.0 deep-extend@0.6.0: {} @@ -13125,6 +14434,12 @@ snapshots: deepmerge@4.3.1: {} + deepslate@0.23.5: + dependencies: + gl-matrix: 3.4.3 + md5: 2.3.0 + pako: 2.1.0 + default-browser-id@3.0.0: dependencies: bplist-parser: 0.2.0 @@ -13134,27 +14449,34 @@ snapshots: dependencies: clone: 1.0.4 - define-data-property@1.1.0: - dependencies: - get-intrinsic: 1.2.1 - gopd: 1.0.1 - has-property-descriptors: 1.0.0 - define-data-property@1.1.4: dependencies: - es-define-property: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 - gopd: 1.0.1 + gopd: 1.2.0 define-lazy-prop@2.0.0: {} define-properties@1.2.1: dependencies: - define-data-property: 1.1.0 - has-property-descriptors: 1.0.0 + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 object-keys: 1.1.1 - defu@6.1.2: {} + define-property@0.2.5: + dependencies: + is-descriptor: 0.1.7 + + define-property@1.0.0: + dependencies: + is-descriptor: 1.0.3 + + define-property@2.0.2: + dependencies: + is-descriptor: 1.0.3 + isobject: 3.0.1 + + defu@6.1.4: {} del@6.1.1: dependencies: @@ -13169,14 +14491,19 @@ snapshots: delayed-stream@1.0.0: {} - delegates@1.0.0: {} + delegates@1.0.0: + optional: true + + depd@1.1.2: {} depd@2.0.0: {} - dequal@1.0.0: {} - dequal@2.0.3: {} + derive-valtio@0.1.0(valtio@1.13.2(@types/react@18.3.18)(react@18.3.1)): + dependencies: + valtio: 1.13.2(@types/react@18.3.18)(react@18.3.1) + des.js@1.1.0: dependencies: inherits: 2.0.4 @@ -13186,7 +14513,7 @@ snapshots: detect-collisions@7.0.5: dependencies: - '@types/rbush': 3.0.1 + '@types/rbush': 3.0.4 '@types/sat': 0.0.31 poly-decomp: 0.3.0 rbush: 3.0.1 @@ -13194,7 +14521,7 @@ snapshots: detect-indent@6.1.0: {} - detect-libc@2.0.2: {} + detect-libc@2.0.3: {} detect-node-es@1.1.0: {} @@ -13202,10 +14529,10 @@ snapshots: dependencies: execa: 5.1.1 - detect-port@1.5.1: + detect-port@1.6.1: dependencies: address: 1.2.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -13213,12 +14540,15 @@ 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/cfaad2d1d5909fdfa63c8cc7bc05fb5e87782d71: dependencies: - minecraft-data: 3.65.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) + minecraft-data: 3.98.0 + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0) + prismarine-registry: 1.11.0 random-seed: 0.3.0 - vec3: 0.1.8 + vec3: 0.1.10 + + diff-match-patch@1.0.5: {} diff-sequences@29.6.3: {} @@ -13227,15 +14557,18 @@ snapshots: diff: 4.0.2 hogan.js: 3.0.2 merge: 1.2.1 - whatwg-fetch: 3.6.18 + whatwg-fetch: 3.6.20 + optional: true - diff@2.2.3: {} + diff@2.2.3: + optional: true - diff@4.0.2: {} + diff@4.0.2: + optional: true diffie-hellman@5.0.3: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.1 miller-rabin: 4.0.1 randombytes: 2.1.0 @@ -13255,8 +14588,8 @@ snapshots: dom-helpers@5.2.1: dependencies: - '@babel/runtime': 7.22.11 - csstype: 3.1.2 + '@babel/runtime': 7.26.9 + csstype: 3.1.3 dom-serializer@2.0.0: dependencies: @@ -13264,7 +14597,10 @@ snapshots: domhandler: 5.0.3 entities: 4.5.0 - dom-walk@0.1.2: {} + dom-walk@0.1.2: + optional: true + + domain-browser@5.7.0: {} domelementtype@2.3.0: {} @@ -13272,7 +14608,7 @@ snapshots: dependencies: domelementtype: 2.3.0 - domutils@3.1.0: + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 domelementtype: 2.3.0 @@ -13281,20 +14617,28 @@ snapshots: dot-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.8.1 dotenv-expand@10.0.0: {} - dotenv@16.3.1: {} + dotenv@16.4.7: {} - draco3d@1.5.6: {} + draco3d@1.5.7: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer@0.1.2: {} duplexify@3.7.1: dependencies: end-of-stream: 1.4.4 inherits: 2.0.4 readable-stream: 2.3.8 - stream-shift: 1.0.1 + stream-shift: 1.0.3 eastasianwidth@0.2.0: {} @@ -13302,6 +14646,7 @@ snapshots: dependencies: jsbn: 0.1.1 safer-buffer: 2.1.2 + optional: true ecdsa-sig-formatter@1.0.11: dependencies: @@ -13309,15 +14654,15 @@ snapshots: ee-first@1.1.1: {} - ejs@3.1.9: + ejs@3.1.10: dependencies: - jake: 10.8.7 + jake: 10.9.2 - electron-to-chromium@1.4.504: {} + electron-to-chromium@1.5.113: {} - elliptic@6.5.4: + elliptic@6.6.1: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.1 brorand: 1.1.0 hash.js: 1.1.7 hmac-drbg: 1.0.1 @@ -13333,6 +14678,8 @@ snapshots: encodeurl@1.0.2: {} + encodeurl@2.0.0: {} + encoding@0.1.13: dependencies: iconv-lite: 0.6.3 @@ -13344,9 +14691,9 @@ snapshots: endian-toggle@0.0.0: {} - engine.io-client@3.5.3: + engine.io-client@3.5.4: dependencies: - component-emitter: 1.3.0 + component-emitter: 1.3.1 component-inherit: 0.0.3 debug: 3.1.0 engine.io-parser: 2.2.1 @@ -13354,21 +14701,22 @@ snapshots: indexof: 0.0.1 parseqs: 0.0.6 parseuri: 0.0.6 - ws: 7.4.6 + ws: 7.5.10 xmlhttprequest-ssl: 1.6.3 yeast: 0.1.2 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate + optional: true - engine.io-client@6.5.2: + engine.io-client@6.6.3: dependencies: - '@socket.io/component-emitter': 3.1.0 - debug: 4.3.4(supports-color@8.1.1) - engine.io-parser: 5.2.1 - ws: 8.11.0 - xmlhttprequest-ssl: 2.0.0 + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.7 + engine.io-parser: 5.2.3 + ws: 8.17.1 + xmlhttprequest-ssl: 2.1.2 transitivePeerDependencies: - bufferutil - supports-color @@ -13381,34 +14729,35 @@ snapshots: base64-arraybuffer: 0.1.4 blob: 0.0.5 has-binary2: 1.0.3 + optional: true - engine.io-parser@5.2.1: {} + engine.io-parser@5.2.3: {} - engine.io@3.6.1: + engine.io@3.6.2: dependencies: accepts: 1.3.8 base64id: 2.0.0 cookie: 0.4.2 debug: 4.1.1 engine.io-parser: 2.2.1 - ws: 7.4.6 + ws: 7.5.10 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate + optional: true - engine.io@6.5.3: + engine.io@6.6.4: dependencies: - '@types/cookie': 0.4.1 - '@types/cors': 2.8.15 - '@types/node': 20.12.8 + '@types/cors': 2.8.17 + '@types/node': 22.13.9 accepts: 1.3.8 base64id: 2.0.0 - cookie: 0.4.2 + cookie: 0.7.2 cors: 2.8.5 - debug: 4.3.4(supports-color@8.1.1) - engine.io-parser: 5.2.1 - ws: 8.11.0 + debug: 4.3.7 + engine.io-parser: 5.2.3 + ws: 8.17.1 transitivePeerDependencies: - bufferutil - supports-color @@ -13418,13 +14767,14 @@ snapshots: dependencies: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + optional: true entities@4.5.0: {} env-paths@2.2.1: optional: true - envinfo@7.10.0: {} + envinfo@7.14.0: {} err-code@2.0.3: optional: true @@ -13437,155 +14787,164 @@ snapshots: dependencies: stackframe: 1.3.4 - eruda@3.0.1: {} + eruda@3.4.1: {} - es-abstract@1.22.2: + es-abstract@1.23.9: dependencies: - array-buffer-byte-length: 1.0.0 - arraybuffer.prototype.slice: 1.0.2 - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - es-set-tostringtag: 2.0.1 - es-to-primitive: 1.2.1 - function.prototype.name: 1.1.6 - get-intrinsic: 1.2.1 - get-symbol-description: 1.0.0 - globalthis: 1.0.3 - gopd: 1.0.1 - has: 1.0.3 - has-property-descriptors: 1.0.0 - has-proto: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.5 - is-array-buffer: 3.0.2 - is-callable: 1.2.7 - is-negative-zero: 2.0.2 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - is-string: 1.0.7 - is-typed-array: 1.1.12 - is-weakref: 1.0.2 - object-inspect: 1.12.3 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.5.1 - safe-array-concat: 1.0.1 - safe-regex-test: 1.0.0 - string.prototype.trim: 1.2.8 - string.prototype.trimend: 1.0.7 - string.prototype.trimstart: 1.0.7 - typed-array-buffer: 1.0.0 - typed-array-byte-length: 1.0.0 - typed-array-byte-offset: 1.0.0 - typed-array-length: 1.0.4 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.11 - - es-abstract@1.23.3: - dependencies: - array-buffer-byte-length: 1.0.1 - arraybuffer.prototype.slice: 1.0.3 + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 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 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 es-errors: 1.3.0 - 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 - get-symbol-description: 1.0.2 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 globalthis: 1.0.4 - gopd: 1.0.1 + gopd: 1.2.0 has-property-descriptors: 1.0.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 + has-proto: 1.2.0 + has-symbols: 1.1.0 hasown: 2.0.2 - internal-slot: 1.0.7 - is-array-buffer: 3.0.4 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 is-callable: 1.2.7 - is-data-view: 1.0.1 - is-negative-zero: 2.0.3 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.3 - is-string: 1.0.7 - is-typed-array: 1.1.13 - is-weakref: 1.0.2 - object-inspect: 1.13.1 + is-data-view: 1.0.2 + is-regex: 1.2.1 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 object-keys: 1.1.1 - object.assign: 4.1.5 - regexp.prototype.flags: 1.5.2 - safe-array-concat: 1.1.2 - safe-regex-test: 1.0.3 - string.prototype.trim: 1.2.9 - string.prototype.trimend: 1.0.8 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 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.15 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.18 - es-define-property@1.0.0: + es-abstract@1.24.0: dependencies: - get-intrinsic: 1.2.4 + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} es-errors@1.3.0: {} - es-iterator-helpers@1.0.19: + es-iterator-helpers@1.2.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.24.0 es-errors: 1.3.0 - es-set-tostringtag: 2.0.3 + es-set-tostringtag: 2.1.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 globalthis: 1.0.4 + gopd: 1.2.0 has-property-descriptors: 1.0.2 - 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.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 es-module-lexer@0.9.3: {} - es-object-atoms@1.0.0: + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 - es-set-tostringtag@2.0.1: + es-set-tostringtag@2.1.0: dependencies: - get-intrinsic: 1.2.1 - has: 1.0.3 - has-tostringtag: 1.0.0 - - es-set-tostringtag@2.0.3: - dependencies: - get-intrinsic: 1.2.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 hasown: 2.0.2 - es-shim-unscopables@1.0.0: - dependencies: - has: 1.0.3 - - es-shim-unscopables@1.0.2: + es-shim-unscopables@1.1.0: dependencies: hasown: 2.0.2 - es-to-primitive@1.2.1: + es-to-primitive@1.3.0: dependencies: is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 - - es6-object-assign@1.1.0: {} + is-date-object: 1.1.0 + is-symbol: 1.1.1 es6-promise@4.2.8: {} @@ -13595,15 +14954,15 @@ snapshots: esbuild-plugin-alias@0.2.1: {} - esbuild-plugin-polyfill-node@0.3.0(esbuild@0.19.3): + esbuild-plugin-polyfill-node@0.3.0(esbuild@0.19.12): dependencies: - '@jspm/core': 2.0.1 - esbuild: 0.19.3 - import-meta-resolve: 3.0.0 + '@jspm/core': 2.1.0 + esbuild: 0.19.12 + import-meta-resolve: 3.1.1 - esbuild-register@3.5.0(esbuild@0.18.20): + esbuild-register@3.6.0(esbuild@0.18.20): dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) esbuild: 0.18.20 transitivePeerDependencies: - supports-color @@ -13633,58 +14992,61 @@ snapshots: '@esbuild/win32-ia32': 0.18.20 '@esbuild/win32-x64': 0.18.20 - esbuild@0.19.11: + esbuild@0.19.12: optionalDependencies: - '@esbuild/aix-ppc64': 0.19.11 - '@esbuild/android-arm': 0.19.11 - '@esbuild/android-arm64': 0.19.11 - '@esbuild/android-x64': 0.19.11 - '@esbuild/darwin-arm64': 0.19.11 - '@esbuild/darwin-x64': 0.19.11 - '@esbuild/freebsd-arm64': 0.19.11 - '@esbuild/freebsd-x64': 0.19.11 - '@esbuild/linux-arm': 0.19.11 - '@esbuild/linux-arm64': 0.19.11 - '@esbuild/linux-ia32': 0.19.11 - '@esbuild/linux-loong64': 0.19.11 - '@esbuild/linux-mips64el': 0.19.11 - '@esbuild/linux-ppc64': 0.19.11 - '@esbuild/linux-riscv64': 0.19.11 - '@esbuild/linux-s390x': 0.19.11 - '@esbuild/linux-x64': 0.19.11 - '@esbuild/netbsd-x64': 0.19.11 - '@esbuild/openbsd-x64': 0.19.11 - '@esbuild/sunos-x64': 0.19.11 - '@esbuild/win32-arm64': 0.19.11 - '@esbuild/win32-ia32': 0.19.11 - '@esbuild/win32-x64': 0.19.11 + '@esbuild/aix-ppc64': 0.19.12 + '@esbuild/android-arm': 0.19.12 + '@esbuild/android-arm64': 0.19.12 + '@esbuild/android-x64': 0.19.12 + '@esbuild/darwin-arm64': 0.19.12 + '@esbuild/darwin-x64': 0.19.12 + '@esbuild/freebsd-arm64': 0.19.12 + '@esbuild/freebsd-x64': 0.19.12 + '@esbuild/linux-arm': 0.19.12 + '@esbuild/linux-arm64': 0.19.12 + '@esbuild/linux-ia32': 0.19.12 + '@esbuild/linux-loong64': 0.19.12 + '@esbuild/linux-mips64el': 0.19.12 + '@esbuild/linux-ppc64': 0.19.12 + '@esbuild/linux-riscv64': 0.19.12 + '@esbuild/linux-s390x': 0.19.12 + '@esbuild/linux-x64': 0.19.12 + '@esbuild/netbsd-x64': 0.19.12 + '@esbuild/openbsd-x64': 0.19.12 + '@esbuild/sunos-x64': 0.19.12 + '@esbuild/win32-arm64': 0.19.12 + '@esbuild/win32-ia32': 0.19.12 + '@esbuild/win32-x64': 0.19.12 - esbuild@0.19.3: + esbuild@0.25.0: optionalDependencies: - '@esbuild/android-arm': 0.19.3 - '@esbuild/android-arm64': 0.19.3 - '@esbuild/android-x64': 0.19.3 - '@esbuild/darwin-arm64': 0.19.3 - '@esbuild/darwin-x64': 0.19.3 - '@esbuild/freebsd-arm64': 0.19.3 - '@esbuild/freebsd-x64': 0.19.3 - '@esbuild/linux-arm': 0.19.3 - '@esbuild/linux-arm64': 0.19.3 - '@esbuild/linux-ia32': 0.19.3 - '@esbuild/linux-loong64': 0.19.3 - '@esbuild/linux-mips64el': 0.19.3 - '@esbuild/linux-ppc64': 0.19.3 - '@esbuild/linux-riscv64': 0.19.3 - '@esbuild/linux-s390x': 0.19.3 - '@esbuild/linux-x64': 0.19.3 - '@esbuild/netbsd-x64': 0.19.3 - '@esbuild/openbsd-x64': 0.19.3 - '@esbuild/sunos-x64': 0.19.3 - '@esbuild/win32-arm64': 0.19.3 - '@esbuild/win32-ia32': 0.19.3 - '@esbuild/win32-x64': 0.19.3 + '@esbuild/aix-ppc64': 0.25.0 + '@esbuild/android-arm': 0.25.0 + '@esbuild/android-arm64': 0.25.0 + '@esbuild/android-x64': 0.25.0 + '@esbuild/darwin-arm64': 0.25.0 + '@esbuild/darwin-x64': 0.25.0 + '@esbuild/freebsd-arm64': 0.25.0 + '@esbuild/freebsd-x64': 0.25.0 + '@esbuild/linux-arm': 0.25.0 + '@esbuild/linux-arm64': 0.25.0 + '@esbuild/linux-ia32': 0.25.0 + '@esbuild/linux-loong64': 0.25.0 + '@esbuild/linux-mips64el': 0.25.0 + '@esbuild/linux-ppc64': 0.25.0 + '@esbuild/linux-riscv64': 0.25.0 + '@esbuild/linux-s390x': 0.25.0 + '@esbuild/linux-x64': 0.25.0 + '@esbuild/netbsd-arm64': 0.25.0 + '@esbuild/netbsd-x64': 0.25.0 + '@esbuild/openbsd-arm64': 0.25.0 + '@esbuild/openbsd-x64': 0.25.0 + '@esbuild/sunos-x64': 0.25.0 + '@esbuild/win32-arm64': 0.25.0 + '@esbuild/win32-ia32': 0.25.0 + '@esbuild/win32-x64': 0.25.0 - escalade@3.1.1: {} + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -13700,44 +15062,44 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-prettier@8.10.0(eslint@8.50.0): + eslint-config-prettier@8.10.0(eslint@8.57.1): dependencies: - eslint: 8.50.0 + eslint: 8.57.1 - 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-react@0.27.0(eslint-plugin-react-hooks@5.2.0(eslint@8.57.1))(eslint-plugin-react@7.37.4(eslint@8.57.1))(eslint@8.57.1): dependencies: - 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) + eslint: 8.57.1 + eslint-plugin-react: 7.37.4(eslint@8.57.1) + eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) - 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-config-xo-typescript@1.0.1(@typescript-eslint/eslint-plugin@6.1.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4): dependencies: - '@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 + '@typescript-eslint/eslint-plugin': 6.1.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.5.4) + eslint: 8.57.1 + typescript: 5.5.4 - eslint-config-xo@0.43.1(eslint@8.50.0): + eslint-config-xo@0.43.1(eslint@8.57.1): dependencies: confusing-browser-globals: 1.0.11 - eslint: 8.50.0 + eslint: 8.57.1 - 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): + eslint-config-zardoy@0.2.17(eslint-plugin-react-hooks@5.2.0(eslint@8.57.1))(eslint-plugin-react@7.37.4(eslint@8.57.1))(eslint@8.57.1)(typescript@5.5.4): 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.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.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.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.5.0-beta + '@rushstack/eslint-patch': 1.10.5 + '@typescript-eslint/eslint-plugin': 6.1.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.5.4) + eslint: 8.57.1 + eslint-config-prettier: 8.10.0(eslint@8.57.1) + eslint-config-xo: 0.43.1(eslint@8.57.1) + eslint-config-xo-react: 0.27.0(eslint-plugin-react-hooks@5.2.0(eslint@8.57.1))(eslint-plugin-react@7.37.4(eslint@8.57.1))(eslint@8.57.1) + eslint-config-xo-typescript: 1.0.1(@typescript-eslint/eslint-plugin@6.1.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4) + eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.1) + eslint-plugin-import: 2.27.5(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1) + eslint-plugin-node: 11.1.0(eslint@8.57.1) + eslint-plugin-sonarjs: 0.19.0(eslint@8.57.1) + eslint-plugin-unicorn: 48.0.0(eslint@8.57.1) + typescript: 5.5.4 transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -13748,115 +15110,115 @@ snapshots: eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7(supports-color@8.1.1) - is-core-module: 2.13.0 - resolve: 1.22.4 + is-core-module: 2.16.1 + resolve: 1.22.10 transitivePeerDependencies: - supports-color - 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): + eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.5.0-beta) - eslint: 8.50.0 + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.5.4) + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-es@3.0.1(eslint@8.50.0): + eslint-plugin-es@3.0.1(eslint@8.57.1): dependencies: - eslint: 8.50.0 + eslint: 8.57.1 eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-eslint-comments@3.2.0(eslint@8.50.0): + eslint-plugin-eslint-comments@3.2.0(eslint@8.57.1): dependencies: escape-string-regexp: 1.0.5 - eslint: 8.50.0 - ignore: 5.2.4 + eslint: 8.57.1 + ignore: 5.3.2 - 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-import@2.27.5(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1): dependencies: - array-includes: 3.1.7 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 + array-includes: 3.1.8 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 debug: 3.2.7(supports-color@8.1.1) doctrine: 2.1.0 - eslint: 8.50.0 + eslint: 8.57.1 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.5.0-beta))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0) - has: 1.0.3 - is-core-module: 2.13.0 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) + has: 1.0.4 + is-core-module: 2.16.1 is-glob: 4.0.3 minimatch: 3.1.2 - object.values: 1.1.7 - resolve: 1.22.4 + object.values: 1.2.1 + resolve: 1.22.10 semver: 6.3.1 - tsconfig-paths: 3.14.2 + tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.5.0-beta) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.5.4) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-node@11.1.0(eslint@8.50.0): + eslint-plugin-node@11.1.0(eslint@8.57.1): dependencies: - eslint: 8.50.0 - eslint-plugin-es: 3.0.1(eslint@8.50.0) + eslint: 8.57.1 + eslint-plugin-es: 3.0.1(eslint@8.57.1) eslint-utils: 2.1.0 - ignore: 5.2.4 + ignore: 5.3.2 minimatch: 3.1.2 - resolve: 1.22.4 + resolve: 1.22.10 semver: 6.3.1 - eslint-plugin-react-hooks@4.6.0(eslint@8.50.0): + eslint-plugin-react-hooks@5.2.0(eslint@8.57.1): dependencies: - eslint: 8.50.0 + eslint: 8.57.1 - eslint-plugin-react@7.34.1(eslint@8.50.0): + eslint-plugin-react@7.37.4(eslint@8.57.1): dependencies: - array-includes: 3.1.8 + array-includes: 3.1.9 array.prototype.findlast: 1.2.5 - array.prototype.flatmap: 1.3.2 - array.prototype.toreversed: 1.1.2 - array.prototype.tosorted: 1.1.3 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.0.19 - eslint: 8.50.0 + es-iterator-helpers: 1.2.1 + eslint: 8.57.1 estraverse: 5.3.0 + hasown: 2.0.2 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 - object.entries: 1.1.8 + object.entries: 1.1.9 object.fromentries: 2.0.8 - object.hasown: 1.1.4 - object.values: 1.2.0 + object.values: 1.2.1 prop-types: 15.8.1 resolve: 2.0.0-next.5 semver: 6.3.1 - string.prototype.matchall: 4.0.11 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 - eslint-plugin-sonarjs@0.19.0(eslint@8.50.0): + eslint-plugin-sonarjs@0.19.0(eslint@8.57.1): dependencies: - eslint: 8.50.0 + eslint: 8.57.1 - eslint-plugin-unicorn@48.0.0(eslint@8.50.0): + eslint-plugin-unicorn@48.0.0(eslint@8.57.1): dependencies: - '@babel/helper-validator-identifier': 7.22.5 - '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) - ci-info: 3.8.0 + '@babel/helper-validator-identifier': 7.25.9 + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + ci-info: 3.9.0 clean-regexp: 1.0.0 - eslint: 8.50.0 - esquery: 1.5.0 + eslint: 8.57.1 + esquery: 1.6.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 - jsesc: 3.0.2 + jsesc: 3.1.0 lodash: 4.17.21 pluralize: 8.0.0 read-pkg-up: 7.0.1 regexp-tree: 0.1.27 regjsparser: 0.10.0 - semver: 7.5.4 + semver: 7.7.1 strip-indent: 3.0.0 eslint-scope@7.2.2: @@ -13872,33 +15234,36 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint@8.50.0: + eslint-visitor-keys@4.2.0: {} + + eslint@8.57.1: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) - '@eslint-community/regexpp': 4.8.0 - '@eslint/eslintrc': 2.1.2 - '@eslint/js': 8.50.0 - '@humanwhocodes/config-array': 0.11.11 + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.1 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.3.0 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) + cross-spawn: 7.0.6 + debug: 4.4.0(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.5.0 + esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.21.0 + globals: 13.24.0 graphemer: 1.4.0 - ignore: 5.2.4 + ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -13908,21 +15273,27 @@ snapshots: lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.3 + optionator: 0.9.4 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: - supports-color + espree@10.3.0: + dependencies: + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) + eslint-visitor-keys: 4.2.0 + espree@9.6.1: dependencies: - acorn: 8.10.0 - acorn-jsx: 5.3.2(acorn@8.10.0) + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} - esquery@1.5.0: + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -13932,14 +15303,6 @@ snapshots: estraverse@5.3.0: {} - estree-to-babel@3.2.1: - dependencies: - '@babel/traverse': 7.22.11 - '@babel/types': 7.23.0 - c8: 7.14.0 - transitivePeerDependencies: - - supports-color - estree-walker@1.0.1: {} estree-walker@2.0.2: {} @@ -13948,9 +15311,20 @@ snapshots: etag@1.8.1: {} + event-stream@3.3.4: + dependencies: + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.1.0 + pause-stream: 0.0.11 + split: 0.3.3 + stream-combiner: 0.0.4 + through: 2.3.8 + event-target-shim@5.0.1: {} - eventemitter2@6.4.7: {} + eventemitter2@6.4.7: + optional: true eventemitter3@4.0.7: {} @@ -13963,7 +15337,7 @@ snapshots: execa@4.1.0: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 get-stream: 5.2.0 human-signals: 1.1.1 is-stream: 2.0.1 @@ -13972,10 +15346,11 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 strip-final-newline: 2.0.0 + optional: true execa@5.1.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -13988,52 +15363,66 @@ snapshots: executable@4.1.1: dependencies: pify: 2.3.0 + optional: true - exif-parser@0.1.12: {} + exif-parser@0.1.12: + optional: true exit-hook@2.2.1: {} + expand-brackets@2.1.4: + dependencies: + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + posix-character-classes: 0.1.1 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + expand-template@2.0.3: {} - exponential-backoff@3.1.1: + exponential-backoff@3.1.2: optional: true - express-ws@4.0.0(express@4.18.2): + express-ws@4.0.0(express@4.21.2): dependencies: - express: 4.18.2 - ws: 5.2.3 + express: 4.21.2 + ws: 5.2.4 transitivePeerDependencies: - bufferutil - utf-8-validate - express@4.18.2: + express@4.21.2: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.1 + body-parser: 1.20.3 content-disposition: 0.5.4 content-type: 1.0.5 - cookie: 0.5.0 + cookie: 0.7.1 cookie-signature: 1.0.6 debug: 2.6.9 depd: 2.0.0 - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.2.0 + finalhandler: 1.3.1 fresh: 0.5.2 http-errors: 2.0.0 - merge-descriptors: 1.0.1 + merge-descriptors: 1.0.3 methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 - path-to-regexp: 0.1.7 + path-to-regexp: 0.1.12 proxy-addr: 2.0.7 - qs: 6.11.0 + qs: 6.13.0 range-parser: 1.2.1 safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 + send: 0.19.0 + serve-static: 1.16.2 setprototypeof: 1.2.0 statuses: 2.0.1 type-is: 1.6.18 @@ -14042,8 +15431,30 @@ snapshots: transitivePeerDependencies: - supports-color + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + extend-shallow@3.0.2: + dependencies: + assign-symbols: 1.0.0 + is-extendable: 1.0.1 + extend@3.0.2: {} + extglob@2.0.4: + dependencies: + array-unique: 0.3.2 + define-property: 1.0.0 + expand-brackets: 2.1.4 + extend-shallow: 2.0.1 + fragment-cache: 0.2.1 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + extract-zip@1.7.0: dependencies: concat-stream: 1.6.2 @@ -14055,7 +15466,7 @@ snapshots: extract-zip@2.0.1(supports-color@8.1.1): dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -14063,31 +15474,36 @@ snapshots: transitivePeerDependencies: - supports-color - extsprintf@1.3.0: {} + extsprintf@1.3.0: + optional: true fast-deep-equal@3.1.3: {} - fast-glob@3.3.1: + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.8 fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} - fast-loops@1.1.3: {} - fast-shallow-equal@1.0.0: {} + fast-uri@3.0.6: {} + fastest-stable-stringify@2.0.2: {} - fastq@1.15.0: + fastq@1.19.1: dependencies: - reusify: 1.0.4 + reusify: 1.1.0 + + faye-websocket@0.11.4: + dependencies: + websocket-driver: 0.7.4 fb-watchman@2.0.2: dependencies: @@ -14104,17 +15520,19 @@ snapshots: figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 + optional: true file-entry-cache@6.0.1: dependencies: - flat-cache: 3.1.0 + flat-cache: 3.2.0 file-system-cache@2.3.0: dependencies: fs-extra: 11.1.1 ramda: 0.29.0 - file-type@9.0.0: {} + file-type@9.0.0: + optional: true file-uri-to-path@1.0.0: optional: true @@ -14123,17 +15541,36 @@ snapshots: dependencies: minimatch: 5.1.6 - filesize@10.0.12: {} + filesize@10.1.6: {} - fill-range@7.0.1: + fill-range@4.0.0: + dependencies: + extend-shallow: 2.0.1 + is-number: 3.0.0 + repeat-string: 1.6.1 + to-regex-range: 2.1.1 + + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - finalhandler@1.2.0: + finalhandler@1.1.2: dependencies: debug: 2.6.9 encodeurl: 1.0.2 escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + finalhandler@1.3.1: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 statuses: 2.0.1 @@ -14169,84 +15606,98 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - flat-cache@3.1.0: + flat-cache@3.2.0: dependencies: - flatted: 3.2.7 - keyv: 4.5.3 + flatted: 3.3.3 + keyv: 4.5.4 rimraf: 3.0.2 flatmap@0.0.3: {} - flatted@3.2.7: {} + flatted@3.3.3: {} - flow-parser@0.218.0: {} + flow-parser@0.263.0: {} - follow-redirects@1.15.3(debug@4.3.4): + follow-redirects@1.15.9(debug@4.4.0): optionalDependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) - follow-redirects@1.15.6(debug@4.3.4): - optionalDependencies: - debug: 4.3.4(supports-color@8.1.1) - - for-each@0.3.3: + for-each@0.3.5: dependencies: is-callable: 1.2.7 - foreground-child@2.0.0: - dependencies: - cross-spawn: 7.0.3 - signal-exit: 3.0.7 + for-in@1.0.2: {} - foreground-child@3.1.1: + foreground-child@3.3.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 4.1.0 - forever-agent@0.6.1: {} + forever-agent@0.6.1: + optional: true form-data@2.3.3: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 + optional: true - form-data@4.0.0: + form-data@4.0.2: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 mime-types: 2.1.35 forwarded@0.2.0: {} + fragment-cache@0.2.1: + dependencies: + map-cache: 0.2.2 + + framer-motion@12.9.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + motion-dom: 12.9.1 + motion-utils: 12.8.3 + tslib: 2.8.1 + optionalDependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + fresh@0.5.2: {} + fresh@2.0.0: {} + + from@0.1.7: {} + fs-constants@1.0.0: {} fs-extra@11.1.1: dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 - universalify: 2.0.0 + universalify: 2.0.1 + + fs-extra@11.3.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 jsonfile: 4.0.0 universalify: 0.1.2 - - fs-extra@8.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 + optional: true fs-extra@9.1.0: dependencies: at-least-node: 1.0.0 graceful-fs: 4.2.11 jsonfile: 6.1.0 - universalify: 2.0.0 + universalify: 2.0.1 fs-minipass@2.1.0: dependencies: @@ -14254,19 +15705,25 @@ snapshots: fs.realpath@1.0.0: {} + fsevents@1.2.13: + dependencies: + bindings: 1.5.0 + nan: 2.22.2 + optional: true + fsevents@2.3.3: optional: true - function-bind@1.1.1: {} - function-bind@1.1.2: {} - function.prototype.name@1.1.6: + function.prototype.name@1.1.8: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.22.2 functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 functions-have-names@1.2.3: {} @@ -14281,6 +15738,7 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 wide-align: 1.1.5 + optional: true gauge@4.0.4: dependencies: @@ -14300,24 +15758,22 @@ snapshots: get-func-name@2.0.2: {} - get-intrinsic@1.2.1: - dependencies: - function-bind: 1.1.1 - has: 1.0.3 - has-proto: 1.0.1 - has-symbols: 1.0.3 - - get-intrinsic@1.2.4: + get-intrinsic@1.3.0: dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 es-errors: 1.3.0 + es-object-atoms: 1.1.1 function-bind: 1.1.2 - has-proto: 1.0.1 - has-symbols: 1.0.3 - hasown: 2.0.1 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 get-nonce@1.0.1: {} - get-npm-tarball-url@2.0.3: {} + get-npm-tarball-url@2.1.0: {} get-own-enumerable-property-symbols@3.0.2: {} @@ -14325,65 +15781,74 @@ snapshots: get-port@5.1.1: {} + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + get-stream@5.2.0: dependencies: - pump: 3.0.0 + pump: 3.0.2 get-stream@6.0.1: {} - get-symbol-description@1.0.0: + get-symbol-description@1.1.0: dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - - get-symbol-description@1.0.2: - dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 - get-tsconfig@4.7.2: + get-tsconfig@4.10.0: dependencies: resolve-pkg-maps: 1.0.0 + get-value@2.0.6: {} + getos@3.2.1: dependencies: - async: 3.2.5 + async: 3.2.6 + optional: true getpass@0.1.7: dependencies: assert-plus: 1.0.0 + optional: true - giget@1.1.3: + giget@1.2.5: dependencies: - colorette: 2.0.20 - defu: 6.1.2 - https-proxy-agent: 7.0.2 - mri: 1.2.0 - node-fetch-native: 1.4.0 - pathe: 1.1.1 - tar: 6.2.0 - transitivePeerDependencies: - - supports-color + citty: 0.1.6 + consola: 3.4.0 + defu: 6.1.4 + node-fetch-native: 1.6.6 + nypm: 0.5.4 + pathe: 2.0.3 + tar: 6.2.1 github-from-package@0.0.0: {} github-slugger@1.5.0: {} + gl-matrix@3.4.3: {} + gl@6.0.2: dependencies: bindings: 1.5.0 bit-twiddle: 1.0.2 glsl-tokenizer: 2.1.5 - nan: 2.18.0 - node-abi: 3.47.0 + nan: 2.22.2 + node-abi: 3.74.0 node-gyp: 9.4.1 - prebuild-install: 7.1.1 + prebuild-install: 7.1.3 transitivePeerDependencies: - bluebird - supports-color optional: true + glob-parent@3.1.0: + dependencies: + is-glob: 3.1.0 + path-dirname: 1.0.2 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -14399,13 +15864,14 @@ snapshots: glob-to-regexp@0.4.1: {} - glob@10.3.3: + glob@10.4.5: dependencies: - foreground-child: 3.1.1 - jackspeak: 2.3.0 - minimatch: 9.0.3 - minipass: 7.0.3 - path-scurry: 1.10.1 + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 glob@7.2.3: dependencies: @@ -14428,33 +15894,31 @@ snapshots: global-dirs@3.0.1: dependencies: ini: 2.0.0 + optional: true global@4.4.0: dependencies: min-document: 2.19.0 process: 0.11.10 + optional: true globals@11.12.0: {} - globals@13.21.0: + globals@13.24.0: dependencies: type-fest: 0.20.2 - globalthis@1.0.3: - dependencies: - define-properties: 1.2.1 - globalthis@1.0.4: dependencies: define-properties: 1.2.1 - gopd: 1.0.1 + gopd: 1.2.0 globby@11.1.0: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.1 - ignore: 5.2.4 + fast-glob: 3.3.3 + ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0 @@ -14463,9 +15927,7 @@ snapshots: through2: 0.6.5 optional: true - gopd@1.0.1: - dependencies: - get-intrinsic: 1.2.1 + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -14480,6 +15942,10 @@ snapshots: pumpify: 1.5.1 through2: 2.0.5 + gzip-size@7.0.0: + dependencies: + duplexer: 0.1.2 + handlebars@4.7.8: dependencies: minimist: 1.2.8 @@ -14487,54 +15953,65 @@ snapshots: source-map: 0.6.1 wordwrap: 1.0.0 optionalDependencies: - uglify-js: 3.17.4 + uglify-js: 3.19.3 hard-rejection@2.1.0: {} - has-bigints@1.0.2: {} + has-bigints@1.1.0: {} has-binary2@1.0.3: dependencies: isarray: 2.0.1 + optional: true - has-cors@1.1.0: {} + has-cors@1.1.0: + optional: true has-flag@3.0.0: {} has-flag@4.0.0: {} - has-property-descriptors@1.0.0: - dependencies: - get-intrinsic: 1.2.1 - has-property-descriptors@1.0.2: dependencies: - es-define-property: 1.0.0 + es-define-property: 1.0.1 - has-proto@1.0.1: {} - - has-proto@1.0.3: {} - - has-symbols@1.0.3: {} - - has-tostringtag@1.0.0: + has-proto@1.2.0: dependencies: - has-symbols: 1.0.3 + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} has-tostringtag@1.0.2: dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 - has-unicode@2.0.1: {} + has-unicode@2.0.1: + optional: true - has@1.0.3: + has-value@0.3.1: dependencies: - function-bind: 1.1.1 + get-value: 2.0.6 + has-values: 0.1.4 + isobject: 2.1.0 - hash-base@3.1.0: + has-value@1.0.0: + dependencies: + get-value: 2.0.6 + has-values: 1.0.0 + isobject: 3.0.1 + + has-values@0.1.4: {} + + has-values@1.0.0: + dependencies: + is-number: 3.0.0 + kind-of: 4.0.0 + + has@1.0.4: {} + + hash-base@3.0.5: dependencies: inherits: 2.0.4 - readable-stream: 3.6.2 safe-buffer: 5.2.1 hash.js@1.1.7: @@ -14542,10 +16019,6 @@ snapshots: inherits: 2.0.4 minimalistic-assert: 1.0.1 - hasown@2.0.1: - dependencies: - function-bind: 1.1.2 - hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -14555,7 +16028,7 @@ snapshots: header-case@2.0.4: dependencies: capital-case: 1.0.4 - tslib: 2.6.2 + tslib: 2.8.1 hmac-drbg@1.0.1: dependencies: @@ -14567,6 +16040,11 @@ snapshots: dependencies: mkdirp: 0.3.0 nopt: 1.0.10 + optional: true + + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 hosted-git-info@2.8.9: {} @@ -14578,10 +16056,17 @@ snapshots: dependencies: whatwg-encoding: 2.0.0 - html-escaper@2.0.2: {} + html-entities@2.6.0: {} html-tags@3.3.1: {} + http-auth@3.1.3: + dependencies: + apache-crypt: 1.2.6 + apache-md5: 1.1.8 + bcryptjs: 2.4.3 + uuid: 3.4.0 + http-browserify@1.7.0: dependencies: Base64: 0.2.1 @@ -14589,6 +16074,13 @@ snapshots: http-cache-semantics@4.1.1: {} + http-errors@1.6.3: + dependencies: + depd: 1.1.2 + inherits: 2.0.3 + setprototypeof: 1.1.0 + statuses: 1.5.0 + http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -14597,35 +16089,37 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 + http-parser-js@0.5.9: {} + http-proxy-agent@5.0.0: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.1 transitivePeerDependencies: - supports-color optional: true - http-proxy@1.18.1(debug@4.3.4): + http-proxy@1.18.1(debug@4.4.0): dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.3(debug@4.3.4) + follow-redirects: 1.15.9(debug@4.4.0) requires-port: 1.0.0 transitivePeerDependencies: - debug - http-server@14.1.1(debug@4.3.4): + http-server@14.1.1(debug@4.4.0): dependencies: basic-auth: 2.0.1 chalk: 4.1.2 corser: 2.0.1 he: 1.2.0 html-encoding-sniffer: 3.0.0 - http-proxy: 1.18.1(debug@4.3.4) + http-proxy: 1.18.1(debug@4.4.0) mime: 1.6.0 minimist: 1.2.8 opener: 1.5.2 - portfinder: 1.0.32 + portfinder: 1.0.33 secure-compare: 3.0.1 union: 0.5.0 url-join: 4.0.1 @@ -14637,32 +16131,28 @@ snapshots: dependencies: assert-plus: 1.0.0 jsprim: 2.0.2 - sshpk: 1.17.0 + sshpk: 1.18.0 + optional: true https-browserify@1.0.0: {} https-proxy-agent@4.0.0: dependencies: agent-base: 5.1.1 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.1 transitivePeerDependencies: - supports-color https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.1 transitivePeerDependencies: - supports-color + optional: true - https-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - - human-signals@1.1.1: {} + human-signals@1.1.1: + optional: true human-signals@2.1.0: {} @@ -14671,11 +16161,9 @@ snapshots: ms: 2.1.3 optional: true - hyphenate-style-name@1.0.4: {} + hyperdyperid@1.2.0: {} - iconify-icon@1.0.8: - dependencies: - '@iconify/types': 2.0.0 + hyphenate-style-name@1.1.0: {} iconv-lite@0.4.24: dependencies: @@ -14689,18 +16177,19 @@ snapshots: ieee754@1.2.1: {} - ignore@5.2.4: {} + ignore@5.3.2: {} - image-size@0.7.5: {} + image-size@0.7.5: + optional: true immediate@3.0.6: {} - import-fresh@3.3.0: + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - import-meta-resolve@3.0.0: {} + import-meta-resolve@3.1.1: {} imurmurhash@0.1.4: {} @@ -14708,7 +16197,8 @@ snapshots: indent-string@5.0.0: {} - indexof@0.0.1: {} + indexof@0.0.1: + optional: true infer-owner@1.0.4: optional: true @@ -14718,75 +16208,80 @@ snapshots: once: 1.4.0 wrappy: 1.0.2 + inherits@2.0.3: {} + inherits@2.0.4: {} ini@1.3.8: {} - ini@2.0.0: {} + ini@2.0.0: + optional: true - inline-style-prefixer@6.0.4: + inline-style-prefixer@7.0.1: dependencies: css-in-js-utils: 3.1.0 - fast-loops: 1.1.3 - internal-slot@1.0.5: - dependencies: - get-intrinsic: 1.2.1 - has: 1.0.3 - side-channel: 1.0.4 - - internal-slot@1.0.7: + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 hasown: 2.0.2 - side-channel: 1.0.6 + side-channel: 1.1.0 - invariant@2.2.4: + ip-address@9.0.5: dependencies: - loose-envify: 1.4.0 - - ip@2.0.0: {} + jsbn: 1.1.0 + sprintf-js: 1.1.3 + optional: true ipaddr.js@1.9.1: {} is-absolute-url@3.0.3: {} - is-arguments@1.1.1: + is-accessor-descriptor@1.0.1: dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 + hasown: 2.0.2 - is-array-buffer@3.0.2: + is-arguments@1.2.0: dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - is-typed-array: 1.1.12 + call-bound: 1.0.4 + has-tostringtag: 1.0.2 - is-array-buffer@3.0.4: + is-array-buffer@3.0.5: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 is-arrayish@0.2.1: {} is-arrayish@0.3.2: {} - is-async-function@2.0.0: + is-async-function@2.1.1: dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 - is-bigint@1.0.4: + is-bigint@1.1.0: dependencies: - has-bigints: 1.0.2 + has-bigints: 1.1.0 + + is-binary-path@1.0.1: + dependencies: + binary-extensions: 1.13.1 is-binary-path@2.1.0: dependencies: - binary-extensions: 2.2.0 + binary-extensions: 2.3.0 - is-boolean-object@1.1.2: + is-boolean-object@1.2.2: dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-buffer@1.1.6: {} is-builtin-module@3.2.1: dependencies: @@ -14796,41 +16291,69 @@ snapshots: is-ci@3.0.1: dependencies: - ci-info: 3.8.0 + ci-info: 3.9.0 + optional: true - is-core-module@2.13.0: - dependencies: - has: 1.0.3 - - is-core-module@2.13.1: + is-core-module@2.16.1: dependencies: hasown: 2.0.2 - is-data-view@1.0.1: + is-data-descriptor@1.0.1: dependencies: - is-typed-array: 1.1.13 + hasown: 2.0.2 - is-date-object@1.0.5: + is-data-view@1.0.2: dependencies: - has-tostringtag: 1.0.0 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 is-deflate@1.0.0: {} + is-descriptor@0.1.7: + dependencies: + is-accessor-descriptor: 1.0.1 + is-data-descriptor: 1.0.1 + + is-descriptor@1.0.3: + dependencies: + is-accessor-descriptor: 1.0.1 + is-data-descriptor: 1.0.1 + is-docker@2.2.1: {} + is-extendable@0.1.1: {} + + is-extendable@1.0.1: + dependencies: + is-plain-object: 2.0.4 + is-extglob@2.1.1: {} - is-finalizationregistry@1.0.2: + is-finalizationregistry@1.1.1: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 is-fullwidth-code-point@3.0.0: {} - is-function@1.0.2: {} + is-function@1.0.2: + optional: true - is-generator-function@1.0.10: + is-generator-function@1.1.0: dependencies: - has-tostringtag: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@3.1.0: + dependencies: + is-extglob: 2.1.1 is-glob@4.0.3: dependencies: @@ -14842,6 +16365,7 @@ snapshots: dependencies: global-dirs: 3.0.1 is-path-inside: 3.0.3 + optional: true is-interactive@1.0.0: {} @@ -14854,16 +16378,19 @@ snapshots: is-nan@1.3.2: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.8 define-properties: 1.2.1 - is-negative-zero@2.0.2: {} - is-negative-zero@2.0.3: {} - is-number-object@1.0.7: + is-number-object@1.1.1: dependencies: - has-tostringtag: 1.0.0 + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@3.0.0: + dependencies: + kind-of: 3.2.2 is-number@7.0.0: {} @@ -14883,55 +16410,57 @@ snapshots: is-plain-object@5.0.0: {} - is-regex@1.1.4: + is-regex@1.2.1: dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 is-regexp@1.0.0: {} is-set@2.0.3: {} - is-shared-array-buffer@1.0.2: + is-shared-array-buffer@1.0.4: dependencies: - call-bind: 1.0.2 - - is-shared-array-buffer@1.0.3: - dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 is-stream@2.0.1: {} - is-string@1.0.7: + is-string@1.1.1: dependencies: - has-tostringtag: 1.0.0 + call-bound: 1.0.4 + has-tostringtag: 1.0.2 - is-symbol@1.0.4: + is-symbol@1.1.1: dependencies: - has-symbols: 1.0.3 + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 - is-typed-array@1.1.12: + is-typed-array@1.1.15: dependencies: - which-typed-array: 1.1.11 + which-typed-array: 1.1.18 - is-typed-array@1.1.13: - dependencies: - which-typed-array: 1.1.15 - - is-typedarray@1.0.0: {} + is-typedarray@1.0.0: + optional: true is-unicode-supported@0.1.0: {} is-weakmap@2.0.2: {} - is-weakref@1.0.2: + is-weakref@1.1.1: dependencies: - call-bind: 1.0.2 + call-bound: 1.0.4 - is-weakset@2.0.3: + is-weakset@2.0.4: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-windows@1.0.2: {} + + is-wsl@1.1.0: {} is-wsl@2.2.0: dependencies: @@ -14942,56 +16471,52 @@ snapshots: isarray@1.0.0: {} - isarray@2.0.1: {} + isarray@2.0.1: + optional: true isarray@2.0.5: {} isexe@2.0.0: {} + isobject@2.1.0: + dependencies: + isarray: 1.0.0 + isobject@3.0.1: {} - isstream@0.1.2: {} + isstream@0.1.2: + optional: true - istanbul-lib-coverage@3.2.0: {} + istanbul-lib-coverage@3.2.2: {} istanbul-lib-instrument@5.2.1: dependencies: - '@babel/core': 7.22.11 - '@babel/parser': 7.22.13 + '@babel/core': 7.26.9 + '@babel/parser': 7.26.9 '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.0 + istanbul-lib-coverage: 3.2.2 semver: 6.3.1 transitivePeerDependencies: - supports-color - istanbul-lib-report@3.0.1: + iterator.prototype@1.1.5: dependencies: - istanbul-lib-coverage: 3.2.0 - make-dir: 4.0.0 - supports-color: 7.2.0 - - istanbul-reports@3.1.6: - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - - iterator.prototype@1.1.2: - dependencies: - define-properties: 1.2.1 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - reflect.getprototypeof: 1.0.6 + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 set-function-name: 2.0.2 - jackspeak@2.3.0: + jackspeak@3.4.3: dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jake@10.8.7: + jake@10.9.2: dependencies: - async: 3.2.5 + async: 3.2.6 chalk: 4.1.2 filelist: 1.0.4 minimatch: 3.1.2 @@ -14999,15 +16524,15 @@ snapshots: jest-haste-map@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.7 - '@types/node': 20.12.8 + '@types/graceful-fs': 4.1.9 + '@types/node': 22.13.9 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 jest-regex-util: 29.6.3 jest-util: 29.7.0 jest-worker: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 @@ -15017,44 +16542,49 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.8 + '@types/node': 22.13.9 chalk: 4.1.2 - ci-info: 3.8.0 + ci-info: 3.9.0 graceful-fs: 4.2.11 picomatch: 2.3.1 - jest-worker@26.6.2: - dependencies: - '@types/node': 20.12.8 - merge-stream: 2.0.0 - supports-color: 7.2.0 - jest-worker@29.7.0: dependencies: - '@types/node': 20.12.8 + '@types/node': 22.13.9 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jimp@0.10.3: + jimp@0.10.3(debug@4.4.0): dependencies: - '@babel/runtime': 7.22.11 - '@jimp/custom': 0.10.3 - '@jimp/plugins': 0.10.3(@jimp/custom@0.10.3) - '@jimp/types': 0.10.3(@jimp/custom@0.10.3) - core-js: 3.32.1 + '@babel/runtime': 7.26.9 + '@jimp/custom': 0.10.3(debug@4.4.0) + '@jimp/plugins': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0))(debug@4.4.0) + '@jimp/types': 0.10.3(@jimp/custom@0.10.3(debug@4.4.0)) + core-js: 3.41.0 regenerator-runtime: 0.13.11 + transitivePeerDependencies: + - debug + optional: true - jose@4.15.5: {} + jiti@2.4.2: {} - jpeg-js@0.3.7: {} + joi@17.13.3: + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 - js-base64@2.6.4: {} + jpeg-js@0.3.7: + optional: true + + js-base64@2.6.4: + optional: true js-cookie@2.2.1: {} - js-graph-algorithms@1.0.18: {} - js-tokens@4.0.0: {} js-yaml@3.14.1: @@ -15066,39 +16596,45 @@ snapshots: dependencies: argparse: 2.0.1 - jsbn@0.1.1: {} + jsbn@0.1.1: + optional: true - jscodeshift@0.14.0(@babel/preset-env@7.22.10(@babel/core@7.22.11)): + jsbn@1.1.0: + optional: true + + jscodeshift@0.15.2(@babel/preset-env@7.26.9(@babel/core@7.26.9)): dependencies: - '@babel/core': 7.22.11 - '@babel/parser': 7.22.13 - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.22.11) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.22.11) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.22.11) - '@babel/plugin-transform-modules-commonjs': 7.22.11(@babel/core@7.22.11) - '@babel/preset-env': 7.22.10(@babel/core@7.22.11) - '@babel/preset-flow': 7.22.15(@babel/core@7.22.11) - '@babel/preset-typescript': 7.23.0(@babel/core@7.22.11) - '@babel/register': 7.22.15(@babel/core@7.22.11) - babel-core: 7.0.0-bridge.0(@babel/core@7.22.11) + '@babel/core': 7.26.9 + '@babel/parser': 7.26.9 + '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.9) + '@babel/plugin-transform-nullish-coalescing-operator': 7.26.6(@babel/core@7.26.9) + '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.9) + '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.9) + '@babel/preset-flow': 7.25.9(@babel/core@7.26.9) + '@babel/preset-typescript': 7.26.0(@babel/core@7.26.9) + '@babel/register': 7.25.9(@babel/core@7.26.9) + babel-core: 7.0.0-bridge.0(@babel/core@7.26.9) chalk: 4.1.2 - flow-parser: 0.218.0 + flow-parser: 0.263.0 graceful-fs: 4.2.11 - micromatch: 4.0.5 + micromatch: 4.0.8 neo-async: 2.6.2 node-dir: 0.1.17 - recast: 0.21.5 + recast: 0.23.11 temp: 0.8.4 write-file-atomic: 2.4.3 + optionalDependencies: + '@babel/preset-env': 7.26.9(@babel/core@7.26.9) transitivePeerDependencies: - supports-color jsesc@0.5.0: {} - jsesc@2.5.2: {} - jsesc@3.0.2: {} + jsesc@3.1.0: {} + json-buffer@3.0.1: {} json-parse-better-errors@1.0.2: {} @@ -15121,15 +16657,14 @@ snapshots: json5@2.2.3: {} - jsonc-parser@3.2.0: {} - jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 + optional: true jsonfile@6.1.0: dependencies: - universalify: 2.0.0 + universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 @@ -15146,7 +16681,7 @@ snapshots: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.6.0 + semver: 7.7.1 jsprim@2.0.2: dependencies: @@ -15154,13 +16689,14 @@ snapshots: extsprintf: 1.3.0 json-schema: 0.4.0 verror: 1.10.0 + optional: true jsx-ast-utils@3.3.5: dependencies: - array-includes: 3.1.8 - array.prototype.flat: 1.3.2 - object.assign: 4.1.5 - object.values: 1.2.0 + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 jszip@3.10.1: dependencies: @@ -15180,20 +16716,29 @@ snapshots: jwa: 1.4.1 safe-buffer: 5.2.1 - keyv@4.5.3: + keyv@4.5.4: dependencies: json-buffer: 3.0.1 + kind-of@3.2.2: + dependencies: + is-buffer: 1.1.6 + + kind-of@4.0.0: + dependencies: + is-buffer: 1.1.6 + kind-of@6.0.3: {} kleur@3.0.3: {} - lazy-ass@1.6.0: {} + lazy-ass@1.6.0: + optional: true lazy-universal-dotenv@4.0.0: dependencies: app-root-dir: 1.0.2 - dotenv: 16.3.1 + dotenv: 16.4.7 dotenv-expand: 10.0.0 leven@3.1.0: {} @@ -15223,23 +16768,45 @@ snapshots: colorette: 2.0.20 log-update: 4.0.0 p-map: 4.0.0 - rfdc: 1.3.0 - rxjs: 7.8.1 + rfdc: 1.4.1 + rxjs: 7.8.2 through: 2.3.8 wrap-ansi: 7.0.0 optionalDependencies: enquirer: 2.4.1 + optional: true - load-bmfont@1.4.1: + live-server@1.2.2: + dependencies: + chokidar: 2.1.8 + colors: 1.4.0 + connect: 3.7.0 + cors: 2.8.5 + event-stream: 3.3.4 + faye-websocket: 0.11.4 + http-auth: 3.1.3 + morgan: 1.10.0 + object-assign: 4.1.1 + opn: 6.0.0 + proxy-middleware: 0.15.0 + send: 1.2.0 + serve-index: 1.9.1 + transitivePeerDependencies: + - supports-color + + load-bmfont@1.4.2(debug@4.4.0): dependencies: buffer-equal: 0.0.1 mime: 1.6.0 parse-bmfont-ascii: 1.0.6 parse-bmfont-binary: 1.0.6 - parse-bmfont-xml: 1.1.4 - phin: 2.9.3 + parse-bmfont-xml: 1.1.6 + phin: 3.7.1(debug@4.4.0) xhr: 2.6.0 xtend: 4.0.2 + transitivePeerDependencies: + - debug + optional: true load-json-file@4.0.0: dependencies: @@ -15304,34 +16871,25 @@ snapshots: cli-cursor: 3.1.0 slice-ansi: 4.0.0 wrap-ansi: 6.2.0 + optional: true - long@5.2.3: {} + long@5.3.1: {} longest-streak@3.1.0: {} - looks-same@8.2.3: - dependencies: - color-diff: 1.4.0 - fs-extra: 8.1.0 - js-graph-algorithms: 1.0.18 - lodash: 4.17.21 - nested-error-stacks: 2.1.1 - parse-color: 1.0.0 - sharp: 0.30.7 - loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 - loupe@2.3.6: + loupe@2.3.7: dependencies: get-func-name: 2.0.2 lower-case@2.0.2: dependencies: - tslib: 2.6.2 + tslib: 2.8.1 - lru-cache@10.0.1: {} + lru-cache@10.4.3: {} lru-cache@5.1.1: dependencies: @@ -15352,11 +16910,11 @@ snapshots: magic-string@0.27.0: dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 - magic-string@0.30.4: + magic-string@0.30.17: dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 make-dir@2.1.0: dependencies: @@ -15367,13 +16925,9 @@ snapshots: dependencies: semver: 6.3.1 - make-dir@4.0.0: - dependencies: - semver: 7.6.0 - make-fetch-happen@10.2.1: dependencies: - agentkeepalive: 4.5.0 + agentkeepalive: 4.6.0 cacache: 16.1.3 http-cache-semantics: 4.1.1 http-proxy-agent: 5.0.0 @@ -15385,7 +16939,7 @@ snapshots: minipass-fetch: 2.1.2 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 - negotiator: 0.6.3 + negotiator: 0.6.4 promise-retry: 2.0.1 socks-proxy-agent: 7.0.0 ssri: 9.0.1 @@ -15398,13 +16952,21 @@ snapshots: dependencies: tmpl: 1.0.5 + map-cache@0.2.2: {} + map-obj@1.0.1: {} map-obj@4.3.0: {} map-or-similar@1.5.0: {} - markdown-it@14.0.0: + map-stream@0.1.0: {} + + map-visit@1.0.0: + dependencies: + object-visit: 1.0.1 + + markdown-it@14.1.0: dependencies: argparse: 2.0.1 entities: 4.5.0 @@ -15413,52 +16975,84 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 - markdown-to-jsx@7.3.2(react@18.2.0): + markdown-to-jsx@7.7.4(react@18.3.1): dependencies: - react: 18.2.0 + react: 18.3.1 + + math-intrinsics@1.1.0: {} + + mc-assets@0.2.62: + dependencies: + maxrects-packer: '@zardoy/maxrects-packer@2.7.4' + zod: 3.24.2 + + mc-bridge@0.1.3(minecraft-data@3.98.0): + dependencies: + minecraft-data: 3.98.0 + + mcraft-fun-mineflayer@0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13)): + dependencies: + '@zardoy/flying-squid': 0.0.49(encoding@0.1.13) + exit-hook: 2.2.1 + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13) + mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13) + prismarine-item: 1.17.0 + ws: 8.18.1 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate md5-file@4.0.0: {} md5.js@1.3.5: dependencies: - hash-base: 3.1.0 + hash-base: 3.0.5 inherits: 2.0.4 safe-buffer: 5.2.1 + md5@2.3.0: + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + is-buffer: 1.1.6 + mdast-util-definitions@4.0.0: dependencies: unist-util-visit: 2.0.3 - mdast-util-from-markdown@2.0.0: + mdast-util-from-markdown@2.0.2: dependencies: - '@types/mdast': 4.0.3 - '@types/unist': 3.0.2 - decode-named-character-reference: 1.0.2 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.1.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 - micromark: 4.0.0 - micromark-util-decode-numeric-character-reference: 2.0.1 - micromark-util-decode-string: 2.0.0 - micromark-util-normalize-identifier: 2.0.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 unist-util-stringify-position: 4.0.0 transitivePeerDependencies: - supports-color mdast-util-phrasing@4.1.0: dependencies: - '@types/mdast': 4.0.3 + '@types/mdast': 4.0.4 unist-util-is: 6.0.0 - mdast-util-to-markdown@2.1.0: + mdast-util-to-markdown@2.1.2: dependencies: - '@types/mdast': 4.0.3 - '@types/unist': 3.0.2 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 longest-streak: 3.1.0 mdast-util-phrasing: 4.1.0 mdast-util-to-string: 4.0.0 - micromark-util-decode-string: 2.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 unist-util-visit: 5.0.0 zwitch: 2.0.4 @@ -15466,7 +17060,7 @@ snapshots: mdast-util-to-string@4.0.0: dependencies: - '@types/mdast': 4.0.3 + '@types/mdast': 4.0.4 mdn-data@2.0.14: {} @@ -15474,6 +17068,15 @@ snapshots: media-typer@0.3.0: {} + memfs@4.17.0: + dependencies: + '@jsonjoy.com/json-pack': 1.2.0(tslib@2.8.1) + '@jsonjoy.com/util': 1.5.0(tslib@2.8.1) + tree-dump: 1.0.2(tslib@2.8.1) + tslib: 2.8.1 + + memoize-one@6.0.0: {} + memoizerific@1.11.3: dependencies: map-or-similar: 1.5.0 @@ -15482,7 +17085,7 @@ snapshots: meow@10.1.5: dependencies: - '@types/minimist': 1.2.3 + '@types/minimist': 1.2.5 camelcase-keys: 7.0.2 decamelize: 5.0.1 decamelize-keys: 1.1.1 @@ -15495,274 +17098,250 @@ snapshots: type-fest: 1.4.0 yargs-parser: 20.2.9 - merge-descriptors@1.0.1: {} + merge-descriptors@1.0.3: {} merge-stream@2.0.0: {} merge2@1.4.1: {} - merge@1.2.1: {} + merge@1.2.1: + optional: true meshoptimizer@0.18.1: {} methods@1.1.2: {} - micromark-core-commonmark@2.0.0: + micromark-core-commonmark@2.0.3: dependencies: - decode-named-character-reference: 1.0.2 + decode-named-character-reference: 1.1.0 devlop: 1.1.0 - micromark-factory-destination: 2.0.0 - micromark-factory-label: 2.0.0 - micromark-factory-space: 2.0.0 - micromark-factory-title: 2.0.0 - micromark-factory-whitespace: 2.0.0 - micromark-util-character: 2.1.0 - micromark-util-chunked: 2.0.0 - micromark-util-classify-character: 2.0.0 - micromark-util-html-tag-name: 2.0.0 - micromark-util-normalize-identifier: 2.0.0 - micromark-util-resolve-all: 2.0.0 - micromark-util-subtokenize: 2.0.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - micromark-factory-destination@2.0.0: + micromark-factory-destination@2.0.1: dependencies: - micromark-util-character: 2.1.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - micromark-factory-label@2.0.0: + micromark-factory-label@2.0.1: dependencies: devlop: 1.1.0 - micromark-util-character: 2.1.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - micromark-factory-space@2.0.0: + micromark-factory-space@2.0.1: dependencies: - micromark-util-character: 2.1.0 - micromark-util-types: 2.0.0 + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 - micromark-factory-title@2.0.0: + micromark-factory-title@2.0.1: dependencies: - micromark-factory-space: 2.0.0 - micromark-util-character: 2.1.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - micromark-factory-whitespace@2.0.0: + micromark-factory-whitespace@2.0.1: dependencies: - micromark-factory-space: 2.0.0 - micromark-util-character: 2.1.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - micromark-util-character@2.1.0: + micromark-util-character@2.1.1: dependencies: - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - micromark-util-chunked@2.0.0: + micromark-util-chunked@2.0.1: dependencies: - micromark-util-symbol: 2.0.0 + micromark-util-symbol: 2.0.1 - micromark-util-classify-character@2.0.0: + micromark-util-classify-character@2.0.1: dependencies: - micromark-util-character: 2.1.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - micromark-util-combine-extensions@2.0.0: + micromark-util-combine-extensions@2.0.1: dependencies: - micromark-util-chunked: 2.0.0 - micromark-util-types: 2.0.0 + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 - micromark-util-decode-numeric-character-reference@2.0.1: + micromark-util-decode-numeric-character-reference@2.0.2: dependencies: - micromark-util-symbol: 2.0.0 + micromark-util-symbol: 2.0.1 - micromark-util-decode-string@2.0.0: + micromark-util-decode-string@2.0.1: dependencies: - decode-named-character-reference: 1.0.2 - micromark-util-character: 2.1.0 - micromark-util-decode-numeric-character-reference: 2.0.1 - micromark-util-symbol: 2.0.0 + decode-named-character-reference: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 - micromark-util-encode@2.0.0: {} + micromark-util-encode@2.0.1: {} - micromark-util-html-tag-name@2.0.0: {} + micromark-util-html-tag-name@2.0.1: {} - micromark-util-normalize-identifier@2.0.0: + micromark-util-normalize-identifier@2.0.1: dependencies: - micromark-util-symbol: 2.0.0 + micromark-util-symbol: 2.0.1 - micromark-util-resolve-all@2.0.0: + micromark-util-resolve-all@2.0.1: dependencies: - micromark-util-types: 2.0.0 + micromark-util-types: 2.0.2 - micromark-util-sanitize-uri@2.0.0: + micromark-util-sanitize-uri@2.0.1: dependencies: - micromark-util-character: 2.1.0 - micromark-util-encode: 2.0.0 - micromark-util-symbol: 2.0.0 + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 - micromark-util-subtokenize@2.0.0: + micromark-util-subtokenize@2.1.0: dependencies: devlop: 1.1.0 - micromark-util-chunked: 2.0.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 - micromark-util-symbol@2.0.0: {} + micromark-util-symbol@2.0.1: {} - micromark-util-types@2.0.0: {} + micromark-util-types@2.0.2: {} - micromark@4.0.0: + micromark@4.0.2: dependencies: '@types/debug': 4.1.12 - debug: 4.3.4(supports-color@8.1.1) - decode-named-character-reference: 1.0.2 + debug: 4.4.1 + decode-named-character-reference: 1.1.0 devlop: 1.1.0 - micromark-core-commonmark: 2.0.0 - micromark-factory-space: 2.0.0 - micromark-util-character: 2.1.0 - micromark-util-chunked: 2.0.0 - micromark-util-combine-extensions: 2.0.0 - micromark-util-decode-numeric-character-reference: 2.0.1 - micromark-util-encode: 2.0.0 - micromark-util-normalize-identifier: 2.0.0 - micromark-util-resolve-all: 2.0.0 - micromark-util-sanitize-uri: 2.0.0 - micromark-util-subtokenize: 2.0.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 transitivePeerDependencies: - supports-color - micromatch@4.0.5: + micromatch@3.1.10: dependencies: - braces: 3.0.2 + arr-diff: 4.0.0 + array-unique: 0.3.2 + braces: 2.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + extglob: 2.0.4 + fragment-cache: 0.2.1 + kind-of: 6.0.3 + nanomatch: 1.2.13 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 picomatch: 2.3.1 miller-rabin@4.0.1: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.1 brorand: 1.1.0 mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 + mime-types@3.0.1: + dependencies: + mime-db: 1.54.0 + mime@1.6.0: {} mime@2.6.0: {} mimic-fn@2.1.0: {} - mimic-response@2.1.0: {} + mimic-response@2.1.0: + optional: true mimic-response@3.1.0: {} min-document@2.19.0: dependencies: dom-walk: 0.1.2 + optional: true min-indent@1.0.1: {} - minecraft-assets@1.12.2: {} - - minecraft-data@3.65.0: {} + minecraft-data@3.98.0: {} minecraft-folder-path@1.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): + minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/89c33d396f3fde4804c71f4be3c203ade1833b41(@types/react@18.3.18)(react@18.3.1): dependencies: - valtio: 1.11.2(@types/react@18.2.20)(react@18.2.0) + valtio: 1.13.2(@types/react@18.3.18)(react@18.3.1) transitivePeerDependencies: - '@types/react' - react - minecraft-protocol@1.47.0(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13): + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13): dependencies: - '@types/readable-stream': 4.0.12 + '@types/node-rsa': 1.1.4 + '@types/readable-stream': 4.0.18 aes-js: 3.1.2 buffer-equal: 1.0.1 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.0(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-data: 3.98.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-auth: 2.7.0 + prismarine-chat: 1.11.0 + prismarine-nbt: 2.7.0 prismarine-realms: 1.3.2(encoding@0.1.13) - protodef: 1.15.0 - readable-stream: 4.5.2 + protodef: 1.18.0 + readable-stream: 4.7.0 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): + minecraft-wrap@1.6.0(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 - aes-js: 3.1.2 - buffer-equal: 1.0.1 - debug: 4.3.4(supports-color@8.1.1) - endian-toggle: 0.0.0 - lodash.get: 4.4.2 - lodash.merge: 4.6.2 - minecraft-data: 3.65.0 - minecraft-folder-path: 1.2.0 - node-fetch: 2.7.0(encoding@0.1.13) - node-rsa: 0.4.2 - prismarine-auth: 2.4.2(encoding@0.1.13) - prismarine-chat: 1.10.1 - prismarine-nbt: 2.5.0 - prismarine-realms: 1.3.2(encoding@0.1.13) - protodef: 1.15.0 - readable-stream: 4.5.2 - uuid-1345: 1.0.2 - yggdrasil: 1.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding - - supports-color - - minecraft-wrap@1.5.1(encoding@0.1.13): - dependencies: - debug: 4.3.4(supports-color@8.1.1) + adm-zip: 0.5.16 + debug: 4.4.0(supports-color@8.1.1) es6-promisify: 5.0.0 extract-zip: 2.0.1(supports-color@8.1.1) flatmap: 0.0.3 @@ -15778,71 +17357,49 @@ snapshots: - encoding - supports-color - minecrafthawkeye@1.3.6: + minecrafthawkeye@1.3.9: dependencies: detect-collisions: 7.0.5 - vec3: 0.1.8 + uuid: 9.0.1 + vec3: 0.1.10 - mineflayer-item-map-downloader@https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7(encoding@0.1.13): + mineflayer-item-map-downloader@https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824(patch_hash=a731ebbace2d8790c973ab3a5ba33494a6e9658533a9710dd8ba36f86db061ad)(encoding@0.1.13): dependencies: - mineflayer: 4.20.1(encoding@0.1.13) + mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13) sharp: 0.30.7 transitivePeerDependencies: - encoding - supports-color - mineflayer-pathfinder@2.4.4: + mineflayer-mouse@0.1.21: dependencies: - 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 - prismarine-nbt: 2.2.1 - prismarine-physics: 1.8.0 - vec3: 0.1.8 - - 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) - 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-entity: 2.3.1 - prismarine-item: 1.14.0 - prismarine-nbt: 2.5.0 - prismarine-physics: 1.8.0 - 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 - protodef: 1.15.0 - typed-emitter: 1.4.0 - vec3: 0.1.8 + change-case: 5.4.4 + debug: 4.4.1 + prismarine-item: 1.17.0 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c transitivePeerDependencies: - - 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/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13): dependencies: - minecraft-data: 3.65.0 - minecraft-protocol: 1.47.0(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-entity: 2.3.1 - prismarine-item: 1.14.0 - prismarine-nbt: 2.5.0 - prismarine-physics: 1.8.0 - prismarine-recipe: 1.3.1(prismarine-registry@1.7.0) - prismarine-registry: 1.7.0 + '@nxg-org/mineflayer-physics-util': 1.8.10 + minecraft-data: 3.98.0 + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13) + prismarine-biome: 1.3.0(minecraft-data@3.98.0)(prismarine-registry@1.11.0) + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-chat: 1.11.0 + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0) + prismarine-entity: 2.5.0 + prismarine-item: 1.17.0 + prismarine-nbt: 2.7.0 + prismarine-physics: https://codeload.github.com/zardoy/prismarine-physics/tar.gz/353e25b800149393f40539ec381218be44cbb03b + prismarine-recipe: 1.3.1(prismarine-registry@1.11.0) + prismarine-registry: 1.11.0 prismarine-windows: 2.9.0 - prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 - protodef: 1.15.0 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c + protodef: 1.18.0 typed-emitter: 1.4.0 - vec3: 0.1.8 + vec3: 0.1.10 transitivePeerDependencies: - encoding - supports-color @@ -15863,6 +17420,10 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + minimist-options@4.1.0: dependencies: arrify: 1.0.1 @@ -15906,16 +17467,22 @@ snapshots: minipass@5.0.0: {} - minipass@7.0.3: {} + minipass@7.1.2: {} minizlib@2.1.2: dependencies: minipass: 3.3.6 yallist: 4.0.0 + mixin-deep@1.3.2: + dependencies: + for-in: 1.0.2 + is-extendable: 1.0.1 + mkdirp-classic@0.5.3: {} - mkdirp@0.3.0: {} + mkdirp@0.3.0: + optional: true mkdirp@0.5.6: dependencies: @@ -15925,25 +17492,39 @@ snapshots: mkdirp@2.1.6: {} - mlly@1.4.2: + mlly@1.7.4: dependencies: - acorn: 8.10.0 - pathe: 1.1.1 - pkg-types: 1.0.3 - ufo: 1.3.1 + acorn: 8.14.1 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.5.4 mojangson@2.0.4: dependencies: nearley: 2.20.1 + monaco-editor@0.52.2: {} + moo@0.5.2: {} - mri@1.2.0: {} + morgan@1.10.0: + dependencies: + basic-auth: 2.0.1 + debug: 2.6.9 + depd: 2.0.0 + on-finished: 2.3.0 + on-headers: 1.0.2 + transitivePeerDependencies: + - supports-color + + motion-dom@12.9.1: + dependencies: + motion-utils: 12.8.3 + + motion-utils@12.8.3: {} ms@2.0.0: {} - ms@2.1.2: {} - ms@2.1.3: {} mz@2.7.0: @@ -15952,26 +17533,41 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nan@2.18.0: {} + nan@2.22.2: + optional: true - nano-css@5.3.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + nano-css@5.6.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 css-tree: 1.1.3 - csstype: 3.1.2 + csstype: 3.1.3 fastest-stable-stringify: 2.0.2 - inline-style-prefixer: 6.0.4 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + inline-style-prefixer: 7.0.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) rtl-css-js: 1.16.1 - sourcemap-codec: 1.4.8 stacktrace-js: 2.0.2 - stylis: 4.2.0 + stylis: 4.3.6 - nanoid@3.3.6: {} + nanoid@3.3.9: {} - nanoid@3.3.7: {} + nanomatch@1.2.13: + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + fragment-cache: 0.2.1 + is-windows: 1.0.2 + kind-of: 6.0.3 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color - napi-build-utils@1.0.2: {} + napi-build-utils@2.0.0: {} natural-compare-lite@1.4.0: {} @@ -15986,15 +17582,15 @@ snapshots: negotiator@0.6.3: {} + negotiator@0.6.4: {} + neo-async@2.6.2: {} - 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/e754999ffdea67853bc9b10553b5e9908b40f618: dependencies: - body-parser: 1.20.2 - express: 4.18.2 - express-ws: 4.0.0(express@4.18.2) + body-parser: 1.20.3 + express: 4.21.2 + express-ws: 4.0.0(express@4.21.2) transitivePeerDependencies: - bufferutil - supports-color @@ -16005,11 +17601,11 @@ snapshots: no-case@3.0.4: dependencies: lower-case: 2.0.2 - tslib: 2.6.2 + tslib: 2.8.1 - node-abi@3.47.0: + node-abi@3.74.0: dependencies: - semver: 7.6.0 + semver: 7.7.1 node-addon-api@5.1.0: {} @@ -16027,7 +17623,7 @@ snapshots: dependencies: minimatch: 3.1.2 - node-fetch-native@1.4.0: {} + node-fetch-native@1.6.6: {} node-fetch@2.7.0(encoding@0.1.13): dependencies: @@ -16035,23 +17631,18 @@ snapshots: optionalDependencies: encoding: 0.1.13 - node-gyp-build-optional-packages@5.1.1: - dependencies: - detect-libc: 2.0.2 - optional: true - node-gyp@9.4.1: dependencies: env-paths: 2.2.1 - exponential-backoff: 3.1.1 + exponential-backoff: 3.1.2 glob: 7.2.3 graceful-fs: 4.2.11 make-fetch-happen: 10.2.1 nopt: 6.0.0 npmlog: 6.0.2 rimraf: 3.0.2 - semver: 7.6.0 - tar: 6.2.0 + semver: 7.7.1 + tar: 6.2.1 which: 2.0.2 transitivePeerDependencies: - bluebird @@ -16060,14 +17651,14 @@ snapshots: node-gzip@1.1.2: {} - node-html-parser@6.1.10: + node-html-parser@6.1.13: dependencies: css-select: 5.1.0 he: 1.2.0 node-int64@0.4.0: {} - node-releases@2.0.13: {} + node-releases@2.0.19: {} node-rsa@0.4.2: dependencies: @@ -16080,10 +17671,12 @@ snapshots: nopt@1.0.10: dependencies: abbrev: 1.1.1 + optional: true nopt@5.0.0: dependencies: abbrev: 1.1.1 + optional: true nopt@6.0.0: dependencies: @@ -16093,30 +17686,34 @@ snapshots: normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.4 + resolve: 1.22.10 semver: 5.7.2 validate-npm-package-license: 3.0.4 normalize-package-data@3.0.3: dependencies: hosted-git-info: 4.1.0 - is-core-module: 2.13.0 - semver: 7.6.0 + is-core-module: 2.16.1 + semver: 7.7.1 validate-npm-package-license: 3.0.4 + normalize-path@2.1.1: + dependencies: + remove-trailing-separator: 1.1.0 + normalize-path@3.0.0: {} npm-run-all@4.1.5: dependencies: ansi-styles: 3.2.1 chalk: 2.4.2 - cross-spawn: 6.0.5 + cross-spawn: 6.0.6 memorystream: 0.3.1 minimatch: 3.1.2 pidtree: 0.3.1 read-pkg: 3.0.0 - shell-quote: 1.8.1 - string.prototype.padend: 3.1.4 + shell-quote: 1.8.2 + string.prototype.padend: 3.1.6 npm-run-path@4.0.1: dependencies: @@ -16128,6 +17725,7 @@ snapshots: console-control-strings: 1.1.0 gauge: 3.0.2 set-blocking: 2.0.0 + optional: true npmlog@6.0.2: dependencies: @@ -16141,65 +17739,76 @@ snapshots: dependencies: boolbase: 1.0.0 + nypm@0.5.4: + dependencies: + citty: 0.1.6 + consola: 3.4.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + tinyexec: 0.3.2 + ufo: 1.5.4 + object-assign@4.1.1: {} - object-inspect@1.12.3: {} - - object-inspect@1.13.1: {} - - object-is@1.1.5: + object-copy@0.1.0: dependencies: - call-bind: 1.0.2 + copy-descriptor: 0.1.1 + define-property: 0.2.5 + kind-of: 3.2.2 + + object-inspect@1.13.4: {} + + object-is@1.1.6: + dependencies: + call-bind: 1.0.8 define-properties: 1.2.1 object-keys@1.1.1: {} - object.assign@4.1.4: + object-visit@1.0.1: dependencies: - call-bind: 1.0.2 + isobject: 3.0.1 + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - has-symbols: 1.0.3 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 object-keys: 1.1.1 - object.assign@4.1.5: + object.entries@1.1.9: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - has-symbols: 1.0.3 - object-keys: 1.1.1 - - object.entries@1.1.8: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 object.fromentries@2.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 - object.hasown@1.1.4: + object.pick@1.3.0: dependencies: - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 + isobject: 3.0.1 - object.values@1.1.7: + object.values@1.2.1: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.22.2 + es-object-atoms: 1.1.1 - object.values@1.2.0: + omggif@1.0.10: + optional: true + + on-finished@2.3.0: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 - - omggif@1.0.10: {} + ee-first: 1.1.1 on-finished@2.4.1: dependencies: @@ -16223,21 +17832,25 @@ snapshots: opener@1.5.2: {} - optionator@0.9.3: + opn@6.0.0: + dependencies: + is-wsl: 1.1.0 + + optionator@0.9.4: dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 + word-wrap: 1.2.5 ora@5.4.1: dependencies: bl: 4.1.0 chalk: 4.1.2 cli-cursor: 3.1.0 - cli-spinners: 2.9.1 + cli-spinners: 2.9.2 is-interactive: 1.0.0 is-unicode-supported: 0.1.0 log-symbols: 4.1.0 @@ -16248,7 +17861,14 @@ snapshots: os-browserify@0.3.0: {} - ospath@1.2.2: {} + ospath@1.2.2: + optional: true + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 p-limit@2.3.0: dependencies: @@ -16260,7 +17880,7 @@ snapshots: p-limit@4.0.0: dependencies: - yocto-queue: 1.0.0 + yocto-queue: 1.2.0 p-locate@3.0.0: dependencies: @@ -16280,41 +17900,46 @@ snapshots: p-try@2.2.0: {} + package-json-from-dist@1.0.1: {} + pako@0.2.9: {} pako@1.0.11: {} + pako@2.1.0: {} + param-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.8.1 parent-module@1.0.1: dependencies: callsites: 3.1.0 - parse-asn1@5.1.6: + parse-asn1@5.1.7: dependencies: - asn1.js: 5.4.1 + asn1.js: 4.10.1 browserify-aes: 1.2.0 evp_bytestokey: 1.0.3 + hash-base: 3.0.5 pbkdf2: 3.1.2 safe-buffer: 5.2.1 - parse-bmfont-ascii@1.0.6: {} + parse-bmfont-ascii@1.0.6: + optional: true - parse-bmfont-binary@1.0.6: {} + parse-bmfont-binary@1.0.6: + optional: true - parse-bmfont-xml@1.1.4: + parse-bmfont-xml@1.1.6: dependencies: xml-parse-from-string: 1.0.1 - xml2js: 0.4.23 + xml2js: 0.5.0 + optional: true - parse-color@1.0.0: - dependencies: - color-convert: 0.5.3 - - parse-headers@2.0.5: {} + parse-headers@2.0.5: + optional: true parse-json@4.0.0: dependencies: @@ -16323,28 +17948,34 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.22.13 + '@babel/code-frame': 7.26.2 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - parseqs@0.0.6: {} + parseqs@0.0.6: + optional: true - parseuri@0.0.6: {} + parseuri@0.0.6: + optional: true parseurl@1.3.3: {} pascal-case@3.1.2: dependencies: no-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.8.1 + + pascalcase@0.1.1: {} path-browserify@1.0.1: {} path-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.8.1 + + path-dirname@1.0.2: {} path-exists-cli@2.0.0: dependencies: @@ -16365,12 +17996,12 @@ snapshots: path-parse@1.0.7: {} - path-scurry@1.10.1: + path-scurry@1.11.1: dependencies: - lru-cache: 10.0.1 - minipass: 7.0.3 + lru-cache: 10.4.3 + minipass: 7.1.2 - path-to-regexp@0.1.7: {} + path-to-regexp@0.1.12: {} path-type@3.0.0: dependencies: @@ -16378,10 +18009,16 @@ snapshots: path-type@4.0.0: {} - pathe@1.1.1: {} + pathe@1.1.2: {} + + pathe@2.0.3: {} pathval@1.1.1: {} + pause-stream@0.0.11: + dependencies: + through: 2.3.8 + pbkdf2@3.1.2: dependencies: create-hash: 1.2.0 @@ -16396,29 +18033,40 @@ snapshots: duplexify: 3.7.1 through2: 2.0.5 - peerjs-js-binarypack@2.0.0: {} + peerjs-js-binarypack@2.1.0: {} - peerjs@1.5.0: + peerjs@1.5.4: dependencies: '@msgpack/msgpack': 2.8.0 - cbor-x: 1.5.4 eventemitter3: 4.0.7 - peerjs-js-binarypack: 2.0.0 - webrtc-adapter: 8.2.3 + peerjs-js-binarypack: 2.1.0 + webrtc-adapter: 9.0.1 pend@1.2.0: {} - performance-now@2.1.0: {} + performance-now@2.1.0: + optional: true - phin@2.9.3: {} + phin@2.9.3: + optional: true - picocolors@1.0.0: {} + phin@3.7.1(debug@4.4.0): + dependencies: + centra: 2.7.0(debug@4.4.0) + transitivePeerDependencies: + - debug + optional: true + + picocolors@1.1.1: {} picomatch@2.3.1: {} + picomatch@4.0.2: {} + pidtree@0.3.1: {} - pify@2.3.0: {} + pify@2.3.0: + optional: true pify@3.0.0: {} @@ -16426,9 +18074,12 @@ snapshots: pirates@4.0.6: {} + pixelarticons@1.8.1(patch_hash=533230072bc402f425c86abd3d0356fe087b14cab2a254d93f419b083f2d8dfa): {} + pixelmatch@4.0.2: dependencies: pngjs: 3.4.0 + optional: true pkg-dir@3.0.0: dependencies: @@ -16442,23 +18093,24 @@ snapshots: dependencies: find-up: 5.0.0 - pkg-types@1.0.3: + pkg-types@1.3.1: dependencies: - jsonc-parser: 3.2.0 - mlly: 1.4.2 - pathe: 1.1.1 + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 2.0.3 pluralize@8.0.0: {} - pngjs@3.4.0: {} + pngjs@3.4.0: + optional: true - polished@4.2.2: + polished@4.3.1: dependencies: - '@babel/runtime': 7.22.11 + '@babel/runtime': 7.26.9 poly-decomp@0.3.0: {} - portfinder@1.0.32: + portfinder@1.0.33: dependencies: async: 2.6.4 debug: 3.2.7(supports-color@8.1.1) @@ -16466,40 +18118,37 @@ snapshots: transitivePeerDependencies: - supports-color - possible-typed-array-names@1.0.0: {} + posix-character-classes@0.1.1: {} - postcss@8.4.31: - dependencies: - nanoid: 3.3.6 - picocolors: 1.0.0 - source-map-js: 1.0.2 + possible-typed-array-names@1.1.0: {} - postcss@8.4.38: + postcss@8.5.3: dependencies: - nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.2.0 + nanoid: 3.3.9 + picocolors: 1.1.1 + source-map-js: 1.2.1 potpack@1.0.2: {} - prebuild-install@7.1.1: + prebuild-install@7.1.3: dependencies: - detect-libc: 2.0.2 + detect-libc: 2.0.3 expand-template: 2.0.3 github-from-package: 0.0.0 minimist: 1.2.8 mkdirp-classic: 0.5.3 - napi-build-utils: 1.0.2 - node-abi: 3.47.0 - pump: 3.0.0 + napi-build-utils: 2.0.0 + node-abi: 3.74.0 + pump: 3.0.2 rc: 1.2.8 simple-get: 4.0.1 - tar-fs: 2.1.1 + tar-fs: 2.1.2 tunnel-agent: 0.6.0 prelude-ls@1.2.1: {} - prettier@1.19.1: {} + prettier@1.19.1: + optional: true prettier@2.8.8: {} @@ -16511,145 +18160,121 @@ snapshots: dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 - react-is: 18.2.0 + react-is: 18.3.1 pretty-hrtime@1.0.3: {} - prismarine-auth@2.4.2(encoding@0.1.13): + prismarine-auth@2.7.0: dependencies: - '@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.5 - node-fetch: 2.7.0(encoding@0.1.13) + '@azure/msal-node': 2.16.2 + '@xboxreplay/xboxlive-auth': 3.3.3(debug@4.4.0) + debug: 4.4.0(supports-color@8.1.1) smart-buffer: 4.2.0 uuid-1345: 1.0.2 transitivePeerDependencies: - - encoding - supports-color - prismarine-biome@1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0): + prismarine-biome@1.3.0(minecraft-data@3.98.0)(prismarine-registry@1.11.0): dependencies: - minecraft-data: 3.65.0 - prismarine-registry: 1.7.0 + minecraft-data: 3.98.0 + prismarine-registry: 1.11.0 - prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0: + prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9: 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-item: 1.14.0 - prismarine-nbt: 2.5.0 - prismarine-registry: 1.7.0 + minecraft-data: 3.98.0 + prismarine-biome: 1.3.0(minecraft-data@3.98.0)(prismarine-registry@1.11.0) + prismarine-chat: 1.11.0 + prismarine-item: 1.17.0 + prismarine-nbt: 2.7.0 + prismarine-registry: 1.11.0 - prismarine-chat@1.10.1: + prismarine-chat@1.11.0: dependencies: mojangson: 2.0.4 - prismarine-nbt: 2.5.0 - prismarine-registry: 1.7.0 + prismarine-nbt: 2.7.0 + prismarine-registry: 1.11.0 - prismarine-chat@1.9.1: + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0): 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/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 + prismarine-biome: 1.3.0(minecraft-data@3.98.0)(prismarine-registry@1.11.0) + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-nbt: 2.7.0 + prismarine-registry: 1.11.0 smart-buffer: 4.2.0 uint4: 0.1.2 - vec3: 0.1.8 + vec3: 0.1.10 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-entity@2.5.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 + prismarine-chat: 1.11.0 + prismarine-item: 1.17.0 + prismarine-registry: 1.11.0 + vec3: 0.1.10 + + prismarine-item@1.17.0: + dependencies: + prismarine-nbt: 2.7.0 + prismarine-registry: 1.11.0 + + prismarine-nbt@2.7.0: + dependencies: + protodef: 1.18.0 + + prismarine-physics@https://codeload.github.com/zardoy/prismarine-physics/tar.gz/353e25b800149393f40539ec381218be44cbb03b: + dependencies: + minecraft-data: 3.98.0 + prismarine-nbt: 2.7.0 + vec3: 0.1.10 + + prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.98.0): + dependencies: + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0) + prismarine-nbt: 2.7.0 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c uint4: 0.1.2 - vec3: 0.1.8 - xxhash-wasm: 0.4.2 - transitivePeerDependencies: - - minecraft-data - - prismarine-entity@2.3.1: - dependencies: - prismarine-chat: 1.10.1 - prismarine-item: 1.14.0 - prismarine-registry: 1.7.0 - vec3: 0.1.8 - - prismarine-item@1.14.0: - dependencies: - prismarine-nbt: 2.5.0 - prismarine-registry: 1.7.0 - - prismarine-nbt@2.2.1: - dependencies: - protodef: 1.15.0 - - prismarine-nbt@2.5.0: - dependencies: - protodef: 1.15.0 - - prismarine-physics@1.8.0: - dependencies: - 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.65.0): - dependencies: - 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 + vec3: 0.1.10 transitivePeerDependencies: - minecraft-data prismarine-realms@1.3.2(encoding@0.1.13): dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) node-fetch: 2.7.0(encoding@0.1.13) transitivePeerDependencies: - encoding - supports-color - prismarine-recipe@1.3.1(prismarine-registry@1.7.0): + prismarine-recipe@1.3.1(prismarine-registry@1.11.0): dependencies: - prismarine-registry: 1.7.0 + prismarine-registry: 1.11.0 - prismarine-registry@1.7.0: + prismarine-registry@1.11.0: dependencies: - minecraft-data: 3.65.0 - prismarine-nbt: 2.5.0 + minecraft-data: 3.98.0 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-nbt: 2.7.0 prismarine-schematic@1.2.3: dependencies: - 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 - vec3: 0.1.8 + minecraft-data: 3.98.0 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-nbt: 2.7.0 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c + vec3: 0.1.10 prismarine-windows@2.9.0: dependencies: - prismarine-item: 1.14.0 - prismarine-registry: 1.7.0 + prismarine-item: 1.17.0 + prismarine-registry: 1.11.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/ab2146c9933eef3247c3f64446de4ccc2c484c7c: dependencies: - vec3: 0.1.8 + vec3: 0.1.10 process-nextick-args@2.0.1: {} @@ -16681,102 +18306,103 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 - prosemirror-commands@1.5.2: + prosemirror-commands@1.7.0: dependencies: - prosemirror-model: 1.19.4 + prosemirror-model: 1.24.1 prosemirror-state: 1.4.3 - prosemirror-transform: 1.8.0 + prosemirror-transform: 1.10.3 prosemirror-dropcursor@1.8.1: dependencies: prosemirror-state: 1.4.3 - prosemirror-transform: 1.8.0 - prosemirror-view: 1.33.1 + prosemirror-transform: 1.10.3 + prosemirror-view: 1.38.1 - prosemirror-example-setup@1.2.2: + prosemirror-example-setup@1.2.3: dependencies: - prosemirror-commands: 1.5.2 + prosemirror-commands: 1.7.0 prosemirror-dropcursor: 1.8.1 prosemirror-gapcursor: 1.3.2 - prosemirror-history: 1.3.2 + prosemirror-history: 1.4.1 prosemirror-inputrules: 1.4.0 prosemirror-keymap: 1.2.2 prosemirror-menu: 1.2.4 - prosemirror-schema-list: 1.3.0 + prosemirror-schema-list: 1.5.1 prosemirror-state: 1.4.3 prosemirror-gapcursor@1.3.2: dependencies: prosemirror-keymap: 1.2.2 - prosemirror-model: 1.19.4 + prosemirror-model: 1.24.1 prosemirror-state: 1.4.3 - prosemirror-view: 1.33.1 + prosemirror-view: 1.38.1 - prosemirror-history@1.3.2: + prosemirror-history@1.4.1: dependencies: prosemirror-state: 1.4.3 - prosemirror-transform: 1.8.0 - prosemirror-view: 1.33.1 + prosemirror-transform: 1.10.3 + prosemirror-view: 1.38.1 rope-sequence: 1.3.4 prosemirror-inputrules@1.4.0: dependencies: prosemirror-state: 1.4.3 - prosemirror-transform: 1.8.0 + prosemirror-transform: 1.10.3 prosemirror-keymap@1.2.2: dependencies: prosemirror-state: 1.4.3 w3c-keyname: 2.2.8 - prosemirror-markdown@1.12.0: + prosemirror-markdown@1.13.1: dependencies: - markdown-it: 14.0.0 - prosemirror-model: 1.19.4 + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 + prosemirror-model: 1.24.1 prosemirror-menu@1.2.4: dependencies: crelt: 1.0.6 - prosemirror-commands: 1.5.2 - prosemirror-history: 1.3.2 + prosemirror-commands: 1.7.0 + prosemirror-history: 1.4.1 prosemirror-state: 1.4.3 - prosemirror-model@1.19.4: + prosemirror-model@1.24.1: dependencies: orderedmap: 2.1.1 - prosemirror-schema-list@1.3.0: + prosemirror-schema-list@1.5.1: dependencies: - prosemirror-model: 1.19.4 + prosemirror-model: 1.24.1 prosemirror-state: 1.4.3 - prosemirror-transform: 1.8.0 + prosemirror-transform: 1.10.3 prosemirror-state@1.4.3: dependencies: - prosemirror-model: 1.19.4 - prosemirror-transform: 1.8.0 - prosemirror-view: 1.33.1 + prosemirror-model: 1.24.1 + prosemirror-transform: 1.10.3 + prosemirror-view: 1.38.1 - prosemirror-transform@1.8.0: + prosemirror-transform@1.10.3: dependencies: - prosemirror-model: 1.19.4 + prosemirror-model: 1.24.1 - prosemirror-view@1.33.1: + prosemirror-view@1.38.1: dependencies: - prosemirror-model: 1.19.4 + prosemirror-model: 1.24.1 prosemirror-state: 1.4.3 - prosemirror-transform: 1.8.0 + prosemirror-transform: 1.10.3 - protodef-validator@1.3.1: + protodef-validator@1.4.0: dependencies: ajv: 6.12.6 - protodef@1.15.0: + protodef@1.18.0: dependencies: lodash.get: 4.4.2 lodash.reduce: 4.6.0 - protodef-validator: 1.3.1 - readable-stream: 3.6.2 + protodef-validator: 1.4.0 + readable-stream: 4.7.0 proxy-addr@2.0.7: dependencies: @@ -16785,16 +18411,26 @@ snapshots: proxy-compare@2.5.1: {} - proxy-from-env@1.0.0: {} + proxy-compare@2.6.0: {} - psl@1.9.0: {} + proxy-from-env@1.0.0: + optional: true + + proxy-from-env@1.1.0: {} + + proxy-middleware@0.15.0: {} + + psl@1.15.0: + dependencies: + punycode: 2.3.1 + optional: true public-encrypt@4.0.3: dependencies: - bn.js: 4.12.0 - browserify-rsa: 4.1.0 + bn.js: 4.12.1 + browserify-rsa: 4.1.1 create-hash: 1.2.0 - parse-asn1: 5.1.6 + parse-asn1: 5.1.7 randombytes: 2.1.0 safe-buffer: 5.2.1 @@ -16803,7 +18439,7 @@ snapshots: end-of-stream: 1.4.4 once: 1.4.0 - pump@3.0.0: + pump@3.0.2: dependencies: end-of-stream: 1.4.4 once: 1.4.0 @@ -16816,44 +18452,48 @@ snapshots: punycode.js@2.3.1: {} - punycode@2.3.0: {} + punycode@1.4.1: {} punycode@2.3.1: {} puppeteer-core@2.1.1: dependencies: - '@types/mime-types': 2.1.2 - debug: 4.3.4(supports-color@8.1.1) + '@types/mime-types': 2.1.4 + debug: 4.4.1 extract-zip: 1.7.0 https-proxy-agent: 4.0.0 mime: 2.6.0 mime-types: 2.1.35 progress: 2.0.3 - proxy-from-env: 1.0.0 + proxy-from-env: 1.1.0 rimraf: 2.7.1 - ws: 6.2.2 + ws: 6.2.3 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - qrcode.react@3.1.0(react@18.2.0): + qrcode.react@3.2.0(react@18.3.1): dependencies: - react: 18.2.0 + react: 18.3.1 qs@6.10.4: dependencies: - side-channel: 1.0.5 + side-channel: 1.1.0 + optional: true - qs@6.11.0: + qs@6.13.0: dependencies: - side-channel: 1.0.4 + side-channel: 1.1.0 - qs@6.11.2: + qs@6.14.0: dependencies: - side-channel: 1.0.4 + side-channel: 1.1.0 - querystringify@2.2.0: {} + querystring-es3@0.2.1: {} + + querystringify@2.2.0: + optional: true queue-microtask@1.2.3: {} @@ -16865,7 +18505,7 @@ snapshots: rambda@6.9.0: {} - rambda@9.2.0: {} + rambda@9.4.2: {} ramda@0.29.0: {} @@ -16891,13 +18531,6 @@ snapshots: range@0.0.3: {} - raw-body@2.5.1: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - raw-body@2.5.2: dependencies: bytes: 3.1.2 @@ -16916,121 +18549,139 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-colorful@5.6.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + react-colorful@5.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) - react-docgen-typescript@2.2.2(typescript@5.5.0-beta): + react-docgen-typescript@2.2.2(typescript@5.5.4): dependencies: - typescript: 5.5.0-beta + typescript: 5.5.4 - react-docgen@6.0.0-alpha.3: + react-docgen@7.1.1: dependencies: - '@babel/core': 7.22.11 - '@babel/generator': 7.22.10 - ast-types: 0.14.2 - commander: 2.20.3 + '@babel/core': 7.26.9 + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.6 + '@types/doctrine': 0.0.9 + '@types/resolve': 1.20.6 doctrine: 3.0.0 - estree-to-babel: 3.2.1 - neo-async: 2.6.2 - node-dir: 0.1.17 - resolve: 1.22.4 - strip-indent: 3.0.0 + resolve: 1.22.10 + strip-indent: 4.0.0 transitivePeerDependencies: - supports-color - react-dom@18.2.0(react@18.2.0): + react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.23.0 + react: 18.3.1 + scheduler: 0.23.2 - react-element-to-jsx-string@15.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + react-element-to-jsx-string@15.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@base2/pretty-print-object': 1.0.1 is-plain-object: 5.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) react-is: 18.1.0 react-fast-compare@3.2.2: {} - react-inspector@6.0.2(react@18.2.0): + react-hook-form@7.54.2(react@18.3.1): dependencies: - react: 18.2.0 + react: 18.3.1 react-is@16.13.1: {} react-is@18.1.0: {} - react-is@18.2.0: {} + react-is@18.3.1: {} - react-popper@2.3.0(@popperjs/core@2.11.8)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + react-popper@2.3.0(@popperjs/core@2.11.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@popperjs/core': 2.11.8 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) react-fast-compare: 3.2.2 warning: 4.0.3 - react-portal@4.2.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + react-portal@4.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: prop-types: 15.8.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) - react-refresh@0.14.0: {} + react-refresh@0.14.2: {} - react-remove-scroll-bar@2.3.4(@types/react@18.2.20)(react@18.2.0): + react-refresh@0.17.0: {} + + react-remove-scroll-bar@2.3.8(@types/react@18.3.18)(react@18.3.1): dependencies: - react: 18.2.0 - react-style-singleton: 2.2.1(@types/react@18.2.20)(react@18.2.0) - tslib: 2.6.2 + react: 18.3.1 + react-style-singleton: 2.2.3(@types/react@18.3.18)(react@18.3.1) + tslib: 2.8.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - react-remove-scroll@2.5.5(@types/react@18.2.20)(react@18.2.0): + react-remove-scroll@2.5.5(@types/react@18.3.18)(react@18.3.1): dependencies: - react: 18.2.0 - react-remove-scroll-bar: 2.3.4(@types/react@18.2.20)(react@18.2.0) - react-style-singleton: 2.2.1(@types/react@18.2.20)(react@18.2.0) - tslib: 2.6.2 - use-callback-ref: 1.3.0(@types/react@18.2.20)(react@18.2.0) - use-sidecar: 1.1.2(@types/react@18.2.20)(react@18.2.0) + react: 18.3.1 + react-remove-scroll-bar: 2.3.8(@types/react@18.3.18)(react@18.3.1) + react-style-singleton: 2.2.3(@types/react@18.3.18)(react@18.3.1) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@18.3.18)(react@18.3.1) + use-sidecar: 1.1.3(@types/react@18.3.18)(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - react-style-singleton@2.2.1(@types/react@18.2.20)(react@18.2.0): + react-select@5.10.1(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@babel/runtime': 7.26.9 + '@emotion/cache': 11.14.0 + '@emotion/react': 11.14.0(@types/react@18.3.18)(react@18.3.1) + '@floating-ui/dom': 1.6.13 + '@types/react-transition-group': 4.4.12(@types/react@18.3.18) + memoize-one: 6.0.0 + prop-types: 15.8.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + use-isomorphic-layout-effect: 1.2.0(@types/react@18.3.18)(react@18.3.1) + transitivePeerDependencies: + - '@types/react' + - supports-color + + react-style-singleton@2.2.3(@types/react@18.3.18)(react@18.3.1): dependencies: get-nonce: 1.0.1 - invariant: 2.2.4 - react: 18.2.0 - tslib: 2.6.2 + react: 18.3.1 + tslib: 2.8.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - react-transition-group@4.4.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@babel/runtime': 7.22.11 + '@babel/runtime': 7.26.9 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) - react-universal-interface@0.6.2(react@18.2.0)(tslib@2.6.2): + react-universal-interface@0.6.2(react@18.3.1)(tslib@2.8.1): dependencies: - react: 18.2.0 - tslib: 2.6.2 + react: 18.3.1 + tslib: 2.8.1 - react-use-measure@2.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + react-use-measure@2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: debounce: 1.2.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) - react-use@17.3.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + react-use@17.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@types/js-cookie': 2.2.7 '@xobotyi/scrollbar-width': 1.9.5 @@ -17038,18 +18689,23 @@ snapshots: fast-deep-equal: 3.1.3 fast-shallow-equal: 1.0.0 js-cookie: 2.2.1 - nano-css: 5.3.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-universal-interface: 0.6.2(react@18.2.0)(tslib@2.6.2) + nano-css: 5.6.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-universal-interface: 0.6.2(react@18.3.1)(tslib@2.8.1) resize-observer-polyfill: 1.5.1 screenfull: 5.2.0 set-harmonic-interval: 1.0.1 throttle-debounce: 3.0.1 ts-easing: 0.2.0 - tslib: 2.6.2 + tslib: 2.8.1 - react@18.2.0: + react-zoom-pan-pinch@3.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + + react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -17073,14 +18729,14 @@ snapshots: read-pkg@5.2.0: dependencies: - '@types/normalize-package-data': 2.4.2 + '@types/normalize-package-data': 2.4.4 normalize-package-data: 2.5.0 parse-json: 5.2.0 type-fest: 0.6.0 read-pkg@6.0.0: dependencies: - '@types/normalize-package-data': 2.4.2 + '@types/normalize-package-data': 2.4.4 normalize-package-data: 3.0.3 parse-json: 5.2.0 type-fest: 1.4.0 @@ -17109,7 +18765,7 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readable-stream@4.5.2: + readable-stream@4.7.0: dependencies: abort-controller: 3.0.0 buffer: 6.0.3 @@ -17117,89 +18773,97 @@ snapshots: process: 0.11.10 string_decoder: 1.3.0 + readdirp@2.2.1: + dependencies: + graceful-fs: 4.2.11 + micromatch: 3.1.10 + readable-stream: 2.3.8 + transitivePeerDependencies: + - supports-color + readdirp@3.6.0: dependencies: picomatch: 2.3.1 readline@1.3.0: {} - recast@0.21.5: + recast@0.23.11: dependencies: - ast-types: 0.15.2 - esprima: 4.0.1 - source-map: 0.6.1 - tslib: 2.6.2 - - recast@0.23.4: - dependencies: - assert: 2.0.0 ast-types: 0.16.1 esprima: 4.0.1 source-map: 0.6.1 - tslib: 2.6.2 + tiny-invariant: 1.3.3 + tslib: 2.8.1 redent@4.0.0: dependencies: indent-string: 5.0.0 strip-indent: 4.0.0 - reflect.getprototypeof@1.0.6: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - globalthis: 1.0.4 - which-builtin-type: 1.1.3 + reduce-configs@1.1.0: {} - regenerate-unicode-properties@10.1.0: + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regenerate-unicode-properties@10.2.0: dependencies: regenerate: 1.4.2 regenerate@1.4.2: {} - regenerator-runtime@0.13.11: {} + regenerator-runtime@0.13.11: + optional: true - regenerator-runtime@0.14.0: {} + regenerator-runtime@0.14.1: {} regenerator-transform@0.15.2: dependencies: - '@babel/runtime': 7.22.11 + '@babel/runtime': 7.26.9 + + regex-not@1.0.2: + dependencies: + extend-shallow: 3.0.2 + safe-regex: 1.1.0 regexp-tree@0.1.27: {} - regexp.prototype.flags@1.5.1: + regexp.prototype.flags@1.5.4: dependencies: - call-bind: 1.0.2 - define-properties: 1.2.1 - set-function-name: 2.0.1 - - regexp.prototype.flags@1.5.2: - dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 set-function-name: 2.0.2 regexpp@3.2.0: {} - regexpu-core@5.3.2: + regexpu-core@6.2.0: dependencies: - '@babel/regjsgen': 0.8.0 regenerate: 1.4.2 - regenerate-unicode-properties: 10.1.0 - regjsparser: 0.9.1 + regenerate-unicode-properties: 10.2.0 + regjsgen: 0.8.0 + regjsparser: 0.12.0 unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.1.0 + unicode-match-property-value-ecmascript: 2.2.0 + + regjsgen@0.8.0: {} regjsparser@0.10.0: dependencies: jsesc: 0.5.0 - regjsparser@0.9.1: + regjsparser@0.12.0: dependencies: - jsesc: 0.5.0 + jsesc: 3.0.2 remark-external-links@8.0.0: dependencies: @@ -17211,10 +18875,10 @@ snapshots: remark-parse@11.0.0: dependencies: - '@types/mdast': 4.0.3 - mdast-util-from-markdown: 2.0.0 - micromark-util-types: 2.0.0 - unified: 11.0.4 + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + micromark-util-types: 2.0.2 + unified: 11.0.5 transitivePeerDependencies: - supports-color @@ -17226,22 +18890,29 @@ snapshots: remark-stringify@11.0.0: dependencies: - '@types/mdast': 4.0.3 - mdast-util-to-markdown: 2.1.0 - unified: 11.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 remark@15.0.1: dependencies: - '@types/mdast': 4.0.3 + '@types/mdast': 4.0.4 remark-parse: 11.0.0 remark-stringify: 11.0.0 - unified: 11.0.4 + unified: 11.0.5 transitivePeerDependencies: - supports-color + remove-trailing-separator@1.1.0: {} + + repeat-element@1.1.4: {} + + repeat-string@1.6.1: {} + request-progress@3.0.0: dependencies: - throttleit: 1.0.0 + throttleit: 1.0.1 + optional: true require-directory@2.1.1: {} @@ -17257,15 +18928,17 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve@1.22.4: + resolve-url@0.2.1: {} + + resolve@1.22.10: dependencies: - is-core-module: 2.13.0 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 resolve@2.0.0-next.5: dependencies: - is-core-module: 2.13.1 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -17279,9 +18952,10 @@ snapshots: retry@0.12.0: optional: true - reusify@1.0.4: {} + reusify@1.1.0: {} - rfdc@1.3.0: {} + rfdc@1.4.1: + optional: true rimraf@2.6.3: dependencies: @@ -17295,74 +18969,88 @@ snapshots: dependencies: glob: 7.2.3 - rimraf@5.0.1: + rimraf@5.0.10: dependencies: - glob: 10.3.3 + glob: 10.4.5 ripemd160@2.0.2: dependencies: - hash-base: 3.1.0 + hash-base: 3.0.5 inherits: 2.0.4 - rollup-plugin-terser@7.0.2(rollup@2.79.1): - dependencies: - '@babel/code-frame': 7.22.13 - jest-worker: 26.6.2 - rollup: 2.79.1 - serialize-javascript: 4.0.0 - terser: 5.19.2 - - rollup@2.79.1: + rollup@2.79.2: optionalDependencies: fsevents: 2.3.3 - rollup@3.29.4: + rollup@3.29.5: optionalDependencies: fsevents: 2.3.3 + rollup@4.34.9: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.34.9 + '@rollup/rollup-android-arm64': 4.34.9 + '@rollup/rollup-darwin-arm64': 4.34.9 + '@rollup/rollup-darwin-x64': 4.34.9 + '@rollup/rollup-freebsd-arm64': 4.34.9 + '@rollup/rollup-freebsd-x64': 4.34.9 + '@rollup/rollup-linux-arm-gnueabihf': 4.34.9 + '@rollup/rollup-linux-arm-musleabihf': 4.34.9 + '@rollup/rollup-linux-arm64-gnu': 4.34.9 + '@rollup/rollup-linux-arm64-musl': 4.34.9 + '@rollup/rollup-linux-loongarch64-gnu': 4.34.9 + '@rollup/rollup-linux-powerpc64le-gnu': 4.34.9 + '@rollup/rollup-linux-riscv64-gnu': 4.34.9 + '@rollup/rollup-linux-s390x-gnu': 4.34.9 + '@rollup/rollup-linux-x64-gnu': 4.34.9 + '@rollup/rollup-linux-x64-musl': 4.34.9 + '@rollup/rollup-win32-arm64-msvc': 4.34.9 + '@rollup/rollup-win32-ia32-msvc': 4.34.9 + '@rollup/rollup-win32-x64-msvc': 4.34.9 + fsevents: 2.3.3 + rope-sequence@1.3.4: {} rtl-css-js@1.16.1: dependencies: - '@babel/runtime': 7.22.11 + '@babel/runtime': 7.26.9 run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - rxjs@7.8.1: + rxjs@7.8.2: dependencies: - tslib: 2.6.2 + tslib: 2.8.1 - safe-array-concat@1.0.1: + safe-array-concat@1.1.3: dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - has-symbols: 1.0.3 - isarray: 2.0.5 - - safe-array-concat@1.1.2: - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 isarray: 2.0.5 safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} - safe-regex-test@1.0.0: + safe-push-apply@1.0.0: dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - is-regex: 1.1.4 - - safe-regex-test@1.0.3: - dependencies: - call-bind: 1.0.7 es-errors: 1.3.0 - is-regex: 1.1.4 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safe-regex@1.1.0: + dependencies: + ret: 0.1.15 safer-buffer@2.1.2: {} @@ -17372,9 +19060,10 @@ snapshots: sat@0.9.0: {} - sax@1.3.0: {} + sax@1.4.1: + optional: true - scheduler@0.23.0: + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 @@ -17388,15 +19077,9 @@ snapshots: semver@6.3.1: {} - semver@7.5.4: - dependencies: - lru-cache: 6.0.0 + semver@7.7.1: {} - semver@7.6.0: - dependencies: - lru-cache: 6.0.0 - - send@0.18.0: + send@0.19.0: dependencies: debug: 2.6.9 depd: 2.0.0 @@ -17414,42 +19097,65 @@ snapshots: transitivePeerDependencies: - supports-color - sentence-case@3.0.4: + send@1.2.0: dependencies: - no-case: 3.0.4 - tslib: 2.6.2 - upper-case-first: 2.0.2 - - serialize-javascript@4.0.0: - dependencies: - randombytes: 2.1.0 - - serve-static@1.15.0: - dependencies: - encodeurl: 1.0.2 + debug: 4.4.1 + encodeurl: 2.0.0 escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.18.0 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 transitivePeerDependencies: - supports-color - set-blocking@2.0.0: {} + sentence-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + upper-case-first: 2.0.2 - set-function-length@1.2.1: + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + serve-index@1.9.1: + dependencies: + accepts: 1.3.8 + batch: 0.6.1 + debug: 2.6.9 + escape-html: 1.0.3 + http-errors: 1.6.3 + mime-types: 2.1.35 + parseurl: 1.3.3 + transitivePeerDependencies: + - supports-color + + serve-static@1.16.2: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.0 + transitivePeerDependencies: + - supports-color + + set-blocking@2.0.0: + optional: true + + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.0.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 has-property-descriptors: 1.0.2 - set-function-name@2.0.1: - dependencies: - define-data-property: 1.1.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.0 - set-function-name@2.0.2: dependencies: define-data-property: 1.1.4 @@ -17459,8 +19165,23 @@ snapshots: set-harmonic-interval@1.0.1: {} + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + set-value@2.0.1: + dependencies: + extend-shallow: 2.0.1 + is-extendable: 0.1.1 + is-plain-object: 2.0.4 + split-string: 3.1.0 + setimmediate@1.0.5: {} + setprototypeof@1.1.0: {} + setprototypeof@1.2.0: {} sha.js@2.4.11: @@ -17475,14 +19196,41 @@ snapshots: sharp@0.30.7: dependencies: color: 4.2.3 - detect-libc: 2.0.2 + detect-libc: 2.0.3 node-addon-api: 5.1.0 - prebuild-install: 7.1.1 - semver: 7.6.0 + prebuild-install: 7.1.3 + semver: 7.7.1 simple-get: 4.0.1 - tar-fs: 2.1.1 + tar-fs: 2.1.2 tunnel-agent: 0.6.0 + sharp@0.33.5: + dependencies: + color: 4.2.3 + detect-libc: 2.0.3 + semver: 7.7.1 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.33.5 + '@img/sharp-darwin-x64': 0.33.5 + '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-linux-arm': 0.33.5 + '@img/sharp-linux-arm64': 0.33.5 + '@img/sharp-linux-s390x': 0.33.5 + '@img/sharp-linux-x64': 0.33.5 + '@img/sharp-linuxmusl-arm64': 0.33.5 + '@img/sharp-linuxmusl-x64': 0.33.5 + '@img/sharp-wasm32': 0.33.5 + '@img/sharp-win32-ia32': 0.33.5 + '@img/sharp-win32-x64': 0.33.5 + optional: true + shebang-command@1.2.0: dependencies: shebang-regex: 1.0.0 @@ -17495,27 +19243,35 @@ snapshots: shebang-regex@3.0.0: {} - shell-quote@1.8.1: {} + shell-quote@1.8.2: {} - side-channel@1.0.4: + side-channel-list@1.0.0: dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - object-inspect: 1.12.3 - - side-channel@1.0.5: - dependencies: - call-bind: 1.0.7 es-errors: 1.3.0 - get-intrinsic: 1.2.4 - object-inspect: 1.13.1 + object-inspect: 1.13.4 - side-channel@1.0.6: + side-channel-map@1.0.1: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - get-intrinsic: 1.2.4 - object-inspect: 1.13.1 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 siginfo@2.0.0: {} @@ -17530,6 +19286,7 @@ snapshots: decompress-response: 4.2.1 once: 1.4.0 simple-concat: 1.0.1 + optional: true simple-get@4.0.1: dependencies: @@ -17541,15 +19298,11 @@ snapshots: dependencies: is-arrayish: 0.3.2 - simple-update-notifier@2.0.0: - dependencies: - semver: 7.6.0 - sisteransi@1.0.5: {} skinview-utils@0.7.1: {} - skinview3d@3.0.1: + skinview3d@3.1.0: dependencies: '@types/three': 0.156.0 skinview-utils: 0.7.1 @@ -17562,65 +19315,97 @@ snapshots: ansi-styles: 4.3.0 astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 + optional: true slice-ansi@4.0.0: dependencies: ansi-styles: 4.3.0 astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 + optional: true smart-buffer@4.2.0: {} + smob@1.5.0: {} + snake-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.6.2 + tslib: 2.8.1 - socket.io-adapter@1.1.2: {} - - socket.io-adapter@2.5.2: + snapdragon-node@2.1.1: dependencies: - ws: 8.11.0 + define-property: 1.0.0 + isobject: 3.0.1 + snapdragon-util: 3.0.1 + + snapdragon-util@3.0.1: + dependencies: + kind-of: 3.2.2 + + snapdragon@0.8.2: + dependencies: + base: 0.11.2 + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + map-cache: 0.2.2 + source-map: 0.5.7 + source-map-resolve: 0.5.3 + use: 3.1.1 + transitivePeerDependencies: + - supports-color + + socket.io-adapter@1.1.2: + optional: true + + socket.io-adapter@2.5.5: + dependencies: + debug: 4.3.7 + ws: 8.17.1 transitivePeerDependencies: - bufferutil + - supports-color - utf-8-validate socket.io-client@2.5.0: dependencies: backo2: 1.0.2 component-bind: 1.0.0 - component-emitter: 1.3.0 + component-emitter: 1.3.1 debug: 3.1.0 - engine.io-client: 3.5.3 + engine.io-client: 3.5.4 has-binary2: 1.0.3 indexof: 0.0.1 parseqs: 0.0.6 parseuri: 0.0.6 - socket.io-parser: 3.3.3 + socket.io-parser: 3.3.4 to-array: 0.1.4 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate + optional: true - socket.io-client@4.7.2: + socket.io-client@4.8.1: dependencies: - '@socket.io/component-emitter': 3.1.0 - debug: 4.3.4(supports-color@8.1.1) - engine.io-client: 6.5.2 + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.7 + engine.io-client: 6.6.3 socket.io-parser: 4.2.4 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - socket.io-parser@3.3.3: + socket.io-parser@3.3.4: dependencies: - component-emitter: 1.3.0 + component-emitter: 1.3.1 debug: 3.1.0 isarray: 2.0.1 transitivePeerDependencies: - supports-color + optional: true socket.io-parser@3.4.3: dependencies: @@ -17629,18 +19414,19 @@ snapshots: isarray: 2.0.1 transitivePeerDependencies: - supports-color + optional: true socket.io-parser@4.2.4: dependencies: - '@socket.io/component-emitter': 3.1.0 - debug: 4.3.4(supports-color@8.1.1) + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.7 transitivePeerDependencies: - supports-color - socket.io@2.5.0: + socket.io@2.5.1: dependencies: debug: 4.1.1 - engine.io: 3.6.1 + engine.io: 3.6.2 has-binary2: 1.0.3 socket.io-adapter: 1.1.2 socket.io-client: 2.5.0 @@ -17649,15 +19435,16 @@ snapshots: - bufferutil - supports-color - utf-8-validate + optional: true - socket.io@4.7.2: + socket.io@4.8.1: dependencies: accepts: 1.3.8 base64id: 2.0.0 cors: 2.8.5 - debug: 4.3.4(supports-color@8.1.1) - engine.io: 6.5.3 - socket.io-adapter: 2.5.2 + debug: 4.3.7 + engine.io: 6.6.4 + socket.io-adapter: 2.5.5 socket.io-parser: 4.2.4 transitivePeerDependencies: - bufferutil @@ -17667,27 +19454,35 @@ snapshots: socks-proxy-agent@7.0.0: dependencies: agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) - socks: 2.7.1 + debug: 4.4.1 + socks: 2.8.4 transitivePeerDependencies: - supports-color optional: true - socks@2.7.1: + socks@2.8.4: dependencies: - ip: 2.0.0 + ip-address: 9.0.5 smart-buffer: 4.2.0 optional: true - source-map-js@1.0.2: {} + source-map-js@1.2.1: {} - source-map-js@1.2.0: {} + source-map-resolve@0.5.3: + dependencies: + atob: 2.1.2 + decode-uri-component: 0.2.2 + resolve-url: 0.2.1 + source-map-url: 0.4.1 + urix: 0.1.0 source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 + source-map-url@0.4.1: {} + source-map@0.5.6: {} source-map@0.5.7: {} @@ -17705,20 +19500,31 @@ snapshots: spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.13 + spdx-license-ids: 3.0.21 - spdx-exceptions@2.3.0: {} + spdx-exceptions@2.5.0: {} spdx-expression-parse@3.0.1: dependencies: - spdx-exceptions: 2.3.0 - spdx-license-ids: 3.0.13 + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.21 - spdx-license-ids@3.0.13: {} + spdx-license-ids@3.0.21: {} + + split-string@3.1.0: + dependencies: + extend-shallow: 3.0.2 + + split@0.3.3: + dependencies: + through: 2.3.8 sprintf-js@1.0.3: {} - sshpk@1.17.0: + sprintf-js@1.1.3: + optional: true + + sshpk@1.18.0: dependencies: asn1: 0.2.6 assert-plus: 1.0.0 @@ -17729,6 +19535,7 @@ snapshots: jsbn: 0.1.1 safer-buffer: 2.1.2 tweetnacl: 0.14.5 + optional: true ssri@9.0.1: dependencies: @@ -17754,19 +19561,35 @@ snapshots: stack-generator: 2.0.10 stacktrace-gps: 3.1.2 - stats-gl@1.0.5: {} + state-local@1.0.7: {} + + static-extend@0.1.2: + dependencies: + define-property: 0.2.5 + object-copy: 0.1.0 + + stats-gl@1.0.7: {} stats.js@0.17.0: {} + statuses@1.5.0: {} + statuses@2.0.1: {} - std-env@3.4.3: {} + statuses@2.0.2: {} - store2@2.14.2: {} + std-env@3.8.1: {} - storybook@7.4.6(encoding@0.1.13): + stop-iteration-iterator@1.1.0: dependencies: - '@storybook/cli': 7.4.6(encoding@0.1.13) + es-errors: 1.3.0 + internal-slot: 1.1.0 + + store2@2.14.4: {} + + storybook@7.6.20(encoding@0.1.13): + dependencies: + '@storybook/cli': 7.6.20(encoding@0.1.13) transitivePeerDependencies: - bufferutil - encoding @@ -17778,7 +19601,18 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - stream-shift@1.0.1: {} + stream-combiner@0.0.4: + dependencies: + duplexer: 0.1.2 + + stream-http@3.2.0: + dependencies: + builtin-status-codes: 3.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + xtend: 4.0.2 + + stream-shift@1.0.3: {} strict-event-emitter-types@2.0.0: {} @@ -17794,75 +19628,56 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 - string.prototype.matchall@4.0.10: + string.prototype.matchall@4.0.12: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.22.2 - get-intrinsic: 1.2.1 - has-symbols: 1.0.3 - internal-slot: 1.0.5 - regexp.prototype.flags: 1.5.1 - set-function-name: 2.0.1 - side-channel: 1.0.4 - - string.prototype.matchall@4.0.11: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.9 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 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 set-function-name: 2.0.2 - side-channel: 1.0.6 + side-channel: 1.1.0 - string.prototype.padend@3.1.4: + string.prototype.padend@3.1.6: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.22.2 + es-abstract: 1.23.9 + es-object-atoms: 1.1.1 - string.prototype.trim@1.2.8: + string.prototype.repeat@1.0.0: dependencies: - call-bind: 1.0.2 define-properties: 1.2.1 - es-abstract: 1.22.2 + es-abstract: 1.24.0 - string.prototype.trim@1.2.9: + string.prototype.trim@1.2.10: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 + es-abstract: 1.23.9 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 - string.prototype.trimend@1.0.7: + string.prototype.trimend@1.0.9: dependencies: - call-bind: 1.0.2 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.22.2 - - string.prototype.trimend@1.0.8: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 - - string.prototype.trimstart@1.0.7: - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.1 - es-abstract: 1.22.2 + es-object-atoms: 1.1.1 string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 string_decoder@0.10.31: optional: true @@ -17887,7 +19702,7 @@ snapshots: strip-ansi@7.1.0: dependencies: - ansi-regex: 6.0.1 + ansi-regex: 6.1.0 strip-bom@3.0.0: {} @@ -17909,10 +19724,12 @@ snapshots: strip-literal@1.3.0: dependencies: - acorn: 8.10.0 + acorn: 8.14.1 stylis@4.2.0: {} + stylis@4.3.6: {} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -17929,16 +19746,16 @@ snapshots: synchronous-promise@2.0.17: {} - systeminformation@5.22.7: + systeminformation@5.25.11: optional: true tabbable@6.2.0: {} - tar-fs@2.1.1: + tar-fs@2.1.2: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.0 + pump: 3.0.2 tar-stream: 2.2.0 tar-stream@2.2.0: @@ -17949,7 +19766,7 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - tar@6.2.0: + tar@6.2.1: dependencies: chownr: 2.0.0 fs-minipass: 2.1.0 @@ -17983,10 +19800,10 @@ snapshots: type-fest: 0.16.0 unique-string: 2.0.0 - terser@5.19.2: + terser@5.39.0: dependencies: - '@jridgewell/source-map': 0.3.5 - acorn: 8.10.0 + '@jridgewell/source-map': 0.3.6 + acorn: 8.14.1 commander: 2.20.3 source-map-support: 0.5.21 @@ -18006,12 +19823,16 @@ snapshots: dependencies: any-promise: 1.3.0 - three-stdlib@2.28.5(three@0.154.0): + thingies@1.21.0(tslib@2.8.1): dependencies: - '@types/draco3d': 1.4.7 - '@types/offscreencanvas': 2019.7.2 - '@types/webxr': 0.5.7 - draco3d: 1.5.6 + tslib: 2.8.1 + + three-stdlib@2.35.14(three@0.154.0): + dependencies: + '@types/draco3d': 1.4.10 + '@types/offscreencanvas': 2019.7.3 + '@types/webxr': 0.5.21 + draco3d: 1.5.7 fflate: 0.6.10 potpack: 1.0.2 three: 0.154.0 @@ -18022,7 +19843,8 @@ snapshots: throttle-debounce@3.0.1: {} - throttleit@1.0.0: {} + throttleit@1.0.1: + optional: true through2@0.6.5: dependencies: @@ -18041,48 +19863,67 @@ snapshots: dependencies: setimmediate: 1.0.5 - timm@1.7.1: {} + timm@1.7.1: + optional: true - tiny-invariant@1.3.1: {} + tiny-invariant@1.3.3: {} - tinybench@2.5.1: {} + tinybench@2.9.0: {} - tinycolor2@1.6.0: {} + tinycolor2@1.6.0: + optional: true + + tinyexec@0.3.2: {} tinypool@0.7.0: {} - tinyspy@2.2.0: {} + tinyspy@2.2.1: {} title-case@3.0.3: dependencies: - tslib: 2.6.2 + tslib: 2.8.1 - tmp@0.2.1: - dependencies: - rimraf: 3.0.2 + tmp@0.2.3: + optional: true tmpl@1.0.5: {} - to-array@0.1.4: {} + to-array@0.1.4: + optional: true - to-fast-properties@2.0.0: {} + to-object-path@0.3.0: + dependencies: + kind-of: 3.2.2 + + to-regex-range@2.1.1: + dependencies: + is-number: 3.0.0 + repeat-string: 1.6.1 to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - tocbot@4.21.2: {} + to-regex@3.0.2: + dependencies: + define-property: 2.0.2 + extend-shallow: 3.0.2 + regex-not: 1.0.2 + safe-regex: 1.1.0 + + tocbot@4.35.0: {} toggle-selection@1.0.6: {} toidentifier@1.0.1: {} - tough-cookie@4.1.3: + tough-cookie@4.1.4: dependencies: - psl: 1.9.0 + psl: 1.15.0 punycode: 2.3.1 universalify: 0.2.0 url-parse: 1.5.10 + optional: true tr46@0.0.3: {} @@ -18090,23 +19931,43 @@ snapshots: dependencies: punycode: 2.3.1 + tree-dump@1.0.2(tslib@2.8.1): + dependencies: + tslib: 2.8.1 + trim-newlines@4.1.1: {} trough@2.2.0: {} truncate-utf8-bytes@1.0.2: dependencies: - utf8-byte-length: 1.0.4 + utf8-byte-length: 1.0.5 - ts-api-utils@1.0.3(typescript@5.5.0-beta): + ts-api-utils@1.4.3(typescript@5.5.4): dependencies: - typescript: 5.5.0-beta + typescript: 5.5.4 + + ts-api-utils@2.0.1(typescript@5.5.4): + dependencies: + typescript: 5.5.4 + + ts-checker-rspack-plugin@1.1.1(@rspack/core@1.3.3(@swc/helpers@0.5.15))(typescript@5.5.4): + dependencies: + '@babel/code-frame': 7.26.2 + '@rspack/lite-tapable': 1.0.1 + chokidar: 3.6.0 + memfs: 4.17.0 + minimatch: 9.0.5 + picocolors: 1.1.1 + typescript: 5.5.4 + optionalDependencies: + '@rspack/core': 1.3.3(@swc/helpers@0.5.15) ts-dedent@2.2.0: {} ts-easing@0.2.0: {} - tsconfig-paths@3.14.2: + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 json5: 1.0.2 @@ -18115,32 +19976,36 @@ snapshots: tslib@1.14.1: {} - tslib@2.6.2: {} + tslib@2.8.1: {} - tsx@4.7.0: + tsx@4.19.3: dependencies: - esbuild: 0.19.11 - get-tsconfig: 4.7.2 + esbuild: 0.25.0 + get-tsconfig: 4.10.0 optionalDependencies: fsevents: 2.3.3 + tty-browserify@0.0.1: {} + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 - tweetnacl@0.14.5: {} + tweetnacl@0.14.5: + optional: true type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - type-detect@4.0.8: {} + type-detect@4.1.0: {} type-fest@0.16.0: {} type-fest@0.20.2: {} - type-fest@0.21.3: {} + type-fest@0.21.3: + optional: true type-fest@0.6.0: {} @@ -18155,127 +20020,111 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - typed-array-buffer@1.0.0: + typed-array-buffer@1.0.3: dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - is-typed-array: 1.1.12 - - typed-array-buffer@1.0.2: - dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - is-typed-array: 1.1.13 + is-typed-array: 1.1.15 - typed-array-byte-length@1.0.0: + typed-array-byte-length@1.0.3: dependencies: - call-bind: 1.0.2 - for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.12 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 - typed-array-byte-length@1.0.1: - 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 - - typed-array-byte-offset@1.0.0: - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.12 - - typed-array-byte-offset@1.0.2: + typed-array-byte-offset@1.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 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 - typed-array-length@1.0.4: + typed-array-length@1.0.7: dependencies: - call-bind: 1.0.2 - for-each: 0.3.3 - is-typed-array: 1.1.12 - - typed-array-length@1.0.6: - 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 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 typed-emitter@1.4.0: {} typed-emitter@2.1.0: optionalDependencies: - rxjs: 7.8.1 + rxjs: 7.8.2 typedarray@0.0.6: {} - typescript@5.5.0-beta: {} + typescript@5.5.4: {} - ua-parser-js@1.0.37: {} + ua-parser-js@1.0.40: {} uc.micro@2.1.0: {} - ufo@1.3.1: {} + ufo@1.5.4: {} - uglify-js@3.17.4: + uglify-js@3.19.3: optional: true uint4@0.1.2: {} - unbox-primitive@1.0.2: + unbox-primitive@1.1.0: dependencies: - call-bind: 1.0.2 - has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 undici-types@5.26.5: {} - undici@5.25.4: - dependencies: - '@fastify/busboy': 2.0.0 + undici-types@6.20.0: {} - unicode-canonical-property-names-ecmascript@2.0.0: {} + undici@6.0.1: + dependencies: + '@fastify/busboy': 2.1.1 + + unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-match-property-ecmascript@2.0.0: dependencies: - unicode-canonical-property-names-ecmascript: 2.0.0 + unicode-canonical-property-names-ecmascript: 2.0.1 unicode-property-aliases-ecmascript: 2.1.0 - unicode-match-property-value-ecmascript@2.1.0: {} + unicode-match-property-value-ecmascript@2.2.0: {} unicode-property-aliases-ecmascript@2.1.0: {} unidiff@1.0.2: dependencies: diff: 2.2.3 + optional: true - unified@11.0.4: + unified@11.0.5: dependencies: - '@types/unist': 3.0.2 + '@types/unist': 3.0.3 bail: 2.0.2 devlop: 1.1.0 extend: 3.0.2 is-plain-obj: 4.1.0 trough: 2.2.0 - vfile: 6.0.1 + vfile: 6.0.3 + + union-value@1.0.1: + dependencies: + arr-union: 3.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + set-value: 2.0.1 union@0.5.0: dependencies: - qs: 6.11.2 + qs: 6.14.0 unique-filename@2.0.1: dependencies: @@ -18295,70 +20144,79 @@ snapshots: unist-util-is@6.0.0: dependencies: - '@types/unist': 3.0.2 + '@types/unist': 3.0.3 unist-util-stringify-position@4.0.0: dependencies: - '@types/unist': 3.0.2 + '@types/unist': 3.0.3 unist-util-visit-parents@3.1.1: dependencies: - '@types/unist': 2.0.8 + '@types/unist': 2.0.11 unist-util-is: 4.1.0 unist-util-visit-parents@6.0.1: dependencies: - '@types/unist': 3.0.2 + '@types/unist': 3.0.3 unist-util-is: 6.0.0 unist-util-visit@2.0.3: dependencies: - '@types/unist': 2.0.8 + '@types/unist': 2.0.11 unist-util-is: 4.1.0 unist-util-visit-parents: 3.1.1 unist-util-visit@5.0.0: dependencies: - '@types/unist': 3.0.2 + '@types/unist': 3.0.3 unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 - universalify@0.1.2: {} + universalify@0.1.2: + optional: true - universalify@0.2.0: {} + universalify@0.2.0: + optional: true - universalify@2.0.0: {} + universalify@2.0.1: {} + + unix-crypt-td-js@1.1.4: {} unpipe@1.0.0: {} - unplugin@1.5.0: + unplugin@1.16.1: dependencies: - acorn: 8.10.0 - chokidar: 3.5.3 - webpack-sources: 3.2.3 - webpack-virtual-modules: 0.5.0 + acorn: 8.14.1 + webpack-virtual-modules: 0.6.2 + + unset-value@1.0.0: + dependencies: + has-value: 0.3.1 + isobject: 3.0.1 untildify@4.0.0: {} upath@1.2.0: {} - update-browserslist-db@1.0.11(browserslist@4.21.10): + update-browserslist-db@1.1.3(browserslist@4.24.4): dependencies: - browserslist: 4.21.10 - escalade: 3.1.1 - picocolors: 1.0.0 + browserslist: 4.24.4 + escalade: 3.2.0 + picocolors: 1.1.1 upper-case-first@2.0.2: dependencies: - tslib: 2.6.2 + tslib: 2.8.1 upper-case@2.0.2: dependencies: - tslib: 2.6.2 + tslib: 2.8.1 uri-js@4.4.1: dependencies: - punycode: 2.3.0 + punycode: 2.3.1 + + urix@0.1.0: {} url-join@4.0.1: {} @@ -18366,60 +20224,75 @@ snapshots: dependencies: querystringify: 2.2.0 requires-port: 1.0.0 + optional: true - use-callback-ref@1.3.0(@types/react@18.2.20)(react@18.2.0): + url@0.11.4: dependencies: - react: 18.2.0 - tslib: 2.6.2 + punycode: 1.4.1 + qs: 6.14.0 + + use-callback-ref@1.3.3(@types/react@18.3.18)(react@18.3.1): + dependencies: + react: 18.3.1 + tslib: 2.8.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - use-deep-compare@1.1.0(react@18.2.0): + use-deep-compare@1.3.0(react@18.3.1): dependencies: - dequal: 1.0.0 - react: 18.2.0 + dequal: 2.0.3 + react: 18.3.1 - use-resize-observer@9.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + use-isomorphic-layout-effect@1.2.0(@types/react@18.3.18)(react@18.3.1): dependencies: - '@juggle/resize-observer': 3.3.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 - use-sidecar@1.1.2(@types/react@18.2.20)(react@18.2.0): + use-resize-observer@9.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@juggle/resize-observer': 3.4.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + + use-sidecar@1.1.3(@types/react@18.3.18)(react@18.3.1): dependencies: detect-node-es: 1.1.0 - react: 18.2.0 - tslib: 2.6.2 + react: 18.3.1 + tslib: 2.8.1 optionalDependencies: - '@types/react': 18.2.20 + '@types/react': 18.3.18 - use-sync-external-store@1.2.0(react@18.2.0): + use-sync-external-store@1.2.0(react@18.3.1): dependencies: - react: 18.2.0 + react: 18.3.1 - use-typed-event-listener@4.0.2(react@18.2.0)(typescript@5.5.0-beta): + use-typed-event-listener@4.0.2(react@18.3.1)(typescript@5.5.4): dependencies: - '@babel/runtime': 7.22.11 - react: 18.2.0 - use-deep-compare: 1.1.0(react@18.2.0) + '@babel/runtime': 7.26.9 + react: 18.3.1 + use-deep-compare: 1.3.0(react@18.3.1) optionalDependencies: - typescript: 5.5.0-beta + typescript: 5.5.4 - utf8-byte-length@1.0.4: {} + use@3.1.1: {} + + utf8-byte-length@1.0.5: {} utif@2.0.1: dependencies: pako: 1.0.11 + optional: true util-deprecate@1.0.2: {} util@0.12.5: dependencies: inherits: 2.0.4 - is-arguments: 1.1.1 - is-generator-function: 1.0.10 - is-typed-array: 1.1.12 - which-typed-array: 1.1.11 + is-arguments: 1.2.0 + is-generator-function: 1.1.0 + is-typed-array: 1.1.15 + which-typed-array: 1.1.18 utils-merge@1.0.1: {} @@ -18427,58 +20300,63 @@ snapshots: dependencies: macaddress: 0.5.3 + uuid@3.4.0: {} + uuid@8.3.2: {} uuid@9.0.1: {} - v8-to-istanbul@9.1.3: - dependencies: - '@jridgewell/trace-mapping': 0.3.19 - '@types/istanbul-lib-coverage': 2.0.4 - convert-source-map: 2.0.0 - validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - valtio@1.11.2(@types/react@18.2.20)(react@18.2.0): + valtio@1.11.2(@types/react@18.3.18)(react@18.3.1): dependencies: proxy-compare: 2.5.1 - use-sync-external-store: 1.2.0(react@18.2.0) + use-sync-external-store: 1.2.0(react@18.3.1) optionalDependencies: - '@types/react': 18.2.20 - react: 18.2.0 + '@types/react': 18.3.18 + react: 18.3.1 + + valtio@1.13.2(@types/react@18.3.18)(react@18.3.1): + dependencies: + derive-valtio: 0.1.0(valtio@1.13.2(@types/react@18.3.18)(react@18.3.1)) + proxy-compare: 2.6.0 + use-sync-external-store: 1.2.0(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.18 + react: 18.3.1 vary@1.1.2: {} - vec3@0.1.8: {} + vec3@0.1.10: {} verror@1.10.0: dependencies: assert-plus: 1.0.0 core-util-is: 1.0.2 extsprintf: 1.3.0 + optional: true vfile-message@4.0.2: dependencies: - '@types/unist': 3.0.2 + '@types/unist': 3.0.3 unist-util-stringify-position: 4.0.0 - vfile@6.0.1: + vfile@6.0.3: dependencies: - '@types/unist': 3.0.2 - unist-util-stringify-position: 4.0.0 + '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite-node@0.34.6(@types/node@20.8.0)(terser@5.19.2): + vite-node@0.34.6(@types/node@22.13.9)(terser@5.39.0): dependencies: cac: 6.7.14 - debug: 4.3.4(supports-color@8.1.1) - mlly: 1.4.2 - pathe: 1.1.1 - picocolors: 1.0.0 - vite: 4.4.10(@types/node@20.8.0)(terser@5.19.2) + debug: 4.4.0(supports-color@8.1.1) + mlly: 1.7.4 + pathe: 1.1.2 + picocolors: 1.1.1 + vite: 4.5.9(@types/node@22.13.9)(terser@5.39.0) transitivePeerDependencies: - '@types/node' - less @@ -18489,62 +20367,55 @@ snapshots: - supports-color - terser - vite@4.4.10(@types/node@20.12.8)(terser@5.19.2): + vite@4.5.9(@types/node@22.13.9)(terser@5.39.0): dependencies: esbuild: 0.18.20 - postcss: 8.4.31 - rollup: 3.29.4 + postcss: 8.5.3 + rollup: 3.29.5 optionalDependencies: - '@types/node': 20.12.8 + '@types/node': 22.13.9 fsevents: 2.3.3 - terser: 5.19.2 + terser: 5.39.0 - vite@4.4.10(@types/node@20.8.0)(terser@5.19.2): + vite@6.2.1(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0): dependencies: - esbuild: 0.18.20 - postcss: 8.4.31 - rollup: 3.29.4 + esbuild: 0.25.0 + postcss: 8.5.3 + rollup: 4.34.9 optionalDependencies: - '@types/node': 20.8.0 + '@types/node': 22.13.9 fsevents: 2.3.3 - terser: 5.19.2 + jiti: 2.4.2 + terser: 5.39.0 + tsx: 4.19.3 + yaml: 2.7.0 - vite@4.5.3(@types/node@20.8.0)(terser@5.19.2): + vitest@0.34.6(terser@5.39.0): dependencies: - esbuild: 0.18.20 - postcss: 8.4.38 - rollup: 3.29.4 - optionalDependencies: - '@types/node': 20.8.0 - fsevents: 2.3.3 - terser: 5.19.2 - - vitest@0.34.6(terser@5.19.2): - dependencies: - '@types/chai': 4.3.6 - '@types/chai-subset': 1.3.3 - '@types/node': 20.8.0 + '@types/chai': 4.3.20 + '@types/chai-subset': 1.3.6(@types/chai@4.3.20) + '@types/node': 22.13.9 '@vitest/expect': 0.34.6 '@vitest/runner': 0.34.6 '@vitest/snapshot': 0.34.6 '@vitest/spy': 0.34.6 '@vitest/utils': 0.34.6 - acorn: 8.10.0 - acorn-walk: 8.2.0 + acorn: 8.14.1 + acorn-walk: 8.3.4 cac: 6.7.14 - chai: 4.3.10 - debug: 4.3.4(supports-color@8.1.1) + chai: 4.5.0 + debug: 4.4.0(supports-color@8.1.1) local-pkg: 0.4.3 - magic-string: 0.30.4 - pathe: 1.1.1 - picocolors: 1.0.0 - std-env: 3.4.3 + magic-string: 0.30.17 + pathe: 1.1.2 + picocolors: 1.1.1 + std-env: 3.8.1 strip-literal: 1.3.0 - tinybench: 2.5.1 + tinybench: 2.9.0 tinypool: 0.7.0 - vite: 4.4.10(@types/node@20.8.0)(terser@5.19.2) - vite-node: 0.34.6(@types/node@20.8.0)(terser@5.19.2) - why-is-node-running: 2.2.2 + vite: 4.5.9(@types/node@22.13.9)(terser@5.39.0) + vite-node: 0.34.6(@types/node@22.13.9)(terser@5.39.0) + why-is-node-running: 2.3.0 transitivePeerDependencies: - less - lightningcss @@ -18554,8 +20425,20 @@ snapshots: - supports-color - terser + vm-browserify@1.1.2: {} + w3c-keyname@2.2.8: {} + wait-on@7.2.0(debug@4.4.0): + dependencies: + axios: 1.8.2(debug@4.4.0) + joi: 17.13.3 + lodash: 4.17.21 + minimist: 1.2.8 + rxjs: 7.8.2 + transitivePeerDependencies: + - debug + walker@1.0.8: dependencies: makeerror: 1.0.12 @@ -18564,7 +20447,7 @@ snapshots: dependencies: loose-envify: 1.4.0 - watchpack@2.4.0: + watchpack@2.4.2: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 @@ -18577,19 +20460,26 @@ snapshots: webidl-conversions@4.0.2: {} - webpack-sources@3.2.3: {} + webpack-virtual-modules@0.6.2: {} - webpack-virtual-modules@0.5.0: {} - - webrtc-adapter@8.2.3: + webrtc-adapter@9.0.1: dependencies: sdp: 3.2.0 + websocket-driver@0.7.4: + dependencies: + http-parser-js: 0.5.9 + safe-buffer: 5.2.1 + websocket-extensions: 0.1.4 + + websocket-extensions@0.1.4: {} + whatwg-encoding@2.0.0: dependencies: iconv-lite: 0.6.3 - whatwg-fetch@3.6.18: {} + whatwg-fetch@3.6.20: + optional: true whatwg-url@5.0.0: dependencies: @@ -18602,50 +20492,54 @@ snapshots: tr46: 1.0.1 webidl-conversions: 4.0.2 - which-boxed-primitive@1.0.2: + which-boxed-primitive@1.1.1: dependencies: - is-bigint: 1.0.4 - is-boolean-object: 1.1.2 - is-number-object: 1.0.7 - is-string: 1.0.7 - is-symbol: 1.0.4 + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 - which-builtin-type@1.1.3: + which-builtin-type@1.2.1: dependencies: - function.prototype.name: 1.1.6 + call-bound: 1.0.4 + function.prototype.name: 1.1.8 has-tostringtag: 1.0.2 - is-async-function: 2.0.0 - is-date-object: 1.0.5 - is-finalizationregistry: 1.0.2 - is-generator-function: 1.0.10 - is-regex: 1.1.4 - is-weakref: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.0 + is-regex: 1.2.1 + is-weakref: 1.1.1 isarray: 2.0.5 - which-boxed-primitive: 1.0.2 + which-boxed-primitive: 1.1.1 which-collection: 1.0.2 - which-typed-array: 1.1.15 + which-typed-array: 1.1.18 which-collection@1.0.2: dependencies: is-map: 2.0.3 is-set: 2.0.3 is-weakmap: 2.0.2 - is-weakset: 2.0.3 + is-weakset: 2.0.4 - which-typed-array@1.1.11: - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.0 - - which-typed-array@1.1.15: + which-typed-array@1.1.18: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 has-tostringtag: 1.0.2 which@1.3.1: @@ -18656,7 +20550,7 @@ snapshots: dependencies: isexe: 2.0.0 - why-is-node-running@2.2.2: + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 stackback: 0.0.2 @@ -18664,127 +20558,131 @@ snapshots: wide-align@1.1.5: dependencies: string-width: 4.2.3 + optional: true + + word-wrap@1.2.5: {} wordwrap@1.0.0: {} - workbox-background-sync@7.0.0: + workbox-background-sync@7.3.0: dependencies: idb: 7.1.1 - workbox-core: 7.0.0 + workbox-core: 7.3.0 - workbox-broadcast-update@7.0.0: + workbox-broadcast-update@7.3.0: dependencies: - workbox-core: 7.0.0 + workbox-core: 7.3.0 - workbox-build@7.0.0(@types/babel__core@7.20.2): + workbox-build@7.3.0(@types/babel__core@7.20.5): dependencies: - '@apideck/better-ajv-errors': 0.3.6(ajv@8.12.0) - '@babel/core': 7.22.11 - '@babel/preset-env': 7.22.10(@babel/core@7.22.11) - '@babel/runtime': 7.22.11 - '@rollup/plugin-babel': 5.3.1(@babel/core@7.22.11)(@types/babel__core@7.20.2)(rollup@2.79.1) - '@rollup/plugin-node-resolve': 11.2.1(rollup@2.79.1) - '@rollup/plugin-replace': 2.4.2(rollup@2.79.1) + '@apideck/better-ajv-errors': 0.3.6(ajv@8.17.1) + '@babel/core': 7.26.9 + '@babel/preset-env': 7.26.9(@babel/core@7.26.9) + '@babel/runtime': 7.26.9 + '@rollup/plugin-babel': 5.3.1(@babel/core@7.26.9)(@types/babel__core@7.20.5)(rollup@2.79.2) + '@rollup/plugin-node-resolve': 15.3.1(rollup@2.79.2) + '@rollup/plugin-replace': 2.4.2(rollup@2.79.2) + '@rollup/plugin-terser': 0.4.4(rollup@2.79.2) '@surma/rollup-plugin-off-main-thread': 2.2.3 - ajv: 8.12.0 + ajv: 8.17.1 common-tags: 1.8.2 fast-json-stable-stringify: 2.1.0 fs-extra: 9.1.0 glob: 7.2.3 lodash: 4.17.21 pretty-bytes: 5.6.0 - rollup: 2.79.1 - rollup-plugin-terser: 7.0.2(rollup@2.79.1) + rollup: 2.79.2 source-map: 0.8.0-beta.0 stringify-object: 3.3.0 strip-comments: 2.0.1 tempy: 0.6.0 upath: 1.2.0 - workbox-background-sync: 7.0.0 - workbox-broadcast-update: 7.0.0 - workbox-cacheable-response: 7.0.0 - workbox-core: 7.0.0 - workbox-expiration: 7.0.0 - workbox-google-analytics: 7.0.0 - workbox-navigation-preload: 7.0.0 - workbox-precaching: 7.0.0 - workbox-range-requests: 7.0.0 - workbox-recipes: 7.0.0 - workbox-routing: 7.0.0 - workbox-strategies: 7.0.0 - workbox-streams: 7.0.0 - workbox-sw: 7.0.0 - workbox-window: 7.0.0 + workbox-background-sync: 7.3.0 + workbox-broadcast-update: 7.3.0 + workbox-cacheable-response: 7.3.0 + workbox-core: 7.3.0 + workbox-expiration: 7.3.0 + workbox-google-analytics: 7.3.0 + workbox-navigation-preload: 7.3.0 + workbox-precaching: 7.3.0 + workbox-range-requests: 7.3.0 + workbox-recipes: 7.3.0 + workbox-routing: 7.3.0 + workbox-strategies: 7.3.0 + workbox-streams: 7.3.0 + workbox-sw: 7.3.0 + workbox-window: 7.3.0 transitivePeerDependencies: - '@types/babel__core' - supports-color - workbox-cacheable-response@7.0.0: + workbox-cacheable-response@7.3.0: dependencies: - workbox-core: 7.0.0 + workbox-core: 7.3.0 - workbox-core@7.0.0: {} + workbox-core@7.3.0: {} - workbox-expiration@7.0.0: + workbox-expiration@7.3.0: dependencies: idb: 7.1.1 - workbox-core: 7.0.0 + workbox-core: 7.3.0 - workbox-google-analytics@7.0.0: + workbox-google-analytics@7.3.0: dependencies: - workbox-background-sync: 7.0.0 - workbox-core: 7.0.0 - workbox-routing: 7.0.0 - workbox-strategies: 7.0.0 + workbox-background-sync: 7.3.0 + workbox-core: 7.3.0 + workbox-routing: 7.3.0 + workbox-strategies: 7.3.0 - workbox-navigation-preload@7.0.0: + workbox-navigation-preload@7.3.0: dependencies: - workbox-core: 7.0.0 + workbox-core: 7.3.0 - workbox-precaching@7.0.0: + workbox-precaching@7.3.0: dependencies: - workbox-core: 7.0.0 - workbox-routing: 7.0.0 - workbox-strategies: 7.0.0 + workbox-core: 7.3.0 + workbox-routing: 7.3.0 + workbox-strategies: 7.3.0 - workbox-range-requests@7.0.0: + workbox-range-requests@7.3.0: dependencies: - workbox-core: 7.0.0 + workbox-core: 7.3.0 - workbox-recipes@7.0.0: + workbox-recipes@7.3.0: dependencies: - workbox-cacheable-response: 7.0.0 - workbox-core: 7.0.0 - workbox-expiration: 7.0.0 - workbox-precaching: 7.0.0 - workbox-routing: 7.0.0 - workbox-strategies: 7.0.0 + workbox-cacheable-response: 7.3.0 + workbox-core: 7.3.0 + workbox-expiration: 7.3.0 + workbox-precaching: 7.3.0 + workbox-routing: 7.3.0 + workbox-strategies: 7.3.0 - workbox-routing@7.0.0: + workbox-routing@7.3.0: dependencies: - workbox-core: 7.0.0 + workbox-core: 7.3.0 - workbox-strategies@7.0.0: + workbox-strategies@7.3.0: dependencies: - workbox-core: 7.0.0 + workbox-core: 7.3.0 - workbox-streams@7.0.0: + workbox-streams@7.3.0: dependencies: - workbox-core: 7.0.0 - workbox-routing: 7.0.0 + workbox-core: 7.3.0 + workbox-routing: 7.3.0 - workbox-sw@7.0.0: {} + workbox-sw@7.3.0: {} - workbox-window@7.0.0: + workbox-window@7.3.0: dependencies: - '@types/trusted-types': 2.0.3 - workbox-core: 7.0.0 + '@types/trusted-types': 2.0.7 + workbox-core: 7.3.0 wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 + optional: true wrap-ansi@7.0.0: dependencies: @@ -18811,17 +20709,20 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 3.0.7 - ws@5.2.3: + ws@5.2.4: dependencies: async-limiter: 1.0.1 - ws@6.2.2: + ws@6.2.3: dependencies: async-limiter: 1.0.1 - ws@7.4.6: {} + ws@7.5.10: + optional: true - ws@8.11.0: {} + ws@8.17.1: {} + + ws@8.18.1: {} xhr@2.6.0: dependencies: @@ -18829,19 +20730,24 @@ snapshots: is-function: 1.0.2 parse-headers: 2.0.5 xtend: 4.0.2 + optional: true - xml-parse-from-string@1.0.1: {} + xml-parse-from-string@1.0.1: + optional: true - xml2js@0.4.23: + xml2js@0.5.0: dependencies: - sax: 1.3.0 + sax: 1.4.1 xmlbuilder: 11.0.1 + optional: true - xmlbuilder@11.0.1: {} + xmlbuilder@11.0.1: + optional: true - xmlhttprequest-ssl@1.6.3: {} + xmlhttprequest-ssl@1.6.3: + optional: true - xmlhttprequest-ssl@2.0.0: {} + xmlhttprequest-ssl@2.1.2: {} xtend@4.0.2: {} @@ -18855,28 +20761,16 @@ snapshots: yaml@1.10.2: {} - yaml@2.3.2: {} - - yaml@2.4.1: {} + yaml@2.7.0: {} yargs-parser@20.2.9: {} yargs-parser@21.1.1: {} - yargs@16.2.0: - dependencies: - cliui: 7.0.4 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - yargs@17.7.2: dependencies: cliui: 8.0.1 - escalade: 3.1.1 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -18888,7 +20782,12 @@ snapshots: buffer-crc32: 0.2.13 fd-slicer: 1.1.0 - yeast@0.1.2: {} + yazl@2.5.1: + dependencies: + buffer-crc32: 0.2.13 + + yeast@0.1.2: + optional: true yggdrasil@1.7.0(encoding@0.1.13): dependencies: @@ -18899,10 +20798,12 @@ snapshots: yocto-queue@0.1.0: {} - yocto-queue@1.0.0: {} + yocto-queue@1.2.0: {} - zustand@3.6.5(react@18.2.0): + zod@3.24.2: {} + + zustand@3.6.5(react@18.3.1): optionalDependencies: - react: 18.2.0 + react: 18.3.1 zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 131aadfe..5de14962 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,4 @@ packages: - "." - - "prismarine-viewer" - - "prismarine-viewer/viewer/sign-renderer/" + - "renderer" + - "renderer/viewer/sign-renderer/" diff --git a/prismarine-viewer/README.MD b/prismarine-viewer/README.MD new file mode 100644 index 00000000..7273a338 --- /dev/null +++ b/prismarine-viewer/README.MD @@ -0,0 +1,5 @@ +# Prismarine Viewer + +Renamed to `renderer`. + +For more info see [CONTRIBUTING.md](../CONTRIBUTING.md). diff --git a/prismarine-viewer/esbuild.mjs b/prismarine-viewer/esbuild.mjs deleted file mode 100644 index 9614a3ad..00000000 --- a/prismarine-viewer/esbuild.mjs +++ /dev/null @@ -1,96 +0,0 @@ -import * as fs from 'fs' -import fsExtra from 'fs-extra' - -//@ts-check -import * as esbuild from 'esbuild' -import { polyfillNode } from 'esbuild-plugin-polyfill-node' -import path, { dirname, join } from 'path' -import { fileURLToPath } from 'url' - -const dev = process.argv.includes('-w') - -const __dirname = path.dirname(fileURLToPath(new URL(import.meta.url))) - -const mcDataPath = join(__dirname, '../dist/mc-data') -if (!fs.existsSync(mcDataPath)) { - // shouldn't it be in the viewer instead? - await import('../scripts/prepareData.mjs') -} - -fs.mkdirSync(join(__dirname, 'public'), { recursive: true }) -fs.copyFileSync(join(__dirname, 'playground.html'), join(__dirname, 'public/index.html')) -fsExtra.copySync(mcDataPath, join(__dirname, 'public/mc-data')) -const availableVersions = fs.readdirSync(mcDataPath).map(ver => ver.replace('.js', '')) - -/** @type {import('esbuild').BuildOptions} */ -const buildOptions = { - bundle: true, - entryPoints: [join(__dirname, './examples/playground.ts')], - // target: ['es2020'], - // logLevel: 'debug', - logLevel: 'info', - platform: 'browser', - sourcemap: dev ? 'inline' : false, - minify: !dev, - outfile: join(__dirname, 'public/playground.js'), - mainFields: [ - 'browser', 'module', 'main' - ], - keepNames: true, - banner: { - js: `globalThis.global = globalThis;globalThis.includedVersions = ${JSON.stringify(availableVersions)};`, - }, - alias: { - events: 'events', - buffer: 'buffer', - 'fs': 'browserfs/dist/shims/fs.js', - http: 'http-browserify', - stream: 'stream-browserify', - net: 'net-browserify', - }, - inject: [], - metafile: true, - loader: { - '.png': 'dataurl', - '.obj': 'text', - }, - plugins: [ - { - name: 'minecraft-data', - setup (build) { - build.onLoad({ - filter: /minecraft-data[\/\\]data.js$/, - }, () => { - const defaultVersionsObj = {} - return { - contents: `window.mcData ??= ${JSON.stringify(defaultVersionsObj)};module.exports = { pc: window.mcData }`, - loader: 'js', - } - }) - build.onEnd((e) => { - if (e.errors.length) return - fs.writeFileSync(join(__dirname, 'public/metafile.json'), JSON.stringify(e.metafile), 'utf8') - }) - } - }, - polyfillNode({ - polyfills: { - fs: false, - crypto: false, - events: false, - http: false, - stream: false, - buffer: false, - perf_hooks: false, - net: false, - }, - }) - ], -} -if (dev) { - (await esbuild.context(buildOptions)).watch() -} else { - await esbuild.build(buildOptions) -} - -// await ctx.rebuild() diff --git a/prismarine-viewer/examples/playground.ts b/prismarine-viewer/examples/playground.ts deleted file mode 100644 index 223fc6f2..00000000 --- a/prismarine-viewer/examples/playground.ts +++ /dev/null @@ -1,478 +0,0 @@ -import _ from 'lodash' -import { WorldDataEmitter, Viewer } from '../viewer' -import { Vec3 } from 'vec3' -import BlockLoader from 'prismarine-block' -import ChunkLoader from 'prismarine-chunk' -import WorldLoader from 'prismarine-world' -import * as THREE from 'three' -import { GUI } from 'lil-gui' -import { toMajor } from '../viewer/lib/version' -import { loadScript } from '../viewer/lib/utils' -import JSZip from 'jszip' -import { TWEEN_DURATION } from '../viewer/lib/entities' -import { EntityMesh } from '../viewer/lib/entity/EntityMesh' - -globalThis.THREE = THREE -//@ts-ignore -import { OrbitControls } from 'three/addons/controls/OrbitControls.js' - -const gui = new GUI() - -// initial values -const params = { - skip: '', - version: globalThis.includedVersions.sort((a, b) => { - const s = (x) => { - const parts = x.split('.') - return +parts[0] + (+parts[1]) - } - return s(a) - s(b) - }).at(-1), - block: '', - metadata: 0, - supportBlock: false, - entity: '', - removeEntity () { - this.entity = '' - }, - entityRotate: false, - camera: '', - playSound () { }, - blockIsomorphicRenderBundle () { } -} - -const qs = new URLSearchParams(window.location.search) -qs.forEach((value, key) => { - const parsed = value.match(/^-?\d+$/) ? parseInt(value) : value === 'true' ? true : value === 'false' ? false : value - params[key] = parsed -}) -const setQs = () => { - const newQs = new URLSearchParams() - for (const [key, value] of Object.entries(params)) { - if (!value || typeof value === 'function' || params.skip.includes(key)) continue - //@ts-ignore - newQs.set(key, value) - } - window.history.replaceState({}, '', `${window.location.pathname}?${newQs}`) -} - -let ignoreResize = false - -async function main () { - let continuousRender = false - - const { version } = params - // temporary solution until web worker is here, cache data for faster reloads - const globalMcData = window['mcData'] - if (!globalMcData['version']) { - const major = toMajor(version) - const sessionKey = `mcData-${major}` - if (sessionStorage[sessionKey]) { - Object.assign(globalMcData, JSON.parse(sessionStorage[sessionKey])) - } else { - if (sessionStorage.length > 1) sessionStorage.clear() - await loadScript(`./mc-data/${major}.js`) - try { - sessionStorage[sessionKey] = JSON.stringify(Object.fromEntries(Object.entries(globalMcData).filter(([ver]) => ver.startsWith(major)))) - } catch { } - } - } - - const mcData = require('minecraft-data')(version) - window['loadedData'] = mcData - - gui.add(params, 'version', globalThis.includedVersions) - gui.add(params, 'block', mcData.blocksArray.map(b => b.name).sort((a, b) => a.localeCompare(b))) - const metadataGui = gui.add(params, 'metadata') - gui.add(params, 'supportBlock') - gui.add(params, 'entity', mcData.entitiesArray.map(b => b.name).sort((a, b) => a.localeCompare(b))).listen() - gui.add(params, 'removeEntity') - gui.add(params, 'entityRotate') - gui.add(params, 'skip') - gui.add(params, 'playSound') - gui.add(params, 'blockIsomorphicRenderBundle') - gui.open(false) - let metadataFolder = gui.addFolder('metadata') - // let entityRotationFolder = gui.addFolder('entity metadata') - - const Chunk = ChunkLoader(version) - const Block = BlockLoader(version) - // const data = await fetch('smallhouse1.schem').then(r => r.arrayBuffer()) - // const schem = await Schematic.read(Buffer.from(data), version) - - const viewDistance = 0 - const targetPos = new Vec3(2, 90, 2) - - const World = WorldLoader(version) - - // const diamondSquare = require('diamond-square')({ version, seed: Math.floor(Math.random() * Math.pow(2, 31)) }) - - //@ts-ignore - const chunk1 = new Chunk() - //@ts-ignore - const chunk2 = new Chunk() - chunk1.setBlockStateId(targetPos, 34) - chunk2.setBlockStateId(targetPos.offset(1, 0, 0), 34) - const world = new World((chunkX, chunkZ) => { - // if (chunkX === 0 && chunkZ === 0) return chunk1 - // if (chunkX === 1 && chunkZ === 0) return chunk2 - //@ts-ignore - const chunk = new Chunk() - return chunk - }) - - // await schem.paste(world, new Vec3(0, 60, 0)) - - const worldView = new WorldDataEmitter(world, viewDistance, targetPos) - - // Create three.js context, add to page - const renderer = new THREE.WebGLRenderer({ alpha: true, ...localStorage['renderer'] }) - renderer.setPixelRatio(window.devicePixelRatio || 1) - renderer.setSize(window.innerWidth, window.innerHeight) - document.body.appendChild(renderer.domElement) - - // Create viewer - const viewer = new Viewer(renderer, { numWorkers: 1, showChunkBorders: false }) - viewer.entities.setDebugMode('basic') - viewer.setVersion(version) - viewer.entities.onSkinUpdate = () => { - viewer.render() - } - viewer.world.mesherConfig.enableLighting = false - - viewer.listen(worldView) - // Load chunks - await worldView.init(targetPos) - window['worldView'] = worldView - window['viewer'] = viewer - - params.blockIsomorphicRenderBundle = () => { - const canvas = renderer.domElement - const onlyCurrent = !confirm('Ok - render all blocks, Cancel - render only current one') - const sizeRaw = prompt('Size', '512') - if (!sizeRaw) return - const size = parseInt(sizeRaw) - // const size = 512 - - ignoreResize = true - canvas.width = size - canvas.height = size - renderer.setSize(size, size) - - //@ts-ignore - viewer.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 10) - viewer.scene.background = null - - const rad = THREE.MathUtils.degToRad(-120) - viewer.directionalLight.position.set( - Math.cos(rad), - Math.sin(rad), - 0.2 - ).normalize() - viewer.directionalLight.intensity = 1 - - const cameraPos = targetPos.offset(2, 2, 2) - const pitch = THREE.MathUtils.degToRad(-30) - const yaw = THREE.MathUtils.degToRad(45) - viewer.camera.rotation.set(pitch, yaw, 0, 'ZYX') - // viewer.camera.lookAt(center.x + 0.5, center.y + 0.5, center.z + 0.5) - viewer.camera.position.set(cameraPos.x + 1, cameraPos.y + 0.5, cameraPos.z + 1) - - const allBlocks = mcData.blocksArray.map(b => b.name) - // const allBlocks = ['stone', 'warped_slab'] - - let blockCount = 1 - let blockName = allBlocks[0] - - const updateBlock = () => { - - //@ts-ignore - // viewer.setBlockStateId(targetPos, mcData.blocksByName[blockName].minStateId) - params.block = blockName - // todo cleanup (introduce getDefaultState) - onUpdate.block() - applyChanges(false, true) - } - viewer.waitForChunksToRender().then(async () => { - // wait for next macro task - await new Promise(resolve => { - setTimeout(resolve, 0) - }) - if (onlyCurrent) { - viewer.render() - onWorldUpdate() - } else { - // will be called on every render update - viewer.world.renderUpdateEmitter.addListener('update', onWorldUpdate) - updateBlock() - } - }) - - const zip = new JSZip() - zip.file('description.txt', 'Generated with prismarine-viewer') - - const end = async () => { - // download zip file - - const a = document.createElement('a') - const blob = await zip.generateAsync({ type: 'blob' }) - const dataUrlZip = URL.createObjectURL(blob) - a.href = dataUrlZip - a.download = 'blocks_render.zip' - a.click() - URL.revokeObjectURL(dataUrlZip) - console.log('end') - - viewer.world.renderUpdateEmitter.removeListener('update', onWorldUpdate) - } - - async function onWorldUpdate () { - // await new Promise(resolve => { - // setTimeout(resolve, 50) - // }) - const dataUrl = canvas.toDataURL('image/png') - - zip.file(`${blockName}.png`, dataUrl.split(',')[1], { base64: true }) - - if (onlyCurrent) { - end() - } else { - nextBlock() - } - } - const nextBlock = async () => { - blockName = allBlocks[blockCount++] - console.log(allBlocks.length, '/', blockCount, blockName) - if (blockCount % 5 === 0) { - await new Promise(resolve => { - setTimeout(resolve, 100) - }) - } - if (blockName) { - updateBlock() - } else { - end() - } - } - } - - //@ts-ignore - const controls = new OrbitControls(viewer.camera, renderer.domElement) - controls.target.set(targetPos.x + 0.5, targetPos.y + 0.5, targetPos.z + 0.5) - - const cameraPos = targetPos.offset(2, 2, 2) - const pitch = THREE.MathUtils.degToRad(-45) - const yaw = THREE.MathUtils.degToRad(45) - viewer.camera.rotation.set(pitch, yaw, 0, 'ZYX') - viewer.camera.lookAt(targetPos.x + 0.5, targetPos.y + 0.5, targetPos.z + 0.5) - viewer.camera.position.set(cameraPos.x + 0.5, cameraPos.y + 0.5, cameraPos.z + 0.5) - controls.update() - - let blockProps = {} - let entityOverrides = {} - const getBlock = () => { - return mcData.blocksByName[params.block || 'air'] - } - - const entityUpdateShared = () => { - viewer.entities.clear() - if (!params.entity) return - worldView.emit('entity', { - id: 'id', name: params.entity, pos: targetPos.offset(0.5, 1, 0.5), width: 1, height: 1, username: localStorage.testUsername, yaw: Math.PI, pitch: 0 - }) - const enableSkeletonDebug = (obj) => { - const { children, isSkeletonHelper } = obj - if (!Array.isArray(children)) return - if (isSkeletonHelper) { - obj.visible = true - return - } - for (const child of children) { - if (typeof child === 'object') enableSkeletonDebug(child) - } - } - enableSkeletonDebug(viewer.entities.entities['id']) - setTimeout(() => { - viewer.render() - }, TWEEN_DURATION) - } - - const onUpdate = { - block () { - metadataFolder.destroy() - const block = mcData.blocksByName[params.block] - if (!block) return - const props = new Block(block.id, 0, 0).getProperties() - //@ts-ignore - const { states } = mcData.blocksByStateId[getBlock()?.minStateId] ?? {} - metadataFolder = gui.addFolder('metadata') - if (states) { - for (const state of states) { - let defaultValue - switch (state.type) { - case 'enum': - defaultValue = state.values[0] - break - case 'bool': - defaultValue = false - break - case 'int': - defaultValue = 0 - break - case 'direction': - defaultValue = 'north' - break - - default: - continue - } - blockProps[state.name] = defaultValue - if (state.type === 'enum') { - metadataFolder.add(blockProps, state.name, state.values) - } else { - metadataFolder.add(blockProps, state.name) - } - } - } else { - for (const [name, value] of Object.entries(props)) { - blockProps[name] = value - metadataFolder.add(blockProps, name) - } - } - metadataFolder.open() - }, - entity () { - continuousRender = params.entity === 'player' - entityUpdateShared() - if (!params.entity) return - if (params.entity === 'player') { - viewer.entities.updatePlayerSkin('id', viewer.entities.entities.id.username, true, true) - viewer.entities.playAnimation('id', 'running') - } - // let prev = false - // setInterval(() => { - // viewer.entities.playAnimation('id', prev ? 'running' : 'idle') - // prev = !prev - // }, 1000) - - EntityMesh.getStaticData(params.entity) - // entityRotationFolder.destroy() - // entityRotationFolder = gui.addFolder('entity metadata') - // entityRotationFolder.add(params, 'entityRotate') - // entityRotationFolder.open() - }, - supportBlock () { - viewer.setBlockStateId(targetPos.offset(0, -1, 0), params.supportBlock ? 1 : 0) - } - } - - - const applyChanges = (metadataUpdate = false, skipQs = false) => { - const blockId = getBlock()?.id - let block: BlockLoader.Block - if (metadataUpdate) { - block = new Block(blockId, 0, params.metadata) - Object.assign(blockProps, block.getProperties()) - for (const _child of metadataFolder.children) { - const child = _child as import('lil-gui').Controller - child.updateDisplay() - } - } else { - try { - //@ts-ignore - block = Block.fromProperties(blockId ?? -1, blockProps, 0) - } catch (err) { - console.error(err) - block = Block.fromStateId(0, 0) - } - } - - //@ts-ignore - viewer.setBlockStateId(targetPos, block.stateId) - console.log('up stateId', block.stateId) - params.metadata = block.metadata - metadataGui.updateDisplay() - if (!skipQs) { - setQs() - } - } - gui.onChange(({ property, object }) => { - if (object === params) { - if (property === 'camera') return - onUpdate[property]?.() - applyChanges(property === 'metadata') - } else { - applyChanges() - } - }) - viewer.waitForChunksToRender().then(async () => { - for (const update of Object.values(onUpdate)) { - update() - } - applyChanges(true) - gui.openAnimated() - }) - - const animate = () => { - // if (controls) controls.update() - // worldView.updatePosition(controls.target) - viewer.render() - // window.requestAnimationFrame(animate) - } - viewer.world.renderUpdateEmitter.addListener('update', () => { - animate() - }) - animate() - - // #region camera rotation param - if (params.camera) { - const [x, y] = params.camera.split(',') - viewer.camera.rotation.set(parseFloat(x), parseFloat(y), 0, 'ZYX') - controls.update() - console.log(viewer.camera.rotation.x, parseFloat(x)) - } - const throttledCamQsUpdate = _.throttle(() => { - const { camera } = viewer - // params.camera = `${camera.rotation.x.toFixed(2)},${camera.rotation.y.toFixed(2)}` - setQs() - }, 200) - controls.addEventListener('change', () => { - throttledCamQsUpdate() - animate() - }) - // #endregion - - const continuousUpdate = () => { - if (continuousRender) { - animate() - } - requestAnimationFrame(continuousUpdate) - } - continuousUpdate() - - window.onresize = () => { - if (ignoreResize) return - // const vec3 = new THREE.Vector3() - // vec3.set(-1, -1, -1).unproject(viewer.camera) - // console.log(vec3) - // box.position.set(vec3.x, vec3.y, vec3.z-1) - - const { camera } = viewer - viewer.camera.aspect = window.innerWidth / window.innerHeight - viewer.camera.updateProjectionMatrix() - renderer.setSize(window.innerWidth, window.innerHeight) - - animate() - } - window.dispatchEvent(new Event('resize')) - - params.playSound = () => { - viewer.playSound(targetPos, 'button_click.mp3') - } - addEventListener('keydown', (e) => { - if (e.code === 'KeyE') { - params.playSound() - } - }, { capture: true }) -} -main() diff --git a/prismarine-viewer/index.d.ts b/prismarine-viewer/index.d.ts deleted file mode 100644 index 543fa225..00000000 --- a/prismarine-viewer/index.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -import {Bot} from "mineflayer"; - -export function mineflayer(bot: Bot, settings: { - viewDistance?: number; - firstPerson?: boolean; - port?: number; - prefix?: string; -}); - -export function standalone(options: { - version: versions; - world: (x: number, y: number, z: number) => 0 | 1; - center?: Vec3; - viewDistance?: number; - port?: number; - prefix?: string; -}); - -export function headless(bot: Bot, settings: { - viewDistance?: number; - output?: string; - frames?: number; - width?: number; - height?: number; - logFFMPEG?: boolean; - jpegOption: any; -}); - -export const viewer: { - Viewer: any; - WorldDataEmitter: any; - MapControls: any; - Entitiy: any; - getBufferFromStream: (stream: any) => Promise; -}; - -export const supportedVersions: versions[]; -export type versions = '1.8.8' | '1.9.4' | '1.10.2' | '1.11.2' | '1.12.2' | '1.13.2' | '1.14.4' | '1.15.2' | '1.16.1' | '1.16.4' | '1.17.1' | '1.18.1'; diff --git a/prismarine-viewer/index.js b/prismarine-viewer/index.js deleted file mode 100644 index 67136592..00000000 --- a/prismarine-viewer/index.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - mineflayer: require('./lib/mineflayer'), - standalone: require('./lib/standalone'), - headless: require('./lib/headless'), - viewer: require('./viewer'), - supportedVersions: require('./viewer/supportedVersions.json') -} diff --git a/prismarine-viewer/jest-puppeteer.config.js b/prismarine-viewer/jest-puppeteer.config.js deleted file mode 100644 index 6007898f..00000000 --- a/prismarine-viewer/jest-puppeteer.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - launch: { - args: ['--no-sandbox', '--disable-setuid-sandbox'] - } -} diff --git a/prismarine-viewer/jest.config.js b/prismarine-viewer/jest.config.js deleted file mode 100644 index ae87d0d0..00000000 --- a/prismarine-viewer/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - preset: 'jest-puppeteer', - testRegex: './*\\.test\\.js$' -} diff --git a/prismarine-viewer/lib/common.js b/prismarine-viewer/lib/common.js deleted file mode 100644 index 9f5fae41..00000000 --- a/prismarine-viewer/lib/common.js +++ /dev/null @@ -1,12 +0,0 @@ -const path = require('path') -const compression = require('compression') -const express = require('express') - -function setupRoutes (app, prefix = '') { - app.use(compression()) - app.use(prefix + '/', express.static(path.join(__dirname, '../public'))) -} - -module.exports = { - setupRoutes -} diff --git a/prismarine-viewer/lib/headless.js b/prismarine-viewer/lib/headless.js deleted file mode 100644 index 5c163100..00000000 --- a/prismarine-viewer/lib/headless.js +++ /dev/null @@ -1,135 +0,0 @@ -/* global THREE */ -function safeRequire (path) { - try { - return require(path) - } catch (e) { - return {} - } -} -const { spawn } = require('child_process') -const net = require('net') -global.THREE = require('three') -global.Worker = require('worker_threads').Worker -const { createCanvas } = safeRequire('node-canvas-webgl/lib') - -const { WorldDataEmitter, Viewer, getBufferFromStream } = require('../viewer') - -module.exports = (bot, { viewDistance = 6, output = 'output.mp4', frames = -1, width = 512, height = 512, logFFMPEG = false, jpegOptions }) => { - const canvas = createCanvas(width, height) - const renderer = new THREE.WebGLRenderer({ canvas }) - const viewer = new Viewer(renderer) - - viewer.setVersion(bot.version) - viewer.setFirstPersonCamera(bot.entity.position, bot.entity.yaw, bot.entity.pitch) - - // Load world - const worldView = new WorldDataEmitter(bot.world, viewDistance, bot.entity.position) - viewer.listen(worldView) - worldView.init(bot.entity.position) - - function botPosition () { - viewer.setFirstPersonCamera(bot.entity.position, bot.entity.yaw, bot.entity.pitch) - worldView.updatePosition(bot.entity.position) - } - - // Render loop streaming - const rtmpOutput = output.startsWith('rtmp://') - const ffmpegOutput = output.endsWith('mp4') - let client = null - - if (rtmpOutput) { - const fps = 20 - const gop = fps * 2 - const gopMin = fps - const probesize = '42M' - const cbr = '1000k' - const threads = 4 - const args = `-y -r ${fps} -probesize ${probesize} -i pipe:0 -f flv -ac 2 -ar 44100 -vcodec libx264 -g ${gop} -keyint_min ${gopMin} -b:v ${cbr} -minrate ${cbr} -maxrate ${cbr} -pix_fmt yuv420p -s 1280x720 -preset ultrafast -tune film -threads ${threads} -strict normal -bufsize ${cbr} ${output}`.split(' ') - client = spawn('ffmpeg', args) - if (logFFMPEG) { - client.stdout.on('data', (data) => { - console.log(`stdout: ${data}`) - }) - - client.stderr.on('data', (data) => { - console.error(`stderr: ${data}`) - }) - } - update() - } else if (ffmpegOutput) { - client = spawn('ffmpeg', ['-y', '-i', 'pipe:0', output]) - if (logFFMPEG) { - client.stdout.on('data', (data) => { - console.log(`stdout: ${data}`) - }) - - client.stderr.on('data', (data) => { - console.error(`stderr: ${data}`) - }) - } - update() - } else { - const [host, port] = output.split(':') - client = new net.Socket() - client.connect(parseInt(port, 10), host, () => { - update() - }) - } - - // Force end of stream - bot.on('end', () => { frames = 0 }) - - let idx = 0 - function update () { - viewer.update() - renderer.render(viewer.scene, viewer.camera) - - const imageStream = canvas.createJPEGStream({ - bufsize: 4096, - quality: 1, - progressive: false, - ...jpegOptions - }) - - if (rtmpOutput || ffmpegOutput) { - imageStream.on('data', (chunk) => { - if (client.stdin.writable) { - client.stdin.write(chunk) - } else { - console.log('Error: ffmpeg stdin closed!') - } - }) - imageStream.on('end', () => { - idx++ - if (idx < frames || frames < 0) { - setTimeout(update, 16) - } else { - console.log('done streaming') - client.stdin.end() - } - }) - imageStream.on('error', () => { }) - } else { - getBufferFromStream(imageStream).then((buffer) => { - const sizebuff = new Uint8Array(4) - const view = new DataView(sizebuff.buffer, 0) - view.setUint32(0, buffer.length, true) - client.write(sizebuff) - client.write(buffer) - - idx++ - if (idx < frames || frames < 0) { - setTimeout(update, 16) - } else { - client.end() - } - }).catch(() => {}) - } - } - - // Register events - bot.on('move', botPosition) - worldView.listenToBot(bot) - - return client -} diff --git a/prismarine-viewer/lib/index.js b/prismarine-viewer/lib/index.js deleted file mode 100644 index 12267d61..00000000 --- a/prismarine-viewer/lib/index.js +++ /dev/null @@ -1,71 +0,0 @@ -/* global THREE */ - -global.THREE = require('three') -const TWEEN = require('@tweenjs/tween.js') -require('three/examples/js/controls/OrbitControls') - -const { Viewer, Entity } = require('../viewer') - -const io = require('socket.io-client') -const socket = io() - -let firstPositionUpdate = true - -const renderer = new THREE.WebGLRenderer() -renderer.setPixelRatio(window.devicePixelRatio || 1) -renderer.setSize(window.innerWidth, window.innerHeight) -document.body.appendChild(renderer.domElement) - -const viewer = new Viewer(renderer) - -let controls = new THREE.OrbitControls(viewer.camera, renderer.domElement) - -function animate () { - window.requestAnimationFrame(animate) - if (controls) controls.update() - viewer.update() - renderer.render(viewer.scene, viewer.camera) -} -animate() - -window.addEventListener('resize', () => { - viewer.camera.aspect = window.innerWidth / window.innerHeight - viewer.camera.updateProjectionMatrix() - renderer.setSize(window.innerWidth, window.innerHeight) -}) - -socket.on('version', (version) => { - viewer.setVersion(version) - - firstPositionUpdate = true - viewer.listen(socket) - - let botMesh - socket.on('position', ({ pos, addMesh, yaw, pitch }) => { - if (yaw !== undefined && pitch !== undefined) { - if (controls) { - controls.dispose() - controls = null - } - viewer.setFirstPersonCamera(pos, yaw, pitch) - return - } - if (pos.y > 0 && firstPositionUpdate) { - controls.target.set(pos.x, pos.y, pos.z) - viewer.camera.position.set(pos.x, pos.y + 20, pos.z + 20) - controls.update() - firstPositionUpdate = false - } - if (addMesh) { - if (!botMesh) { - botMesh = new Entity('1.16.4', 'player', viewer.scene).mesh - viewer.scene.add(botMesh) - } - new TWEEN.Tween(botMesh.position).to({ x: pos.x, y: pos.y, z: pos.z }, 50).start() - - const da = (yaw - botMesh.rotation.y) % (Math.PI * 2) - const dy = 2 * da % (Math.PI * 2) - da - new TWEEN.Tween(botMesh.rotation).to({ y: botMesh.rotation.y + dy }, 50).start() - } - }) -}) diff --git a/prismarine-viewer/lib/mineflayer.js b/prismarine-viewer/lib/mineflayer.js deleted file mode 100644 index 1735371e..00000000 --- a/prismarine-viewer/lib/mineflayer.js +++ /dev/null @@ -1,91 +0,0 @@ -const EventEmitter = require('events') -const { WorldDataEmitter } = require('../viewer') - -module.exports = (bot, { viewDistance = 6, firstPerson = false, port = 3000, prefix = '' }) => { - const express = require('express') - - const app = express() - const http = require('http').createServer(app) - - const io = require('socket.io')(http, { path: prefix + '/socket.io' }) - - const { setupRoutes } = require('./common') - setupRoutes(app, prefix) - - const sockets = [] - const primitives = {} - - bot.viewer = new EventEmitter() - - bot.viewer.erase = (id) => { - delete primitives[id] - for (const socket of sockets) { - socket.emit('primitive', { id }) - } - } - - bot.viewer.drawBoxGrid = (id, start, end, color = 'aqua') => { - primitives[id] = { type: 'boxgrid', id, start, end, color } - for (const socket of sockets) { - socket.emit('primitive', primitives[id]) - } - } - - bot.viewer.drawLine = (id, points, color = 0xff0000) => { - primitives[id] = { type: 'line', id, points, color } - for (const socket of sockets) { - socket.emit('primitive', primitives[id]) - } - } - - bot.viewer.drawPoints = (id, points, color = 0xff0000, size = 5) => { - primitives[id] = { type: 'points', id, points, color, size } - for (const socket of sockets) { - socket.emit('primitive', primitives[id]) - } - } - - io.on('connection', (socket) => { - socket.emit('version', bot.version) - sockets.push(socket) - - const worldView = new WorldDataEmitter(bot.world, viewDistance, bot.entity.position, socket) - worldView.init(bot.entity.position) - - worldView.on('blockClicked', (block, face, button) => { - bot.viewer.emit('blockClicked', block, face, button) - }) - - for (const id in primitives) { - socket.emit('primitive', primitives[id]) - } - - function botPosition () { - const packet = { pos: bot.entity.position, yaw: bot.entity.yaw, addMesh: true } - if (firstPerson) { - packet.pitch = bot.entity.pitch - } - socket.emit('position', packet) - worldView.updatePosition(bot.entity.position) - } - - bot.on('move', botPosition) - worldView.listenToBot(bot) - socket.on('disconnect', () => { - bot.removeListener('move', botPosition) - worldView.removeListenersFromBot(bot) - sockets.splice(sockets.indexOf(socket), 1) - }) - }) - - http.listen(port, () => { - console.log(`Prismarine viewer web server running on *:${port}`) - }) - - bot.viewer.close = () => { - http.close() - for (const socket of sockets) { - socket.disconnect() - } - } -} diff --git a/prismarine-viewer/lib/standalone.js b/prismarine-viewer/lib/standalone.js deleted file mode 100644 index ed26d507..00000000 --- a/prismarine-viewer/lib/standalone.js +++ /dev/null @@ -1,52 +0,0 @@ -const { Vec3 } = require('vec3') - -module.exports = ({ version, world, center = new Vec3(0, 0, 0), viewDistance = 4, port = 3000, prefix = '' }) => { - const express = require('express') - - const app = express() - const http = require('http').createServer(app) - - const io = require('socket.io')(http) - - const { setupRoutes } = require('./common') - setupRoutes(app, prefix) - - const sockets = [] - const viewer = { world } - - async function sendChunks (sockets) { - const cx = Math.floor(center.x / 16) - const cz = Math.floor(center.z / 16) - - for (let x = cx - viewDistance; x <= cx + viewDistance; x++) { - for (let z = cz - viewDistance; z <= cz + viewDistance; z++) { - const chunk = (await viewer.world.getColumn(x, z)).toJson() - for (const socket of sockets) { - socket.emit('loadChunk', { x: x * 16, z: z * 16, chunk }) - } - } - } - } - - viewer.update = () => { - sendChunks(sockets) - } - - io.on('connection', (socket) => { - socket.emit('version', version) - sockets.push(socket) - - sendChunks([socket]) - socket.emit('position', { pos: center, addMesh: false }) - - socket.on('disconnect', () => { - sockets.splice(sockets.indexOf(socket), 1) - }) - }) - - http.listen(port, () => { - console.log(`Prismarine viewer web server running on *:${port}`) - }) - - return viewer -} diff --git a/prismarine-viewer/tsconfig.json b/prismarine-viewer/tsconfig.json deleted file mode 100644 index b6e39df3..00000000 --- a/prismarine-viewer/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "strictNullChecks": true, - "experimentalDecorators": true - }, - "files": [ - "index.d.ts" - ] -} diff --git a/prismarine-viewer/viewer/index.js b/prismarine-viewer/viewer/index.js deleted file mode 100644 index 39ee4f54..00000000 --- a/prismarine-viewer/viewer/index.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - Viewer: require('./lib/viewer').Viewer, - WorldDataEmitter: require('./lib/worldDataEmitter').WorldDataEmitter, - MapControls: require('./lib/controls').MapControls, - Entity: require('./lib/entity/EntityMesh'), - getBufferFromStream: require('./lib/simpleUtils').getBufferFromStream -} diff --git a/prismarine-viewer/viewer/lib/controls.js b/prismarine-viewer/viewer/lib/controls.js deleted file mode 100644 index e4cce51b..00000000 --- a/prismarine-viewer/viewer/lib/controls.js +++ /dev/null @@ -1,923 +0,0 @@ -/* eslint-disable */ -// Similar to THREE MapControls with more Minecraft-like -// controls. -// Defaults: -// Shift = Move Down, Space = Move Up -// W/Z - north, S - south, A/Q - west, D - east - -const STATE = { - NONE: -1, - ROTATE: 0, - DOLLY: 1, - PAN: 2, - TOUCH_ROTATE: 3, - TOUCH_PAN: 4, - TOUCH_DOLLY_PAN: 5, - TOUCH_DOLLY_ROTATE: 6 -} - -class MapControls { - constructor(camera, domElement) { - this.enabled = true - this.object = camera - this.element = domElement - - // Mouse buttons - this.mouseButtons = { LEFT: THREE.MOUSE.ROTATE, MIDDLE: THREE.MOUSE.DOLLY, RIGHT: THREE.MOUSE.PAN } - - // Touch fingers - this.touches = { ONE: THREE.TOUCH.ROTATE, TWO: THREE.TOUCH.DOLLY_PAN } - - this.controlMap = { - MOVE_FORWARD: ['KeyW', 'KeyZ'], - MOVE_BACKWARD: 'KeyS', - MOVE_LEFT: ['KeyA', 'KeyQ'], - MOVE_RIGHT: 'KeyD', - MOVE_DOWN: 'ShiftLeft', - MOVE_UP: 'Space' - } - - this.target = new THREE.Vector3() - - // How far you can dolly in and out ( PerspectiveCamera only ) - this.minDistance = 0 - this.maxDistance = Infinity - - // How far you can zoom in and out ( OrthographicCamera only ) - this.minZoom = 0 - this.maxZoom = Infinity - - // How far you can orbit vertically, upper and lower limits. - // Range is 0 to Math.PI radians. - this.minPolarAngle = 0 // radians - this.maxPolarAngle = Math.PI // radians - - // How far you can orbit horizontally, upper and lower limits. - // If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI ) - this.minAzimuthAngle = -Infinity // radians - this.maxAzimuthAngle = Infinity // radians - - // Set to true to enable damping (inertia) - // If damping is enabled, you must call controls.update() in your animation loop - this.enableDamping = false - this.dampingFactor = 0.01 - - // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. - // Set to false to disable zooming - this.enableZoom = true - this.enableTouchZoom = true - this.zoomSpeed = 1.0 - - // Set to false to disable rotating - this.enableRotate = true - this.enableTouchRotate = true - this.rotateSpeed = 1.0 - - // Set to false to disable panning - this.enablePan = true - this.enableTouchPan = true - this.panSpeed = 1.0 - this.screenSpacePanning = false // if false, pan orthogonal to world-space direction camera.up - this.keyPanDistance = 32 // how far to pan - this.keyPanSpeed = 10 // pixels moved per arrow key push - this.verticalTranslationSpeed = 0.5 // how much Y increments moving up/down - - this.keyDowns = [] - - // State-related stuff - - this.changeEvent = { type: 'change' } - this.startEvent = { type: 'start' } - this.endEvent = { type: 'end' } - - this.state = STATE.NONE - - this.EPS = 0.000001 - - this.spherical = new THREE.Spherical() - this.sphericalDelta = new THREE.Spherical() - - this.scale = 1 - this.panOffset = new THREE.Vector3() - this.zoomChanged = false - - this.rotateStart = new THREE.Vector2() - this.rotateEnd = new THREE.Vector2() - this.rotateDelta = new THREE.Vector2() - - this.panStart = new THREE.Vector2() - this.panEnd = new THREE.Vector2() - this.panDelta = new THREE.Vector2() - - this.dollyStart = new THREE.Vector2() - this.dollyEnd = new THREE.Vector2() - this.dollyDelta = new THREE.Vector2() - - // for reset - this.target0 = this.target.clone() - this.position0 = this.object.position.clone() - this.zoom0 = this.object.zoom - - this.ticks = 0 - - // register event handlers - this.onPointerMove = this.onPointerMove.bind(this) - this.onPointerUp = this.onPointerUp.bind(this) - this.onPointerDown = this.onPointerDown.bind(this) - this.onMouseWheel = this.onMouseWheel.bind(this) - - this.onTouchStart = this.onTouchStart.bind(this) - this.onTouchEnd = this.onTouchEnd.bind(this) - this.onTouchMove = this.onTouchMove.bind(this) - - this.onContextMenu = this.onContextMenu.bind(this) - this.onKeyDown = this.onKeyDown.bind(this) - this.onKeyUp = this.onKeyUp.bind(this) - - this.registerHandlers() - } - - //#region Public Methods - setRotationOrigin(position) { - this.target = position.clone() - } - - unsetRotationOrigin() { - this.target = new THREE.Vector3() - } - - getPolarAngle() { - return this.spherical.phi - } - - getAzimuthalAngle() { - return this.spherical.theta - } - - saveState() { - this.target0.copy(this.target) - this.position0.copy(this.object.position) - this.zoom0 = this.object.zoom - } - - reset() { - this.target.copy(this.target0) - this.object.position.copy(this.position0) - this.object.zoom = this.zoom0 - - this.object.updateProjectionMatrix() - this.dispatchEvent(this.changeEvent) - - this.update(true) - - this.state = STATE.NONE - } - - // this method is exposed, but perhaps it would be better if we can make it private... - update(force) { - // tick controls if called from render loop - if (!force) { - this.tickControls() - } - - var offset = new THREE.Vector3() - - // so camera.up is the orbit axis - var quat = new THREE.Quaternion().setFromUnitVectors(this.object.up, new THREE.Vector3(0, 1, 0)) - var quatInverse = quat.clone().invert() - - var lastPosition = new THREE.Vector3() - var lastQuaternion = new THREE.Quaternion() - - var twoPI = 2 * Math.PI - - var position = this.object.position - offset.copy(position).sub(this.target) - - // rotate offset to "y-axis-is-up" space - offset.applyQuaternion(quat) - - // angle from z-axis around y-axis - this.spherical.setFromVector3(offset) - - if (this.autoRotate && this.state === STATE.NONE) { - this.rotateLeft(this.getAutoRotationAngle()) - } - - if (this.enableDamping) { - this.spherical.theta += this.sphericalDelta.theta * this.dampingFactor - this.spherical.phi += this.sphericalDelta.phi * this.dampingFactor - } else { - this.spherical.theta += this.sphericalDelta.theta - this.spherical.phi += this.sphericalDelta.phi - } - - // restrict theta to be between desired limits - var min = this.minAzimuthAngle - var max = this.maxAzimuthAngle - - if (isFinite(min) && isFinite(max)) { - if (min < - Math.PI) min += twoPI; else if (min > Math.PI) min -= twoPI - if (max < - Math.PI) max += twoPI; else if (max > Math.PI) max -= twoPI - if (min < max) { - this.spherical.theta = Math.max(min, Math.min(max, this.spherical.theta)) - } else { - this.spherical.theta = (this.spherical.theta > (min + max) / 2) ? - Math.max(min, this.spherical.theta) : - Math.min(max, this.spherical.theta) - } - } - - // restrict phi to be between desired limits - this.spherical.phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this.spherical.phi)) - this.spherical.makeSafe() - this.spherical.radius *= this.scale - - // restrict radius to be between desired limits - this.spherical.radius = Math.max(this.minDistance, Math.min(this.maxDistance, this.spherical.radius)) - - // move target to panned location - if (this.enableDamping === true) { - this.target.addScaledVector(this.panOffset, this.dampingFactor) - } else { - this.target.add(this.panOffset) - } - - offset.setFromSpherical(this.spherical) - - // rotate offset back to "camera-up-vector-is-up" space - offset.applyQuaternion(quatInverse) - - position.copy(this.target).add(offset) - - this.object.lookAt(this.target) - - if (this.enableDamping === true) { - this.sphericalDelta.theta *= (1 - this.dampingFactor) - this.sphericalDelta.phi *= (1 - this.dampingFactor) - this.panOffset.multiplyScalar(1 - this.dampingFactor) - } else { - this.sphericalDelta.set(0, 0, 0) - this.panOffset.set(0, 0, 0) - } - - this.scale = 1 - - // update condition is: - // min(camera displacement, camera rotation in radians)^2 > EPS - // using small-angle approximation cos(x/2) = 1 - x^2 / 8 - - if (this.zoomChanged || - lastPosition.distanceToSquared(this.object.position) > this.EPS || - 8 * (1 - lastQuaternion.dot(this.object.quaternion)) > this.EPS) { - - this.dispatchEvent(this.changeEvent) - - lastPosition.copy(this.object.position) - lastQuaternion.copy(this.object.quaternion) - this.zoomChanged = false - - return true - } - - return false - } - - //#endregion - - //#region Orbit Controls - getAutoRotationAngle() { - return 2 * Math.PI / 60 / 60 * this.autoRotateSpeed - } - - getZoomScale() { - return Math.pow(0.95, this.zoomSpeed) - } - - rotateLeft(angle) { - this.sphericalDelta.theta -= angle - } - - rotateUp(angle) { - this.sphericalDelta.phi -= angle - } - - panLeft(distance, objectMatrix) { - let v = new THREE.Vector3() - - v.setFromMatrixColumn(objectMatrix, 0) // get X column of objectMatrix - v.multiplyScalar(- distance) - - this.panOffset.add(v) - } - - panUp(distance, objectMatrix) { - let v = new THREE.Vector3() - - if (this.screenSpacePanning === true) { - v.setFromMatrixColumn(objectMatrix, 1) - } else { - v.setFromMatrixColumn(objectMatrix, 0) - v.crossVectors(this.object.up, v) - } - - v.multiplyScalar(distance) - - this.panOffset.add(v) - } - - // Patch - translate Y - translateY(delta) { - this.panOffset.y += delta - } - - // deltaX and deltaY are in pixels; right and down are positive - pan(deltaX, deltaY, distance) { - let offset = new THREE.Vector3() - - if (this.object.isPerspectiveCamera) { - // perspective - var position = this.object.position - offset.copy(position).sub(this.target) - var targetDistance = offset.length() - - // half of the fov is center to top of screen - targetDistance *= Math.tan((this.object.fov / 2) * Math.PI / 180.0) - targetDistance = distance || targetDistance - - // we use only clientHeight here so aspect ratio does not distort speed - this.panLeft(2 * deltaX * targetDistance / this.element.clientHeight, this.object.matrix) - this.panUp(2 * deltaY * targetDistance / this.element.clientHeight, this.object.matrix) - } else if (this.object.isOrthographicCamera) { - // orthographic - this.panLeft(deltaX * (this.object.right - this.object.left) / this.object.zoom / this.element.clientWidth, this.object.matrix) - this.panUp(deltaY * (this.object.top - this.object.bottom) / this.object.zoom / this.element.clientHeight, this.object.matrix) - } else { - // camera neither orthographic nor perspective - console.warn('WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.') - this.enablePan = false - } - } - - dollyOut(dollyScale) { - if (this.object.isPerspectiveCamera) { - this.scale /= dollyScale - } else if (this.object.isOrthographicCamera) { - this.object.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.object.zoom * dollyScale)) - this.object.updateProjectionMatrix() - this.zoomChanged = true - } else { - console.warn('WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.') - this.enableZoom = false - } - } - - dollyIn(dollyScale) { - if (this.object.isPerspectiveCamera) { - this.scale *= dollyScale - } else if (this.object.isOrthographicCamera) { - this.object.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.object.zoom / dollyScale)) - this.object.updateProjectionMatrix() - this.zoomChanged = true - } else { - console.warn('WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.') - this.enableZoom = false - } - } - //#endregion - - //#region Event Callbacks - update the object state - - handleMouseDownRotate(event) { - this.rotateStart.set(event.clientX, event.clientY) - - } - - handleMouseDownDolly(event) { - this.dollyStart.set(event.clientX, event.clientY) - - } - - handleMouseDownPan(event) { - this.panStart.set(event.clientX, event.clientY) - } - - handleMouseMoveRotate(event) { - this.rotateEnd.set(event.clientX, event.clientY) - - this.rotateDelta.subVectors(this.rotateEnd, this.rotateStart).multiplyScalar(this.rotateSpeed) - - this.rotateLeft(2 * Math.PI * this.rotateDelta.x / this.element.clientHeight) // yes, height - this.rotateUp(2 * Math.PI * this.rotateDelta.y / this.element.clientHeight) - - this.rotateStart.copy(this.rotateEnd) - - this.update(true) - } - - handleMouseMoveDolly(event) { - this.dollyEnd.set(event.clientX, event.clientY) - this.dollyDelta.subVectors(this.dollyEnd, this.dollyStart) - - if (this.dollyDelta.y > 0) { - this.dollyOut(this.getZoomScale()) - } else if (this.dollyDelta.y < 0) { - this.dollyIn(this.getZoomScale()) - } - this.dollyStart.copy(this.dollyEnd) - this.update(true) - } - - handleMouseMovePan(event) { - this.panEnd.set(event.clientX, event.clientY) - this.panDelta.subVectors(this.panEnd, this.panStart).multiplyScalar(this.panSpeed) - this.pan(this.panDelta.x, this.panDelta.y) - - this.panStart.copy(this.panEnd) - - this.update(true) - } - - handleMouseUp(/*event*/) { - // no-op - } - - handleMouseWheel(event) { - if (event.deltaY < 0) { - this.dollyIn(this.getZoomScale()) - } else if (event.deltaY > 0) { - this.dollyOut(this.getZoomScale()) - } - - this.update(true) - } - - //#endregion - - //#region Mouse/Keyboard handlers - - // Called when the cursor location has moved - onPointerMove(event) { - if (!this.enabled || (this.state == STATE.NONE)) return - - switch (event.pointerType) { - case 'mouse': - case 'pen': - this.onMouseMove(event) - break - // TODO touch - } - } - - // Called when the cursor is no longer behind held - onPointerUp(event) { - if (!this.enabled) return - switch (event.pointerType) { - case 'mouse': - case 'pen': - this.onMouseUp(event) - break - // TODO touch - } - } - - // On left click or tap - onPointerDown(event) { - if (!this.enabled) return - - switch (event.pointerType) { - case 'mouse': - case 'pen': - this.onMouseDown(event) - break - // TODO touch - } - } - - onMouseDown(event) { - // Prevent the browser from scrolling. - event.preventDefault() - - // Manually set the focus since calling preventDefault above - // prevents the browser from setting it automatically. - this.element.focus ? this.element.focus() : window.focus() - - var mouseAction - - switch (event.button) { - case 0: - mouseAction = this.mouseButtons.LEFT - break - case 1: - mouseAction = this.mouseButtons.MIDDLE - break - case 2: - mouseAction = this.mouseButtons.RIGHT - break - default: - mouseAction = - 1 - } - - switch (mouseAction) { - case THREE.MOUSE.DOLLY: - if (this.enableZoom === false) return - this.handleMouseDownDolly(event) - this.state = STATE.DOLLY - break - case THREE.MOUSE.ROTATE: - if (event.ctrlKey || event.metaKey || event.shiftKey) { - if (this.enablePan === false) return - this.handleMouseDownPan(event) - this.state = STATE.PAN - } else { - if (this.enableRotate === false) return - this.handleMouseDownRotate(event) - this.state = STATE.ROTATE - } - break - case THREE.MOUSE.PAN: - if (event.ctrlKey || event.metaKey || event.shiftKey) { - if (this.enableRotate === false) return - this.handleMouseDownRotate(event) - this.state = STATE.ROTATE - } else { - if (this.enablePan === false) return - this.handleMouseDownPan(event) - this.state = STATE.PAN - } - break - default: - this.state = STATE.NONE - - } - - } - - onMouseMove(event) { - if (this.enabled === false) return - - event.preventDefault() - - switch (this.state) { - case STATE.ROTATE: - if (this.enableRotate === false) return - this.handleMouseMoveRotate(event) - break - case STATE.DOLLY: - if (this.enableZoom === false) return - this.handleMouseMoveDolly(event) - break - case STATE.PAN: - if (this.enablePan === false) return - this.handleMouseMovePan(event) - break - } - } - - onMouseUp(event) { - this.state = STATE.NONE - } - - onMouseWheel(event) { - if (this.enabled === false || this.enableZoom === false || (this.state !== STATE.NONE && this.state !== STATE.ROTATE)) return - event.preventDefault() - event.stopPropagation() - this.dispatchEvent(this.startEvent) - this.handleMouseWheel(event) - this.dispatchEvent(this.endEvent) - } - - //#endregion - - - //#region Touch handlers - handleTouchStartRotate(event) { - - if (event.touches.length == 1) { - - this.rotateStart.set(event.touches[0].pageX, event.touches[0].pageY) - - } else { - - var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX) - var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY) - - this.rotateStart.set(x, y) - - } - - } - - handleTouchStartPan(event) { - - if (event.touches.length == 1) { - - this.panStart.set(event.touches[0].pageX, event.touches[0].pageY) - - } else { - - var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX) - var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY) - - this.panStart.set(x, y) - - } - - } - - handleTouchStartDolly(event) { - - var dx = event.touches[0].pageX - event.touches[1].pageX - var dy = event.touches[0].pageY - event.touches[1].pageY - - var distance = Math.sqrt(dx * dx + dy * dy) - - this.dollyStart.set(0, distance) - - } - - handleTouchStartDollyPan(event) { - if (this.enableTouchZoom) this.handleTouchStartDolly(event) - if (this.enableTouchPan) this.handleTouchStartPan(event) - } - - handleTouchStartDollyRotate(event) { - if (this.enableTouchZoom) this.handleTouchStartDolly(event) - if (this.enableTouchRotate) this.handleTouchStartRotate(event) - - } - - handleTouchMoveRotate(event) { - if (event.touches.length == 1) { - this.rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY) - } else { - var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX) - var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY) - - this.rotateEnd.set(x, y) - } - - this.rotateDelta.subVectors(this.rotateEnd, this.rotateStart).multiplyScalar(this.rotateSpeed) - - this.rotateLeft(2 * Math.PI * this.rotateDelta.x / this.element.clientHeight) // yes, height - - this.rotateUp(2 * Math.PI * this.rotateDelta.y / this.element.clientHeight) - - this.rotateStart.copy(this.rotateEnd) - - } - - handleTouchMovePan(event) { - - if (event.touches.length == 1) { - this.panEnd.set(event.touches[0].pageX, event.touches[0].pageY) - - } else { - - var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX) - var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY) - - this.panEnd.set(x, y) - - } - - this.panDelta.subVectors(this.panEnd, this.panStart).multiplyScalar(this.panSpeed) - - this.pan(this.panDelta.x, this.panDelta.y) - - this.panStart.copy(this.panEnd) - - } - - handleTouchMoveDolly(event) { - - var dx = event.touches[0].pageX - event.touches[1].pageX - var dy = event.touches[0].pageY - event.touches[1].pageY - - var distance = Math.sqrt(dx * dx + dy * dy) - - this.dollyEnd.set(0, distance) - - this.dollyDelta.set(0, Math.pow(this.dollyEnd.y / this.dollyStart.y, this.zoomSpeed)) - - this.dollyOut(this.dollyDelta.y) - - this.dollyStart.copy(this.dollyEnd) - - } - - handleTouchMoveDollyPan(event) { - - if (this.enableTouchZoom) this.handleTouchMoveDolly(event) - - if (this.enableTouchPan) this.handleTouchMovePan(event) - - } - - handleTouchMoveDollyRotate(event) { - - if (this.enableTouchZoom) this.handleTouchMoveDolly(event) - - if (this.enableTouchRotate) this.handleTouchMoveRotate(event) - - } - - handleTouchEnd( /*event*/) { - - // no-op - - } - - //#endregion - - tickControls() { - const control = this.controlMap - - for (var keyCode of this.keyDowns) { - if (control.MOVE_FORWARD.includes(keyCode)) { - this.pan(0, this.keyPanSpeed, this.keyPanDistance) - } else if (control.MOVE_BACKWARD.includes(keyCode)) { - this.pan(0, -this.keyPanSpeed, this.keyPanDistance) - } else if (control.MOVE_LEFT.includes(keyCode)) { - this.pan(this.keyPanSpeed, 0, this.keyPanDistance) - } else if (control.MOVE_RIGHT.includes(keyCode)) { - this.pan(-this.keyPanSpeed, 0, this.keyPanDistance) - } else if (control.MOVE_UP.includes(keyCode)) { - this.translateY(+this.verticalTranslationSpeed) - } else if (control.MOVE_DOWN.includes(keyCode)) { - this.translateY(-this.verticalTranslationSpeed) - } - } - } - - onKeyDown(e) { - if (!this.enabled) return - - if (e.code && !this.keyDowns.includes(e.code)) { - this.keyDowns.push(e.code) - // console.debug('[control] Key down: ', this.keyDowns) - } - } - - onKeyUp(event) { - // console.log('[control] Key up: ', event.code, this.keyDowns) - this.keyDowns = this.keyDowns.filter(code => code != event.code) - } - - onTouchStart(event) { - if (this.enabled === false) return - event.preventDefault() // prevent scrolling - switch (event.touches.length) { - case 1: - switch (this.touches.ONE) { - case THREE.TOUCH.ROTATE: - if (this.enableTouchRotate === false) return - this.handleTouchStartRotate(event) - this.state = STATE.TOUCH_ROTATE - break - case THREE.TOUCH.PAN: - if (this.enableTouchPan === false) return - this.handleTouchStartPan(event) - this.state = STATE.TOUCH_PAN - break - default: - this.state = STATE.NONE - } - break - case 2: - switch (this.touches.TWO) { - case THREE.TOUCH.DOLLY_PAN: - if (this.enableTouchZoom === false && this.enableTouchPan === false) return - this.handleTouchStartDollyPan(event) - this.state = STATE.TOUCH_DOLLY_PAN - break - case THREE.TOUCH.DOLLY_ROTATE: - if (this.enableTouchZoom === false && this.enableTouchRotate === false) return - this.handleTouchStartDollyRotate(event) - this.state = STATE.TOUCH_DOLLY_ROTATE - break - default: - this.state = STATE.NONE - } - break - default: - this.state = STATE.NONE - } - if (this.state !== STATE.NONE) { - this.dispatchEvent(this.startEvent) - } - } - - onTouchMove(event) { - - if (this.enabled === false) return - - event.preventDefault() // prevent scrolling - event.stopPropagation() - - switch (this.state) { - - case STATE.TOUCH_ROTATE: - - if (this.enableTouchRotate === false) return - - this.handleTouchMoveRotate(event) - - this.update() - - break - - case STATE.TOUCH_PAN: - - if (this.enableTouchPan === false) return - - this.handleTouchMovePan(event) - - this.update() - - break - - case STATE.TOUCH_DOLLY_PAN: - - if (this.enableTouchZoom === false && this.enableTouchPan === false) return - - this.handleTouchMoveDollyPan(event) - - this.update() - - break - - case STATE.TOUCH_DOLLY_ROTATE: - - if (this.enableTouchZoom === false && this.enableTouchRotate === false) return - - this.handleTouchMoveDollyRotate(event) - - this.update() - - break - - default: - - this.state = STATE.NONE - - } - - } - - onTouchEnd(event) { - - if (this.enabled === false) return - - this.handleTouchEnd(event) - - this.dispatchEvent(this.endEvent) - - this.state = STATE.NONE - - } - - - onContextMenu(event) { - // Disable context menu - if (this.enabled) event.preventDefault() - } - - registerHandlers() { - this.element.addEventListener('pointermove', this.onPointerMove, false, {passive: true}) - this.element.addEventListener('pointerup', this.onPointerUp, false, {passive: true}) - this.element.addEventListener('pointerdown', this.onPointerDown, false, {passive: true}) - this.element.addEventListener('wheel', this.onMouseWheel, true, {passive: true}) - - this.element.addEventListener('touchstart', this.onTouchStart, false, {passive: true}) - this.element.addEventListener('touchend', this.onTouchEnd, false, {passive: true}) - this.element.addEventListener('touchmove', this.onTouchMove, false, {passive: true}) - - this.element.ownerDocument.addEventListener('contextmenu', this.onContextMenu, false, {passive: true}) - this.element.ownerDocument.addEventListener('keydown', this.onKeyDown, false, {passive: true}) - this.element.ownerDocument.addEventListener('keyup', this.onKeyUp, false, {passive: true}) - console.log('[controls] registered handlers', this.element) - } - - unregisterHandlers() { - this.element.removeEventListener('pointermove', this.onPointerMove, false, {passive: true}) - this.element.removeEventListener('pointerup', this.onPointerUp, false, {passive: true}) - this.element.removeEventListener('pointerdown', this.onPointerDown, false, {passive: true}) - this.element.removeEventListener('wheel', this.onMouseWheel, true, {passive: true}) - - this.element.removeEventListener('touchstart', this.onTouchStart, false, {passive: true}) - this.element.removeEventListener('touchend', this.onTouchEnd, false, {passive: true}) - this.element.removeEventListener('touchmove', this.onTouchMove, false, {passive: true}) - - this.element.ownerDocument.removeEventListener('contextmenu', this.onContextMenu, false, {passive: true}) - this.element.ownerDocument.removeEventListener('keydown', this.onKeyDown, false, {passive: true}) - this.element.ownerDocument.removeEventListener('keyup', this.onKeyUp, false, {passive: true}) - console.log('[controls] unregistered handlers', this.element) - } - - dispatchEvent() { - // no-op - } -} - -module.exports = { MapControls } \ No newline at end of file diff --git a/prismarine-viewer/viewer/lib/entities.js b/prismarine-viewer/viewer/lib/entities.js deleted file mode 100644 index 930f62c9..00000000 --- a/prismarine-viewer/viewer/lib/entities.js +++ /dev/null @@ -1,473 +0,0 @@ -//@ts-check -import * as THREE from 'three' -import * as TWEEN from '@tweenjs/tween.js' -import * as Entity from './entity/EntityMesh' -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 -import stevePng from 'minecraft-assets/minecraft-assets/data/1.20.2/entity/player/wide/steve.png' -import { WalkingGeneralSwing } from './entity/animations' -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' }) { - const canvas = document.createElement('canvas') - const ctx = canvas.getContext('2d') - if (!ctx) throw new Error('Could not get 2d context') - - const fontSize = 50 - const padding = 5 - ctx.font = `${fontSize}px ${fontFamily}` - - const textWidth = ctx.measureText(username).width + padding * 2 - - canvas.width = textWidth - canvas.height = fontSize + padding * 2 - - ctx.fillStyle = 'rgba(0, 0, 0, 0.3)' - ctx.fillRect(0, 0, canvas.width, canvas.height) - - ctx.font = `${fontSize}px ${fontFamily}` - ctx.fillStyle = 'white' - ctx.fillText(username, padding, fontSize) - - return canvas -} - -const addNametag = (entity, options, mesh) => { - if (entity.username !== undefined) { - if (mesh.children.find(c => c.name === 'nametag')) return // todo update - const canvas = getUsernameTexture(entity.username, options) - const tex = new THREE.Texture(canvas) - tex.needsUpdate = true - const spriteMat = new THREE.SpriteMaterial({ map: tex }) - const sprite = new THREE.Sprite(spriteMat) - sprite.renderOrder = 1000 - sprite.scale.set(canvas.width * 0.005, canvas.height * 0.005, 1) - sprite.position.y += entity.height + 0.6 - sprite.name = 'nametag' - - mesh.add(sprite) - } -} - -// todo cleanup -const nametags = {} - -function getEntityMesh (entity, scene, options, overrides) { - if (entity.name) { - try { - // https://github.com/PrismarineJS/prismarine-viewer/pull/410 - const entityName = entity.name.toLowerCase() - const e = new Entity.EntityMesh('1.16.4', entityName, scene, overrides) - - if (e.mesh) { - addNametag(entity, options, e.mesh) - return e.mesh - } - } catch (err) { - reportError?.(err) - } - } - - const geometry = new THREE.BoxGeometry(entity.width, entity.height, entity.width) - geometry.translate(0, entity.height / 2, 0) - const material = new THREE.MeshBasicMaterial({ color: 0xff_00_ff }) - const cube = new THREE.Mesh(geometry, material) - const nametagCount = (nametags[entity.name] = (nametags[entity.name] || 0) + 1) - if (nametagCount < 6) { - addNametag({ - username: entity.name, - height: entity.height, - }, options, cube) - } - return cube -} - -export class Entities extends EventEmitter { - constructor(scene) { - super() - this.scene = scene - this.entities = {} - this.entitiesOptions = {} - this.debugMode = 'none' - this.onSkinUpdate = () => { } - this.clock = new THREE.Clock() - this.visible = true - this.itemsTexture = null - this.getItemUv = undefined - } - - clear () { - for (const mesh of Object.values(this.entities)) { - this.scene.remove(mesh) - disposeObject(mesh) - } - this.entities = {} - } - - 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') - boxHelper.visible = false - if (this.debugMode === 'basic') { - boxHelper.visible = true - } - // todo advanced - } - } - - setVisible (visible, /** @type {THREE.Object3D?} */entity = null) { - this.visible = visible - for (const mesh of entity ? [entity] : Object.values(this.entities)) { - mesh.visible = visible - } - } - - render () { - const dt = this.clock.getDelta() - for (const entityId of Object.keys(this.entities)) { - const playerObject = this.getPlayerObject(entityId) - if (playerObject?.animation) { - playerObject.animation.update(playerObject, dt) - } - } - } - - getPlayerObject (entityId) { - /** @type {(PlayerObject & { animation?: PlayerAnimation }) | undefined} */ - const playerObject = this.entities[entityId]?.playerObject - return playerObject - } - - // fixme workaround - defaultSteveTexture - - // true means use default skin url - 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 - // or https://mulv.vercel.app/ - if (skinUrl === true) { - skinUrl = `https://mulv.tycrek.dev/api/lookup?username=${username}&type=skin` - if (!username) return - } - loadImage(skinUrl).then((image) => { - playerObject = this.getPlayerObject(entityId) - if (!playerObject) return - /** @type {THREE.CanvasTexture} */ - let skinTexture - if (skinUrl === stevePng && this.defaultSteveTexture) { - skinTexture = this.defaultSteveTexture - } else { - const skinCanvas = document.createElement('canvas') - loadSkinToCanvas(skinCanvas, image) - skinTexture = new THREE.CanvasTexture(skinCanvas) - if (skinUrl === stevePng) { - this.defaultSteveTexture = skinTexture - } - } - skinTexture.magFilter = THREE.NearestFilter - skinTexture.minFilter = THREE.NearestFilter - skinTexture.needsUpdate = true - //@ts-ignore - playerObject.skin.map = skinTexture - playerObject.skin.modelType = inferModelType(skinTexture.image) - - const earsCanvas = document.createElement('canvas') - loadEarsToCanvasFromSkin(earsCanvas, image) - if (!isCanvasBlank(earsCanvas)) { - const earsTexture = new THREE.CanvasTexture(earsCanvas) - earsTexture.magFilter = THREE.NearestFilter - earsTexture.minFilter = THREE.NearestFilter - earsTexture.needsUpdate = true - //@ts-ignore - playerObject.ears.map = earsTexture - playerObject.ears.visible = true - } else { - playerObject.ears.map = null - playerObject.ears.visible = false - } - this.onSkinUpdate?.() - if (capeUrl) { - if (capeUrl === true) capeUrl = `https://mulv.tycrek.dev/api/lookup?username=${username}&type=cape` - loadImage(capeUrl).then((capeImage) => { - playerObject = this.getPlayerObject(entityId) - if (!playerObject) return - const capeCanvas = document.createElement('canvas') - loadCapeToCanvas(capeCanvas, capeImage) - - const capeTexture = new THREE.CanvasTexture(capeCanvas) - capeTexture.magFilter = THREE.NearestFilter - capeTexture.minFilter = THREE.NearestFilter - capeTexture.needsUpdate = true - //@ts-ignore - playerObject.cape.map = capeTexture - playerObject.cape.visible = true - //@ts-ignore - playerObject.elytra.map = capeTexture - this.onSkinUpdate?.() - - if (!playerObject.backEquipment) { - playerObject.backEquipment = 'cape' - } - }, () => { }) - } - }, () => { }) - - - playerObject.cape.visible = false - if (!capeUrl) { - playerObject.backEquipment = null - playerObject.elytra.map = null - if (playerObject.cape.map) { - playerObject.cape.map.dispose() - } - playerObject.cape.map = null - } - - 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) { - const playerObject = this.getPlayerObject(entityPlayerId) - if (!playerObject) return - - if (animation === 'oneSwing') { - if (!(playerObject.animation instanceof WalkingGeneralSwing)) throw new Error('Expected WalkingGeneralSwing') - playerObject.animation.swingArm() - return - } - - if (playerObject.animation instanceof WalkingGeneralSwing) { - playerObject.animation.switchAnimationCallback = () => { - if (!(playerObject.animation instanceof WalkingGeneralSwing)) throw new Error('Expected WalkingGeneralSwing') - playerObject.animation.isMoving = animation !== 'idle' - playerObject.animation.isRunning = animation === 'running' - } - } - - } - - 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) { - let isPlayerModel = entity.name === 'player' - if (entity.name === 'zombie' || entity.name === 'zombie_villager' || entity.name === 'husk') { - isPlayerModel = true - overrides.texture = `textures/1.16.4/entity/${entity.name === 'zombie_villager' ? 'zombie_villager/zombie_villager.png' : `zombie/${entity.name}.png`}` - } - if (!this.entities[entity.id] && !entity.delete) { - const group = new THREE.Group() - let mesh - if (entity.name === 'item') { - /** @type {any} */ - //@ts-ignore - const item = entity.metadata?.find(m => typeof m === 'object' && m !== null && m.itemCount) - if (item) { - const textureUv = this.getItemUv?.(item.itemId ?? item.blockId) - if (textureUv) { - // todo use geometry buffer uv instead! - const { u, v, size, su, sv, texture } = textureUv - const itemsTexture = texture.clone() - itemsTexture.flipY = true - itemsTexture.offset.set(u, 1 - v - (sv ?? size)) - itemsTexture.repeat.set(su ?? size, sv ?? size) - itemsTexture.needsUpdate = true - itemsTexture.magFilter = THREE.NearestFilter - itemsTexture.minFilter = THREE.NearestFilter - const itemsTextureFlipped = itemsTexture.clone() - itemsTextureFlipped.repeat.x *= -1 - itemsTextureFlipped.needsUpdate = true - itemsTextureFlipped.offset.set(u + (su ?? size), 1 - v - (sv ?? size)) - const material = new THREE.MeshStandardMaterial({ - map: itemsTexture, - transparent: true, - alphaTest: 0.1, - }) - const materialFlipped = new THREE.MeshStandardMaterial({ - map: itemsTextureFlipped, - transparent: true, - alphaTest: 0.1, - }) - mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 0.0), [ - // top left and right bottom are black box materials others are transparent - new THREE.MeshBasicMaterial({ color: 0x000000 }), new THREE.MeshBasicMaterial({ color: 0x000000 }), - new THREE.MeshBasicMaterial({ color: 0x000000 }), new THREE.MeshBasicMaterial({ color: 0x000000 }), - material, materialFlipped - ]) - mesh.scale.set(0.5, 0.5, 0.5) - mesh.position.set(0, 0.2, 0) - // set faces - // mesh.position.set(targetPos.x + 0.5 + 2, targetPos.y + 0.5, targetPos.z + 0.5) - // viewer.scene.add(mesh) - const clock = new THREE.Clock() - mesh.onBeforeRender = () => { - const delta = clock.getDelta() - mesh.rotation.y += delta - } - //@ts-ignore - group.additionalCleanup = () => { - // important: avoid texture memory leak and gpu slowdown - itemsTexture.dispose() - itemsTextureFlipped.dispose() - } - } - } - } else if (isPlayerModel) { - // CREATE NEW PLAYER ENTITY - const wrapper = new THREE.Group() - /** @type {PlayerObject & { animation?: PlayerAnimation }} */ - const playerObject = new PlayerObject() - playerObject.position.set(0, 16, 0) - - //@ts-ignore - wrapper.add(playerObject) - const scale = 1 / 16 - wrapper.scale.set(scale, scale, scale) - - if (entity.username) { - // todo proper colors - const nameTag = new NameTagObject(fromFormattedString(entity.username).text, { - font: `48px ${this.entitiesOptions.fontFamily}`, - }) - nameTag.position.y = playerObject.position.y + playerObject.scale.y * 16 + 3 - nameTag.renderOrder = 1000 - - //@ts-ignore - wrapper.add(nameTag) - } - - //@ts-ignore - group.playerObject = playerObject - wrapper.rotation.set(0, Math.PI, 0) - mesh = wrapper - playerObject.animation = new WalkingGeneralSwing() - //@ts-ignore - playerObject.animation.isMoving = false - } else { - mesh = getEntityMesh(entity, this.scene, this.entitiesOptions, overrides) - } - if (!mesh) return - mesh.name = 'mesh' - // set initial position so there are no weird jumps update after - group.position.set(entity.pos.x, entity.pos.y, entity.pos.z) - - // todo use width and height instead - const boxHelper = new THREE.BoxHelper(mesh, - entity.type === 'hostile' ? 0xff0000 : - entity.type === 'mob' ? 0x00ff00 : - entity.type === "player" ? 0x0000ff : - 0xffa500 - ) - boxHelper.name = 'debug' - group.add(mesh) - group.add(boxHelper) - boxHelper.visible = false - this.scene.add(group) - - this.entities[entity.id] = group - - this.emit('add', entity) - - if (isPlayerModel) { - this.updatePlayerSkin(entity.id, '', overrides?.texture || stevePng) - } - this.setDebugMode(this.debugMode, group) - this.setVisible(this.visible, group) - } - - //@ts-ignore - 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 - } - } - } - // not player - const displayText = entity.metadata?.[3] && this.displaySimpleText(entity.metadata[2]) - if (entity.name !== 'player' && displayText) { - addNametag({ ...entity, username: displayText }, this.entitiesOptions, this.entities[entity.id].children.find(c => c.name === 'mesh')) - } - - // todo handle map, map_chunks events - // if (entity.name === 'item_frame' || entity.name === 'glow_item_frame') { - // const example = { - // "present": true, - // "itemId": 847, - // "itemCount": 1, - // "nbtData": { - // "type": "compound", - // "name": "", - // "value": { - // "map": { - // "type": "int", - // "value": 2146483444 - // }, - // "interactiveboard": { - // "type": "byte", - // "value": 1 - // } - // } - // } - // } - // const item = entity.metadata?.[8] - // if (item.nbtData) { - // const nbt = nbt.simplify(item.nbtData) - // } - // } - - // this can be undefined in case where packet entity_destroy was sent twice (so it was already deleted) - const e = this.entities[entity.id] - - if (entity.username) { - e.username = entity.username - } - - if (e?.playerObject && overrides?.rotation?.head) { - /** @type {PlayerObject} */ - const playerObject = e.playerObject - const headRotationDiff = overrides.rotation.head.y ? overrides.rotation.head.y - entity.yaw : 0 - playerObject.skin.head.rotation.y = -headRotationDiff - playerObject.skin.head.rotation.x = overrides.rotation.head.x ? - overrides.rotation.head.x : 0 - } - - if (entity.delete && e) { - if (e.additionalCleanup) e.additionalCleanup() - this.emit('remove', entity) - this.scene.remove(e) - disposeObject(e) - // todo dispose textures as well ? - delete this.entities[entity.id] - } - - if (entity.pos) { - new TWEEN.Tween(e.position).to({ x: entity.pos.x, y: entity.pos.y, z: entity.pos.z }, TWEEN_DURATION).start() - } - if (entity.yaw) { - const da = (entity.yaw - e.rotation.y) % (Math.PI * 2) - const dy = 2 * da % (Math.PI * 2) - da - new TWEEN.Tween(e.rotation).to({ y: e.rotation.y + dy }, TWEEN_DURATION).start() - } - } -} diff --git a/prismarine-viewer/viewer/lib/entity/EntityMesh.js b/prismarine-viewer/viewer/lib/entity/EntityMesh.js deleted file mode 100644 index 8f8812d0..00000000 --- a/prismarine-viewer/viewer/lib/entity/EntityMesh.js +++ /dev/null @@ -1,383 +0,0 @@ -//@ts-check -import { OBJLoader } from 'three-stdlib' -import entities from './entities.json' -import { externalModels } from './objModels' -import externalTexturesJson from './externalTextures.json' -// import { loadTexture } from globalThis.isElectron ? '../utils.electron.js' : '../utils'; -const { loadTexture } = globalThis.isElectron ? require('../utils.electron.js') : require('../utils') - -const elemFaces = { - up: { - dir: [0, 1, 0], - u0: [0, 0, 1], - v0: [0, 0, 0], - u1: [1, 0, 1], - v1: [0, 0, 1], - corners: [ - [0, 1, 1, 0, 0], - [1, 1, 1, 1, 0], - [0, 1, 0, 0, 1], - [1, 1, 0, 1, 1] - ] - }, - down: { - dir: [0, -1, 0], - u0: [1, 0, 1], - v0: [0, 0, 0], - u1: [2, 0, 1], - v1: [0, 0, 1], - corners: [ - [1, 0, 1, 0, 0], - [0, 0, 1, 1, 0], - [1, 0, 0, 0, 1], - [0, 0, 0, 1, 1] - ] - }, - east: { - dir: [1, 0, 0], - u0: [0, 0, 0], - v0: [0, 0, 1], - u1: [0, 0, 1], - v1: [0, 1, 1], - corners: [ - [1, 1, 1, 0, 0], - [1, 0, 1, 0, 1], - [1, 1, 0, 1, 0], - [1, 0, 0, 1, 1] - ] - }, - west: { - dir: [-1, 0, 0], - u0: [1, 0, 1], - v0: [0, 0, 1], - u1: [1, 0, 2], - v1: [0, 1, 1], - corners: [ - [0, 1, 0, 0, 0], - [0, 0, 0, 0, 1], - [0, 1, 1, 1, 0], - [0, 0, 1, 1, 1] - ] - }, - north: { - dir: [0, 0, -1], - u0: [0, 0, 1], - v0: [0, 0, 1], - u1: [1, 0, 1], - v1: [0, 1, 1], - corners: [ - [1, 0, 0, 0, 1], - [0, 0, 0, 1, 1], - [1, 1, 0, 0, 0], - [0, 1, 0, 1, 0] - ] - }, - south: { - dir: [0, 0, 1], - u0: [1, 0, 2], - v0: [0, 0, 1], - u1: [2, 0, 2], - v1: [0, 1, 1], - corners: [ - [0, 0, 1, 0, 1], - [1, 0, 1, 1, 1], - [0, 1, 1, 0, 0], - [1, 1, 1, 1, 0] - ] - } -} - -function dot (a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] -} - -function addCube (attr, boneId, bone, cube, texWidth = 64, texHeight = 64) { - const cubeRotation = new THREE.Euler(0, 0, 0) - if (cube.rotation) { - cubeRotation.x = -cube.rotation[0] * Math.PI / 180 - cubeRotation.y = -cube.rotation[1] * Math.PI / 180 - cubeRotation.z = -cube.rotation[2] * Math.PI / 180 - } - for (const { dir, corners, u0, v0, u1, v1 } of Object.values(elemFaces)) { - const ndx = Math.floor(attr.positions.length / 3) - - for (const pos of corners) { - const u = (cube.uv[0] + dot(pos[3] ? u1 : u0, cube.size)) / texWidth - const v = (cube.uv[1] + dot(pos[4] ? v1 : v0, cube.size)) / texHeight - - const inflate = cube.inflate ? cube.inflate : 0 - let vecPos = new THREE.Vector3( - cube.origin[0] + pos[0] * cube.size[0] + (pos[0] ? inflate : -inflate), - cube.origin[1] + pos[1] * cube.size[1] + (pos[1] ? inflate : -inflate), - cube.origin[2] + pos[2] * cube.size[2] + (pos[2] ? inflate : -inflate) - ) - - vecPos = vecPos.applyEuler(cubeRotation) - vecPos = vecPos.sub(bone.position) - vecPos = vecPos.applyEuler(bone.rotation) - vecPos = vecPos.add(bone.position) - - attr.positions.push(vecPos.x, vecPos.y, vecPos.z) - attr.normals.push(...dir) - attr.uvs.push(u, v) - attr.skinIndices.push(boneId, 0, 0, 0) - attr.skinWeights.push(1, 0, 0, 0) - } - - attr.indices.push( - ndx, ndx + 1, ndx + 2, - ndx + 2, ndx + 1, ndx + 3 - ) - } -} - -function getMesh (texture, jsonModel, overrides = {}) { - const bones = {} - - const geoData = { - positions: [], - normals: [], - uvs: [], - indices: [], - skinIndices: [], - skinWeights: [] - } - let i = 0 - for (const jsonBone of jsonModel.bones) { - const bone = new THREE.Bone() - if (jsonBone.pivot) { - bone.position.x = jsonBone.pivot[0] - bone.position.y = jsonBone.pivot[1] - bone.position.z = jsonBone.pivot[2] - } - if (jsonBone.bind_pose_rotation) { - bone.rotation.x = -jsonBone.bind_pose_rotation[0] * Math.PI / 180 - bone.rotation.y = -jsonBone.bind_pose_rotation[1] * Math.PI / 180 - bone.rotation.z = -jsonBone.bind_pose_rotation[2] * Math.PI / 180 - } else if (jsonBone.rotation) { - bone.rotation.x = -jsonBone.rotation[0] * Math.PI / 180 - bone.rotation.y = -jsonBone.rotation[1] * Math.PI / 180 - bone.rotation.z = -jsonBone.rotation[2] * Math.PI / 180 - } - if (overrides.rotation?.[jsonBone.name]) { - bone.rotation.x -= (overrides.rotation[jsonBone.name].x ?? 0) * Math.PI / 180 - bone.rotation.y -= (overrides.rotation[jsonBone.name].y ?? 0) * Math.PI / 180 - bone.rotation.z -= (overrides.rotation[jsonBone.name].z ?? 0) * Math.PI / 180 - } - bone.name = `bone_${jsonBone.name}` - bones[jsonBone.name] = bone - - if (jsonBone.cubes) { - for (const cube of jsonBone.cubes) { - addCube(geoData, i, bone, cube, jsonModel.texturewidth, jsonModel.textureheight) - } - } - i++ - } - - const rootBones = [] - for (const jsonBone of jsonModel.bones) { - if (jsonBone.parent && bones[jsonBone.parent]) bones[jsonBone.parent].add(bones[jsonBone.name]) - else { - rootBones.push(bones[jsonBone.name]) - } - } - - const skeleton = new THREE.Skeleton(Object.values(bones)) - - const geometry = new THREE.BufferGeometry() - geometry.setAttribute('position', new THREE.Float32BufferAttribute(geoData.positions, 3)) - geometry.setAttribute('normal', new THREE.Float32BufferAttribute(geoData.normals, 3)) - geometry.setAttribute('uv', new THREE.Float32BufferAttribute(geoData.uvs, 2)) - geometry.setAttribute('skinIndex', new THREE.Uint16BufferAttribute(geoData.skinIndices, 4)) - geometry.setAttribute('skinWeight', new THREE.Float32BufferAttribute(geoData.skinWeights, 4)) - geometry.setIndex(geoData.indices) - - const material = new THREE.MeshLambertMaterial({ transparent: true, alphaTest: 0.1 }) - const mesh = new THREE.SkinnedMesh(geometry, material) - mesh.add(...rootBones) - mesh.bind(skeleton) - mesh.scale.set(1 / 16, 1 / 16, 1 / 16) - - loadTexture(texture, texture => { - if (material.map) { - // texture is already loaded - return - } - texture.magFilter = THREE.NearestFilter - texture.minFilter = THREE.NearestFilter - texture.flipY = false - texture.wrapS = THREE.RepeatWrapping - texture.wrapT = THREE.RepeatWrapping - material.map = texture - }) - - return mesh -} - -export const knownNotHandled = [ - 'area_effect_cloud', 'block_display', - 'chest_boat', 'end_crystal', - 'falling_block', 'furnace_minecart', - 'giant', 'glow_item_frame', - 'glow_squid', 'illusioner', - 'interaction', 'item', - 'item_display', 'item_frame', - 'lightning_bolt', 'marker', - 'painting', 'spawner_minecart', - 'spectral_arrow', 'text_display', - 'tnt', 'trader_llama', 'zombie_horse' -] - -export const temporaryMap = { - 'furnace_minecart': 'minecart', - 'spawner_minecart': 'minecart', - 'chest_minecart': 'minecart', - 'hopper_minecart': 'minecart', - 'command_block_minecart': 'minecart', - 'tnt_minecart': 'minecart', - 'glow_squid': 'squid', - 'trader_llama': 'llama', - 'chest_boat': 'boat', - 'spectral_arrow': 'arrow', - 'husk': 'zombie', - 'zombie_horse': 'horse', - 'donkey': 'horse', - 'skeleton_horse': 'horse', - 'mule': 'horse', - 'ocelot': 'cat', - // 'falling_block': 'block', - // 'lightning_bolt': 'lightning', -} - -const getEntity = (name) => { - return entities[name] -} - -// const externalModelsTextures = { -// allay: 'allay/allay', -// axolotl: 'axolotl/axolotl_blue', -// blaze: 'blaze', -// camel: 'camel/camel', -// cat: 'cat/black', -// chicken: 'chicken', -// cod: 'fish/cod', -// creeper: 'creeper/creeper', -// dolphin: 'dolphin', -// ender_dragon: 'enderdragon/dragon', -// enderman: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAAgCAYAAACinX6EAAAABGdBTUEAALGPC/xhBQAAAY5JREFUaN7lWNESgzAI8yv8/z/tXjZPHSShYitb73rXedo1AQJ0WchY17WhudQZ7TS18Qb5AXtY/yUBO8tXIaCRqRNwXlcgwDJgmAALfBUP8AjYEdHnAZUIAGdvPy+CnobJIVw9DVIPEABawuEyyvYx1sMIMP8fAbUO7ukBImZmCCEP2AhglnRip8vio7MIxYEsaVkdeYNjYfbN/BBA1twP9AxpB0qlMwj48gBP5Ji1rXc8nfBImk6A5+KqShNwdTwgKy0xYRzdS4yoY651W8EDRwGVJEDVITGtjiEAaEBq3o4SwGqRVAKsdVYIsAzDCACV6VwCFMBCpqLvgudzQ6CnjL5afmeX4pdE0LIQuYCBzZbQfT4rC6COUQGn9B3MQ28pSIxDSDdNrKdQSZJ7lDurMeZm6iEjKVENh8cQgBowBFK5gEHhsO3xFA/oKXp6vg8RoHaD2QRkiaDnAYcZAcB+E6GTRVAhQCVJyVImKOUiBLW3KL4jzU2POHp64RIQ/ADO6D6Ry1gl9tlN1Xm+AK8s2jHadDijAAAAAElFTkSuQmCC', -// endermite: 'endermite', -// fox: 'fox/fox', -// frog: 'frog/cold_frog', -// ghast: 'ghast/ghast', -// goat: 'goat/goat', -// guardian: 'guardian', -// horse: 'horse/horse_brown', -// llama: 'llama/creamy', -// minecart: 'minecart', -// parrot: 'parrot/parrot_grey', -// piglin: 'piglin/piglin', -// pillager: 'illager/pillager', -// rabbit: 'rabbit/brown', -// sheep: 'sheep/sheep', -// shulker: 'shulker/shulker', -// sniffer: 'sniffer/sniffer', -// spider: 'spider/spider', -// tadpole: 'tadpole/tadpole', -// turtle: 'turtle/big_sea_turtle', -// vex: 'illager/vex', -// villager: 'villager/villager', -// warden: 'warden/warden', -// witch: 'witch', -// wolf: 'wolf/wolf', -// zombie_villager: 'zombie_villager/zombie_villager' -// } - -export class EntityMesh { - constructor (version, type, scene, /** @type {{textures?, rotation?: Record}} */overrides = {}) { - let originalType = type - const mappedValue = temporaryMap[type] - if (mappedValue) type = mappedValue - - if (externalModels[type]) { - const objLoader = new OBJLoader() - let texturePath = externalTexturesJson[type] - if (originalType === 'zombie_horse') { - texturePath = `textures/${version}/entity/horse/horse_zombie.png` - } - if (originalType === 'skeleton_horse') { - texturePath = `textures/${version}/entity/horse/horse_skeleton.png` - } - if (originalType === 'donkey') { - texturePath = `textures/${version}/entity/horse/donkey.png` - } - if (originalType === 'mule') { - texturePath = `textures/${version}/entity/horse/mule.png` - } - if (originalType === 'ocelot') { - texturePath = `textures/${version}/entity/cat/ocelot.png` - } - if (!texturePath) throw new Error(`No texture for ${type}`) - const texture = new THREE.TextureLoader().load(texturePath) - texture.minFilter = THREE.NearestFilter - texture.magFilter = THREE.NearestFilter - const material = new THREE.MeshBasicMaterial({ - map: texture, - transparent: true, - alphaTest: 0.1 - }) - const obj = objLoader.parse(externalModels[type]) - if (type === 'boat') obj.position.y = -1 // todo, should not be hardcoded - obj.traverse((child) => { - if (child instanceof THREE.Mesh) { - child.material = material - // todo - if (child.name === 'Head layer') child.visible = false - if (child.name === 'Head' && overrides.rotation?.head) { // todo - child.rotation.x -= (overrides.rotation.head.x ?? 0) * Math.PI / 180 - child.rotation.y -= (overrides.rotation.head.y ?? 0) * Math.PI / 180 - child.rotation.z -= (overrides.rotation.head.z ?? 0) * Math.PI / 180 - } - } - }) - this.mesh = obj - return - } - - const e = getEntity(type) - if (!e) { - if (knownNotHandled.includes(type)) return - throw new Error(`Unknown entity ${type}`) - } - - this.mesh = new THREE.Object3D() - for (const [name, jsonModel] of Object.entries(e.geometry)) { - const texture = overrides.textures?.[name] ?? e.textures[name] - if (!texture) continue - // console.log(JSON.stringify(jsonModel, null, 2)) - const mesh = getMesh(texture.replace('textures', 'textures/' + version) + '.png', jsonModel, overrides) - mesh.name = `geometry_${name}` - this.mesh.add(mesh) - - const skeletonHelper = new THREE.SkeletonHelper(mesh) - //@ts-ignore - skeletonHelper.material.linewidth = 2 - skeletonHelper.visible = false - this.mesh.add(skeletonHelper) - } - } - - static getStaticData (name) { - name = temporaryMap[name] || name - if (externalModels[name]) { - return { - boneNames: [] // todo - } - } - const e = getEntity(name) - if (!e) throw new Error(`Unknown entity ${name}`) - return { - boneNames: Object.values(e.geometry).flatMap(x => x.name) - } - } -} diff --git a/prismarine-viewer/viewer/lib/entity/animations.js b/prismarine-viewer/viewer/lib/entity/animations.js deleted file mode 100644 index 626c75d1..00000000 --- a/prismarine-viewer/viewer/lib/entity/animations.js +++ /dev/null @@ -1,103 +0,0 @@ -import { PlayerAnimation } from 'skinview3d' - -export class WalkingGeneralSwing extends PlayerAnimation { - - switchAnimationCallback - - isRunning = false - isMoving = true - - _startArmSwing - - swingArm () { - this._startArmSwing = this.progress - } - - animate (player) { - // Multiply by animation's natural speed - let t - const updateT = () => { - if (!this.isMoving) { - t = 0 - return - } - if (this.isRunning) { - t = this.progress * 10 + Math.PI * 0.5 - } else { - t = this.progress * 8 - } - } - updateT() - let reset = false - - if ((this.isRunning ? Math.cos(t) : Math.sin(t)) < 0.01) { - if (this.switchAnimationCallback) { - reset = true - this.progress = 0 - updateT() - } - } - - if (this.isRunning) { - // Leg swing with larger amplitude - player.skin.leftLeg.rotation.x = Math.cos(t + Math.PI) * 1.3 - player.skin.rightLeg.rotation.x = Math.cos(t) * 1.3 - } else { - // Leg swing - player.skin.leftLeg.rotation.x = Math.sin(t) * 0.5 - player.skin.rightLeg.rotation.x = Math.sin(t + Math.PI) * 0.5 - } - - if (this._startArmSwing) { - let tHand = (this.progress - this._startArmSwing) * 18 + Math.PI * 0.5 - player.skin.rightArm.rotation.x = Math.cos(tHand) * 1.5 - const basicArmRotationZ = Math.PI * 0.1 - player.skin.rightArm.rotation.z = Math.cos(t + Math.PI) * 0.3 - basicArmRotationZ - - if (tHand > Math.PI + Math.PI * 0.5) { - this._startArmSwing = null - player.skin.rightArm.rotation.z = 0 - } - } - - if (this.isRunning) { - player.skin.leftArm.rotation.x = Math.cos(t) * 1.5 - if (!this._startArmSwing) { - player.skin.rightArm.rotation.x = Math.cos(t + Math.PI) * 1.5 - } - const basicArmRotationZ = Math.PI * 0.1 - player.skin.leftArm.rotation.z = Math.cos(t) * 0.1 + basicArmRotationZ - if (!this._startArmSwing) { - player.skin.rightArm.rotation.z = Math.cos(t + Math.PI) * 0.1 - basicArmRotationZ - } - } else { - // Arm swing - player.skin.leftArm.rotation.x = Math.sin(t + Math.PI) * 0.5 - if (!this._startArmSwing) { - player.skin.rightArm.rotation.x = Math.sin(t) * 0.5 - } - const basicArmRotationZ = Math.PI * 0.02 - player.skin.leftArm.rotation.z = Math.cos(t) * 0.03 + basicArmRotationZ - if (!this._startArmSwing) { - player.skin.rightArm.rotation.z = Math.cos(t + Math.PI) * 0.03 - basicArmRotationZ - } - } - - if (this.isRunning) { - player.rotation.z = Math.cos(t + Math.PI) * 0.01 - } - if (this.isRunning) { - const basicCapeRotationX = Math.PI * 0.3 - player.cape.rotation.x = Math.sin(t * 2) * 0.1 + basicCapeRotationX - } else { - // Always add an angle for cape around the x axis - const basicCapeRotationX = Math.PI * 0.06 - player.cape.rotation.x = Math.sin(t / 1.5) * 0.06 + basicCapeRotationX - } - - if (reset) { - this.switchAnimationCallback() - this.switchAnimationCallback = null - } - } -} diff --git a/prismarine-viewer/viewer/lib/entity/entities.json b/prismarine-viewer/viewer/lib/entity/entities.json deleted file mode 100644 index f005f5d1..00000000 --- a/prismarine-viewer/viewer/lib/entity/entities.json +++ /dev/null @@ -1,21476 +0,0 @@ -{ - "armor_stand": { - "identifier": "minecraft:armor_stand", - "min_engine_version": "1.8.0", - "materials": {"default": "armor_stand"}, - "textures": {"default": "textures/entity/armorstand/wood"}, - "animations": { - "default_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this", "-this"]}, - "head": {"rotation": ["-this", "-this", "-this"]}, - "leftarm": {"rotation": ["-this - 10", "-this", "-this - 10"]}, - "leftleg": {"rotation": ["-this - 1", "-this", "-this - 1"]}, - "rightarm": {"rotation": ["-this - 15", "-this", "-this + 10"]}, - "rightitem": {"rotation": ["-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-this + 1", "-this", "-this + 1"]} - } - }, - "no_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this", "-this"]}, - "head": {"rotation": ["-this", "-this", "-this"]}, - "leftarm": {"rotation": ["-this", "-this", "-this"]}, - "leftleg": {"rotation": ["-this", "-this", "-this"]}, - "rightarm": {"rotation": ["-this", "-this", "-this"]}, - "rightitem": {"rotation": ["-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-this", "-this", "-this"]} - } - }, - "solemn_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this", "-this + 2"]}, - "head": {"rotation": ["-this + 15", "-this", "-this"]}, - "leftarm": {"rotation": ["-this - 30", "-this + 15", "-this + 15"]}, - "leftleg": {"rotation": ["-this - 1", "-this", "-this - 1"]}, - "rightarm": {"rotation": ["-this - 60", "-this - 20", "-this - 10"]}, - "rightitem": {"rotation": ["-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-this + 1", "-this", "-this + 1"]} - } - }, - "athena_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this", "-this + 2"]}, - "head": {"rotation": ["-this - 5", "-this", "-this"]}, - "leftarm": {"rotation": ["-this + 10", "-this", "-this - 5"]}, - "leftleg": {"rotation": ["-this - 3", "-this - 3", "-this - 3"]}, - "rightarm": {"rotation": ["-this - 60", "-this + 20", "-this - 10"]}, - "rightitem": {"rotation": ["-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-this + 3", "-this + 3", "-this + 3"]} - } - }, - "brandish_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this", "-this - 2"]}, - "head": {"rotation": ["-this - 15", "-this", "-this"]}, - "leftarm": {"rotation": ["-this + 20", "-this", "-this - 10"]}, - "leftleg": {"rotation": ["-this + 5", "-this - 3", "-this - 3"]}, - "rightarm": {"rotation": ["-this - 110", "-this + 50", "-this"]}, - "rightitem": {"rotation": ["-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-this - 5", "-this + 3", "-this + 3"]} - } - }, - "honor_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this", "-this"]}, - "head": {"rotation": ["-this - 15", "-this", "-this"]}, - "leftarm": {"rotation": ["-this - 110", "-this + 35", "-this"]}, - "leftleg": {"rotation": ["-this + 5", "-this - 3", "-this - 3"]}, - "rightarm": {"rotation": ["-this - 110", "-this - 35", "-this"]}, - "rightitem": {"rotation": ["-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-this - 5", "-this + 3", "-this + 3"]} - } - }, - "entertain_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this", "-this"]}, - "head": {"rotation": ["-this - 15", "-this", "-this"]}, - "leftarm": {"rotation": ["-this - 110", "-this - 35", "-this"]}, - "leftleg": {"rotation": ["-this + 5", "-this - 3", "-this - 3"]}, - "rightarm": {"rotation": ["-this - 110", "-this + 35", "-this"]}, - "rightitem": {"rotation": ["-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-this - 5", "-this + 3", "-this + 3"]} - } - }, - "salute_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this", "-this"]}, - "head": {"rotation": ["-this", "-this", "-this"]}, - "leftarm": {"rotation": ["-this + 10", "-this", "-this - 5"]}, - "leftleg": {"rotation": ["-this - 1", "-this", "-this - 1"]}, - "rightarm": {"rotation": ["-this - 70", "-this - 40", "-this"]}, - "rightitem": {"rotation": ["-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-this + 1", "-this", "-this + 1"]} - } - }, - "riposte_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this", "-this"]}, - "head": {"rotation": ["-this + 16", "-this + 20", "-this"]}, - "leftarm": {"rotation": ["-this + 4", "-this + 8", "-this + 237"]}, - "leftleg": {"rotation": ["-this - 14", "-this - 18", "-this - 16"]}, - "rightarm": {"rotation": ["-this + 246", "-this", "-this + 89"]}, - "rightitem": {"rotation": ["-this", "-this + 180", "-this"]}, - "rightleg": {"rotation": ["-this + 8", "-this + 20", "-this + 4"]} - } - }, - "zombie_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this", "-this"]}, - "head": {"rotation": ["-this - 10", "-this", "-this - 5"]}, - "leftarm": {"rotation": ["-this - 105", "-this", "-this"]}, - "leftleg": {"rotation": ["-this + 7", "-this", "-this"]}, - "rightarm": {"rotation": ["-this - 100", "-this", "-this"]}, - "rightitem": {"rotation": ["-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-this - 46", "-this", "-this"]} - } - }, - "cancan_a_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this + 22", "-this"]}, - "head": {"rotation": ["-this - 5", "-this + 18", "-this"]}, - "leftarm": {"rotation": ["-this + 8", "-this", "-this - 114"]}, - "leftleg": {"rotation": ["-this - 111", "-this + 55", "-this"]}, - "rightarm": {"rotation": ["-this", "-this + 84", "-this + 111"]}, - "rightitem": {"rotation": ["-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-this", "-this + 23", "-this - 13"]} - } - }, - "cancan_b_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this - 18", "-this"]}, - "head": {"rotation": ["-this - 10", "-this - 20", "-this"]}, - "leftarm": {"rotation": ["-this", "-this", "-this - 112"]}, - "leftleg": {"rotation": ["-this", "-this", "-this + 13"]}, - "rightarm": {"rotation": ["-this + 8", "-this + 90", "-this + 111"]}, - "rightitem": {"rotation": ["-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-this - 119", "-this - 42", "-this"]} - } - }, - "hero_pose": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", "-this + 8", "-this"]}, - "head": {"rotation": ["-this - 4", "-this + 67", "-this"]}, - "leftarm": {"rotation": ["-this + 16", "-this + 32", "-this - 8"]}, - "leftleg": {"rotation": ["-this", "-this - 75", "-this - 8"]}, - "rightarm": {"rotation": ["-this - 99", "-this + 63", "-this"]}, - "rightitem": {"rotation": ["-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-this + 4", "-this + 63", "-this + 8"]} - } - }, - "wiggle": { - "loop": true, - "bones": { - "baseplate": { - "rotation": [ - 0, - "math.sin((variable.armor_stand.hurt_time - query.frame_alpha) * 120) * 3", - 0 - ] - } - } - } - }, - "scripts": { - "initialize": [ - "variable.armor_stand.pose_index = 0;", - "variable.armor_stand.hurt_time = 0;" - ], - "animate": ["controller.pose", "controller.wiggling"] - }, - "geometry": { - "default": { - "bones": [ - { - "name": "baseplate", - "cubes": [ - {"origin": [-6, 0, -6], "size": [12, 1, 12], "uv": [0, 32]} - ] - }, - {"name": "waist", "parent": "baseplate", "pivot": [0, 12, 0]}, - { - "name": "body", - "parent": "waist", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-6, 21, -1.5], "size": [12, 3, 3], "uv": [0, 26]}, - {"origin": [-3, 14, -1], "size": [2, 7, 2], "uv": [16, 0]}, - {"origin": [1, 14, -1], "size": [2, 7, 2], "uv": [48, 16]}, - {"origin": [-4, 12, -1], "size": [8, 2, 2], "uv": [0, 48]} - ] - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-1, 24, -1], "size": [2, 7, 2], "uv": [0, 0]}] - }, - { - "name": "hat", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [32, 0]} - ] - }, - { - "name": "leftarm", - "parent": "body", - "mirror": true, - "pivot": [5, 22, 0], - "cubes": [ - {"origin": [5, 12, -1], "size": [2, 12, 2], "uv": [32, 16]} - ] - }, - {"name": "leftitem", "parent": "leftarm", "pivot": [6, 15, 1]}, - { - "name": "leftleg", - "parent": "body", - "mirror": true, - "pivot": [1.9, 12, 0], - "cubes": [ - {"origin": [0.9, 1, -1], "size": [2, 11, 2], "uv": [40, 16]} - ] - }, - { - "name": "rightarm", - "parent": "body", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-7, 12, -1], "size": [2, 12, 2], "uv": [24, 0]} - ] - }, - {"name": "rightitem", "parent": "rightarm", "pivot": [-6, 15, 1]}, - { - "name": "rightleg", - "parent": "body", - "pivot": [-1.9, 12, 0], - "cubes": [ - {"origin": [-2.9, 1, -1], "size": [2, 11, 2], "uv": [8, 0]} - ] - } - ], - "visible_bounds_width": 1.5, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 64 - } - }, - "render_controllers": ["controller.render.armor_stand"], - "enable_attachables": true, - "animation_controllers": { - "controller.pose": { - "initial_state": "default", - "states": { - "athena": { - "animations": ["athena_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"default": "variable.armor_stand.pose_index == 0"}, - {"none": "variable.armor_stand.pose_index == 1"}, - {"solemn": "variable.armor_stand.pose_index == 2"}, - {"brandish": "variable.armor_stand.pose_index == 4"}, - {"honor": "variable.armor_stand.pose_index == 5"}, - {"entertain": "variable.armor_stand.pose_index == 6"}, - {"salute": "variable.armor_stand.pose_index == 7"}, - {"riposte": "variable.armor_stand.pose_index == 8"}, - {"zombie": "variable.armor_stand.pose_index == 9"}, - {"cancan_a": "variable.armor_stand.pose_index == 10"}, - {"cancan_b": "variable.armor_stand.pose_index == 11"}, - {"hero": "variable.armor_stand.pose_index == 12"} - ] - }, - "brandish": { - "animations": ["brandish_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"default": "variable.armor_stand.pose_index == 0"}, - {"none": "variable.armor_stand.pose_index == 1"}, - {"solemn": "variable.armor_stand.pose_index == 2"}, - {"athena": "variable.armor_stand.pose_index == 3"}, - {"honor": "variable.armor_stand.pose_index == 5"}, - {"entertain": "variable.armor_stand.pose_index == 6"}, - {"salute": "variable.armor_stand.pose_index == 7"}, - {"riposte": "variable.armor_stand.pose_index == 8"}, - {"zombie": "variable.armor_stand.pose_index == 9"}, - {"cancan_a": "variable.armor_stand.pose_index == 10"}, - {"cancan_b": "variable.armor_stand.pose_index == 11"}, - {"hero": "variable.armor_stand.pose_index == 12"} - ] - }, - "cancan_a": { - "animations": ["cancan_a_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"default": "variable.armor_stand.pose_index == 0"}, - {"none": "variable.armor_stand.pose_index == 1"}, - {"solemn": "variable.armor_stand.pose_index == 2"}, - {"athena": "variable.armor_stand.pose_index == 3"}, - {"brandish": "variable.armor_stand.pose_index == 4"}, - {"honor": "variable.armor_stand.pose_index == 5"}, - {"entertain": "variable.armor_stand.pose_index == 6"}, - {"salute": "variable.armor_stand.pose_index == 7"}, - {"riposte": "variable.armor_stand.pose_index == 8"}, - {"zombie": "variable.armor_stand.pose_index == 9"}, - {"cancan_b": "variable.armor_stand.pose_index == 11"}, - {"hero": "variable.armor_stand.pose_index == 12"} - ] - }, - "cancan_b": { - "animations": ["cancan_b_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"default": "variable.armor_stand.pose_index == 0"}, - {"none": "variable.armor_stand.pose_index == 1"}, - {"solemn": "variable.armor_stand.pose_index == 2"}, - {"athena": "variable.armor_stand.pose_index == 3"}, - {"brandish": "variable.armor_stand.pose_index == 4"}, - {"honor": "variable.armor_stand.pose_index == 5"}, - {"entertain": "variable.armor_stand.pose_index == 6"}, - {"salute": "variable.armor_stand.pose_index == 7"}, - {"riposte": "variable.armor_stand.pose_index == 8"}, - {"zombie": "variable.armor_stand.pose_index == 9"}, - {"cancan_a": "variable.armor_stand.pose_index == 10"}, - {"hero": "variable.armor_stand.pose_index == 12"} - ] - }, - "default": { - "animations": ["default_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"none": "variable.armor_stand.pose_index == 1"}, - {"solemn": "variable.armor_stand.pose_index == 2"}, - {"athena": "variable.armor_stand.pose_index == 3"}, - {"brandish": "variable.armor_stand.pose_index == 4"}, - {"honor": "variable.armor_stand.pose_index == 5"}, - {"entertain": "variable.armor_stand.pose_index == 6"}, - {"salute": "variable.armor_stand.pose_index == 7"}, - {"riposte": "variable.armor_stand.pose_index == 8"}, - {"zombie": "variable.armor_stand.pose_index == 9"}, - {"cancan_a": "variable.armor_stand.pose_index == 10"}, - {"cancan_b": "variable.armor_stand.pose_index == 11"}, - {"hero": "variable.armor_stand.pose_index == 12"} - ] - }, - "entertain": { - "animations": ["entertain_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"default": "variable.armor_stand.pose_index == 0"}, - {"none": "variable.armor_stand.pose_index == 1"}, - {"solemn": "variable.armor_stand.pose_index == 2"}, - {"athena": "variable.armor_stand.pose_index == 3"}, - {"brandish": "variable.armor_stand.pose_index == 4"}, - {"honor": "variable.armor_stand.pose_index == 5"}, - {"salute": "variable.armor_stand.pose_index == 7"}, - {"riposte": "variable.armor_stand.pose_index == 8"}, - {"zombie": "variable.armor_stand.pose_index == 9"}, - {"cancan_a": "variable.armor_stand.pose_index == 10"}, - {"cancan_b": "variable.armor_stand.pose_index == 11"}, - {"hero": "variable.armor_stand.pose_index == 12"} - ] - }, - "hero": { - "animations": ["hero_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"default": "variable.armor_stand.pose_index == 0"}, - {"none": "variable.armor_stand.pose_index == 1"}, - {"solemn": "variable.armor_stand.pose_index == 2"}, - {"athena": "variable.armor_stand.pose_index == 3"}, - {"brandish": "variable.armor_stand.pose_index == 4"}, - {"honor": "variable.armor_stand.pose_index == 5"}, - {"entertain": "variable.armor_stand.pose_index == 6"}, - {"salute": "variable.armor_stand.pose_index == 7"}, - {"riposte": "variable.armor_stand.pose_index == 8"}, - {"zombie": "variable.armor_stand.pose_index == 9"}, - {"cancan_a": "variable.armor_stand.pose_index == 10"}, - {"cancan_b": "variable.armor_stand.pose_index == 11"} - ] - }, - "honor": { - "animations": ["honor_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"default": "variable.armor_stand.pose_index == 0"}, - {"none": "variable.armor_stand.pose_index == 1"}, - {"solemn": "variable.armor_stand.pose_index == 2"}, - {"athena": "variable.armor_stand.pose_index == 3"}, - {"brandish": "variable.armor_stand.pose_index == 4"}, - {"entertain": "variable.armor_stand.pose_index == 6"}, - {"salute": "variable.armor_stand.pose_index == 7"}, - {"riposte": "variable.armor_stand.pose_index == 8"}, - {"zombie": "variable.armor_stand.pose_index == 9"}, - {"cancan_a": "variable.armor_stand.pose_index == 10"}, - {"cancan_b": "variable.armor_stand.pose_index == 11"}, - {"hero": "variable.armor_stand.pose_index == 12"} - ] - }, - "none": { - "animations": ["no_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"default": "variable.armor_stand.pose_index == 0"}, - {"solemn": "variable.armor_stand.pose_index == 2"}, - {"athena": "variable.armor_stand.pose_index == 3"}, - {"brandish": "variable.armor_stand.pose_index == 4"}, - {"honor": "variable.armor_stand.pose_index == 5"}, - {"entertain": "variable.armor_stand.pose_index == 6"}, - {"salute": "variable.armor_stand.pose_index == 7"}, - {"riposte": "variable.armor_stand.pose_index == 8"}, - {"zombie": "variable.armor_stand.pose_index == 9"}, - {"cancan_a": "variable.armor_stand.pose_index == 10"}, - {"cancan_b": "variable.armor_stand.pose_index == 11"}, - {"hero": "variable.armor_stand.pose_index == 12"} - ] - }, - "riposte": { - "animations": ["riposte_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"default": "variable.armor_stand.pose_index == 0"}, - {"none": "variable.armor_stand.pose_index == 1"}, - {"solemn": "variable.armor_stand.pose_index == 2"}, - {"athena": "variable.armor_stand.pose_index == 3"}, - {"brandish": "variable.armor_stand.pose_index == 4"}, - {"honor": "variable.armor_stand.pose_index == 5"}, - {"entertain": "variable.armor_stand.pose_index == 6"}, - {"salute": "variable.armor_stand.pose_index == 7"}, - {"zombie": "variable.armor_stand.pose_index == 9"}, - {"cancan_a": "variable.armor_stand.pose_index == 10"}, - {"cancan_b": "variable.armor_stand.pose_index == 11"}, - {"hero": "variable.armor_stand.pose_index == 12"} - ] - }, - "salute": { - "animations": ["salute_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"default": "variable.armor_stand.pose_index == 0"}, - {"none": "variable.armor_stand.pose_index == 1"}, - {"solemn": "variable.armor_stand.pose_index == 2"}, - {"athena": "variable.armor_stand.pose_index == 3"}, - {"brandish": "variable.armor_stand.pose_index == 4"}, - {"honor": "variable.armor_stand.pose_index == 5"}, - {"entertain": "variable.armor_stand.pose_index == 6"}, - {"riposte": "variable.armor_stand.pose_index == 8"}, - {"zombie": "variable.armor_stand.pose_index == 9"}, - {"cancan_a": "variable.armor_stand.pose_index == 10"}, - {"cancan_b": "variable.armor_stand.pose_index == 11"}, - {"hero": "variable.armor_stand.pose_index == 12"} - ] - }, - "solemn": { - "animations": ["solemn_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"default": "variable.armor_stand.pose_index == 0"}, - {"none": "variable.armor_stand.pose_index == 1"}, - {"athena": "variable.armor_stand.pose_index == 3"}, - {"brandish": "variable.armor_stand.pose_index == 4"}, - {"honor": "variable.armor_stand.pose_index == 5"}, - {"entertain": "variable.armor_stand.pose_index == 6"}, - {"salute": "variable.armor_stand.pose_index == 7"}, - {"riposte": "variable.armor_stand.pose_index == 8"}, - {"zombie": "variable.armor_stand.pose_index == 9"}, - {"cancan_a": "variable.armor_stand.pose_index == 10"}, - {"cancan_b": "variable.armor_stand.pose_index == 11"}, - {"hero": "variable.armor_stand.pose_index == 12"} - ] - }, - "zombie": { - "animations": ["zombie_pose"], - "blend_transition": 0.1, - "blend_via_shortest_path": true, - "transitions": [ - {"default": "variable.armor_stand.pose_index == 0"}, - {"none": "variable.armor_stand.pose_index == 1"}, - {"solemn": "variable.armor_stand.pose_index == 2"}, - {"athena": "variable.armor_stand.pose_index == 3"}, - {"brandish": "variable.armor_stand.pose_index == 4"}, - {"honor": "variable.armor_stand.pose_index == 5"}, - {"entertain": "variable.armor_stand.pose_index == 6"}, - {"salute": "variable.armor_stand.pose_index == 7"}, - {"riposte": "variable.armor_stand.pose_index == 8"}, - {"cancan_a": "variable.armor_stand.pose_index == 10"}, - {"cancan_b": "variable.armor_stand.pose_index == 11"}, - {"hero": "variable.armor_stand.pose_index == 12"} - ] - } - } - }, - "controller.wiggling": { - "initial_state": "default", - "states": { - "default": { - "transitions": [ - { - "wiggling": "(variable.armor_stand.hurt_time - query.frame_alpha) > 0" - } - ] - }, - "wiggling": { - "animations": ["wiggle"], - "transitions": [ - { - "default": "(variable.armor_stand.hurt_time - query.frame_alpha) <= 0" - } - ] - } - } - } - } - }, - "arrow": { - "identifier": "minecraft:arrow", - "materials": {"default": "arrow"}, - "textures": {"default": "textures/entity/arrow"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 1, 0], - "cubes": [ - { - "origin": [0, -2.5, -3], - "rotation": [0, 0, 45], - "size": [0, 5, 16], - "uv": {"east": {"uv": [0, 0]}} - }, - { - "origin": [0, -2.5, -3], - "rotation": [0, 0, -45], - "size": [0, 5, 16], - "uv": {"east": {"uv": [0, 0]}} - }, - { - "origin": [-2.5, -2.5, 12], - "rotation": [0, 0, 45], - "size": [5, 5, 0], - "uv": {"south": {"uv": [0, 5]}} - } - ] - } - ], - "texturewidth": 32, - "textureheight": 32 - } - }, - "animations": { - "move": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "variable.shake_power - query.target_x_rotation", - "-query.target_y_rotation", - 0 - ], - "scale": [0.7, 0.7, 0.9] - } - } - } - }, - "scripts": { - "pre_animation": [ - "variable.shake = query.shake_time - query.frame_alpha;", - "variable.shake_power = variable.shake > 0.0 ? -Math.sin(variable.shake * 200.0) * variable.shake : 0.0;" - ], - "animate": ["move"] - }, - "render_controllers": ["controller.render.arrow"] - }, - "bat": { - "identifier": "minecraft:bat", - "materials": {"default": "bat"}, - "textures": {"default": "textures/entity/bat"}, - "geometry": { - "default": { - "visible_bounds_width": 1, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0.5, 0], - "bones": [ - { - "name": "head", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-3, 21, -3], "size": [6, 6, 6], "uv": [0, 0]}] - }, - { - "name": "rightEar", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 26, -2], "size": [3, 4, 1], "uv": [24, 0]} - ], - "parent": "head" - }, - { - "name": "leftEar", - "mirror": true, - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [1, 26, -2], "size": [3, 4, 1], "uv": [24, 0]} - ], - "parent": "head" - }, - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-3, 8, -3], "size": [6, 12, 6], "uv": [0, 16]}, - {"origin": [-5, -8, 0], "size": [10, 16, 1], "uv": [0, 34]} - ] - }, - { - "name": "rightWing", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-12, 7, 1.5], "size": [10, 16, 1], "uv": [42, 0]} - ], - "parent": "body" - }, - { - "name": "rightWingTip", - "pivot": [-12, 23, 1.5], - "cubes": [ - {"origin": [-20, 10, 1.5], "size": [8, 12, 1], "uv": [24, 16]} - ], - "parent": "rightWing" - }, - { - "name": "leftWing", - "mirror": true, - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [2, 7, 1.5], "size": [10, 16, 1], "uv": [42, 0]} - ], - "parent": "body" - }, - { - "name": "leftWingTip", - "mirror": true, - "pivot": [12, 23, 1.5], - "cubes": [ - {"origin": [12, 10, 1.5], "size": [8, 12, 1], "uv": [24, 16]} - ], - "parent": "leftWing" - } - ] - } - }, - "scripts": {"scale": "0.35"}, - "animations": { - "resting": { - "loop": true, - "bones": { - "body": {"position": [0, -0.035, 0], "rotation": [180, 0, 0]}, - "head": { - "position": [0, -0.035, 0], - "rotation": [ - "query.target_x_rotation", - "180.0f - query.target_y_rotation", - 180 - ] - }, - "leftwing": {"position": [3, 0, 3], "rotation": [-9, 72, 0]}, - "leftwingtip": {"rotation": [0, 99, 0]}, - "rightwing": {"position": [-3, 0, 3], "rotation": [-9, -72, 0]}, - "rightwingtip": {"rotation": [0, -99, 0]} - } - }, - "flying": { - "loop": true, - "bones": { - "body": { - "position": [0, "math.cos(query.life_time * 343.774) * 1.6", 0], - "rotation": [ - "45.0 - math.cos(query.life_time * 1489.6) * 8.59", - 0, - 0 - ] - }, - "head": { - "position": [ - "-this", - "math.cos(query.life_time * 343.774) * 1.6 - this", - "-this" - ], - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - }, - "leftwing": { - "position": ["-this", "-this", "-this"], - "rotation": [0, "math.cos(query.life_time * 1489.6) * -45.0", 0] - }, - "leftwingtip": { - "rotation": [0, "math.cos(query.life_time * 1489.6) * -22.0", 0] - }, - "rightwing": { - "position": ["-this", "-this", "-this"], - "rotation": [0, "math.cos(query.life_time * 1489.6) * 45.0", 0] - }, - "rightwingtip": { - "rotation": [0, "math.cos(query.life_time * 1489.6) * 22.0", 0] - } - } - } - }, - "animation_controllers": { - "move": { - "initial_state": "flying", - "states": { - "flying": { - "animations": ["flying"], - "transitions": [{"resting": "query.is_resting"}] - }, - "resting": { - "animations": ["resting"], - "transitions": [{"flying": "!query.is_resting"}] - } - } - } - }, - "render_controllers": ["controller.render.bat"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 18} - }, - "bee": { - "identifier": "minecraft:bee", - "materials": {"default": "bee"}, - "textures": { - "default": "textures/entity/bee/bee", - "angry": "textures/entity/bee/bee_angry", - "nectar": "textures/entity/bee/bee_nectar", - "angry_nectar": "textures/entity/bee/bee_angry_nectar" - }, - "geometry": { - "default": { - "texturewidth": 64, - "textureheight": 64, - "visible_bounds_width": 1.5, - "visible_bounds_height": 1.5, - "visible_bounds_offset": [0, 0.25, 0], - "bones": [ - { - "name": "body", - "pivot": [0.5, 5, 0], - "cubes": [ - {"origin": [-3, 2, -5], "size": [7, 7, 10], "uv": [0, 0]}, - {"origin": [2, 7, -8], "size": [1, 2, 3], "uv": [2, 0]}, - {"origin": [-2, 7, -8], "size": [1, 2, 3], "uv": [2, 3]} - ], - "locators": {"lead": [0, 4, -1]} - }, - { - "name": "stinger", - "parent": "body", - "pivot": [0.5, 6, 1], - "cubes": [{"origin": [0.5, 5, 5], "size": [0, 1, 2], "uv": [26, 7]}] - }, - { - "name": "rightwing_bone", - "parent": "body", - "pivot": [-1, 9, -3], - "rotation": [15, -15, 0], - "cubes": [ - {"origin": [-10, 9, -3], "size": [9, 0, 6], "uv": [0, 18]} - ] - }, - { - "name": "leftwing_bone", - "parent": "body", - "pivot": [2, 9, -3], - "rotation": [15, 15, 0], - "cubes": [{"origin": [2, 9, -3], "size": [9, 0, 6], "uv": [9, 24]}] - }, - { - "name": "leg_front", - "parent": "body", - "pivot": [2, 2, -2], - "cubes": [{"origin": [-3, 0, -2], "size": [7, 2, 0], "uv": [26, 1]}] - }, - { - "name": "leg_mid", - "parent": "body", - "pivot": [2, 2, 0], - "cubes": [{"origin": [-3, 0, 0], "size": [7, 2, 0], "uv": [26, 3]}] - }, - { - "name": "leg_back", - "parent": "body", - "pivot": [2, 2, 2], - "cubes": [{"origin": [-3, 0, 2], "size": [7, 2, 0], "uv": [26, 5]}] - } - ] - } - }, - "animations": { - "flying": { - "loop": true, - "animation_length": 2.55, - "bones": { - "body": { - "rotation": {"0.0": [0, 0, 0], "1.30": [5, 0, 0], "2.55": [0, 0, 0]} - }, - "leftwing_bone": { - "rotation": { - "0.0": [0, 0, 35], - "0.05": [0, 0, 0], - "0.10": [0, 0, -35], - "0.15": [0, 0, 0], - "0.2": [0, 0, 35], - "0.25": [0, 0, 0], - "0.30": [0, 0, -35], - "0.35": [0, 0, 0], - "0.40": [0, 0, 35], - "0.45": [0, 0, 0], - "0.50": [0, 0, -35], - "0.55": [0, 0, 0], - "0.60": [0, 0, 35], - "0.65": [0, 0, 0], - "0.70": [0, 0, -35], - "0.75": [0, 0, 0], - "0.80": [0, 0, 35], - "0.85": [0, 0, 0], - "0.90": [0, 0, -35], - "0.95": [0, 0, 0], - "1.0": [0, 0, 35], - "1.05": [0, 0, 0], - "1.10": [0, 0, -35], - "1.15": [0, 0, 0], - "1.20": [0, 0, 35], - "1.25": [0, 0, 0], - "1.30": [0, 0, -35], - "1.35": [0, 0, 0], - "1.40": [0, 0, 35], - "1.45": [0, 0, 0], - "1.50": [0, 0, -35], - "1.55": [0, 0, 0], - "1.60": [0, 0, 35], - "1.65": [0, 0, 0], - "1.70": [0, 0, -35], - "1.75": [0, 0, 0], - "1.80": [0, 0, 35], - "1.85": [0, 0, 0], - "1.90": [0, 0, -35], - "1.95": [0, 0, 0], - "2.0": [0, 0, 35], - "2.05": [0, 0, 0], - "2.10": [0, 0, -35], - "2.15": [0, 0, 0], - "2.20": [0, 0, 35], - "2.25": [0, 0, 0], - "2.30": [0, 0, -35], - "2.35": [0, 0, 0], - "2.40": [0, 0, 35], - "2.45": [0, 0, 0], - "2.50": [0, 0, -35], - "2.55": [0, 0, 0] - } - }, - "leg_front": { - "rotation": { - "0.0": [15, 0, 0], - "1.20": [25, 0, 0], - "2.55": [15, 0, 0] - } - }, - "leg_mid": { - "rotation": { - "0.0": [15, 0, 0], - "1.30": [35, 0, 0], - "2.55": [15, 0, 0] - } - }, - "leg_back": { - "rotation": { - "0.0": [30, 0, 0], - "1.60": [45, 0, 0], - "2.55": [30, 0, 0] - } - }, - "rightwing_bone": { - "rotation": { - "0.0": [0, 0, -35], - "0.05": [0, 0, 0], - "0.10": [0, 0, 35], - "0.15": [0, 0, 0], - "0.2": [0, 0, -35], - "0.25": [0, 0, 0], - "0.30": [0, 0, 35], - "0.35": [0, 0, 0], - "0.40": [0, 0, -35], - "0.45": [0, 0, 0], - "0.50": [0, 0, 35], - "0.55": [0, 0, 0], - "0.60": [0, 0, -35], - "0.65": [0, 0, 0], - "0.70": [0, 0, 35], - "0.75": [0, 0, 0], - "0.80": [0, 0, -35], - "0.85": [0, 0, 0], - "0.90": [0, 0, 35], - "0.95": [0, 0, 0], - "1.0": [0, 0, -35], - "1.05": [0, 0, 0], - "1.10": [0, 0, 35], - "1.15": [0, 0, 0], - "1.20": [0, 0, -35], - "1.25": [0, 0, 0], - "1.30": [0, 0, 35], - "1.35": [0, 0, 0], - "1.40": [0, 0, -35], - "1.45": [0, 0, 0], - "1.50": [0, 0, 35], - "1.55": [0, 0, 0], - "1.60": [0, 0, -35], - "1.65": [0, 0, 0], - "1.70": [0, 0, 35], - "1.75": [0, 0, 0], - "1.80": [0, 0, -35], - "1.85": [0, 0, 0], - "1.90": [0, 0, 35], - "1.95": [0, 0, 0], - "2.0": [0, 0, -35], - "2.05": [0, 0, 0], - "2.10": [0, 0, 35], - "2.15": [0, 0, 0], - "2.20": [0, 0, -35], - "2.25": [0, 0, 0], - "2.30": [0, 0, 35], - "2.35": [0, 0, 0], - "2.40": [0, 0, -35], - "2.45": [0, 0, 0], - "2.50": [0, 0, 35], - "2.55": [0, 0, 0] - } - } - } - }, - "bee_sting": { - "loop": true, - "bones": { - "body": { - "rotation": ["-175 * math.sin(variable.attack_time * 180)", 0, 0] - } - } - }, - "bee_no_stinger": {"loop": true, "bones": {"stinger": {"scale": 0}}}, - "bee_fly_bobbing": { - "loop": true, - "bones": { - "body": { - "position": [0, "math.cos(query.life_time * 343.774) * 1.6", 0], - "rotation": [0, "20 * math.cos(query.life_time * 343.774 / 2)", 0] - } - } - } - }, - "particle_effects": {"nectar_dripping": "minecraft:nectar_drip_particle"}, - "scripts": { - "animate": [ - "bee_root_controller", - {"bee_no_stinger": "query.mark_variant == 1"} - ] - }, - "render_controllers": ["controller.render.bee"], - "spawn_egg": {"texture": "egg_bee", "texture_index": 0}, - "animation_controllers": { - "drip": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"dripping": "query.is_powered"}]}, - "dripping": { - "particle_effects": [{"effect": "nectar_dripping"}], - "transitions": [{"default": "!query.is_powered"}] - } - } - }, - "controller_bee_sting": { - "initial_state": "default", - "states": {"default": {"animations": ["bee_sting"]}} - }, - "bee_root_controller": { - "initial_state": "default", - "states": { - "default": { - "animations": [ - "flying", - "drip", - "bee_fly_bobbing", - "controller_bee_sting" - ] - } - } - } - } - }, - "blaze": { - "identifier": "minecraft:blaze", - "min_engine_version": "1.8.0", - "materials": {"body": "blaze_body", "head": "blaze_head"}, - "textures": {"default": "textures/entity/blaze"}, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "upperBodyParts0", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 16, 0], "size": [2, 8, 2], "uv": [0, 16]}] - }, - { - "name": "upperBodyParts1", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 16, 0], "size": [2, 8, 2], "uv": [0, 16]}] - }, - { - "name": "upperBodyParts2", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 16, 0], "size": [2, 8, 2], "uv": [0, 16]}] - }, - { - "name": "upperBodyParts3", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 16, 0], "size": [2, 8, 2], "uv": [0, 16]}] - }, - { - "name": "upperBodyParts4", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 16, 0], "size": [2, 8, 2], "uv": [0, 16]}] - }, - { - "name": "upperBodyParts5", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 16, 0], "size": [2, 8, 2], "uv": [0, 16]}] - }, - { - "name": "upperBodyParts6", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 16, 0], "size": [2, 8, 2], "uv": [0, 16]}] - }, - { - "name": "upperBodyParts7", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 16, 0], "size": [2, 8, 2], "uv": [0, 16]}] - }, - { - "name": "upperBodyParts8", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 16, 0], "size": [2, 8, 2], "uv": [0, 16]}] - }, - { - "name": "upperBodyParts9", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 16, 0], "size": [2, 8, 2], "uv": [0, 16]}] - }, - { - "name": "upperBodyParts10", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 16, 0], "size": [2, 8, 2], "uv": [0, 16]}] - }, - { - "name": "upperBodyParts11", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 16, 0], "size": [2, 8, 2], "uv": [0, 16]}] - }, - { - "name": "head", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-4, 20, -4], "size": [8, 8, 8], "uv": [0, 0]}] - } - ] - } - }, - "animations": { - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "move": { - "loop": true, - "bones": { - "upperbodyparts0": { - "position": [ - "math.cos(query.life_time * -360.0 ) * 9.0", - "2.0 + math.cos((0 * 2 + query.life_time * 20.0) * 14.32)", - "math.sin(query.life_time * -360.0 ) * 9.0" - ] - }, - "upperbodyparts1": { - "position": [ - "math.cos(query.life_time * -360.0 + 90.0) * 9.0", - "2.0 + math.cos((1 * 2 + query.life_time * 20.0) * 14.32)", - "math.sin(query.life_time * -360.0 + 90.0) * 9.0" - ] - }, - "upperbodyparts10": { - "position": [ - "math.cos(query.life_time * -180.0 + 207.0) * 5.0", - "-11.0 + math.cos((10 * 1.5 + query.life_time * 20.0) * 14.32)", - "math.sin(query.life_time * -180.0 + 207.0) * 5.0" - ] - }, - "upperbodyparts11": { - "position": [ - "math.cos(query.life_time * -180.0 + 297.0) * 5.0", - "-11.0 + math.cos((11 * 1.5 + query.life_time * 20.0) * 14.32)", - "math.sin(query.life_time * -180.0 + 297.0) * 5.0" - ] - }, - "upperbodyparts2": { - "position": [ - "math.cos(query.life_time * -360.0 + 180.0) * 9.0", - "2.0 + math.cos((2 * 2 + query.life_time * 20.0) * 14.32)", - "math.sin(query.life_time * -360.0 + 180.0) * 9.0" - ] - }, - "upperbodyparts3": { - "position": [ - "math.cos(query.life_time * -360.0 + 270.0) * 9.0", - "2.0 + math.cos((3 * 2 + query.life_time * 20.0) * 14.32)", - "math.sin(query.life_time * -360.0 + 270.0) * 9.0" - ] - }, - "upperbodyparts4": { - "position": [ - "math.cos(query.life_time * 108.0 + 45.0) * 7.0", - "-2.0 + math.cos((4 * 2 + query.life_time * 20.0) * 14.32)", - "math.sin(query.life_time * 108.0 + 45.0) * 7.0" - ] - }, - "upperbodyparts5": { - "position": [ - "math.cos(query.life_time * 108.0 + 135.0) * 7.0", - "-2.0 + math.cos((5 * 2 + query.life_time * 20.0) * 14.32)", - "math.sin(query.life_time * 108.0 + 135.0) * 7.0" - ] - }, - "upperbodyparts6": { - "position": [ - "math.cos(query.life_time * 108.0 + 225.0) * 7.0", - "-2.0 + math.cos((6 * 2 + query.life_time * 20.0) * 14.32)", - "math.sin(query.life_time * 108.0 + 225.0) * 7.0" - ] - }, - "upperbodyparts7": { - "position": [ - "math.cos(query.life_time * 108.0 + 315.0) * 7.0", - "-2.0 + math.cos((7 * 2 + query.life_time * 20.0) * 14.32)", - "math.sin(query.life_time * 108.0 + 315.0) * 7.0" - ] - }, - "upperbodyparts8": { - "position": [ - "math.cos(query.life_time * -180.0 + 27.0) * 5.0", - "-11.0 + math.cos((8 * 1.5 + query.life_time * 20.0) * 14.32)", - "math.sin(query.life_time * -180.0 + 27.0) * 5.0" - ] - }, - "upperbodyparts9": { - "position": [ - "math.cos(query.life_time * -180.0 + 117.0) * 5.0", - "-11.0 + math.cos((9 * 1.5 + query.life_time * 20.0) * 14.32)", - "math.sin(query.life_time * -180.0 + 117.0) * 5.0" - ] - } - } - } - }, - "particle_effects": {"charged_flames": "minecraft:mobflame_emitter"}, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move", "look_at_target"]}} - }, - "flame": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"flaming": "query.is_charged"}]}, - "flaming": { - "particle_effects": [{"effect": "charged_flames"}], - "transitions": [{"default": "!query.is_charged"}] - } - } - } - }, - "render_controllers": ["controller.render.blaze"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 21} - }, - "boat": { - "identifier": "minecraft:boat", - "textures": { - "default": "textures/entity/boat/acacia", - "acacia": "textures/entity/boat/acacia", - "birch": "textures/entity/boat/birch", - "darkoak": "textures/entity/boat/dark_oak", - "jungle": "textures/entity/boat/jungle", - "oak": "textures/entity/boat/oak", - "spruce": "textures/entity/boat/spruce" - }, - "geometry": { - "default": { - "texturewidth": 128, - "textureheight": 64, - "bones": [ - { - "name": "bottom", - "pivot": [0, 18, 0], - "rotation": [90, 0, 0], - "mirror": true, - "cubes": [ - {"origin": [-14, 10, 0], "size": [28, 16, 3], "uv": [0, 0]} - ] - }, - { - "name": "front", - "pivot": [15, 24, 0], - "rotation": [0, 90, 0], - "mirror": true, - "cubes": [ - {"origin": [7, 21, -1], "size": [16, 6, 2], "uv": [0, 27]} - ] - }, - { - "name": "back", - "pivot": [-15, 24, 0], - "rotation": [0, -90, 0], - "mirror": true, - "cubes": [ - {"origin": [-24, 21, -1], "size": [18, 6, 2], "uv": [0, 19]} - ] - }, - { - "name": "right", - "pivot": [0, 24, -9], - "rotation": [0, -180, 0], - "mirror": true, - "cubes": [ - {"origin": [-14, 21, -10], "size": [28, 6, 2], "uv": [0, 35]} - ] - }, - { - "name": "left", - "pivot": [0, 24, 9], - "mirror": true, - "cubes": [ - {"origin": [-14, 21, 8], "size": [28, 6, 2], "uv": [0, 43]} - ] - } - ] - } - } - }, - "cat": { - "identifier": "minecraft:cat", - "materials": {"default": "cat"}, - "textures": { - "white": "textures/entity/cat/white", - "black": "textures/entity/cat/tuxedo", - "red": "textures/entity/cat/red", - "siamese": "textures/entity/cat/siamese", - "british": "textures/entity/cat/british_shorthair", - "calico": "textures/entity/cat/calico", - "persian": "textures/entity/cat/persian", - "ragdoll": "textures/entity/cat/ragdoll", - "tabby": "textures/entity/cat/tabby", - "jellie": "textures/entity/cat/jellie", - "all_black": "textures/entity/cat/all_black", - "white_tame": "textures/entity/cat/white", - "black_tame": "textures/entity/cat/tuxedo_tame", - "red_tame": "textures/entity/cat/red", - "siamese_tame": "textures/entity/cat/siamese", - "british_tame": "textures/entity/cat/british_shorthair", - "calico_tame": "textures/entity/cat/calico", - "persian_tame": "textures/entity/cat/persian", - "ragdoll_tame": "textures/entity/cat/ragdoll", - "tabby_tame": "textures/entity/cat/tabby", - "all_black_tame": "textures/entity/cat/all_black", - "jellie_tame": "textures/entity/cat/jellie" - }, - "geometry": { - "default": { - "visible_bounds_width": 2.5, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "pivot": [0, 9, -9], - "locators": {"lead": [0, 9, -9]}, - "cubes": [ - {"origin": [-2.5, 7, -12], "size": [5, 4, 5], "uv": [0, 0]}, - { - "origin": [-1.5, 7.01562, -13], - "size": [3, 2, 2], - "uv": [0, 24] - }, - {"origin": [-2, 11, -9], "size": [1, 1, 2], "uv": [0, 10]}, - {"origin": [1, 11, -9], "size": [1, 1, 2], "uv": [6, 10]} - ], - "name": "head", - "parent": "body" - }, - { - "pivot": [0, 7, 1], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-2, -1, -2], "size": [4, 16, 6], "uv": [20, 0]} - ], - "name": "body" - }, - { - "pivot": [0, 9, 8], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-0.5, 1, 8], "size": [1, 8, 1], "uv": [0, 15]} - ], - "name": "tail1", - "parent": "body" - }, - { - "pivot": [0, 9, 16], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - { - "origin": [-0.5, 1, 16], - "size": [1, 8, 1], - "uv": [4, 15], - "inflate": 0, - "mirror": false - } - ], - "name": "tail2", - "parent": "tail1" - }, - { - "pivot": [1.1, 6, 7], - "cubes": [ - { - "origin": [0.1, 0, 6], - "size": [2, 6, 2], - "uv": [8, 13], - "inflate": 0, - "mirror": false - } - ], - "name": "backLegL", - "parent": "body" - }, - { - "pivot": [-1.1, 6, 7], - "cubes": [ - { - "origin": [-2.1, 0, 6], - "size": [2, 6, 2], - "uv": [8, 13], - "inflate": 0, - "mirror": false - } - ], - "name": "backLegR", - "parent": "body" - }, - { - "pivot": [1.2, 10, -4], - "cubes": [ - { - "origin": [0.2, 0.2, -5], - "size": [2, 10, 2], - "uv": [40, 0], - "inflate": 0, - "mirror": false - } - ], - "name": "frontLegL", - "parent": "body" - }, - { - "pivot": [-1.2, 10, -4], - "cubes": [ - { - "origin": [-2.2, 0.2, -5], - "size": [2, 10, 2], - "uv": [40, 0], - "inflate": 0, - "mirror": false - } - ], - "name": "frontLegR", - "parent": "body" - } - ] - } - }, - "animations": { - "sneak": { - "loop": true, - "bones": { - "backlegl": { - "position": [0, 1, 0], - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17) * 57.3 * query.modified_move_speed", - 0, - 0 - ] - }, - "backlegr": { - "position": [0, 1, 0], - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 180.0) * 57.3 * query.modified_move_speed", - 0, - 0 - ] - }, - "body": {"position": [0, -1, 0]}, - "frontlegl": { - "position": [0, 1, 0], - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 180.0) * 57.3 * query.modified_move_speed", - 0, - 0 - ] - }, - "frontlegr": { - "position": [0, 1, 0], - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17) * 57.3 * query.modified_move_speed", - 0, - 0 - ] - }, - "head": {"position": [0, -1, 0]}, - "tail1": {"position": [0, 1, 0]}, - "tail2": { - "rotation": [ - "62.0 + math.cos(query.modified_distance_moved * 57.3) * 27.0 * query.modified_move_speed", - 0, - 0 - ] - } - } - }, - "walk": { - "loop": true, - "bones": { - "backlegl": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17) * 57.3 * query.modified_move_speed", - 0, - 0 - ] - }, - "backlegr": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 180.0) * 57.3 * query.modified_move_speed", - 0, - 0 - ] - }, - "frontlegl": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 180.0) * 57.3 * query.modified_move_speed", - 0, - 0 - ] - }, - "frontlegr": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17) * 57.3 * query.modified_move_speed", - 0, - 0 - ] - }, - "tail1": {"rotation": [-51.57, 0, 0]}, - "tail2": { - "rotation": [ - "62.0 + math.cos(query.modified_distance_moved * 57.3) * 45.0 * query.modified_move_speed", - 0, - 0 - ] - } - } - }, - "sprint": { - "loop": true, - "bones": { - "backlegl": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17) * 57.3 * query.modified_move_speed", - 0, - 0 - ] - }, - "backlegr": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 17.19) * 57.3 * query.modified_move_speed", - 0, - 0 - ] - }, - "frontlegl": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 197.19) * 57.3 * query.modified_move_speed", - 0, - 0 - ] - }, - "frontlegr": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 180.0) * 57.3 * query.modified_move_speed", - 0, - 0 - ] - }, - "tail1": {"rotation": [0, 0, 0]}, - "tail2": { - "rotation": [ - "62.0 + math.cos(query.modified_distance_moved * 57.3) * 18.0 * query.modified_move_speed", - 0, - 0 - ] - } - } - }, - "sit": { - "loop": true, - "bones": { - "backlegl": {"position": [0, 0, 1], "rotation": [-45, 0, 0]}, - "backlegr": {"position": [0, 0, 1], "rotation": [-45, 0, 0]}, - "body": {"position": [0, -1, 0], "rotation": [-45, 0, 0]}, - "frontlegl": {"position": [0, -4.5, -1], "rotation": [42.15, 0, 0]}, - "frontlegr": {"position": [0, -4.5, -1], "rotation": [42.15, 0, 0]}, - "tail1": {"position": [0, -3, 1], "rotation": [45, 0, 0]}, - "tail2": {"position": [0, 0, 0], "rotation": [45, 0, 0]} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "baby_transform": {"loop": true, "bones": {"head": {"scale": 1.5}}}, - "lie_down": { - "loop": true, - "bones": { - "backlegl": {"position": [0, -0.7, 0], "rotation": [-22.92, 0, 0]}, - "backlegr": { - "position": [0.1, -1.2, 0], - "rotation": [28.65, 0, -28.65] - }, - "body": { - "position": [ - 0, - "variable.liedownamount * -4.5 + variable.lieonplayer * (4.5 + query.is_baby * 6)", - 0 - ], - "rotation": [ - 0, - 0, - "math.lerprotate(0.0, 90.0, variable.liedownamount)" - ] - }, - "frontlegl": {"position": [0, -1, -1.5], "rotation": [-72.81, 0, 0]}, - "frontlegr": { - "position": [0.2, -0.9, 0], - "rotation": [-30, 0, -14.46] - }, - "head": { - "position": [-0.1, 0, -0.5], - "rotation": [ - -10, - "math.lerprotate(this, 75.81, variable.liedownamount)", - 0 - ] - }, - "tail1": { - "position": [0, 0, 0], - "rotation": [ - "math.lerprotate(this, -33.84, variable.liedownamounttail)", - 0, - 0 - ] - }, - "tail2": { - "position": [0, 0, 0], - "rotation": [ - "math.lerprotate(this, -68.92, variable.liedownamounttail)", - 0, - 0 - ] - } - } - } - }, - "animation_controllers": { - "look_at_target": { - "initial_state": "default", - "states": {"default": {"animations": ["look_at_target"]}} - }, - "move": { - "initial_state": "lie_down", - "states": { - "lie_down": { - "animations": ["lie_down"], - "transitions": [ - {"sneaking": "variable.state == 0"}, - {"sprinting": "variable.state == 1"}, - {"sitting": "variable.state == 2"}, - {"walking": "variable.state == 3"} - ] - }, - "sitting": { - "animations": ["sit"], - "transitions": [ - {"sneaking": "variable.state == 0"}, - {"sprinting": "variable.state == 1"}, - {"walking": "variable.state == 3"}, - {"lie_down": "variable.state == 4"} - ] - }, - "sneaking": { - "animations": ["sneak"], - "transitions": [ - {"sprinting": "variable.state == 1"}, - {"sitting": "variable.state == 2"}, - {"walking": "variable.state == 3"}, - {"lie_down": "variable.state == 4"} - ] - }, - "sprinting": { - "animations": ["sprint"], - "transitions": [ - {"sneaking": "variable.state == 0"}, - {"sitting": "variable.state == 2"}, - {"walking": "variable.state == 3"}, - {"lie_down": "variable.state == 4"} - ] - }, - "walking": { - "animations": ["walk"], - "transitions": [ - {"sneaking": "variable.state == 0"}, - {"sprinting": "variable.state == 1"}, - {"sitting": "variable.state == 2"}, - {"lie_down": "variable.state == 4"} - ] - } - } - }, - "baby": { - "initial_state": "baby", - "states": { - "baby": {"animations": [{"baby_transform": "query.is_baby"}]} - } - } - }, - "render_controllers": ["controller.render.cat"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 53} - }, - "cave_spider": { - "identifier": "minecraft:cave_spider", - "min_engine_version": "1.8.0", - "materials": {"default": "spider", "invisible": "spider_invisible"}, - "textures": {"default": "textures/entity/spider/cave_spider"}, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "head", - "pivot": [0, 9, -3], - "cubes": [ - {"origin": [-4, 5, -11], "size": [8, 8, 8], "uv": [32, 4]} - ], - "parent": "body0" - }, - { - "name": "body0", - "pivot": [0, 9, 0], - "cubes": [{"origin": [-3, 6, -3], "size": [6, 6, 6], "uv": [0, 0]}] - }, - { - "name": "body1", - "pivot": [0, 9, 9], - "cubes": [ - {"origin": [-5, 5, 3], "size": [10, 8, 12], "uv": [0, 12]} - ], - "parent": "body0" - }, - { - "name": "leg0", - "pivot": [-4, 9, 2], - "cubes": [ - {"origin": [-19, 8, 1], "size": [16, 2, 2], "uv": [18, 0]} - ], - "parent": "body0" - }, - { - "name": "leg1", - "pivot": [4, 9, 2], - "cubes": [{"origin": [3, 8, 1], "size": [16, 2, 2], "uv": [18, 0]}], - "parent": "body0" - }, - { - "name": "leg2", - "pivot": [-4, 9, 1], - "cubes": [ - {"origin": [-19, 8, 0], "size": [16, 2, 2], "uv": [18, 0]} - ], - "parent": "body0" - }, - { - "name": "leg3", - "pivot": [4, 9, 1], - "cubes": [{"origin": [3, 8, 0], "size": [16, 2, 2], "uv": [18, 0]}], - "parent": "body0" - }, - { - "name": "leg4", - "pivot": [-4, 9, 0], - "cubes": [ - {"origin": [-19, 8, -1], "size": [16, 2, 2], "uv": [18, 0]} - ], - "parent": "body0" - }, - { - "name": "leg5", - "pivot": [4, 9, 0], - "cubes": [ - {"origin": [3, 8, -1], "size": [16, 2, 2], "uv": [18, 0]} - ], - "parent": "body0" - }, - { - "name": "leg6", - "pivot": [-4, 9, -1], - "cubes": [ - {"origin": [-19, 8, -2], "size": [16, 2, 2], "uv": [18, 0]} - ], - "parent": "body0" - }, - { - "name": "leg7", - "pivot": [4, 9, -1], - "cubes": [ - {"origin": [3, 8, -2], "size": [16, 2, 2], "uv": [18, 0]} - ], - "parent": "body0" - } - ] - } - }, - "scripts": {"scale": "0.7"}, - "animations": { - "default_leg_pose": { - "loop": true, - "bones": { - "leg0": {"rotation": [0, "45.0 - this", "-45.0 - this"]}, - "leg1": {"rotation": [0, "-45.0 - this", "45.0 - this"]}, - "leg2": {"rotation": [0, "22.5 - this", "-33.3 - this"]}, - "leg3": {"rotation": [0, "-22.5 - this", "33.3 - this"]}, - "leg4": {"rotation": [0, "-22.5 - this", "-33.3 - this"]}, - "leg5": {"rotation": [0, "22.5 - this", "33.3 - this"]}, - "leg6": {"rotation": [0, "-45.0 - this", "-45.0 - this"]}, - "leg7": {"rotation": [0, "45.0 - this", "45.0 - this"]} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "walk": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": [ - 0, - "-math.abs(math.cos(query.anim_time * 76.34 + 90 * 0) * 22.92)", - "math.abs(math.sin(query.anim_time * 38.17 + 90 * 0) * 22.92)" - ] - }, - "leg1": { - "rotation": [ - 0, - "math.abs(math.cos(query.anim_time * 76.34 + 90 * 0) * 22.92)", - "-math.abs(math.sin(query.anim_time * 38.17 + 90 * 0) * 22.92)" - ] - }, - "leg2": { - "rotation": [ - 0, - "-math.abs(math.cos(query.anim_time * 76.34 + 90 * 1) * 22.92)", - "math.abs(math.sin(query.anim_time * 38.17 + 90 * 1) * 22.92)" - ] - }, - "leg3": { - "rotation": [ - 0, - "math.abs(math.cos(query.anim_time * 76.34 + 90 * 1) * 22.92)", - "-math.abs(math.sin(query.anim_time * 38.17 + 90 * 1) * 22.92)" - ] - }, - "leg4": { - "rotation": [ - 0, - "-math.abs(math.cos(query.anim_time * 76.34 + 90 * 2) * 22.92)", - "math.abs(math.sin(query.anim_time * 38.17 + 90 * 2) * 22.92)" - ] - }, - "leg5": { - "rotation": [ - 0, - "math.abs(math.cos(query.anim_time * 76.34 + 90 * 2) * 22.92)", - "-math.abs(math.sin(query.anim_time * 38.17 + 90 * 2) * 22.92)" - ] - }, - "leg6": { - "rotation": [ - 0, - "-math.abs(math.cos(query.anim_time * 76.34 + 90 * 3) * 22.92)", - "math.abs(math.sin(query.anim_time * 38.17 + 90 * 3) * 22.92)" - ] - }, - "leg7": { - "rotation": [ - 0, - "math.abs(math.cos(query.anim_time * 76.34 + 90 * 3) * 22.92)", - "-math.abs(math.sin(query.anim_time * 38.17 + 90 * 3) * 22.92)" - ] - } - } - } - }, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": { - "default": { - "animations": [ - "default_leg_pose", - {"walk": "query.modified_move_speed"}, - "look_at_target" - ] - } - } - } - }, - "render_controllers": ["controller.render.spider"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 22} - }, - "chest_minecart": { - "identifier": "minecraft:chest_minecart", - "min_engine_version": "1.8.0", - "materials": {"default": "minecart"}, - "textures": {"default": "textures/entity/minecart"}, - "geometry": { - "default": { - "bones": [ - { - "name": "bottom", - "pivot": [0, 6, 0], - "cubes": [ - { - "origin": [-10, -6.5, -1], - "size": [20, 16, 2], - "rotation": [90, 0, 0], - "uv": [0, 10] - } - ] - }, - { - "name": "back", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-17, 2.5, -1], - "size": [16, 8, 2], - "rotation": [0, 270, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "front", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [1, 2.5, -1], - "size": [16, 8, 2], - "rotation": [0, 90, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "right", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, 2.5, -8], - "size": [16, 8, 2], - "rotation": [0, 180, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "left", - "pivot": [0, 0, 0], - "cubes": [ - {"origin": [-8, 2.5, 6], "size": [16, 8, 2], "uv": [0, 0]} - ], - "parent": "bottom" - } - ], - "texturewidth": 64, - "textureheight": 32 - } - }, - "scripts": { - "pre_animation": ["variable.hurt = query.hurt_time - query.frame_alpha;"], - "animate": ["move"] - }, - "animations": { - "move": { - "loop": true, - "bones": { - "bottom": { - "position": [ - "variable.rail_offset.x / query.model_scale", - "variable.rail_offset.y / query.model_scale", - "variable.rail_offset.z / query.model_scale" - ], - "rotation": [ - "variable.hurt > 0 ? -Math.sin(variable.hurt * 360 / (Math.pi * 2)) * variable.hurt * (((20 * 2 - query.structural_integrity) - query.frame_alpha) < 0 ? 0: (20 * 2 - query.structural_integrity) - query.frame_alpha) / 10 * query.hurt_direction : 0", - 0, - "-variable.rail_rotation.z" - ] - } - } - } - }, - "render_controllers": ["controller.render.minecart"] - }, - "chicken": { - "identifier": "minecraft:chicken", - "min_engine_version": "1.12.0", - "materials": {"default": "chicken", "legs": "chicken_legs"}, - "textures": {"default": "textures/entity/chicken"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 8, 0], - "cubes": [ - { - "origin": [-3, 4, -3], - "rotation": [90, 0, 0], - "size": [6, 8, 6], - "uv": [0, 9] - } - ] - }, - { - "name": "head", - "pivot": [0, 9, -4], - "cubes": [{"origin": [-2, 9, -6], "size": [4, 6, 3], "uv": [0, 0]}], - "locators": {"lead": [0, 9, -4]} - }, - { - "name": "comb", - "parent": "head", - "pivot": [0, 9, -4], - "cubes": [{"origin": [-1, 9, -7], "size": [2, 2, 2], "uv": [14, 4]}] - }, - { - "name": "beak", - "parent": "head", - "pivot": [0, 9, -4], - "cubes": [ - {"origin": [-2, 11, -8], "size": [4, 2, 2], "uv": [14, 0]} - ] - }, - { - "name": "leg0", - "pivot": [-2, 5, 1], - "cubes": [{"origin": [-3, 0, -2], "size": [3, 5, 3], "uv": [26, 0]}] - }, - { - "name": "leg1", - "pivot": [1, 5, 1], - "cubes": [{"origin": [0, 0, -2], "size": [3, 5, 3], "uv": [26, 0]}] - }, - { - "name": "wing0", - "pivot": [-3, 11, 0], - "cubes": [ - {"origin": [-4, 7, -3], "size": [1, 4, 6], "uv": [24, 13]} - ] - }, - { - "name": "wing1", - "pivot": [3, 11, 0], - "cubes": [{"origin": [3, 7, -3], "size": [1, 4, 6], "uv": [24, 13]}] - } - ], - "visible_bounds_width": 1.5, - "visible_bounds_height": 1.5, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 32 - } - }, - "animations": { - "move": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - }, - "leg1": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - } - } - }, - "general": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", 0, 0]}, - "wing0": {"rotation": [0, 0, "variable.wing_flap - this"]}, - "wing1": {"rotation": [0, 0, "-variable.wing_flap - this"]} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "baby_transform": {"loop": true, "bones": {"head": {"scale": 2}}} - }, - "scripts": { - "animate": [ - "general", - {"move": "query.modified_move_speed"}, - "look_at_target", - {"baby_transform": "query.is_baby"} - ] - }, - "render_controllers": ["controller.render.chicken"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 0} - }, - "cod": { - "identifier": "minecraft:cod", - "materials": {"default": "cod"}, - "textures": {"default": "textures/entity/fish/cod"}, - "geometry": { - "default": { - "visible_bounds_width": 0.5, - "visible_bounds_height": 0.5, - "texturewidth": 32, - "textureheight": 32, - "bones": [ - { - "name": "body", - "cubes": [ - {"origin": [-1, 0, 1], "size": [2, 4, 7], "uv": [0, 0]}, - {"origin": [0, 4, 0], "size": [0, 1, 6], "uv": [20, -6]}, - {"origin": [0, -1, 3], "size": [0, 1, 2], "uv": [22, -1]} - ] - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 2, 0], - "cubes": [ - { - "origin": [-0.9992, 1.0008, -3], - "size": [2, 3, 1], - "uv": [0, 0] - }, - {"origin": [-1, 0, -2], "size": [2, 4, 3], "uv": [11, 0]} - ] - }, - { - "name": "leftFin", - "parent": "body", - "pivot": [1, 1, 0], - "rotation": [0, 0, 35], - "cubes": [{"origin": [1, 0, 0], "size": [2, 1, 2], "uv": [24, 4]}] - }, - { - "name": "rightFin", - "parent": "body", - "pivot": [-1, 1, 0], - "rotation": [0, 0, -35], - "cubes": [{"origin": [-3, 0, 0], "size": [2, 1, 2], "uv": [24, 1]}] - }, - { - "name": "tailfin", - "parent": "body", - "pivot": [0, 0, 8], - "cubes": [{"origin": [0, 0, 8], "size": [0, 4, 6], "uv": [20, 1]}] - }, - {"name": "waist", "parent": "body", "cubes": []} - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.ZRot = !query.is_in_water ? Math.cos((query.time_stamp + query.frame_alpha) * 14.32) * 90 : 0.0;", - "variable.AnimationAmountBlend = Math.lerp(variable.AnimationAmountPrev, variable.AnimationAmount, query.frame_alpha);" - ] - }, - "animations": { - "flop": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 45.0) * 2.0", - "variable.zrot" - ] - }, - "head": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 45.0) * 4.0", - 0 - ] - }, - "tailfin": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 45.0) * -25.75", - 0 - ] - } - } - }, - "swim": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 30.0) * 2.0", - 0 - ] - }, - "head": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 30.0) * 4.0", - 0 - ] - }, - "tailfin": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 30.0) * -25.75", - 0 - ] - } - } - } - }, - "animation_controllers": { - "general": { - "initial_state": "flopping", - "states": { - "flopping": { - "animations": ["flop"], - "transitions": [ - {"swimming": "query.is_in_water || query.is_levitating"} - ] - }, - "swimming": { - "animations": ["swim"], - "transitions": [ - {"flopping": "!query.is_in_water && !query.is_levitating"} - ] - } - } - } - }, - "render_controllers": ["controller.render.cod"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 45} - }, - "command_block_minecart": { - "identifier": "minecraft:command_block_minecart", - "min_engine_version": "1.8.0", - "materials": {"default": "minecart"}, - "textures": {"default": "textures/entity/minecart"}, - "geometry": { - "default": { - "bones": [ - { - "name": "bottom", - "pivot": [0, 6, 0], - "cubes": [ - { - "origin": [-10, -6.5, -1], - "size": [20, 16, 2], - "rotation": [90, 0, 0], - "uv": [0, 10] - } - ] - }, - { - "name": "back", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-17, 2.5, -1], - "size": [16, 8, 2], - "rotation": [0, 270, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "front", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [1, 2.5, -1], - "size": [16, 8, 2], - "rotation": [0, 90, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "right", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, 2.5, -8], - "size": [16, 8, 2], - "rotation": [0, 180, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "left", - "pivot": [0, 0, 0], - "cubes": [ - {"origin": [-8, 2.5, 6], "size": [16, 8, 2], "uv": [0, 0]} - ], - "parent": "bottom" - } - ], - "texturewidth": 64, - "textureheight": 32 - } - }, - "scripts": { - "pre_animation": ["variable.hurt = query.hurt_time - query.frame_alpha;"], - "animate": ["move"] - }, - "animations": { - "move": { - "loop": true, - "bones": { - "bottom": { - "position": [ - "variable.rail_offset.x / query.model_scale", - "variable.rail_offset.y / query.model_scale", - "variable.rail_offset.z / query.model_scale" - ], - "rotation": [ - "variable.hurt > 0 ? -Math.sin(variable.hurt * 360 / (Math.pi * 2)) * variable.hurt * (((20 * 2 - query.structural_integrity) - query.frame_alpha) < 0 ? 0: (20 * 2 - query.structural_integrity) - query.frame_alpha) / 10 * query.hurt_direction : 0", - 0, - "-variable.rail_rotation.z" - ] - } - } - } - }, - "render_controllers": ["controller.render.minecart"] - }, - "cow": { - "identifier": "minecraft:cow", - "min_engine_version": "1.8.0", - "materials": {"default": "cow"}, - "textures": {"default": "textures/entity/cow/cow"}, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 1.75, - "visible_bounds_offset": [0, 0.75, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "body", - "pivot": [0, 19, 2], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-6, 11, -5], "size": [12, 18, 10], "uv": [18, 4]}, - {"origin": [-2, 11, -6], "size": [4, 6, 1], "uv": [52, 0]} - ] - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 20, -8], - "locators": {"lead": [0, 20, -8]}, - "cubes": [ - {"origin": [-4, 16, -14], "size": [8, 8, 6], "uv": [0, 0]}, - {"origin": [-5, 22, -12], "size": [1, 3, 1], "uv": [22, 0]}, - {"origin": [4, 22, -12], "size": [1, 3, 1], "uv": [22, 0]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-4, 12, 7], - "cubes": [{"origin": [-6, 0, 5], "size": [4, 12, 4], "uv": [0, 16]}] - }, - { - "name": "leg1", - "parent": "body", - "mirror": true, - "pivot": [4, 12, 7], - "cubes": [{"origin": [2, 0, 5], "size": [4, 12, 4], "uv": [0, 16]}] - }, - { - "name": "leg2", - "parent": "body", - "pivot": [-4, 12, -6], - "cubes": [ - {"origin": [-6, 0, -7], "size": [4, 12, 4], "uv": [0, 16]} - ] - }, - { - "name": "leg3", - "parent": "body", - "mirror": true, - "pivot": [4, 12, -6], - "cubes": [{"origin": [2, 0, -7], "size": [4, 12, 4], "uv": [0, 16]}] - } - ] - } - }, - "animations": { - "setup": {"loop": true, "bones": {"body": {"rotation": ["-this", 0, 0]}}}, - "walk": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - }, - "leg1": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg2": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg3": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "baby_transform": { - "loop": true, - "bones": {"head": {"position": [0, 4, 4], "scale": 2}} - } - }, - "scripts": { - "animate": [ - "setup", - {"walk": "query.modified_move_speed"}, - "look_at_target", - {"baby_transform": "query.is_baby"} - ] - }, - "render_controllers": ["controller.render.cow"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 1} - }, - "creeper": { - "identifier": "minecraft:creeper", - "min_engine_version": "1.8.0", - "materials": {"default": "creeper", "charged": "charged_creeper"}, - "textures": { - "default": "textures/entity/creeper/creeper", - "charged": "textures/entity/creeper/creeper_armor" - }, - "geometry": { - "default": { - "visible_bounds_width": 1, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 0.75, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "body", - "cubes": [ - {"origin": [-4, 6, -2], "size": [8, 12, 4], "uv": [16, 16]} - ] - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 18, 0], - "cubes": [{"origin": [-4, 18, -4], "size": [8, 8, 8], "uv": [0, 0]}] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-2, 6, 4], - "cubes": [{"origin": [-4, 0, 2], "size": [4, 6, 4], "uv": [0, 16]}] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [2, 6, 4], - "cubes": [{"origin": [0, 0, 2], "size": [4, 6, 4], "uv": [0, 16]}] - }, - { - "name": "leg2", - "parent": "body", - "pivot": [-2, 6, -4], - "cubes": [{"origin": [-4, 0, -6], "size": [4, 6, 4], "uv": [0, 16]}] - }, - { - "name": "leg3", - "parent": "body", - "pivot": [2, 6, -4], - "cubes": [{"origin": [0, 0, -6], "size": [4, 6, 4], "uv": [0, 16]}] - } - ] - }, - "charged": { - "visible_bounds_width": 1, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 0.75, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "body", - "cubes": [ - {"origin": [-4, 6, -2], "size": [8, 12, 4], "uv": [16, 16]} - ], - "inflate": 2 - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 18, 0], - "cubes": [ - {"origin": [-4, 18, -4], "size": [8, 8, 8], "uv": [0, 0]} - ], - "inflate": 2 - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-2, 6, 4], - "cubes": [{"origin": [-4, 0, 2], "size": [4, 6, 4], "uv": [0, 16]}], - "inflate": 2 - }, - { - "name": "leg1", - "parent": "body", - "pivot": [2, 6, 4], - "cubes": [{"origin": [0, 0, 2], "size": [4, 6, 4], "uv": [0, 16]}], - "inflate": 2 - }, - { - "name": "leg2", - "parent": "body", - "pivot": [-2, 6, -4], - "cubes": [ - {"origin": [-4, 0, -6], "size": [4, 6, 4], "uv": [0, 16]} - ], - "inflate": 2 - }, - { - "name": "leg3", - "parent": "body", - "pivot": [2, 6, -4], - "cubes": [{"origin": [0, 0, -6], "size": [4, 6, 4], "uv": [0, 16]}], - "inflate": 2 - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 6}, - "scripts": { - "pre_animation": [ - "variable.wobble = Math.sin(query.swell_amount * 5730) * query.swell_amount * 0.01 + 1.0;", - "variable.swelling_scale1 = (Math.pow(Math.clamp(query.swell_amount, 0.0, 1.0), 4.0) * 0.4 + 1.0) * variable.wobble;", - "variable.swelling_scale2 = (Math.pow(Math.clamp(query.swell_amount, 0.0, 1.0), 4.0) * 0.1 + 1.0) / variable.wobble;", - "variable.leg_rot = Math.cos(query.modified_distance_moved * 38.17326) * 80.22 * query.modified_move_speed;", - "variable.flash = Math.mod(Math.Round(query.swell_amount * 10.0), 2.0);" - ] - }, - "animations": { - "creeper_head": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "creeper_legs": { - "loop": true, - "bones": { - "leg0": {"rotation": ["variable.leg_rot - this", 0, 0]}, - "leg1": {"rotation": ["-variable.leg_rot - this", 0, 0]}, - "leg2": {"rotation": ["-variable.leg_rot - this", 0, 0]}, - "leg3": {"rotation": ["variable.leg_rot - this", 0, 0]} - } - }, - "creeper_swelling": { - "loop": true, - "bones": { - "body": { - "scale": [ - "variable.swelling_scale1", - "variable.swelling_scale2", - "variable.swelling_scale1" - ] - }, - "head": { - "scale": [ - "variable.swelling_scale1", - "variable.swelling_scale2", - "variable.swelling_scale1" - ] - }, - "leg0": { - "scale": [ - "variable.swelling_scale1", - "variable.swelling_scale2", - "variable.swelling_scale1" - ] - }, - "leg1": { - "scale": [ - "variable.swelling_scale1", - "variable.swelling_scale2", - "variable.swelling_scale1" - ] - }, - "leg2": { - "scale": [ - "variable.swelling_scale1", - "variable.swelling_scale2", - "variable.swelling_scale1" - ] - }, - "leg3": { - "scale": [ - "variable.swelling_scale1", - "variable.swelling_scale2", - "variable.swelling_scale1" - ] - } - } - } - }, - "animation_controllers": { - "creeper_head": { - "initial_state": "default", - "states": {"default": {"animations": ["creeper_head"]}} - }, - "creeper_legs": { - "initial_state": "default", - "states": {"default": {"animations": ["creeper_legs"]}} - }, - "creeper_swelling": { - "initial_state": "default", - "states": {"default": {"animations": ["creeper_swelling"]}} - } - }, - "render_controllers": [ - "controller.render.creeper", - "controller.render.creeper_armor" - ] - }, - "dolphin": { - "identifier": "minecraft:dolphin", - "materials": {"default": "dolphin"}, - "textures": {"default": "textures/entity/dolphin"}, - "geometry": { - "default": { - "bones": [ - { - "pivot": [0, 0, -3], - "locators": {"lead": [0, 0, 0]}, - "cubes": [ - { - "origin": [-4, 0, -9], - "size": [8, 7, 6], - "uv": [0, 0], - "inflate": 0, - "mirror": false - } - ], - "name": "head", - "parent": "body" - }, - { - "pivot": [0, 0, -3], - "cubes": [ - { - "origin": [-4, 0, -3], - "size": [8, 7, 13], - "uv": [0, 13], - "inflate": 0, - "mirror": false - } - ], - "name": "body" - }, - { - "pivot": [0, 2.5, 11], - "cubes": [ - { - "origin": [-2, 0, 10], - "size": [4, 5, 11], - "uv": [0, 33], - "inflate": 0, - "mirror": false - } - ], - "name": "tail", - "parent": "body" - }, - { - "pivot": [0, 2.5, 20], - "cubes": [ - { - "origin": [-5, 2, 19], - "size": [10, 1, 6], - "uv": [0, 49], - "inflate": 0, - "mirror": false - } - ], - "name": "tail_fin", - "parent": "tail" - }, - { - "pivot": [0, 7, 2], - "rotation": [-30, 0, 0], - "cubes": [ - { - "origin": [-0.5, 6.25, 1], - "size": [1, 5, 4], - "uv": [29, 0], - "inflate": 0, - "mirror": false - } - ], - "name": "back_fin", - "parent": "body" - }, - { - "pivot": [3, 1, -1], - "rotation": [0, -25, 20], - "cubes": [ - { - "origin": [3, 1, -2.5], - "size": [8, 1, 4], - "uv": [40, 0], - "inflate": 0, - "mirror": false - } - ], - "name": "left_fin", - "parent": "body" - }, - { - "pivot": [-3, 1, -1], - "rotation": [0, 25, -20], - "cubes": [ - { - "origin": [-11, 1, -2.5], - "size": [8, 1, 4], - "uv": [40, 6], - "inflate": 0, - "mirror": false - } - ], - "name": "right_fin", - "parent": "body" - }, - { - "pivot": [0, 0, -13], - "cubes": [ - { - "origin": [-1, 0, -13], - "size": [2, 2, 4], - "uv": [0, 13], - "inflate": 0, - "mirror": false - } - ], - "name": "nose", - "parent": "head" - } - ], - "texturewidth": 64, - "textureheight": 64 - } - }, - "animations": { - "move": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "query.target_x_rotation - 2.865 + (-2.865 * math.cos(query.life_time * 343.8))", - "query.target_y_rotation", - 0 - ] - }, - "left_fin": { - "rotation": [ - 0, - 0, - "17.19 * math.cos(query.life_time * 229.2) + 22.92" - ] - }, - "right_fin": { - "rotation": [ - 0, - 0, - "-17.19 * math.cos(query.life_time * 229.2) - 22.92" - ] - }, - "tail": { - "rotation": ["-5.73 * math.cos(query.life_time * 343.8)", 0, 0] - }, - "tail_fin": { - "rotation": ["-11.46 * math.cos(query.life_time * 343.8)", 0, 0] - } - } - } - }, - "animation_controllers": { - "general": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - } - }, - "render_controllers": ["controller.render.dolphin"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 49} - }, - "donkey": { - "identifier": "minecraft:donkey", - "textures": { - "base_brown": "textures/entity/horse/horse_brown", - "base_white": "textures/entity/horse/horse_white", - "base_chestnut": "textures/entity/horse/horse_chestnut", - "base_creamy": "textures/entity/horse/horse_creamy", - "base_black": "textures/entity/horse/horse_black", - "base_gray": "textures/entity/horse/horse_gray", - "base_darkbrown": "textures/entity/horse/horse_darkbrown", - "markings_none": "textures/entity/horse/horse_markings_none", - "markings_white": "textures/entity/horse/horse_markings_white", - "markings_whitefield": "textures/entity/horse/horse_markings_whitefield", - "markings_whitedots": "textures/entity/horse/horse_markings_whitedots", - "markings_blackdots": "textures/entity/horse/horse_markings_blackdots", - "mule": "textures/entity/horse/mule", - "donkey": "textures/entity/horse/donkey", - "skeleton": "textures/entity/horse/horse_skeleton", - "zombie": "textures/entity/horse/horse_zombie", - "armor_none": "textures/entity/horse/armor/horse_armor_none", - "armor_leather": "textures/entity/horse/armor/horse_armor_leather", - "armor_iron": "textures/entity/horse/armor/horse_armor_iron", - "armor_gold": "textures/entity/horse/armor/horse_armor_gold", - "armor_diamond": "textures/entity/horse/armor/horse_armor_diamond" - }, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 128, - "textureheight": 128, - "bones": [ - { - "name": "Body", - "pivot": [0, 13, 9], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 11, -10], "size": [10, 10, 24], "uv": [0, 34]} - ] - }, - { - "name": "TailA", - "pivot": [0, 21, 14], - "rotation": [-65, 0, 0], - "cubes": [ - {"origin": [-1, 20, 14], "size": [2, 2, 3], "uv": [44, 0]} - ] - }, - { - "name": "TailB", - "pivot": [0, 21, 14], - "rotation": [-65, 0, 0], - "cubes": [ - {"origin": [-1.5, 19, 17], "size": [3, 4, 7], "uv": [38, 7]} - ] - }, - { - "name": "TailC", - "pivot": [0, 21, 14], - "rotation": [-80.34, 0, 0], - "cubes": [ - {"origin": [-1.5, 21.5, 23], "size": [3, 4, 7], "uv": [24, 3]} - ] - }, - { - "name": "Leg1A", - "pivot": [4, 15, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.5, 8, 8.5], "size": [4, 9, 5], "uv": [78, 29]} - ] - }, - { - "name": "Leg1B", - "pivot": [4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2, 3, 9.5], "size": [3, 5, 3], "uv": [78, 43]} - ] - }, - { - "name": "Leg1C", - "pivot": [4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.5, -0.1, 9], "size": [4, 3, 4], "uv": [78, 51]} - ] - }, - { - "name": "Leg2A", - "pivot": [-4, 15, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 8, 8.5], "size": [4, 9, 5], "uv": [96, 29]} - ] - }, - { - "name": "Leg2B", - "pivot": [-4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 3, 9.5], "size": [3, 5, 3], "uv": [96, 43]} - ] - }, - { - "name": "Leg2C", - "pivot": [-4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, -0.1, 9], "size": [4, 3, 4], "uv": [96, 51]} - ] - }, - { - "name": "Leg3A", - "pivot": [4, 15, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.1, 8, -10.1], "size": [3, 8, 4], "uv": [44, 29]} - ] - }, - { - "name": "Leg3B", - "pivot": [4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.1, 3, -9.6], "size": [3, 5, 3], "uv": [44, 41]} - ] - }, - { - "name": "Leg3C", - "pivot": [4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.6, -0.1, -10.1], "size": [4, 3, 4], "uv": [44, 51]} - ] - }, - { - "name": "Leg4A", - "pivot": [-4, 15, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.1, 8, -10.1], "size": [3, 8, 4], "uv": [60, 29]} - ] - }, - { - "name": "Leg4B", - "pivot": [-4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.1, 3, -9.6], "size": [3, 5, 3], "uv": [60, 41]} - ] - }, - { - "name": "Leg4C", - "pivot": [-4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.6, -0.1, -10.1], "size": [4, 3, 4], "uv": [60, 51]} - ] - }, - { - "name": "Head", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.5, 25, -11.5], "size": [5, 5, 7], "uv": [0, 0]} - ] - }, - { - "name": "UMouth", - "pivot": [0, 20.05, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2, 27.05, -17], "size": [4, 3, 6], "uv": [24, 18]} - ] - }, - { - "name": "LMouth", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2, 25, -16.5], "size": [4, 2, 5], "uv": [24, 27]} - ] - }, - { - "name": "Ear1", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [0.45, 29, -6], "size": [2, 3, 1], "uv": [0, 0]} - ] - }, - { - "name": "Ear2", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.45, 29, -6], "size": [2, 3, 1], "uv": [0, 0]} - ] - }, - { - "name": "MuleEarL", - "pivot": [0, 20, -10], - "rotation": [30, 0, 15], - "cubes": [ - {"origin": [-2, 29, -6], "size": [2, 7, 1], "uv": [0, 12]} - ] - }, - { - "name": "MuleEarR", - "pivot": [0, 20, -10], - "rotation": [30, 0, -15], - "cubes": [{"origin": [0, 29, -6], "size": [2, 7, 1], "uv": [0, 12]}] - }, - { - "name": "Neck", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.05, 15.8, -12], "size": [4, 14, 8], "uv": [0, 12]} - ] - }, - { - "name": "Bag1", - "pivot": [-7.5, 21, 10], - "rotation": [0, 90, 0], - "cubes": [ - {"origin": [-10.5, 13, 10], "size": [8, 8, 3], "uv": [0, 34]} - ] - }, - { - "name": "Bag2", - "pivot": [4.5, 21, 10], - "rotation": [0, 90, 0], - "cubes": [ - {"origin": [1.5, 13, 10], "size": [8, 8, 3], "uv": [0, 47]} - ] - }, - { - "name": "Saddle", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 21, -1], "size": [10, 1, 8], "uv": [80, 0]} - ] - }, - { - "name": "SaddleB", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-1.5, 22, -1], "size": [3, 1, 2], "uv": [106, 9]} - ] - }, - { - "name": "SaddleC", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [{"origin": [-4, 22, 5], "size": [8, 1, 2], "uv": [80, 9]}] - }, - { - "name": "SaddleL2", - "pivot": [5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [4.5, 13, 1], "size": [1, 2, 2], "uv": [74, 0]} - ] - }, - { - "name": "SaddleL", - "pivot": [5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [4.5, 15, 1.5], "size": [1, 6, 1], "uv": [70, 0]} - ] - }, - { - "name": "SaddleR2", - "pivot": [-5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 13, 1], "size": [1, 2, 2], "uv": [74, 4]} - ] - }, - { - "name": "SaddleR", - "pivot": [-5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 15, 1.5], "size": [1, 6, 1], "uv": [80, 0]} - ] - }, - { - "name": "SaddleMouthL", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [1.5, 26, -14], "size": [1, 2, 2], "uv": [74, 13]} - ] - }, - { - "name": "SaddleMouthR", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.5, 26, -14], "size": [1, 2, 2], "uv": [74, 13]} - ] - }, - { - "name": "SaddleMouthLine", - "pivot": [0, 20, -10], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.6, 23, -16], "size": [0, 3, 16], "uv": [44, 10]} - ] - }, - { - "name": "SaddleMouthLineR", - "pivot": [0, 20, -10], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-2.6, 23, -16], "size": [0, 3, 16], "uv": [44, 5]} - ] - }, - { - "name": "Mane", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-1, 15.5, -5], "size": [2, 16, 4], "uv": [58, 0]} - ] - }, - { - "name": "HeadSaddle", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - { - "origin": [-2.5, 25.1, -17], - "size": [5, 5, 12], - "uv": [80, 12], - "inflate": 0.05 - } - ] - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 30} - }, - "dragon_fireball": { - "identifier": "minecraft:dragon_fireball", - "materials": {"default": "fireball"}, - "textures": {"default": "textures/entity/enderdragon/dragon_fireball"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, -4, 0], - "size": [16, 16, 0], - "uv": {"south": {"uv": [0, 0]}} - } - ] - } - ], - "texturewidth": 16, - "textureheight": 16 - } - }, - "animations": { - "face_player": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "query.camera_rotation(0)", - "query.camera_rotation(1)", - 0 - ] - } - } - } - }, - "scripts": {"scale": "2.0", "animate": ["face_player"]}, - "render_controllers": ["controller.render.fireball"] - }, - "drowned": { - "identifier": "minecraft:drowned", - "min_engine_version": "1.16.0", - "materials": {"default": "drowned"}, - "textures": {"default": "textures/entity/zombie/drowned"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} - ] - }, - { - "name": "jacket", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 12, -2], - "size": [8, 12, 4], - "uv": [16, 32], - "inflate": 0.5 - } - ] - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 8, 8], - "uv": [0, 0], - "inflate": 0.5 - } - ] - }, - { - "name": "hat", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 8, 8], - "uv": [32, 0], - "inflate": 1 - } - ] - }, - { - "name": "rightArm", - "parent": "body", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-7, 12, -2], "size": [4, 12, 4], "uv": [0, 16]} - ] - }, - { - "name": "leftArm", - "parent": "body", - "pivot": [5, 22, 0], - "cubes": [ - { - "origin": [4, 12, -2], - "size": [4, 12, 4], - "uv": [40, 16], - "mirror": true - } - ] - }, - { - "name": "rightSleeve", - "parent": "rightArm", - "pivot": [-5, 22, 0], - "cubes": [ - { - "origin": [-7, 12, -2], - "size": [4, 12, 4], - "uv": [48, 48], - "inflate": 0.5 - } - ] - }, - { - "name": "leftSleeve", - "parent": "leftArm", - "pivot": [5, 22, 0], - "cubes": [ - { - "origin": [4, 12, -2], - "size": [4, 12, 4], - "uv": [40, 32], - "inflate": 0.5, - "mirror": true - } - ] - }, - { - "name": "rightLeg", - "parent": "body", - "pivot": [-1.9, 12, 0], - "cubes": [ - {"origin": [-4.05, 0, -2], "size": [4, 12, 4], "uv": [16, 48]} - ] - }, - { - "name": "leftLeg", - "parent": "body", - "pivot": [1.9, 12, 0], - "cubes": [ - { - "origin": [0.05, 0, -2], - "size": [4, 12, 4], - "uv": [32, 48], - "mirror": true - } - ] - }, - { - "name": "rightPants", - "parent": "rightLeg", - "pivot": [-1.9, 12, 0], - "cubes": [ - { - "origin": [-4.25, 0, -2], - "size": [4, 12, 4], - "uv": [0, 48], - "inflate": 0.25 - } - ] - }, - { - "name": "leftPants", - "parent": "leftLeg", - "pivot": [1.9, 12, 0], - "cubes": [ - { - "origin": [0.25, 0, -2], - "size": [4, 12, 4], - "uv": [0, 32], - "inflate": 0.25, - "mirror": true - } - ] - }, - {"name": "waist", "parent": "body", "pivot": [0, 12, 0]}, - {"name": "rightItem", "parent": "rightArm", "pivot": [-6, 15, 1]}, - {"name": "leftItem", "parent": "leftArm", "pivot": [6, 15, 1]} - ], - "visible_bounds_width": 2.5, - "visible_bounds_height": 2.5, - "visible_bounds_offset": [0, 1.25, 0], - "texturewidth": 64, - "textureheight": 64 - } - }, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;" - ], - "animate": [ - {"humanoid_big_head": "query.is_baby"}, - "look_at_target", - "move", - {"riding.arms": "query.is_riding"}, - {"riding.legs": "query.is_riding"}, - "holding", - {"charging": "query.is_charging"}, - "attack_controller", - {"brandish_spear": "variable.is_brandishing_spear"}, - "bob", - {"damage_nearby_mobs": "variable.damage_nearby_mobs"}, - { - "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 )" - }, - {"swimming": "variable.swim_amount > 0.0"} - ] - }, - "animations": { - "humanoid_big_head": {"loop": true, "bones": {"head": {"scale": 1.4}}}, - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "move": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - }, - "holding": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - } - } - }, - "brandish_spear": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "this * -0.5 - 157.5 - 22.5 * variable.charge_amount", - "-this", - 0 - ] - } - } - }, - "charging": { - "loop": true, - "bones": { - "rightarm": { - "rotation": ["22.5 * variable.charge_amount - this", "-this", 0] - } - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "damage_nearby_mobs": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["-45.0-this", "-this", "-this"]}, - "leftleg": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightarm": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-45.0-this", "-this", "-this"]} - } - }, - "use_item_progress": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "variable.use_item_startup_progress * -60.0 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -22.5 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -5.625 + variable.use_item_interval_progress * 11.25" - ] - } - } - }, - "zombie_attack_bare_hand": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "-90.0 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) - (math.sin(query.life_time * 76.776372) * 2.865) - this", - "5.73 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 0.6) - this", - "math.cos(query.life_time * 103.13244) * -2.865 - 2.865 - this" - ] - }, - "rightarm": { - "rotation": [ - "90.0 * (variable.is_brandishing_spear - 1.0) - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) + (math.sin(query.life_time * 76.776372) * 2.865) - this", - "(math.sin(variable.attack_time * 180.0) * 57.3) * 0.6 - 5.73 - this", - "math.cos(query.life_time * 103.13244) * 2.865 + 2.865 - this" - ] - } - } - }, - "attack_rotations": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.sin(math.sqrt(variable.attack_time) * 360.0) * 11.46", - 0 - ] - }, - "leftarm": { - "rotation": [ - "-(math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) + math.sin(variable.attack_time * 180.0)) * 5.73", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "-(math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 34.38 + math.sin(variable.attack_time * 180.0) * 28.65) * (variable.is_brandishing_spear ? -2.5 : 1.0 )", - "variable.is_brandishing_spear ? 0.0 : math.sin(math.sqrt(variable.attack_time) * 360.0) * 22.92", - 0 - ] - } - } - }, - "swimming": { - "loop": true, - "bones": { - "body": { - "position": [ - 0, - "variable.swim_amount * -10.0 - this", - "variable.swim_amount * 9.0 - this" - ], - "rotation": [ - "variable.swim_amount * (90.0 + query.target_x_rotation)", - 0, - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) - (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, 14.325, variable.swim_amount) - (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "leftleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0 + 180.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) + (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, -14.325, variable.swim_amount) + (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "rightleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - } - } - } - }, - "render_controllers": ["controller.render.drowned"], - "enable_attachables": true, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 48}, - "animation_controllers": { - "look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "attack_controller": { - "initial_state": "default", - "states": { - "default": { - "animations": ["zombie_attack_bare_hand"], - "transitions": [ - {"one_hand_attack": "query.is_item_equipped('off_hand')"}, - { - "spear_attack": "variable.is_brandishing_spear && !query.is_item_equipped('off_hand')" - } - ] - }, - "one_hand_attack": { - "animations": ["attack_rotations"], - "transitions": [ - {"default": "!query.is_item_equipped('off_hand')"}, - { - "spear_attack": "variable.is_brandishing_spear && !query.is_item_equipped('off_hand')" - } - ] - }, - "spear_attack": { - "animations": ["zombie_attack_bare_hand", "attack_rotations"], - "transitions": [ - { - "default": "!query.is_item_equipped('off_hand') && !variable.is_brandishing_spear" - }, - {"one_hand_attack": "query.is_item_equipped('off_hand')"} - ] - } - } - } - } - }, - "egg": { - "identifier": "minecraft:egg", - "materials": {"default": "egg"}, - "textures": {"default": "textures/items/egg"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, -8, 0], - "size": [16, 16, 0], - "uv": [0, 0], - "rotation": [0, 0, 0] - } - ] - } - ], - "texturewidth": 16, - "textureheight": 16 - } - }, - "render_controllers": ["controller.render.item_sprite"], - "animations": { - "flying": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "query.camera_rotation(0)", - "query.camera_rotation(1)", - 0 - ] - } - } - } - }, - "scripts": {"animate": ["flying"]} - }, - "elder_guardian": { - "identifier": "minecraft:elder_guardian", - "min_engine_version": "1.8.0", - "materials": {"default": "guardian", "ghost": "guardian_ghost"}, - "textures": { - "default": "textures/entity/guardian", - "elder": "textures/entity/guardian_elder", - "beam": "textures/entity/guardian_beam" - }, - "geometry": { - "default": { - "visible_bounds_width": 3.5, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "head", - "pivot": [0, 0, 0], - "mirror": true, - "cubes": [ - { - "mirror": false, - "origin": [-6, 2, -8], - "size": [12, 12, 16], - "uv": [0, 0] - }, - { - "mirror": false, - "origin": [-8, 2, -6], - "size": [2, 12, 12], - "uv": [0, 28] - }, - {"origin": [6, 2, -6], "size": [2, 12, 12], "uv": [0, 28]}, - {"origin": [-6, 14, -6], "size": [12, 2, 12], "uv": [16, 40]}, - {"origin": [-6, 0, -6], "size": [12, 2, 12], "uv": [16, 40]} - ] - }, - { - "name": "eye", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-1, 6, 0], "size": [2, 2, 1], "uv": [8, 0]}] - }, - { - "name": "tailpart0", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-2, 6, 7], "size": [4, 4, 8], "uv": [40, 0]}] - }, - { - "name": "tailpart1", - "parent": "tailpart0", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 7, 0], "size": [3, 3, 7], "uv": [0, 54]}] - }, - { - "name": "tailpart2", - "parent": "tailpart1", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [0, 8, 0], "size": [2, 2, 6], "uv": [41, 32]}, - {"origin": [1, 4.5, 3], "size": [1, 9, 9], "uv": [25, 19]} - ] - }, - { - "name": "spikepart0", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart1", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart2", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart3", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart4", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart5", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart6", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart7", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart8", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart9", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart10", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart11", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - } - ] - }, - "ghost": { - "visible_bounds_width": 3.5, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "head", - "pivot": [0, 24, 0], - "mirror": true, - "cubes": [ - { - "mirror": false, - "origin": [-6, 2, -8], - "size": [12, 12, 16], - "uv": [0, 0] - }, - { - "mirror": false, - "origin": [-8, 2, -6], - "size": [2, 12, 12], - "uv": [0, 28] - }, - {"origin": [6, 2, -6], "size": [2, 12, 12], "uv": [0, 28]}, - {"origin": [-6, 14, -6], "size": [12, 2, 12], "uv": [16, 40]}, - {"origin": [-6, 0, -6], "size": [12, 2, 12], "uv": [16, 40]} - ] - }, - { - "name": "eye", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-1, 7, 0], "size": [2, 2, 1], "uv": [8, 0]}] - }, - { - "name": "tailpart0", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-2, 6, 7], "size": [4, 4, 8], "uv": [40, 0]}] - }, - { - "name": "tailpart1", - "parent": "tailpart0", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 7, 0], "size": [3, 3, 7], "uv": [0, 54]}] - }, - { - "name": "tailpart2", - "parent": "tailpart1", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [0, 8, 0], "size": [2, 2, 6], "uv": [41, 32]}, - {"origin": [1, 4.5, 3], "size": [1, 9, 9], "uv": [25, 19]} - ] - }, - { - "name": "spikepart0", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart1", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart2", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart3", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart4", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart5", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart6", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart7", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart8", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart9", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart10", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart11", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - } - ] - } - }, - "animations": { - "setup": { - "loop": true, - "bones": { - "spikepart0": { - "rotation": ["-45.0 - this", "0.0 - this", "0.0 - this"] - }, - "spikepart1": { - "rotation": ["45.0 - this", "0.0 - this", "0.0 - this"] - }, - "spikepart10": { - "rotation": ["0.0 - this", "0.0 - this", " 135.0 - this"] - }, - "spikepart11": { - "rotation": ["0.0 - this", "0.0 - this", " -135.0 - this"] - }, - "spikepart2": { - "rotation": ["0.0 - this", "0.0 - this", "45.0 - this"] - }, - "spikepart3": { - "rotation": ["0.0 - this", "0.0 - this", "-45.0 - this"] - }, - "spikepart4": { - "rotation": ["90.0 - this", "45.0 - this", " 0.0 - this"] - }, - "spikepart5": { - "rotation": ["90.0 - this", "-45.0 - this", " 0.0 - this"] - }, - "spikepart6": { - "rotation": ["90.0 - this", "-135.0 - this", "0.0 - this"] - }, - "spikepart7": { - "rotation": ["90.0 - this", "135.0 - this", " 0.0 - this"] - }, - "spikepart8": { - "rotation": ["-135.0 - this", "0.0 - this", " 0.0 - this"] - }, - "spikepart9": { - "rotation": ["135.0 - this", "0.0 - this", " 0.0 - this"] - } - } - }, - "spikes": { - "loop": true, - "bones": { - "spikepart0": { - "position": [ - "-this", - "24 + -8 * (1 + math.cos(query.life_time * 20 * 1.5) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "8 * (1 + math.cos(query.life_time * 20 * 1.5) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this" - ] - }, - "spikepart1": { - "position": [ - "-this", - "24 + -8 * (1 + math.cos(query.life_time * 20 * 1.5 + 1) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 1) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this" - ] - }, - "spikepart10": { - "position": [ - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 10) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this", - "-8 + 8 * (1 + math.cos(query.life_time * 20 * 1.5 + 10) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "-this" - ] - }, - "spikepart11": { - "position": [ - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 11) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this", - "-8 + 8 * (1 + math.cos(query.life_time * 20 * 1.5 + 11) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "-this" - ] - }, - "spikepart2": { - "position": [ - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 2) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this", - "24 + -8 * (1 + math.cos(query.life_time * 20 * 1.5 + 2) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "-this" - ] - }, - "spikepart3": { - "position": [ - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 3) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this", - "24 + -8 * (1 + math.cos(query.life_time * 20 * 1.5 + 3) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - 0 - ] - }, - "spikepart4": { - "position": [ - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 4) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this", - "8 - this", - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 4) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this" - ] - }, - "spikepart5": { - "position": [ - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 5) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this", - "8 - this", - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 5) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this" - ] - }, - "spikepart6": { - "position": [ - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 6) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this", - "8 - this", - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 6) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this" - ] - }, - "spikepart7": { - "position": [ - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 7) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this", - "8 - this", - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 7) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this" - ] - }, - "spikepart8": { - "position": [ - "-this", - "-8 + 8 * (1 + math.cos(query.life_time * 20 * 1.5 + 8) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 8) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this" - ] - }, - "spikepart9": { - "position": [ - "-this", - "-8 + 8 * (1 + math.cos(query.life_time * 20 * 1.5 + 9) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 9) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this" - ] - } - } - }, - "swim": { - "loop": true, - "bones": { - "tailpart0": { - "rotation": [0, "variable.tail_base_angle * 11.6 - this", 0] - }, - "tailpart1": { - "position": ["-1.5 - this", "-0.5 - this", "14.0 - this"], - "rotation": [0, "variable.tail_base_angle * 22.8 - this", 0] - }, - "tailpart2": { - "position": ["0.5 - this", "-0.5 - this", "6.0 - this"], - "rotation": [0, "variable.tail_base_angle * 34.4 - this", 0] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "move_eye": { - "loop": true, - "bones": { - "eye": { - "position": [ - "query.eye_target_x_rotation - this", - "24 + query.eye_target_y_rotation - this", - "-8.25 - this" - ] - } - } - } - }, - "scripts": { - "pre_animation": [ - "variable.spike_shake = Math.sin(query.life_time * 2000)/50;", - "variable.spike_animation_speed = query.life_time < 0.1 ? 0.0 : (!query.is_in_water ? (Math.round(Math.sin(query.life_time * 2000)) == 0.0 ? (Math.random(0.0, 1.0)) : (variable.spike_animation_speed)) : (query.is_moving ? (variable.spike_animation_speed - variable.spike_animation_speed * 0.06) : (variable.spike_animation_speed + (1.0 - variable.spike_animation_speed) * 0.06)));", - "variable.spike_extension = (1.0 - variable.spike_animation_speed) * 0.55;", - "variable.tail_animation_speed = query.life_time < 0.1 ? 0.0 : (!query.is_in_water ? 2.0 : query.is_moving ? (variable.tail_animation_speed < 0.5 ? 4.0 : variable.tail_animation_speed + (0.5 - variable.tail_animation_speed) * 0.1) : variable.tail_animation_speed + (0.125 - variable.tail_animation_speed) * 0.2);", - "variable.tail_swim = query.life_time < 0.1 ? 0.0 : (variable.tail_swim + variable.tail_animation_speed);", - "variable.tail_base_angle = Math.sin(variable.tail_swim*20.0);" - ], - "scale": "2.35", - "animate": ["setup", "spikes", "swim", "look_at_target", "move_eye"] - }, - "render_controllers": ["controller.render.guardian"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 36} - }, - "ender_dragon": { - "identifier": "minecraft:ender_dragon", - "textures": { - "default": "textures/entity/enderdragon/dragon", - "exploding": "textures/entity/enderdragon/dragon_exploding", - "beam": "textures/entity/end_crystal/end_crystal_beam" - }, - "geometry": { - "default": { - "visible_bounds_width": 14, - "visible_bounds_height": 13, - "visible_bounds_offset": [0, 2, 0], - "texturewidth": 256, - "textureheight": 256, - "bones": [ - { - "name": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-6, 20, -24], "size": [12, 5, 16], "uv": [176, 44]}, - {"origin": [-8, 16, -10], "size": [16, 16, 16], "uv": [112, 30]}, - { - "mirror": true, - "origin": [-5, 32, -4], - "size": [2, 4, 6], - "uv": [0, 0] - }, - { - "mirror": true, - "origin": [-5, 25, -22], - "size": [2, 2, 4], - "uv": [112, 0] - }, - {"origin": [3, 32, -4], "size": [2, 4, 6], "uv": [0, 0]}, - {"origin": [3, 25, -22], "size": [2, 2, 4], "uv": [112, 0]} - ] - }, - { - "name": "jaw", - "pivot": [0, 20, -8], - "cubes": [ - {"origin": [-6, 16, -24], "size": [12, 4, 16], "uv": [176, 65]} - ] - }, - { - "name": "neck", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-5, 19, -5], "size": [10, 10, 10], "uv": [192, 104]}, - {"origin": [-1, 29, -3], "size": [2, 4, 6], "uv": [48, 0]} - ] - }, - { - "name": "body", - "pivot": [0, 20, 8], - "cubes": [ - {"origin": [-12, -4, -8], "size": [24, 24, 64], "uv": [0, 0]}, - {"origin": [-1, 20, -2], "size": [2, 6, 12], "uv": [220, 53]}, - {"origin": [-1, 20, 18], "size": [2, 6, 12], "uv": [220, 53]}, - {"origin": [-1, 20, 38], "size": [2, 6, 12], "uv": [220, 53]} - ] - }, - { - "name": "wing", - "pivot": [-12, 19, 2], - "cubes": [ - {"origin": [-68, 15, -2], "size": [56, 8, 8], "uv": [112, 88]}, - {"origin": [-68, 19, 4], "size": [56, 0, 56], "uv": [-56, 88]} - ] - }, - { - "name": "wingtip", - "pivot": [-56, 24, 0], - "cubes": [ - {"origin": [-112, 22, -2], "size": [56, 4, 4], "uv": [112, 136]}, - {"origin": [-112, 24, 2], "size": [56, 0, 56], "uv": [-56, 144]} - ] - }, - { - "name": "wing1", - "pivot": [12, 19, 2], - "cubes": [ - {"origin": [-44, 15, -2], "size": [56, 8, 8], "uv": [112, 88]}, - {"origin": [-44, 19, 4], "size": [56, 0, 56], "uv": [-56, 88]} - ] - }, - { - "name": "wingtip1", - "pivot": [-56, 24, 0], - "cubes": [ - {"origin": [-112, 22, -2], "size": [56, 4, 4], "uv": [112, 136]}, - {"origin": [-112, 24, 2], "size": [56, 0, 56], "uv": [-56, 144]} - ] - }, - { - "name": "rearleg", - "pivot": [-16, 8, 42], - "cubes": [ - {"origin": [-24, -20, 34], "size": [16, 32, 16], "uv": [0, 0]} - ] - }, - { - "name": "rearleg1", - "pivot": [16, 8, 42], - "cubes": [ - {"origin": [8, -20, 34], "size": [16, 32, 16], "uv": [0, 0]} - ] - }, - { - "name": "frontleg", - "pivot": [-12, 4, 2], - "cubes": [ - {"origin": [-16, -16, -2], "size": [8, 24, 8], "uv": [112, 104]} - ] - }, - { - "name": "frontleg1", - "pivot": [12, 4, 2], - "cubes": [ - {"origin": [8, -16, -2], "size": [8, 24, 8], "uv": [112, 104]} - ] - }, - { - "name": "rearlegtip", - "pivot": [0, -8, -4], - "cubes": [ - {"origin": [-6, -38, -4], "size": [12, 32, 12], "uv": [196, 0]} - ] - }, - { - "name": "rearlegtip1", - "pivot": [0, -8, -4], - "cubes": [ - {"origin": [-6, -38, -4], "size": [12, 32, 12], "uv": [196, 0]} - ] - }, - { - "name": "frontlegtip", - "pivot": [0, 4, -1], - "cubes": [ - {"origin": [-3, -19, -4], "size": [6, 24, 6], "uv": [226, 138]} - ] - }, - { - "name": "frontlegtip1", - "pivot": [0, 4, -1], - "cubes": [ - {"origin": [-3, -19, -4], "size": [6, 24, 6], "uv": [226, 138]} - ] - }, - { - "name": "rearfoot", - "pivot": [0, -7, 4], - "cubes": [ - {"origin": [-9, -13, -16], "size": [18, 6, 24], "uv": [112, 0]} - ] - }, - { - "name": "rearfoot1", - "pivot": [0, -7, 4], - "cubes": [ - {"origin": [-9, -13, -16], "size": [18, 6, 24], "uv": [112, 0]} - ] - }, - { - "name": "frontfoot", - "pivot": [0, 1, 0], - "cubes": [ - {"origin": [-4, -3, -12], "size": [8, 4, 16], "uv": [144, 104]} - ] - }, - { - "name": "frontfoot1", - "pivot": [0, 1, 0], - "cubes": [ - {"origin": [-4, -3, -12], "size": [8, 4, 16], "uv": [144, 104]} - ] - } - ] - } - } - }, - "eye_of_ender": { - "identifier": "minecraft:eye_of_ender_signal", - "materials": {"default": "eye_of_ender_signal"}, - "textures": {"default": "textures/items/ender_eye"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, -8, 0], - "size": [16, 16, 0], - "uv": [0, 0], - "rotation": [0, 0, 0] - } - ] - } - ], - "texturewidth": 16, - "textureheight": 16 - } - }, - "render_controllers": ["controller.render.item_sprite"], - "animations": { - "flying": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "query.camera_rotation(0)", - "query.camera_rotation(1)", - 0 - ] - } - } - } - }, - "scripts": {"animate": ["flying"]} - }, - "ender_pearl": { - "identifier": "minecraft:ender_pearl", - "materials": {"default": "ender_pearl"}, - "textures": {"default": "textures/items/ender_pearl"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, -8, 0], - "size": [16, 16, 0], - "uv": [0, 0], - "rotation": [0, 0, 0] - } - ] - } - ], - "texturewidth": 16, - "textureheight": 16 - } - }, - "render_controllers": ["controller.render.item_sprite"], - "animations": { - "flying": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "query.camera_rotation(0)", - "query.camera_rotation(1)", - 0 - ] - } - } - } - }, - "scripts": {"animate": ["flying"]} - }, - "enderman": { - "identifier": "minecraft:enderman", - "min_engine_version": "1.8.0", - "materials": {"default": "enderman", "invisible": "enderman_invisible"}, - "textures": {"default": "textures/entity/enderman/enderman"}, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "hat", - "parent": "head", - "reset": true, - "pivot": [0, 38, 0], - "cubes": [ - { - "origin": [-4, 37.5, -4], - "size": [8, 8, 8], - "uv": [0, 16], - "inflate": -0.5 - } - ], - "neverRender": false - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]}] - }, - { - "name": "body", - "reset": true, - "pivot": [0, 38, 0], - "cubes": [ - {"origin": [-4, 26, -2], "size": [8, 12, 4], "uv": [32, 16]} - ] - }, - { - "name": "rightArm", - "parent": "body", - "reset": true, - "pivot": [-3, 36, 0], - "cubes": [ - {"origin": [-4, 8, -1], "size": [2, 30, 2], "uv": [56, 0]} - ] - }, - { - "name": "rightItem", - "pivot": [-6, 15, 1], - "neverRender": true, - "parent": "rightArm" - }, - { - "name": "leftArm", - "parent": "body", - "reset": true, - "mirror": true, - "pivot": [5, 36, 0], - "cubes": [{"origin": [4, 8, -1], "size": [2, 30, 2], "uv": [56, 0]}] - }, - { - "name": "rightLeg", - "parent": "body", - "reset": true, - "pivot": [-2, 26, 0], - "cubes": [ - {"origin": [-3, -4, -1], "size": [2, 30, 2], "uv": [56, 0]} - ] - }, - { - "name": "leftLeg", - "parent": "body", - "reset": true, - "mirror": true, - "pivot": [2, 26, 0], - "cubes": [ - {"origin": [1, -4, -1], "size": [2, 30, 2], "uv": [56, 0]} - ] - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 28.65;" - ] - }, - "animations": { - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "move": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "attack.rotations": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46 - this", - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.sin(1.0 - math.pow(1.0 - variable.attack_time, 3.0) * 180.0) * (variable.is_brandishing_spear ? -1.0 : 1.0 )", - "variable.is_brandishing_spear ? 0.0 : (math.sin(math.sqrt(variable.attack_time) * 360) * 11.46) * 2.0", - 0 - ] - } - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "base_pose": { - "loop": true, - "bones": { - "body": { - "position": ["-this", "11.0 - this", "-this"], - "rotation": ["-this", 0, 0] - }, - "hat": { - "position": ["-this", "-this", "-this"], - "rotation": ["-this", "-this", "-this"] - }, - "head": {"position": ["-this", "-this", "-this"]}, - "leftarm": {"position": ["4.0-this", 0, "-this"]}, - "leftleg": {"position": [0, "-5.0 - this", 0]}, - "rightarm": {"position": ["-4.0-this", 0, "-this"]}, - "rightleg": {"position": [0, "-5.0 - this", 0]} - } - }, - "arms_legs": { - "loop": true, - "bones": { - "leftarm": { - "rotation": ["math.clamp(this, -22.92, 22.92) - this", 0, 0] - }, - "leftleg": { - "rotation": ["math.clamp(this, -22.92, 22.92) - this", 0, 0] - }, - "rightarm": { - "rotation": ["math.clamp(this, -22.92, 22.92) - this", 0, 0] - }, - "rightleg": { - "rotation": ["math.clamp(this, -22.92, 22.92) - this", 0, 0] - } - } - }, - "carrying": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["-28.65 - this", 0, "-2.87 - this"]}, - "rightarm": {"rotation": ["-28.65 - this", 0, "2.87 - this"]} - } - }, - "scary_face": { - "loop": true, - "bones": { - "hat": {"position": [0, "-5.0 - this", 0]}, - "head": {"position": [0, "5.0 - this", 0]} - } - } - }, - "animation_controllers": { - "look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - }, - "attack": { - "initial_state": "default", - "states": { - "attacking": { - "animations": ["attack.rotations"], - "transitions": [{"default": "variable.attack_time < 0.0"}] - }, - "default": { - "transitions": [{"attacking": "variable.attack_time >= 0.0"}] - } - } - }, - "bob": { - "initial_state": "default", - "states": {"default": {"animations": ["bob"]}} - }, - "base_pose": { - "initial_state": "default", - "states": {"default": {"animations": ["base_pose", "arms_legs"]}} - }, - "carrying": { - "initial_state": "default", - "states": { - "carry": { - "animations": ["carrying"], - "transitions": [{"default": "!query.is_carrying_block"}] - }, - "default": {"transitions": [{"carry": "query.is_carrying_block"}]} - } - }, - "scary_face": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"scary": "query.is_angry"}]}, - "scary": { - "animations": ["scary_face"], - "transitions": [{"default": "!query.is_angry"}] - } - } - } - }, - "render_controllers": ["controller.render.enderman"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 7} - }, - "endermite": { - "identifier": "minecraft:endermite", - "materials": {"default": "endermite"}, - "textures": {"default": "textures/entity/endermite"}, - "geometry": { - "default": { - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "section_0", - "parent": "section_2", - "pivot": [0, 0, 0], - "cubes": [ - {"origin": [-2, 0, -4.4], "size": [4, 3, 2], "uv": [0, 0]} - ] - }, - { - "name": "section_1", - "parent": "section_2", - "pivot": [0, 0, 0], - "cubes": [ - {"origin": [-3, 0, -2.4], "size": [6, 4, 5], "uv": [0, 5]} - ] - }, - { - "name": "section_2", - "pivot": [0, 0, 2.5], - "cubes": [ - {"origin": [-1.5, 0, 2.5], "size": [3, 3, 1], "uv": [0, 14]} - ] - }, - { - "name": "section_3", - "parent": "section_2", - "pivot": [0, 0, 0], - "cubes": [ - {"origin": [-0.5, 0, 3.5], "size": [1, 2, 1], "uv": [0, 18]} - ] - } - ] - } - }, - "animations": { - "move": { - "loop": true, - "bones": { - "section_0": { - "position": [ - "(math.cos(-query.life_time * 928.26) * 1.26) - this", - 0, - 0 - ], - "rotation": [ - 0, - "(math.cos(query.life_time * 928.26) * 26.9) - this", - 0 - ] - }, - "section_1": { - "position": [ - "(math.sin(query.life_time * 928.26) * 0.63) - this", - 0, - 0 - ], - "rotation": [ - 0, - "(math.cos(query.life_time * 928.26) * 16) - this", - 0 - ] - }, - "section_2": { - "position": [0, 0, 0], - "rotation": [ - 0, - "(math.cos(query.life_time * 928.26) * 9.17) - this", - 0 - ] - }, - "section_3": { - "position": [ - "(math.cos(query.life_time * 928.26) * 0.8) - this", - 0, - 0 - ] - } - } - } - }, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - } - }, - "render_controllers": ["controller.render.endermite"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 25} - }, - "evoker_fangs": { - "identifier": "minecraft:evocation_fang", - "materials": {"default": "fang"}, - "textures": {"default": "textures/entity/illager/evoker_fangs"}, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "upper_jaw", - "parent": "base", - "pivot": [0, 11, 0], - "cubes": [ - { - "origin": [-1.5, 0, -4], - "size": [4, 14, 8], - "uv": [40, 0], - "inflate": 0.01 - } - ] - }, - { - "name": "lower_jaw", - "parent": "base", - "pivot": [0, 11, 0], - "bind_pose_rotation": [0, 180, 0], - "cubes": [ - {"origin": [-1.5, 0, -4], "size": [4, 14, 8], "uv": [40, 0]} - ] - }, - { - "name": "base", - "pivot": [0, 0, 0], - "bind_pose_rotation": [0, 90, 0], - "cubes": [ - {"origin": [-5, 0, -5], "size": [10, 12, 10], "uv": [0, 0]} - ] - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.remaining_life = (query.life_span - 2.0) - (query.life_time*20.0);", - "variable.animation_progress = query.life_span == 0.0 ? 0.0 : (variable.remaining_life < 1.0 ? 1.0 : 1.0 - Math.min(1.0, variable.remaining_life / 20.0));", - "variable.bite_amount = (1 - Math.Pow(Math.Clamp(variable.animation_progress*2.0, 0, 1.0), 3.0)) * 0.35 * 180;", - "variable.y_offset = (variable.animation_progress + Math.sin(variable.animation_progress*2.7*80.0)) * 0.6 * 12.0;" - ], - "animate": ["bite"], - "scale": "variable.animation_progress > 0.9 ? (1.0 - variable.animation_progress) / 0.1 : 1.0" - }, - "animations": { - "bite": { - "loop": true, - "bones": { - "base": {"position": [0, "-12.0 + variable.y_offset", 0]}, - "lower_jaw": {"rotation": [0, 0, "180.0 + variable.bite_amount"]}, - "upper_jaw": {"rotation": [0, 0, "180.0 - variable.bite_amount"]} - } - } - }, - "render_controllers": ["controller.render.evocation_fang"] - }, - "evoker": { - "identifier": "minecraft:evocation_illager", - "min_engine_version": "1.8.0", - "materials": {"default": "evoker"}, - "textures": {"default": "textures/entity/illager/evoker"}, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 2.5, - "visible_bounds_offset": [0, 1.25, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 10, 8], "uv": [0, 0]} - ] - }, - { - "name": "nose", - "parent": "head", - "pivot": [0, 26, 0], - "cubes": [ - {"origin": [-1, 23, -6], "size": [2, 4, 2], "uv": [24, 0]} - ] - }, - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -3], "size": [8, 12, 6], "uv": [16, 20]}, - { - "origin": [-4, 6, -3], - "size": [8, 18, 6], - "uv": [0, 38], - "inflate": 0.5 - } - ] - }, - { - "name": "arms", - "parent": "body", - "pivot": [0, 22, 0], - "cubes": [ - {"origin": [-8, 16, -2], "size": [4, 8, 4], "uv": [44, 22]}, - {"origin": [4, 16, -2], "size": [4, 8, 4], "uv": [44, 22]}, - {"origin": [-4, 16, -2], "size": [8, 4, 4], "uv": [40, 38]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-2, 12, 0], - "cubes": [ - {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 22]} - ] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [2, 12, 0], - "mirror": true, - "cubes": [{"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [0, 22]}] - }, - { - "name": "rightArm", - "parent": "body", - "pivot": [-5, 22, 0], - "locators": {"right_hand": [-6, 12, 0]}, - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 46]} - ] - }, - { - "name": "rightItem", - "pivot": [-5.5, 16, 0.5], - "neverRender": true, - "parent": "rightArm" - }, - { - "name": "leftArm", - "parent": "body", - "pivot": [5, 22, 0], - "locators": {"left_hand": [6, 12, 0]}, - "mirror": true, - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 46]} - ] - } - ] - } - }, - "scripts": { - "scale": "0.9375", - "animate": ["controller_general", "controller_move"] - }, - "animations": { - "general": { - "loop": true, - "bones": { - "arms": { - "position": [0, "-3.0 - this", "-1.0 - this"], - "rotation": ["-42.97 - this", "- this", "- this"], - "scale": 1 - }, - "leftarm": {"scale": 0}, - "rightarm": {"scale": 0} - } - }, - "casting": { - "loop": true, - "bones": { - "arms": {"scale": 0}, - "leftarm": { - "rotation": [ - "math.cos(query.life_time * 763.4) * 14.3239 - this", - "-this", - "-135.0 - this" - ], - "scale": 1 - }, - "rightarm": { - "rotation": [ - "math.cos(query.life_time * 763.4) * 14.3239 - this", - "-this", - "135.0 - this" - ], - "scale": 1 - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "move": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": [ - "(math.cos(query.anim_time * 38.17) * 40.0) - this", - "-this", - 0 - ] - }, - "leg1": { - "rotation": [ - "(math.cos(query.anim_time * 38.17 + 180) * 40.0) - this", - "-this", - 0 - ] - } - } - }, - "celebrating": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "(math.cos(query.life_time * 800.0) * 2.865)", - 180, - -135 - ] - }, - "rightarm": { - "rotation": [ - "(math.cos(query.life_time * 800.0) * 2.865)", - 180, - 153 - ] - } - } - } - }, - "particle_effects": {"spell": "minecraft:evoker_spell"}, - "render_controllers": ["controller.render.evoker"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 40}, - "animation_controllers": { - "controller_general": { - "initial_state": "default", - "states": { - "casting": { - "animations": ["look_at_target", "casting"], - "particle_effects": [ - {"effect": "spell", "locator": "left_hand"}, - {"effect": "spell", "locator": "right_hand"} - ], - "transitions": [{"default": "!query.is_casting"}] - }, - "celebrating": { - "animations": ["celebrating"], - "blend_transition": 0.2, - "blend_via_shortest_path": true, - "transitions": [{"default": "!query.is_celebrating"}] - }, - "default": { - "animations": ["look_at_target", "general"], - "blend_transition": 0.2, - "blend_via_shortest_path": true, - "transitions": [ - {"casting": "query.is_casting"}, - {"celebrating": "query.is_celebrating"} - ] - } - } - }, - "controller_move": { - "initial_state": "default", - "states": { - "default": {"animations": [{"move": "query.modified_move_speed"}]} - } - } - } - }, - "experience_bottle": { - "identifier": "minecraft:xp_bottle", - "materials": {"default": "xp_bottle"}, - "textures": { - "default": "textures/items/experience_bottle", - "enchanted": "textures/misc/enchanted_item_glint" - }, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, -8, 0], - "size": [16, 16, 0], - "uv": [0, 0], - "rotation": [0, 0, 0] - } - ] - } - ], - "texturewidth": 16, - "textureheight": 16 - } - }, - "render_controllers": ["controller.render.experience_bottle"], - "animations": { - "flying": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "query.camera_rotation(0)", - "query.camera_rotation(1)", - 0 - ] - } - } - } - }, - "scripts": {"animate": ["flying"]} - }, - "experience_orb": { - "identifier": "minecraft:xp_orb", - "materials": {"default": "experience_orb"}, - "textures": {"default": "textures/entity/experience_orb"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [8, 8, 0], - "cubes": [ - { - "origin": [0, 0, 0], - "size": [16, 16, 0], - "uv": {"south": {"uv": [0, 0]}} - } - ] - } - ], - "texturewidth": 64, - "textureheight": 64 - } - }, - "animations": { - "face_player": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "query.camera_rotation(0)", - "query.camera_rotation(1)", - 0 - ] - } - } - } - }, - "scripts": { - "scale": "0.3", - "pre_animation": [ - "variable.u = Math.mod(query.texture_frame_index, 4) * 16.0 / 64.0;", - "variable.v = math.round(query.texture_frame_index / 4) * 16.0 / 64.0;" - ], - "animate": ["face_player"] - }, - "render_controllers": ["controller.render.experience_orb"] - }, - "fireball": { - "identifier": "minecraft:fireball", - "materials": {"default": "fireball"}, - "textures": {"default": "textures/items/fire_charge"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, -4, 0], - "size": [16, 16, 0], - "uv": {"south": {"uv": [0, 0]}} - } - ] - } - ], - "texturewidth": 16, - "textureheight": 16 - } - }, - "animations": { - "face_player": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "query.camera_rotation(0)", - "query.camera_rotation(1)", - 0 - ] - } - } - } - }, - "scripts": {"scale": "2.0", "animate": ["face_player"]}, - "render_controllers": ["controller.render.fireball"] - }, - "firework_rocket": { - "identifier": "minecraft:fireworks_rocket", - "materials": {"default": "fireworks_rocket"}, - "textures": {"default": "textures/entity/fireworks"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, -8, 0], - "rotation": [0, 90, 0], - "size": [16, 16, 0], - "uv": {"north": {"uv": [0, 0]}} - }, - { - "origin": [-8, -8, 0], - "rotation": [90, 90, 0], - "size": [16, 16, 0], - "uv": {"north": {"uv": [0, 0]}} - } - ] - } - ], - "texturewidth": 32, - "textureheight": 32 - } - }, - "animations": { - "move": { - "loop": true, - "bones": { - "body": { - "position": [0, -3.5, 0], - "rotation": [ - "-query.target_x_rotation", - "-query.target_y_rotation", - 0 - ], - "scale": 0.6 - } - } - } - }, - "scripts": {"animate": ["move"]}, - "render_controllers": ["controller.render.fireworks_rocket"] - }, - "fishing_bobber": { - "identifier": "minecraft:fishing_hook", - "materials": {"default": "fishing_hook"}, - "textures": {"default": "textures/entity/fishing_hook"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-1.5, -1.5, -1.5], - "size": [3, 3, 3], - "rotation": [0, 0, 180], - "uv": { - "up": {"uv": [0, 0]}, - "down": {"uv": [3, 0]}, - "south": {"uv": [9, 0], "uv_size": [-3, 3]}, - "north": {"uv": [9, 0]}, - "east": {"uv": [12, 0]}, - "west": {"uv": [15, 0]} - } - }, - { - "origin": [0, -4.5, -0.5], - "size": [0, 3, 3], - "uv": {"east": {"uv": [18, 0]}} - }, - { - "origin": [0, 1.5, -1.5], - "size": [0, 3, 3], - "uv": {"east": {"uv": [21, 0]}} - }, - { - "origin": [-1.5, 1.5, 0], - "size": [3, 3, 0], - "uv": {"north": {"uv": [21, 0]}} - } - ] - } - ], - "texturewidth": 24, - "textureheight": 3 - } - }, - "render_controllers": ["controller.render.fishing_hook"] - }, - "fox": { - "identifier": "minecraft:fox", - "materials": {"default": "fox"}, - "textures": { - "red": "textures/entity/fox/fox", - "arctic": "textures/entity/fox/snow_fox" - }, - "geometry": { - "default": { - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "world", - "pivot": [0, 0, 0], - "bind_pose_rotation": [0, 0, 0], - "cubes": [] - }, - { - "name": "root", - "parent": "world", - "pivot": [0, 0, 0], - "bind_pose_rotation": [0, 0, 0], - "cubes": [] - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 8, -3], - "locators": {"held_item": [-2, 5, -10], "lead": [0, 4, -4]}, - "bind_pose_rotation": [0, 0, 0], - "cubes": [ - {"origin": [-4, 4, -9], "size": [8, 6, 6], "uv": [0, 0]}, - {"origin": [-4, 10, -8], "size": [2, 2, 1], "uv": [0, 0]}, - {"origin": [2, 10, -8], "size": [2, 2, 1], "uv": [22, 0]}, - {"origin": [-2, 4, -12], "size": [4, 2, 3], "uv": [0, 24]} - ] - }, - { - "name": "head_sleeping", - "parent": "head", - "pivot": [0, 8, -3], - "bind_pose_rotation": [0, 0, 0], - "cubes": [ - {"origin": [-4, 4, -9], "size": [8, 6, 6], "uv": [0, 12]}, - {"origin": [-4, 10, -8], "size": [2, 2, 1], "uv": [0, 0]}, - {"origin": [2, 10, -8], "size": [2, 2, 1], "uv": [22, 0]}, - {"origin": [-2, 4, -12], "size": [4, 2, 3], "uv": [0, 24]} - ] - }, - { - "name": "body", - "parent": "root", - "pivot": [0, 8, 0], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-3, 0, -3], "size": [6, 11, 6], "uv": [30, 15]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-3, 6, 6], - "bind_pose_rotation": [0, 0, 0], - "cubes": [ - {"origin": [-3.005, 0, 5], "size": [2, 6, 2], "uv": [14, 24]} - ] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [1, 6, 6], - "bind_pose_rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.005, 0, 5], "size": [2, 6, 2], "uv": [22, 24]} - ] - }, - { - "name": "leg2", - "parent": "body", - "pivot": [-3, 6, -1], - "bind_pose_rotation": [0, 0, 0], - "cubes": [ - {"origin": [-3.005, 0, -2], "size": [2, 6, 2], "uv": [14, 24]} - ] - }, - { - "name": "leg3", - "parent": "body", - "pivot": [1, 6, -1], - "bind_pose_rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.005, 0, -2], "size": [2, 6, 2], "uv": [22, 24]} - ] - }, - { - "name": "tail", - "parent": "body", - "pivot": [0, 8, 7], - "bind_pose_rotation": [80, 0, 0], - "cubes": [ - {"origin": [-2, -2, 4.75], "size": [4, 9, 5], "uv": [28, 0]} - ] - } - ] - } - }, - "animations": { - "walk": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - }, - "leg1": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg2": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg3": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "baby_transform": { - "loop": true, - "bones": { - "head": { - "position": [ - 0, - "query.is_baby ? 4.0 : 0.0", - "query.is_baby ? 4.0 : 0.0" - ], - "scale": "query.is_baby ? 1.3 : 1.0" - } - } - }, - "crouch": { - "loop": true, - "bones": { - "body": {"position": [0, -1.8, 0], "rotation": [0, 0, 0]}, - "head": {"position": [0, -0.8, 0], "rotation": [0, 0, 0]}, - "leg0": {"position": [0, 1.6, 0], "rotation": [0, 0, 0]}, - "leg1": {"position": [0, 1.6, 0], "rotation": [0, 0, 0]}, - "leg2": {"position": [0, 1.6, 0], "rotation": [0, 0, 0]}, - "leg3": {"position": [0, 1.6, 0], "rotation": [0, 0, 0]} - } - }, - "sleep": { - "loop": true, - "bones": { - "body": {"position": [0, -4.8, 0], "rotation": [0, 0, -90]}, - "head": { - "position": [1.8, -0.4, -2], - "rotation": [ - 0, - -115, - "math.cos(query.anim_time * 160.0) + 90 -this" - ] - }, - "tail": {"position": [0, 0, 1.5], "rotation": [-125, 0, 0]} - } - }, - "setup": {"loop": true, "bones": {"body": {"rotation": ["-this", 0, 0]}}}, - "sit": { - "loop": true, - "bones": { - "body": {"position": [0, 1, 0], "rotation": [-60, 0, 0]}, - "head": {"position": [0, 3, -3], "rotation": [60, 0, 0]}, - "leg0": {"position": [0, 4, 2.5], "rotation": [-15, 0, 0]}, - "leg1": {"position": [0, 4, 2.5], "rotation": [-15, 0, 0]}, - "leg2": {"position": [0, 0.75, 3.5], "rotation": [40, 0, 0]}, - "leg3": {"position": [0, 0.75, 3.5], "rotation": [40, 0, 0]}, - "tail": {"position": [0, -0.075, -0.15], "rotation": [60, 0, 0]} - } - }, - "wiggle": { - "loop": true, - "bones": { - "body": { - "position": [0, -1.8, 0], - "rotation": [ - 0, - "math.cos(query.life_time * 20.0 * 53.7) * 5.0 -this", - 0 - ] - }, - "head": { - "position": [0, -0.8, 0], - "rotation": [ - "math.clamp(-5.0 * (query.anim_time / 2.0), -5.0, 0)", - 0, - "math.clamp(25.0 * (query.anim_time / 2.0), 0, 25.0)" - ] - }, - "leg0": {"position": [0, 1.6, 0], "rotation": [0, 0, 0]}, - "leg1": {"position": [0, 1.6, 0], "rotation": [0, 0, 0]}, - "leg2": {"position": [0, 1.6, 0], "rotation": [0, 0, 0]}, - "leg3": {"position": [0, 1.6, 0], "rotation": [0, 0, 0]}, - "tail": { - "rotation": [ - 0, - "math.cos(query.life_time * 20.0 * 53.7) * 10.0 -this", - 0 - ] - } - } - }, - "stuck": { - "loop": true, - "bones": {"body": {"position": [0, -0.3, 0], "rotation": [60, 0, 0]}} - }, - "pounce": { - "loop": true, - "bones": { - "body": { - "position": [0, 0, 0], - "rotation": ["query.vertical_speed * -7.0", 0, 0] - }, - "head": { - "position": [0, 0, 0], - "rotation": ["query.vertical_speed * -7.0", 0, 0] - } - } - } - }, - "scripts": { - "animate": ["setup", {"baby_transform": "query.is_baby"}, "move"] - }, - "render_controllers": ["controller.render.fox"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 55}, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": { - "crouch": { - "animations": [ - "look_at_target", - "crouch", - {"walk": "query.modified_move_speed"} - ], - "blend_transition": 0.4, - "transitions": [ - {"default": "!query.is_stalking && !query.is_interested"}, - {"wiggle": "query.is_interested"} - ] - }, - "default": { - "animations": [ - "look_at_target", - {"walk": "query.modified_move_speed"} - ], - "blend_transition": 0.1, - "transitions": [ - {"crouch": "query.is_stalking"}, - {"sleep": "query.is_sleeping"}, - {"stuck": "query.is_stunned"}, - {"sit": "query.is_sitting"} - ] - }, - "pounce": { - "animations": [ - "look_at_target", - "pounce", - {"walk": "query.modified_move_speed"} - ], - "transitions": [{"default": "query.is_on_ground"}] - }, - "sit": { - "animations": ["sit"], - "blend_transition": 0.2, - "transitions": [{"default": "!query.is_sitting"}] - }, - "sleep": { - "animations": ["sleep"], - "blend_transition": 0.2, - "transitions": [{"default": "!query.is_sleeping"}] - }, - "stuck": { - "animations": [ - "stuck", - {"walk": "math.cos(query.life_time * 20.0 * 53.7)"} - ], - "blend_transition": 0.2, - "transitions": [{"default": "!query.is_stunned"}] - }, - "wiggle": { - "animations": [ - "look_at_target", - "wiggle", - {"walk": "query.modified_move_speed"} - ], - "blend_transition": 0.2, - "transitions": [ - { - "default": "query.is_on_ground && !query.is_interested && !query.is_stalking" - }, - { - "crouch": "query.is_on_ground && !query.is_interested && query.is_stalking" - }, - {"pounce": "!query.is_on_ground"} - ] - } - } - } - } - }, - "ghast": { - "identifier": "minecraft:ghast", - "materials": {"default": "ghast"}, - "textures": { - "default": "textures/entity/ghast/ghast", - "shooting": "textures/entity/ghast/ghast_shooting" - }, - "geometry": { - "default": { - "visible_bounds_width": 6, - "visible_bounds_height": 9, - "visible_bounds_offset": [0, 4.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "tentacles_0", - "parent": "body", - "pivot": [-3.8, 1, -5], - "cubes": [ - {"origin": [-4.8, -8, -6], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "tentacles_1", - "parent": "body", - "pivot": [1.3, 1, -5], - "cubes": [ - {"origin": [0.3, -10, -6], "size": [2, 11, 2], "uv": [0, 0]} - ] - }, - { - "name": "tentacles_2", - "parent": "body", - "pivot": [6.3, 1, -5], - "cubes": [ - {"origin": [5.3, -7, -6], "size": [2, 8, 2], "uv": [0, 0]} - ] - }, - { - "name": "tentacles_3", - "parent": "body", - "pivot": [-6.3, 1, 0], - "cubes": [ - {"origin": [-7.3, -8, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "tentacles_4", - "parent": "body", - "pivot": [-1.3, 1, 0], - "cubes": [ - {"origin": [-2.3, -12, -1], "size": [2, 13, 2], "uv": [0, 0]} - ] - }, - { - "name": "tentacles_5", - "parent": "body", - "pivot": [3.8, 1, 0], - "cubes": [ - {"origin": [2.8, -10, -1], "size": [2, 11, 2], "uv": [0, 0]} - ] - }, - { - "name": "tentacles_6", - "parent": "body", - "pivot": [-3.8, 1, 5], - "cubes": [ - {"origin": [-4.8, -11, 4], "size": [2, 12, 2], "uv": [0, 0]} - ] - }, - { - "name": "tentacles_7", - "parent": "body", - "pivot": [1.3, 1, 5], - "cubes": [ - {"origin": [0.3, -11, 4], "size": [2, 12, 2], "uv": [0, 0]} - ] - }, - { - "name": "tentacles_8", - "parent": "body", - "pivot": [6.3, 1, 5], - "cubes": [ - {"origin": [5.3, -12, 4], "size": [2, 13, 2], "uv": [0, 0]} - ] - }, - { - "name": "body", - "pivot": [0, 1.5, 0], - "cubes": [ - {"origin": [-8, 0, -8], "size": [16, 16, 16], "uv": [0, 0]} - ] - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 19}, - "animations": { - "move": { - "loop": true, - "bones": { - "tentacles_0": { - "rotation": [ - "math.sin(query.life_time * 360.0 + 0) * 11.5 + 23", - 0, - 0 - ] - }, - "tentacles_1": { - "rotation": [ - "math.sin(query.life_time * 360.0 + 57) * 11.5 + 23", - 0, - 0 - ] - }, - "tentacles_2": { - "rotation": [ - "math.sin(query.life_time * 360.0 + 115) * 11.5 + 23", - 0, - 0 - ] - }, - "tentacles_3": { - "rotation": [ - "math.sin(query.life_time * 360.0 + 172) * 11.5 + 23", - 0, - 0 - ] - }, - "tentacles_4": { - "rotation": [ - "math.sin(query.life_time * 360.0 + 229) * 11.5 + 23", - 0, - 0 - ] - }, - "tentacles_5": { - "rotation": [ - "math.sin(query.life_time * 360.0 + 286) * 11.5 + 23", - 0, - 0 - ] - }, - "tentacles_6": { - "rotation": [ - "math.sin(query.life_time * 360.0 + 344) * 11.5 + 23", - 0, - 0 - ] - }, - "tentacles_7": { - "rotation": [ - "math.sin(query.life_time * 360.0 + 402) * 11.5 + 23", - 0, - 0 - ] - }, - "tentacles_8": { - "rotation": [ - "math.sin(query.life_time * 360.0 + 458) * 11.5 + 23", - 0, - 0 - ] - } - } - }, - "scale": {"loop": true, "bones": {"body": {"scale": 4.5}}} - }, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - }, - "scale": { - "initial_state": "default", - "states": {"default": {"animations": ["scale"]}} - } - }, - "render_controllers": ["controller.render.ghast"] - }, - "guardian": { - "identifier": "minecraft:guardian", - "min_engine_version": "1.8.0", - "materials": {"default": "guardian", "ghost": "guardian_ghost"}, - "textures": { - "default": "textures/entity/guardian", - "elder": "textures/entity/guardian_elder", - "beam": "textures/entity/guardian_beam" - }, - "geometry": { - "default": { - "visible_bounds_width": 3.5, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "head", - "pivot": [0, 0, 0], - "mirror": true, - "cubes": [ - { - "mirror": false, - "origin": [-6, 2, -8], - "size": [12, 12, 16], - "uv": [0, 0] - }, - { - "mirror": false, - "origin": [-8, 2, -6], - "size": [2, 12, 12], - "uv": [0, 28] - }, - {"origin": [6, 2, -6], "size": [2, 12, 12], "uv": [0, 28]}, - {"origin": [-6, 14, -6], "size": [12, 2, 12], "uv": [16, 40]}, - {"origin": [-6, 0, -6], "size": [12, 2, 12], "uv": [16, 40]} - ] - }, - { - "name": "eye", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-1, 6, 0], "size": [2, 2, 1], "uv": [8, 0]}] - }, - { - "name": "tailpart0", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-2, 6, 7], "size": [4, 4, 8], "uv": [40, 0]}] - }, - { - "name": "tailpart1", - "parent": "tailpart0", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 7, 0], "size": [3, 3, 7], "uv": [0, 54]}] - }, - { - "name": "tailpart2", - "parent": "tailpart1", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [0, 8, 0], "size": [2, 2, 6], "uv": [41, 32]}, - {"origin": [1, 4.5, 3], "size": [1, 9, 9], "uv": [25, 19]} - ] - }, - { - "name": "spikepart0", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart1", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart2", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart3", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart4", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart5", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart6", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart7", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart8", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart9", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart10", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart11", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - } - ] - }, - "ghost": { - "visible_bounds_width": 3.5, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "head", - "pivot": [0, 24, 0], - "mirror": true, - "cubes": [ - { - "mirror": false, - "origin": [-6, 2, -8], - "size": [12, 12, 16], - "uv": [0, 0] - }, - { - "mirror": false, - "origin": [-8, 2, -6], - "size": [2, 12, 12], - "uv": [0, 28] - }, - {"origin": [6, 2, -6], "size": [2, 12, 12], "uv": [0, 28]}, - {"origin": [-6, 14, -6], "size": [12, 2, 12], "uv": [16, 40]}, - {"origin": [-6, 0, -6], "size": [12, 2, 12], "uv": [16, 40]} - ] - }, - { - "name": "eye", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-1, 7, 0], "size": [2, 2, 1], "uv": [8, 0]}] - }, - { - "name": "tailpart0", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-2, 6, 7], "size": [4, 4, 8], "uv": [40, 0]}] - }, - { - "name": "tailpart1", - "parent": "tailpart0", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 7, 0], "size": [3, 3, 7], "uv": [0, 54]}] - }, - { - "name": "tailpart2", - "parent": "tailpart1", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [0, 8, 0], "size": [2, 2, 6], "uv": [41, 32]}, - {"origin": [1, 4.5, 3], "size": [1, 9, 9], "uv": [25, 19]} - ] - }, - { - "name": "spikepart0", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart1", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart2", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart3", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart4", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart5", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart6", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart7", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart8", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart9", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart10", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - }, - { - "name": "spikepart11", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} - ] - } - ] - } - }, - "animations": { - "setup": { - "loop": true, - "bones": { - "spikepart0": { - "rotation": ["-45.0 - this", "0.0 - this", "0.0 - this"] - }, - "spikepart1": { - "rotation": ["45.0 - this", "0.0 - this", "0.0 - this"] - }, - "spikepart10": { - "rotation": ["0.0 - this", "0.0 - this", " 135.0 - this"] - }, - "spikepart11": { - "rotation": ["0.0 - this", "0.0 - this", " -135.0 - this"] - }, - "spikepart2": { - "rotation": ["0.0 - this", "0.0 - this", "45.0 - this"] - }, - "spikepart3": { - "rotation": ["0.0 - this", "0.0 - this", "-45.0 - this"] - }, - "spikepart4": { - "rotation": ["90.0 - this", "45.0 - this", " 0.0 - this"] - }, - "spikepart5": { - "rotation": ["90.0 - this", "-45.0 - this", " 0.0 - this"] - }, - "spikepart6": { - "rotation": ["90.0 - this", "-135.0 - this", "0.0 - this"] - }, - "spikepart7": { - "rotation": ["90.0 - this", "135.0 - this", " 0.0 - this"] - }, - "spikepart8": { - "rotation": ["-135.0 - this", "0.0 - this", " 0.0 - this"] - }, - "spikepart9": { - "rotation": ["135.0 - this", "0.0 - this", " 0.0 - this"] - } - } - }, - "spikes": { - "loop": true, - "bones": { - "spikepart0": { - "position": [ - "-this", - "24 + -8 * (1 + math.cos(query.life_time * 20 * 1.5) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "8 * (1 + math.cos(query.life_time * 20 * 1.5) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this" - ] - }, - "spikepart1": { - "position": [ - "-this", - "24 + -8 * (1 + math.cos(query.life_time * 20 * 1.5 + 1) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 1) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this" - ] - }, - "spikepart10": { - "position": [ - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 10) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this", - "-8 + 8 * (1 + math.cos(query.life_time * 20 * 1.5 + 10) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "-this" - ] - }, - "spikepart11": { - "position": [ - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 11) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this", - "-8 + 8 * (1 + math.cos(query.life_time * 20 * 1.5 + 11) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "-this" - ] - }, - "spikepart2": { - "position": [ - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 2) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this", - "24 + -8 * (1 + math.cos(query.life_time * 20 * 1.5 + 2) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "-this" - ] - }, - "spikepart3": { - "position": [ - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 3) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this", - "24 + -8 * (1 + math.cos(query.life_time * 20 * 1.5 + 3) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - 0 - ] - }, - "spikepart4": { - "position": [ - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 4) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this", - "8 - this", - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 4) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this" - ] - }, - "spikepart5": { - "position": [ - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 5) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this", - "8 - this", - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 5) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this" - ] - }, - "spikepart6": { - "position": [ - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 6) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this", - "8 - this", - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 6) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this" - ] - }, - "spikepart7": { - "position": [ - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 7) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this", - "8 - this", - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 7) * 0.01 - (variable.spike_extension - variable.spike_shake)) - this" - ] - }, - "spikepart8": { - "position": [ - "-this", - "-8 + 8 * (1 + math.cos(query.life_time * 20 * 1.5 + 8) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "8 * (1 + math.cos(query.life_time * 20 * 1.5 + 8) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this" - ] - }, - "spikepart9": { - "position": [ - "-this", - "-8 + 8 * (1 + math.cos(query.life_time * 20 * 1.5 + 9) * 0.01 + (variable.spike_extension + variable.spike_shake)) - this", - "-8 * (1 + math.cos(query.life_time * 20 * 1.5 + 9) * 0.01 - (variable.spike_extension + variable.spike_shake)) - this" - ] - } - } - }, - "swim": { - "loop": true, - "bones": { - "tailpart0": { - "rotation": [0, "variable.tail_base_angle * 11.6 - this", 0] - }, - "tailpart1": { - "position": ["-1.5 - this", "-0.5 - this", "14.0 - this"], - "rotation": [0, "variable.tail_base_angle * 22.8 - this", 0] - }, - "tailpart2": { - "position": ["0.5 - this", "-0.5 - this", "6.0 - this"], - "rotation": [0, "variable.tail_base_angle * 34.4 - this", 0] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "move_eye": { - "loop": true, - "bones": { - "eye": { - "position": [ - "query.eye_target_x_rotation - this", - "24 + query.eye_target_y_rotation - this", - "-8.25 - this" - ] - } - } - } - }, - "scripts": { - "pre_animation": [ - "variable.spike_shake = Math.sin(query.life_time * 2000)/50;", - "variable.spike_animation_speed = query.life_time < 0.1 ? 0.0 : (!query.is_in_water ? (Math.round(Math.sin(query.life_time * 2000)) == 0.0 ? (Math.random(0.0, 1.0)) : (variable.spike_animation_speed)) : (query.is_moving ? (variable.spike_animation_speed - variable.spike_animation_speed * 0.06) : (variable.spike_animation_speed + (1.0 - variable.spike_animation_speed) * 0.06)));", - "variable.spike_extension = (1.0 - variable.spike_animation_speed) * 0.55;", - "variable.tail_animation_speed = query.life_time < 0.1 ? 0.0 : (!query.is_in_water ? 2.0 : query.is_moving ? (variable.tail_animation_speed < 0.5 ? 4.0 : variable.tail_animation_speed + (0.5 - variable.tail_animation_speed) * 0.1) : variable.tail_animation_speed + (0.125 - variable.tail_animation_speed) * 0.2);", - "variable.tail_swim = query.life_time < 0.1 ? 0.0 : (variable.tail_swim + variable.tail_animation_speed);", - "variable.tail_base_angle = Math.sin(variable.tail_swim*20.0);" - ], - "animate": ["setup", "spikes", "swim", "look_at_target", "move_eye"] - }, - "render_controllers": ["controller.render.guardian"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 26} - }, - "hoglin": { - "identifier": "minecraft:hoglin", - "materials": {"default": "hoglin"}, - "textures": {"default": "textures/entity/hoglin/hoglin"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 19, -3], - "cubes": [ - { - "origin": [-8, 11, -7], - "size": [16, 14, 26], - "inflate": 0.02, - "uv": [1, 1] - }, - { - "origin": [0, 22, -10], - "size": [0, 10, 19], - "inflate": 0.02, - "uv": [90, 33] - } - ], - "locators": {"lead": [0, 20, -5]} - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 22, -5], - "rotation": [50, 0, 0], - "cubes": [ - {"origin": [-7, 21, -24], "size": [14, 6, 19], "uv": [61, 1]}, - {"origin": [-8, 22, -19], "size": [2, 11, 2], "uv": [1, 13]}, - {"origin": [6, 22, -19], "size": [2, 11, 2], "uv": [1, 13]} - ] - }, - { - "name": "right_ear", - "parent": "head", - "pivot": [-7, 27, -7], - "rotation": [0, 0, -50], - "cubes": [ - {"origin": [-13, 26, -10], "size": [6, 1, 4], "uv": [1, 1]} - ] - }, - { - "name": "left_ear", - "parent": "head", - "pivot": [7, 27, -7], - "rotation": [0, 0, 50], - "cubes": [{"origin": [7, 26, -10], "size": [6, 1, 4], "uv": [1, 6]}] - }, - { - "name": "leg_back_right", - "pivot": [6, 8, 17], - "cubes": [ - {"origin": [-8, 0, 13], "size": [5, 11, 5], "uv": [21, 45]} - ] - }, - { - "name": "leg_back_left", - "pivot": [-6, 8, 17], - "cubes": [{"origin": [3, 0, 13], "size": [5, 11, 5], "uv": [0, 45]}] - }, - { - "name": "leg_front_right", - "pivot": [-6, 12, -3], - "cubes": [ - {"origin": [-8, 0, -6], "size": [6, 14, 6], "uv": [66, 42]} - ] - }, - { - "name": "leg_front_left", - "pivot": [6, 12, -3], - "cubes": [ - {"origin": [2, 0, -6], "size": [6, 14, 6], "uv": [41, 42]} - ] - } - ], - "visible_bounds_width": 4, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1.5, 0], - "texturewidth": 128, - "textureheight": 64 - } - }, - "spawn_egg": {"base_color": "#C66E55", "overlay_color": "#5f6464"}, - "scripts": { - "pre_animation": [ - "variable.tcos_right_side = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;", - "variable.tcos_left_side = -variable.tcos_right_side;", - "variable.attack_head_rot = Math.sin(variable.attack_time * 180.0) * -37.3;" - ] - }, - "animations": { - "walk": { - "loop": true, - "bones": { - "left_ear": {"rotation": [0, 0, "variable.tcos_left_side * 0.5"]}, - "right_ear": {"rotation": [0, 0, "variable.tcos_right_side * 0.5"]}, - "leg_back_right": {"rotation": ["variable.tcos_right_side", 0, 0]}, - "leg_back_left": {"rotation": ["variable.tcos_left_side", 0, 0]}, - "leg_front_right": {"rotation": ["-variable.tcos_right_side", 0, 0]}, - "leg_front_left": {"rotation": ["-variable.tcos_left_side", 0, 0]} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [0, "query.target_y_rotation - this", 0] - } - } - }, - "attack": { - "loop": true, - "bones": {"head": {"rotation": ["variable.attack_head_rot", 0, 0]}} - }, - "hoglin_baby_scaling": { - "loop": true, - "bones": {"head": {"position": [0, 10, 4], "scale": 1.4}} - } - }, - "animation_controllers": { - "look_at_target": { - "initial_state": "default", - "states": {"default": {"animations": ["look_at_target"]}} - }, - "walk": { - "initial_state": "walking", - "states": {"walking": {"animations": ["walk"]}} - }, - "attack": { - "initial_state": "default", - "states": { - "attack": { - "animations": ["attack"], - "transitions": [ - {"default": "!variable.has_target || variable.attack_time < 0.0"} - ] - }, - "default": { - "transitions": [ - {"attack": "variable.has_target && variable.attack_time >= 0.0"} - ] - } - } - }, - "hoglin_baby_scaling": { - "initial_state": "default", - "states": { - "baby": { - "animations": ["hoglin_baby_scaling"], - "transitions": [{"default": "!query.is_baby"}] - }, - "default": {"transitions": [{"baby": "query.is_baby"}]} - } - } - }, - "render_controllers": ["controller.render.hoglin"] - }, - "hopper_minecart": { - "identifier": "minecraft:hopper_minecart", - "min_engine_version": "1.8.0", - "materials": {"default": "minecart"}, - "textures": {"default": "textures/entity/minecart"}, - "geometry": { - "default": { - "bones": [ - { - "name": "bottom", - "pivot": [0, 6, 0], - "cubes": [ - { - "origin": [-10, -6.5, -1], - "size": [20, 16, 2], - "rotation": [90, 0, 0], - "uv": [0, 10] - } - ] - }, - { - "name": "back", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-17, 2.5, -1], - "size": [16, 8, 2], - "rotation": [0, 270, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "front", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [1, 2.5, -1], - "size": [16, 8, 2], - "rotation": [0, 90, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "right", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, 2.5, -8], - "size": [16, 8, 2], - "rotation": [0, 180, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "left", - "pivot": [0, 0, 0], - "cubes": [ - {"origin": [-8, 2.5, 6], "size": [16, 8, 2], "uv": [0, 0]} - ], - "parent": "bottom" - } - ], - "texturewidth": 64, - "textureheight": 32 - } - }, - "scripts": { - "pre_animation": ["variable.hurt = query.hurt_time - query.frame_alpha;"], - "animate": ["move"] - }, - "animations": { - "move": { - "loop": true, - "bones": { - "bottom": { - "position": [ - "variable.rail_offset.x / query.model_scale", - "variable.rail_offset.y / query.model_scale", - "variable.rail_offset.z / query.model_scale" - ], - "rotation": [ - "variable.hurt > 0 ? -Math.sin(variable.hurt * 360 / (Math.pi * 2)) * variable.hurt * (((20 * 2 - query.structural_integrity) - query.frame_alpha) < 0 ? 0: (20 * 2 - query.structural_integrity) - query.frame_alpha) / 10 * query.hurt_direction : 0", - 0, - "-variable.rail_rotation.z" - ] - } - } - } - }, - "render_controllers": ["controller.render.minecart"] - }, - "horse": { - "identifier": "minecraft:horse", - "textures": { - "base_brown": "textures/entity/horse/horse_brown", - "base_white": "textures/entity/horse/horse_white", - "base_chestnut": "textures/entity/horse/horse_chestnut", - "base_creamy": "textures/entity/horse/horse_creamy", - "base_black": "textures/entity/horse/horse_black", - "base_gray": "textures/entity/horse/horse_gray", - "base_darkbrown": "textures/entity/horse/horse_darkbrown", - "markings_none": "textures/entity/horse/horse_markings_none", - "markings_white": "textures/entity/horse/horse_markings_white", - "markings_whitefield": "textures/entity/horse/horse_markings_whitefield", - "markings_whitedots": "textures/entity/horse/horse_markings_whitedots", - "markings_blackdots": "textures/entity/horse/horse_markings_blackdots", - "mule": "textures/entity/horse/mule", - "donkey": "textures/entity/horse/donkey", - "skeleton": "textures/entity/horse/horse_skeleton", - "zombie": "textures/entity/horse/horse_zombie", - "armor_none": "textures/entity/horse/armor/horse_armor_none", - "armor_leather": "textures/entity/horse/armor/horse_armor_leather", - "armor_iron": "textures/entity/horse/armor/horse_armor_iron", - "armor_gold": "textures/entity/horse/armor/horse_armor_gold", - "armor_diamond": "textures/entity/horse/armor/horse_armor_diamond" - }, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 128, - "textureheight": 128, - "bones": [ - { - "name": "Body", - "pivot": [0, 13, 9], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 11, -10], "size": [10, 10, 24], "uv": [0, 34]} - ] - }, - { - "name": "TailA", - "pivot": [0, 21, 14], - "rotation": [-65, 0, 0], - "cubes": [ - {"origin": [-1, 20, 14], "size": [2, 2, 3], "uv": [44, 0]} - ] - }, - { - "name": "TailB", - "pivot": [0, 21, 14], - "rotation": [-65, 0, 0], - "cubes": [ - {"origin": [-1.5, 19, 17], "size": [3, 4, 7], "uv": [38, 7]} - ] - }, - { - "name": "TailC", - "pivot": [0, 21, 14], - "rotation": [-80.34, 0, 0], - "cubes": [ - {"origin": [-1.5, 21.5, 23], "size": [3, 4, 7], "uv": [24, 3]} - ] - }, - { - "name": "Leg1A", - "pivot": [4, 15, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.5, 8, 8.5], "size": [4, 9, 5], "uv": [78, 29]} - ] - }, - { - "name": "Leg1B", - "pivot": [4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2, 3, 9.5], "size": [3, 5, 3], "uv": [78, 43]} - ] - }, - { - "name": "Leg1C", - "pivot": [4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.5, -0.1, 9], "size": [4, 3, 4], "uv": [78, 51]} - ] - }, - { - "name": "Leg2A", - "pivot": [-4, 15, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 8, 8.5], "size": [4, 9, 5], "uv": [96, 29]} - ] - }, - { - "name": "Leg2B", - "pivot": [-4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 3, 9.5], "size": [3, 5, 3], "uv": [96, 43]} - ] - }, - { - "name": "Leg2C", - "pivot": [-4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, -0.1, 9], "size": [4, 3, 4], "uv": [96, 51]} - ] - }, - { - "name": "Leg3A", - "pivot": [4, 15, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.1, 8, -10.1], "size": [3, 8, 4], "uv": [44, 29]} - ] - }, - { - "name": "Leg3B", - "pivot": [4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.1, 3, -9.6], "size": [3, 5, 3], "uv": [44, 41]} - ] - }, - { - "name": "Leg3C", - "pivot": [4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.6, -0.1, -10.1], "size": [4, 3, 4], "uv": [44, 51]} - ] - }, - { - "name": "Leg4A", - "pivot": [-4, 15, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.1, 8, -10.1], "size": [3, 8, 4], "uv": [60, 29]} - ] - }, - { - "name": "Leg4B", - "pivot": [-4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.1, 3, -9.6], "size": [3, 5, 3], "uv": [60, 41]} - ] - }, - { - "name": "Leg4C", - "pivot": [-4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.6, -0.1, -10.1], "size": [4, 3, 4], "uv": [60, 51]} - ] - }, - { - "name": "Head", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.5, 25, -11.5], "size": [5, 5, 7], "uv": [0, 0]} - ] - }, - { - "name": "UMouth", - "pivot": [0, 20.05, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2, 27.05, -17], "size": [4, 3, 6], "uv": [24, 18]} - ] - }, - { - "name": "LMouth", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2, 25, -16.5], "size": [4, 2, 5], "uv": [24, 27]} - ] - }, - { - "name": "Ear1", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [0.45, 29, -6], "size": [2, 3, 1], "uv": [0, 0]} - ] - }, - { - "name": "Ear2", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.45, 29, -6], "size": [2, 3, 1], "uv": [0, 0]} - ] - }, - { - "name": "MuleEarL", - "pivot": [0, 20, -10], - "rotation": [30, 0, 15], - "cubes": [ - {"origin": [-2, 29, -6], "size": [2, 7, 1], "uv": [0, 12]} - ] - }, - { - "name": "MuleEarR", - "pivot": [0, 20, -10], - "rotation": [30, 0, -15], - "cubes": [{"origin": [0, 29, -6], "size": [2, 7, 1], "uv": [0, 12]}] - }, - { - "name": "Neck", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.05, 15.8, -12], "size": [4, 14, 8], "uv": [0, 12]} - ] - }, - { - "name": "Bag1", - "pivot": [-7.5, 21, 10], - "rotation": [0, 90, 0], - "cubes": [ - {"origin": [-10.5, 13, 10], "size": [8, 8, 3], "uv": [0, 34]} - ] - }, - { - "name": "Bag2", - "pivot": [4.5, 21, 10], - "rotation": [0, 90, 0], - "cubes": [ - {"origin": [1.5, 13, 10], "size": [8, 8, 3], "uv": [0, 47]} - ] - }, - { - "name": "Saddle", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 21, -1], "size": [10, 1, 8], "uv": [80, 0]} - ] - }, - { - "name": "SaddleB", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-1.5, 22, -1], "size": [3, 1, 2], "uv": [106, 9]} - ] - }, - { - "name": "SaddleC", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [{"origin": [-4, 22, 5], "size": [8, 1, 2], "uv": [80, 9]}] - }, - { - "name": "SaddleL2", - "pivot": [5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [4.5, 13, 1], "size": [1, 2, 2], "uv": [74, 0]} - ] - }, - { - "name": "SaddleL", - "pivot": [5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [4.5, 15, 1.5], "size": [1, 6, 1], "uv": [70, 0]} - ] - }, - { - "name": "SaddleR2", - "pivot": [-5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 13, 1], "size": [1, 2, 2], "uv": [74, 4]} - ] - }, - { - "name": "SaddleR", - "pivot": [-5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 15, 1.5], "size": [1, 6, 1], "uv": [80, 0]} - ] - }, - { - "name": "SaddleMouthL", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [1.5, 26, -14], "size": [1, 2, 2], "uv": [74, 13]} - ] - }, - { - "name": "SaddleMouthR", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.5, 26, -14], "size": [1, 2, 2], "uv": [74, 13]} - ] - }, - { - "name": "SaddleMouthLine", - "pivot": [0, 20, -10], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.6, 23, -16], "size": [0, 3, 16], "uv": [44, 10]} - ] - }, - { - "name": "SaddleMouthLineR", - "pivot": [0, 20, -10], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-2.6, 23, -16], "size": [0, 3, 16], "uv": [44, 5]} - ] - }, - { - "name": "Mane", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-1, 15.5, -5], "size": [2, 16, 4], "uv": [58, 0]} - ] - }, - { - "name": "HeadSaddle", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - { - "origin": [-2.5, 25.1, -17], - "size": [5, 5, 12], - "uv": [80, 12], - "inflate": 0.05 - } - ] - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 23} - }, - "husk": { - "identifier": "minecraft:husk", - "min_engine_version": "1.8.0", - "materials": {"default": "husk"}, - "textures": {"default": "textures/entity/zombie/husk"}, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 2.5, - "visible_bounds_offset": [0, 1.25, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} - ], - "parent": "waist" - }, - {"name": "waist", "neverRender": true, "pivot": [0, 12, 0]}, - { - "name": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]} - ], - "parent": "body" - }, - { - "name": "hat", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 8, 8], - "uv": [32, 0], - "inflate": 0.5 - } - ], - "neverRender": true, - "parent": "head" - }, - { - "name": "rightArm", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} - ], - "parent": "body" - }, - { - "name": "rightItem", - "pivot": [-6, 15, 1], - "neverRender": true, - "parent": "rightArm" - }, - { - "name": "leftArm", - "pivot": [5, 22, 0], - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} - ], - "mirror": true, - "parent": "body" - }, - { - "name": "rightLeg", - "pivot": [-1.9, 12, 0], - "cubes": [ - {"origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} - ], - "parent": "body" - }, - { - "name": "leftLeg", - "pivot": [1.9, 12, 0], - "cubes": [ - {"origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} - ], - "mirror": true, - "parent": "body" - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;" - ] - }, - "animations": { - "humanoid_big_head": {"loop": true, "bones": {"head": {"scale": 1.4}}}, - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "move": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - }, - "holding": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - } - } - }, - "brandish_spear": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "this * -0.5 - 157.5 - 22.5 * variable.charge_amount", - "-this", - 0 - ] - } - } - }, - "charging": { - "loop": true, - "bones": { - "rightarm": { - "rotation": ["22.5 * variable.charge_amount - this", "-this", 0] - } - } - }, - "attack.rotations": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46 - this", - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.sin(1.0 - math.pow(1.0 - variable.attack_time, 3.0) * 180.0) * (variable.is_brandishing_spear ? -1.0 : 1.0 )", - "variable.is_brandishing_spear ? 0.0 : (math.sin(math.sqrt(variable.attack_time) * 360) * 11.46) * 2.0", - 0 - ] - } - } - }, - "sneaking": { - "loop": true, - "bones": { - "body": {"rotation": ["0.5 - this", 0, 0]}, - "head": {"position": [0, 1, 0]}, - "leftarm": {"rotation": [72, 0, 0]}, - "leftleg": {"position": [0, -3, 4]}, - "rightarm": {"rotation": [72, 0, 0]}, - "rightleg": {"position": [0, -3, 4]} - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "damage_nearby_mobs": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["-45.0-this", "-this", "-this"]}, - "leftleg": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightarm": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-45.0-this", "-this", "-this"]} - } - }, - "bow_and_arrow": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "query.target_x_rotation - 90.0 - math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation + 28.65", - "-(math.cos(query.life_time * 103.2) * 2.865) - 2.865" - ] - }, - "rightarm": { - "rotation": [ - "query.target_x_rotation - 90.0 + math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation - 5.73", - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "use_item_progress": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "variable.use_item_startup_progress * -60.0 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -22.5 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -5.625 + variable.use_item_interval_progress * 11.25" - ] - } - } - }, - "zombie_attack_bare_hand": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "-90.0 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) - (math.sin(query.life_time * 76.776372) * 2.865) - this", - "5.73 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 0.6) - this", - "math.cos(query.life_time * 103.13244) * -2.865 - 2.865 - this" - ] - }, - "rightarm": { - "rotation": [ - "90.0 * (variable.is_brandishing_spear - 1.0) - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) + (math.sin(query.life_time * 76.776372) * 2.865) - this", - "(math.sin(variable.attack_time * 180.0) * 57.3) * 0.6 - 5.73 - this", - "math.cos(query.life_time * 103.13244) * 2.865 + 2.865 - this" - ] - } - } - }, - "swimming": { - "loop": true, - "bones": { - "body": { - "position": [ - 0, - "variable.swim_amount * -10.0 - this", - "variable.swim_amount * 9.0 - this" - ], - "rotation": [ - "variable.swim_amount * (90.0 + query.target_x_rotation)", - 0, - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) - (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, 14.325, variable.swim_amount) - (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "leftleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0 + 180.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) + (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, -14.325, variable.swim_amount) + (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "rightleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - } - } - } - }, - "animation_controllers": { - "humanoid_baby_big_head": { - "initial_state": "default", - "states": { - "baby": { - "animations": ["humanoid_big_head"], - "transitions": [{"default": "!query.is_baby"}] - }, - "default": {"transitions": [{"baby": "query.is_baby"}]} - } - }, - "look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - }, - "riding": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"riding": "query.is_riding"}]}, - "riding": { - "animations": ["riding.arms", "riding.legs"], - "transitions": [{"default": "!query.is_riding"}] - } - } - }, - "holding": { - "initial_state": "default", - "states": {"default": {"animations": ["holding"]}} - }, - "brandish_spear": { - "initial_state": "default", - "states": { - "brandish_spear": { - "animations": ["brandish_spear"], - "transitions": [{"default": "!variable.is_brandishing_spear"}] - }, - "default": { - "transitions": [{"brandish_spear": "variable.is_brandishing_spear"}] - } - } - }, - "charging": { - "initial_state": "default", - "states": { - "charging": { - "animations": ["charging"], - "transitions": [{"default": "!query.is_charging"}] - }, - "default": {"transitions": [{"charging": "query.is_charging"}]} - } - }, - "attack": { - "initial_state": "default", - "states": { - "attacking": { - "animations": ["attack.rotations"], - "transitions": [{"default": "variable.attack_time < 0.0"}] - }, - "default": { - "transitions": [{"attacking": "variable.attack_time >= 0.0"}] - } - } - }, - "sneaking": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"sneaking": "query.is_sneaking"}]}, - "sneaking": { - "animations": ["sneaking"], - "transitions": [{"default": "!query.is_sneaking"}] - } - } - }, - "bob": { - "initial_state": "default", - "states": {"default": {"animations": ["bob"]}} - }, - "damage_nearby_mobs": { - "initial_state": "default", - "states": { - "damage_nearby_mobs": { - "animations": ["damage_nearby_mobs"], - "transitions": [{"default": "!variable.damage_nearby_mobs"}] - }, - "default": { - "transitions": [ - {"damage_nearby_mobs": "variable.damage_nearby_mobs"} - ] - } - } - }, - "bow_and_arrow": { - "initial_state": "default", - "states": { - "bow_and_arrow": { - "animations": ["bow_and_arrow"], - "transitions": [{"default": "!query.has_target"}] - }, - "default": {"transitions": [{"bow_and_arrow": "query.has_target"}]} - } - }, - "use_item_progress": { - "initial_state": "default", - "states": { - "default": { - "transitions": [ - { - "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 )" - } - ] - }, - "use_item_progress": { - "animations": ["use_item_progress"], - "transitions": [ - { - "default": "( variable.use_item_interval_progress <= 0.0 ) && ( variable.use_item_startup_progress <= 0.0 )" - } - ] - } - } - }, - "zombie_attack_bare_hand": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"is_bare_hand": "variable.is_holding_left != 1.0"}] - }, - "is_bare_hand": { - "animations": ["zombie_attack_bare_hand"], - "transitions": [{"default": "variable.is_holding_left == 1.0"}] - } - } - }, - "swimming": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"is_swimming": "variable.swim_amount > 0.0"}] - }, - "is_swimming": { - "animations": ["swimming"], - "transitions": [{"default": "variable.swim_amount <= 0.0"}] - } - } - } - }, - "render_controllers": ["controller.render.husk"], - "enable_attachables": true, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 28} - }, - "iron_golem": { - "identifier": "minecraft:iron_golem", - "materials": {"default": "iron_golem"}, - "textures": {"default": "textures/entity/iron_golem/iron_golem"}, - "geometry": { - "default": { - "visible_bounds_width": 3, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1.5, 0], - "texturewidth": 128, - "textureheight": 128, - "bones": [ - { - "name": "body", - "pivot": [0, 31, 0], - "cubes": [ - {"origin": [-9, 21, -6], "size": [18, 12, 11], "uv": [0, 40]}, - { - "origin": [-4.5, 16, -3], - "size": [9, 5, 6], - "uv": [0, 70], - "inflate": 0.5 - } - ] - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 31, -2], - "locators": {"lead": [0, 31, -2]}, - "cubes": [ - {"origin": [-4, 33, -7.5], "size": [8, 10, 8], "uv": [0, 0]}, - {"origin": [-1, 32, -9.5], "size": [2, 4, 2], "uv": [24, 0]} - ] - }, - { - "name": "arm0", - "parent": "body", - "pivot": [0, 31, 0], - "cubes": [ - {"origin": [-13, 3.5, -3], "size": [4, 30, 6], "uv": [60, 21]} - ] - }, - { - "name": "arm1", - "parent": "body", - "pivot": [0, 31, 0], - "cubes": [ - {"origin": [9, 3.5, -3], "size": [4, 30, 6], "uv": [60, 58]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-4, 13, 0], - "cubes": [ - {"origin": [-7.5, 0, -3], "size": [6, 16, 5], "uv": [37, 0]} - ] - }, - { - "name": "leg1", - "parent": "body", - "mirror": true, - "pivot": [5, 13, 0], - "cubes": [ - {"origin": [1.5, 0, -3], "size": [6, 16, 5], "uv": [60, 0]} - ] - } - ] - } - }, - "animations": { - "walk": { - "loop": true, - "bones": { - "body": {"rotation": [0, 0, "variable.modified_tcos0 / 1.5"]}, - "head": {"rotation": [0, 0, "variable.modified_tcos0 / 1.5"]}, - "leg0": {"rotation": ["variable.modified_tcos0 * 6.0", 0, 0]}, - "leg1": {"rotation": ["-variable.modified_tcos0 * 6.0", 0, 0]} - } - }, - "move": { - "loop": true, - "bones": { - "arm0": {"rotation": ["-variable.modified_tcos0 * 2.0", 0, 0]}, - "arm1": {"rotation": ["variable.modified_tcos0 * 2.0", 0, 0]} - } - }, - "walk_to_target": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - 0, - "2.0 * (math.abs(math.mod(query.modified_distance_moved + 6, 13.0) - 6.5) - 3.25)" - ] - }, - "head": { - "rotation": [ - 0, - 0, - "2.0 * (math.abs(math.mod(query.modified_distance_moved + 6, 13.0) - 6.5) - 3.25)" - ] - }, - "leg0": { - "rotation": [ - "(math.cos(query.modified_distance_moved * 38.17) * 40.0)", - 0, - 0 - ] - }, - "leg1": { - "rotation": [ - "(math.cos(query.modified_distance_moved * 38.17 + 180) * 40.0)", - 0, - 0 - ] - } - } - }, - "move_to_target": { - "loop": true, - "bones": { - "arm0": { - "rotation": [ - "((math.abs(math.mod(query.modified_distance_moved, 13) - 6.5) - 3.25) / 2.25) * 30.0", - 0, - 0 - ] - }, - "arm1": { - "rotation": [ - "((math.abs(math.mod(query.modified_distance_moved, 13) - 6.5) - 3.25) / 2.25) * -30.0", - 0, - 0 - ] - } - } - }, - "attack": { - "loop": true, - "bones": { - "arm0": { - "rotation": [ - "-114 + ((1.5 * math.abs(math.mod(variable.attack_animation_tick - query.frame_alpha, 10) - 5) - 2.5) / 5) * 57.3", - 0, - 0 - ] - }, - "arm1": { - "rotation": [ - "-114 + ((1.5 * math.abs(math.mod(variable.attack_animation_tick - query.frame_alpha, 10) - 5) - 2.5) / 5) * 57.3", - 0, - 0 - ] - } - } - }, - "flower": { - "loop": true, - "bones": { - "arm0": { - "rotation": [ - "-45.8 + ((0.25 * math.abs(math.mod(variable.offer_flower_tick, 70) - 35) - 17.5) / 35)", - 0, - 0 - ] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - } - }, - "scripts": { - "pre_animation": [ - "variable.modified_tcos0 = Math.clamp(((Math.cos(query.modified_distance_moved * 13.5) * Math.min(query.modified_move_speed, 0.6) / variable.gliding_speed_value) * 25.0), -12.5, 12.5);" - ], - "animate": ["look_at_target", "move_controller", "arm_controller"] - }, - "render_controllers": ["controller.render.iron_golem"], - "animation_controllers": { - "move_controller": { - "initial_state": "default", - "states": { - "default": { - "animations": [{"walk": "query.modified_move_speed"}], - "transitions": [{"has_target": "query.has_target"}] - }, - "has_target": { - "animations": [{"walk_to_target": "query.modified_move_speed"}], - "transitions": [{"default": "!query.has_target"}] - } - } - }, - "arm_controller": { - "initial_state": "default", - "states": { - "attack": { - "animations": ["attack"], - "transitions": [ - { - "default": "!query.has_target && variable.attack_animation_tick <= 0.0" - }, - { - "has_target": "query.has_target && variable.attack_animation_tick <= 0.0" - } - ] - }, - "default": { - "animations": ["move"], - "transitions": [ - {"attack": "variable.attack_animation_tick > 0.0"}, - {"flower": "variable.offer_flower_tick"}, - {"has_target": "query.has_target"} - ] - }, - "flower": { - "animations": ["flower"], - "transitions": [ - {"attack": "variable.attack_animation_tick > 0.0"}, - {"default": "variable.offer_flower_tick <= 0.0"}, - {"has_target": "query.has_target"} - ] - }, - "has_target": { - "animations": ["move_to_target"], - "transitions": [ - {"attack": "variable.attack_animation_tick > 0.0"}, - {"default": "!query.has_target"}, - {"flower": "variable.offer_flower_tick"} - ] - } - } - } - } - }, - "leash_knot": { - "identifier": "minecraft:leash_knot", - "materials": {"default": "leash_knot"}, - "textures": {"default": "textures/entity/lead_knot"}, - "geometry": { - "default": { - "bones": [ - { - "name": "knot", - "cubes": [{"origin": [-3, 2, -3], "size": [6, 8, 6]}] - } - ], - "texturewidth": 32, - "textureheight": 32 - } - }, - "render_controllers": ["controller.render.leash_knot"] - }, - "llama": { - "identifier": "minecraft:llama", - "min_engine_version": "1.8.0", - "materials": {"default": "llama"}, - "textures": { - "creamy": "textures/entity/llama/creamy", - "white": "textures/entity/llama/white", - "brown": "textures/entity/llama/brown", - "gray": "textures/entity/llama/gray", - "decor_none": "textures/entity/llama/decor/decor_none", - "decor_white": "textures/entity/llama/decor/white", - "decor_orange": "textures/entity/llama/decor/orange", - "decor_magenta": "textures/entity/llama/decor/magenta", - "decor_light_blue": "textures/entity/llama/decor/light_blue", - "decor_yellow": "textures/entity/llama/decor/yellow", - "decor_lime": "textures/entity/llama/decor/lime", - "decor_pink": "textures/entity/llama/decor/pink", - "decor_gray": "textures/entity/llama/decor/gray", - "decor_silver": "textures/entity/llama/decor/light_gray", - "decor_cyan": "textures/entity/llama/decor/cyan", - "decor_purple": "textures/entity/llama/decor/purple", - "decor_blue": "textures/entity/llama/decor/blue", - "decor_brown": "textures/entity/llama/decor/brown", - "decor_green": "textures/entity/llama/decor/green", - "decor_red": "textures/entity/llama/decor/red", - "decor_black": "textures/entity/llama/decor/black", - "decor_wandering_trader": "textures/entity/llama/decor/trader_llama" - }, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 2.5, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 128, - "textureheight": 64, - "bones": [ - { - "name": "head", - "parent": "body", - "pivot": [0, 17, -6], - "locators": {"lead": [0, 18, -11]}, - "cubes": [ - {"origin": [-2, 27, -16], "size": [4, 4, 9], "uv": [0, 0]}, - {"origin": [-4, 15, -12], "size": [8, 18, 6], "uv": [0, 14]}, - {"origin": [-4, 33, -10], "size": [3, 3, 2], "uv": [17, 0]}, - {"origin": [1, 33, -10], "size": [3, 3, 2], "uv": [17, 0]} - ] - }, - { - "name": "chest1", - "parent": "body", - "pivot": [-8.5, 21, 3], - "rotation": [0, 90, 0], - "cubes": [ - {"origin": [-11.5, 13, 3], "size": [8, 8, 3], "uv": [45, 28]} - ] - }, - { - "name": "chest2", - "parent": "body", - "pivot": [5.5, 21, 3], - "rotation": [0, 90, 0], - "cubes": [ - {"origin": [2.5, 13, 3], "size": [8, 8, 3], "uv": [45, 41]} - ] - }, - { - "name": "body", - "pivot": [0, 19, 2], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-6, 11, -5], "size": [12, 18, 10], "uv": [29, 0]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-3.5, 14, 6], - "cubes": [ - {"origin": [-5.5, 0, 4], "size": [4, 14, 4], "uv": [29, 29]} - ] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [3.5, 14, 6], - "cubes": [ - {"origin": [1.5, 0, 4], "size": [4, 14, 4], "uv": [29, 29]} - ] - }, - { - "name": "leg2", - "parent": "body", - "pivot": [-3.5, 14, -5], - "cubes": [ - {"origin": [-5.5, 0, -7], "size": [4, 14, 4], "uv": [29, 29]} - ] - }, - { - "name": "leg3", - "parent": "body", - "pivot": [3.5, 14, -5], - "cubes": [ - {"origin": [1.5, 0, -7], "size": [4, 14, 4], "uv": [29, 29]} - ] - } - ] - } - }, - "animations": { - "setup": {"loop": true, "bones": {"body": {"rotation": ["-this", 0, 0]}}}, - "walk": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - }, - "leg1": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg2": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg3": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "baby_transform": { - "loop": true, - "bones": { - "body": {"position": [0, -5.5, -5], "scale": [1.2, 1, 1]}, - "head": {"position": [0, 2, 0], "scale": [1.3, 1.2, 1.2]}, - "leg0": {"position": [0, -1, 0], "scale": [0.91, 0.56, 0.91]}, - "leg1": {"position": [0, -1, 0], "scale": [0.91, 0.56, 0.91]}, - "leg2": {"position": [0, -1, 0], "scale": [0.91, 0.56, 0.91]}, - "leg3": {"position": [0, -1, 0], "scale": [0.91, 0.56, 0.91]} - } - } - }, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": { - "default": { - "animations": [ - "setup", - {"walk": "query.modified_move_speed"}, - "look_at_target" - ] - } - } - }, - "baby": { - "initial_state": "baby", - "states": { - "baby": {"animations": [{"baby_transform": "query.is_baby"}]} - } - } - }, - "render_controllers": ["controller.render.llama"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 38} - }, - "llama_spit": { - "identifier": "minecraft:llama_spit", - "materials": {"default": "llama_spit"}, - "textures": {"default": "textures/entity/llama/spit"}, - "geometry": { - "default": { - "visible_bounds_width": 1, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 22, 0], "size": [2, 2, 2], "uv": [0, 0]}, - {"origin": [0, 26, 0], "size": [2, 2, 2], "uv": [0, 0]}, - {"origin": [0, 22, -4], "size": [2, 2, 2], "uv": [0, 0]}, - {"origin": [0, 22, 0], "size": [2, 2, 2], "uv": [0, 0]}, - {"origin": [2, 22, 0], "size": [2, 2, 2], "uv": [0, 0]}, - {"origin": [0, 20, 0], "size": [2, 2, 2], "uv": [0, 0]}, - {"origin": [0, 22, 2], "size": [2, 2, 2], "uv": [0, 0]} - ] - } - ] - } - }, - "animations": { - "setup": { - "loop": true, - "bones": { - "body": { - "position": [0, -15, 0], - "rotation": [ - 0, - "query.target_y_rotation - 90.0 - this", - "query.target_x_rotation - this" - ] - } - } - } - }, - "scripts": {"animate": ["setup"]}, - "render_controllers": ["controller.render.llama_spit"] - }, - "magma_cube": { - "identifier": "minecraft:magma_cube", - "materials": {"default": "magma_cube"}, - "textures": {"default": "textures/entity/slime/magmacube"}, - "geometry": { - "default": { - "visible_bounds_width": 2.5, - "visible_bounds_height": 5, - "visible_bounds_offset": [0, 2.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "bodyCube_0", - "parent": "insideCube", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-4, 7, -4], "size": [8, 1, 8], "uv": [0, 0]}] - }, - { - "name": "bodyCube_1", - "parent": "insideCube", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-4, 6, -4], "size": [8, 1, 8], "uv": [0, 1]}] - }, - { - "name": "bodyCube_2", - "parent": "insideCube", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 5, -4], "size": [8, 1, 8], "uv": [24, 10]} - ] - }, - { - "name": "bodyCube_3", - "parent": "insideCube", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 4, -4], "size": [8, 1, 8], "uv": [24, 19]} - ] - }, - { - "name": "bodyCube_4", - "parent": "insideCube", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-4, 3, -4], "size": [8, 1, 8], "uv": [0, 4]}] - }, - { - "name": "bodyCube_5", - "parent": "insideCube", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-4, 2, -4], "size": [8, 1, 8], "uv": [0, 5]}] - }, - { - "name": "bodyCube_6", - "parent": "insideCube", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-4, 1, -4], "size": [8, 1, 8], "uv": [0, 6]}] - }, - { - "name": "bodyCube_7", - "parent": "insideCube", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-4, 0, -4], "size": [8, 1, 8], "uv": [0, 7]}] - }, - { - "name": "insideCube", - "pivot": [0, 0, 0], - "cubes": [{"origin": [-2, 2, -2], "size": [4, 4, 4], "uv": [0, 16]}] - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.slime_squish_factor = (query.previous_squish_value + (query.current_squish_value - query.previous_squish_value) * query.frame_alpha);", - "variable.bounce = 1 / ((variable.slime_squish_factor / (query.variant * 0.5 + 1)) + 1);", - "variable.horizontal_scale_amount = variable.bounce * query.variant;", - "variable.vertical_scale_amount = (1 / variable.bounce) * query.variant;" - ], - "scaleX": "variable.horizontal_scale_amount", - "scaleY": "variable.vertical_scale_amount", - "scaleZ": "variable.horizontal_scale_amount" - }, - "animations": { - "move": { - "loop": true, - "bones": { - "bodycube_0": { - "position": [ - 0, - "3.0 * (variable.slime_squish_factor < 0.0 ? 0.0 : variable.slime_squish_factor) * 1.7", - 0 - ] - }, - "bodycube_1": { - "position": [ - 0, - "2.0 * (variable.slime_squish_factor < 0.0 ? 0.0 : variable.slime_squish_factor) * 1.7", - 0 - ] - }, - "bodycube_2": { - "position": [ - 0, - "1.0 * (variable.slime_squish_factor < 0.0 ? 0.0 : variable.slime_squish_factor) * 1.7", - 0 - ] - }, - "bodycube_4": { - "position": [ - 0, - "-1.0 * (variable.slime_squish_factor < 0.0 ? 0.0 : variable.slime_squish_factor) * 1.7", - 0 - ] - }, - "bodycube_5": { - "position": [ - 0, - "-2.0 * (variable.slime_squish_factor < 0.0 ? 0.0 : variable.slime_squish_factor) * 1.7", - 0 - ] - }, - "bodycube_6": { - "position": [ - 0, - "-3.0 * (variable.slime_squish_factor < 0.0 ? 0.0 : variable.slime_squish_factor) * 1.7", - 0 - ] - }, - "bodycube_7": { - "position": [ - 0, - "-4.0 * (variable.slime_squish_factor < 0.0 ? 0.0 : variable.slime_squish_factor) * 1.7", - 0 - ] - } - } - } - }, - "animation_controllers": { - "general": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - } - }, - "render_controllers": ["controller.render.magma_cube"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 20} - }, - "minecart": { - "identifier": "minecraft:minecart", - "min_engine_version": "1.8.0", - "materials": {"default": "minecart"}, - "textures": {"default": "textures/entity/minecart"}, - "geometry": { - "default": { - "bones": [ - { - "name": "bottom", - "pivot": [0, 6, 0], - "cubes": [ - { - "origin": [-10, -6.5, -1], - "size": [20, 16, 2], - "rotation": [90, 0, 0], - "uv": [0, 10] - } - ] - }, - { - "name": "back", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-17, 2.5, -1], - "size": [16, 8, 2], - "rotation": [0, 270, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "front", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [1, 2.5, -1], - "size": [16, 8, 2], - "rotation": [0, 90, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "right", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, 2.5, -8], - "size": [16, 8, 2], - "rotation": [0, 180, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "left", - "pivot": [0, 0, 0], - "cubes": [ - {"origin": [-8, 2.5, 6], "size": [16, 8, 2], "uv": [0, 0]} - ], - "parent": "bottom" - } - ], - "texturewidth": 64, - "textureheight": 32 - } - }, - "scripts": { - "pre_animation": ["variable.hurt = query.hurt_time - query.frame_alpha;"], - "animate": ["move"] - }, - "animations": { - "move": { - "loop": true, - "bones": { - "bottom": { - "position": [ - "variable.rail_offset.x / query.model_scale", - "variable.rail_offset.y / query.model_scale", - "variable.rail_offset.z / query.model_scale" - ], - "rotation": [ - "variable.hurt > 0 ? -Math.sin(variable.hurt * 360 / (Math.pi * 2)) * variable.hurt * (((20 * 2 - query.structural_integrity) - query.frame_alpha) < 0 ? 0: (20 * 2 - query.structural_integrity) - query.frame_alpha) / 10 * query.hurt_direction : 0", - 0, - "-variable.rail_rotation.z" - ] - } - } - } - }, - "render_controllers": ["controller.render.minecart"] - }, - "mooshroom": { - "identifier": "minecraft:mooshroom", - "min_engine_version": "1.8.0", - "materials": {"default": "mooshroom"}, - "textures": { - "default": "textures/entity/cow/red_mooshroom", - "brown": "textures/entity/cow/brown_mooshroom" - }, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "body", - "pivot": [0, 19, 2], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-6, 11, -5], "size": [12, 18, 10], "uv": [18, 4]}, - {"origin": [-2, 11, -6], "size": [4, 6, 1], "uv": [52, 0]} - ] - }, - { - "name": "head", - "pivot": [0, 20, -8], - "locators": {"lead": [0, 20, -8]}, - "cubes": [ - {"origin": [-4, 16, -14], "size": [8, 8, 6], "uv": [0, 0]}, - {"origin": [-5, 22, -12], "size": [1, 3, 1], "uv": [22, 0]}, - {"origin": [4, 22, -12], "size": [1, 3, 1], "uv": [22, 0]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-4, 12, 7], - "cubes": [{"origin": [-6, 0, 5], "size": [4, 12, 4], "uv": [0, 16]}] - }, - { - "name": "leg1", - "parent": "body", - "mirror": true, - "pivot": [4, 12, 7], - "cubes": [{"origin": [2, 0, 5], "size": [4, 12, 4], "uv": [0, 16]}] - }, - { - "name": "leg2", - "parent": "body", - "pivot": [-4, 12, -6], - "cubes": [ - {"origin": [-6, 0, -7], "size": [4, 12, 4], "uv": [0, 16]} - ] - }, - { - "name": "leg3", - "parent": "body", - "mirror": true, - "pivot": [4, 12, -6], - "cubes": [{"origin": [2, 0, -7], "size": [4, 12, 4], "uv": [0, 16]}] - } - ] - } - }, - "animations": { - "setup": {"loop": true, "bones": {"body": {"rotation": ["-this", 0, 0]}}}, - "walk": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - }, - "leg1": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg2": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg3": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "baby_transform": { - "loop": true, - "bones": { - "head": { - "position": [ - 0, - "query.is_baby ? 4.0 : 0.0", - "query.is_baby ? 4.0 : 0.0" - ], - "scale": "query.is_baby ? 2.0 : 1.0" - } - } - } - }, - "animation_controllers": { - "setup": { - "initial_state": "default", - "states": {"default": {"animations": ["setup"]}} - }, - "move": { - "initial_state": "default", - "states": { - "default": { - "animations": [ - {"walk": "query.modified_move_speed"}, - "look_at_target" - ] - } - } - }, - "baby": { - "initial_state": "default", - "states": {"default": {"animations": ["baby_transform"]}} - } - }, - "render_controllers": ["controller.render.mooshroom"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 5} - }, - "mule": { - "identifier": "minecraft:mule", - "textures": { - "base_brown": "textures/entity/horse/horse_brown", - "base_white": "textures/entity/horse/horse_white", - "base_chestnut": "textures/entity/horse/horse_chestnut", - "base_creamy": "textures/entity/horse/horse_creamy", - "base_black": "textures/entity/horse/horse_black", - "base_gray": "textures/entity/horse/horse_gray", - "base_darkbrown": "textures/entity/horse/horse_darkbrown", - "markings_none": "textures/entity/horse/horse_markings_none", - "markings_white": "textures/entity/horse/horse_markings_white", - "markings_whitefield": "textures/entity/horse/horse_markings_whitefield", - "markings_whitedots": "textures/entity/horse/horse_markings_whitedots", - "markings_blackdots": "textures/entity/horse/horse_markings_blackdots", - "mule": "textures/entity/horse/mule", - "donkey": "textures/entity/horse/donkey", - "skeleton": "textures/entity/horse/horse_skeleton", - "zombie": "textures/entity/horse/horse_zombie", - "armor_none": "textures/entity/horse/armor/horse_armor_none", - "armor_leather": "textures/entity/horse/armor/horse_armor_leather", - "armor_iron": "textures/entity/horse/armor/horse_armor_iron", - "armor_gold": "textures/entity/horse/armor/horse_armor_gold", - "armor_diamond": "textures/entity/horse/armor/horse_armor_diamond" - }, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 128, - "textureheight": 128, - "bones": [ - { - "name": "Body", - "pivot": [0, 13, 9], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 11, -10], "size": [10, 10, 24], "uv": [0, 34]} - ] - }, - { - "name": "TailA", - "pivot": [0, 21, 14], - "rotation": [-65, 0, 0], - "cubes": [ - {"origin": [-1, 20, 14], "size": [2, 2, 3], "uv": [44, 0]} - ] - }, - { - "name": "TailB", - "pivot": [0, 21, 14], - "rotation": [-65, 0, 0], - "cubes": [ - {"origin": [-1.5, 19, 17], "size": [3, 4, 7], "uv": [38, 7]} - ] - }, - { - "name": "TailC", - "pivot": [0, 21, 14], - "rotation": [-80.34, 0, 0], - "cubes": [ - {"origin": [-1.5, 21.5, 23], "size": [3, 4, 7], "uv": [24, 3]} - ] - }, - { - "name": "Leg1A", - "pivot": [4, 15, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.5, 8, 8.5], "size": [4, 9, 5], "uv": [78, 29]} - ] - }, - { - "name": "Leg1B", - "pivot": [4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2, 3, 9.5], "size": [3, 5, 3], "uv": [78, 43]} - ] - }, - { - "name": "Leg1C", - "pivot": [4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.5, -0.1, 9], "size": [4, 3, 4], "uv": [78, 51]} - ] - }, - { - "name": "Leg2A", - "pivot": [-4, 15, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 8, 8.5], "size": [4, 9, 5], "uv": [96, 29]} - ] - }, - { - "name": "Leg2B", - "pivot": [-4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 3, 9.5], "size": [3, 5, 3], "uv": [96, 43]} - ] - }, - { - "name": "Leg2C", - "pivot": [-4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, -0.1, 9], "size": [4, 3, 4], "uv": [96, 51]} - ] - }, - { - "name": "Leg3A", - "pivot": [4, 15, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.1, 8, -10.1], "size": [3, 8, 4], "uv": [44, 29]} - ] - }, - { - "name": "Leg3B", - "pivot": [4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.1, 3, -9.6], "size": [3, 5, 3], "uv": [44, 41]} - ] - }, - { - "name": "Leg3C", - "pivot": [4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.6, -0.1, -10.1], "size": [4, 3, 4], "uv": [44, 51]} - ] - }, - { - "name": "Leg4A", - "pivot": [-4, 15, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.1, 8, -10.1], "size": [3, 8, 4], "uv": [60, 29]} - ] - }, - { - "name": "Leg4B", - "pivot": [-4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.1, 3, -9.6], "size": [3, 5, 3], "uv": [60, 41]} - ] - }, - { - "name": "Leg4C", - "pivot": [-4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.6, -0.1, -10.1], "size": [4, 3, 4], "uv": [60, 51]} - ] - }, - { - "name": "Head", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.5, 25, -11.5], "size": [5, 5, 7], "uv": [0, 0]} - ] - }, - { - "name": "UMouth", - "pivot": [0, 20.05, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2, 27.05, -17], "size": [4, 3, 6], "uv": [24, 18]} - ] - }, - { - "name": "LMouth", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2, 25, -16.5], "size": [4, 2, 5], "uv": [24, 27]} - ] - }, - { - "name": "Ear1", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [0.45, 29, -6], "size": [2, 3, 1], "uv": [0, 0]} - ] - }, - { - "name": "Ear2", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.45, 29, -6], "size": [2, 3, 1], "uv": [0, 0]} - ] - }, - { - "name": "MuleEarL", - "pivot": [0, 20, -10], - "rotation": [30, 0, 15], - "cubes": [ - {"origin": [-2, 29, -6], "size": [2, 7, 1], "uv": [0, 12]} - ] - }, - { - "name": "MuleEarR", - "pivot": [0, 20, -10], - "rotation": [30, 0, -15], - "cubes": [{"origin": [0, 29, -6], "size": [2, 7, 1], "uv": [0, 12]}] - }, - { - "name": "Neck", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.05, 15.8, -12], "size": [4, 14, 8], "uv": [0, 12]} - ] - }, - { - "name": "Bag1", - "pivot": [-7.5, 21, 10], - "rotation": [0, 90, 0], - "cubes": [ - {"origin": [-10.5, 13, 10], "size": [8, 8, 3], "uv": [0, 34]} - ] - }, - { - "name": "Bag2", - "pivot": [4.5, 21, 10], - "rotation": [0, 90, 0], - "cubes": [ - {"origin": [1.5, 13, 10], "size": [8, 8, 3], "uv": [0, 47]} - ] - }, - { - "name": "Saddle", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 21, -1], "size": [10, 1, 8], "uv": [80, 0]} - ] - }, - { - "name": "SaddleB", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-1.5, 22, -1], "size": [3, 1, 2], "uv": [106, 9]} - ] - }, - { - "name": "SaddleC", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [{"origin": [-4, 22, 5], "size": [8, 1, 2], "uv": [80, 9]}] - }, - { - "name": "SaddleL2", - "pivot": [5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [4.5, 13, 1], "size": [1, 2, 2], "uv": [74, 0]} - ] - }, - { - "name": "SaddleL", - "pivot": [5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [4.5, 15, 1.5], "size": [1, 6, 1], "uv": [70, 0]} - ] - }, - { - "name": "SaddleR2", - "pivot": [-5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 13, 1], "size": [1, 2, 2], "uv": [74, 4]} - ] - }, - { - "name": "SaddleR", - "pivot": [-5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 15, 1.5], "size": [1, 6, 1], "uv": [80, 0]} - ] - }, - { - "name": "SaddleMouthL", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [1.5, 26, -14], "size": [1, 2, 2], "uv": [74, 13]} - ] - }, - { - "name": "SaddleMouthR", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.5, 26, -14], "size": [1, 2, 2], "uv": [74, 13]} - ] - }, - { - "name": "SaddleMouthLine", - "pivot": [0, 20, -10], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.6, 23, -16], "size": [0, 3, 16], "uv": [44, 10]} - ] - }, - { - "name": "SaddleMouthLineR", - "pivot": [0, 20, -10], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-2.6, 23, -16], "size": [0, 3, 16], "uv": [44, 5]} - ] - }, - { - "name": "Mane", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-1, 15.5, -5], "size": [2, 16, 4], "uv": [58, 0]} - ] - }, - { - "name": "HeadSaddle", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - { - "origin": [-2.5, 25.1, -17], - "size": [5, 5, 12], - "uv": [80, 12], - "inflate": 0.05 - } - ] - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 31} - }, - "ocelot": { - "identifier": "minecraft:ocelot", - "min_engine_version": "1.8.0", - "materials": {"default": "ocelot"}, - "textures": { - "black": "textures/entity/cat/black", - "red": "textures/entity/cat/red", - "siamese": "textures/entity/cat/siamese", - "wild": "textures/entity/cat/ocelot" - }, - "geometry": { - "default": { - "visible_bounds_width": 2.5, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "pivot": [0, 9, -9], - "locators": {"lead": [0, 9, -9]}, - "cubes": [ - {"origin": [-2.5, 7, -12], "size": [5, 4, 5], "uv": [0, 0]}, - { - "origin": [-1.5, 7.01562, -13], - "size": [3, 2, 2], - "uv": [0, 24] - }, - {"origin": [-2, 11, -9], "size": [1, 1, 2], "uv": [0, 10]}, - {"origin": [1, 11, -9], "size": [1, 1, 2], "uv": [6, 10]} - ], - "name": "head", - "parent": "body" - }, - { - "pivot": [0, 7, 1], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-2, -1, -2], "size": [4, 16, 6], "uv": [20, 0]} - ], - "name": "body" - }, - { - "pivot": [0, 9, 8], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-0.5, 1, 8], "size": [1, 8, 1], "uv": [0, 15]} - ], - "name": "tail1", - "parent": "body" - }, - { - "pivot": [0, 9, 16], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-0.5, 1, 16], "size": [1, 8, 1], "uv": [4, 15]} - ], - "name": "tail2", - "parent": "tail1" - }, - { - "pivot": [1.1, 6, 7], - "cubes": [ - {"origin": [0.1, 0, 6], "size": [2, 6, 2], "uv": [8, 13]} - ], - "name": "backLegL", - "parent": "body" - }, - { - "pivot": [-1.1, 6, 7], - "cubes": [ - {"origin": [-2.1, 0, 6], "size": [2, 6, 2], "uv": [8, 13]} - ], - "name": "backLegR", - "parent": "body" - }, - { - "pivot": [1.2, 10, -4], - "cubes": [ - {"origin": [0.2, 0.2, -5], "size": [2, 10, 2], "uv": [40, 0]} - ], - "name": "frontLegL", - "parent": "body" - }, - { - "pivot": [-1.2, 10, -4], - "cubes": [ - {"origin": [-2.2, 0.2, -5], "size": [2, 10, 2], "uv": [40, 0]} - ], - "name": "frontLegR", - "parent": "body" - } - ] - } - }, - "animations": { - "sneak": { - "loop": true, - "bones": { - "backlegl": { - "position": [0, "1.0 - this", 0], - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17) * 57.3 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "backlegr": { - "position": [0, "1.0 - this", 0], - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 180.0) * 57.3 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "body": {"position": [0, -1, 0]}, - "frontlegl": { - "position": [0, "1.0 - this", 0], - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 180.0) * 57.3 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "frontlegr": { - "position": [0, "1.0 - this", 0], - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17) * 57.3 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "head": {"position": [0, -1, 0]}, - "tail1": {"position": [0, "1.0 - this", 0]}, - "tail2": { - "rotation": [ - "62.0 + math.cos(query.modified_distance_moved * 57.3) * 27.0 * query.modified_move_speed - this", - 0, - 0 - ] - } - } - }, - "walk": { - "loop": true, - "bones": { - "backlegl": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17) * 57.3 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "backlegr": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 180.0) * 57.3 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "frontlegl": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 180.0) * 57.3 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "frontlegr": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17) * 57.3 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "tail1": {"rotation": ["-51.57 - this", 0, 0]}, - "tail2": { - "rotation": [ - "62.0 + math.cos(query.modified_distance_moved * 57.3) * 45.0 * query.modified_move_speed - this", - 0, - 0 - ] - } - } - }, - "sprint": { - "loop": true, - "bones": { - "backlegl": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17) * 57.3 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "backlegr": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 17.19) * 57.3 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "frontlegl": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 197.19) * 57.3 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "frontlegr": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 180.0) * 57.3 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "tail1": {"rotation": ["-this", 0, 0]}, - "tail2": { - "rotation": [ - "62.0 + math.cos(query.modified_distance_moved * 57.3) * 18.0 * query.modified_move_speed - this", - 0, - 0 - ] - } - } - }, - "sit": { - "loop": true, - "bones": { - "backlegl": { - "position": [0, "-2.0 - this", "6.0 - this"], - "rotation": [-45, 0, 0] - }, - "backlegr": { - "position": [0, "-2.0 - this", "6.0 - this"], - "rotation": ["-45 - this", 0, 0] - }, - "body": {"rotation": ["-45 - this", 0, 0]}, - "frontlegl": { - "position": [0, "-1.5 - this", "-7.0 - this"], - "rotation": ["42.15 - this", 0, 0] - }, - "frontlegr": { - "position": [0, "-1.5 - this", "-7.0 - this"], - "rotation": ["42.15 - this", 0, 0] - }, - "head": {"position": [0, -2, 0]}, - "tail1": {"position": [0, 0, 0], "rotation": ["45 - this", 0, 0]}, - "tail2": {"position": [0, 0, 0], "rotation": ["45 - this", 0, 0]} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "baby_transform": {"loop": true, "bones": {"head": {"scale": 1.5}}} - }, - "animation_controllers": { - "move": { - "initial_state": "sitting", - "states": { - "sitting": { - "animations": ["sit"], - "transitions": [ - {"sneaking": "variable.state == 0"}, - {"sprinting": "variable.state == 1"}, - {"walking": "variable.state == 3"} - ] - }, - "sneaking": { - "animations": ["sneak"], - "transitions": [ - {"sprinting": "variable.state == 1"}, - {"sitting": "variable.state == 2"}, - {"walking": "variable.state == 3"} - ] - }, - "sprinting": { - "animations": ["sprint"], - "transitions": [ - {"sneaking": "variable.state == 0"}, - {"sitting": "variable.state == 2"}, - {"walking": "variable.state == 3"} - ] - }, - "walking": { - "animations": ["walk"], - "transitions": [ - {"sneaking": "variable.state == 0"}, - {"sprinting": "variable.state == 1"}, - {"sitting": "variable.state == 2"} - ] - } - } - }, - "baby": { - "initial_state": "baby", - "states": { - "baby": {"animations": [{"baby_transform": "query.is_baby"}]} - } - }, - "look_at_target": { - "initial_state": "default", - "states": {"default": {"animations": ["look_at_target"]}} - } - }, - "render_controllers": ["controller.render.ocelot"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 16} - }, - "panda": { - "identifier": "minecraft:panda", - "materials": {"default": "panda"}, - "textures": { - "default": "textures/entity/panda/panda", - "lazy": "textures/entity/panda/lazy_panda", - "worried": "textures/entity/panda/worried_panda", - "playful": "textures/entity/panda/playful_panda", - "brown": "textures/entity/panda/brown_panda", - "weak": "textures/entity/panda/weak_panda", - "aggressive": "textures/entity/panda/aggressive_panda" - }, - "geometry": { - "default": { - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "head", - "parent": "body", - "pivot": [0, 12.5, -17], - "locators": {"lead": [0, 14, -16]}, - "cubes": [ - {"origin": [-6.5, 7.5, -21], "size": [13, 10, 9], "uv": [0, 6]}, - {"origin": [-3.5, 7.5, -23], "size": [7, 5, 2], "uv": [45, 16]}, - {"origin": [-8.5, 16.5, -18], "size": [5, 4, 1], "uv": [52, 25]}, - {"origin": [3.5, 16.5, -18], "size": [5, 4, 1], "uv": [52, 25]} - ] - }, - { - "name": "body", - "pivot": [0, 14, 0], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-9.5, 1, -6.5], "size": [19, 26, 13], "uv": [0, 25]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-5.5, 9, 9], - "cubes": [ - {"origin": [-8.5, 0, 6], "size": [6, 9, 6], "uv": [40, 0]} - ] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [5.5, 9, 9], - "cubes": [{"origin": [2.5, 0, 6], "size": [6, 9, 6], "uv": [40, 0]}] - }, - { - "name": "leg2", - "parent": "body", - "pivot": [-5.5, 9, -9], - "cubes": [ - {"origin": [-8.5, 0, -12], "size": [6, 9, 6], "uv": [40, 0]} - ] - }, - { - "name": "leg3", - "parent": "body", - "pivot": [5.5, 9, -9], - "cubes": [ - {"origin": [2.5, 0, -12], "size": [6, 9, 6], "uv": [40, 0]} - ] - } - ] - } - }, - "animations": { - "unhappy": { - "loop": true, - "bones": { - "head": { - "rotation": [ - 0, - "(math.sin(query.life_time * 327.6) * 20) - this", - "(math.sin(query.life_time * 327.6) * 20) - this" - ] - }, - "leg2": { - "rotation": [ - "(math.sin(query.life_time * 343.8) * -43) - this", - 0, - 0 - ] - }, - "leg3": { - "rotation": [ - "(math.sin(query.life_time * 343.8) * 43) - this", - 0, - 0 - ] - } - } - }, - "sneezing": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "(query.sneeze_counter < 15) ? (-45 * (query.sneeze_counter / 14)) : (-45 + (9 * (query.sneeze_counter - 15)) - this)", - 0, - 0 - ] - } - } - }, - "walk": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - }, - "leg1": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg2": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg3": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "baby_transform": { - "loop": true, - "bones": { - "body": {"position": [0, 1.77, 0], "scale": [1.15, 1.15, 1]}, - "head": {"position": [0, -0.18, 0.15], "scale": 1.8} - } - }, - "sitting": { - "loop": true, - "bones": { - "body": { - "position": [0, "-2.15 -10 -this", 0], - "rotation": [ - "(query.is_scared * math.cos(query.life_time * 71.62) * 16.2) + (query.sit_amount * -90) - this", - 0, - 0 - ] - }, - "head": { - "rotation": [ - "query.is_eating ? (90.0 + 11.5 * math.sin(query.life_time * 750)) : (query.sit_amount * (100 - this)) - this", - 0, - 0 - ] - }, - "leg0": {"rotation": [0, 0, "32.7 - this"]}, - "leg1": {"rotation": [0, 0, "-32.7 - this"]}, - "leg2": { - "rotation": [ - "(query.is_eating ? (-23 - (16.5 * math.sin(query.life_time * 750))) : 0) - this", - 0, - -15 - ] - }, - "leg3": { - "rotation": [ - "(query.is_eating ? (-23 - (16.5 * math.sin(query.life_time * 750))) : 0) - this", - 0, - 15 - ] - } - } - }, - "rolling": { - "loop": true, - "bones": { - "body": {"rotation": ["(query.roll_counter / 32) * 360", 0, 0]}, - "head": { - "rotation": ["(this * -118) + query.roll_counter - this", 0, 0] - }, - "leg0": { - "rotation": [ - "math.sin(query.life_time * 60 * (query.is_baby ? 0.95 : 0.5) * 57.3) * 8.6 - this", - 0, - 0 - ] - }, - "leg1": { - "rotation": [ - "math.sin(query.life_time * 60 * (query.is_baby ? 0.95 : 0.5) * 57.3) * -8.6 - this", - 0, - 0 - ] - }, - "leg2": { - "rotation": [ - "math.sin(query.life_time * 60 * (query.is_baby ? 0.95 : 0.5) * 57.3) * -8.6 - this", - 0, - 0 - ] - }, - "leg3": { - "rotation": [ - "math.sin(query.life_time * 60 * (query.is_baby ? 0.95 : 0.5) * 57.3) * 8.6 - this", - 0, - 0 - ] - } - } - }, - "lying": { - "loop": true, - "bones": { - "body": { - "position": [ - 0, - "(query.is_baby ? -8.8 : -7.67) * query.lie_amount -10 - this", - 0 - ], - "rotation": ["query.lie_amount * -180 - this", 0, 0] - }, - "head": {"rotation": ["(query.lie_amount * 90) - this", 0, 0]}, - "leg0": { - "rotation": [ - "math.sin(query.life_time * 206.28) * -17.2 - this", - 0, - 0 - ] - }, - "leg1": { - "rotation": [ - "math.sin(query.life_time * 263.58) * 17.2 - this", - 0, - 0 - ] - }, - "leg2": { - "rotation": ["math.sin(query.life_time * 172) * 17.2 - this", 0, 0] - }, - "leg3": { - "rotation": [ - "math.sin(query.life_time * 229.2) * -17.2 - this", - 0, - 0 - ] - } - } - } - }, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": { - "default": { - "animations": [ - {"walk": "query.modified_move_speed"}, - "look_at_target" - ], - "transitions": [ - {"rolling": "query.roll_counter > 0"}, - {"sitting": "query.sit_amount > 0"}, - {"lying": "query.lie_amount > 0"} - ] - }, - "lying": { - "animations": ["lying"], - "transitions": [ - {"default": "query.lie_amount <= 0"}, - {"rolling": "query.roll_counter > 0"}, - {"sitting": "query.sit_amount > 0"} - ] - }, - "rolling": { - "animations": ["rolling"], - "transitions": [ - {"default": "query.roll_counter <= 0"}, - {"sitting": "query.sit_amount > 0"}, - {"lying": "query.lie_amount > 0"} - ] - }, - "sitting": { - "animations": ["sitting"], - "transitions": [ - {"default": "query.sit_amount <= 0"}, - {"rolling": "query.roll_counter > 0"}, - {"lying": "query.lie_amount > 0"} - ] - } - } - }, - "unhappy": { - "initial_state": "baby", - "states": { - "baby": {"animations": [{"unhappy": "query.unhappy_counter"}]} - } - }, - "sneezing": { - "initial_state": "baby", - "states": { - "baby": {"animations": [{"sneezing": "query.sneeze_counter"}]} - } - }, - "baby": { - "initial_state": "baby", - "states": { - "baby": {"animations": [{"baby_transform": "query.is_baby"}]} - } - } - }, - "render_controllers": ["controller.render.panda"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 54} - }, - "parrot": { - "identifier": "minecraft:parrot", - "materials": {"default": "parrot"}, - "textures": { - "blue": "textures/entity/parrot/parrot_blue", - "green": "textures/entity/parrot/parrot_green", - "red_blue": "textures/entity/parrot/parrot_red_blue", - "yellow_blue": "textures/entity/parrot/parrot_yellow_blue", - "grey": "textures/entity/parrot/parrot_grey" - }, - "geometry": { - "default": { - "visible_bounds_width": 1, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 32, - "textureheight": 32, - "bones": [ - { - "name": "head", - "parent": "body", - "pivot": [0, 8.3, -2.8], - "locators": {"lead": [0, 6, -4]}, - "cubes": [ - {"origin": [-1, 6.8, -3.8], "size": [2, 3, 2], "uv": [2, 2]} - ] - }, - { - "name": "head2", - "parent": "head", - "pivot": [0, 26, -1], - "cubes": [ - {"origin": [-1, 9.8, -5.8], "size": [2, 1, 4], "uv": [10, 0]} - ] - }, - { - "name": "beak1", - "parent": "head", - "pivot": [0, 24.5, -1.5], - "cubes": [ - {"origin": [-0.5, 7.8, -4.7], "size": [1, 2, 1], "uv": [11, 7]} - ] - }, - { - "name": "beak2", - "parent": "head", - "pivot": [0, 25.8, -2.5], - "cubes": [ - {"origin": [-0.5, 8.1, -5.7], "size": [1, 1.7, 1], "uv": [16, 7]} - ] - }, - { - "name": "body", - "pivot": [0, 7.5, -3], - "bind_pose_rotation": [28.287, 0, 0], - "cubes": [ - {"origin": [-1.5, 1.5, -4.5], "size": [3, 6, 3], "uv": [2, 8]} - ] - }, - { - "name": "tail", - "parent": "body", - "pivot": [0, 2.9, 1.2], - "cubes": [ - {"origin": [-1.5, -0.1, 0.2], "size": [3, 4, 1], "uv": [22, 1]} - ] - }, - { - "name": "wing0", - "parent": "body", - "pivot": [1.5, 7.1, -2.8], - "cubes": [ - {"origin": [1, 2.1, -4.3], "size": [1, 5, 3], "uv": [19, 8]} - ] - }, - { - "name": "wing1", - "parent": "body", - "pivot": [-1.5, 7.1, -2.8], - "cubes": [ - {"origin": [-2, 2.1, -4.3], "size": [1, 5, 3], "uv": [19, 8]} - ] - }, - { - "name": "feather", - "parent": "head", - "pivot": [0, 10.1, 0.2], - "bind_pose_rotation": [-12.685, 0, 0], - "cubes": [ - {"origin": [0, 9.1, -4.9], "size": [0, 5, 4], "uv": [2, 18]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [1.5, 1, -0.5], - "cubes": [ - {"origin": [0.5, -0.5, -1.5], "size": [1, 2, 1], "uv": [14, 18]} - ] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [-0.5, 1, -0.5], - "cubes": [ - {"origin": [-1.5, -0.5, -1.5], "size": [1, 2, 1], "uv": [14, 18]} - ] - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.state = query.is_dancing ? 3 : (query.is_sitting ? 2 : (!query.is_on_ground && !query.is_jumping && !query.is_riding ? 0 : 1));", - "variable.dance.x = Math.cos(query.life_time * 57.3 * 20.0);", - "variable.dance.y = -Math.sin(query.life_time * 57.3 * 20.0);", - "variable.wing_flap = ((math.sin(query.wing_flap_position * 57.3) + 1) * query.wing_flap_speed);" - ] - }, - "animations": { - "moving": { - "loop": true, - "bones": { - "body": {"position": [0, "variable.wing_flap * 0.3", 0]}, - "tail": { - "rotation": [ - "60.0 + math.cos(query.anim_time * 38.17) * 17.0 - this", - 0, - 0 - ] - }, - "wing0": {"rotation": [0, 0, "-5.0 - variable.wing_flap * 57.3"]}, - "wing1": {"rotation": [0, 0, "5.0 + variable.wing_flap * 57.3"]} - } - }, - "base": { - "loop": true, - "bones": { - "body": {"position": ["-this", 0, 0], "rotation": ["-this", 0, 0]}, - "feather": {"rotation": ["-this", 0, 0]}, - "head": {"position": ["-this", 0, 0], "rotation": [0, 0, "-this"]}, - "leg0": { - "position": [0, "-6.0-this", -0.5], - "rotation": ["-16.713-this", 0, "-this"] - }, - "leg1": { - "position": [0, "-6.0-this", -0.5], - "rotation": ["-16.713-this", 0, "-this"] - }, - "tail": {"position": ["-this", 0, 0]}, - "wing0": { - "position": ["1.5-this", 0, 0], - "rotation": ["-40.0-this", "-180.0-this", 0] - }, - "wing1": { - "position": ["-1.5-this", 0, 0], - "rotation": ["-40.0-this", "-180.0-this", 0] - } - } - }, - "dance": { - "loop": true, - "bones": { - "body": { - "position": ["variable.dance.x-this", "variable.dance.y", 0] - }, - "head": { - "rotation": ["-this", "-this", "variable.dance.y*23.0 - this"] - }, - "leg0": { - "position": ["-variable.dance.x", "-variable.dance.y", 0], - "rotation": [0, 0, "-20.0 - this"] - }, - "leg1": { - "position": ["-variable.dance.x", "-variable.dance.y", 0], - "rotation": [0, 0, "20.0 - this"] - }, - "tail": {"rotation": ["60.0 - this", 0, 0]}, - "wing0": {"rotation": [0, 0, "-5.0 - variable.wing_flap"]}, - "wing1": {"rotation": [0, 0, "5.0 + variable.wing_flap"]} - } - }, - "sitting": { - "loop": true, - "bones": { - "body": {"position": [0, -1.9, 0]}, - "leg0": {"rotation": [90, 0, 0]}, - "leg1": {"rotation": [90, 0, 0]}, - "tail": {"rotation": ["90.0 - this", 0, 0]}, - "wing0": {"rotation": [0, 0, "-5.0-this"]}, - "wing1": {"rotation": [0, 0, "5.0-this"]} - } - }, - "flying": { - "loop": true, - "bones": { - "leg0": { - "rotation": [ - "math.cos(query.anim_time * 38.17) * 80.0 * query.modified_move_speed", - 0, - 0 - ] - }, - "leg1": { - "rotation": [ - "math.cos(query.anim_time * 38.17) * -80.0 * query.modified_move_speed", - 0, - 0 - ] - } - } - }, - "standing": { - "loop": true, - "bones": { - "leg0": {"rotation": [20, 0, 0]}, - "leg1": {"rotation": [20, 0, 0]} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - } - }, - "animation_controllers": { - "setup": { - "initial_state": "default", - "states": {"default": {"animations": ["look_at_target", "base"]}} - }, - "move": { - "initial_state": "dancing", - "states": { - "dancing": { - "animations": ["dance"], - "transitions": [ - {"flying": "variable.state == 0"}, - {"standing": "variable.state == 1"}, - {"sitting": "variable.state == 2"} - ] - }, - "flying": { - "animations": ["moving", "flying"], - "transitions": [ - {"standing": "variable.state == 1"}, - {"sitting": "variable.state == 2"}, - {"dancing": "variable.state == 3"} - ] - }, - "sitting": { - "animations": ["sitting"], - "transitions": [ - {"flying": "variable.state == 0"}, - {"standing": "variable.state == 1"}, - {"dancing": "variable.state == 3"} - ] - }, - "standing": { - "animations": ["moving", "standing"], - "transitions": [ - {"flying": "variable.state == 0"}, - {"sitting": "variable.state == 2"}, - {"dancing": "variable.state == 3"} - ] - } - } - } - }, - "render_controllers": ["controller.render.parrot"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 43} - }, - "phantom": { - "identifier": "minecraft:phantom", - "materials": {"default": "phantom", "invisible": "phantom_invisible"}, - "textures": {"default": "textures/entity/phantom"}, - "geometry": { - "default": { - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "body", - "pivot": [0, 24, 0], - "bind_pose_rotation": [0, 0, 0], - "cubes": [{"origin": [-3, 23, -8], "size": [5, 3, 9], "uv": [0, 8]}] - }, - { - "name": "wing0", - "pivot": [2, 26, -8], - "bind_pose_rotation": [0, 0, 5.7], - "cubes": [ - {"origin": [2, 24, -8], "size": [6, 2, 9], "uv": [23, 12]} - ], - "parent": "body" - }, - { - "name": "wingtip0", - "pivot": [8, 26, -8], - "bind_pose_rotation": [0, 0, 5.7], - "locators": {"left_wing": [21, 26, 0]}, - "cubes": [ - {"origin": [8, 25, -8], "size": [13, 1, 9], "uv": [16, 24]} - ], - "parent": "wing0" - }, - { - "name": "wing1", - "pivot": [-3, 26, -8], - "bind_pose_rotation": [0, 0, -5.7], - "mirror": true, - "cubes": [ - {"origin": [-9, 24, -8], "size": [6, 2, 9], "uv": [23, 12]} - ], - "parent": "body" - }, - { - "name": "wingtip1", - "pivot": [-9, 24, -8], - "bind_pose_rotation": [0, 0, -5.7], - "locators": {"right_wing": [-22, 24, 0]}, - "mirror": true, - "cubes": [ - {"origin": [-22, 25, -8], "size": [13, 1, 9], "uv": [16, 24]} - ], - "parent": "wing1" - }, - { - "name": "head", - "pivot": [0, 23, -7], - "bind_pose_rotation": [11.5, 0, 0], - "cubes": [ - {"origin": [-4, 22, -12], "size": [7, 3, 5], "uv": [0, 0]} - ], - "parent": "body" - }, - { - "name": "tail", - "pivot": [0, 26, 1], - "bind_pose_rotation": [0, 0, 0], - "cubes": [ - {"origin": [-2, 24, 1], "size": [3, 2, 6], "uv": [3, 20]} - ], - "parent": "body" - }, - { - "name": "tailtip", - "pivot": [0, 25.5, 7], - "bind_pose_rotation": [0, 0, 0], - "cubes": [ - {"origin": [-1, 24.5, 7], "size": [1, 1, 6], "uv": [4, 29]} - ], - "parent": "tail" - } - ] - } - }, - "scripts": { - "initialize": [ - "variable.runtimeid = 0;", - "variable.tailrotx = -5.0;", - "variable.wingrotz = 0.0;" - ], - "animate": ["phantom_base_pose_controller", "move"] - }, - "animations": { - "phantom_base_pose": { - "loop": true, - "bones": { - "body": { - "position": [0, -20, 0], - "rotation": ["-query.target_x_rotation", 0, 0] - } - } - }, - "move": { - "loop": true, - "start_delay": "math.random(0, 2.417)", - "animation_length": 2.417, - "bones": { - "tail": { - "rotation": [ - "-5.0 * Math.cos(297.9380535 * query.anim_time) - 5.0", - 0, - 0 - ] - }, - "tailtip": { - "rotation": [ - "-5.0 * Math.cos(297.9380535 * query.anim_time) - 5.0", - 0, - 0 - ] - }, - "wing0": { - "rotation": [0, 0, "16.0 * Math.cos(148.9690267 * query.anim_time)"] - }, - "wing1": { - "rotation": [ - 0, - 0, - "-16.0 * Math.cos(148.9690267 * query.anim_time)" - ] - }, - "wingtip0": { - "rotation": [0, 0, "16.0 * Math.cos(148.9690267 * query.anim_time)"] - }, - "wingtip1": { - "rotation": [ - 0, - 0, - "-16.0 * Math.cos(148.9690267 * query.anim_time)" - ] - } - }, - "sound_effects": {"1.4": {"effect": "flap"}} - } - }, - "particle_effects": {"wing_dust": "minecraft:phantom_trail_particle"}, - "sound_effects": {"flap": "mob.phantom.flap"}, - "render_controllers": ["controller.render.phantom"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 51}, - "animation_controllers": { - "phantom_base_pose_controller": { - "initial_state": "default", - "states": { - "default": { - "animations": ["phantom_base_pose"], - "particle_effects": [ - {"effect": "wing_dust", "locator": "left_wing"}, - {"effect": "wing_dust", "locator": "right_wing"} - ] - } - } - } - } - }, - "pig": { - "identifier": "minecraft:pig", - "min_engine_version": "1.8.0", - "materials": {"default": "pig"}, - "textures": { - "default": "textures/entity/pig/pig", - "saddled": "textures/entity/pig/pig_saddle" - }, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 1.5, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "body", - "pivot": [0, 13, 2], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-5, 7, -5], "size": [10, 16, 8], "uv": [28, 8]} - ] - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 12, -6], - "locators": {"lead": [0, 14, -6]}, - "cubes": [ - {"origin": [-4, 8, -14], "size": [8, 8, 8], "uv": [0, 0]}, - {"origin": [-2, 9, -15], "size": [4, 3, 1], "uv": [16, 16]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-3, 6, 7], - "cubes": [{"origin": [-5, 0, 5], "size": [4, 6, 4], "uv": [0, 16]}] - }, - { - "name": "leg1", - "parent": "body", - "mirror": true, - "pivot": [3, 6, 7], - "cubes": [{"origin": [1, 0, 5], "size": [4, 6, 4], "uv": [0, 16]}] - }, - { - "name": "leg2", - "parent": "body", - "pivot": [-3, 6, -5], - "cubes": [{"origin": [-5, 0, -7], "size": [4, 6, 4], "uv": [0, 16]}] - }, - { - "name": "leg3", - "parent": "body", - "mirror": true, - "pivot": [3, 6, -5], - "cubes": [{"origin": [1, 0, -7], "size": [4, 6, 4], "uv": [0, 16]}] - } - ] - } - }, - "animations": { - "setup": {"loop": true, "bones": {"body": {"rotation": ["-this", 0, 0]}}}, - "walk": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - }, - "leg1": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg2": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg3": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "baby_transform": { - "loop": true, - "bones": {"head": {"position": [0, 4, 4], "scale": 2}} - } - }, - "scripts": { - "animate": [ - "setup", - {"walk": "query.modified_move_speed"}, - "look_at_target", - {"baby_transform": "query.is_baby"} - ] - }, - "render_controllers": ["controller.render.pig"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 2} - }, - "piglin": { - "identifier": "minecraft:piglin", - "materials": {"default": "piglin"}, - "textures": {"default": "textures/entity/piglin/piglin"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]}, - { - "origin": [-4, 12, -2], - "size": [8, 12, 4], - "uv": [16, 32], - "inflate": 0.25 - } - ] - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-5, 24, -4], - "size": [10, 8, 8], - "uv": [0, 0], - "inflate": -0.02 - }, - {"origin": [-2, 24, -5], "size": [4, 4, 1], "uv": [31, 1]}, - {"origin": [2, 24, -5], "size": [1, 2, 1], "uv": [2, 4]}, - {"origin": [-3, 24, -5], "size": [1, 2, 1], "uv": [2, 0]} - ], - "inflate": -0.02 - }, - { - "name": "leftear", - "parent": "head", - "pivot": [5, 30, 0], - "rotation": [0, 0, -30], - "cubes": [{"origin": [4, 25, -2], "size": [1, 5, 4], "uv": [51, 6]}] - }, - { - "name": "rightear", - "parent": "head", - "pivot": [-5, 30, 0], - "rotation": [0, 0, 30], - "cubes": [ - {"origin": [-5, 25, -2], "size": [1, 5, 4], "uv": [39, 6]} - ] - }, - {"name": "hat", "parent": "head", "pivot": [0, 24, 0]}, - { - "name": "rightarm", - "parent": "body", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]}, - { - "origin": [-8, 12, -2], - "size": [4, 12, 4], - "uv": [40, 32], - "inflate": 0.25 - } - ] - }, - {"name": "rightItem", "parent": "rightarm", "pivot": [-6, 15, 1]}, - { - "name": "leftarm", - "parent": "body", - "pivot": [5, 22, 0], - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [32, 48]}, - { - "origin": [4, 12, -2], - "size": [4, 12, 4], - "uv": [48, 48], - "inflate": 0.25 - } - ] - }, - {"name": "leftItem", "parent": "leftArm", "pivot": [6, 15, 1]}, - { - "name": "rightleg", - "parent": "body", - "pivot": [-1.9, 12, 0], - "cubes": [ - {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 16]}, - { - "origin": [-4, 0, -2], - "size": [4, 12, 4], - "uv": [0, 32], - "inflate": 0.25 - } - ] - }, - { - "name": "leftleg", - "parent": "body", - "pivot": [1.9, 12, 0], - "cubes": [ - {"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [16, 48]}, - { - "origin": [0, 0, -2], - "size": [4, 12, 4], - "uv": [0, 48], - "inflate": 0.25 - } - ] - } - ], - "visible_bounds_width": 2, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 64, - "textureheight": 64 - } - }, - "spawn_egg": {"base_color": "#995f40", "overlay_color": "#f9f3a4"}, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;", - "variable.attack = Math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3;", - "variable.attack2 = Math.sin(variable.attack_time * 180.0) * 57.3;", - "variable.z_bob = Math.cos(query.life_time * 103.13244) * 2.865 + 2.865;", - "variable.x_bob = Math.sin(query.life_time * 76.776372) * 2.865;" - ], - "animate": [ - {"admire": "query.is_admiring"}, - {"humanoid_big_head": "query.is_baby"}, - {"celebrate_hunt": "query.is_celebrating"}, - {"celebrate_hunt_special": "query.is_celebrating_special"}, - "move", - "bob", - "look_at_target_controller", - "piglin_attack_controller", - "riding_controller" - ] - }, - "animations": { - "move": { - "loop": true, - "bones": { - "leftear": {"rotation": [0, 0, "variable.tcos0 * 0.5"]}, - "rightear": {"rotation": [0, 0, "-variable.tcos0 * 0.5"]}, - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["-variable.tcos0 * 1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "humanoid_big_head": {"loop": true, "bones": {"head": {"scale": 1.4}}}, - "admire": { - "loop": true, - "bones": { - "leftarm": {"rotation": [320, 25, 0]}, - "head": {"rotation": [30, 0, 0]} - } - }, - "celebrate_hunt": { - "loop": true, - "bones": { - "leftear": { - "rotation": [0, 0, "Math.sin(query.time_stamp * 30) * 10"] - }, - "rightear": { - "rotation": [0, 0, "Math.cos(query.time_stamp * 30) * 10"] - } - } - }, - "celebrate_hunt_special": { - "loop": true, - "bones": { - "leftear": { - "rotation": [0, 0, "Math.sin(query.time_stamp * 30) * 10"] - }, - "rightear": { - "rotation": [0, 0, "Math.cos(query.time_stamp * 30) * 10"] - }, - "head": { - "position": [ - "Math.sin(query.time_stamp * 10)", - "Math.sin(query.time_stamp * 40)", - 0 - ] - }, - "rightarm": { - "rotation": [0, 0, "70 + Math.cos(query.time_stamp * 40) * 10"] - }, - "leftarm": { - "rotation": [0, 0, "-70 - Math.cos(query.time_stamp * 40) * 10"] - }, - "body": {"position": [0, "Math.sin(query.time_stamp * 40) * 0.35", 0]} - } - }, - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "crossbow_hold": { - "bones": { - "leftarm": { - "rotation": [ - "-85.94 + query.target_x_rotation -this", - "34.38 + math.clamp(query.target_y_rotation, -45, 25) -this", - 0 - ] - }, - "rightarm": { - "rotation": [ - "-90.0 + 5.73 + query.target_x_rotation -this", - "-17.19 + math.clamp(query.target_y_rotation, -25, 45) -this", - 0 - ] - } - }, - "loop": true - }, - "crossbow_charge": { - "bones": { - "leftarm": { - "rotation": [ - "math.lerp(-90.0 + 34.38, -90.0, variable.crossbow_charge) -this", - "math.lerp(22.92, 48.70, variable.crossbow_charge) -this", - 0 - ] - }, - "rightarm": {"rotation": ["-90.0 + 34.38 -this", "-45.84 -this", 0]} - }, - "loop": true - }, - "melee_attack": { - "bones": { - "leftarm": { - "rotation": [ - "(math.cos(query.life_time * 20.0 * 10.89) * 28.65) + (math.sin(variable.attack_time * 180.0) * 68.76 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0)) * 22.92)", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "-100 + (variable.attack2 * 2.2 - variable.attack * 0.4) + variable.x_bob - this", - "variable.attack2 * 0.6 - 5.73 - this", - "variable.z_bob - this" - ] - } - }, - "loop": true - }, - "hand_attack": { - "bones": { - "leftarm": { - "rotation": [ - "-(math.sin((1 - math.pow((1 - variable.attack_time), 4)) * 180) * 1.2 + math.sin(variable.attack_time * 180)) * 10.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "-(math.sin((1 - math.pow((1 - variable.attack_time), 4)) * 180) * 1.2 + math.sin(variable.attack_time * 180)) * 30.0", - "-(math.sin((1 - math.pow((1 - variable.attack_time), 4)) * 180) ? (-90.0 * math.sin((1 - math.pow((1 - variable.attack_time), 4)) * 180)) + 30.0 : 0.0)", - 0 - ] - } - }, - "loop": true - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - } - }, - "render_controllers": ["controller.render.piglin"], - "enable_attachables": true, - "animation_controllers": { - "look_at_target_controller": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "piglin_attack_controller": { - "initial_state": "default", - "states": { - "ranged_charge": { - "animations": ["crossbow_charge"], - "transitions": [ - {"default": "variable.attack_state == 0 || query.is_admiring"}, - {"ranged_hold": "variable.attack_state == 1"} - ] - }, - "default": { - "transitions": [ - { - "ranged_hold": "query.variant == 0 && variable.attack_state == 1 && !query.is_admiring" - }, - { - "ranged_charge": "query.variant == 0 && variable.attack_state == 2 && !query.is_admiring" - }, - { - "hand_attack": "variable.has_target && query.variant == 1 && !query.is_item_equipped && variable.attack_time >= 0.0 && !query.is_admiring" - }, - { - "melee_attack": "variable.has_target && query.variant == 1 && query.is_item_equipped && variable.attack_time >= 0.0 && !query.is_admiring" - } - ] - }, - "ranged_hold": { - "animations": ["crossbow_hold"], - "transitions": [ - {"default": "variable.attack_state == 0 || query.is_admiring"}, - {"ranged_charge": "variable.attack_state == 2"} - ] - }, - "melee_attack": { - "animations": ["melee_attack"], - "transitions": [ - { - "default": "!query.is_item_equipped || !variable.has_target || variable.attack_time < 0.0 || query.is_admiring" - } - ] - }, - "hand_attack": { - "animations": ["hand_attack"], - "transitions": [ - { - "default": "query.is_item_equipped || !variable.has_target || variable.attack_time < 0.0 || query.is_admiring" - } - ] - } - } - }, - "riding_controller": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"riding": "query.is_riding"}]}, - "riding": { - "animations": ["riding.arms", "riding.legs"], - "transitions": [{"default": "!query.is_riding"}] - } - } - } - } - }, - "piglin_brute": { - "identifier": "minecraft:piglin_brute", - "materials": {"default": "piglin_brute"}, - "textures": {"default": "textures/entity/piglin/piglin_brute"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]}, - { - "origin": [-4, 12, -2], - "size": [8, 12, 4], - "uv": [16, 32], - "inflate": 0.25 - } - ] - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-5, 24, -4], - "size": [10, 8, 8], - "uv": [0, 0], - "inflate": -0.02 - }, - {"origin": [-2, 24, -5], "size": [4, 4, 1], "uv": [31, 1]}, - {"origin": [2, 24, -5], "size": [1, 2, 1], "uv": [2, 4]}, - {"origin": [-3, 24, -5], "size": [1, 2, 1], "uv": [2, 0]} - ], - "inflate": -0.02 - }, - { - "name": "leftear", - "parent": "head", - "pivot": [5, 30, 0], - "rotation": [0, 0, -30], - "cubes": [{"origin": [4, 25, -2], "size": [1, 5, 4], "uv": [51, 6]}] - }, - { - "name": "rightear", - "parent": "head", - "pivot": [-5, 30, 0], - "rotation": [0, 0, 30], - "cubes": [ - {"origin": [-5, 25, -2], "size": [1, 5, 4], "uv": [39, 6]} - ] - }, - {"name": "hat", "parent": "head", "pivot": [0, 24, 0]}, - { - "name": "rightarm", - "parent": "body", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]}, - { - "origin": [-8, 12, -2], - "size": [4, 12, 4], - "uv": [40, 32], - "inflate": 0.25 - } - ] - }, - {"name": "rightItem", "parent": "rightarm", "pivot": [-6, 15, 1]}, - { - "name": "leftarm", - "parent": "body", - "pivot": [5, 22, 0], - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [32, 48]}, - { - "origin": [4, 12, -2], - "size": [4, 12, 4], - "uv": [48, 48], - "inflate": 0.25 - } - ] - }, - {"name": "leftItem", "parent": "leftArm", "pivot": [6, 15, 1]}, - { - "name": "rightleg", - "parent": "body", - "pivot": [-1.9, 12, 0], - "cubes": [ - {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 16]}, - { - "origin": [-4, 0, -2], - "size": [4, 12, 4], - "uv": [0, 32], - "inflate": 0.25 - } - ] - }, - { - "name": "leftleg", - "parent": "body", - "pivot": [1.9, 12, 0], - "cubes": [ - {"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [16, 48]}, - { - "origin": [0, 0, -2], - "size": [4, 12, 4], - "uv": [0, 48], - "inflate": 0.25 - } - ] - } - ], - "visible_bounds_width": 2, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 64, - "textureheight": 64 - } - }, - "spawn_egg": {"base_color": "#592A10", "overlay_color": "#F9F3A4"}, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;", - "variable.attack = Math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3;", - "variable.attack2 = Math.sin(variable.attack_time * 180.0) * 57.3;", - "variable.z_bob = Math.cos(query.life_time * 103.13244) * 2.865 + 2.865;", - "variable.x_bob = Math.sin(query.life_time * 76.776372) * 2.865;" - ], - "animate": [ - {"humanoid_big_head": "query.is_baby"}, - "move", - "bob", - "look_at_target_controller", - "piglin_attack_controller", - "riding_controller" - ] - }, - "animations": { - "move": { - "loop": true, - "bones": { - "leftear": {"rotation": [0, 0, "variable.tcos0 * 0.5"]}, - "rightear": {"rotation": [0, 0, "-variable.tcos0 * 0.5"]}, - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["-variable.tcos0 * 1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "humanoid_big_head": {"loop": true, "bones": {"head": {"scale": 1.4}}}, - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "crossbow_hold": { - "bones": { - "leftarm": { - "rotation": [ - "-85.94 + query.target_x_rotation -this", - "34.38 + math.clamp(query.target_y_rotation, -45, 25) -this", - 0 - ] - }, - "rightarm": { - "rotation": [ - "-90.0 + 5.73 + query.target_x_rotation -this", - "-17.19 + math.clamp(query.target_y_rotation, -25, 45) -this", - 0 - ] - } - }, - "loop": true - }, - "crossbow_charge": { - "bones": { - "leftarm": { - "rotation": [ - "math.lerp(-90.0 + 34.38, -90.0, variable.crossbow_charge) -this", - "math.lerp(22.92, 48.70, variable.crossbow_charge) -this", - 0 - ] - }, - "rightarm": {"rotation": ["-90.0 + 34.38 -this", "-45.84 -this", 0]} - }, - "loop": true - }, - "melee_attack": { - "bones": { - "leftarm": { - "rotation": [ - "(math.cos(query.life_time * 20.0 * 10.89) * 28.65) + (math.sin(variable.attack_time * 180.0) * 68.76 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0)) * 22.92)", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "-100 + (variable.attack2 * 2.2 - variable.attack * 0.4) + variable.x_bob - this", - "variable.attack2 * 0.6 - 5.73 - this", - "variable.z_bob - this" - ] - } - }, - "loop": true - }, - "hand_attack": { - "bones": { - "leftarm": { - "rotation": [ - "-(math.sin((1 - math.pow((1 - variable.attack_time), 4)) * 180) * 1.2 + math.sin(variable.attack_time * 180)) * 10.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "-(math.sin((1 - math.pow((1 - variable.attack_time), 4)) * 180) * 1.2 + math.sin(variable.attack_time * 180)) * 30.0", - "-(math.sin((1 - math.pow((1 - variable.attack_time), 4)) * 180) ? (-90.0 * math.sin((1 - math.pow((1 - variable.attack_time), 4)) * 180)) + 30.0 : 0.0)", - 0 - ] - } - }, - "loop": true - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - } - }, - "render_controllers": ["controller.render.piglin_brute"], - "enable_attachables": true, - "animation_controllers": { - "look_at_target_controller": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "piglin_attack_controller": { - "initial_state": "default", - "states": { - "ranged_charge": { - "animations": ["crossbow_charge"], - "transitions": [ - {"default": "variable.attack_state == 0 || query.is_admiring"}, - {"ranged_hold": "variable.attack_state == 1"} - ] - }, - "default": { - "transitions": [ - { - "ranged_hold": "query.variant == 0 && variable.attack_state == 1 && !query.is_admiring" - }, - { - "ranged_charge": "query.variant == 0 && variable.attack_state == 2 && !query.is_admiring" - }, - { - "hand_attack": "variable.has_target && query.variant == 1 && !query.is_item_equipped && variable.attack_time >= 0.0 && !query.is_admiring" - }, - { - "melee_attack": "variable.has_target && query.variant == 1 && query.is_item_equipped && variable.attack_time >= 0.0 && !query.is_admiring" - } - ] - }, - "ranged_hold": { - "animations": ["crossbow_hold"], - "transitions": [ - {"default": "variable.attack_state == 0 || query.is_admiring"}, - {"ranged_charge": "variable.attack_state == 2"} - ] - }, - "melee_attack": { - "animations": ["melee_attack"], - "transitions": [ - { - "default": "!query.is_item_equipped || !variable.has_target || variable.attack_time < 0.0 || query.is_admiring" - } - ] - }, - "hand_attack": { - "animations": ["hand_attack"], - "transitions": [ - { - "default": "query.is_item_equipped || !variable.has_target || variable.attack_time < 0.0 || query.is_admiring" - } - ] - } - } - }, - "riding_controller": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"riding": "query.is_riding"}]}, - "riding": { - "animations": ["riding.arms", "riding.legs"], - "transitions": [{"default": "!query.is_riding"}] - } - } - } - } - }, - "pillager": { - "identifier": "minecraft:pillager", - "materials": {"default": "pillager"}, - "textures": {"default": "textures/entity/illager/pillager"}, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 2.5, - "visible_bounds_offset": [0, 1.25, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "head", - "pivot": [0, 24, 0], - "locators": {"lead": [0, 0, 0]}, - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 10, 8], "uv": [0, 0]} - ], - "parent": "body" - }, - { - "name": "nose", - "pivot": [0, 26, 0], - "cubes": [ - {"origin": [-1, 23, -6], "size": [2, 4, 2], "uv": [24, 0]} - ], - "parent": "head" - }, - { - "name": "body", - "parent": "waist", - "pivot": [0, 0, 0], - "cubes": [ - {"origin": [-4, 12, -3], "size": [8, 12, 6], "uv": [16, 20]}, - { - "origin": [-4, 6, -3], - "size": [8, 18, 6], - "uv": [0, 38], - "inflate": 0.5 - } - ] - }, - {"name": "waist", "neverRender": true, "pivot": [0, 12, 0]}, - { - "name": "leftLeg", - "parent": "body", - "pivot": [2, 12, 0], - "cubes": [{"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [0, 22]}] - }, - { - "name": "rightLeg", - "parent": "body", - "pivot": [-2, 12, 0], - "mirror": true, - "cubes": [ - {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 22]} - ] - }, - { - "name": "rightarm", - "parent": "body", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 46]} - ] - }, - { - "name": "rightItem", - "pivot": [-6, 15, 1], - "neverRender": true, - "parent": "rightArm" - }, - { - "name": "leftarm", - "parent": "body", - "pivot": [5, 22, 0], - "mirror": true, - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 46]} - ] - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 56}, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;" - ], - "animate": ["pillager_root_controller"] - }, - "animations": { - "humanoid_base_pose": { - "loop": true, - "bones": {"waist": {"rotation": [0, 0, 0]}} - }, - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "move": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - }, - "holding": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - } - } - }, - "attack.rotations": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46 - this", - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.sin(1.0 - math.pow(1.0 - variable.attack_time, 3.0) * 180.0) * (variable.is_brandishing_spear ? -1.0 : 1.0 )", - "variable.is_brandishing_spear ? 0.0 : (math.sin(math.sqrt(variable.attack_time) * 360) * 11.46) * 2.0", - 0 - ] - } - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "crossbow_hold": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "-85.94 + query.target_x_rotation -this", - "34.38 + math.clamp(query.target_y_rotation, -45, 25) -this", - 0 - ] - }, - "rightarm": { - "rotation": [ - "-90.0 + 5.73 + query.target_x_rotation -this", - "-17.19 + math.clamp(query.target_y_rotation, -25, 45) -this", - 0 - ] - } - } - }, - "crossbow_charge": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "math.lerp(-90.0 + 34.38, -90.0, variable.crossbow_charge) -this", - "math.lerp(22.92, 48.70, variable.crossbow_charge) -this", - 0 - ] - }, - "rightarm": {"rotation": ["-90.0 + 34.38 -this", "-45.84 -this", 0]} - } - }, - "celebrating": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "(math.cos(query.life_time * 800.0) * 2.865)", - 180, - -135 - ] - }, - "rightarm": { - "rotation": [ - "(math.cos(query.life_time * 800.0) * 2.865)", - 180, - 153 - ] - } - } - } - }, - "render_controllers": ["controller.render.pillager"], - "enable_attachables": true, - "animation_controllers": { - "controller_humanoid_base_pose": { - "initial_state": "default", - "states": {"default": {"animations": ["humanoid_base_pose"]}} - }, - "controller_look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "controller_move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - }, - "controller_riding": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"riding": "query.is_riding"}]}, - "riding": { - "animations": ["riding.arms", "riding.legs"], - "transitions": [{"default": "!query.is_riding"}] - } - } - }, - "controller_attack": { - "initial_state": "default", - "states": { - "attacking": { - "animations": ["attack.rotations"], - "transitions": [{"default": "variable.attack_time < 0.0"}] - }, - "default": { - "transitions": [{"attacking": "variable.attack_time >= 0.0"}] - } - } - }, - "controller_bob": { - "initial_state": "default", - "states": {"default": {"animations": ["bob"]}} - }, - "controller_pillager_attack": { - "initial_state": "default", - "states": { - "charge": { - "animations": ["crossbow_charge"], - "transitions": [ - {"default": "variable.attack_state == 0"}, - {"hold": "variable.attack_state == 1"} - ] - }, - "default": { - "transitions": [ - {"hold": "variable.attack_state == 1"}, - {"charge": "variable.attack_state == 2"} - ] - }, - "hold": { - "animations": ["crossbow_hold"], - "transitions": [ - {"default": "variable.attack_state == 0"}, - {"charge": "variable.attack_state == 2"} - ] - } - } - }, - "pillager_root_controller": { - "initial_state": "default", - "states": { - "default": { - "blend_transition": 0.2, - "blend_via_shortest_path": true, - "animations": [ - "controller_humanoid_base_pose", - "controller_look_at_target", - "controller_move", - "controller_riding", - "controller_attack", - "controller_bob", - "controller_pillager_attack" - ], - "transitions": [{"celebrating": "query.is_celebrating"}] - }, - "celebrating": { - "animations": ["celebrating", {"riding.legs": "query.is_riding"}], - "blend_transition": 0.2, - "blend_via_shortest_path": true, - "transitions": [{"default": "!query.is_celebrating"}] - } - } - } - } - }, - "player": { - "identifier": "minecraft:player", - "materials": { - "default": "entity_alphatest", - "cape": "entity_alphatest", - "animated": "player_animated" - }, - "textures": { - "default": "textures/entity/steve", - "cape": "textures/entity/cape_invisible" - }, - "geometry": { - "default": { - "visible_bounds_width": 1, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "bones": [ - {"name": "root", "pivot": [0, 0, 0]}, - { - "name": "body", - "parent": "waist", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} - ] - }, - {"name": "waist", "parent": "root", "pivot": [0, 12, 0]}, - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]}] - }, - {"name": "cape", "pivot": [0, 24, 3], "parent": "body"}, - { - "name": "hat", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 8, 8], - "uv": [32, 0], - "inflate": 0.5 - } - ] - }, - { - "name": "leftArm", - "parent": "body", - "pivot": [5, 22, 0], - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [32, 48]} - ] - }, - { - "name": "leftSleeve", - "parent": "leftArm", - "pivot": [5, 22, 0], - "cubes": [ - { - "origin": [4, 12, -2], - "size": [4, 12, 4], - "uv": [48, 48], - "inflate": 0.25 - } - ] - }, - {"name": "leftItem", "pivot": [6, 15, 1], "parent": "leftArm"}, - { - "name": "rightArm", - "parent": "body", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} - ] - }, - { - "name": "rightSleeve", - "parent": "rightArm", - "pivot": [-5, 22, 0], - "cubes": [ - { - "origin": [-8, 12, -2], - "size": [4, 12, 4], - "uv": [40, 32], - "inflate": 0.25 - } - ] - }, - { - "name": "rightItem", - "pivot": [-6, 15, 1], - "locators": {"lead_hold": [-6, 15, 1]}, - "parent": "rightArm" - }, - { - "name": "leftLeg", - "parent": "root", - "pivot": [1.9, 12, 0], - "cubes": [ - {"origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [16, 48]} - ] - }, - { - "name": "leftPants", - "parent": "leftLeg", - "pivot": [1.9, 12, 0], - "cubes": [ - { - "origin": [-0.1, 0, -2], - "size": [4, 12, 4], - "uv": [0, 48], - "inflate": 0.25 - } - ] - }, - { - "name": "rightLeg", - "parent": "root", - "pivot": [-1.9, 12, 0], - "cubes": [ - {"origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} - ] - }, - { - "name": "rightPants", - "parent": "rightLeg", - "pivot": [-1.9, 12, 0], - "cubes": [ - { - "origin": [-3.9, 0, -2], - "size": [4, 12, 4], - "uv": [0, 32], - "inflate": 0.25 - } - ] - }, - { - "name": "jacket", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 12, -2], - "size": [8, 12, 4], - "uv": [16, 32], - "inflate": 0.25 - } - ] - } - ] - }, - "cape": { - "texturewidth": 64, - "textureheight": 32, - "bones": [ - {"name": "root", "pivot": [0, 0, 0]}, - {"name": "body", "pivot": [0, 24, 0], "parent": "waist"}, - { - "name": "waist", - "parent": "root", - "neverRender": true, - "pivot": [0, 12, 0] - }, - { - "name": "cape", - "parent": "body", - "pivot": [0, 24, 3], - "bind_pose_rotation": [0, 180, 0], - "rotation": [0, 180, 0], - "cubes": [{"origin": [-5, 8, 3], "size": [10, 16, 1], "uv": [0, 0]}] - } - ] - } - }, - "scripts": { - "scale": "0.9375", - "initialize": [ - "variable.is_holding_right = 0.0;", - "variable.is_blinking = 0.0;", - "variable.last_blink_time = 0.0;", - "variable.hand_bob = 0.0;" - ], - "pre_animation": [ - "variable.helmet_layer_visible = 1.0;", - "variable.leg_layer_visible = 1.0;", - "variable.boot_layer_visible = 1.0;", - "variable.chest_layer_visible = 1.0;", - "variable.attack_body_rot_y = Math.sin(360*Math.sqrt(variable.attack_time)) * 5.0;", - "variable.tcos0 = (math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;", - "variable.first_person_rotation_factor = math.sin((1 - variable.attack_time) * 180.0);", - "variable.hand_bob = query.life_time < 0.01 ? 0.0 : variable.hand_bob + ((query.is_on_ground && query.is_alive ? math.clamp(math.sqrt(math.pow(query.position_delta(0), 2.0) + math.pow(query.position_delta(2), 2.0)), 0.0, 0.1) : 0.0) - variable.hand_bob) * 0.02;", - "variable.map_angle = math.clamp(1 - variable.player_x_rotation / 45.1, 0.0, 1.0);", - "variable.item_use_normalized = query.main_hand_item_use_duration / query.main_hand_item_max_duration;" - ], - "animate": ["root"] - }, - "animations": { - "humanoid_base_pose": { - "loop": true, - "bones": {"waist": {"rotation": [0, 0, 0]}} - }, - "look_at_target_ui": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_inverted": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "-query.target_x_rotation", - "-query.target_y_rotation", - 0 - ] - } - } - }, - "cape": { - "loop": true, - "bones": { - "cape": { - "position": [ - 0, - "query.get_root_locator_offset('armor_offset.default_neck', 1)", - 0 - ], - "rotation": [ - "math.lerp(0.0, -126.0, query.cape_flap_amount) - 6.0", - 0, - 0 - ] - } - } - }, - "move.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]} - } - }, - "move.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "swimming": { - "animation_length": 1.3, - "loop": true, - "override_previous_animation": true, - "bones": { - "leftarm": { - "rotation": { - "0": [0, 180, 180], - "0.7": [0, 180, 287.2], - "1.1": [90, 180, 180], - "1.3": [0, 180, 180] - } - }, - "rightarm": { - "rotation": { - "0": [0, 180, -180], - "0.7": [0, 180, -287.2], - "1.1": [90, 180, -180], - "1.3": [0, 180, -180] - } - }, - "root": { - "position": [ - 0, - "(math.sin(query.target_x_rotation) * 24.0 + 3.0) * variable.swim_amount", - "(math.cos(query.target_x_rotation) * 24.0 + 9.0) * variable.swim_amount" - ], - "rotation": [ - "variable.swim_amount * (90 + query.target_x_rotation)", - 0, - 0 - ] - } - } - }, - "swimming.legs": { - "loop": true, - "override_previous_animation": true, - "bones": { - "leftleg": { - "rotation": [ - "math.lerp(0.0, math.cos(query.life_time * 390.0 + 180.0) * 17.2, variable.swim_amount)", - 0, - 0 - ] - }, - "rightleg": { - "rotation": [ - "math.lerp(0.0, math.cos(query.life_time * 390.0) * 17.2, variable.swim_amount)", - 0, - 0 - ] - } - } - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - }, - "holding": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - } - } - }, - "brandish_spear": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "this * -0.5 - 157.5 - 22.5 * variable.charge_amount", - "-this", - 0 - ] - } - } - }, - "charging": { - "loop": true, - "bones": { - "rightarm": { - "rotation": ["22.5 * variable.charge_amount - this", "-this", 0] - } - } - }, - "attack.positions": { - "loop": true, - "bones": {"head": {"rotation": [0, 0, 0]}} - }, - "attack.rotations": { - "loop": true, - "bones": { - "body": {"rotation": [0, "variable.attack_body_rot_y", 0]}, - "leftarm": { - "rotation": [ - "-(math.sin((1 - math.pow((1 - variable.attack_time), 4)) * 180) * 1.2 + math.sin(variable.attack_time * 180)) * 10.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "-(math.sin((1 - math.pow((1 - variable.attack_time), 4)) * 180) * 1.2 + math.sin(variable.attack_time * 180)) * 30.0", - "-(math.sin((1 - math.pow((1 - variable.attack_time), 4)) * 180) ? (-90.0 * math.sin((1 - math.pow((1 - variable.attack_time), 4)) * 180)) + 30.0 : 0.0)", - 0 - ] - } - } - }, - "sneaking": { - "loop": true, - "bones": { - "body": {"position": [0, -2, 0]}, - "head": {"position": [0, -1, 0]}, - "leftarm": {"rotation": [-5.7, 0, 0]}, - "leftleg": {"rotation": [-28, 0, 0]}, - "rightarm": {"rotation": [-5.7, 0, 0]}, - "rightleg": {"rotation": [-28, 0, 0]}, - "root": {"position": [0, 1.25, 9], "rotation": ["28.0 - this", 0, 0]} - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "-((math.cos(query.life_time * 103.2) * 2.865) + 2.865)" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "damage_nearby_mobs": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["-45.0-this", "-this", "-this"]}, - "leftleg": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightarm": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-45.0-this", "-this", "-this"]} - } - }, - "fishing_rod": { - "loop": true, - "bones": {"rightarm": {"rotation": [" -19.0 - this", "-this", "-this"]}} - }, - "use_item_progress": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "variable.use_item_startup_progress * -60.0 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -22.5 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -5.625 + variable.use_item_interval_progress * 11.25" - ] - } - } - }, - "skeleton_attack": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "-68.75 * math.sin(variable.attack_time * 180.0) + 22.92 * (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0))", - "5.73 - math.sin(variable.attack_time * 180.0) * 34.38 - this", - "-this" - ] - }, - "rightarm": { - "rotation": [ - "-68.75 * math.sin(variable.attack_time * 180.0) + 22.92 * (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0))", - "-5.73 + math.sin(variable.attack_time * 180.0) * 34.38 - this", - "-this" - ] - } - } - }, - "sleeping": { - "loop": true, - "override_previous_animation": true, - "bones": { - "head": {"rotation": ["30.0 - this", "-this", "-this"]}, - "root": { - "position": [ - "24.0 * math.cos(query.body_y_rotation) * math.cos(query.sleep_rotation) - 24.0 * math.sin(query.body_y_rotation) * math.sin(query.sleep_rotation)", - 0, - "24.0 * math.cos(query.body_y_rotation) * math.sin(query.sleep_rotation) + 24.0 * math.sin(query.body_y_rotation) * math.cos(query.sleep_rotation)" - ], - "rotation": [ - -90, - "270.0 - query.sleep_rotation - query.body_y_rotation", - 0 - ] - } - } - }, - "first_person_base_pose": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "first_person_empty_hand": { - "loop": true, - "bones": { - "rightarm": { - "position": [13.5, -10, 12], - "rotation": [ - "95.0 + variable.is_using_vr * 7.5", - "-45.0 + variable.is_using_vr * 7.5", - "115.0 + variable.is_using_vr * -2.5" - ] - } - } - }, - "first_person_swap_item": { - "loop": true, - "bones": { - "leftarm": { - "position": [ - 0, - "query.get_equipped_item_name('off_hand') == 'map' ? 0.0 : -10.0 * (1.0 - variable.player_arm_height)", - 0 - ] - }, - "rightarm": { - "position": [0, "-10.0 * (1.0 - variable.player_arm_height)", 0] - } - } - }, - "first_person_attack_rotation": { - "loop": true, - "bones": { - "rightarm": { - "position": [ - "math.clamp(-15.5 * math.sin(variable.first_person_rotation_factor * variable.attack_time * 112.0), -7.0, 999.0) * math.sin(variable.first_person_rotation_factor * variable.attack_time * 112.0)", - "math.sin(variable.first_person_rotation_factor * (1.0 - variable.attack_time) * (1.0 - variable.attack_time) * 200.0) * 7.5 - variable.first_person_rotation_factor * variable.attack_time * 15.0 + variable.short_arm_offset_right", - "math.sin(variable.first_person_rotation_factor * variable.attack_time * 120.0) * 1.75" - ], - "rotation": [ - "math.sin(variable.first_person_rotation_factor * (1.0 - variable.attack_time) * (1.0 - variable.attack_time) * 280.0) * -60.0", - "math.sin(variable.first_person_rotation_factor * (1.0 - variable.attack_time) * (1.0 - variable.attack_time) * 280.0) * 40.0", - "math.sin(variable.first_person_rotation_factor * (1.0 - variable.attack_time) * (1.0 - variable.attack_time) * 280.0) * 20.0" - ] - } - } - }, - "first_person_vr_attack_rotation": { - "loop": true, - "bones": { - "rightarm": { - "position": [ - "5.0 * math.sin(variable.first_person_rotation_factor * variable.attack_time * 112.0)", - "(math.sin(variable.first_person_rotation_factor * (1.0 - variable.attack_time) * (1.0 - variable.attack_time) * 200.0) - 0.8) * 8.75 + 5.0", - "math.sin(variable.first_person_rotation_factor * variable.attack_time * 120.0) * 15.0" - ], - "rotation": [ - "30.7 * math.sin(variable.first_person_rotation_factor * variable.attack_time * -180.0 - 45.0) * 1.5", - 0, - "21.8 * math.sin(variable.first_person_rotation_factor * variable.attack_time * 200.0 + 30.0) * 1.25" - ] - } - } - }, - "first_person_map_hold": { - "loop": true, - "bones": { - "leftarm": { - "position": [ - "-16.250 + variable.is_vertical_splitscreen * 7.0", - "-10.75 - variable.map_angle * 8.0 + variable.is_vertical_splitscreen * 0.6 - variable.short_arm_offset_left", - "9.0 - variable.map_angle * 8.0 + variable.short_arm_offset_left" - ], - "rotation": [40, -20, -155], - "scale": [1.15, 1.15, 1.15] - }, - "rightarm": { - "position": [ - "12.50 + variable.is_vertical_splitscreen * 1.75", - "-7.5 - variable.map_angle * 8.0 + variable.is_vertical_splitscreen * 0.5 - variable.short_arm_offset_right", - "5.25 - variable.map_angle * 8.0 + variable.short_arm_offset_right" - ], - "rotation": [77.5, 7.5, 160] - } - } - }, - "first_person_map_hold_attack": { - "loop": true, - "bones": { - "leftarm": { - "position": [ - "math.sin(variable.first_person_rotation_factor * variable.attack_time * 112.0) * -10.75", - "math.sin(variable.first_person_rotation_factor * (1.0 - variable.attack_time) * (1.0 - variable.attack_time) * 200.0) * 3.75 - variable.first_person_rotation_factor * variable.attack_time * 1.25 + variable.short_arm_offset_left", - "math.sin(variable.first_person_rotation_factor * variable.attack_time * 120.0) * 5.75" - ], - "rotation": [ - "variable.map_angle * 90.0", - "-15.0 * math.sin(variable.first_person_rotation_factor * (1.0 - variable.attack_time) * -100.0)", - 0 - ] - }, - "rightarm": { - "position": [ - "math.sin(variable.first_person_rotation_factor * variable.attack_time * 112.0) * -6.25", - "math.sin(variable.first_person_rotation_factor * (1.0 - variable.attack_time) * (1.0 - variable.attack_time) * 200.0) * 1.75 + variable.short_arm_offset_right", - "math.sin(variable.first_person_rotation_factor * variable.attack_time * 120.0) * 5.25" - ], - "rotation": ["variable.map_angle * 90.0", 0, 0] - } - } - }, - "first_person_map_hold_off_hand": { - "loop": true, - "bones": { - "leftarm": { - "position": [ - "-14.50 + variable.is_horizontal_splitscreen * 2.0 + variable.is_vertical_splitscreen * 8.7", - "-8.250 + variable.short_arm_offset_left", - "11.50 + variable.is_horizontal_splitscreen * 0.5" - ], - "rotation": [195, 182.5, 2.5], - "scale": [0.75, 0.75, 0.75] - } - } - }, - "first_person_map_hold_main_hand": { - "loop": true, - "bones": { - "rightarm": { - "position": [ - "14.50 - variable.is_vertical_splitscreen * 0.75", - "-8.25 + variable.short_arm_offset_right + math.sin(variable.first_person_rotation_factor * (1.0 - variable.attack_time) * (1.0 - variable.attack_time) * 200.0) * 2.75 - variable.first_person_rotation_factor * variable.attack_time * 3.0 - variable.is_horizontal_splitscreen", - "11.5 + math.sin(variable.first_person_rotation_factor * variable.attack_time * 120.0) * 3.5 + variable.is_horizontal_splitscreen * 3.5" - ], - "rotation": [195, 182.5, -5], - "scale": [0.75, 0.75, 0.75] - } - } - }, - "first_person_crossbow_equipped": { - "loop": true, - "override_previous_animation": true, - "bones": { - "leftarm": { - "position": [ - "1.5 - variable.item_use_normalized * 3.5", - "-3.799999952316284 + variable.short_arm_offset_left", - "8.25 - (1 - variable.item_use_normalized)" - ], - "rotation": [165, -60, 45], - "scale": [0.4, 0.4, 0.4] - } - } - }, - "third_person_crossbow_equipped": { - "loop": true, - "bones": { - "leftarm": { - "position": [0, 0, 0.5], - "rotation": [ - "-this - 65.0 - (1.0 - variable.item_use_normalized) * 5.0", - "-this + (1.0 - variable.item_use_normalized) * 30.0", - "-this + 20.0 + (1.0 - variable.item_use_normalized) * 10.0" - ] - }, - "rightarm": { - "rotation": ["- 60.0 - this", "- 45.0 - this", "- 2.5 - this"] - } - } - }, - "third_person_bow_equipped": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "-90.0 + query.target_x_rotation - query.is_sneaking * 15.0 - this", - "27.5 + query.target_y_rotation", - 0 - ] - }, - "rightarm": { - "rotation": [ - "-90.0 + query.target_x_rotation - query.is_sneaking * 15.0 - this", - "-5.0 + query.target_y_rotation", - 0 - ] - }, - "rightitem": {"rotation": [0, -10, 0]} - } - }, - "crossbow_hold": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "query.is_swimming ? 0.0 : -93.0 + query.target_x_rotation - query.is_sneaking * 27.0 -this", - "query.is_swimming ? 0.0 : 42.0 + math.clamp(query.target_y_rotation, -45.0, 5.0) -this", - "query.is_sneaking * -15.0" - ] - }, - "rightarm": { - "rotation": [ - "query.is_swimming ? 0.0 : -93.0 + query.target_x_rotation - query.is_sneaking * 27.0 -this", - "query.is_swimming ? 0.0 : math.clamp(query.target_y_rotation, -60.0, 45.0) -this", - 0 - ] - } - } - }, - "shield_block_main_hand": { - "loop": true, - "bones": { - "rightarm": {"rotation": [-20, -30, -25]}, - "rightitem": {"position": [-1, -3, 0], "rotation": [0, -60, -45]} - } - }, - "shield_block_off_hand": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-20, 20, 20]}, - "leftitem": { - "position": [ - "1.0 + query.item_is_charged * 1.5", - "-3.0 + query.item_is_charged", - 0 - ], - "rotation": [ - "query.item_is_charged * 30.0", - "70.0 - query.item_is_charged * 60.0", - "65.0 - query.item_is_charged * 15.0" - ] - } - } - } - }, - "render_controllers": [ - {"controller.render.player.first_person": "variable.is_first_person"}, - { - "controller.render.player.third_person": "!variable.is_first_person && !variable.map_face_icon" - }, - {"controller.render.player.map": "variable.map_face_icon"} - ], - "enable_attachables": true, - "animation_controllers": { - "root": { - "initial_state": "first_person", - "states": { - "first_person": { - "animations": [ - "first_person_swap_item", - { - "first_person_attack_controller": "variable.attack_time > 0.0f && query.get_equipped_item_name != 'map'" - }, - "first_person_base_pose", - { - "first_person_empty_hand": "query.get_equipped_item_name(0, 1) != 'map'" - }, - { - "first_person_map_controller": "(query.get_equipped_item_name(0, 1) == 'map' || query.get_equipped_item_name('off_hand') == 'map')" - }, - { - "first_person_crossbow_equipped": "query.get_equipped_item_name == 'crossbow' && (variable.item_use_normalized > 0 && variable.item_use_normalized < 1.0)" - } - ], - "transitions": [ - {"paperdoll": "variable.is_paperdoll"}, - {"map_player": "variable.map_face_icon"}, - {"third_person": "!variable.is_first_person"} - ] - }, - "map_player": { - "transitions": [ - {"paperdoll": "variable.is_paperdoll"}, - {"first_person": "variable.is_first_person"}, - { - "third_person": "!variable.map_face_icon && !variable.is_first_person" - } - ] - }, - "paperdoll": { - "animations": [ - "humanoid_base_pose", - {"look_at_target_ui": "variable.should_look_at_target_ui"}, - "move.arms", - "move.legs", - "cape" - ], - "transitions": [ - { - "first_person": "!variable.is_paperdoll && variable.is_first_person" - }, - {"map_player": "variable.map_face_icon"}, - { - "third_person": "!variable.is_paperdoll && !variable.is_first_person" - } - ] - }, - "third_person": { - "animations": [ - "humanoid_base_pose", - {"look_at_target": "!query.is_sleeping && !query.is_emoting"}, - "move.arms", - "move.legs", - "cape", - {"riding.arms": "query.is_riding"}, - {"riding.legs": "query.is_riding"}, - "holding", - {"brandish_spear": "variable.is_brandishing_spear"}, - {"charging": "query.is_charging"}, - {"sneaking": "query.is_sneaking && !query.is_sleeping"}, - "bob", - {"damage_nearby_mobs": "variable.damage_nearby_mobs"}, - {"swimming": "variable.swim_amount > 0.0"}, - {"swimming.legs": "variable.swim_amount > 0.0"}, - { - "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 ) && !variable.is_brandishing_spear" - }, - {"fishing_rod": "query.get_equipped_item_name == 'fishing_rod'"}, - {"sleeping": "query.is_sleeping && query.is_alive"}, - {"attack.positions": "variable.attack_time >= 0.0"}, - {"attack.rotations": "variable.attack_time >= 0.0"}, - { - "shield_block_main_hand": "query.blocking && query.get_equipped_item_name('off_hand') != 'shield' && query.get_equipped_item_name == 'shield'" - }, - { - "shield_block_off_hand": "query.blocking && query.get_equipped_item_name('off_hand') == 'shield' && !(variable.item_use_normalized > 0 && variable.item_use_normalized < 1.0)" - }, - { - "crossbow_controller": "query.get_equipped_item_name == 'crossbow'" - }, - { - "third_person_bow_equipped": "query.get_equipped_item_name == 'bow' && (variable.item_use_normalized > 0 && variable.item_use_normalized < 1.0)" - } - ], - "transitions": [ - {"paperdoll": "variable.is_paperdoll"}, - {"first_person": "variable.is_first_person"}, - {"map_player": "variable.map_face_icon"} - ] - } - } - }, - "base_controller": "controller.animation.player.base", - "hudplayer": { - "initial_state": "default", - "states": { - "default": { - "animations": [ - "humanoid_base_pose", - {"look_at_target": "!query.is_sleeping && !query.is_emoting"}, - "move.arms", - "move.legs", - "cape", - {"riding.arms": "query.is_riding"}, - {"riding.legs": "query.is_riding"}, - "holding", - {"brandish_spear": "variable.is_brandishing_spear"}, - {"charging": "query.is_charging"}, - {"sneaking": "query.is_sneaking && !query.is_sleeping"}, - "bob", - {"damage_nearby_mobs": "variable.damage_nearby_mobs"}, - {"swimming": "variable.swim_amount > 0.0"}, - {"swimming.legs": "variable.swim_amount > 0.0"}, - { - "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 ) && !variable.is_brandishing_spear" - }, - {"sleeping": "query.is_sleeping && query.is_alive"}, - {"attack.positions": "variable.attack_time >= 0.0"}, - {"attack.rotations": "variable.attack_time >= 0.0"}, - { - "shield_block_main_hand": "query.blocking && query.get_equipped_item_name('off_hand') != 'shield' && query.get_equipped_item_name == 'shield'" - }, - { - "shield_block_off_hand": "query.blocking && query.get_equipped_item_name('off_hand') == 'shield' && !(variable.item_use_normalized > 0 && variable.item_use_normalized < 1.0)" - }, - { - "crossbow_controller": "query.get_equipped_item_name == 'crossbow'" - }, - { - "third_person_bow_equipped": "query.get_equipped_item_name == 'bow' && (variable.item_use_normalized > 0 && variable.item_use_normalized < 1.0)" - } - ] - } - } - }, - "look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "first_person_attack_controller": { - "initial_state": "default", - "states": { - "default": { - "animations": ["first_person_attack_rotation"], - "transitions": [{"vr_attack": "variable.is_using_vr"}] - }, - "vr_attack": { - "animations": ["first_person_vr_attack_rotation"], - "transitions": [{"default": "!variable.is_using_vr"}] - } - } - }, - "first_person_map_controller": { - "initial_state": "default", - "states": { - "default": { - "transitions": [ - { - "one_hand": "query.get_equipped_item_name('off_hand') == 'map' || query.get_equipped_item_name('off_hand') == 'shield'" - }, - { - "two_hand": "query.get_equipped_item_name('off_hand') != 'map' && query.get_equipped_item_name('off_hand') != 'shield'" - } - ] - }, - "one_hand": { - "animations": [ - { - "first_person_map_hold_main_hand": "query.get_equipped_item_name(0, 1) == 'map'" - }, - { - "first_person_map_hold_off_hand": "query.get_equipped_item_name('off_hand') == 'map' && (query.get_equipped_item_name == 'bow' ? !(variable.item_use_normalized > 0 && variable.item_use_normalized < 1.0) : 1.0)" - } - ], - "transitions": [ - { - "default": "query.get_equipped_item_name(0, 1) != 'map' && query.get_equipped_item_name('off_hand') != 'map'" - }, - { - "two_hand": "query.get_equipped_item_name('off_hand') != 'map' && query.get_equipped_item_name('off_hand') != 'shield'" - } - ] - }, - "two_hand": { - "animations": [ - "first_person_map_hold", - "first_person_map_hold_attack" - ], - "transitions": [ - { - "default": "query.get_equipped_item_name(0, 1) != 'map' && query.get_equipped_item_name('off_hand') != 'map'" - }, - { - "one_hand": "query.get_equipped_item_name('off_hand') == 'map' || query.get_equipped_item_name('off_hand') == 'shield'" - } - ] - } - } - }, - "crossbow_controller": { - "initial_state": "default", - "states": { - "charge": { - "animations": ["third_person_crossbow_equipped"], - "transitions": [ - { - "default": "query.get_equipped_item_name != 'crossbow' || (query.item_remaining_use_duration <= 0.0 && !query.item_is_charged)" - }, - {"hold": "query.item_is_charged"} - ] - }, - "default": { - "transitions": [ - {"hold": "query.item_is_charged"}, - {"charge": "query.item_remaining_use_duration > 0.0"} - ] - }, - "hold": { - "animations": ["crossbow_hold"], - "transitions": [ - { - "default": "query.get_equipped_item_name != 'crossbow' || (query.item_remaining_use_duration <= 0.0 && !query.item_is_charged)" - }, - {"charge": "query.item_remaining_use_duration > 0.0"} - ] - } - } - }, - "blink": { - "initial_state": "default", - "states": { - "default": { - "transitions": [ - { - "open": "variable.is_blinking = 0; variable.last_blink_time = query.life_time; return variable.last_blink_time != 0;" - } - ] - }, - "open": { - "transitions": [ - { - "blink": "variable.is_blinking = 0; variable.return_from_blink = query.life_time + math.random(0, 0.2); return query.life_time > (variable.last_blink_time + math.random(3, 40));" - } - ] - }, - "blink": { - "transitions": [ - { - "open": "variable.is_blinking = 1; variable.last_blink_time = query.life_time; return query.all_animations_finished && (query.life_time > variable.return_from_blink);" - } - ] - } - } - } - } - }, - "polar_bear": { - "identifier": "minecraft:polar_bear", - "materials": {"default": "polar_bear"}, - "textures": {"default": "textures/entity/bear/polarbear"}, - "geometry": { - "default": { - "visible_bounds_width": 3, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 128, - "textureheight": 64, - "bones": [ - { - "name": "head", - "parent": "body", - "pivot": [0, 14, -16], - "locators": {"lead": [0, 14, -16]}, - "mirror": true, - "cubes": [ - { - "mirror": false, - "origin": [-3.5, 10, -19], - "size": [7, 7, 7], - "uv": [0, 0] - }, - { - "mirror": false, - "origin": [-2.5, 10, -22], - "size": [5, 3, 3], - "uv": [0, 44] - }, - { - "mirror": false, - "origin": [-4.5, 16, -17], - "size": [2, 2, 1], - "uv": [26, 0] - }, - {"origin": [2.5, 16, -17], "size": [2, 2, 1], "uv": [26, 0]} - ] - }, - { - "name": "body", - "pivot": [-2, 15, 12], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-7, 14, 5], "size": [14, 14, 11], "uv": [0, 19]}, - {"origin": [-6, 28, 5], "size": [12, 12, 10], "uv": [39, 0]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-4.5, 10, 6], - "cubes": [ - {"origin": [-6.5, 0, 4], "size": [4, 10, 8], "uv": [50, 22]} - ] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [4.5, 10, 6], - "cubes": [ - {"origin": [2.5, 0, 4], "size": [4, 10, 8], "uv": [50, 22]} - ] - }, - { - "name": "leg2", - "parent": "body", - "pivot": [-3.5, 10, -8], - "cubes": [ - {"origin": [-5.5, 0, -10], "size": [4, 10, 6], "uv": [50, 40]} - ] - }, - { - "name": "leg3", - "parent": "body", - "pivot": [3.5, 10, -8], - "cubes": [ - {"origin": [1.5, 0, -10], "size": [4, 10, 6], "uv": [50, 40]} - ] - } - ] - } - }, - "animations": { - "walk": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - }, - "leg1": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg2": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg3": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - } - } - }, - "move": { - "loop": true, - "bones": { - "body": { - "position": [0, "-9 - 2 * query.standing_scale - this", 0], - "rotation": ["(-(query.standing_scale) * 63) - this", 0, 0] - }, - "leg0": { - "position": [ - 0, - "-1 * query.standing_scale", - "6 * query.standing_scale" - ], - "rotation": ["query.standing_scale * 63", 0, 0] - }, - "leg1": { - "position": [ - 0, - "-1 * query.standing_scale", - "6 * query.standing_scale" - ], - "rotation": ["query.standing_scale * 63", 0, 0] - }, - "leg2": { - "rotation": [ - "(query.standing_scale > 1) ? (query.standing_scale * 81) - this : 0", - 0, - 0 - ] - }, - "leg3": { - "rotation": [ - "(query.standing_scale > 1) ? (query.standing_scale * 81) - this : 0", - 0, - 0 - ] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "baby_transform": { - "loop": true, - "bones": {"head": {"position": [0, -1, 3], "scale": 1.25}} - } - }, - "scripts": {"scale": "1.2"}, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": { - "default": { - "animations": [ - {"walk": "query.modified_move_speed"}, - "move", - "look_at_target" - ] - } - } - }, - "baby": { - "initial_state": "baby", - "states": { - "baby": {"animations": [{"baby_transform": "query.is_baby"}]} - } - } - }, - "render_controllers": ["controller.render.polarbear"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 37} - }, - "pufferfish": { - "identifier": "minecraft:pufferfish", - "min_engine_version": "1.8.0", - "materials": {"default": "pufferfish"}, - "textures": {"default": "textures/entity/fish/pufferfish"}, - "geometry": { - "default": { - "visible_bounds_width": 0.5, - "visible_bounds_height": 0.5, - "texturewidth": 32, - "textureheight": 32, - "bones": [ - { - "name": "body", - "cubes": [ - {"origin": [-1.5, 0, -1.5], "size": [3, 2, 3], "uv": [0, 27]}, - {"origin": [0.5, 2, -1.5], "size": [1, 1, 1], "uv": [24, 6]}, - {"origin": [-1.5, 2, -1.5], "size": [1, 1, 1], "uv": [28, 6]} - ], - "locators": {"lead": [0, 0, 0]} - }, - { - "name": "tailfin", - "parent": "body", - "cubes": [ - {"origin": [-1.5, 1, 1.5], "size": [3, 0, 3], "uv": [-3, 0]} - ] - }, - { - "name": "leftFin", - "parent": "body", - "pivot": [6.5, 5, 0.5], - "cubes": [ - { - "origin": [1.5, 0, -1.5], - "size": [1, 1, 2], - "uv": [25, 0], - "mirror": true - } - ] - }, - { - "name": "rightFin", - "parent": "body", - "pivot": [-6.5, 5, 0.5], - "cubes": [ - {"origin": [-2.5, 0, -1.5], "size": [1, 1, 2], "uv": [25, 0]} - ] - } - ] - }, - "mid": { - "visible_bounds_width": 0.5, - "visible_bounds_height": 0.5, - "texturewidth": 32, - "textureheight": 32, - "bones": [ - { - "name": "body", - "cubes": [ - {"origin": [-2.5, 1, -2.5], "size": [5, 5, 5], "uv": [12, 22]} - ] - }, - { - "name": "leftFin", - "parent": "body", - "pivot": [2.5, 5, 0.5], - "cubes": [ - {"origin": [2.5, 4, -1.5], "size": [2, 1, 2], "uv": [24, 3]} - ] - }, - { - "name": "rightFin", - "parent": "body", - "pivot": [-2.5, 5, 0.5], - "cubes": [ - {"origin": [-4.5, 4, -1.5], "size": [2, 1, 2], "uv": [24, 0]} - ] - }, - { - "name": "spines_top_front", - "parent": "body", - "bind_pose_rotation": [45, 0, 0], - "pivot": [0, 6, -2.5], - "cubes": [ - {"origin": [-2.5, 6, -2.5], "size": [5, 1, 0], "uv": [19, 17]} - ] - }, - { - "name": "spines_top_back", - "parent": "body", - "bind_pose_rotation": [-45, 0, 0], - "pivot": [0, 6, 2.5], - "cubes": [ - {"origin": [-2.5, 6, 2.5], "size": [5, 1, 0], "uv": [11, 17]} - ] - }, - { - "name": "spines_bottom_front", - "parent": "body", - "bind_pose_rotation": [-45, 0, 0], - "pivot": [0, 1, -2.5], - "cubes": [ - {"origin": [-2.5, 0, -2.5], "size": [5, 1, 0], "uv": [18, 20]} - ] - }, - { - "name": "spines_bottom_back", - "parent": "body", - "bind_pose_rotation": [45, 0, 0], - "pivot": [0, 1, 2.5], - "rotation": [45, 0, 0], - "cubes": [ - {"origin": [-2.5, 0, 2.5], "size": [5, 1, 0], "uv": [18, 20]} - ] - }, - { - "name": "spines_left_front", - "parent": "body", - "bind_pose_rotation": [0, 45, 0], - "pivot": [2.5, 0, -2.5], - "rotation": [0, 45, 0], - "cubes": [ - {"origin": [2.5, 1, -2.5], "size": [1, 5, 0], "uv": [1, 17]} - ] - }, - { - "name": "spines_left_back", - "parent": "body", - "bind_pose_rotation": [0, -45, 0], - "pivot": [2.5, 0, 2.5], - "rotation": [0, -45, 0], - "cubes": [ - {"origin": [2.5, 1, 2.5], "size": [1, 5, 0], "uv": [1, 17]} - ] - }, - { - "name": "spines_right_front", - "parent": "body", - "bind_pose_rotation": [0, -45, 0], - "pivot": [-2.5, 0, -2.5], - "rotation": [0, -45, 0], - "cubes": [ - {"origin": [-3.5, 1, -2.5], "size": [1, 5, 0], "uv": [5, 17]} - ] - }, - { - "name": "spines_right_back", - "parent": "body", - "bind_pose_rotation": [0, 45, 0], - "pivot": [-2.5, 0, 2.5], - "rotation": [0, 45, 0], - "cubes": [ - {"origin": [-3.5, 1, 2.5], "size": [1, 5, 0], "uv": [9, 17]} - ] - } - ] - }, - "large": { - "visible_bounds_width": 0.5, - "visible_bounds_height": 0.5, - "texturewidth": 32, - "textureheight": 32, - "bones": [ - { - "name": "body", - "cubes": [{"origin": [-4, 0, -4], "size": [8, 8, 8], "uv": [0, 0]}] - }, - { - "name": "leftFin", - "parent": "body", - "pivot": [4, 7, 1], - "cubes": [ - {"origin": [4, 6, -2.9904], "size": [2, 1, 2], "uv": [24, 3]} - ] - }, - { - "name": "rightFin", - "parent": "body", - "pivot": [-4, 7, 1], - "cubes": [ - {"origin": [-5.9968, 6, -2.992], "size": [2, 1, 2], "uv": [24, 0]} - ] - }, - { - "name": "spines_top_front", - "parent": "body", - "pivot": [-4, 8, -4], - "bind_pose_rotation": [45, 0, 0], - "cubes": [ - {"origin": [-4, 8, -4], "size": [8, 1, 1], "uv": [14, 16]} - ] - }, - { - "name": "spines_top_mid", - "parent": "body", - "pivot": [0, 8, 0], - "cubes": [{"origin": [-4, 8, 0], "size": [8, 1, 1], "uv": [14, 16]}] - }, - { - "name": "spines_top_back", - "parent": "body", - "pivot": [0, 8, 4], - "bind_pose_rotation": [-45, 0, 0], - "cubes": [{"origin": [-4, 8, 4], "size": [8, 1, 1], "uv": [14, 16]}] - }, - { - "name": "spines_bottom_front", - "parent": "body", - "pivot": [0, 0, -4], - "bind_pose_rotation": [-45, 0, 0], - "cubes": [ - {"origin": [-4, -1, -4], "size": [8, 1, 1], "uv": [14, 19]} - ] - }, - { - "name": "spines_bottom_mid", - "parent": "body", - "pivot": [0, -1, 0], - "cubes": [ - {"origin": [-4, -1, 0], "size": [8, 1, 1], "uv": [14, 19]} - ] - }, - { - "name": "spines_bottom_back", - "parent": "body", - "pivot": [0, 0, 4], - "bind_pose_rotation": [45, 0, 0], - "cubes": [ - {"origin": [-4, -1, 4], "size": [8, 1, 1], "uv": [14, 19]} - ] - }, - { - "name": "spines_left_front", - "parent": "body", - "pivot": [4, 0, -4], - "bind_pose_rotation": [0, 45, 0], - "cubes": [{"origin": [4, 0, -4], "size": [1, 8, 1], "uv": [0, 16]}] - }, - { - "name": "spines_left_mid", - "parent": "body", - "pivot": [4, 0, 0], - "cubes": [ - { - "origin": [4, 0, 0], - "size": [1, 8, 1], - "uv": [4, 16], - "mirror": true - } - ] - }, - { - "name": "spines_left_back", - "parent": "body", - "pivot": [4, 0, 4], - "bind_pose_rotation": [0, -45, 0], - "cubes": [ - { - "origin": [4, 0, 4], - "size": [1, 8, 1], - "uv": [8, 16], - "mirror": true - } - ] - }, - { - "name": "spines_right_front", - "parent": "body", - "pivot": [-4, 0, -4], - "bind_pose_rotation": [0, -45, 0], - "cubes": [{"origin": [-5, 0, -4], "size": [1, 8, 1], "uv": [4, 16]}] - }, - { - "name": "spines_right_mid", - "parent": "body", - "pivot": [-4, 0, 0], - "cubes": [{"origin": [-5, 0, 0], "size": [1, 8, 1], "uv": [8, 16]}] - }, - { - "name": "spines_right_back", - "parent": "body", - "pivot": [-4, 0, 4], - "bind_pose_rotation": [0, 45, 0], - "cubes": [{"origin": [-5, 0, 4], "size": [1, 8, 1], "uv": [8, 16]}] - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.ZRot = !query.is_in_water ? Math.cos(query.time_stamp * 14.32) * 90 : 0.0;", - "variable.AnimationAmountBlend = Math.lerp(variable.AnimationAmountPrev, variable.AnimationAmount, query.frame_alpha);" - ], - "animate": ["general"] - }, - "animations": { - "flop": { - "loop": true, - "bones": { - "body": {"rotation": [0, 0, "variable.zrot"]}, - "tailfin": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 45.0) * -5.75", - 0 - ] - } - } - }, - "swim": { - "loop": true, - "bones": { - "tailfin": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 30.0) * -5.75", - 0 - ] - } - } - } - }, - "render_controllers": [ - {"controller.render.pufferfish.small": "query.variant == 0"}, - {"controller.render.pufferfish.medium": "query.variant == 1"}, - {"controller.render.pufferfish.large": "query.variant == 2"} - ], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 46}, - "animation_controllers": { - "general": { - "initial_state": "flopping", - "states": { - "flopping": { - "animations": ["flop"], - "transitions": [ - {"swimming": "query.is_in_water || query.is_levitating"} - ] - }, - "swimming": { - "animations": ["swim"], - "transitions": [ - {"flopping": "!query.is_in_water && !query.is_levitating"} - ] - } - } - } - } - }, - "rabbit": { - "identifier": "minecraft:rabbit", - "min_engine_version": "1.8.0", - "materials": {"default": "rabbit"}, - "textures": { - "brown": "textures/entity/rabbit/brown", - "white": "textures/entity/rabbit/white", - "black": "textures/entity/rabbit/black", - "white_splotched": "textures/entity/rabbit/white_splotched", - "gold": "textures/entity/rabbit/gold", - "salt": "textures/entity/rabbit/salt", - "toast": "textures/entity/rabbit/toast" - }, - "geometry": { - "default": { - "visible_bounds_width": 1, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "rearFootLeft", - "pivot": [3, 6.5, 3.7], - "mirror": true, - "parent": "body", - "cubes": [{"origin": [2, 0, 0], "size": [2, 1, 7], "uv": [8, 24]}] - }, - { - "name": "rearFootRight", - "pivot": [-3, 6.5, 3.7], - "mirror": true, - "parent": "body", - "cubes": [{"origin": [-4, 0, 0], "size": [2, 1, 7], "uv": [26, 24]}] - }, - { - "name": "haunchLeft", - "pivot": [3, 6.5, 3.7], - "bind_pose_rotation": [-20, 0, 0], - "mirror": true, - "parent": "body", - "cubes": [ - {"origin": [2, 2.5, 3.7], "size": [2, 4, 5], "uv": [16, 15]} - ] - }, - { - "name": "haunchRight", - "pivot": [-3, 6.5, 3.7], - "bind_pose_rotation": [-20, 0, 0], - "mirror": true, - "parent": "body", - "cubes": [ - {"origin": [-4, 2.5, 3.7], "size": [2, 4, 5], "uv": [30, 15]} - ] - }, - { - "name": "body", - "pivot": [0, 5, 8], - "bind_pose_rotation": [-20, 0, 0], - "mirror": true, - "cubes": [{"origin": [-3, 2, -2], "size": [6, 5, 10], "uv": [0, 0]}] - }, - { - "name": "frontLegLeft", - "pivot": [3, 7, -1], - "bind_pose_rotation": [-10, 0, 0], - "mirror": true, - "parent": "body", - "cubes": [{"origin": [2, 0, -2], "size": [2, 7, 2], "uv": [8, 15]}] - }, - { - "name": "frontLegRight", - "pivot": [-3, 7, -1], - "bind_pose_rotation": [-10, 0, 0], - "mirror": true, - "parent": "body", - "cubes": [{"origin": [-4, 0, -2], "size": [2, 7, 2], "uv": [0, 15]}] - }, - { - "name": "head", - "pivot": [0, 8, -1], - "locators": {"lead": [0, 8, -1]}, - "mirror": true, - "parent": "body", - "cubes": [ - {"origin": [-2.5, 8, -6], "size": [5, 4, 5], "uv": [32, 0]} - ] - }, - { - "name": "earRight", - "pivot": [0, 8, -1], - "bind_pose_rotation": [0, -15, 0], - "mirror": true, - "parent": "body", - "cubes": [ - {"origin": [-2.5, 12, -2], "size": [2, 5, 1], "uv": [58, 0]} - ] - }, - { - "name": "earLeft", - "pivot": [0, 8, -1], - "bind_pose_rotation": [0, 15, 0], - "mirror": true, - "parent": "body", - "cubes": [ - {"origin": [0.5, 12, -2], "size": [2, 5, 1], "uv": [52, 0]} - ] - }, - { - "name": "tail", - "pivot": [0, 4, 7], - "bind_pose_rotation": [-20, 0, 0], - "mirror": true, - "parent": "body", - "cubes": [ - {"origin": [-1.5, 2.5, 7], "size": [3, 3, 2], "uv": [52, 6]} - ] - }, - { - "name": "nose", - "pivot": [0, 8, -1], - "mirror": true, - "parent": "body", - "cubes": [ - {"origin": [-0.5, 9.5, -6.5], "size": [1, 1, 1], "uv": [32, 9]} - ] - } - ] - } - }, - "animations": { - "move": { - "loop": true, - "bones": { - "earleft": { - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this + 15.0", - 0 - ] - }, - "earright": { - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this - 15.0", - 0 - ] - }, - "frontlegleft": { - "rotation": ["variable.jump_rotation * -40.0 - 11.0 - this", 0, 0] - }, - "frontlegright": { - "rotation": ["variable.jump_rotation * -40.0 - 11.0 - this", 0, 0] - }, - "haunchleft": { - "rotation": ["variable.jump_rotation * 50.0 - 21.0 - this", 0, 0] - }, - "haunchright": { - "rotation": ["variable.jump_rotation * 50.0 - 21.0 - this", 0, 0] - }, - "nose": { - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - }, - "rearfootleft": { - "rotation": ["variable.jump_rotation * 50.0 - this", 0, 0] - }, - "rearfootright": { - "rotation": ["variable.jump_rotation * 50.0 - this", 0, 0] - } - } - }, - "baby_transform": { - "loop": true, - "bones": { - "earleft": {"position": [0, -1, 1], "scale": 1.5}, - "earright": {"position": [0, -1, 1], "scale": 1.5}, - "head": {"position": [0, -1, 1], "scale": 1.5}, - "nose": {"position": [0, -1, 1], "scale": 1.5} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - } - }, - "animation_controllers": { - "general": { - "initial_state": "default", - "states": {"default": {"animations": ["move", "look_at_target"]}} - }, - "baby": { - "initial_state": "baby", - "states": { - "baby": {"animations": [{"baby_transform": "query.is_baby"}]} - } - } - }, - "render_controllers": ["controller.render.rabbit"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 24} - }, - "ravager": { - "identifier": "minecraft:ravager", - "textures": {"default": "textures/entity/illager/ravager"}, - "materials": {"default": "ravager"}, - "geometry": { - "default": { - "bones": [ - { - "pivot": [0, 19, 2], - "rotation": [90, 0, 0], - "cubes": [ - {"origin": [-7, 10, -2], "size": [14, 16, 20], "uv": [0, 55]}, - {"origin": [-6, -3, -2], "size": [12, 13, 18], "uv": [0, 91]} - ], - "name": "body" - }, - { - "pivot": [0, 15, -10], - "cubes": [ - {"origin": [-8, 13, -24], "size": [16, 3, 16], "uv": [0, 36]} - ], - "name": "mouth", - "parent": "head" - }, - { - "pivot": [0, 20, -20], - "cubes": [ - {"origin": [-5, 21, -10], "size": [10, 10, 18], "uv": [68, 73]} - ], - "name": "neck" - }, - { - "locators": {"stun": [0, 32, -15]}, - "pivot": [0, 28, -10], - "cubes": [ - {"origin": [-8, 14, -24], "size": [16, 20, 16], "uv": [0, 0]}, - {"origin": [-2, 12, -28], "size": [4, 8, 4], "uv": [0, 0]} - ], - "name": "head", - "parent": "neck" - }, - { - "pivot": [-12, 30, 22], - "cubes": [ - {"origin": [-12, 0, 17], "size": [8, 37, 8], "uv": [96, 0]} - ], - "name": "leg0" - }, - { - "pivot": [4, 30, 22], - "cubes": [ - {"origin": [4, 0, 17], "size": [8, 37, 8], "uv": [96, 0]} - ], - "name": "leg1" - }, - { - "pivot": [-4, 26, -4], - "cubes": [ - {"origin": [-12, 0, -8], "size": [8, 37, 8], "uv": [64, 0]} - ], - "name": "leg2" - }, - { - "pivot": [-4, 26, -4], - "cubes": [ - {"origin": [4, 0, -8], "size": [8, 37, 8], "uv": [64, 0]} - ], - "name": "leg3" - }, - { - "pivot": [-5, 27, -19], - "rotation": [60, 0, 0], - "cubes": [ - {"origin": [-10, 27, -20], "size": [2, 14, 4], "uv": [74, 55]}, - {"origin": [8, 27, -20], "size": [2, 14, 4], "uv": [74, 55]} - ], - "name": "horns", - "parent": "head" - } - ], - "texturewidth": 128, - "textureheight": 128, - "visible_bounds_width": 4, - "visible_bounds_height": 3.5, - "visible_bounds_offset": [0, 1.25, 0] - } - }, - "render_controllers": ["controller.render.ravager"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 57}, - "animations": { - "walk": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": ["math.cos(query.anim_time * 38.17) * 22.92", 0, 0] - }, - "leg1": { - "rotation": ["math.cos(query.anim_time * 38.17) * -22.92", 0, 0] - }, - "leg2": { - "rotation": ["math.cos(query.anim_time * 38.17) * -22.92", 0, 0] - }, - "leg3": { - "rotation": ["math.cos(query.anim_time * 38.17) * 22.92", 0, 0] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "idle_mouth": { - "loop": true, - "bones": { - "mouth": {"rotation": [1.8, 0, 0]}, - "neck": {"position": [0, 0, 0]} - } - }, - "stunned": { - "loop": true, - "bones": { - "neck": { - "position": ["math.sin(query.life_time * 180.0) * 2.8", -5, 0], - "rotation": [15, 0, 0] - } - } - }, - "roaring": { - "loop": true, - "bones": { - "mouth": { - "rotation": [ - "math.sin(math.min(query.anim_time / variable.roar_length, 1.0) * 180) * 40.0", - 0, - 0 - ] - } - } - }, - "biting": { - "loop": true, - "bones": { - "mouth": { - "rotation": [ - "math.sin(math.min(query.anim_time / (variable.bite_anim_duration / 2.0f), 1.0f) * 180.0f) * 40.0f", - 0, - 0 - ] - }, - "neck": { - "position": [ - 0, - 0, - "-math.sin(math.min(query.anim_time / variable.bite_anim_duration, 1.0f) * 180.0f) * variable.bite_neck_length" - ] - } - } - } - }, - "scripts": { - "pre_animation": [ - "variable.roar_length = 1.0;", - "variable.bite_anim_duration = 0.75f;", - "variable.bite_neck_length = 10;" - ], - "animate": ["move", "head"] - }, - "particle_effects": {"stun_particles": "minecraft:stunned_emitter"}, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": { - "default": { - "animations": [ - {"walk": "query.modified_move_speed"}, - "look_at_target" - ], - "transitions": [{"stunned": "query.is_stunned == 1"}] - }, - "stunned": { - "animations": ["stunned"], - "particle_effects": [ - {"effect": "stun_particles", "locator": "stun"} - ], - "transitions": [{"default": "query.is_stunned == 0"}] - } - } - }, - "head": { - "initial_state": "default", - "states": { - "biting": { - "animations": ["biting"], - "transitions": [{"default": "query.is_delayed_attacking == 0"}] - }, - "default": { - "animations": ["idle_mouth"], - "transitions": [ - {"roaring": "query.is_roaring == 1"}, - {"biting": "query.is_delayed_attacking == 1"} - ] - }, - "roaring": { - "animations": ["roaring"], - "transitions": [{"default": "query.is_roaring == 0"}] - } - } - } - } - }, - "salmon": { - "identifier": "minecraft:salmon", - "materials": {"default": "salmon"}, - "textures": {"default": "textures/entity/fish/salmon"}, - "geometry": { - "default": { - "visible_bounds_width": 0.5, - "visible_bounds_height": 0.5, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 32, - "textureheight": 32, - "bones": [ - { - "name": "body_front", - "pivot": [0, 0, -4], - "cubes": [ - {"origin": [-1.5, 3.5, -4], "size": [3, 5, 8], "uv": [0, 0]} - ] - }, - { - "name": "body_back", - "parent": "body_front", - "pivot": [0, 0, 4], - "cubes": [ - {"origin": [-1.5, 3.5, 4], "size": [3, 5, 8], "uv": [0, 13]} - ] - }, - { - "name": "dorsal_front", - "parent": "body_front", - "pivot": [0, 5, 2], - "cubes": [{"origin": [0, 8.5, 2], "size": [0, 2, 2], "uv": [4, 2]}] - }, - { - "name": "dorsal_back", - "parent": "body_back", - "pivot": [0, 5, 4], - "cubes": [{"origin": [0, 8.5, 4], "size": [0, 2, 3], "uv": [2, 3]}] - }, - { - "name": "tailfin", - "parent": "body_back", - "pivot": [0, 0, 12], - "cubes": [ - {"origin": [0, 3.5, 12], "size": [0, 5, 6], "uv": [20, 10]} - ] - }, - { - "name": "head", - "parent": "body_front", - "pivot": [0, 3, -4], - "locators": {"lead": [0, 3, -4]}, - "cubes": [ - {"origin": [-1, 4.5, -7], "size": [2, 4, 3], "uv": [22, 0]} - ] - }, - { - "name": "leftFin", - "parent": "body_front", - "pivot": [1.5, 1, -4], - "rotation": [0, 0, 35], - "cubes": [ - { - "origin": [-0.50752, 3.86703, -4], - "size": [2, 0, 2], - "uv": [2, 0] - } - ] - }, - { - "name": "rightFin", - "parent": "body_front", - "pivot": [-1.5, 1, -4], - "rotation": [0, 0, -35], - "cubes": [ - { - "origin": [-1.49258, 3.86703, -4], - "size": [2, 0, 2], - "uv": [-2, 0] - } - ] - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.ZRot = !query.is_in_water ? Math.cos((query.time_stamp + query.frame_alpha) * 14.32) * 90 : 0.0;", - "variable.AnimationAmountBlend = Math.lerp(variable.AnimationAmountPrev, variable.AnimationAmount, query.frame_alpha);" - ] - }, - "animations": { - "flop": { - "loop": true, - "bones": { - "body_back": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 45.0) * -21.75", - 0 - ] - }, - "body_front": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 45.0) * 4.0", - "variable.zrot" - ] - }, - "tailfin": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 45.0) * -40.0", - 0 - ] - } - } - }, - "swim": { - "loop": true, - "bones": { - "body_back": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 30.0) * -21.75", - 0 - ] - }, - "body_front": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 30.0) * 4.0", - 0 - ] - }, - "tailfin": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 30.0) * -40.0", - 0 - ] - } - } - } - }, - "animation_controllers": { - "general": { - "initial_state": "flopping", - "states": { - "flopping": { - "animations": ["flop"], - "transitions": [ - {"swimming": "query.is_in_water || query.is_levitating"} - ] - }, - "swimming": { - "animations": ["swim"], - "transitions": [ - {"flopping": "!query.is_in_water && !query.is_levitating"} - ] - } - } - } - }, - "render_controllers": ["controller.render.salmon"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 47} - }, - "sheep": { - "identifier": "minecraft:sheep", - "min_engine_version": "1.8.0", - "materials": {"default": "sheep"}, - "textures": { - "default": "textures/entity/sheep/sheep_fur", - "sheared": "textures/entity/sheep/sheep" - }, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 1.75, - "visible_bounds_offset": [0, 0.5, 0], - "bones": [ - { - "name": "head", - "pivot": [0, 18, -8], - "cubes": [ - { - "origin": [-3, 16, -12], - "size": [6, 6, 6], - "uv": [0, 32], - "inflate": 0.6 - } - ] - }, - { - "name": "body", - "pivot": [0, 19, 2], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - { - "origin": [-4, 13, -5], - "size": [8, 16, 6], - "uv": [28, 40], - "inflate": 1.75 - } - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-3, 12, 7], - "cubes": [ - { - "origin": [-5, 6, 5], - "size": [4, 6, 4], - "uv": [0, 48], - "inflate": 0.5 - } - ] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [3, 12, 7], - "cubes": [ - { - "origin": [1, 6, 5], - "size": [4, 6, 4], - "uv": [0, 48], - "inflate": 0.5 - } - ] - }, - { - "name": "leg2", - "parent": "body", - "pivot": [-3, 12, -5], - "cubes": [ - { - "origin": [-5, 6, -7], - "size": [4, 6, 4], - "uv": [0, 48], - "inflate": 0.5 - } - ] - }, - { - "name": "leg3", - "parent": "body", - "pivot": [3, 12, -5], - "cubes": [ - { - "origin": [1, 6, -7], - "size": [4, 6, 4], - "uv": [0, 48], - "inflate": 0.5 - } - ] - } - ] - }, - "sheared": { - "visible_bounds_width": 2, - "visible_bounds_height": 1.75, - "visible_bounds_offset": [0, 0.5, 0], - "bones": [ - { - "name": "body", - "pivot": [0, 19, 2], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-4, 13, -5], "size": [8, 16, 6], "uv": [28, 8]} - ] - }, - { - "name": "head", - "pivot": [0, 18, -8], - "locators": {"lead": [0, 18, -8]}, - "cubes": [ - {"origin": [-3, 16, -14], "size": [6, 6, 8], "uv": [0, 0]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-3, 12, 7], - "cubes": [{"origin": [-5, 0, 5], "size": [4, 12, 4], "uv": [0, 16]}] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [3, 12, 7], - "cubes": [{"origin": [1, 0, 5], "size": [4, 12, 4], "uv": [0, 16]}] - }, - { - "name": "leg2", - "parent": "body", - "pivot": [-3, 12, -5], - "cubes": [ - {"origin": [-5, 0, -7], "size": [4, 12, 4], "uv": [0, 16]} - ] - }, - { - "name": "leg3", - "parent": "body", - "pivot": [3, 12, -5], - "cubes": [{"origin": [1, 0, -7], "size": [4, 12, 4], "uv": [0, 16]}] - } - ] - } - }, - "animations": { - "setup": { - "loop": true, - "bones": { - "body": {"rotation": ["-this", 0, 0]}, - "head": {"position": [0, "-6.0 - this", 0]} - } - }, - "grazing": { - "animation_length": 2, - "loop": true, - "bones": { - "head": { - "position": { - "0": [0, 0, 0], - "2": [0, 0, 0], - "0.2": [0, -9, 0], - "1.8": [0, -9, 0] - }, - "rotation": { - "0.2": { - "post": [ - "180.0 * (0.2 + 0.07 * math.sin(query.key_frame_lerp_time * 1644.39))", - 0, - 0 - ], - "pre": [36, 0, 0] - }, - "1.8": { - "post": [36, 0, 0], - "pre": [ - "180.0 * (0.2 + 0.07 * math.sin(query.key_frame_lerp_time * 1644.39))", - 0, - 0 - ] - } - } - } - } - }, - "walk": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - }, - "leg1": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg2": { - "rotation": ["math.cos(query.anim_time * 38.17) * -80.0", 0, 0] - }, - "leg3": { - "rotation": ["math.cos(query.anim_time * 38.17) * 80.0", 0, 0] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "baby_transform": { - "loop": true, - "bones": {"head": {"position": [0, 4, 4], "scale": 2}} - } - }, - "scripts": { - "animate": [ - "setup", - "look_at_target", - "move", - {"baby_transform": "query.is_baby"} - ] - }, - "render_controllers": ["controller.render.sheep"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 3}, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": { - "default": { - "animations": [{"walk": "query.modified_move_speed"}], - "transitions": [{"grazing": "query.is_grazing"}] - }, - "grazing": { - "animations": ["grazing"], - "transitions": [{"default": "query.all_animations_finished"}] - } - } - } - } - }, - "shulker": { - "identifier": "minecraft:shulker", - "min_engine_version": "1.8.0", - "materials": {"default": "shulker"}, - "textures": { - "undyed": "textures/entity/shulker/shulker", - "white": "textures/entity/shulker/shulker_white", - "orange": "textures/entity/shulker/shulker_orange", - "magenta": "textures/entity/shulker/shulker_magenta", - "light_blue": "textures/entity/shulker/shulker_light_blue", - "yellow": "textures/entity/shulker/shulker_yellow", - "lime": "textures/entity/shulker/shulker_lime", - "pink": "textures/entity/shulker/shulker_pink", - "gray": "textures/entity/shulker/shulker_gray", - "silver": "textures/entity/shulker/shulker_light_gray", - "cyan": "textures/entity/shulker/shulker_cyan", - "purple": "textures/entity/shulker/shulker_purple", - "blue": "textures/entity/shulker/shulker_blue", - "brown": "textures/entity/shulker/shulker_brown", - "green": "textures/entity/shulker/shulker_green", - "red": "textures/entity/shulker/shulker_red", - "black": "textures/entity/shulker/shulker_black" - }, - "geometry": { - "default": { - "visible_bounds_width": 3, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "lid", - "parent": "base", - "pivot": [0, 0, 0], - "cubes": [ - {"origin": [-8, 4, -8], "size": [16, 12, 16], "uv": [0, 0]} - ] - }, - { - "name": "base", - "pivot": [0, 0, 0], - "cubes": [ - {"origin": [-8, 0, -8], "size": [16, 8, 16], "uv": [0, 28]} - ] - }, - { - "name": "head", - "parent": "base", - "pivot": [0, 12, 0], - "cubes": [{"origin": [-3, 6, -3], "size": [6, 6, 6], "uv": [0, 52]}] - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 34}, - "scripts": { - "pre_animation": [ - "variable.Shulker.LidPositionFactor = 180 * (0.5 + variable.Shulker.PeekAmount);", - "variable.Shulker.LidRotationFactor = -1 + Math.sin(180 * (0.5 + variable.Shulker.PeekAmount));", - "variable.Shulker.UpFacing = variable.Shulker.FacingDirection == 1;", - "variable.Shulker.NorthFacing = variable.Shulker.FacingDirection == 2;", - "variable.Shulker.SouthFacing = variable.Shulker.FacingDirection == 3;", - "variable.Shulker.WestFacing = variable.Shulker.FacingDirection == 4;", - "variable.Shulker.EastFacing = variable.Shulker.FacingDirection == 5;", - "variable.Shulker.XPreRotation = variable.Shulker.UpFacing * 180 + variable.Shulker.NorthFacing * 90 - variable.Shulker.SouthFacing * 90;", - "variable.Shulker.ZPreRotation = variable.Shulker.NorthFacing * 180 + variable.Shulker.WestFacing * 90 - variable.Shulker.EastFacing * 90;", - "variable.Shulker.XOffset = -variable.Shulker.WestFacing * 7.99 + variable.Shulker.EastFacing * 7.99;", - "variable.Shulker.YOffset = variable.Shulker.UpFacing * 16 + variable.Shulker.NorthFacing * 7.99 + variable.Shulker.SouthFacing * 7.99 + variable.Shulker.WestFacing * 7.99 + variable.Shulker.EastFacing * 7.99;", - "variable.Shulker.ZOffset = variable.Shulker.NorthFacing * 7.99 - variable.Shulker.SouthFacing * 7.99;" - ] - }, - "animations": { - "facing": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "base": { - "position": [ - "variable.shulker.xoffset", - "variable.shulker.yoffset", - "variable.shulker.zoffset" - ], - "rotation": [ - "variable.shulker.xprerotation", - 0, - "variable.shulker.zprerotation" - ], - "scale": 0.98 - } - } - }, - "move": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "head": { - "position": [ - 0, - "-variable.shulker.upfacing * 6 - (3 * (variable.shulker.northfacing + variable.shulker.southfacing + variable.shulker.westfacing + variable.shulker.eastfacing))", - 0 - ] - }, - "lid": { - "position": [ - 0, - "7.2 - math.sin(variable.shulker.lidpositionfactor * 1.16) * 7.5 + (variable.shulker.lidpositionfactor > 180 ? math.sin(query.life_time * 114.6) * 0.7 + 1.5: 0.0)", - 0 - ], - "rotation": [ - 0, - "variable.shulker.peekamount > 0.3 ? math.pow(variable.shulker.lidrotationfactor, 4) * 22.5 : 0.0", - 0 - ] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - } - }, - "animation_controllers": { - "facing": { - "initial_state": "default", - "states": {"default": {"animations": ["facing"]}} - }, - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move", "look_at_target"]}} - } - }, - "render_controllers": ["controller.render.shulker"] - }, - "shulker_bullet": { - "identifier": "minecraft:shulker_bullet", - "materials": {"default": "shulker_bullet"}, - "textures": {"default": "textures/entity/shulker/spark"}, - "geometry": { - "default": { - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "body", - "pivot": [0, 0, 0], - "cubes": [ - {"origin": [-4, -4, -1], "size": [8, 8, 2], "uv": [0, 0]}, - {"origin": [-1, -4, -4], "size": [2, 8, 8], "uv": [0, 10]}, - {"origin": [-4, -1, -4], "size": [8, 2, 8], "uv": [20, 0]} - ] - } - ] - } - }, - "animations": { - "move": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "math.cos(query.life_time * 120) * 180", - "math.sin(query.life_time * 120) * 180", - "math.sin(query.life_time * 170) * 360" - ] - } - } - } - }, - "scripts": {"animate": ["move"]}, - "render_controllers": ["controller.render.shulker_bullet"] - }, - "silverfish": { - "identifier": "minecraft:silverfish", - "materials": {"default": "silverfish", "body_layer": "silverfish_layers"}, - "textures": {"default": "textures/entity/silverfish"}, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "bodyPart_0", - "parent": "bodyPart_2", - "pivot": [0, 2, -3.5], - "cubes": [ - {"origin": [-1.5, 0, -4.5], "size": [3, 2, 2], "uv": [0, 0]} - ] - }, - { - "name": "bodyPart_1", - "parent": "bodyPart_2", - "pivot": [0, 3, -1.5], - "cubes": [ - {"origin": [-2, 0, -2.5], "size": [4, 3, 2], "uv": [0, 4]} - ] - }, - { - "name": "bodyPart_2", - "pivot": [0, 4, 1], - "cubes": [ - {"origin": [-3, 0, -0.5], "size": [6, 4, 3], "uv": [0, 9]} - ] - }, - { - "name": "bodyPart_3", - "parent": "bodyPart_2", - "pivot": [0, 3, 4], - "cubes": [ - {"origin": [-1.5, 0, 2.5], "size": [3, 3, 3], "uv": [0, 16]} - ] - }, - { - "name": "bodyPart_4", - "parent": "bodyPart_2", - "pivot": [0, 2, 7], - "cubes": [ - {"origin": [-1, 0, 5.5], "size": [2, 2, 3], "uv": [0, 22]} - ] - }, - { - "name": "bodyPart_5", - "parent": "bodyPart_2", - "pivot": [0, 1, 9.5], - "cubes": [ - {"origin": [-1, 0, 8.5], "size": [2, 1, 2], "uv": [11, 0]} - ] - }, - { - "name": "bodyPart_6", - "parent": "bodyPart_2", - "pivot": [0, 1, 11.5], - "cubes": [ - {"origin": [-0.5, 0, 10.5], "size": [1, 1, 2], "uv": [13, 4]} - ] - }, - { - "name": "bodyLayer_0", - "parent": "bodyPart_2", - "pivot": [0, 8, 1], - "cubes": [ - {"origin": [-5, 0, -0.5], "size": [10, 8, 3], "uv": [20, 0]} - ] - }, - { - "name": "bodyLayer_1", - "parent": "bodyPart_4", - "pivot": [0, 4, 7], - "cubes": [ - {"origin": [-3, 0, 5.5], "size": [6, 4, 3], "uv": [20, 11]} - ] - }, - { - "name": "bodyLayer_2", - "parent": "bodyPart_1", - "pivot": [0, 5, -1.5], - "cubes": [ - {"origin": [-3, 0, -3], "size": [6, 5, 2], "uv": [20, 18]} - ] - } - ] - } - }, - "animations": { - "move": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "bodypart_0": { - "position": ["math.sin(query.life_time * 1031.4) * 1.26", 0, 0], - "rotation": [0, "math.cos(query.life_time * 1031.4) * 27", 0] - }, - "bodypart_1": { - "position": [ - "math.sin(query.life_time * 1031.4 + 27) * 0.63", - 0, - 0 - ], - "rotation": [0, "math.cos(query.life_time * 1031.4 + 27) * 18", 0] - }, - "bodypart_2": { - "rotation": [0, "math.cos(query.life_time * 1031.4 + 54) * 9", 0] - }, - "bodypart_3": { - "position": [ - "math.sin(query.life_time * 1031.4 + 81) * 0.63", - 0, - 0 - ], - "rotation": [0, "math.cos(query.life_time * 1031.4 + 81) * 18", 0] - }, - "bodypart_4": { - "position": [ - "math.sin(query.life_time * 1031.4 + 108) * 1.26", - 0, - 0 - ], - "rotation": [0, "math.cos(query.life_time * 1031.4 + 108) * 27", 0] - }, - "bodypart_5": { - "position": [ - "math.sin(query.life_time * 1031.4 + 135) * 1.89", - 0, - 0 - ], - "rotation": [0, "math.cos(query.life_time * 1031.4 + 135) * 36", 0] - }, - "bodypart_6": { - "position": [ - "math.sin(query.life_time * 1031.4 + 162) * 2.52", - 0, - 0 - ], - "rotation": [0, "math.cos(query.life_time * 1031.4 + 162) * 45", 0] - } - } - } - }, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - } - }, - "render_controllers": ["controller.render.silverfish"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 8} - }, - "skeleton": { - "identifier": "minecraft:skeleton", - "min_engine_version": "1.8.0", - "materials": {"default": "skeleton"}, - "textures": {"default": "textures/entity/skeleton/skeleton"}, - "geometry": { - "default": { - "texturewidth": 64, - "textureheight": 32, - "visible_bounds_width": 2, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "bones": [ - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} - ], - "parent": "waist" - }, - {"name": "waist", "pivot": [0, 12, 0]}, - { - "name": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]} - ], - "parent": "body" - }, - { - "name": "hat", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 8, 8], - "uv": [32, 0], - "inflate": 0.5 - } - ], - "neverRender": true, - "parent": "head" - }, - { - "name": "rightArm", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-6, 12, -1], "size": [2, 12, 2], "uv": [40, 16]} - ], - "parent": "body" - }, - { - "name": "rightItem", - "pivot": [-6, 15, 1], - "neverRender": true, - "parent": "rightArm" - }, - { - "name": "leftArm", - "pivot": [5, 22, 0], - "cubes": [ - {"origin": [4, 12, -1], "size": [2, 12, 2], "uv": [40, 16]} - ], - "mirror": true, - "parent": "body" - }, - { - "name": "leftItem", - "pivot": [6, 15, 1], - "neverRender": true, - "parent": "leftArm" - }, - { - "name": "rightLeg", - "pivot": [-2, 12, 0], - "cubes": [ - {"origin": [-3, 0, -1], "size": [2, 12, 2], "uv": [0, 16]} - ], - "parent": "body" - }, - { - "name": "leftLeg", - "pivot": [2, 12, 0], - "cubes": [ - {"origin": [1, 0, -1], "size": [2, 12, 2], "uv": [0, 16]} - ], - "mirror": true, - "parent": "body" - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 9}, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;" - ] - }, - "animations": { - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "move": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - }, - "holding": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - } - } - }, - "brandish_spear": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "this * -0.5 - 157.5 - 22.5 * variable.charge_amount", - "-this", - 0 - ] - } - } - }, - "charging": { - "loop": true, - "bones": { - "rightarm": { - "rotation": ["22.5 * variable.charge_amount - this", "-this", 0] - } - } - }, - "attack.rotations": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46 - this", - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.sin(1.0 - math.pow(1.0 - variable.attack_time, 3.0) * 180.0) * (variable.is_brandishing_spear ? -1.0 : 1.0 )", - "variable.is_brandishing_spear ? 0.0 : (math.sin(math.sqrt(variable.attack_time) * 360) * 11.46) * 2.0", - 0 - ] - } - } - }, - "sneaking": { - "loop": true, - "bones": { - "body": {"rotation": ["0.5 - this", 0, 0]}, - "head": {"position": [0, 1, 0]}, - "leftarm": {"rotation": [72, 0, 0]}, - "leftleg": {"position": [0, -3, 4]}, - "rightarm": {"rotation": [72, 0, 0]}, - "rightleg": {"position": [0, -3, 4]} - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "damage_nearby_mobs": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["-45.0-this", "-this", "-this"]}, - "leftleg": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightarm": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-45.0-this", "-this", "-this"]} - } - }, - "bow_and_arrow": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "query.target_x_rotation - 90.0 - math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation + 28.65", - "-(math.cos(query.life_time * 103.2) * 2.865) - 2.865" - ] - }, - "rightarm": { - "rotation": [ - "query.target_x_rotation - 90.0 + math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation - 5.73", - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "swimming": { - "loop": true, - "bones": { - "body": { - "position": [ - 0, - "variable.swim_amount * -10.0 - this", - "variable.swim_amount * 9.0 - this" - ], - "rotation": [ - "variable.swim_amount * (90.0 + query.target_x_rotation)", - 0, - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) - (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, 14.325, variable.swim_amount) - (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "leftleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0 + 180.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) + (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, -14.325, variable.swim_amount) + (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "rightleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - } - } - }, - "use_item_progress": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "variable.use_item_startup_progress * -60.0 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -22.5 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -5.625 + variable.use_item_interval_progress * 11.25" - ] - } - } - }, - "skeleton_attack": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "-68.75 * math.sin(variable.attack_time * 180.0) + 22.92 * (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0))", - "5.73 - math.sin(variable.attack_time * 180.0) * 34.38 - this", - "-this" - ] - }, - "rightarm": { - "rotation": [ - "-68.75 * math.sin(variable.attack_time * 180.0) + 22.92 * (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0))", - "-5.73 + math.sin(variable.attack_time * 180.0) * 34.38 - this", - "-this" - ] - } - } - } - }, - "animation_controllers": { - "look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - }, - "riding": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"riding": "query.is_riding"}]}, - "riding": { - "animations": ["riding.arms", "riding.legs"], - "transitions": [{"default": "!query.is_riding"}] - } - } - }, - "holding": { - "initial_state": "default", - "states": {"default": {"animations": ["holding"]}} - }, - "brandish_spear": { - "initial_state": "default", - "states": { - "brandish_spear": { - "animations": ["brandish_spear"], - "transitions": [{"default": "!variable.is_brandishing_spear"}] - }, - "default": { - "transitions": [{"brandish_spear": "variable.is_brandishing_spear"}] - } - } - }, - "charging": { - "initial_state": "default", - "states": { - "charging": { - "animations": ["charging"], - "transitions": [{"default": "!query.is_charging"}] - }, - "default": {"transitions": [{"charging": "query.is_charging"}]} - } - }, - "attack": { - "initial_state": "default", - "states": { - "attacking": { - "animations": ["attack.rotations"], - "transitions": [{"default": "variable.attack_time < 0.0"}] - }, - "default": { - "transitions": [{"attacking": "variable.attack_time >= 0.0"}] - } - } - }, - "sneaking": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"sneaking": "query.is_sneaking"}]}, - "sneaking": { - "animations": ["sneaking"], - "transitions": [{"default": "!query.is_sneaking"}] - } - } - }, - "bob": { - "initial_state": "default", - "states": {"default": {"animations": ["bob"]}} - }, - "damage_nearby_mobs": { - "initial_state": "default", - "states": { - "damage_nearby_mobs": { - "animations": ["damage_nearby_mobs"], - "transitions": [{"default": "!variable.damage_nearby_mobs"}] - }, - "default": { - "transitions": [ - {"damage_nearby_mobs": "variable.damage_nearby_mobs"} - ] - } - } - }, - "bow_and_arrow": { - "initial_state": "default", - "states": { - "bow_and_arrow": { - "animations": ["bow_and_arrow"], - "transitions": [{"default": "!query.has_target"}] - }, - "default": {"transitions": [{"bow_and_arrow": "query.has_target"}]} - } - }, - "swimming": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"is_swimming": "variable.swim_amount > 0.0"}] - }, - "is_swimming": { - "animations": ["swimming"], - "transitions": [{"default": "variable.swim_amount <= 0.0"}] - } - } - }, - "use_item_progress": { - "initial_state": "default", - "states": { - "default": { - "transitions": [ - { - "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 )" - } - ] - }, - "use_item_progress": { - "animations": ["use_item_progress"], - "transitions": [ - { - "default": "( variable.use_item_interval_progress <= 0.0 ) && ( variable.use_item_startup_progress <= 0.0 )" - } - ] - } - } - }, - "skeleton_attack": { - "initial_state": "default", - "states": {"default": {"animations": ["skeleton_attack"]}} - } - }, - "render_controllers": ["controller.render.skeleton"], - "enable_attachables": true - }, - "skeleton_horse": { - "identifier": "minecraft:skeleton_horse", - "textures": { - "base_brown": "textures/entity/horse/horse_brown", - "base_white": "textures/entity/horse/horse_white", - "base_chestnut": "textures/entity/horse/horse_chestnut", - "base_creamy": "textures/entity/horse/horse_creamy", - "base_black": "textures/entity/horse/horse_black", - "base_gray": "textures/entity/horse/horse_gray", - "base_darkbrown": "textures/entity/horse/horse_darkbrown", - "markings_none": "textures/entity/horse/horse_markings_none", - "markings_white": "textures/entity/horse/horse_markings_white", - "markings_whitefield": "textures/entity/horse/horse_markings_whitefield", - "markings_whitedots": "textures/entity/horse/horse_markings_whitedots", - "markings_blackdots": "textures/entity/horse/horse_markings_blackdots", - "mule": "textures/entity/horse/mule", - "donkey": "textures/entity/horse/donkey", - "skeleton": "textures/entity/horse/horse_skeleton", - "zombie": "textures/entity/horse/horse_zombie", - "armor_none": "textures/entity/horse/armor/horse_armor_none", - "armor_leather": "textures/entity/horse/armor/horse_armor_leather", - "armor_iron": "textures/entity/horse/armor/horse_armor_iron", - "armor_gold": "textures/entity/horse/armor/horse_armor_gold", - "armor_diamond": "textures/entity/horse/armor/horse_armor_diamond" - }, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 128, - "textureheight": 128, - "bones": [ - { - "name": "Body", - "pivot": [0, 13, 9], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 11, -10], "size": [10, 10, 24], "uv": [0, 34]} - ] - }, - { - "name": "TailA", - "pivot": [0, 21, 14], - "rotation": [-65, 0, 0], - "cubes": [ - {"origin": [-1, 20, 14], "size": [2, 2, 3], "uv": [44, 0]} - ] - }, - { - "name": "TailB", - "pivot": [0, 21, 14], - "rotation": [-65, 0, 0], - "cubes": [ - {"origin": [-1.5, 19, 17], "size": [3, 4, 7], "uv": [38, 7]} - ] - }, - { - "name": "TailC", - "pivot": [0, 21, 14], - "rotation": [-80.34, 0, 0], - "cubes": [ - {"origin": [-1.5, 21.5, 23], "size": [3, 4, 7], "uv": [24, 3]} - ] - }, - { - "name": "Leg1A", - "pivot": [4, 15, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.5, 8, 8.5], "size": [4, 9, 5], "uv": [78, 29]} - ] - }, - { - "name": "Leg1B", - "pivot": [4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2, 3, 9.5], "size": [3, 5, 3], "uv": [78, 43]} - ] - }, - { - "name": "Leg1C", - "pivot": [4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.5, -0.1, 9], "size": [4, 3, 4], "uv": [78, 51]} - ] - }, - { - "name": "Leg2A", - "pivot": [-4, 15, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 8, 8.5], "size": [4, 9, 5], "uv": [96, 29]} - ] - }, - { - "name": "Leg2B", - "pivot": [-4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 3, 9.5], "size": [3, 5, 3], "uv": [96, 43]} - ] - }, - { - "name": "Leg2C", - "pivot": [-4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, -0.1, 9], "size": [4, 3, 4], "uv": [96, 51]} - ] - }, - { - "name": "Leg3A", - "pivot": [4, 15, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.1, 8, -10.1], "size": [3, 8, 4], "uv": [44, 29]} - ] - }, - { - "name": "Leg3B", - "pivot": [4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.1, 3, -9.6], "size": [3, 5, 3], "uv": [44, 41]} - ] - }, - { - "name": "Leg3C", - "pivot": [4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.6, -0.1, -10.1], "size": [4, 3, 4], "uv": [44, 51]} - ] - }, - { - "name": "Leg4A", - "pivot": [-4, 15, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.1, 8, -10.1], "size": [3, 8, 4], "uv": [60, 29]} - ] - }, - { - "name": "Leg4B", - "pivot": [-4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.1, 3, -9.6], "size": [3, 5, 3], "uv": [60, 41]} - ] - }, - { - "name": "Leg4C", - "pivot": [-4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.6, -0.1, -10.1], "size": [4, 3, 4], "uv": [60, 51]} - ] - }, - { - "name": "Head", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.5, 25, -11.5], "size": [5, 5, 7], "uv": [0, 0]} - ] - }, - { - "name": "UMouth", - "pivot": [0, 20.05, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2, 27.05, -17], "size": [4, 3, 6], "uv": [24, 18]} - ] - }, - { - "name": "LMouth", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2, 25, -16.5], "size": [4, 2, 5], "uv": [24, 27]} - ] - }, - { - "name": "Ear1", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [0.45, 29, -6], "size": [2, 3, 1], "uv": [0, 0]} - ] - }, - { - "name": "Ear2", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.45, 29, -6], "size": [2, 3, 1], "uv": [0, 0]} - ] - }, - { - "name": "MuleEarL", - "pivot": [0, 20, -10], - "rotation": [30, 0, 15], - "cubes": [ - {"origin": [-2, 29, -6], "size": [2, 7, 1], "uv": [0, 12]} - ] - }, - { - "name": "MuleEarR", - "pivot": [0, 20, -10], - "rotation": [30, 0, -15], - "cubes": [{"origin": [0, 29, -6], "size": [2, 7, 1], "uv": [0, 12]}] - }, - { - "name": "Neck", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.05, 15.8, -12], "size": [4, 14, 8], "uv": [0, 12]} - ] - }, - { - "name": "Bag1", - "pivot": [-7.5, 21, 10], - "rotation": [0, 90, 0], - "cubes": [ - {"origin": [-10.5, 13, 10], "size": [8, 8, 3], "uv": [0, 34]} - ] - }, - { - "name": "Bag2", - "pivot": [4.5, 21, 10], - "rotation": [0, 90, 0], - "cubes": [ - {"origin": [1.5, 13, 10], "size": [8, 8, 3], "uv": [0, 47]} - ] - }, - { - "name": "Saddle", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 21, -1], "size": [10, 1, 8], "uv": [80, 0]} - ] - }, - { - "name": "SaddleB", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-1.5, 22, -1], "size": [3, 1, 2], "uv": [106, 9]} - ] - }, - { - "name": "SaddleC", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [{"origin": [-4, 22, 5], "size": [8, 1, 2], "uv": [80, 9]}] - }, - { - "name": "SaddleL2", - "pivot": [5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [4.5, 13, 1], "size": [1, 2, 2], "uv": [74, 0]} - ] - }, - { - "name": "SaddleL", - "pivot": [5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [4.5, 15, 1.5], "size": [1, 6, 1], "uv": [70, 0]} - ] - }, - { - "name": "SaddleR2", - "pivot": [-5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 13, 1], "size": [1, 2, 2], "uv": [74, 4]} - ] - }, - { - "name": "SaddleR", - "pivot": [-5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 15, 1.5], "size": [1, 6, 1], "uv": [80, 0]} - ] - }, - { - "name": "SaddleMouthL", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [1.5, 26, -14], "size": [1, 2, 2], "uv": [74, 13]} - ] - }, - { - "name": "SaddleMouthR", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.5, 26, -14], "size": [1, 2, 2], "uv": [74, 13]} - ] - }, - { - "name": "SaddleMouthLine", - "pivot": [0, 20, -10], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.6, 23, -16], "size": [0, 3, 16], "uv": [44, 10]} - ] - }, - { - "name": "SaddleMouthLineR", - "pivot": [0, 20, -10], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-2.6, 23, -16], "size": [0, 3, 16], "uv": [44, 5]} - ] - }, - { - "name": "Mane", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-1, 15.5, -5], "size": [2, 16, 4], "uv": [58, 0]} - ] - }, - { - "name": "HeadSaddle", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - { - "origin": [-2.5, 25.1, -17], - "size": [5, 5, 12], - "uv": [80, 12], - "inflate": 0.05 - } - ] - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 32} - }, - "slime": { - "identifier": "minecraft:slime", - "materials": {"default": "slime", "outer": "slime_outer"}, - "textures": {"default": "textures/entity/slime/slime"}, - "geometry": { - "default": { - "visible_bounds_width": 5, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "cube", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-3, 1, -3], "size": [6, 6, 6], "uv": [0, 16]}] - }, - { - "name": "eye0", - "parent": "cube", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-3.3, 4, -3.5], "size": [2, 2, 2], "uv": [32, 0]} - ] - }, - { - "name": "eye1", - "parent": "cube", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [1.3, 4, -3.5], "size": [2, 2, 2], "uv": [32, 4]} - ] - }, - { - "name": "mouth", - "parent": "cube", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [0, 2, -3.5], "size": [1, 1, 1], "uv": [32, 8]} - ] - } - ] - }, - "armor": { - "visible_bounds_width": 1, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "cube", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-4, 0, -4], "size": [8, 8, 8], "uv": [0, 0]}] - }, - { - "name": "eye0", - "parent": "cube", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-3.3, 4, -3.5], "size": [2, 2, 2], "uv": [32, 0]} - ] - }, - { - "name": "eye1", - "parent": "cube", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [1.3, 4, -3.5], "size": [2, 2, 2], "uv": [32, 4]} - ] - }, - { - "name": "mouth", - "parent": "cube", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [0, 2, -3.5], "size": [1, 1, 1], "uv": [32, 8]} - ] - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.squish_factor = (query.previous_squish_value + (query.current_squish_value - query.previous_squish_value) * query.frame_alpha);", - "variable.bounce = 1 / ((variable.squish_factor / (query.variant * 0.5 + 1)) + 1);", - "variable.horizontal_scale_amount = variable.bounce * query.variant;", - "variable.vertical_scale_amount = (1 / variable.bounce) * query.variant;" - ], - "scaleX": "variable.horizontal_scale_amount", - "scaleY": "variable.vertical_scale_amount", - "scaleZ": "variable.horizontal_scale_amount" - }, - "render_controllers": [ - "controller.render.slime", - "controller.render.slime_armor" - ], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 10} - }, - "small_fireball": { - "identifier": "minecraft:small_fireball", - "materials": {"default": "fireball"}, - "textures": {"default": "textures/items/fire_charge"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, -4, 0], - "size": [16, 16, 0], - "uv": {"south": {"uv": [0, 0]}} - } - ] - } - ], - "texturewidth": 16, - "textureheight": 16 - } - }, - "animations": { - "face_player": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "query.camera_rotation(0)", - "query.camera_rotation(1)", - 0 - ] - } - } - } - }, - "scripts": {"scale": "0.5", "animate": ["face_player"]}, - "render_controllers": ["controller.render.fireball"] - }, - "snow_golem": { - "identifier": "minecraft:snow_golem", - "min_engine_version": "1.8.0", - "materials": {"default": "snow_golem", "head": "snow_golem_pumpkin"}, - "textures": {"default": "textures/entity/snow_golem"}, - "geometry": { - "default": { - "visible_bounds_width": 1, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "bones": [ - { - "name": "head", - "parent": "piece1", - "pivot": [0, 20, 0], - "locators": {"lead": [0, 20, 0]}, - "cubes": [ - { - "origin": [-4, 20, -4], - "size": [8, 8, 8], - "uv": [0, 0], - "inflate": -0.5 - } - ] - }, - { - "name": "arm1", - "parent": "piece1", - "pivot": [0, 18, 0], - "bind_pose_rotation": [0, 0, 57.3], - "cubes": [ - { - "origin": [1, 20, -1], - "size": [12, 2, 2], - "uv": [32, 0], - "inflate": -0.5 - } - ] - }, - { - "name": "arm2", - "parent": "piece1", - "pivot": [0, 18, 0], - "bind_pose_rotation": [0, 180, -57.3], - "cubes": [ - { - "origin": [1, 20, -1], - "size": [12, 2, 2], - "uv": [32, 0], - "inflate": -0.5 - } - ] - }, - { - "name": "piece1", - "parent": "piece2", - "pivot": [0, 11, 0], - "cubes": [ - { - "origin": [-5, 11, -5], - "size": [10, 10, 10], - "uv": [0, 16], - "inflate": -0.5 - } - ] - }, - { - "name": "piece2", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-6, 0, -6], - "size": [12, 12, 12], - "uv": [0, 36], - "inflate": -0.5 - } - ] - } - ] - } - }, - "animations": { - "move": { - "loop": true, - "bones": { - "piece1": {"rotation": [0, "query.target_y_rotation * 0.25", 0]} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - } - }, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": { - "default": { - "animations": [ - {"move": "query.modified_move_speed"}, - "look_at_target" - ] - } - } - } - }, - "render_controllers": ["controller.render.snowgolem"] - }, - "snowball": { - "identifier": "minecraft:snowball", - "materials": {"default": "snowball"}, - "textures": {"default": "textures/items/snowball"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, -8, 0], - "size": [16, 16, 0], - "uv": [0, 0], - "rotation": [0, 0, 0] - } - ] - } - ], - "texturewidth": 16, - "textureheight": 16 - } - }, - "render_controllers": ["controller.render.item_sprite"], - "animations": { - "flying": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "query.camera_rotation(0)", - "query.camera_rotation(1)", - 0 - ] - } - } - } - }, - "scripts": {"animate": ["flying"]} - }, - "spider": { - "identifier": "minecraft:spider", - "min_engine_version": "1.8.0", - "materials": {"default": "spider", "invisible": "spider_invisible"}, - "textures": {"default": "textures/entity/spider/spider"}, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "head", - "pivot": [0, 9, -3], - "cubes": [ - {"origin": [-4, 5, -11], "size": [8, 8, 8], "uv": [32, 4]} - ], - "parent": "body0" - }, - { - "name": "body0", - "pivot": [0, 9, 0], - "cubes": [{"origin": [-3, 6, -3], "size": [6, 6, 6], "uv": [0, 0]}] - }, - { - "name": "body1", - "pivot": [0, 9, 9], - "cubes": [ - {"origin": [-5, 5, 3], "size": [10, 8, 12], "uv": [0, 12]} - ], - "parent": "body0" - }, - { - "name": "leg0", - "pivot": [-4, 9, 2], - "cubes": [ - {"origin": [-19, 8, 1], "size": [16, 2, 2], "uv": [18, 0]} - ], - "parent": "body0" - }, - { - "name": "leg1", - "pivot": [4, 9, 2], - "cubes": [{"origin": [3, 8, 1], "size": [16, 2, 2], "uv": [18, 0]}], - "parent": "body0" - }, - { - "name": "leg2", - "pivot": [-4, 9, 1], - "cubes": [ - {"origin": [-19, 8, 0], "size": [16, 2, 2], "uv": [18, 0]} - ], - "parent": "body0" - }, - { - "name": "leg3", - "pivot": [4, 9, 1], - "cubes": [{"origin": [3, 8, 0], "size": [16, 2, 2], "uv": [18, 0]}], - "parent": "body0" - }, - { - "name": "leg4", - "pivot": [-4, 9, 0], - "cubes": [ - {"origin": [-19, 8, -1], "size": [16, 2, 2], "uv": [18, 0]} - ], - "parent": "body0" - }, - { - "name": "leg5", - "pivot": [4, 9, 0], - "cubes": [ - {"origin": [3, 8, -1], "size": [16, 2, 2], "uv": [18, 0]} - ], - "parent": "body0" - }, - { - "name": "leg6", - "pivot": [-4, 9, -1], - "cubes": [ - {"origin": [-19, 8, -2], "size": [16, 2, 2], "uv": [18, 0]} - ], - "parent": "body0" - }, - { - "name": "leg7", - "pivot": [4, 9, -1], - "cubes": [ - {"origin": [3, 8, -2], "size": [16, 2, 2], "uv": [18, 0]} - ], - "parent": "body0" - } - ] - } - }, - "animations": { - "default_leg_pose": { - "loop": true, - "bones": { - "leg0": {"rotation": [0, "45.0 - this", "-45.0 - this"]}, - "leg1": {"rotation": [0, "-45.0 - this", "45.0 - this"]}, - "leg2": {"rotation": [0, "22.5 - this", "-33.3 - this"]}, - "leg3": {"rotation": [0, "-22.5 - this", "33.3 - this"]}, - "leg4": {"rotation": [0, "-22.5 - this", "-33.3 - this"]}, - "leg5": {"rotation": [0, "22.5 - this", "33.3 - this"]}, - "leg6": {"rotation": [0, "-45.0 - this", "-45.0 - this"]}, - "leg7": {"rotation": [0, "45.0 - this", "45.0 - this"]} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "walk": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": [ - 0, - "-math.abs(math.cos(query.anim_time * 76.34 + 90 * 0) * 22.92)", - "math.abs(math.sin(query.anim_time * 38.17 + 90 * 0) * 22.92)" - ] - }, - "leg1": { - "rotation": [ - 0, - "math.abs(math.cos(query.anim_time * 76.34 + 90 * 0) * 22.92)", - "-math.abs(math.sin(query.anim_time * 38.17 + 90 * 0) * 22.92)" - ] - }, - "leg2": { - "rotation": [ - 0, - "-math.abs(math.cos(query.anim_time * 76.34 + 90 * 1) * 22.92)", - "math.abs(math.sin(query.anim_time * 38.17 + 90 * 1) * 22.92)" - ] - }, - "leg3": { - "rotation": [ - 0, - "math.abs(math.cos(query.anim_time * 76.34 + 90 * 1) * 22.92)", - "-math.abs(math.sin(query.anim_time * 38.17 + 90 * 1) * 22.92)" - ] - }, - "leg4": { - "rotation": [ - 0, - "-math.abs(math.cos(query.anim_time * 76.34 + 90 * 2) * 22.92)", - "math.abs(math.sin(query.anim_time * 38.17 + 90 * 2) * 22.92)" - ] - }, - "leg5": { - "rotation": [ - 0, - "math.abs(math.cos(query.anim_time * 76.34 + 90 * 2) * 22.92)", - "-math.abs(math.sin(query.anim_time * 38.17 + 90 * 2) * 22.92)" - ] - }, - "leg6": { - "rotation": [ - 0, - "-math.abs(math.cos(query.anim_time * 76.34 + 90 * 3) * 22.92)", - "math.abs(math.sin(query.anim_time * 38.17 + 90 * 3) * 22.92)" - ] - }, - "leg7": { - "rotation": [ - 0, - "math.abs(math.cos(query.anim_time * 76.34 + 90 * 3) * 22.92)", - "-math.abs(math.sin(query.anim_time * 38.17 + 90 * 3) * 22.92)" - ] - } - } - } - }, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": { - "default": { - "animations": [ - "default_leg_pose", - {"walk": "query.modified_move_speed"}, - "look_at_target" - ] - } - } - } - }, - "render_controllers": ["controller.render.spider"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 11} - }, - "potion": { - "identifier": "minecraft:splash_potion", - "materials": {"default": "splash_potion_enchanted"}, - "textures": { - "moveSlowdown": "textures/items/potion_bottle_splash_moveSlowdown", - "moveSpeed": "textures/items/potion_bottle_splash_moveSpeed", - "digSlowdown": "textures/items/potion_bottle_splash_digSlowdown", - "digSpeed": "textures/items/potion_bottle_splash_digSpeed", - "damageBoost": "textures/items/potion_bottle_splash_damageBoost", - "heal": "textures/items/potion_bottle_splash_heal", - "harm": "textures/items/potion_bottle_splash_harm", - "jump": "textures/items/potion_bottle_splash_jump", - "confusion": "textures/items/potion_bottle_splash_confusion", - "regeneration": "textures/items/potion_bottle_splash_regeneration", - "resistance": "textures/items/potion_bottle_splash_resistance", - "fireResistance": "textures/items/potion_bottle_splash_fireResistance", - "waterBreathing": "textures/items/potion_bottle_splash_waterBreathing", - "invisibility": "textures/items/potion_bottle_splash_invisibility", - "blindness": "textures/items/potion_bottle_splash_blindness", - "nightVision": "textures/items/potion_bottle_splash_nightVision", - "hunger": "textures/items/potion_bottle_splash_hunger", - "weakness": "textures/items/potion_bottle_splash_weakness", - "poison": "textures/items/potion_bottle_splash_poison", - "wither": "textures/items/potion_bottle_splash_wither", - "healthBoost": "textures/items/potion_bottle_splash_healthBoost", - "absorption": "textures/items/potion_bottle_splash_absorption", - "saturation": "textures/items/potion_bottle_splash_saturation", - "levitation": "textures/items/potion_bottle_splash_levitation", - "turtleMaster": "textures/items/potion_bottle_splash_turtleMaster", - "slowFall": "textures/items/potion_bottle_splash_slowFall", - "default": "textures/items/potion_bottle_splash", - "enchanted": "textures/misc/enchanted_item_glint" - }, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, -8, 0], - "size": [16, 16, 0], - "uv": [0, 0], - "rotation": [0, 0, 0] - } - ] - } - ], - "texturewidth": 16, - "textureheight": 16 - } - }, - "render_controllers": ["controller.render.splash_potion"], - "animations": { - "flying": { - "loop": true, - "bones": { - "body": { - "rotation": [ - "query.camera_rotation(0)", - "query.camera_rotation(1)", - 0 - ] - } - } - } - }, - "scripts": {"animate": ["flying"]} - }, - "squid": { - "identifier": "minecraft:squid", - "materials": {"default": "squid"}, - "textures": {"default": "textures/entity/squid"}, - "geometry": { - "default": { - "visible_bounds_width": 3, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "body", - "cubes": [ - {"origin": [-6, -8, -6], "size": [12, 16, 12], "uv": [0, 0]} - ] - }, - { - "name": "tentacle1", - "parent": "body", - "pivot": [5, -7, 0], - "cubes": [ - {"origin": [4, -25, -1], "size": [2, 18, 2], "uv": [48, 0]} - ], - "rotation": [0, 90, 0] - }, - { - "name": "tentacle2", - "parent": "body", - "pivot": [3.5, -7, 3.5], - "cubes": [ - {"origin": [2.5, -25, 2.5], "size": [2, 18, 2], "uv": [48, 0]} - ], - "rotation": [0, 45, 0] - }, - { - "name": "tentacle3", - "parent": "body", - "pivot": [0, -7, 5], - "cubes": [ - {"origin": [-1, -25, 4], "size": [2, 18, 2], "uv": [48, 0]} - ], - "rotation": [0, 0, 0] - }, - { - "name": "tentacle4", - "parent": "body", - "pivot": [-3.5, -7, 3.5], - "cubes": [ - {"origin": [-4.5, -25, 2.5], "size": [2, 18, 2], "uv": [48, 0]} - ], - "rotation": [0, -45, 0] - }, - { - "name": "tentacle5", - "parent": "body", - "pivot": [-5, -7, 0], - "cubes": [ - {"origin": [-6, -25, -1], "size": [2, 18, 2], "uv": [48, 0]} - ], - "rotation": [0, -90, 0] - }, - { - "name": "tentacle6", - "parent": "body", - "pivot": [-3.5, -7, -3.5], - "cubes": [ - {"origin": [-4.5, -25, -4.5], "size": [2, 18, 2], "uv": [48, 0]} - ], - "rotation": [0, -135, 0] - }, - { - "name": "tentacle7", - "parent": "body", - "pivot": [0, -7, -5], - "cubes": [ - {"origin": [-1, -25, -6], "size": [2, 18, 2], "uv": [48, 0]} - ], - "rotation": [0, -180, 0] - }, - { - "name": "tentacle8", - "parent": "body", - "pivot": [3.5, -7, -3.5], - "cubes": [ - {"origin": [2.5, -25, -4.5], "size": [2, 18, 2], "uv": [48, 0]} - ], - "rotation": [0, -225, 0] - } - ] - } - }, - "animations": { - "move": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "body": { - "position": [ - 0, - "query.is_in_water ? 0.0 : (query.is_baby ? 3.2 : 6.4)", - 0 - ] - }, - "tentacle1": { - "rotation": [ - "variable.squid.tentacle_angle - this", - "90.0 - this", - 0 - ] - }, - "tentacle2": { - "rotation": [ - "variable.squid.tentacle_angle - this", - "45.0 - this", - 0 - ] - }, - "tentacle3": { - "rotation": [ - "variable.squid.tentacle_angle - this", - "0.0 - this", - 0 - ] - }, - "tentacle4": { - "rotation": [ - "variable.squid.tentacle_angle - this", - "-45.0 - this", - 0 - ] - }, - "tentacle5": { - "rotation": [ - "variable.squid.tentacle_angle - this", - "-90.0 - this", - 0 - ] - }, - "tentacle6": { - "rotation": [ - "variable.squid.tentacle_angle - this", - "-135.0 - this", - 0 - ] - }, - "tentacle7": { - "rotation": [ - "variable.squid.tentacle_angle - this", - "-180.0 - this", - 0 - ] - }, - "tentacle8": { - "rotation": [ - "variable.squid.tentacle_angle - this", - "-225.0 - this", - 0 - ] - } - } - }, - "squid_rotate": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "body": { - "rotation": [ - {"y": "180.0 - this"}, - {"x": "query.body_x_rotation"}, - {"y": "variable.squid.swim_rotation"} - ] - } - } - } - }, - "scripts": {"animate": ["move", "squid_rotate"]}, - "render_controllers": ["controller.render.squid"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 15} - }, - "stray": { - "identifier": "minecraft:stray", - "min_engine_version": "1.8.0", - "materials": {"default": "stray", "overlay": "stray_clothes"}, - "textures": { - "default": "textures/entity/skeleton/stray", - "overlay": "textures/entity/skeleton/stray_overlay" - }, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} - ], - "parent": "waist" - }, - {"name": "waist", "pivot": [0, 12, 0]}, - { - "name": "head", - "pivot": [0, 24, 0], - "locators": {"lead": [0, 24, 0]}, - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]} - ], - "parent": "body" - }, - { - "name": "hat", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 8, 8], - "uv": [32, 0], - "inflate": 0.5 - } - ], - "neverRender": true, - "parent": "head" - }, - { - "name": "rightArm", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-6, 12, -1], "size": [2, 12, 2], "uv": [40, 16]} - ], - "parent": "body" - }, - { - "name": "rightItem", - "pivot": [-6, 15, 1], - "neverRender": true, - "parent": "rightArm" - }, - { - "name": "leftArm", - "pivot": [5, 22, 0], - "cubes": [ - {"origin": [4, 12, -1], "size": [2, 12, 2], "uv": [40, 16]} - ], - "mirror": true, - "parent": "body" - }, - { - "name": "leftItem", - "pivot": [6, 15, 1], - "neverRender": true, - "parent": "leftArm" - }, - { - "name": "rightLeg", - "pivot": [-2, 12, 0], - "cubes": [ - {"origin": [-3, 0, -1], "size": [2, 12, 2], "uv": [0, 16]} - ], - "parent": "body" - }, - { - "name": "leftLeg", - "pivot": [2, 12, 0], - "cubes": [ - {"origin": [1, 0, -1], "size": [2, 12, 2], "uv": [0, 16]} - ], - "mirror": true, - "parent": "body" - } - ] - }, - "overlay": { - "visible_bounds_width": 2, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "body", - "parent": "waist", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} - ], - "inflate": 0.25 - }, - {"name": "waist", "neverRender": true, "pivot": [0, 12, 0]}, - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]} - ], - "inflate": 0.25 - }, - { - "name": "hat", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 8, 8], - "uv": [32, 0], - "inflate": 0.5 - } - ], - "neverRender": true - }, - { - "name": "rightArm", - "parent": "body", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} - ], - "inflate": 0.25 - }, - { - "name": "rightItem", - "parent": "rightArm", - "pivot": [-6, 15, 1], - "neverRender": true - }, - { - "name": "leftArm", - "parent": "body", - "pivot": [5, 22, 0], - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} - ], - "mirror": true, - "inflate": 0.25 - }, - { - "name": "rightLeg", - "parent": "body", - "pivot": [-1.9, 12, 0], - "cubes": [ - {"origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} - ], - "inflate": 0.25 - }, - { - "name": "leftLeg", - "parent": "body", - "pivot": [1.9, 12, 0], - "cubes": [ - {"origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} - ], - "inflate": 0.25, - "mirror": true - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 27}, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;" - ] - }, - "animations": { - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "move": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - }, - "holding": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - } - } - }, - "brandish_spear": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "this * -0.5 - 157.5 - 22.5 * variable.charge_amount", - "-this", - 0 - ] - } - } - }, - "charging": { - "loop": true, - "bones": { - "rightarm": { - "rotation": ["22.5 * variable.charge_amount - this", "-this", 0] - } - } - }, - "attack.rotations": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46 - this", - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.sin(1.0 - math.pow(1.0 - variable.attack_time, 3.0) * 180.0) * (variable.is_brandishing_spear ? -1.0 : 1.0 )", - "variable.is_brandishing_spear ? 0.0 : (math.sin(math.sqrt(variable.attack_time) * 360) * 11.46) * 2.0", - 0 - ] - } - } - }, - "sneaking": { - "loop": true, - "bones": { - "body": {"rotation": ["0.5 - this", 0, 0]}, - "head": {"position": [0, 1, 0]}, - "leftarm": {"rotation": [72, 0, 0]}, - "leftleg": {"position": [0, -3, 4]}, - "rightarm": {"rotation": [72, 0, 0]}, - "rightleg": {"position": [0, -3, 4]} - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "damage_nearby_mobs": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["-45.0-this", "-this", "-this"]}, - "leftleg": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightarm": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-45.0-this", "-this", "-this"]} - } - }, - "bow_and_arrow": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "query.target_x_rotation - 90.0 - math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation + 28.65", - "-(math.cos(query.life_time * 103.2) * 2.865) - 2.865" - ] - }, - "rightarm": { - "rotation": [ - "query.target_x_rotation - 90.0 + math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation - 5.73", - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "swimming": { - "loop": true, - "bones": { - "body": { - "position": [ - 0, - "variable.swim_amount * -10.0 - this", - "variable.swim_amount * 9.0 - this" - ], - "rotation": [ - "variable.swim_amount * (90.0 + query.target_x_rotation)", - 0, - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) - (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, 14.325, variable.swim_amount) - (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "leftleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0 + 180.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) + (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, -14.325, variable.swim_amount) + (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "rightleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - } - } - }, - "use_item_progress": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "variable.use_item_startup_progress * -60.0 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -22.5 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -5.625 + variable.use_item_interval_progress * 11.25" - ] - } - } - } - }, - "animation_controllers": { - "look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - }, - "riding": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"riding": "query.is_riding"}]}, - "riding": { - "animations": ["riding.arms", "riding.legs"], - "transitions": [{"default": "!query.is_riding"}] - } - } - }, - "holding": { - "initial_state": "default", - "states": {"default": {"animations": ["holding"]}} - }, - "brandish_spear": { - "initial_state": "default", - "states": { - "brandish_spear": { - "animations": ["brandish_spear"], - "transitions": [{"default": "!variable.is_brandishing_spear"}] - }, - "default": { - "transitions": [{"brandish_spear": "variable.is_brandishing_spear"}] - } - } - }, - "charging": { - "initial_state": "default", - "states": { - "charging": { - "animations": ["charging"], - "transitions": [{"default": "!query.is_charging"}] - }, - "default": {"transitions": [{"charging": "query.is_charging"}]} - } - }, - "attack": { - "initial_state": "default", - "states": { - "attacking": { - "animations": ["attack.rotations"], - "transitions": [{"default": "variable.attack_time < 0.0"}] - }, - "default": { - "transitions": [{"attacking": "variable.attack_time >= 0.0"}] - } - } - }, - "sneaking": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"sneaking": "query.is_sneaking"}]}, - "sneaking": { - "animations": ["sneaking"], - "transitions": [{"default": "!query.is_sneaking"}] - } - } - }, - "bob": { - "initial_state": "default", - "states": {"default": {"animations": ["bob"]}} - }, - "damage_nearby_mobs": { - "initial_state": "default", - "states": { - "damage_nearby_mobs": { - "animations": ["damage_nearby_mobs"], - "transitions": [{"default": "!variable.damage_nearby_mobs"}] - }, - "default": { - "transitions": [ - {"damage_nearby_mobs": "variable.damage_nearby_mobs"} - ] - } - } - }, - "bow_and_arrow": { - "initial_state": "default", - "states": { - "bow_and_arrow": { - "animations": ["bow_and_arrow"], - "transitions": [{"default": "!query.has_target"}] - }, - "default": {"transitions": [{"bow_and_arrow": "query.has_target"}]} - } - }, - "swimming": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"is_swimming": "variable.swim_amount > 0.0"}] - }, - "is_swimming": { - "animations": ["swimming"], - "transitions": [{"default": "variable.swim_amount <= 0.0"}] - } - } - }, - "use_item_progress": { - "initial_state": "default", - "states": { - "default": { - "transitions": [ - { - "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 )" - } - ] - }, - "use_item_progress": { - "animations": ["use_item_progress"], - "transitions": [ - { - "default": "( variable.use_item_interval_progress <= 0.0 ) && ( variable.use_item_startup_progress <= 0.0 )" - } - ] - } - } - } - }, - "render_controllers": [ - "controller.render.stray_clothes", - "controller.render.stray" - ], - "enable_attachables": true - }, - "strider": { - "identifier": "minecraft:strider", - "materials": {"default": "strider"}, - "textures": { - "default": "textures/entity/strider/strider", - "saddled": "textures/entity/strider/strider", - "suffocated": "textures/entity/strider/strider_cold", - "suffocated_saddled": "textures/entity/strider/strider_cold" - }, - "geometry": { - "default": { - "bones": [ - { - "name": "right_leg", - "pivot": [-4, 16, 0], - "cubes": [ - {"origin": [-6, 0, -2], "size": [4, 16, 4], "uv": [0, 32]} - ] - }, - { - "name": "left_leg", - "pivot": [4, 16, 0], - "cubes": [{"origin": [2, 0, -2], "size": [4, 16, 4], "uv": [0, 55]}] - }, - { - "name": "body", - "pivot": [0, 16, 0], - "cubes": [ - {"origin": [-8, 14, -8], "size": [16, 14, 16], "uv": [0, 0]} - ], - "locators": {"lead": [0, 15, -1]} - }, - { - "name": "bristle5", - "parent": "body", - "pivot": [8, 19, 0], - "cubes": [ - { - "origin": [8, 19, -8], - "size": [12, 0, 16], - "pivot": [8, 19, 0], - "rotation": [0, 0, 70], - "uv": [16, 65] - } - ] - }, - { - "name": "bristle4", - "parent": "body", - "pivot": [8, 24, 0], - "cubes": [ - { - "origin": [8, 24, -8], - "size": [12, 0, 16], - "pivot": [8, 24, 0], - "rotation": [0, 0, 65], - "uv": [16, 49] - } - ] - }, - { - "name": "bristle3", - "parent": "body", - "pivot": [8, 28, 0], - "cubes": [ - { - "origin": [8, 28, -8], - "size": [12, 0, 16], - "pivot": [8, 28, 0], - "rotation": [0, 0, 50], - "uv": [16, 33] - } - ] - }, - { - "name": "bristle2", - "parent": "body", - "pivot": [-8, 28, 0], - "cubes": [ - { - "origin": [-20, 28, -8], - "size": [12, 0, 16], - "pivot": [-8, 28, 0], - "rotation": [0, 0, -50], - "uv": [16, 33], - "mirror": true - } - ] - }, - { - "name": "bristle1", - "parent": "body", - "pivot": [-8, 24, 0], - "cubes": [ - { - "origin": [-20, 24, -8], - "size": [12, 0, 16], - "pivot": [-8, 24, 0], - "rotation": [0, 0, -65], - "uv": [16, 49], - "mirror": true - } - ] - }, - { - "name": "bristle0", - "parent": "body", - "pivot": [-8, 19, 0], - "cubes": [ - { - "origin": [-20, 19, -8], - "size": [12, 0, 16], - "pivot": [-8, 19, 0], - "rotation": [0, 0, -70], - "uv": [16, 65], - "mirror": true - } - ] - } - ], - "visible_bounds_width": 3, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 64, - "textureheight": 128 - } - }, - "spawn_egg": {"base_color": "#9c3436", "overlay_color": "#4d494d"}, - "scripts": { - "pre_animation": [ - "variable.animation_speed = Math.min(query.modified_move_speed, 0.25);", - "variable.speed = 85.9437;", - "variable.bristle_flow=Math.cos(query.modified_distance_moved * variable.speed + 180) * variable.animation_speed;", - "variable.bristle_range_mod=1;", - "variable.bristle_speed_mod=1;" - ], - "animate": ["look_at_target", "walk", "bristle_flow"] - }, - "animations": { - "look_at_target": { - "loop": true, - "bones": { - "body": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "walk": { - "loop": true, - "bones": { - "right_leg": { - "rotation": [ - "Math.sin(query.modified_distance_moved * variable.speed * 0.5 + 180) * 114.592 * variable.animation_speed", - 0, - "10 * Math.cos(query.modified_distance_moved * variable.speed * 0.5f + 180) * variable.animation_speed" - ], - "position": [ - 0, - "-2 * Math.sin(query.modified_distance_moved * variable.speed * 0.5) * 2 * variable.animation_speed", - 0 - ] - }, - "left_leg": { - "rotation": [ - "Math.sin(query.modified_distance_moved * variable.speed * 0.5) * 114.592 * variable.animation_speed", - 0, - "10 * Math.cos(query.modified_distance_moved * variable.speed * 0.5f) * variable.animation_speed" - ], - "position": [ - 0, - "-2 * Math.sin(query.modified_distance_moved * variable.speed * 0.5 + 180) * 2 * variable.animation_speed", - 0 - ] - }, - "body": { - "rotation": [ - 0, - 0, - "5.72958 * Math.sin(query.modified_distance_moved * variable.speed) * 4 * variable.animation_speed" - ], - "position": [ - 0, - "-2 * Math.cos(query.modified_distance_moved * variable.speed) * 2 * variable.animation_speed", - 0 - ] - }, - "bristle1": {"rotation": [0, 0, "variable.bristle_flow * 74.4845"]}, - "bristle2": {"rotation": [0, 0, "variable.bristle_flow * 68.7549"]}, - "bristle3": {"rotation": [0, 0, "variable.bristle_flow * 34.3775"]}, - "bristle4": {"rotation": [0, 0, "variable.bristle_flow * 68.7549"]}, - "bristle5": {"rotation": [0, 0, "variable.bristle_flow * 74.4845"]} - } - }, - "bristle_flow": { - "loop": true, - "bones": { - "bristle0": { - "rotation": [ - 0, - 0, - "2.864789 * variable.bristle_range_mod * Math.sin(query.life_time * 20 * variable.bristle_speed_mod * -22.9183)" - ] - }, - "bristle1": { - "rotation": [ - 0, - 0, - "5.72958 * variable.bristle_range_mod * Math.sin(query.life_time * 20 * variable.bristle_speed_mod * 11.4592)" - ] - }, - "bristle2": { - "rotation": [ - 0, - 0, - "5.72958 * variable.bristle_range_mod * Math.sin(query.life_time * 20 * variable.bristle_speed_mod * 22.9183)" - ] - }, - "bristle3": { - "rotation": [ - 0, - 0, - "5.72958 * variable.bristle_range_mod * Math.sin(query.life_time * 20 * variable.bristle_speed_mod * 22.9183)" - ] - }, - "bristle4": { - "rotation": [ - 0, - 0, - "5.72958 * variable.bristle_range_mod * Math.sin(query.life_time * 20 * variable.bristle_speed_mod * 11.4592)" - ] - }, - "bristle5": { - "rotation": [ - 0, - 0, - "2.864789 * variable.bristle_range_mod * Math.sin(query.life_time * 20 * variable.bristle_speed_mod * -22.9183)" - ] - } - } - } - }, - "render_controllers": ["controller.render.strider"] - }, - "trident": { - "identifier": "minecraft:thrown_trident", - "textures": { - "default": "textures/entity/trident", - "loyalty_rope": "textures/entity/lead_knot" - }, - "geometry": { - "default": { - "texturewidth": 32, - "textureheight": 32, - "bones": [ - { - "name": "pole", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-0.5, -3, -0.5], - "size": [1, 31, 1], - "inflate": 0.01, - "uv": [0, 0] - }, - {"origin": [-1.5, 22, -0.5], "size": [3, 2, 1], "uv": [4, 0]}, - {"origin": [-2.5, 23, -0.5], "size": [1, 4, 1], "uv": [4, 3]}, - {"origin": [1.5, 23, -0.5], "size": [1, 4, 1], "uv": [4, 3]} - ] - } - ] - } - } - }, - "tnt_minecart": { - "identifier": "minecraft:tnt_minecart", - "min_engine_version": "1.8.0", - "materials": {"default": "minecart"}, - "textures": {"default": "textures/entity/minecart"}, - "geometry": { - "default": { - "bones": [ - { - "name": "bottom", - "pivot": [0, 6, 0], - "cubes": [ - { - "origin": [-10, -6.5, -1], - "size": [20, 16, 2], - "rotation": [90, 0, 0], - "uv": [0, 10] - } - ] - }, - { - "name": "back", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-17, 2.5, -1], - "size": [16, 8, 2], - "rotation": [0, 270, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "front", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [1, 2.5, -1], - "size": [16, 8, 2], - "rotation": [0, 90, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "right", - "pivot": [0, 0, 0], - "cubes": [ - { - "origin": [-8, 2.5, -8], - "size": [16, 8, 2], - "rotation": [0, 180, 0], - "uv": [0, 0] - } - ], - "parent": "bottom" - }, - { - "name": "left", - "pivot": [0, 0, 0], - "cubes": [ - {"origin": [-8, 2.5, 6], "size": [16, 8, 2], "uv": [0, 0]} - ], - "parent": "bottom" - } - ], - "texturewidth": 64, - "textureheight": 32 - } - }, - "scripts": { - "pre_animation": ["variable.hurt = query.hurt_time - query.frame_alpha;"], - "animate": ["move"] - }, - "animations": { - "move": { - "loop": true, - "bones": { - "bottom": { - "position": [ - "variable.rail_offset.x / query.model_scale", - "variable.rail_offset.y / query.model_scale", - "variable.rail_offset.z / query.model_scale" - ], - "rotation": [ - "variable.hurt > 0 ? -Math.sin(variable.hurt * 360 / (Math.pi * 2)) * variable.hurt * (((20 * 2 - query.structural_integrity) - query.frame_alpha) < 0 ? 0: (20 * 2 - query.structural_integrity) - query.frame_alpha) / 10 * query.hurt_direction : 0", - 0, - "-variable.rail_rotation.z" - ] - } - } - } - }, - "render_controllers": ["controller.render.minecart"] - }, - "tropical_fish": { - "identifier": "minecraft:tropicalfish", - "materials": {"default": "tropicalfish"}, - "textures": { - "typeA": "textures/entity/fish/tropical_a", - "typeB": "textures/entity/fish/tropical_b", - "aPattern1": "textures/entity/fish/tropical_a_pattern_1", - "aPattern2": "textures/entity/fish/tropical_a_pattern_2", - "aPattern3": "textures/entity/fish/tropical_a_pattern_3", - "aPattern4": "textures/entity/fish/tropical_a_pattern_4", - "aPattern5": "textures/entity/fish/tropical_a_pattern_5", - "aPattern6": "textures/entity/fish/tropical_a_pattern_6", - "bPattern1": "textures/entity/fish/tropical_b_pattern_1", - "bPattern2": "textures/entity/fish/tropical_b_pattern_2", - "bPattern3": "textures/entity/fish/tropical_b_pattern_3", - "bPattern4": "textures/entity/fish/tropical_b_pattern_4", - "bPattern5": "textures/entity/fish/tropical_b_pattern_5", - "bPattern6": "textures/entity/fish/tropical_b_pattern_6" - }, - "scripts": { - "pre_animation": [ - "variable.ZRot = !query.is_in_water ? Math.cos((query.time_stamp + query.frame_alpha) * 0.25) * 90 : 0.0;", - "variable.AnimationAmountBlend = Math.lerp(variable.AnimationAmountPrev, variable.AnimationAmount, query.frame_alpha);" - ] - }, - "geometry": { - "typeA": { - "visible_bounds_width": 0.5, - "visible_bounds_height": 0.5, - "bones": [ - { - "pivot": [-0.5, 0, 0], - "cubes": [ - {"origin": [-1, 0, -3], "size": [2, 3, 6], "uv": [0, 0]}, - {"origin": [0, 3, -2.9992], "size": [0, 4, 6], "uv": [10, -6]} - ], - "name": "body" - }, - { - "pivot": [0, 0, 3], - "cubes": [{"origin": [0, 0, 3], "size": [0, 3, 4], "uv": [24, -4]}], - "name": "tailfin", - "parent": "body" - }, - { - "pivot": [0.5, 0, 1], - "bind_pose_rotation": [0, -35, 0], - "cubes": [ - {"origin": [0.336, 0, -0.10594], "size": [2, 2, 0], "uv": [2, 12]} - ], - "name": "leftFin", - "parent": "body" - }, - { - "pivot": [-0.5, 0, 1], - "bind_pose_rotation": [0, 35, 0], - "cubes": [ - { - "origin": [-2.336, 0, -0.10594], - "size": [2, 2, 0], - "uv": [2, 16] - } - ], - "name": "rightFin", - "parent": "body" - } - ], - "texturewidth": 32, - "textureheight": 32 - }, - "typeB": { - "visible_bounds_width": 0.5, - "visible_bounds_height": 0.5, - "bones": [ - { - "pivot": [-0.5, 0, 0], - "cubes": [ - {"origin": [-1, 0, -0.0008], "size": [2, 6, 6], "uv": [0, 20]}, - {"origin": [0, -5, -0.0008], "size": [0, 5, 6], "uv": [20, 21]}, - {"origin": [0, 6, -0.0008], "size": [0, 5, 6], "uv": [20, 10]} - ], - "name": "body" - }, - { - "pivot": [0, 0, 6], - "cubes": [ - {"origin": [0, 0.0008, 6], "size": [0, 6, 5], "uv": [21, 16]} - ], - "name": "tailfin", - "parent": "body" - }, - { - "pivot": [0.5, 0, 1], - "bind_pose_rotation": [0, -35, 0], - "cubes": [ - { - "origin": [2.05673, 0, 2.35152], - "size": [2, 2, 0], - "uv": [2, 12] - } - ], - "name": "leftFin", - "parent": "body" - }, - { - "pivot": [-0.5, 0, 1], - "bind_pose_rotation": [0, 35, 0], - "cubes": [ - { - "origin": [-4.05673, 0, 2.35152], - "size": [2, 2, 0], - "uv": [2, 16] - } - ], - "name": "rightFin", - "parent": "body" - } - ], - "texturewidth": 32, - "textureheight": 32 - } - }, - "animations": { - "flop": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 45.0) * 2.0", - "variable.zrot" - ] - }, - "tailfin": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 45.0) * -25.75", - 0 - ] - } - } - }, - "swim": { - "loop": true, - "bones": { - "tailfin": { - "rotation": [ - 0, - "math.cos(variable.animationamountblend * 30.0) * -25.75", - 0 - ] - } - } - } - }, - "animation_controllers": { - "general": { - "initial_state": "flopping", - "states": { - "flopping": { - "animations": ["flop"], - "transitions": [ - {"swimming": "query.is_in_water || query.is_levitating"} - ] - }, - "swimming": { - "animations": ["swim"], - "transitions": [ - {"flopping": "!query.is_in_water && !query.is_levitating"} - ] - } - } - } - }, - "render_controllers": ["controller.render.tropicalfish"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 44} - }, - "turtle": { - "identifier": "minecraft:turtle", - "materials": {"default": "turtle"}, - "textures": {"default": "textures/entity/turtle/big_sea_turtle"}, - "geometry": { - "default": { - "texturewidth": 128, - "textureheight": 64, - "bones": [ - { - "name": "head", - "parent": "body", - "pivot": [0, 5, -10], - "cubes": [{"origin": [-3, 1, -13], "size": [6, 5, 6], "uv": [2, 0]}] - }, - { - "name": "eggbelly", - "parent": "body", - "pivot": [0, 13, -10], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-4.5, -8, -24], "size": [9, 18, 1], "uv": [69, 33]} - ] - }, - { - "name": "body", - "pivot": [0, 13, -10], - "bind_pose_rotation": [90, 0, 0], - "cubes": [ - {"origin": [-9.5, -10, -20], "size": [19, 20, 6], "uv": [6, 37]}, - {"origin": [-5.5, -8, -23], "size": [11, 18, 3], "uv": [30, 1]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-3.5, 2, 11], - "cubes": [ - {"origin": [-5.5, 1, 11], "size": [4, 1, 10], "uv": [0, 23]} - ] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [3.5, 2, 11], - "cubes": [ - {"origin": [1.5, 1, 11], "size": [4, 1, 10], "uv": [0, 12]} - ] - }, - { - "name": "leg2", - "parent": "body", - "pivot": [-5, 3, -4], - "cubes": [ - {"origin": [-18, 2, -6], "size": [13, 1, 5], "uv": [26, 30]} - ] - }, - { - "name": "leg3", - "parent": "body", - "pivot": [5, 3, -4], - "cubes": [ - {"origin": [5, 2, -6], "size": [13, 1, 5], "uv": [26, 24]} - ] - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.timeMultiplier = query.has_rider ? 0.39972 : 1.0;", - "variable.backLegMultiplier = query.has_rider ? 0.5 : 3.0;", - "variable.frontLegMultiplier = query.has_rider ? 2.0 : 8.0;", - "variable.legSpeedMultiplier = query.has_rider ? 2.0 : 5.0;" - ], - "scale": "1.2" - }, - "animations": { - "general": { - "loop": true, - "bones": { - "body": { - "position": [0, "query.is_pregnant ? 1.0 : 0.0", 0], - "rotation": ["-this", 0, 0] - }, - "eggbelly": { - "position": [0, -0.08, 0], - "rotation": ["-this", 0, 0], - "scale": "query.is_pregnant ? 1.0 : 0.0" - } - } - }, - "move": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": [ - "math.clamp(math.cos(query.anim_time * 22.92) * query.modified_move_speed * 28.65, -90.0, 90.0) - this", - "-this", - "-this" - ] - }, - "leg1": { - "rotation": [ - "math.clamp(math.cos(query.anim_time * 22.92 + 180) * query.modified_move_speed * 28.65, -90.0, 90.0) - this", - "-this", - "-this" - ] - }, - "leg2": { - "rotation": [ - "-this", - "-this", - "math.clamp(math.cos(query.anim_time * 22.92 + 180) * query.modified_move_speed * 28.65, -90.0, 90.0) - this" - ] - }, - "leg3": { - "rotation": [ - "-this", - "-this", - "math.clamp(math.cos(query.anim_time * 22.92) * query.modified_move_speed * 28.65, -90.0, 90.0) - this" - ] - } - } - }, - "ground_move": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": [ - "-this", - "math.clamp(math.cos(query.anim_time * variable.timemultiplier * variable.legspeedmultiplier * 57.3 + 180) * variable.backlegmultiplier * query.modified_move_speed * 57.3, -90.0, 90.0) - this", - "-this" - ] - }, - "leg1": { - "rotation": [ - "-this", - "math.clamp(math.cos(query.anim_time * variable.timemultiplier * variable.legspeedmultiplier * 57.3) * variable.backlegmultiplier * query.modified_move_speed * 57.3, -90.0, 90.0) - this", - "-this" - ] - }, - "leg2": { - "rotation": [ - "-this", - "query.is_laying_egg ? math.cos(query.life_time * 1146.0 + 180) * 90.0 : math.clamp(math.cos(query.anim_time * variable.timemultiplier * variable.legspeedmultiplier * 57.3 + 180) * variable.frontlegmultiplier * query.modified_move_speed * 57.3, -90.0, 90.0) - this", - "-this" - ] - }, - "leg3": { - "rotation": [ - "-this", - "query.is_laying_egg ? math.cos(query.life_time * 1146.0) * 90.0 : math.clamp(math.cos(query.anim_time * variable.timemultiplier * variable.legspeedmultiplier * 57.3) * variable.frontlegmultiplier * query.modified_move_speed * 57.3, -90.0, 90.0) - this", - "-this" - ] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - } - }, - "animation_controllers": { - "general": { - "initial_state": "default", - "states": {"default": {"animations": ["general"]}} - }, - "move": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target"], - "transitions": [ - {"swimming": "query.is_in_water && !query.is_on_ground"}, - {"walking": "!query.is_in_water && query.is_on_ground"} - ] - }, - "swimming": { - "animations": ["move", "look_at_target"], - "transitions": [ - {"walking": "!query.is_in_water && query.is_on_ground"} - ] - }, - "walking": { - "animations": ["ground_move", "look_at_target"], - "transitions": [ - {"swimming": "query.is_in_water && !query.is_on_ground"} - ] - } - } - } - }, - "render_controllers": ["controller.render.turtle"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 50} - }, - "vex": { - "identifier": "minecraft:vex", - "min_engine_version": "1.8.0", - "materials": {"default": "vex"}, - "textures": { - "default": "textures/entity/illager/vex", - "charging": "textures/entity/illager/vex_charging" - }, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]}] - }, - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} - ] - }, - { - "name": "rightArm", - "parent": "body", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} - ] - }, - { - "name": "rightItem", - "pivot": [-6, 13, 0], - "neverRender": true, - "parent": "rightarm" - }, - { - "name": "leftArm", - "parent": "body", - "pivot": [5, 22, 0], - "mirror": true, - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-1.9, 12, 0], - "cubes": [ - {"origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]}, - {"origin": [-2.9, 3, -2], "size": [6, 10, 4], "uv": [32, 0]} - ] - }, - { - "name": "leftwing", - "parent": "body", - "pivot": [0, 24, 0], - "mirror": true, - "cubes": [ - {"origin": [0, 12, 0], "size": [20, 12, 1], "uv": [0, 32]} - ] - }, - { - "name": "rightwing", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-20, 12, 0], "size": [20, 12, 1], "uv": [0, 32]} - ] - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;" - ], - "scale": "0.4" - }, - "animations": { - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "move": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - }, - "holding": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - } - } - }, - "brandish_spear": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "this * -0.5 - 157.5 - 22.5 * variable.charge_amount", - "-this", - 0 - ] - } - } - }, - "charging": { - "loop": true, - "bones": { - "rightarm": { - "rotation": ["22.5 * variable.charge_amount - this", "-this", 0] - } - } - }, - "attack.rotations": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46 - this", - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.sin(1.0 - math.pow(1.0 - variable.attack_time, 3.0) * 180.0) * (variable.is_brandishing_spear ? -1.0 : 1.0 )", - "variable.is_brandishing_spear ? 0.0 : (math.sin(math.sqrt(variable.attack_time) * 360) * 11.46) * 2.0", - 0 - ] - } - } - }, - "sneaking": { - "loop": true, - "bones": { - "body": {"rotation": ["0.5 - this", 0, 0]}, - "head": {"position": [0, 1, 0]}, - "leftarm": {"rotation": [72, 0, 0]}, - "leftleg": {"position": [0, -3, 4]}, - "rightarm": {"rotation": [72, 0, 0]}, - "rightleg": {"position": [0, -3, 4]} - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "damage_nearby_mobs": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["-45.0-this", "-this", "-this"]}, - "leftleg": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightarm": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-45.0-this", "-this", "-this"]} - } - }, - "bow_and_arrow": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "query.target_x_rotation - 90.0 - math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation + 28.65", - "-(math.cos(query.life_time * 103.2) * 2.865) - 2.865" - ] - }, - "rightarm": { - "rotation": [ - "query.target_x_rotation - 90.0 + math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation - 5.73", - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "swimming": { - "animation_length": 1.3, - "loop": true, - "bones": { - "leftarm": { - "rotation": { - "0.7": { - "post": [ - "math.lerp(this, 11.25 * math.mod(query.modified_distance_moved, 26.0), variable.leftarmswim_amount)", - "math.lerp(this, 180.0, variable.leftarmswim_amount)", - "math.lerp(this, 72.77 + 13.4 * math.mod(query.modified_distance_moved, 26.0), variable.leftarmswim_amount)" - ], - "pre": [ - "math.lerp(this, 0.0, variable.leftarmswim_amount)", - "math.lerp(this, 180.0, variable.leftarmswim_amount)", - "math.lerp(this, 180.0 - 0.01877 * (-65.0 * math.mod(query.modified_distance_moved, 26.0) + math.mod(query.modified_distance_moved, 26.0) * math.mod(query.modified_distance_moved, 26.0)), variable.leftarmswim_amount)" - ] - }, - "1.1": [ - "math.lerp(this, 11.25 * math.mod(query.modified_distance_moved, 26.0), variable.leftarmswim_amount)", - "math.lerp(this, 180.0, variable.leftarmswim_amount)", - "math.lerp(this, 72.77 + 13.4 * math.mod(query.modified_distance_moved, 26.0), variable.leftarmswim_amount)" - ], - "1.3": { - "post": [ - "math.lerp(this, 90.0 - (22.5 * math.mod(query.modified_distance_moved, 26.0)), variable.leftarmswim_amount)", - "math.lerp(this, 180.0, variable.leftarmswim_amount)", - "math.lerp(this, 180.0, variable.leftarmswim_amount)" - ], - "pre": [ - "math.lerp(this, 11.25 * math.mod(query.modified_distance_moved, 26.0), variable.leftarmswim_amount)", - "math.lerp(this, 180.0, variable.leftarmswim_amount)", - "math.lerp(this, 72.77 + 13.4 * math.mod(query.modified_distance_moved, 26.0), variable.leftarmswim_amount)" - ] - } - } - }, - "leftleg": { - "rotation": [ - "math.lerp(this, math.cos(query.modified_distance_moved * 19.5 + 180.0) * 17.2, variable.leftarmswim_amount) - this", - 0, - 0 - ] - }, - "rightarm": { - "rotation": { - "0.7": { - "post": [ - "math.lerp(this, 11.25 * math.mod(query.modified_distance_moved, 26.0), variable.rightarmswim_amount)", - "math.lerp(this, 180.0, variable.rightarmswim_amount)", - "math.lerp(this, 72.77 + 13.4 * math.mod(query.modified_distance_moved, 26.0), variable.rightarmswim_amount)" - ], - "pre": [ - "math.lerp(this, 0.0, variable.rightarmswim_amount)", - "math.lerp(this, 180.0, variable.rightarmswim_amount)", - "math.lerp(this, -0.1019 * (-65.0 * math.mod(query.modified_distance_moved, 26.0) + math.mod(query.modified_distance_moved, 26.0) * math.mod(query.modified_distance_moved, 26.0)), variable.rightarmswim_amount)" - ] - }, - "1.1": [ - "math.lerp(this, 11.25 * math.mod(query.modified_distance_moved, 26.0), variable.rightarmswim_amount)", - "math.lerp(this, 180.0, variable.rightarmswim_amount)", - "math.lerp(this, 72.77 + 13.4 * math.mod(query.modified_distance_moved, 26.0), variable.rightarmswim_amount)" - ], - "1.3": { - "post": [ - "math.lerp(this, 90.0 - (22.5 * math.mod(query.modified_distance_moved, 26.0)), variable.rightarmswim_amount)", - "math.lerp(this, 180.0, variable.rightarmswim_amount)", - "math.lerp(this, 180.0, variable.rightarmswim_amount)" - ], - "pre": [ - "math.lerp(this, 11.25 * math.mod(query.modified_distance_moved, 26.0), variable.rightarmswim_amount)", - "math.lerp(this, 180.0, variable.rightarmswim_amount)", - "math.lerp(this, 72.77 + 13.4 * math.mod(query.modified_distance_moved, 26.0), variable.rightarmswim_amount)" - ] - } - } - }, - "rightleg": { - "rotation": [ - "math.lerp(this, math.cos(query.modified_distance_moved * 19.5) * 17.2, variable.leftarmswim_amount) - this", - 0, - 0 - ] - } - } - }, - "use_item_progress": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "variable.use_item_startup_progress * -60.0 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -22.5 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -5.625 + variable.use_item_interval_progress * 11.25" - ] - } - } - }, - "vex_move": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leftwing": { - "position": [0, "-1.0 - this", "2.0 - this"], - "rotation": [ - "27.0 - this", - "-(27.0 + math.cos(query.life_time * 916.8) * 9.0) - this", - "-27.0 - this" - ] - }, - "leg0": {"rotation": ["variable.tcos0 * 1.4 + 36.0", 0, 0]}, - "rightarm": { - "rotation": ["query.is_charging ? (216.0 - this) : 0.0", 0, 0] - }, - "rightwing": { - "position": [0, "-1.0 - this", "2.0 - this"], - "rotation": [ - "27.0 - this", - "27.0 + math.cos(query.life_time * 916.8) * 9.0 - this", - "27.0 - this" - ] - } - } - } - }, - "animation_controllers": { - "look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - }, - "riding": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"riding": "query.is_riding"}]}, - "riding": { - "animations": ["riding.arms", "riding.legs"], - "transitions": [{"default": "!query.is_riding"}] - } - } - }, - "holding": { - "initial_state": "default", - "states": {"default": {"animations": ["holding"]}} - }, - "brandish_spear": { - "initial_state": "default", - "states": { - "brandish_spear": { - "animations": ["brandish_spear"], - "transitions": [{"default": "!variable.is_brandishing_spear"}] - }, - "default": { - "transitions": [{"brandish_spear": "variable.is_brandishing_spear"}] - } - } - }, - "charging": { - "initial_state": "default", - "states": { - "charging": { - "animations": ["charging"], - "transitions": [{"default": "!query.is_charging"}] - }, - "default": {"transitions": [{"charging": "query.is_charging"}]} - } - }, - "attack": { - "initial_state": "default", - "states": { - "attacking": { - "animations": ["attack.rotations"], - "transitions": [{"default": "variable.attack_time < 0.0"}] - }, - "default": { - "transitions": [{"attacking": "variable.attack_time >= 0.0"}] - } - } - }, - "sneaking": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"sneaking": "query.is_sneaking"}]}, - "sneaking": { - "animations": ["sneaking"], - "transitions": [{"default": "!query.is_sneaking"}] - } - } - }, - "bob": { - "initial_state": "default", - "states": {"default": {"animations": ["bob"]}} - }, - "damage_nearby_mobs": { - "initial_state": "default", - "states": { - "damage_nearby_mobs": { - "animations": ["damage_nearby_mobs"], - "transitions": [{"default": "!variable.damage_nearby_mobs"}] - }, - "default": { - "transitions": [ - {"damage_nearby_mobs": "variable.damage_nearby_mobs"} - ] - } - } - }, - "bow_and_arrow": { - "initial_state": "default", - "states": { - "bow_and_arrow": { - "animations": ["bow_and_arrow"], - "transitions": [{"default": "!query.has_target"}] - }, - "default": {"transitions": [{"bow_and_arrow": "query.has_target"}]} - } - }, - "swimming": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"swimming": "variable.swim_amount > 0.0"}] - }, - "swimming": { - "animations": ["swimming"], - "transitions": [{"default": "variable.swim_amount <= 0.0"}] - } - } - }, - "use_item_progress": { - "initial_state": "default", - "states": { - "default": { - "transitions": [ - { - "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 )" - } - ] - }, - "use_item_progress": { - "animations": ["use_item_progress"], - "transitions": [ - { - "default": "( variable.use_item_interval_progress <= 0.0 ) && ( variable.use_item_startup_progress <= 0.0 )" - } - ] - } - } - }, - "vex_move": { - "initial_state": "default", - "states": {"default": {"animations": ["vex_move"]}} - } - }, - "render_controllers": ["controller.render.vex"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 41} - }, - "villager": { - "identifier": "minecraft:villager", - "min_engine_version": "1.8.0", - "materials": {"default": "villager"}, - "textures": { - "farmer": "textures/entity/villager/profession/farmer", - "librarian": "textures/entity/villager/profession/librarian", - "priest": "textures/entity/villager/profession/cleric", - "smith": "textures/entity/villager/profession/weaponsmith", - "butcher": "textures/entity/villager/profession/butcher" - }, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 2.5, - "visible_bounds_offset": [0, 1.25, 0], - "bones": [ - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 10, 8], "uv": [0, 0]} - ] - }, - { - "name": "nose", - "parent": "head", - "pivot": [0, 26, 0], - "cubes": [ - {"origin": [-1, 23, -6], "size": [2, 4, 2], "uv": [24, 0]} - ] - }, - { - "name": "body", - "cubes": [ - {"origin": [-4, 12, -3], "size": [8, 12, 6], "uv": [16, 20]}, - { - "origin": [-4, 6, -3], - "size": [8, 18, 6], - "uv": [0, 38], - "inflate": 0.5 - } - ] - }, - { - "name": "arms", - "parent": "body", - "pivot": [0, 22, 0], - "cubes": [ - {"origin": [-4, 16, -2], "size": [8, 4, 4], "uv": [40, 38]}, - {"origin": [-8, 16, -2], "size": [4, 8, 4], "uv": [44, 22]}, - {"origin": [4, 16, -2], "size": [4, 8, 4], "uv": [44, 22]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-2, 12, 0], - "cubes": [ - {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 22]} - ] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [2, 12, 0], - "cubes": [{"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [0, 22]}] - } - ] - } - }, - "scripts": {"scale": "0.9375"}, - "animations": { - "general": { - "loop": true, - "bones": { - "arms": {"position": [0, -1, -1], "rotation": ["-42.97 - this", 0, 0]} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "move": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": [ - "(math.cos(query.anim_time * 38.17) * 40.0) - this", - "-this", - 0 - ] - }, - "leg1": { - "rotation": [ - "(math.cos(query.anim_time * 38.17 + 180) * 40.0) - this", - "-this", - 0 - ] - } - } - }, - "baby_transform": {"loop": true, "bones": {"head": {"scale": 1.5}}} - }, - "animation_controllers": { - "general": { - "initial_state": "default", - "states": { - "default": { - "animations": ["general", {"look_at_target": "!query.is_sleeping"}] - } - } - }, - "move": { - "initial_state": "default", - "states": { - "default": {"animations": [{"move": "query.modified_move_speed"}]} - } - }, - "baby": { - "initial_state": "baby", - "states": { - "baby": {"animations": [{"baby_transform": "query.is_baby"}]} - } - } - }, - "render_controllers": ["controller.render.villager"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 14} - }, - "vindicator": { - "identifier": "minecraft:vindicator", - "min_engine_version": "1.8.0", - "materials": {"default": "vindicator"}, - "textures": {"default": "textures/entity/illager/vindicator"}, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 2.5, - "visible_bounds_offset": [0, 1.25, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 10, 8], "uv": [0, 0]} - ] - }, - { - "name": "nose", - "parent": "head", - "pivot": [0, 26, 0], - "cubes": [ - {"origin": [-1, 23, -6], "size": [2, 4, 2], "uv": [24, 0]} - ] - }, - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -3], "size": [8, 12, 6], "uv": [16, 20]}, - { - "origin": [-4, 6, -3], - "size": [8, 18, 6], - "uv": [0, 38], - "inflate": 0.5 - } - ] - }, - { - "name": "arms", - "parent": "body", - "pivot": [0, 22, 0], - "cubes": [ - {"origin": [-8, 16, -2], "size": [4, 8, 4], "uv": [44, 22]}, - {"origin": [4, 16, -2], "size": [4, 8, 4], "uv": [44, 22]}, - {"origin": [-4, 16, -2], "size": [8, 4, 4], "uv": [40, 38]} - ] - }, - { - "name": "leg0", - "parent": "body", - "pivot": [-2, 12, 0], - "cubes": [ - {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 22]} - ] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [2, 12, 0], - "mirror": true, - "cubes": [{"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [0, 22]}] - }, - { - "name": "rightArm", - "parent": "body", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 46]} - ] - }, - { - "name": "rightItem", - "pivot": [-5.5, 16, 0.5], - "neverRender": true, - "parent": "rightArm" - }, - { - "name": "leftArm", - "parent": "body", - "pivot": [5, 22, 0], - "mirror": true, - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 46]} - ] - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 39}, - "scripts": { - "scale": "0.9375", - "animate": [ - "vindicator_base", - "vindicator_walk", - "controller_look_at_target", - "controller_vindicator_base", - "controller_riding" - ] - }, - "animations": { - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "riding.arms": { - "loop": true, - "bones": {"leftarm": {"rotation": [-36, 0, 0]}} - }, - "riding.legs": { - "loop": true, - "bones": { - "leg0": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]}, - "leg1": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]} - } - }, - "vindicator_base": { - "loop": true, - "bones": { - "arms": { - "position": [0, "-3.0 - this", "-1.0 - this"], - "rotation": ["-42.97 - this", 0, 0] - }, - "leftarm": { - "rotation": [ - "math.cos(query.life_time * 20.0 * 3.84) * 2.87", - -9, - "-1 * (math.cos(query.life_time * 20.0 * 5.16) * 2.87 + 2.87)" - ] - }, - "rightarm": { - "rotation": [ - "math.cos(query.life_time * 20.0 * 3.84) * 2.87", - 9, - "math.cos(query.life_time * 20.0 * 5.16) * 2.87 + 2.87" - ] - } - } - }, - "vindicator_attack": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "query.is_riding ? 0.0 : ((math.cos(query.life_time * 20.0 * 10.89) * 28.65) + (math.sin(variable.attack_time * 180.0) * 68.76 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0)) * 22.92))", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "(-108 + math.cos(query.life_time * 20.0 * 3.84) * 2.87) + (math.sin(variable.attack_time * 180.0) * 126.05 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0)) * 22.92)", - 0, - 0 - ] - } - } - }, - "vindicator_hand_attack": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "(-108 + math.cos(query.life_time * 20.0 * 3.84) * 2.87) + (math.sin(variable.attack_time * 180.0) * 126.05 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0)) * 22.92)", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "(-108 + math.cos(query.life_time * 20.0 * 3.84) * 2.87) + (math.sin(variable.attack_time * 180.0) * 126.05 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0)) * 22.92)", - 0, - 0 - ] - } - } - }, - "vindicator_walk": { - "loop": true, - "bones": { - "leg0": { - "rotation": [ - "(math.cos(query.modified_distance_moved * 38.17) * 80.21) * query.modified_move_speed * 0.5", - 0, - 0 - ] - }, - "leg1": { - "rotation": [ - "(math.cos(query.modified_distance_moved * 38.17 + 180) * 80.21) * query.modified_move_speed * 0.5", - 0, - 0 - ] - } - } - }, - "celebrating": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "(math.cos(query.life_time * 800.0) * 2.865)", - 180, - -135 - ] - }, - "rightarm": { - "rotation": [ - "(math.cos(query.life_time * 800.0) * 2.865)", - 180, - 153 - ] - } - } - } - }, - "render_controllers": ["controller.render.vindicator"], - "enable_attachables": true, - "animation_controllers": { - "controller_look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "controller_vindicator_base": { - "initial_state": "default", - "states": { - "default": { - "blend_transition": 0.2, - "blend_via_shortest_path": true, - "transitions": [ - {"celebrating": "query.is_celebrating"}, - { - "hand_attack": "!query.is_item_equipped && variable.has_target && variable.attack_time >= 0.0" - }, - { - "melee_attack": "query.is_item_equipped && variable.has_target && variable.attack_time >= 0.0" - } - ] - }, - "hand_attack": { - "blend_transition": 0.2, - "blend_via_shortest_path": true, - "animations": ["vindicator_hand_attack"], - "transitions": [ - { - "default": "query.is_item_equipped || !variable.has_target || variable.attack_time < 0.0 || query.is_celebrating" - } - ] - }, - "melee_attack": { - "blend_transition": 0.2, - "blend_via_shortest_path": true, - "animations": ["vindicator_attack"], - "transitions": [ - { - "default": "!query.is_item_equipped || !variable.has_target || variable.attack_time < 0.0 || query.is_celebrating" - } - ] - }, - "celebrating": { - "animations": ["celebrating"], - "blend_transition": 0.2, - "blend_via_shortest_path": true, - "transitions": [{"default": "!query.is_celebrating"}] - } - } - }, - "controller_riding": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"riding": "query.is_riding"}]}, - "riding": { - "animations": ["riding.arms", "riding.legs"], - "transitions": [{"default": "!query.is_riding"}] - } - } - } - } - }, - "wandering_trader": { - "identifier": "minecraft:wandering_trader", - "materials": {"default": "wandering_trader"}, - "textures": {"default": "textures/entity/wandering_trader"}, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 2.5, - "visible_bounds_offset": [0, 1.25, 0], - "bones": [ - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 10, 8], "uv": [0, 0]} - ] - }, - { - "name": "helmet", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 10, 8], - "uv": [32, 0], - "inflate": 0.5 - } - ] - }, - { - "name": "brim", - "parent": "head", - "pivot": [0, 24, 0], - "bind_pose_rotation": [-90, 0, 0], - "cubes": [ - { - "origin": [-8, 16, -6], - "size": [16, 16, 1], - "uv": [30, 47], - "inflate": 0.1 - } - ] - }, - { - "name": "nose", - "parent": "head", - "pivot": [0, 26, 0], - "cubes": [ - {"origin": [-1, 23, -6], "size": [2, 4, 2], "uv": [24, 0]} - ] - }, - { - "name": "body", - "locators": {"lead_hold": [0, 40, 0]}, - "cubes": [ - {"origin": [-4, 12, -3], "size": [8, 12, 6], "uv": [16, 20]}, - { - "origin": [-4, 6, -3], - "size": [8, 18, 6], - "uv": [0, 38], - "inflate": 0.5 - } - ] - }, - { - "name": "arms", - "parent": "body", - "pivot": [0, 22, 0], - "cubes": [ - {"origin": [-4, 16, -2], "size": [8, 4, 4], "uv": [40, 38]}, - {"origin": [-8, 16, -2], "size": [4, 8, 4], "uv": [44, 22]}, - { - "origin": [4, 16, -2], - "size": [4, 8, 4], - "uv": [44, 22], - "mirror": true - } - ] - }, - {"name": "held_item", "parent": "arms", "pivot": [0, 0, 0]}, - { - "name": "leg0", - "parent": "body", - "pivot": [-2, 12, 0], - "cubes": [ - {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 22]} - ] - }, - { - "name": "leg1", - "parent": "body", - "pivot": [2, 12, 0], - "cubes": [ - { - "origin": [0, 0, -2], - "size": [4, 12, 4], - "uv": [0, 22], - "mirror": true - } - ] - } - ] - } - }, - "scripts": {"scale": "0.9375"}, - "animations": { - "general": { - "loop": true, - "bones": { - "arms": {"position": [0, -1, -1], "rotation": ["-42.97 - this", 0, 0]} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "raise_arms": { - "loop": true, - "bones": {"arms": {"rotation": ["variable.raise_arms * -15.0", 0, 0]}} - }, - "move": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": [ - "(math.cos(query.anim_time * 38.17) * 40.0) - this", - "-this", - 0 - ] - }, - "leg1": { - "rotation": [ - "(math.cos(query.anim_time * 38.17 + 180) * 40.0) - this", - "-this", - 0 - ] - } - } - } - }, - "animation_controllers": { - "general": { - "initial_state": "default", - "states": { - "default": { - "animations": ["general", {"look_at_target": "!query.is_sleeping"}] - } - } - }, - "raise_arms": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"raising": "variable.raise_arms > 0.0"}] - }, - "raising": { - "animations": ["raise_arms"], - "transitions": [{"default": "variable.raise_arms == 0.0"}] - } - } - }, - "move": { - "initial_state": "default", - "states": { - "default": {"animations": [{"move": "query.modified_move_speed"}]} - } - } - }, - "render_controllers": ["controller.render.wandering_trader"], - "spawn_egg": {"texture": "spawn_egg_wandering_trader"} - }, - "witch": { - "identifier": "minecraft:witch", - "min_engine_version": "1.8.0", - "materials": {"default": "witch"}, - "textures": {"default": "textures/entity/witch"}, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1.5, 0], - "texturewidth": 64, - "textureheight": 128, - "bones": [ - { - "name": "nose", - "parent": "head", - "cubes": [ - { - "origin": [0, 25, -6.75], - "size": [1, 1, 1], - "uv": [0, 0], - "inflate": -0.25 - } - ] - }, - { - "name": "hat", - "parent": "head", - "pivot": [-5, 32.03125, -5], - "cubes": [ - {"origin": [-5, 32.05, -5], "size": [10, 2, 10], "uv": [0, 64]} - ] - }, - { - "name": "hat2", - "parent": "hat", - "pivot": [1.75, 32, 2], - "cubes": [ - {"origin": [-3.25, 33.5, -3], "size": [7, 4, 7], "uv": [0, 76]} - ], - "rotation": [-3, 0, 1.5] - }, - { - "name": "hat3", - "parent": "hat2", - "pivot": [1.75, 35, 2], - "cubes": [ - {"origin": [-1.5, 36.5, -1], "size": [4, 4, 4], "uv": [0, 87]} - ], - "rotation": [-6, 0, 3] - }, - { - "name": "hat4", - "parent": "hat3", - "pivot": [1.75, 38, 2], - "cubes": [ - { - "origin": [0.25, 40, 1], - "size": [1, 2, 1], - "uv": [0, 95], - "inflate": 0.25 - } - ], - "rotation": [-12, 0, 6] - } - ] - } - }, - "scripts": {"scale": "0.9375"}, - "animations": { - "villager_general": { - "loop": true, - "bones": { - "arms": {"position": [0, -1, -1], "rotation": ["-42.97 - this", 0, 0]} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "move": { - "anim_time_update": "query.modified_distance_moved", - "loop": true, - "bones": { - "leg0": { - "rotation": [ - "(math.cos(query.anim_time * 38.17) * 40.0) - this", - "-this", - 0 - ] - }, - "leg1": { - "rotation": [ - "(math.cos(query.anim_time * 38.17 + 180) * 40.0) - this", - "-this", - 0 - ] - } - } - }, - "general": { - "loop": true, - "bones": { - "nose": { - "rotation": [ - "(variable.isholdingitem ? -25.7831 : (math.sin(query.life_time * 57.296) * 4.5)) - this", - 0, - "(math.cos(query.life_time * 57.296) * 2.5) - this" - ] - } - } - } - }, - "animation_controllers": { - "general": { - "initial_state": "default", - "states": { - "default": { - "animations": ["villager_general", "look_at_target", "general"] - } - } - }, - "move": { - "initial_state": "default", - "states": { - "default": {"animations": [{"move": "query.modified_move_speed"}]} - } - } - }, - "render_controllers": ["controller.render.witch"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 17} - }, - "wither": { - "identifier": "minecraft:wither", - "min_engine_version": "1.8.0", - "materials": {"default": "wither_boss", "armor": "wither_boss_armor"}, - "textures": { - "default": "textures/entity/wither/wither", - "armor_white": "textures/entity/wither/wither_armor", - "armor_blue": "textures/entity/wither/wither_armor", - "invulnerable": "textures/entity/wither/wither_invulnerable" - }, - "geometry": { - "default": { - "visible_bounds_width": 3, - "visible_bounds_height": 4, - "visible_bounds_offset": [0, 2, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "upperBodyPart1", - "cubes": [ - {"origin": [-10, 17.1, -0.5], "size": [20, 3, 3], "uv": [0, 16]} - ] - }, - { - "name": "upperBodyPart2", - "parent": "upperBodyPart1", - "pivot": [-2, 17.1, -0.5], - "cubes": [ - {"origin": [-2, 7.1, -0.5], "size": [3, 10, 3], "uv": [0, 22]}, - {"origin": [-6, 13.6, 0], "size": [11, 2, 2], "uv": [24, 22]}, - {"origin": [-6, 11.1, 0], "size": [11, 2, 2], "uv": [24, 22]}, - {"origin": [-6, 8.6, 0], "size": [11, 2, 2], "uv": [24, 22]} - ] - }, - { - "name": "upperBodyPart3", - "parent": "upperBodyPart2", - "pivot": [0, 24, 0], - "cubes": [{"origin": [0, 18, 0], "size": [3, 6, 3], "uv": [12, 22]}] - }, - { - "name": "head1", - "parent": "upperBodyPart1", - "pivot": [0, 20, 0], - "cubes": [{"origin": [-4, 20, -4], "size": [8, 8, 8], "uv": [0, 0]}] - }, - { - "name": "head2", - "parent": "upperBodyPart1", - "pivot": [-9, 18, -1], - "cubes": [ - {"origin": [-12, 18, -4], "size": [6, 6, 6], "uv": [32, 0]} - ] - }, - { - "name": "head3", - "parent": "upperBodyPart1", - "pivot": [9, 18, -1], - "cubes": [{"origin": [6, 18, -4], "size": [6, 6, 6], "uv": [32, 0]}] - } - ] - }, - "armor": { - "visible_bounds_width": 3, - "visible_bounds_height": 4, - "visible_bounds_offset": [0, 2, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "upperBodyPart1", - "cubes": [ - {"origin": [-10, 17.1, -0.5], "size": [20, 3, 3], "uv": [0, 16]} - ], - "inflate": 2 - }, - { - "name": "upperBodyPart2", - "parent": "upperBodyPart1", - "pivot": [-2, 17.1, -0.5], - "cubes": [ - {"origin": [-2, 7.1, -0.5], "size": [3, 10, 3], "uv": [0, 22]}, - {"origin": [-6, 13.6, 0], "size": [11, 2, 2], "uv": [24, 22]}, - {"origin": [-6, 11.1, 0], "size": [11, 2, 2], "uv": [24, 22]}, - {"origin": [-6, 8.6, 0], "size": [11, 2, 2], "uv": [24, 22]} - ], - "inflate": 2 - }, - { - "name": "upperBodyPart3", - "parent": "upperBodyPart2", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [0, 18, 0], "size": [3, 6, 3], "uv": [12, 22]} - ], - "inflate": 2 - }, - { - "name": "head1", - "parent": "upperBodyPart1", - "pivot": [0, 20, 0], - "cubes": [ - {"origin": [-4, 20, -4], "size": [8, 8, 8], "uv": [0, 0]} - ], - "inflate": 2 - }, - { - "name": "head2", - "parent": "upperBodyPart1", - "pivot": [-9, 18, -1], - "cubes": [ - {"origin": [-12, 18, -4], "size": [6, 6, 6], "uv": [32, 0]} - ], - "inflate": 2 - }, - { - "name": "head3", - "parent": "upperBodyPart1", - "pivot": [9, 18, -1], - "cubes": [ - {"origin": [6, 18, -4], "size": [6, 6, 6], "uv": [32, 0]} - ], - "inflate": 2 - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.base_scale = 2;", - "variable.swell_clamped = Math.clamp(query.swell_amount, 0.0, 1.0);", - "variable.wobble = 1.0 + Math.sin(query.swell_amount * 5730) * query.swell_amount * 0.01;", - "variable.swell_adjustment = Math.pow(variable.swell_clamped, 4);", - "variable.scale_xz = (1.0 + variable.swell_adjustment * 0.4) * variable.wobble;", - "variable.scale_y = (1.0 + variable.swell_adjustment * 0.1) / variable.wobble;", - "variable.body_base_rotation = Math.cos(query.life_time * 114.6);", - "variable.upper_body_rotation = (0.065 + 0.05 * variable.body_base_rotation) * 180 + query.target_x_rotation;", - "variable.is_invulnerable = query.invulnerable_ticks > 0.0;", - "variable.display_normal_skin = (query.invulnerable_ticks <= 0) || ((query.invulnerable_ticks <= 80) && (Math.mod(query.invulnerable_ticks / 5, 2) == 1));" - ], - "scalex": "variable.scale_xz * variable.base_scale", - "scaley": "variable.scale_y * variable.base_scale", - "scalez": "variable.scale_xz * variable.base_scale" - }, - "animations": { - "scale": { - "loop": true, - "bones": {"upperbodypart1": {"rotation": ["-this", "-this", "-this"]}} - }, - "move": { - "loop": true, - "bones": { - "upperbodypart2": { - "rotation": [ - "variable.upper_body_rotation - this", - "-this", - "-this" - ] - }, - "upperbodypart3": { - "position": [-2, -16.9, -0.5], - "rotation": [ - "((0.2 + 0.1 * variable.body_base_rotation) * 180) - this", - "-this", - "-this" - ] - } - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head1": { - "rotation": [ - "query.head_x_rotation(0) - this", - "query.head_y_rotation(0) - this", - "-this" - ] - }, - "head2": { - "rotation": [ - "query.head_x_rotation(1) - this", - "query.head_y_rotation(1) - this", - "-this" - ] - }, - "head3": { - "rotation": [ - "query.head_x_rotation(2) - this", - "query.head_y_rotation(2) - this", - "-this" - ] - } - } - } - }, - "animation_controllers": { - "move": { - "initial_state": "default", - "states": { - "default": {"animations": ["scale", "move", "look_at_target"]} - } - } - }, - "render_controllers": [ - "controller.render.wither_boss", - "controller.render.wither_boss_armor_white", - "controller.render.wither_boss_armor_blue" - ] - }, - "wither_skeleton": { - "identifier": "minecraft:wither_skeleton", - "min_engine_version": "1.8.0", - "materials": {"default": "skeleton"}, - "textures": {"default": "textures/entity/skeleton/wither_skeleton"}, - "geometry": { - "default": { - "texturewidth": 64, - "textureheight": 32, - "visible_bounds_width": 1.5, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1.5, 0], - "bones": [ - { - "name": "body", - "parent": "waist", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} - ] - }, - {"name": "waist", "pivot": [0, 12, 0]}, - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [{"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]}] - }, - { - "name": "hat", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 8, 8], - "uv": [32, 0], - "inflate": 0.5 - } - ], - "neverRender": true - }, - { - "name": "rightArm", - "parent": "body", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-6, 12, -1], "size": [2, 12, 2], "uv": [40, 16]} - ] - }, - { - "name": "rightItem", - "parent": "rightArm", - "pivot": [-5, 15, 1], - "neverRender": true - }, - { - "name": "leftArm", - "parent": "body", - "pivot": [5, 22, 0], - "cubes": [ - {"origin": [4, 12, -1], "size": [2, 12, 2], "uv": [40, 16]} - ], - "mirror": true - }, - { - "name": "leftItem", - "parent": "leftArm", - "pivot": [6, 15, 1], - "neverRender": true - }, - { - "name": "rightLeg", - "parent": "body", - "pivot": [-2, 12, 0], - "cubes": [ - {"origin": [-3, 0, -1], "size": [2, 12, 2], "uv": [0, 16]} - ] - }, - { - "name": "leftLeg", - "parent": "body", - "pivot": [2, 12, 0], - "cubes": [ - {"origin": [1, 0, -1], "size": [2, 12, 2], "uv": [0, 16]} - ], - "mirror": true - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;" - ] - }, - "animations": { - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "move": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - }, - "holding": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - } - } - }, - "brandish_spear": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "this * -0.5 - 157.5 - 22.5 * variable.charge_amount", - "-this", - 0 - ] - } - } - }, - "charging": { - "loop": true, - "bones": { - "rightarm": { - "rotation": ["22.5 * variable.charge_amount - this", "-this", 0] - } - } - }, - "attack.rotations": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46 - this", - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.sin(1.0 - math.pow(1.0 - variable.attack_time, 3.0) * 180.0) * (variable.is_brandishing_spear ? -1.0 : 1.0 )", - "variable.is_brandishing_spear ? 0.0 : (math.sin(math.sqrt(variable.attack_time) * 360) * 11.46) * 2.0", - 0 - ] - } - } - }, - "sneaking": { - "loop": true, - "bones": { - "body": {"rotation": ["0.5 - this", 0, 0]}, - "head": {"position": [0, 1, 0]}, - "leftarm": {"rotation": [72, 0, 0]}, - "leftleg": {"position": [0, -3, 4]}, - "rightarm": {"rotation": [72, 0, 0]}, - "rightleg": {"position": [0, -3, 4]} - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "damage_nearby_mobs": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["-45.0-this", "-this", "-this"]}, - "leftleg": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightarm": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-45.0-this", "-this", "-this"]} - } - }, - "bow_and_arrow": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "query.target_x_rotation - 90.0 - math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation + 28.65", - "-(math.cos(query.life_time * 103.2) * 2.865) - 2.865" - ] - }, - "rightarm": { - "rotation": [ - "query.target_x_rotation - 90.0 + math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation - 5.73", - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "use_item_progress": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "variable.use_item_startup_progress * -60.0 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -22.5 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -5.625 + variable.use_item_interval_progress * 11.25" - ] - } - } - }, - "wither_skeleton_attack": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "-90 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) - (math.sin(query.life_time * 76.776372) * 2.865) - this", - "5.73 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 0.6) - this", - "math.cos(query.life_time * 103.13244) * -2.865 - 2.865 - this" - ] - }, - "rightarm": { - "rotation": [ - "-90 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) + (math.sin(query.life_time * 76.776372) * 2.865) - this", - "(math.sin(variable.attack_time * 180.0) * 57.3) * 0.6 - 5.73 - this", - "math.cos(query.life_time * 103.13244) * 2.865 + 2.865 - this" - ] - } - } - }, - "swimming": { - "loop": true, - "bones": { - "body": { - "position": [ - 0, - "variable.swim_amount * -10.0 - this", - "variable.swim_amount * 9.0 - this" - ], - "rotation": [ - "variable.swim_amount * (90.0 + query.target_x_rotation)", - 0, - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) - (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, 14.325, variable.swim_amount) - (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "leftleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0 + 180.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) + (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, -14.325, variable.swim_amount) + (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "rightleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - } - } - } - }, - "animation_controllers": { - "look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - }, - "riding": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"riding": "query.is_riding"}]}, - "riding": { - "animations": ["riding.arms", "riding.legs"], - "transitions": [{"default": "!query.is_riding"}] - } - } - }, - "holding": { - "initial_state": "default", - "states": {"default": {"animations": ["holding"]}} - }, - "brandish_spear": { - "initial_state": "default", - "states": { - "brandish_spear": { - "animations": ["brandish_spear"], - "transitions": [{"default": "!variable.is_brandishing_spear"}] - }, - "default": { - "transitions": [{"brandish_spear": "variable.is_brandishing_spear"}] - } - } - }, - "charging": { - "initial_state": "default", - "states": { - "charging": { - "animations": ["charging"], - "transitions": [{"default": "!query.is_charging"}] - }, - "default": {"transitions": [{"charging": "query.is_charging"}]} - } - }, - "attack": { - "initial_state": "default", - "states": { - "attacking": { - "animations": ["attack.rotations"], - "transitions": [{"default": "variable.attack_time < 0.0"}] - }, - "default": { - "transitions": [{"attacking": "variable.attack_time >= 0.0"}] - } - } - }, - "sneaking": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"sneaking": "query.is_sneaking"}]}, - "sneaking": { - "animations": ["sneaking"], - "transitions": [{"default": "!query.is_sneaking"}] - } - } - }, - "damage_nearby_mobs": { - "initial_state": "default", - "states": { - "damage_nearby_mobs": { - "animations": ["damage_nearby_mobs"], - "transitions": [{"default": "!variable.damage_nearby_mobs"}] - }, - "default": { - "transitions": [ - {"damage_nearby_mobs": "variable.damage_nearby_mobs"} - ] - } - } - }, - "bow_and_arrow": { - "initial_state": "default", - "states": { - "bow_and_arrow": { - "animations": ["bow_and_arrow"], - "transitions": [{"default": "!query.has_target"}] - }, - "default": {"transitions": [{"bow_and_arrow": "query.has_target"}]} - } - }, - "use_item_progress": { - "initial_state": "default", - "states": { - "default": { - "transitions": [ - { - "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 )" - } - ] - }, - "use_item_progress": { - "animations": ["use_item_progress"], - "transitions": [ - { - "default": "( variable.use_item_interval_progress <= 0.0 ) && ( variable.use_item_startup_progress <= 0.0 )" - } - ] - } - } - }, - "wither_skeleton_attack": { - "initial_state": "default", - "states": { - "chase_target": { - "animations": ["wither_skeleton_attack"], - "transitions": [{"default": "!variable.has_target"}] - }, - "default": {"transitions": [{"chase_target": "variable.has_target"}]} - } - }, - "swimming": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"is_swimming": "variable.swim_amount > 0.0"}] - }, - "is_swimming": { - "animations": ["swimming"], - "transitions": [{"default": "variable.swim_amount <= 0.0"}] - } - } - } - }, - "render_controllers": ["controller.render.wither_skeleton"], - "enable_attachables": true, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 29} - }, - "wither_skull": { - "identifier": "minecraft:wither_skull", - "materials": {"default": "wither_skull"}, - "textures": {"default": "textures/entity/wither/wither"}, - "geometry": { - "default": { - "bones": [ - { - "name": "head", - "cubes": [{"origin": [-4, 0, -4], "size": [8, 8, 8], "uv": [0, 35]}] - } - ], - "visible_bounds_width": 1, - "visible_bounds_height": 1, - "texturewidth": 64, - "textureheight": 64 - } - }, - "animations": { - "move": { - "loop": true, - "bones": {"head": {"rotation": [0, "-query.target_y_rotation", 0]}} - } - }, - "scripts": {"animate": ["move"]}, - "render_controllers": ["controller.render.wither_skull"] - }, - "wolf": { - "identifier": "minecraft:wolf", - "materials": {"default": "wolf"}, - "textures": { - "default": "textures/entity/wolf/wolf", - "angry": "textures/entity/wolf/wolf_angry", - "tame": "textures/entity/wolf/wolf_tame" - }, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0.5, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "head", - "pivot": [-1, 10.5, -7], - "locators": {"lead": [-1, 10.5, -7]}, - "cubes": [ - {"origin": [-4, 7.5, -9], "size": [6, 6, 4], "uv": [0, 0]}, - {"origin": [-4, 13.5, -7], "size": [2, 2, 1], "uv": [16, 14]}, - {"origin": [0, 13.5, -7], "size": [2, 2, 1], "uv": [16, 14]}, - { - "origin": [-2.5, 7.515625, -12], - "size": [3, 3, 4], - "uv": [0, 10] - } - ] - }, - { - "name": "body", - "pivot": [0, 10, 2], - "cubes": [ - {"origin": [-4, 3, -1], "size": [6, 9, 6], "uv": [18, 14]} - ] - }, - { - "name": "upperBody", - "pivot": [-1, 10, 2], - "cubes": [{"origin": [-5, 7, -1], "size": [8, 6, 7], "uv": [21, 0]}] - }, - { - "name": "leg0", - "pivot": [-2.5, 8, 7], - "cubes": [ - {"origin": [-3.5, 0, 6], "size": [2, 8, 2], "uv": [0, 18]} - ] - }, - { - "name": "leg1", - "pivot": [0.5, 8, 7], - "cubes": [ - {"origin": [-0.5, 0, 6], "size": [2, 8, 2], "uv": [0, 18]} - ] - }, - { - "name": "leg2", - "pivot": [-2.5, 8, -4], - "cubes": [ - {"origin": [-3.5, 0, -5], "size": [2, 8, 2], "uv": [0, 18]} - ] - }, - { - "name": "leg3", - "pivot": [0.5, 8, -4], - "cubes": [ - {"origin": [-0.5, 0, -5], "size": [2, 8, 2], "uv": [0, 18]} - ] - }, - { - "name": "tail", - "pivot": [-1, 12, 8], - "cubes": [{"origin": [-2, 4, 7], "size": [2, 8, 2], "uv": [9, 18]}] - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.body_shake_angle = 0.05 * query.frame_alpha + query.shake_angle;", - "variable.body_roll_progress = Math.clamp((variable.body_shake_angle - 0.16) / 1.8, 0, 1);", - "variable.body_rot_z = Math.sin(variable.body_roll_progress * 180) * Math.sin(variable.body_roll_progress * 1980) * 27;", - "variable.upper_body_roll_progress = Math.clamp((variable.body_shake_angle - 0.08) / 1.8, 0, 1);", - "variable.upper_body_rot_z = (Math.sin(variable.upper_body_roll_progress * 180) * Math.sin(variable.upper_body_roll_progress * 1980) * 27) - variable.body_rot_z;", - "variable.tail_roll_progress = Math.clamp((variable.body_shake_angle - 0.2) / 1.8, 0, 1);", - "variable.tail_rot_z = (Math.sin(variable.tail_roll_progress * 180) * Math.sin(variable.tail_roll_progress * 1980) * 27) - variable.body_rot_z;", - "variable.head_roll_progress = Math.clamp(variable.body_shake_angle / 1.8, 0, 1);", - "variable.head_rot_z = (Math.sin(variable.head_roll_progress * 180) * Math.sin(variable.head_roll_progress * 1980) * 27) - variable.body_rot_z;" - ] - }, - "animations": { - "wolf_setup": { - "loop": true, - "bones": { - "body": { - "position": ["-this", "-14 - this", "2.0 - this"], - "rotation": ["90 - this", 0, 0] - }, - "leg0": {"position": ["-2.5 - this", "-16 - this", "7 - this"]}, - "leg1": {"position": ["0.5 - this", "-16 - this", "7 - this"]}, - "leg2": {"position": ["-2.5 - this", "-16 - this", "-4 - this"]}, - "leg3": {"position": ["0.5 - this", "-16 - this", "-4 - this"]}, - "tail": {"position": ["-1.0 - this", "-12 - this", "8.0 - this"]}, - "upperbody": { - "position": ["-1.0 - this", "-14 - this", "-3.0 - this"], - "rotation": ["90 - this", 0, 0] - } - } - }, - "wolf_baby_scaling": { - "loop": true, - "bones": {"head": {"position": [0, 1, -2], "scale": 1.6}} - }, - "wolf_look_at": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation - this", - "query.target_y_rotation - this", - 0 - ] - } - } - }, - "wolf_head_rot_z": { - "loop": true, - "bones": { - "head": { - "rotation": [ - 0, - 0, - "(query.is_interested ? (query.head_roll_angle * 57.3) : 0) + (query.is_shaking_wetness ? variable.head_rot_z : 0) - this" - ] - } - } - }, - "wolf_tail_default": { - "loop": true, - "bones": { - "tail": { - "rotation": [ - "query.tail_angle * 57.3 - this", - 0, - "variable.tail_rot_z - this" - ] - } - } - }, - "wolf_angry": { - "loop": true, - "bones": { - "tail": { - "rotation": [ - 0, - "query.is_angry ? -this : (math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed * 80.22 - this)", - 0 - ] - } - } - }, - "wolf_sitting": { - "loop": true, - "bones": { - "body": { - "position": ["-this", "-18 - this", "-this"], - "rotation": ["45.0 - this", 0, 0] - }, - "leg0": { - "position": ["-2.5 - this", "-22 - this", "2 - this"], - "rotation": ["270 - this", 0, 0] - }, - "leg1": { - "position": ["0.5 - this", "-22 - this", "2 - this"], - "rotation": ["270 - this", 0, 0] - }, - "leg2": { - "position": ["-2.49 - this", "-17 - this", "-4 - this"], - "rotation": ["333 - this", 0, 0] - }, - "leg3": { - "position": ["0.51 - this", "-17 - this", "-4 - this"], - "rotation": ["333 - this", 0, 0] - }, - "tail": {"position": ["-1.0 - this", "-19 - this", "6.0 - this"]}, - "upperbody": { - "position": ["-1.0 - this", "-16 - this", "-3.0 - this"], - "rotation": ["72 - this", "-this", 0] - } - } - }, - "wolf_shaking": { - "loop": true, - "bones": { - "body": {"rotation": [0, 0, "variable.body_rot_z - this"]}, - "upperbody": {"rotation": [0, 0, "variable.upper_body_rot_z - this"]} - } - }, - "wolf_leg_default": { - "loop": true, - "bones": { - "leg0": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17) * 80.22 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "leg1": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 180) * 80.22 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "leg2": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17 + 180) * 80.22 * query.modified_move_speed - this", - 0, - 0 - ] - }, - "leg3": { - "rotation": [ - "math.cos(query.modified_distance_moved * 38.17) * 80.22 * query.modified_move_speed - this", - 0, - 0 - ] - } - } - } - }, - "animation_controllers": { - "wolf_setup": { - "initial_state": "default", - "states": {"default": {"animations": ["wolf_setup"]}} - }, - "wolf_look_at": { - "initial_state": "default", - "states": {"default": {"animations": ["wolf_look_at"]}} - }, - "wolf_baby_scaling": { - "initial_state": "default", - "states": { - "baby": { - "animations": ["wolf_baby_scaling"], - "transitions": [{"default": "!query.is_baby"}] - }, - "default": {"transitions": [{"baby": "query.is_baby"}]} - } - }, - "wolf_head_rot_z": { - "initial_state": "default", - "states": { - "default": { - "transitions": [ - {"rot": "query.is_interested || query.is_shaking_wetness"} - ] - }, - "rot": { - "animations": ["wolf_head_rot_z"], - "transitions": [ - {"default": "!query.is_interested && !query.is_shaking_wetness"} - ] - } - } - }, - "wolf_tail_default": { - "initial_state": "default", - "states": {"default": {"animations": ["wolf_tail_default"]}} - }, - "wolf_angry": { - "initial_state": "default", - "states": {"default": {"animations": ["wolf_angry"]}} - }, - "wolf_sitting": { - "initial_state": "default", - "states": { - "default": { - "animations": ["wolf_leg_default"], - "transitions": [{"sitting": "query.is_sitting"}] - }, - "sitting": { - "animations": ["wolf_sitting"], - "transitions": [{"default": "!query.is_sitting"}] - } - } - }, - "wolf_shaking": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"shaking": "query.is_shaking_wetness"}]}, - "shaking": { - "animations": ["wolf_shaking"], - "transitions": [{"default": "!query.is_shaking_wetness"}] - } - } - } - }, - "render_controllers": ["controller.render.wolf"], - "spawn_egg": {"texture": "spawn_egg", "texture_index": 4} - }, - "zoglin": { - "identifier": "minecraft:zoglin", - "materials": {"default": "zoglin"}, - "textures": {"default": "textures/entity/hoglin/zoglin"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 19, -3], - "cubes": [ - { - "origin": [-8, 11, -7], - "size": [16, 14, 26], - "inflate": 0.02, - "uv": [1, 1] - }, - { - "origin": [0, 22, -10], - "size": [0, 10, 19], - "inflate": 0.02, - "uv": [90, 33] - } - ], - "locators": {"lead": [0, 20, -5]} - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 22, -5], - "rotation": [50, 0, 0], - "cubes": [ - {"origin": [-7, 21, -24], "size": [14, 6, 19], "uv": [61, 1]}, - {"origin": [-8, 22, -19], "size": [2, 11, 2], "uv": [1, 13]}, - {"origin": [6, 22, -19], "size": [2, 11, 2], "uv": [1, 13]} - ] - }, - { - "name": "right_ear", - "parent": "head", - "pivot": [-7, 27, -7], - "rotation": [0, 0, -50], - "cubes": [ - {"origin": [-13, 26, -10], "size": [6, 1, 4], "uv": [1, 1]} - ] - }, - { - "name": "left_ear", - "parent": "head", - "pivot": [7, 27, -7], - "rotation": [0, 0, 50], - "cubes": [{"origin": [7, 26, -10], "size": [6, 1, 4], "uv": [1, 6]}] - }, - { - "name": "leg_back_right", - "pivot": [6, 8, 17], - "cubes": [ - {"origin": [-8, 0, 13], "size": [5, 11, 5], "uv": [21, 45]} - ] - }, - { - "name": "leg_back_left", - "pivot": [-6, 8, 17], - "cubes": [{"origin": [3, 0, 13], "size": [5, 11, 5], "uv": [0, 45]}] - }, - { - "name": "leg_front_right", - "pivot": [-6, 12, -3], - "cubes": [ - {"origin": [-8, 0, -6], "size": [6, 14, 6], "uv": [66, 42]} - ] - }, - { - "name": "leg_front_left", - "pivot": [6, 12, -3], - "cubes": [ - {"origin": [2, 0, -6], "size": [6, 14, 6], "uv": [41, 42]} - ] - } - ], - "visible_bounds_width": 4, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1.5, 0], - "texturewidth": 128, - "textureheight": 64 - } - }, - "spawn_egg": {"base_color": "#c66e55", "overlay_color": "#e6e6e6"}, - "scripts": { - "pre_animation": [ - "variable.tcos_right_side = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;", - "variable.tcos_left_side = -variable.tcos_right_side;", - "variable.attack_head_rot = Math.sin(variable.attack_time * 180.0) * -37.3;" - ], - "animate": [ - "walk", - "look_at_target", - {"attack": "variable.has_target && variable.attack_time >= 0.0"}, - {"hoglin_baby_scaling": "query.is_baby"} - ] - }, - "animations": { - "walk": { - "loop": true, - "bones": { - "left_ear": {"rotation": [0, 0, "variable.tcos_left_side * 0.5"]}, - "right_ear": {"rotation": [0, 0, "variable.tcos_right_side * 0.5"]}, - "leg_back_right": {"rotation": ["variable.tcos_right_side", 0, 0]}, - "leg_back_left": {"rotation": ["variable.tcos_left_side", 0, 0]}, - "leg_front_right": {"rotation": ["-variable.tcos_right_side", 0, 0]}, - "leg_front_left": {"rotation": ["-variable.tcos_left_side", 0, 0]} - } - }, - "look_at_target": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [0, "query.target_y_rotation - this", 0] - } - } - }, - "attack": { - "loop": true, - "bones": {"head": {"rotation": ["variable.attack_head_rot", 0, 0]}} - }, - "hoglin_baby_scaling": { - "loop": true, - "bones": {"head": {"position": [0, 10, 4], "scale": 1.4}} - } - }, - "render_controllers": ["controller.render.zoglin"] - }, - "zombie": { - "identifier": "minecraft:zombie", - "min_engine_version": "1.8.0", - "materials": {"default": "zombie"}, - "textures": {"default": "textures/entity/zombie/zombie"}, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 64, - "textureheight": 32, - "bones": [ - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} - ], - "parent": "waist" - }, - {"name": "waist", "neverRender": true, "pivot": [0, 12, 0]}, - { - "name": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]} - ], - "parent": "body" - }, - { - "name": "hat", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 8, 8], - "uv": [32, 0], - "inflate": 0.5 - } - ], - "neverRender": true, - "parent": "head" - }, - { - "name": "rightArm", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} - ], - "parent": "body" - }, - { - "name": "rightItem", - "pivot": [-6, 15, 1], - "neverRender": true, - "parent": "rightArm" - }, - { - "name": "leftArm", - "pivot": [5, 22, 0], - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} - ], - "mirror": true, - "parent": "body" - }, - { - "name": "rightLeg", - "pivot": [-1.9, 12, 0], - "cubes": [ - {"origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} - ], - "parent": "body" - }, - { - "name": "leftLeg", - "pivot": [1.9, 12, 0], - "cubes": [ - {"origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} - ], - "mirror": true, - "parent": "body" - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 12}, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;" - ] - }, - "animations": { - "humanoid_big_head": {"loop": true, "bones": {"head": {"scale": 1.4}}}, - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "move": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - }, - "holding": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - } - } - }, - "brandish_spear": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "this * -0.5 - 157.5 - 22.5 * variable.charge_amount", - "-this", - 0 - ] - } - } - }, - "charging": { - "loop": true, - "bones": { - "rightarm": { - "rotation": ["22.5 * variable.charge_amount - this", "-this", 0] - } - } - }, - "attack.rotations": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46 - this", - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.sin(1.0 - math.pow(1.0 - variable.attack_time, 3.0) * 180.0) * (variable.is_brandishing_spear ? -1.0 : 1.0 )", - "variable.is_brandishing_spear ? 0.0 : (math.sin(math.sqrt(variable.attack_time) * 360) * 11.46) * 2.0", - 0 - ] - } - } - }, - "sneaking": { - "loop": true, - "bones": { - "body": {"rotation": ["0.5 - this", 0, 0]}, - "head": {"position": [0, 1, 0]}, - "leftarm": {"rotation": [72, 0, 0]}, - "leftleg": {"position": [0, -3, 4]}, - "rightarm": {"rotation": [72, 0, 0]}, - "rightleg": {"position": [0, -3, 4]} - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "damage_nearby_mobs": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["-45.0-this", "-this", "-this"]}, - "leftleg": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightarm": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-45.0-this", "-this", "-this"]} - } - }, - "bow_and_arrow": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "query.target_x_rotation - 90.0 - math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation + 28.65", - "-(math.cos(query.life_time * 103.2) * 2.865) - 2.865" - ] - }, - "rightarm": { - "rotation": [ - "query.target_x_rotation - 90.0 + math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation - 5.73", - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "use_item_progress": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "variable.use_item_startup_progress * -60.0 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -22.5 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -5.625 + variable.use_item_interval_progress * 11.25" - ] - } - } - }, - "zombie_attack_bare_hand": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "-90.0 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) - (math.sin(query.life_time * 76.776372) * 2.865) - this", - "5.73 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 0.6) - this", - "math.cos(query.life_time * 103.13244) * -2.865 - 2.865 - this" - ] - }, - "rightarm": { - "rotation": [ - "90.0 * (variable.is_brandishing_spear - 1.0) - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) + (math.sin(query.life_time * 76.776372) * 2.865) - this", - "(math.sin(variable.attack_time * 180.0) * 57.3) * 0.6 - 5.73 - this", - "math.cos(query.life_time * 103.13244) * 2.865 + 2.865 - this" - ] - } - } - }, - "swimming": { - "loop": true, - "bones": { - "body": { - "position": [ - 0, - "variable.swim_amount * -10.0 - this", - "variable.swim_amount * 9.0 - this" - ], - "rotation": [ - "variable.swim_amount * (90.0 + query.target_x_rotation)", - 0, - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) - (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, 14.325, variable.swim_amount) - (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "leftleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0 + 180.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) + (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, -14.325, variable.swim_amount) + (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "rightleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - } - } - } - }, - "animation_controllers": { - "humanoid_baby_big_head": { - "initial_state": "default", - "states": { - "baby": { - "animations": ["humanoid_big_head"], - "transitions": [{"default": "!query.is_baby"}] - }, - "default": {"transitions": [{"baby": "query.is_baby"}]} - } - }, - "look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - }, - "riding": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"riding": "query.is_riding"}]}, - "riding": { - "animations": ["riding.arms", "riding.legs"], - "transitions": [{"default": "!query.is_riding"}] - } - } - }, - "holding": { - "initial_state": "default", - "states": {"default": {"animations": ["holding"]}} - }, - "brandish_spear": { - "initial_state": "default", - "states": { - "brandish_spear": { - "animations": ["brandish_spear"], - "transitions": [{"default": "!variable.is_brandishing_spear"}] - }, - "default": { - "transitions": [{"brandish_spear": "variable.is_brandishing_spear"}] - } - } - }, - "charging": { - "initial_state": "default", - "states": { - "charging": { - "animations": ["charging"], - "transitions": [{"default": "!query.is_charging"}] - }, - "default": {"transitions": [{"charging": "query.is_charging"}]} - } - }, - "attack": { - "initial_state": "default", - "states": { - "attacking": { - "animations": ["attack.rotations"], - "transitions": [{"default": "variable.attack_time < 0.0"}] - }, - "default": { - "transitions": [{"attacking": "variable.attack_time >= 0.0"}] - } - } - }, - "sneaking": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"sneaking": "query.is_sneaking"}]}, - "sneaking": { - "animations": ["sneaking"], - "transitions": [{"default": "!query.is_sneaking"}] - } - } - }, - "bob": { - "initial_state": "default", - "states": {"default": {"animations": ["bob"]}} - }, - "damage_nearby_mobs": { - "initial_state": "default", - "states": { - "damage_nearby_mobs": { - "animations": ["damage_nearby_mobs"], - "transitions": [{"default": "!variable.damage_nearby_mobs"}] - }, - "default": { - "transitions": [ - {"damage_nearby_mobs": "variable.damage_nearby_mobs"} - ] - } - } - }, - "bow_and_arrow": { - "initial_state": "default", - "states": { - "bow_and_arrow": { - "animations": ["bow_and_arrow"], - "transitions": [{"default": "!query.has_target"}] - }, - "default": {"transitions": [{"bow_and_arrow": "query.has_target"}]} - } - }, - "use_item_progress": { - "initial_state": "default", - "states": { - "default": { - "transitions": [ - { - "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 )" - } - ] - }, - "use_item_progress": { - "animations": ["use_item_progress"], - "transitions": [ - { - "default": "( variable.use_item_interval_progress <= 0.0 ) && ( variable.use_item_startup_progress <= 0.0 )" - } - ] - } - } - }, - "zombie_attack_bare_hand": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"is_bare_hand": "variable.is_holding_left != 1.0"}] - }, - "is_bare_hand": { - "animations": ["zombie_attack_bare_hand"], - "transitions": [{"default": "variable.is_holding_left == 1.0"}] - } - } - }, - "swimming": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"is_swimming": "variable.swim_amount > 0.0"}] - }, - "is_swimming": { - "animations": ["swimming"], - "transitions": [{"default": "variable.swim_amount <= 0.0"}] - } - } - } - }, - "render_controllers": ["controller.render.zombie"], - "enable_attachables": true - }, - "zombie_horse": { - "identifier": "minecraft:zombie_horse", - "textures": { - "base_brown": "textures/entity/horse/horse_brown", - "base_white": "textures/entity/horse/horse_white", - "base_chestnut": "textures/entity/horse/horse_chestnut", - "base_creamy": "textures/entity/horse/horse_creamy", - "base_black": "textures/entity/horse/horse_black", - "base_gray": "textures/entity/horse/horse_gray", - "base_darkbrown": "textures/entity/horse/horse_darkbrown", - "markings_none": "textures/entity/horse/horse_markings_none", - "markings_white": "textures/entity/horse/horse_markings_white", - "markings_whitefield": "textures/entity/horse/horse_markings_whitefield", - "markings_whitedots": "textures/entity/horse/horse_markings_whitedots", - "markings_blackdots": "textures/entity/horse/horse_markings_blackdots", - "mule": "textures/entity/horse/mule", - "donkey": "textures/entity/horse/donkey", - "skeleton": "textures/entity/horse/horse_skeleton", - "zombie": "textures/entity/horse/horse_zombie", - "armor_none": "textures/entity/horse/armor/horse_armor_none", - "armor_leather": "textures/entity/horse/armor/horse_armor_leather", - "armor_iron": "textures/entity/horse/armor/horse_armor_iron", - "armor_gold": "textures/entity/horse/armor/horse_armor_gold", - "armor_diamond": "textures/entity/horse/armor/horse_armor_diamond" - }, - "geometry": { - "default": { - "visible_bounds_width": 2, - "visible_bounds_height": 3, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 128, - "textureheight": 128, - "bones": [ - { - "name": "Body", - "pivot": [0, 13, 9], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 11, -10], "size": [10, 10, 24], "uv": [0, 34]} - ] - }, - { - "name": "TailA", - "pivot": [0, 21, 14], - "rotation": [-65, 0, 0], - "cubes": [ - {"origin": [-1, 20, 14], "size": [2, 2, 3], "uv": [44, 0]} - ] - }, - { - "name": "TailB", - "pivot": [0, 21, 14], - "rotation": [-65, 0, 0], - "cubes": [ - {"origin": [-1.5, 19, 17], "size": [3, 4, 7], "uv": [38, 7]} - ] - }, - { - "name": "TailC", - "pivot": [0, 21, 14], - "rotation": [-80.34, 0, 0], - "cubes": [ - {"origin": [-1.5, 21.5, 23], "size": [3, 4, 7], "uv": [24, 3]} - ] - }, - { - "name": "Leg1A", - "pivot": [4, 15, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.5, 8, 8.5], "size": [4, 9, 5], "uv": [78, 29]} - ] - }, - { - "name": "Leg1B", - "pivot": [4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2, 3, 9.5], "size": [3, 5, 3], "uv": [78, 43]} - ] - }, - { - "name": "Leg1C", - "pivot": [4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.5, -0.1, 9], "size": [4, 3, 4], "uv": [78, 51]} - ] - }, - { - "name": "Leg2A", - "pivot": [-4, 15, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 8, 8.5], "size": [4, 9, 5], "uv": [96, 29]} - ] - }, - { - "name": "Leg2B", - "pivot": [-4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 3, 9.5], "size": [3, 5, 3], "uv": [96, 43]} - ] - }, - { - "name": "Leg2C", - "pivot": [-4, 8, 11], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, -0.1, 9], "size": [4, 3, 4], "uv": [96, 51]} - ] - }, - { - "name": "Leg3A", - "pivot": [4, 15, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.1, 8, -10.1], "size": [3, 8, 4], "uv": [44, 29]} - ] - }, - { - "name": "Leg3B", - "pivot": [4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.1, 3, -9.6], "size": [3, 5, 3], "uv": [44, 41]} - ] - }, - { - "name": "Leg3C", - "pivot": [4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [1.6, -0.1, -10.1], "size": [4, 3, 4], "uv": [44, 51]} - ] - }, - { - "name": "Leg4A", - "pivot": [-4, 15, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.1, 8, -10.1], "size": [3, 8, 4], "uv": [60, 29]} - ] - }, - { - "name": "Leg4B", - "pivot": [-4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.1, 3, -9.6], "size": [3, 5, 3], "uv": [60, 41]} - ] - }, - { - "name": "Leg4C", - "pivot": [-4, 8, -8], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.6, -0.1, -10.1], "size": [4, 3, 4], "uv": [60, 51]} - ] - }, - { - "name": "Head", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.5, 25, -11.5], "size": [5, 5, 7], "uv": [0, 0]} - ] - }, - { - "name": "UMouth", - "pivot": [0, 20.05, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2, 27.05, -17], "size": [4, 3, 6], "uv": [24, 18]} - ] - }, - { - "name": "LMouth", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2, 25, -16.5], "size": [4, 2, 5], "uv": [24, 27]} - ] - }, - { - "name": "Ear1", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [0.45, 29, -6], "size": [2, 3, 1], "uv": [0, 0]} - ] - }, - { - "name": "Ear2", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.45, 29, -6], "size": [2, 3, 1], "uv": [0, 0]} - ] - }, - { - "name": "MuleEarL", - "pivot": [0, 20, -10], - "rotation": [30, 0, 15], - "cubes": [ - {"origin": [-2, 29, -6], "size": [2, 7, 1], "uv": [0, 12]} - ] - }, - { - "name": "MuleEarR", - "pivot": [0, 20, -10], - "rotation": [30, 0, -15], - "cubes": [{"origin": [0, 29, -6], "size": [2, 7, 1], "uv": [0, 12]}] - }, - { - "name": "Neck", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.05, 15.8, -12], "size": [4, 14, 8], "uv": [0, 12]} - ] - }, - { - "name": "Bag1", - "pivot": [-7.5, 21, 10], - "rotation": [0, 90, 0], - "cubes": [ - {"origin": [-10.5, 13, 10], "size": [8, 8, 3], "uv": [0, 34]} - ] - }, - { - "name": "Bag2", - "pivot": [4.5, 21, 10], - "rotation": [0, 90, 0], - "cubes": [ - {"origin": [1.5, 13, 10], "size": [8, 8, 3], "uv": [0, 47]} - ] - }, - { - "name": "Saddle", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5, 21, -1], "size": [10, 1, 8], "uv": [80, 0]} - ] - }, - { - "name": "SaddleB", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-1.5, 22, -1], "size": [3, 1, 2], "uv": [106, 9]} - ] - }, - { - "name": "SaddleC", - "pivot": [0, 22, 2], - "rotation": [0, 0, 0], - "cubes": [{"origin": [-4, 22, 5], "size": [8, 1, 2], "uv": [80, 9]}] - }, - { - "name": "SaddleL2", - "pivot": [5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [4.5, 13, 1], "size": [1, 2, 2], "uv": [74, 0]} - ] - }, - { - "name": "SaddleL", - "pivot": [5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [4.5, 15, 1.5], "size": [1, 6, 1], "uv": [70, 0]} - ] - }, - { - "name": "SaddleR2", - "pivot": [-5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 13, 1], "size": [1, 2, 2], "uv": [74, 4]} - ] - }, - { - "name": "SaddleR", - "pivot": [-5, 21, 2], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-5.5, 15, 1.5], "size": [1, 6, 1], "uv": [80, 0]} - ] - }, - { - "name": "SaddleMouthL", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [1.5, 26, -14], "size": [1, 2, 2], "uv": [74, 13]} - ] - }, - { - "name": "SaddleMouthR", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-2.5, 26, -14], "size": [1, 2, 2], "uv": [74, 13]} - ] - }, - { - "name": "SaddleMouthLine", - "pivot": [0, 20, -10], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [2.6, 23, -16], "size": [0, 3, 16], "uv": [44, 10]} - ] - }, - { - "name": "SaddleMouthLineR", - "pivot": [0, 20, -10], - "rotation": [0, 0, 0], - "cubes": [ - {"origin": [-2.6, 23, -16], "size": [0, 3, 16], "uv": [44, 5]} - ] - }, - { - "name": "Mane", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - {"origin": [-1, 15.5, -5], "size": [2, 16, 4], "uv": [58, 0]} - ] - }, - { - "name": "HeadSaddle", - "pivot": [0, 20, -10], - "rotation": [30, 0, 0], - "cubes": [ - { - "origin": [-2.5, 25.1, -17], - "size": [5, 5, 12], - "uv": [80, 12], - "inflate": 0.05 - } - ] - } - ] - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 33} - }, - "zombified_piglin": { - "identifier": "minecraft:zombie_pigman", - "min_engine_version": "1.8.0", - "materials": {"default": "zombie"}, - "textures": {"default": "textures/entity/piglin/zombified_piglin"}, - "geometry": { - "default": { - "bones": [ - { - "name": "body", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]}, - { - "origin": [-4, 12, -2], - "size": [8, 12, 4], - "uv": [16, 32], - "inflate": 0.25 - } - ] - }, - { - "name": "head", - "parent": "body", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-5, 24, -4], - "size": [10, 8, 8], - "uv": [0, 0], - "inflate": -0.02 - }, - {"origin": [-2, 24, -5], "size": [4, 4, 1], "uv": [31, 1]}, - {"origin": [2, 24, -5], "size": [1, 2, 1], "uv": [2, 4]}, - {"origin": [-3, 24, -5], "size": [1, 2, 1], "uv": [2, 0]} - ], - "inflate": -0.02 - }, - { - "name": "leftear", - "parent": "head", - "pivot": [5, 30, 0], - "rotation": [0, 0, -30], - "cubes": [{"origin": [4, 25, -2], "size": [1, 5, 4], "uv": [51, 6]}] - }, - { - "name": "rightear", - "parent": "head", - "pivot": [-5, 30, 0], - "rotation": [0, 0, 30], - "cubes": [ - {"origin": [-5, 25, -2], "size": [1, 5, 4], "uv": [39, 6]} - ] - }, - {"name": "hat", "parent": "head", "pivot": [0, 24, 0]}, - { - "name": "rightarm", - "parent": "body", - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]}, - { - "origin": [-8, 12, -2], - "size": [4, 12, 4], - "uv": [40, 32], - "inflate": 0.25 - } - ] - }, - {"name": "rightItem", "parent": "rightarm", "pivot": [-6, 15, 1]}, - { - "name": "leftarm", - "parent": "body", - "pivot": [5, 22, 0], - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [32, 48]}, - { - "origin": [4, 12, -2], - "size": [4, 12, 4], - "uv": [48, 48], - "inflate": 0.25 - } - ] - }, - {"name": "leftItem", "parent": "leftArm", "pivot": [6, 15, 1]}, - { - "name": "rightleg", - "parent": "body", - "pivot": [-1.9, 12, 0], - "cubes": [ - {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 16]}, - { - "origin": [-4, 0, -2], - "size": [4, 12, 4], - "uv": [0, 32], - "inflate": 0.25 - } - ] - }, - { - "name": "leftleg", - "parent": "body", - "pivot": [1.9, 12, 0], - "cubes": [ - {"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [16, 48]}, - { - "origin": [0, 0, -2], - "size": [4, 12, 4], - "uv": [0, 48], - "inflate": 0.25 - } - ] - } - ], - "visible_bounds_width": 2, - "visible_bounds_height": 2, - "visible_bounds_offset": [0, 1, 0], - "texturewidth": 64, - "textureheight": 64 - } - }, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 13}, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;" - ] - }, - "animations": { - "humanoid_big_head": {"loop": true, "bones": {"head": {"scale": 1.4}}}, - "humanoid_base_pose": { - "loop": true, - "bones": {"waist": {"rotation": [0, 0, 0]}} - }, - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "move": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - }, - "holding": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - } - } - }, - "brandish_spear": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "this * -0.5 - 157.5 - 22.5 * variable.charge_amount", - "-this", - 0 - ] - } - } - }, - "charging": { - "loop": true, - "bones": { - "rightarm": { - "rotation": ["22.5 * variable.charge_amount - this", "-this", 0] - } - } - }, - "attack.rotations": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46 - this", - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.sin(1.0 - math.pow(1.0 - variable.attack_time, 3.0) * 180.0) * (variable.is_brandishing_spear ? -1.0 : 1.0 )", - "variable.is_brandishing_spear ? 0.0 : (math.sin(math.sqrt(variable.attack_time) * 360) * 11.46) * 2.0", - 0 - ] - } - } - }, - "sneaking": { - "loop": true, - "bones": { - "body": {"rotation": ["0.5 - this", 0, 0]}, - "head": {"position": [0, 1, 0]}, - "leftarm": {"rotation": [72, 0, 0]}, - "leftleg": {"position": [0, -3, 4]}, - "rightarm": {"rotation": [72, 0, 0]}, - "rightleg": {"position": [0, -3, 4]} - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "damage_nearby_mobs": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["-45.0-this", "-this", "-this"]}, - "leftleg": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightarm": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-45.0-this", "-this", "-this"]} - } - }, - "bow_and_arrow": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "query.target_x_rotation - 90.0 - math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation + 28.65", - "-(math.cos(query.life_time * 103.2) * 2.865) - 2.865" - ] - }, - "rightarm": { - "rotation": [ - "query.target_x_rotation - 90.0 + math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation - 5.73", - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "swimming": { - "animation_length": 1.3, - "loop": true, - "bones": { - "leftarm": { - "rotation": { - "0.7": { - "post": [ - "math.lerp(this, 11.25 * math.mod(query.modified_distance_moved, 26.0), variable.leftarmswim_amount)", - "math.lerp(this, 180.0, variable.leftarmswim_amount)", - "math.lerp(this, 72.77 + 13.4 * math.mod(query.modified_distance_moved, 26.0), variable.leftarmswim_amount)" - ], - "pre": [ - "math.lerp(this, 0.0, variable.leftarmswim_amount)", - "math.lerp(this, 180.0, variable.leftarmswim_amount)", - "math.lerp(this, 180.0 - 0.01877 * (-65.0 * math.mod(query.modified_distance_moved, 26.0) + math.mod(query.modified_distance_moved, 26.0) * math.mod(query.modified_distance_moved, 26.0)), variable.leftarmswim_amount)" - ] - }, - "1.1": [ - "math.lerp(this, 11.25 * math.mod(query.modified_distance_moved, 26.0), variable.leftarmswim_amount)", - "math.lerp(this, 180.0, variable.leftarmswim_amount)", - "math.lerp(this, 72.77 + 13.4 * math.mod(query.modified_distance_moved, 26.0), variable.leftarmswim_amount)" - ], - "1.3": { - "post": [ - "math.lerp(this, 90.0 - (22.5 * math.mod(query.modified_distance_moved, 26.0)), variable.leftarmswim_amount)", - "math.lerp(this, 180.0, variable.leftarmswim_amount)", - "math.lerp(this, 180.0, variable.leftarmswim_amount)" - ], - "pre": [ - "math.lerp(this, 11.25 * math.mod(query.modified_distance_moved, 26.0), variable.leftarmswim_amount)", - "math.lerp(this, 180.0, variable.leftarmswim_amount)", - "math.lerp(this, 72.77 + 13.4 * math.mod(query.modified_distance_moved, 26.0), variable.leftarmswim_amount)" - ] - } - } - }, - "leftleg": { - "rotation": [ - "math.lerp(this, math.cos(query.modified_distance_moved * 19.5 + 180.0) * 17.2, variable.leftarmswim_amount) - this", - 0, - 0 - ] - }, - "rightarm": { - "rotation": { - "0.7": { - "post": [ - "math.lerp(this, 11.25 * math.mod(query.modified_distance_moved, 26.0), variable.rightarmswim_amount)", - "math.lerp(this, 180.0, variable.rightarmswim_amount)", - "math.lerp(this, 72.77 + 13.4 * math.mod(query.modified_distance_moved, 26.0), variable.rightarmswim_amount)" - ], - "pre": [ - "math.lerp(this, 0.0, variable.rightarmswim_amount)", - "math.lerp(this, 180.0, variable.rightarmswim_amount)", - "math.lerp(this, -0.1019 * (-65.0 * math.mod(query.modified_distance_moved, 26.0) + math.mod(query.modified_distance_moved, 26.0) * math.mod(query.modified_distance_moved, 26.0)), variable.rightarmswim_amount)" - ] - }, - "1.1": [ - "math.lerp(this, 11.25 * math.mod(query.modified_distance_moved, 26.0), variable.rightarmswim_amount)", - "math.lerp(this, 180.0, variable.rightarmswim_amount)", - "math.lerp(this, 72.77 + 13.4 * math.mod(query.modified_distance_moved, 26.0), variable.rightarmswim_amount)" - ], - "1.3": { - "post": [ - "math.lerp(this, 90.0 - (22.5 * math.mod(query.modified_distance_moved, 26.0)), variable.rightarmswim_amount)", - "math.lerp(this, 180.0, variable.rightarmswim_amount)", - "math.lerp(this, 180.0, variable.rightarmswim_amount)" - ], - "pre": [ - "math.lerp(this, 11.25 * math.mod(query.modified_distance_moved, 26.0), variable.rightarmswim_amount)", - "math.lerp(this, 180.0, variable.rightarmswim_amount)", - "math.lerp(this, 72.77 + 13.4 * math.mod(query.modified_distance_moved, 26.0), variable.rightarmswim_amount)" - ] - } - } - }, - "rightleg": { - "rotation": [ - "math.lerp(this, math.cos(query.modified_distance_moved * 19.5) * 17.2, variable.leftarmswim_amount) - this", - 0, - 0 - ] - } - } - }, - "use_item_progress": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "variable.use_item_startup_progress * -60.0 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -22.5 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -5.625 + variable.use_item_interval_progress * 11.25" - ] - } - } - }, - "zombie_attack_bare_hand": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "-90.0 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) - (math.sin(query.life_time * 76.776372) * 2.865) - this", - "5.73 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 0.6) - this", - "math.cos(query.life_time * 103.13244) * -2.865 - 2.865 - this" - ] - }, - "rightarm": { - "rotation": [ - "90.0 * (variable.is_brandishing_spear - 1.0) - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) + (math.sin(query.life_time * 76.776372) * 2.865) - this", - "(math.sin(variable.attack_time * 180.0) * 57.3) * 0.6 - 5.73 - this", - "math.cos(query.life_time * 103.13244) * 2.865 + 2.865 - this" - ] - } - } - } - }, - "animation_controllers": { - "humanoid_baby_big_head": { - "initial_state": "default", - "states": { - "baby": { - "animations": ["humanoid_big_head"], - "transitions": [{"default": "!query.is_baby"}] - }, - "default": {"transitions": [{"baby": "query.is_baby"}]} - } - }, - "humanoid_base_pose": { - "initial_state": "default", - "states": {"default": {"animations": ["humanoid_base_pose"]}} - }, - "look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - }, - "riding": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"riding": "query.is_riding"}]}, - "riding": { - "animations": ["riding.arms", "riding.legs"], - "transitions": [{"default": "!query.is_riding"}] - } - } - }, - "holding": { - "initial_state": "default", - "states": {"default": {"animations": ["holding"]}} - }, - "brandish_spear": { - "initial_state": "default", - "states": { - "brandish_spear": { - "animations": ["brandish_spear"], - "transitions": [{"default": "!variable.is_brandishing_spear"}] - }, - "default": { - "transitions": [{"brandish_spear": "variable.is_brandishing_spear"}] - } - } - }, - "charging": { - "initial_state": "default", - "states": { - "charging": { - "animations": ["charging"], - "transitions": [{"default": "!query.is_charging"}] - }, - "default": {"transitions": [{"charging": "query.is_charging"}]} - } - }, - "attack": { - "initial_state": "default", - "states": { - "attacking": { - "animations": ["attack.rotations"], - "transitions": [{"default": "variable.attack_time < 0.0"}] - }, - "default": { - "transitions": [{"attacking": "variable.attack_time >= 0.0"}] - } - } - }, - "sneaking": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"sneaking": "query.is_sneaking"}]}, - "sneaking": { - "animations": ["sneaking"], - "transitions": [{"default": "!query.is_sneaking"}] - } - } - }, - "bob": { - "initial_state": "default", - "states": {"default": {"animations": ["bob"]}} - }, - "damage_nearby_mobs": { - "initial_state": "default", - "states": { - "damage_nearby_mobs": { - "animations": ["damage_nearby_mobs"], - "transitions": [{"default": "!variable.damage_nearby_mobs"}] - }, - "default": { - "transitions": [ - {"damage_nearby_mobs": "variable.damage_nearby_mobs"} - ] - } - } - }, - "bow_and_arrow": { - "initial_state": "default", - "states": { - "bow_and_arrow": { - "animations": ["bow_and_arrow"], - "transitions": [{"default": "!query.has_target"}] - }, - "default": {"transitions": [{"bow_and_arrow": "query.has_target"}]} - } - }, - "swimming": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"swimming": "variable.swim_amount > 0.0"}] - }, - "swimming": { - "animations": ["swimming"], - "transitions": [{"default": "variable.swim_amount <= 0.0"}] - } - } - }, - "use_item_progress": { - "initial_state": "default", - "states": { - "default": { - "transitions": [ - { - "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 )" - } - ] - }, - "use_item_progress": { - "animations": ["use_item_progress"], - "transitions": [ - { - "default": "( variable.use_item_interval_progress <= 0.0 ) && ( variable.use_item_startup_progress <= 0.0 )" - } - ] - } - } - }, - "zombie_attack_bare_hand": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"is_bare_hand": "variable.is_holding_left != 1.0"}] - }, - "is_bare_hand": { - "animations": ["zombie_attack_bare_hand"], - "transitions": [{"default": "variable.is_holding_left == 1.0"}] - } - } - } - }, - "render_controllers": ["controller.render.zombie_pigman"], - "enable_attachables": true - }, - "zombie_villager": { - "identifier": "minecraft:zombie_villager", - "min_engine_version": "1.8.0", - "materials": {"default": "zombie_villager"}, - "textures": { - "smith": "textures/entity/zombie_villager/profession/weaponsmith", - "butcher": "textures/entity/zombie_villager/profession/butcher", - "librarian": "textures/entity/zombie_villager/profession/librarian", - "priest": "textures/entity/zombie_villager/profession/cleric", - "farmer": "textures/entity/zombie_villager/profession/farmer" - }, - "geometry": { - "default": { - "visible_bounds_width": 1.5, - "visible_bounds_height": 2.5, - "visible_bounds_offset": [0, 1.25, 0], - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "hat", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 8, 8], - "uv": [32, 0], - "inflate": 0.5 - } - ], - "neverRender": true - }, - { - "name": "head", - "parent": "body", - "reset": true, - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 10, 8], - "uv": [0, 0], - "inflate": 0.25 - }, - { - "origin": [-1, 23, -6], - "size": [2, 4, 2], - "uv": [24, 0], - "inflate": 0.25 - } - ] - }, - { - "name": "hat", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - { - "origin": [-4, 24, -4], - "size": [8, 8, 8], - "uv": [32, 0], - "inflate": 0.5 - } - ], - "neverRender": true - }, - { - "name": "body", - "parent": "waist", - "reset": true, - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 12, -3], "size": [8, 12, 6], "uv": [16, 20]}, - { - "origin": [-4, 6, -3], - "size": [8, 18, 6], - "uv": [0, 38], - "inflate": 0.5 - } - ] - }, - {"name": "waist", "neverRender": true, "pivot": [0, 12, 0]}, - { - "name": "rightArm", - "parent": "body", - "reset": true, - "pivot": [-5, 22, 0], - "cubes": [ - {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [44, 38]} - ] - }, - { - "name": "rightItem", - "pivot": [-6, 15, 1], - "neverRender": true, - "parent": "rightArm" - }, - { - "name": "leftArm", - "parent": "body", - "reset": true, - "mirror": true, - "pivot": [5, 22, 0], - "cubes": [ - {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [44, 38]} - ] - }, - { - "name": "rightLeg", - "parent": "body", - "reset": true, - "pivot": [-2, 12, 0], - "cubes": [ - {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 22]} - ] - }, - { - "name": "leftLeg", - "parent": "body", - "reset": true, - "mirror": true, - "pivot": [2, 12, 0], - "cubes": [{"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [0, 22]}] - } - ] - } - }, - "scripts": { - "pre_animation": [ - "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;" - ] - }, - "animations": { - "humanoid_big_head": {"loop": true, "bones": {"head": {"scale": 1.4}}}, - "humanoid_base_pose": { - "loop": true, - "bones": {"waist": {"rotation": [0, 0, 0]}} - }, - "look_at_target_default": { - "loop": true, - "bones": { - "head": { - "relative_to": {"rotation": "entity"}, - "rotation": [ - "query.target_x_rotation", - "query.target_y_rotation", - 0 - ] - } - } - }, - "look_at_target_gliding": { - "loop": true, - "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} - }, - "look_at_target_swimming": { - "loop": true, - "bones": { - "head": { - "rotation": [ - "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", - "query.target_y_rotation", - 0 - ] - } - } - }, - "move": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, - "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, - "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, - "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} - } - }, - "riding.arms": { - "loop": true, - "bones": { - "leftarm": {"rotation": [-36, 0, 0]}, - "rightarm": {"rotation": [-36, 0, 0]} - } - }, - "riding.legs": { - "loop": true, - "bones": { - "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, - "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} - } - }, - "holding": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", - 0, - 0 - ] - } - } - }, - "brandish_spear": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "this * -0.5 - 157.5 - 22.5 * variable.charge_amount", - "-this", - 0 - ] - } - } - }, - "charging": { - "loop": true, - "bones": { - "rightarm": { - "rotation": ["22.5 * variable.charge_amount - this", "-this", 0] - } - } - }, - "attack.rotations": { - "loop": true, - "bones": { - "body": { - "rotation": [ - 0, - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46 - this", - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.sin(1.0 - math.pow(1.0 - variable.attack_time, 3.0) * 180.0) * (variable.is_brandishing_spear ? -1.0 : 1.0 )", - "variable.is_brandishing_spear ? 0.0 : (math.sin(math.sqrt(variable.attack_time) * 360) * 11.46) * 2.0", - 0 - ] - } - } - }, - "sneaking": { - "loop": true, - "bones": { - "body": {"rotation": ["0.5 - this", 0, 0]}, - "head": {"position": [0, 1, 0]}, - "leftarm": {"rotation": [72, 0, 0]}, - "leftleg": {"position": [0, -3, 4]}, - "rightarm": {"rotation": [72, 0, 0]}, - "rightleg": {"position": [0, -3, 4]} - } - }, - "bob": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - 0, - 0, - "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" - ] - }, - "rightarm": { - "rotation": [ - 0, - 0, - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "damage_nearby_mobs": { - "loop": true, - "bones": { - "leftarm": {"rotation": ["-45.0-this", "-this", "-this"]}, - "leftleg": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightarm": {"rotation": ["45.0-this", "-this", "-this"]}, - "rightleg": {"rotation": ["-45.0-this", "-this", "-this"]} - } - }, - "bow_and_arrow": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "query.target_x_rotation - 90.0 - math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation + 28.65", - "-(math.cos(query.life_time * 103.2) * 2.865) - 2.865" - ] - }, - "rightarm": { - "rotation": [ - "query.target_x_rotation - 90.0 + math.sin(query.life_time * 76.8) * 2.865 - this", - "query.target_y_rotation - 5.73", - "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" - ] - } - } - }, - "use_item_progress": { - "loop": true, - "bones": { - "rightarm": { - "rotation": [ - "variable.use_item_startup_progress * -60.0 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -22.5 + variable.use_item_interval_progress * 11.25", - "variable.use_item_startup_progress * -5.625 + variable.use_item_interval_progress * 11.25" - ] - } - } - }, - "zombie_attack_bare_hand": { - "loop": true, - "bones": { - "leftarm": { - "rotation": [ - "-90.0 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) - (math.sin(query.life_time * 76.776372) * 2.865) - this", - "5.73 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 0.6) - this", - "math.cos(query.life_time * 103.13244) * -2.865 - 2.865 - this" - ] - }, - "rightarm": { - "rotation": [ - "90.0 * (variable.is_brandishing_spear - 1.0) - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) + (math.sin(query.life_time * 76.776372) * 2.865) - this", - "(math.sin(variable.attack_time * 180.0) * 57.3) * 0.6 - 5.73 - this", - "math.cos(query.life_time * 103.13244) * 2.865 + 2.865 - this" - ] - } - } - }, - "swimming": { - "loop": true, - "bones": { - "body": { - "position": [ - 0, - "variable.swim_amount * -10.0 - this", - "variable.swim_amount * 9.0 - this" - ], - "rotation": [ - "variable.swim_amount * (90.0 + query.target_x_rotation)", - 0, - 0 - ] - }, - "leftarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) - (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, 14.325, variable.swim_amount) - (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "leftleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0 + 180.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - }, - "rightarm": { - "rotation": [ - "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) + (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", - "math.lerp(this, 14.325, variable.swim_amount) - this", - "math.lerp(this, -14.325, variable.swim_amount) + (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" - ] - }, - "rightleg": { - "rotation": [ - "math.lerp(this, math.cos(query.life_time * 390.0) * 0.3, variable.swim_amount)", - 0, - 0 - ] - } - } - } - }, - "animation_controllers": { - "humanoid_baby_big_head": { - "initial_state": "default", - "states": { - "baby": { - "animations": ["humanoid_big_head"], - "transitions": [{"default": "!query.is_baby"}] - }, - "default": {"transitions": [{"baby": "query.is_baby"}]} - } - }, - "humanoid_base_pose": { - "initial_state": "default", - "states": {"default": {"animations": ["humanoid_base_pose"]}} - }, - "look_at_target": { - "initial_state": "default", - "states": { - "default": { - "animations": ["look_at_target_default"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"swimming": "query.is_swimming"} - ] - }, - "gliding": { - "animations": ["look_at_target_gliding"], - "transitions": [ - {"swimming": "query.is_swimming"}, - {"default": "!query.is_gliding"} - ] - }, - "swimming": { - "animations": ["look_at_target_swimming"], - "transitions": [ - {"gliding": "query.is_gliding"}, - {"default": "!query.is_swimming"} - ] - } - } - }, - "move": { - "initial_state": "default", - "states": {"default": {"animations": ["move"]}} - }, - "riding": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"riding": "query.is_riding"}]}, - "riding": { - "animations": ["riding.arms", "riding.legs"], - "transitions": [{"default": "!query.is_riding"}] - } - } - }, - "holding": { - "initial_state": "default", - "states": {"default": {"animations": ["holding"]}} - }, - "brandish_spear": { - "initial_state": "default", - "states": { - "brandish_spear": { - "animations": ["brandish_spear"], - "transitions": [{"default": "!variable.is_brandishing_spear"}] - }, - "default": { - "transitions": [{"brandish_spear": "variable.is_brandishing_spear"}] - } - } - }, - "charging": { - "initial_state": "default", - "states": { - "charging": { - "animations": ["charging"], - "transitions": [{"default": "!query.is_charging"}] - }, - "default": {"transitions": [{"charging": "query.is_charging"}]} - } - }, - "attack": { - "initial_state": "default", - "states": { - "attacking": { - "animations": ["attack.rotations"], - "transitions": [{"default": "variable.attack_time < 0.0"}] - }, - "default": { - "transitions": [{"attacking": "variable.attack_time >= 0.0"}] - } - } - }, - "sneaking": { - "initial_state": "default", - "states": { - "default": {"transitions": [{"sneaking": "query.is_sneaking"}]}, - "sneaking": { - "animations": ["sneaking"], - "transitions": [{"default": "!query.is_sneaking"}] - } - } - }, - "bob": { - "initial_state": "default", - "states": {"default": {"animations": ["bob"]}} - }, - "damage_nearby_mobs": { - "initial_state": "default", - "states": { - "damage_nearby_mobs": { - "animations": ["damage_nearby_mobs"], - "transitions": [{"default": "!variable.damage_nearby_mobs"}] - }, - "default": { - "transitions": [ - {"damage_nearby_mobs": "variable.damage_nearby_mobs"} - ] - } - } - }, - "bow_and_arrow": { - "initial_state": "default", - "states": { - "bow_and_arrow": { - "animations": ["bow_and_arrow"], - "transitions": [{"default": "!query.has_target"}] - }, - "default": {"transitions": [{"bow_and_arrow": "query.has_target"}]} - } - }, - "use_item_progress": { - "initial_state": "default", - "states": { - "default": { - "transitions": [ - { - "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 )" - } - ] - }, - "use_item_progress": { - "animations": ["use_item_progress"], - "transitions": [ - { - "default": "( variable.use_item_interval_progress <= 0.0 ) && ( variable.use_item_startup_progress <= 0.0 )" - } - ] - } - } - }, - "zombie_attack_bare_hand": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"is_bare_hand": "variable.is_holding_left != 1.0"}] - }, - "is_bare_hand": { - "animations": ["zombie_attack_bare_hand"], - "transitions": [{"default": "variable.is_holding_left == 1.0"}] - } - } - }, - "swimming": { - "initial_state": "default", - "states": { - "default": { - "transitions": [{"is_swimming": "variable.swim_amount > 0.0"}] - }, - "is_swimming": { - "animations": ["swimming"], - "transitions": [{"default": "variable.swim_amount <= 0.0"}] - } - } - } - }, - "render_controllers": ["controller.render.zombie_villager"], - "enable_attachables": true, - "spawn_egg": {"texture": "spawn_egg", "texture_index": 42} - } -} \ No newline at end of file diff --git a/prismarine-viewer/viewer/lib/entity/models/zombie.obj b/prismarine-viewer/viewer/lib/entity/models/zombie.obj deleted file mode 100644 index bcd7444c..00000000 --- a/prismarine-viewer/viewer/lib/entity/models/zombie.obj +++ /dev/null @@ -1,325 +0,0 @@ -# Made in Blockbench 4.9.4 -mtllib materials.mtl - -o Body -v 0.25 1.5 0.125 -v 0.25 1.5 -0.125 -v 0.25 0.75 0.125 -v 0.25 0.75 -0.125 -v -0.25 1.5 -0.125 -v -0.25 1.5 0.125 -v -0.25 0.75 -0.125 -v -0.25 0.75 0.125 -vt 0.3125 0.375 -vt 0.4375 0.375 -vt 0.4375 0 -vt 0.3125 0 -vt 0.25 0.375 -vt 0.3125 0.375 -vt 0.3125 0 -vt 0.25 0 -vt 0.5 0.375 -vt 0.625 0.375 -vt 0.625 0 -vt 0.5 0 -vt 0.4375 0.375 -vt 0.5 0.375 -vt 0.5 0 -vt 0.4375 0 -vt 0.4375 0.375 -vt 0.3125 0.375 -vt 0.3125 0.5 -vt 0.4375 0.5 -vt 0.5625 0.5 -vt 0.4375 0.5 -vt 0.4375 0.375 -vt 0.5625 0.375 -vn 0 0 -1 -vn 1 0 0 -vn 0 0 1 -vn -1 0 0 -vn 0 1 0 -vn 0 -1 0 -usemtl m_9eb5cf2e-0212-52a4-6070-8cb3b67f2e24 -f 4/4/1 7/3/1 5/2/1 2/1/1 -f 3/8/2 4/7/2 2/6/2 1/5/2 -f 8/12/3 3/11/3 1/10/3 6/9/3 -f 7/16/4 8/15/4 6/14/4 5/13/4 -f 6/20/5 1/19/5 2/18/5 5/17/5 -f 7/24/6 4/23/6 3/22/6 8/21/6 -o Head -v 0.25 2 0.25 -v 0.25 2 -0.25 -v 0.25 1.5 0.25 -v 0.25 1.5 -0.25 -v -0.25 2 -0.25 -v -0.25 2 0.25 -v -0.25 1.5 -0.25 -v -0.25 1.5 0.25 -vt 0.125 0.75 -vt 0.25 0.75 -vt 0.25 0.5 -vt 0.125 0.5 -vt 0 0.75 -vt 0.125 0.75 -vt 0.125 0.5 -vt 0 0.5 -vt 0.375 0.75 -vt 0.5 0.75 -vt 0.5 0.5 -vt 0.375 0.5 -vt 0.25 0.75 -vt 0.375 0.75 -vt 0.375 0.5 -vt 0.25 0.5 -vt 0.25 0.75 -vt 0.125 0.75 -vt 0.125 1 -vt 0.25 1 -vt 0.375 1 -vt 0.25 1 -vt 0.25 0.75 -vt 0.375 0.75 -vn 0 0 -1 -vn 1 0 0 -vn 0 0 1 -vn -1 0 0 -vn 0 1 0 -vn 0 -1 0 -usemtl m_9eb5cf2e-0212-52a4-6070-8cb3b67f2e24 -f 12/28/7 15/27/7 13/26/7 10/25/7 -f 11/32/8 12/31/8 10/30/8 9/29/8 -f 16/36/9 11/35/9 9/34/9 14/33/9 -f 15/40/10 16/39/10 14/38/10 13/37/10 -f 14/44/11 9/43/11 10/42/11 13/41/11 -f 15/48/12 12/47/12 11/46/12 16/45/12 -o Hat Layer -v 0.28125 2.03125 0.28125 -v 0.28125 2.03125 -0.28125 -v 0.28125 1.46875 0.28125 -v 0.28125 1.46875 -0.28125 -v -0.28125 2.03125 -0.28125 -v -0.28125 2.03125 0.28125 -v -0.28125 1.46875 -0.28125 -v -0.28125 1.46875 0.28125 -vt 0.625 0.75 -vt 0.75 0.75 -vt 0.75 0.5 -vt 0.625 0.5 -vt 0.5 0.75 -vt 0.625 0.75 -vt 0.625 0.5 -vt 0.5 0.5 -vt 0.875 0.75 -vt 1 0.75 -vt 1 0.5 -vt 0.875 0.5 -vt 0.75 0.75 -vt 0.875 0.75 -vt 0.875 0.5 -vt 0.75 0.5 -vt 0.75 0.75 -vt 0.625 0.75 -vt 0.625 1 -vt 0.75 1 -vt 0.875 1 -vt 0.75 1 -vt 0.75 0.75 -vt 0.875 0.75 -vn 0 0 -1 -vn 1 0 0 -vn 0 0 1 -vn -1 0 0 -vn 0 1 0 -vn 0 -1 0 -usemtl m_9eb5cf2e-0212-52a4-6070-8cb3b67f2e24 -f 20/52/13 23/51/13 21/50/13 18/49/13 -f 19/56/14 20/55/14 18/54/14 17/53/14 -f 24/60/15 19/59/15 17/58/15 22/57/15 -f 23/64/16 24/63/16 22/62/16 21/61/16 -f 22/68/17 17/67/17 18/66/17 21/65/17 -f 23/72/18 20/71/18 19/70/18 24/69/18 -o RightArm -v 0.5 1.5 0.125 -v 0.5 1.5 -0.125 -v 0.5 0.75 0.125 -v 0.5 0.75 -0.125 -v 0.25 1.5 -0.125 -v 0.25 1.5 0.125 -v 0.25 0.75 -0.125 -v 0.25 0.75 0.125 -vt 0.6875 0.375 -vt 0.75 0.375 -vt 0.75 0 -vt 0.6875 0 -vt 0.625 0.375 -vt 0.6875 0.375 -vt 0.6875 0 -vt 0.625 0 -vt 0.8125 0.375 -vt 0.875 0.375 -vt 0.875 0 -vt 0.8125 0 -vt 0.75 0.375 -vt 0.8125 0.375 -vt 0.8125 0 -vt 0.75 0 -vt 0.75 0.375 -vt 0.6875 0.375 -vt 0.6875 0.5 -vt 0.75 0.5 -vt 0.8125 0.5 -vt 0.75 0.5 -vt 0.75 0.375 -vt 0.8125 0.375 -vn 0 0 -1 -vn 1 0 0 -vn 0 0 1 -vn -1 0 0 -vn 0 1 0 -vn 0 -1 0 -usemtl m_9eb5cf2e-0212-52a4-6070-8cb3b67f2e24 -f 28/76/19 31/75/19 29/74/19 26/73/19 -f 27/80/20 28/79/20 26/78/20 25/77/20 -f 32/84/21 27/83/21 25/82/21 30/81/21 -f 31/88/22 32/87/22 30/86/22 29/85/22 -f 30/92/23 25/91/23 26/90/23 29/89/23 -f 31/96/24 28/95/24 27/94/24 32/93/24 -o LeftArm -v -0.25 1.5 0.125 -v -0.25 1.5 -0.125 -v -0.25 0.75 0.125 -v -0.25 0.75 -0.125 -v -0.5 1.5 -0.125 -v -0.5 1.5 0.125 -v -0.5 0.75 -0.125 -v -0.5 0.75 0.125 -vt 0.75 0.375 -vt 0.6875 0.375 -vt 0.6875 0 -vt 0.75 0 -vt 0.8125 0.375 -vt 0.75 0.375 -vt 0.75 0 -vt 0.8125 0 -vt 0.875 0.375 -vt 0.8125 0.375 -vt 0.8125 0 -vt 0.875 0 -vt 0.6875 0.375 -vt 0.625 0.375 -vt 0.625 0 -vt 0.6875 0 -vt 0.6875 0.375 -vt 0.75 0.375 -vt 0.75 0.5 -vt 0.6875 0.5 -vt 0.75 0.5 -vt 0.8125 0.5 -vt 0.8125 0.375 -vt 0.75 0.375 -vn 0 0 -1 -vn 1 0 0 -vn 0 0 1 -vn -1 0 0 -vn 0 1 0 -vn 0 -1 0 -usemtl m_9eb5cf2e-0212-52a4-6070-8cb3b67f2e24 -f 36/100/25 39/99/25 37/98/25 34/97/25 -f 35/104/26 36/103/26 34/102/26 33/101/26 -f 40/108/27 35/107/27 33/106/27 38/105/27 -f 39/112/28 40/111/28 38/110/28 37/109/28 -f 38/116/29 33/115/29 34/114/29 37/113/29 -f 39/120/30 36/119/30 35/118/30 40/117/30 -o RightLeg -v 0.24375000000000002 0.75 0.125 -v 0.24375000000000002 0.75 -0.125 -v 0.24375000000000002 0 0.125 -v 0.24375000000000002 0 -0.125 -v -0.006249999999999978 0.75 -0.125 -v -0.006249999999999978 0.75 0.125 -v -0.006249999999999978 0 -0.125 -v -0.006249999999999978 0 0.125 -vt 0.0625 0.375 -vt 0.125 0.375 -vt 0.125 0 -vt 0.0625 0 -vt 0 0.375 -vt 0.0625 0.375 -vt 0.0625 0 -vt 0 0 -vt 0.1875 0.375 -vt 0.25 0.375 -vt 0.25 0 -vt 0.1875 0 -vt 0.125 0.375 -vt 0.1875 0.375 -vt 0.1875 0 -vt 0.125 0 -vt 0.125 0.375 -vt 0.0625 0.375 -vt 0.0625 0.5 -vt 0.125 0.5 -vt 0.1875 0.5 -vt 0.125 0.5 -vt 0.125 0.375 -vt 0.1875 0.375 -vn 0 0 -1 -vn 1 0 0 -vn 0 0 1 -vn -1 0 0 -vn 0 1 0 -vn 0 -1 0 -usemtl m_9eb5cf2e-0212-52a4-6070-8cb3b67f2e24 -f 44/124/31 47/123/31 45/122/31 42/121/31 -f 43/128/32 44/127/32 42/126/32 41/125/32 -f 48/132/33 43/131/33 41/130/33 46/129/33 -f 47/136/34 48/135/34 46/134/34 45/133/34 -f 46/140/35 41/139/35 42/138/35 45/137/35 -f 47/144/36 44/143/36 43/142/36 48/141/36 -o LeftLeg -v 0.006249999999999978 0.75 0.125 -v 0.006249999999999978 0.75 -0.125 -v 0.006249999999999978 0 0.125 -v 0.006249999999999978 0 -0.125 -v -0.24375000000000002 0.75 -0.125 -v -0.24375000000000002 0.75 0.125 -v -0.24375000000000002 0 -0.125 -v -0.24375000000000002 0 0.125 -vt 0.125 0.375 -vt 0.0625 0.375 -vt 0.0625 0 -vt 0.125 0 -vt 0.1875 0.375 -vt 0.125 0.375 -vt 0.125 0 -vt 0.1875 0 -vt 0.25 0.375 -vt 0.1875 0.375 -vt 0.1875 0 -vt 0.25 0 -vt 0.0625 0.375 -vt 0 0.375 -vt 0 0 -vt 0.0625 0 -vt 0.0625 0.375 -vt 0.125 0.375 -vt 0.125 0.5 -vt 0.0625 0.5 -vt 0.125 0.5 -vt 0.1875 0.5 -vt 0.1875 0.375 -vt 0.125 0.375 -vn 0 0 -1 -vn 1 0 0 -vn 0 0 1 -vn -1 0 0 -vn 0 1 0 -vn 0 -1 0 -usemtl m_9eb5cf2e-0212-52a4-6070-8cb3b67f2e24 -f 52/148/37 55/147/37 53/146/37 50/145/37 -f 51/152/38 52/151/38 50/150/38 49/149/38 -f 56/156/39 51/155/39 49/154/39 54/153/39 -f 55/160/40 56/159/40 54/158/40 53/157/40 -f 54/164/41 49/163/41 50/162/41 53/161/41 -f 55/168/42 52/167/42 51/166/42 56/165/42 \ No newline at end of file diff --git a/prismarine-viewer/viewer/lib/entity/objModels.js b/prismarine-viewer/viewer/lib/entity/objModels.js deleted file mode 100644 index bfd6b114..00000000 --- a/prismarine-viewer/viewer/lib/entity/objModels.js +++ /dev/null @@ -1,3 +0,0 @@ -import * as externalModels from './exportedModels' - -export { externalModels } diff --git a/prismarine-viewer/viewer/lib/mesher/mesher.ts b/prismarine-viewer/viewer/lib/mesher/mesher.ts deleted file mode 100644 index bc1d3bbb..00000000 --- a/prismarine-viewer/viewer/lib/mesher/mesher.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { World } from './world' -import { Vec3 } from 'vec3' -import { getSectionGeometry, setBlockStatesData } from './models' - -if (module.require) { - // If we are in a node environement, we need to fake some env variables - const r = module.require - const { parentPort } = r('worker_threads') - global.self = parentPort - global.postMessage = (value, transferList) => { parentPort.postMessage(value, transferList) } - global.performance = r('perf_hooks').performance -} - -let world: World -let dirtySections: Map = new Map() -let blockStatesReady = false - -function sectionKey (x, y, z) { - return `${x},${y},${z}` -} - -function setSectionDirty (pos, value = true) { - const x = Math.floor(pos.x / 16) * 16 - const y = Math.floor(pos.y / 16) * 16 - const z = Math.floor(pos.z / 16) * 16 - const key = sectionKey(x, y, z) - if (!value) { - dirtySections.delete(key) - postMessage({ type: 'sectionFinished', key }) - return - } - - const chunk = world.getColumn(x, z) - if (chunk?.getSection(pos)) { - dirtySections.set(key, (dirtySections.get(key) || 0) + 1) - } else { - postMessage({ type: 'sectionFinished', key }) - } -} - -const softCleanup = () => { - // clean block cache and loaded chunks - world = new World(world.config.version) -} - -self.onmessage = ({ data }) => { - const globalVar: any = globalThis - - if (data.type === 'mcData') { - globalVar.mcData = data.mcData - } - - if (data.config) { - world ??= new World(data.config.version) - world.config = {...world.config, ...data.config} - globalThis.world = world - } - - if (data.type === 'mesherData') { - setBlockStatesData(data.json) - blockStatesReady = true - } else if (data.type === 'dirty') { - const loc = new Vec3(data.x, data.y, data.z) - setSectionDirty(loc, data.value) - } else if (data.type === 'chunk') { - world.addColumn(data.x, data.z, data.chunk) - } else if (data.type === 'unloadChunk') { - world.removeColumn(data.x, data.z) - if (Object.keys(world.columns).length === 0) softCleanup() - } else if (data.type === 'blockUpdate') { - const loc = new Vec3(data.pos.x, data.pos.y, data.pos.z).floored() - world.setBlockStateId(loc, data.stateId) - } else if (data.type === 'reset') { - world = undefined as any - // blocksStates = null - dirtySections = new Map() - // todo also remove cached - globalVar.mcData = null - blockStatesReady = false - } -} - -setInterval(() => { - if (world === null || !blockStatesReady) return - - if (dirtySections.size === 0) return - // console.log(sections.length + ' dirty sections') - - // const start = performance.now() - for (const key of dirtySections.keys()) { - let [x, y, z] = key.split(',').map(v => parseInt(v, 10)) - const chunk = world.getColumn(x, z) - if (chunk?.getSection(new Vec3(x, y, z))) { - const geometry = getSectionGeometry(x, y, z, world) - const transferable = [geometry.positions.buffer, geometry.normals.buffer, geometry.colors.buffer, geometry.uvs.buffer] - //@ts-ignore - postMessage({ type: 'geometry', key, geometry }, transferable) - } else { - console.info('[mesher] Missing section', x, y, z) - } - const dirtyTimes = dirtySections.get(key) - if (!dirtyTimes) throw new Error('dirtySections.get(key) is falsy') - for (let i = 0; i < dirtyTimes; i++) { - postMessage({ type: 'sectionFinished', key }) - } - dirtySections.delete(key) - } - // const time = performance.now() - start - // console.log(`Processed ${sections.length} sections in ${time} ms (${time / sections.length} ms/section)`) -}, 50) diff --git a/prismarine-viewer/viewer/lib/mesher/models.ts b/prismarine-viewer/viewer/lib/mesher/models.ts deleted file mode 100644 index 40b82ea2..00000000 --- a/prismarine-viewer/viewer/lib/mesher/models.ts +++ /dev/null @@ -1,693 +0,0 @@ -import { Vec3 } from 'vec3' -import type { BlockStatesOutput } from '../../prepare/modelsBuilder' -import { World } from './world' -import { WorldBlock as Block } from './world' -import legacyJson from '../../../../src/preflatMap.json' -import { versionToNumber } from '../../prepare/utils' - -const tints: any = {} -let blockStates: BlockStatesOutput -let needTiles = false - -let tintsData -try { - tintsData = require('esbuild-data').tints -} catch (err) { - tintsData = require("minecraft-data/minecraft-data/data/pc/1.16.2/tints.json") -} -for (const key of Object.keys(tintsData)) { - tints[key] = prepareTints(tintsData[key]) -} - -function prepareTints (tints) { - const map = new Map() - const defaultValue = tintToGl(tints.default) - for (let { keys, color } of tints.data) { - color = tintToGl(color) - for (const key of keys) { - map.set(`${key}`, color) - } - } - return new Proxy(map, { - get: (target, key) => { - return target.has(key) ? target.get(key) : defaultValue - } - }) -} - -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 - const b = tint & 0xff - return [r / 255, g / 255, b / 255] -} - -const elemFaces = { - up: { - dir: [0, 1, 0], - mask1: [1, 1, 0], - mask2: [0, 1, 1], - corners: [ - [0, 1, 1, 0, 1], - [1, 1, 1, 1, 1], - [0, 1, 0, 0, 0], - [1, 1, 0, 1, 0] - ] - }, - down: { - dir: [0, -1, 0], - mask1: [1, 1, 0], - mask2: [0, 1, 1], - corners: [ - [1, 0, 1, 0, 1], - [0, 0, 1, 1, 1], - [1, 0, 0, 0, 0], - [0, 0, 0, 1, 0] - ] - }, - east: { - dir: [1, 0, 0], - mask1: [1, 1, 0], - mask2: [1, 0, 1], - corners: [ - [1, 1, 1, 0, 0], - [1, 0, 1, 0, 1], - [1, 1, 0, 1, 0], - [1, 0, 0, 1, 1] - ] - }, - west: { - dir: [-1, 0, 0], - mask1: [1, 1, 0], - mask2: [1, 0, 1], - corners: [ - [0, 1, 0, 0, 0], - [0, 0, 0, 0, 1], - [0, 1, 1, 1, 0], - [0, 0, 1, 1, 1] - ] - }, - north: { - dir: [0, 0, -1], - mask1: [1, 0, 1], - mask2: [0, 1, 1], - corners: [ - [1, 0, 0, 0, 1], - [0, 0, 0, 1, 1], - [1, 1, 0, 0, 0], - [0, 1, 0, 1, 0] - ] - }, - south: { - dir: [0, 0, 1], - mask1: [1, 0, 1], - mask2: [0, 1, 1], - corners: [ - [0, 0, 1, 0, 1], - [1, 0, 1, 1, 1], - [0, 1, 1, 0, 0], - [1, 1, 1, 1, 0] - ] - } -} - -function getLiquidRenderHeight (world, block, type, pos) { - if (!block || block.type !== type) return 1 / 9 - if (block.metadata === 0) { // source block - const blockAbove = world.getBlock(pos.offset(0, 1, 0)) - if (blockAbove && blockAbove.type === type) return 1 - return 8 / 9 - } - return ((block.metadata >= 8 ? 8 : 7 - block.metadata) + 1) / 9 -} - -const everyArray = (array, callback) => { - if (!array?.length) return false - return array.every(callback) -} - - -const isCube = (block) => { - if (!block || block.transparent) return false - if (block.isCube) return true - if (!block.variant) block.variant = getModelVariants(block) - if (!block.variant.length) return false - return block.variant.every(v => everyArray(v?.model?.elements, e => { - return e.from[0] === 0 && e.from[1] === 0 && e.from[2] === 0 && e.to[0] === 16 && e.to[1] === 16 && e.to[2] === 16 - })) -} - -function renderLiquid (world, cursor, texture, type, biome, water, attr) { - const heights: number[] = [] - for (let z = -1; z <= 1; z++) { - for (let x = -1; x <= 1; x++) { - const pos = cursor.offset(x, 0, z) - heights.push(getLiquidRenderHeight(world, world.getBlock(pos), type, pos)) - } - } - const cornerHeights = [ - Math.max(Math.max(heights[0], heights[1]), Math.max(heights[3], heights[4])), - Math.max(Math.max(heights[1], heights[2]), Math.max(heights[4], heights[5])), - Math.max(Math.max(heights[3], heights[4]), Math.max(heights[6], heights[7])), - Math.max(Math.max(heights[4], heights[5]), Math.max(heights[7], heights[8])) - ] - - for (const face in elemFaces) { - const { dir, corners } = elemFaces[face] - const isUp = dir[1] === 1 - - const neighborPos = cursor.offset(...dir) - const neighbor = world.getBlock(neighborPos) - if (!neighbor) continue - if (neighbor.type === type) continue - const isGlass = neighbor.name.includes('glass') - if ((isCube(neighbor) && !isUp) || neighbor.material === 'plant' || neighbor.getProperties().waterlogged) continue - - let tint = [1, 1, 1] - if (water) { - let m = 1 // Fake lighting to improve lisibility - if (Math.abs(dir[0]) > 0) m = 0.6 - else if (Math.abs(dir[2]) > 0) m = 0.8 - tint = tints.water[biome] - tint = [tint[0] * m, tint[1] * m, tint[2] * m] - } - - if (needTiles) { - attr.tiles[`${cursor.x},${cursor.y},${cursor.z}`] ??= { - block: 'water', - faces: [], - } - attr.tiles[`${cursor.x},${cursor.y},${cursor.z}`].faces.push({ - face, - neighbor: `${neighborPos.x},${neighborPos.y},${neighborPos.z}`, - // texture: eFace.texture.name, - }) - } - - const u = texture.u - const v = texture.v - const su = texture.su - const sv = texture.sv - - 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) - 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]) - } - } -} - -function vecadd3 (a, b) { - if (!b) return a - return [a[0] + b[0], a[1] + b[1], a[2] + b[2]] -} - -function vecsub3 (a, b) { - if (!b) return a - return [a[0] - b[0], a[1] - b[1], a[2] - b[2]] -} - -function matmul3 (matrix, vector): [number, number, number] { - if (!matrix) return vector - return [ - matrix[0][0] * vector[0] + matrix[0][1] * vector[1] + matrix[0][2] * vector[2], - matrix[1][0] * vector[0] + matrix[1][1] * vector[1] + matrix[1][2] * vector[2], - matrix[2][0] * vector[0] + matrix[2][1] * vector[1] + matrix[2][2] * vector[2] - ] -} - -function matmulmat3 (a, b) { - const te = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] - - const a11 = a[0][0]; const a12 = a[1][0]; const a13 = a[2][0] - const a21 = a[0][1]; const a22 = a[1][1]; const a23 = a[2][1] - const a31 = a[0][2]; const a32 = a[1][2]; const a33 = a[2][2] - - const b11 = b[0][0]; const b12 = b[1][0]; const b13 = b[2][0] - const b21 = b[0][1]; const b22 = b[1][1]; const b23 = b[2][1] - const b31 = b[0][2]; const b32 = b[1][2]; const b33 = b[2][2] - - te[0][0] = a11 * b11 + a12 * b21 + a13 * b31 - te[1][0] = a11 * b12 + a12 * b22 + a13 * b32 - te[2][0] = a11 * b13 + a12 * b23 + a13 * b33 - - te[0][1] = a21 * b11 + a22 * b21 + a23 * b31 - te[1][1] = a21 * b12 + a22 * b22 + a23 * b32 - te[2][1] = a21 * b13 + a22 * b23 + a23 * b33 - - te[0][2] = a31 * b11 + a32 * b21 + a33 * b31 - te[1][2] = a31 * b12 + a32 * b22 + a33 * b32 - te[2][2] = a31 * b13 + a32 * b23 + a33 * b33 - - return te -} - -function buildRotationMatrix (axis, degree) { - const radians = degree / 180 * Math.PI - const cos = Math.cos(radians) - const sin = Math.sin(radians) - - const axis0 = { x: 0, y: 1, z: 2 }[axis] - const axis1 = (axis0 + 1) % 3 - const axis2 = (axis0 + 2) % 3 - - const matrix = [ - [0, 0, 0], - [0, 0, 0], - [0, 0, 0] - ] - - matrix[axis0][axis0] = 1 - matrix[axis1][axis1] = cos - matrix[axis1][axis2] = -sin - matrix[axis2][axis1] = +sin - matrix[axis2][axis2] = cos - - return matrix -} - -let needRecompute = false - -function renderElement (world: World, cursor: Vec3, element, doAO: boolean, attr, globalMatrix, globalShift, block: Block, biome) { - const position = cursor - // const key = `${position.x},${position.y},${position.z}` - // if (!globalThis.allowedBlocks.includes(key)) return - const cullIfIdentical = block.name.indexOf('glass') >= 0 - - for (const face in element.faces) { - const eFace = element.faces[face] - const { corners, mask1, mask2 } = elemFaces[face] - const dir = matmul3(globalMatrix, elemFaces[face].dir) - - if (eFace.cullface) { - const neighbor = world.getBlock(cursor.plus(new Vec3(...dir))) - if (neighbor) { - if (cullIfIdentical && neighbor.type === block.type) continue - if (!neighbor.transparent && isCube(neighbor)) continue - } else { - needRecompute = true - continue - } - } - - const minx = element.from[0] - const miny = element.from[1] - const minz = element.from[2] - const maxx = element.to[0] - const maxy = element.to[1] - const maxz = element.to[2] - - const u = eFace.texture.u - const v = eFace.texture.v - const su = eFace.texture.su - const sv = eFace.texture.sv - - const ndx = Math.floor(attr.positions.length / 3) - - let tint = [1, 1, 1] - if (eFace.tintindex !== undefined) { - if (eFace.tintindex === 0) { - if (block.name === 'redstone_wire') { - tint = tints.redstone[`${block.getProperties().power}`] - } else if (block.name === 'birch_leaves' || - block.name === 'spruce_leaves' || - block.name === 'lily_pad') { - tint = tints.constant[block.name] - } else if (block.name.includes('leaves') || block.name === 'vine') { - tint = tints.foliage[biome] - } else { - tint = tints.grass[biome] - } - } - } - - // UV rotation - const r = eFace.rotation || 0 - const uvcs = Math.cos(r * Math.PI / 180) - const uvsn = -Math.sin(r * Math.PI / 180) - - let localMatrix = null as any - let localShift = null as any - - if (element.rotation) { - localMatrix = buildRotationMatrix( - element.rotation.axis, - element.rotation.angle - ) - - localShift = vecsub3( - element.rotation.origin, - matmul3( - localMatrix, - element.rotation.origin - ) - ) - } - - const aos: number[] = [] - const neighborPos = position.plus(new Vec3(...dir)) - const baseLight = world.getLight(neighborPos, undefined, undefined, block.name) / 15 - for (const pos of corners) { - let vertex = [ - (pos[0] ? maxx : minx), - (pos[1] ? maxy : miny), - (pos[2] ? maxz : minz) - ] - - vertex = vecadd3(matmul3(localMatrix, vertex), localShift) - vertex = vecadd3(matmul3(globalMatrix, vertex), globalShift) - vertex = vertex.map(v => v / 16) - - attr.positions.push( - vertex[0] + (cursor.x & 15) - 8, - vertex[1] + (cursor.y & 15) - 8, - vertex[2] + (cursor.z & 15) - 8 - ) - - attr.normals.push(...dir) - - const baseu = (pos[3] - 0.5) * uvcs - (pos[4] - 0.5) * uvsn + 0.5 - const basev = (pos[3] - 0.5) * uvsn + (pos[4] - 0.5) * uvcs + 0.5 - attr.uvs.push(baseu * su + u, basev * sv + v) - - let light = 1 - if (doAO) { - const dx = pos[0] * 2 - 1 - const dy = pos[1] * 2 - 1 - const dz = pos[2] * 2 - 1 - const cornerDir = matmul3(globalMatrix, [dx, dy, dz]) - const side1Dir = matmul3(globalMatrix, [dx * mask1[0], dy * mask1[1], dz * mask1[2]]) - const side2Dir = matmul3(globalMatrix, [dx * mask2[0], dy * mask2[1], dz * mask2[2]]) - const side1 = world.getBlock(cursor.offset(...side1Dir)) - const side2 = world.getBlock(cursor.offset(...side2Dir)) - const corner = world.getBlock(cursor.offset(...cornerDir)) - - let cornerLightResult = 15 - if (/* world.config.smoothLighting */false) { // todo fix - const side1Light = world.getLight(cursor.plus(new Vec3(...side1Dir)), true) - const side2Light = world.getLight(cursor.plus(new Vec3(...side2Dir)), true) - const cornerLight = world.getLight(cursor.plus(new Vec3(...cornerDir)), true) - // interpolate - cornerLightResult = (side1Light + side2Light + cornerLight) / 3 - } - - const side1Block = world.shouldMakeAo(side1) ? 1 : 0 - const side2Block = world.shouldMakeAo(side2) ? 1 : 0 - const cornerBlock = world.shouldMakeAo(corner) ? 1 : 0 - - // TODO: correctly interpolate ao light based on pos (evaluate once for each corner of the block) - - const ao = (side1Block && side2Block) ? 0 : (3 - (side1Block + side2Block + cornerBlock)) - // todo light should go upper on lower blocks - light = (ao + 1) / 4 * (cornerLightResult / 15) - aos.push(ao) - } - - attr.colors.push(baseLight * tint[0] * light, baseLight * tint[1] * light, baseLight * tint[2] * light) - } - - if (needTiles) { - attr.tiles[`${cursor.x},${cursor.y},${cursor.z}`] ??= { - block: block.name, - faces: [], - } - attr.tiles[`${cursor.x},${cursor.y},${cursor.z}`].faces.push({ - face, - neighbor: `${neighborPos.x},${neighborPos.y},${neighborPos.z}`, - light: baseLight - // texture: eFace.texture.name, - }) - } - - if (doAO && aos[0] + aos[3] >= aos[1] + aos[2]) { - attr.indices.push( - ndx, ndx + 3, ndx + 2, - ndx, ndx + 1, ndx + 3 - ) - } else { - attr.indices.push( - ndx, ndx + 1, ndx + 2, - ndx + 2, ndx + 1, ndx + 3 - ) - } - } -} - -export function getSectionGeometry (sx, sy, sz, world: World) { - let delayedRender = [] as (() => void)[] - - const attr = { - sx: sx + 8, - sy: sy + 8, - sz: sz + 8, - positions: [], - normals: [], - colors: [], - uvs: [], - t_positions: [], - t_normals: [], - t_colors: [], - t_uvs: [], - indices: [], - tiles: {}, - // todo this can be removed here - signs: {} - } as Record - - const cursor = new Vec3(0, 0, 0) - for (cursor.y = sy; cursor.y < sy + 16; cursor.y++) { - 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') || block.name === 'sign') { - const key = `${cursor.x},${cursor.y},${cursor.z}` - const props: any = block.getProperties() - const facingRotationMap = { - "north": 2, - "south": 0, - "west": 1, - "east": 3 - } - const isWall = block.name.endsWith('wall_sign') || block.name.endsWith('hanging_sign') - attr.signs[key] = { - isWall, - rotation: isWall ? facingRotationMap[props.facing] : +props.rotation - } - } - const biome = block.biome.name - - 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) - } - - for (const variant of block.variant) { - if (!variant || !variant.model) continue - - const isWaterlogged = block.getProperties().waterlogged - if (block.name === 'water' || isWaterlogged) { - const waterBlock = block.name === 'water' ? block : { name: 'water', metadata: 0 } - const variant = getModelVariants(waterBlock as any)[0] - const pos = cursor.clone() - delayedRender.push(() => { - renderLiquid(world, pos, variant.model.textures.particle, block.type, biome, true, attr) - }) - } else if (block.name === 'lava') { - renderLiquid(world, cursor, variant.model.textures.particle, block.type, biome, false, attr) - } - if (block.name !== "water") { - let globalMatrix = null as any - let globalShift = null as any - - for (const axis of ['x', 'y', 'z']) { - if (axis in variant) { - if (!globalMatrix) globalMatrix = buildRotationMatrix(axis, -variant[axis]) - else globalMatrix = matmulmat3(globalMatrix, buildRotationMatrix(axis, -variant[axis])) - } - } - - if (globalMatrix) { - globalShift = [8, 8, 8] - globalShift = vecsub3(globalShift, matmul3(globalMatrix, globalShift)) - } - - for (const element of variant.model.elements) { - if (block.transparent) { - const pos = cursor.clone() - delayedRender.push(() => { - renderElement(world, pos, element, variant.model.ao, attr, globalMatrix, globalShift, block, biome) - }) - } else { - renderElement(world, cursor, element, variant.model.ao, attr, globalMatrix, globalShift, block, biome) - } - } - } - } - } - } - } - - for (const render of delayedRender) { - render() - } - delayedRender = [] - - let ndx = attr.positions.length / 3 - for (let i = 0; i < attr.t_positions.length / 12; i++) { - attr.indices.push( - ndx, ndx + 1, ndx + 2, - ndx + 2, ndx + 1, ndx + 3, - // back face - ndx, ndx + 2, ndx + 1, - ndx + 2, ndx + 3, ndx + 1 - ) - ndx += 4 - } - - attr.positions.push(...attr.t_positions) - attr.normals.push(...attr.t_normals) - attr.colors.push(...attr.t_colors) - attr.uvs.push(...attr.t_uvs) - - delete attr.t_positions - delete attr.t_normals - delete attr.t_colors - delete attr.t_uvs - - attr.positions = new Float32Array(attr.positions) as any - attr.normals = new Float32Array(attr.normals) as any - attr.colors = new Float32Array(attr.colors) as any - attr.uvs = new Float32Array(attr.uvs) as any - - return attr -} - -function parseProperties (properties) { - if (typeof properties === 'object') { return properties } - - const json = {} - for (const prop of properties.split(',')) { - const [key, value] = prop.split('=') - json[key] = value - } - return json -} - -function matchProperties (block: Block, /* to match against */properties: Record & { OR }) { - if (!properties) { return true } - - properties = parseProperties(properties) - const blockProps = block.getProperties() - if (properties.OR) { - return properties.OR.some((or) => matchProperties(block, or)) - } - for (const prop in blockProps) { - if (properties[prop] === undefined) continue // unknown property, ignore - if (typeof properties[prop] !== 'string') properties[prop] = String(properties[prop]) - if (!(properties[prop] as string).split('|').some((value) => value === String(blockProps[prop]))) { - return false - } - } - return true -} - -function getModelVariants (block: Block) { - // air, cave_air, void_air and so on... - // full list of invisible & special blocks https://minecraft.wiki/w/Model#Blocks_and_fluids - if (block.name === '' || block.name === 'air' || block.name.endsWith('_air')) return [] - if (block.name === 'barrier') return [] - const matchedState = blockStates[block.name] - // if (!matchedState) currentWarnings.value.add(`Missing block ${block.name}`) - const state = matchedState ?? blockStates.missing_texture - if (!state) return [] - if (state.variants) { - for (const [properties, variant] of Object.entries(state.variants)) { - if (!matchProperties(block, properties as any)) continue - if (variant instanceof Array) return [variant[0]] - return [variant] - } - } - if (state.multipart) { - const parts = state.multipart.filter(multipart => matchProperties(block, multipart.when)) - let variants = [] as any[] - for (const part of parts) { - variants = [...variants, ...Array.isArray(part.apply) ? part.apply : [part.apply]] - } - - return variants - } - - return [] -} - -export const setBlockStatesData = (_blockStates: BlockStatesOutput | null, _needTiles = false) => { - blockStates = _blockStates! - needTiles = _needTiles -} diff --git a/prismarine-viewer/viewer/lib/mesher/shared.ts b/prismarine-viewer/viewer/lib/mesher/shared.ts deleted file mode 100644 index 36c319b1..00000000 --- a/prismarine-viewer/viewer/lib/mesher/shared.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const defaultMesherConfig = { - version: '', - enableLighting: true, - skyLight: 15, - smoothLighting: true, - outputFormat: 'threeJs' as 'threeJs' | 'webgl', - textureSize: 1024, // for testing -} - -export type MesherConfig = typeof defaultMesherConfig diff --git a/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts b/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts deleted file mode 100644 index 6103a3d4..00000000 --- a/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { setBlockStatesData, getSectionGeometry } from '../models' -import { World as MesherWorld } from '../world' -import ChunkLoader, { PCChunk } from 'prismarine-chunk' -import { Vec3 } from 'vec3' -import MinecraftData from 'minecraft-data' - -export const setup = (version, initialBlocks: [number[], string][]) => { - const mcData = MinecraftData(version) - const blockStates = require(`../../../../public/blocksStates/${version}.json`) - const mesherWorld = new MesherWorld(version) - const Chunk = ChunkLoader(version) - const chunk1 = new Chunk(undefined as any) - - const pos = new Vec3(2, 5, 2) - for (const [addPos, name] of initialBlocks) { - chunk1.setBlockStateId(pos.offset(addPos[0], addPos[1], addPos[2]), mcData.blocksByName[name].defaultState!) - } - - const getGeometry = () => { - const sectionGeometry = getSectionGeometry(0, 0, 0, mesherWorld) - const centerFaces = sectionGeometry.tiles[`${pos.x},${pos.y},${pos.z}`]?.faces.length ?? 0 - const totalTiles = Object.values(sectionGeometry.tiles).reduce((acc, val: any) => acc + val.faces.length, 0) - const centerTileNeighbors = Object.entries(sectionGeometry.tiles).reduce((acc, [key, val]: any) => { - return acc + val.faces.filter((face: any) => face.neighbor === `${pos.x},${pos.y},${pos.z}`).length - }, 0) - return { - centerFaces, - totalTiles, - centerTileNeighbors, - faces: sectionGeometry.tiles[`${pos.x},${pos.y},${pos.z}`]?.faces ?? [] - } - } - - setBlockStatesData(blockStates, true) - const reload = () => { - mesherWorld.removeColumn(0, 0) - mesherWorld.addColumn(0, 0, chunk1.toJson()) - } - 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, - reload, - chunk: chunk1 as PCChunk - } -} - -// surround it -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'], -] diff --git a/prismarine-viewer/viewer/lib/mesher/test/playground.ts b/prismarine-viewer/viewer/lib/mesher/test/playground.ts deleted file mode 100644 index 6e9e7b10..00000000 --- a/prismarine-viewer/viewer/lib/mesher/test/playground.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { setup } from './mesherTester' - -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'], -] as const - -const { mesherWorld, getGeometry, pos, mcData } = setup('1.18.1', addPositions as any) - -// mesherWorld.setBlockStateId(pos, mcData.blocksByName.soul_sand.defaultState) - -// console.log(getGeometry().centerTileNeighbors) diff --git a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts deleted file mode 100644 index 75dd98fa..00000000 --- a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { test, expect } from 'vitest' -import { setup } from './mesherTester' -import minecraftData from 'minecraft-data' -import minecraftAssets from 'minecraft-assets' - -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'], -] as const - -test('Known blocks are not rendered', () => { - 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 (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/lib/renderUtils.js b/prismarine-viewer/viewer/lib/renderUtils.js deleted file mode 100644 index 0a879322..00000000 --- a/prismarine-viewer/viewer/lib/renderUtils.js +++ /dev/null @@ -1,11 +0,0 @@ -import { fromFormattedString } from '@xmcl/text-component' - -export const formattedStringToSimpleString = (str) => { - const result = fromFormattedString(str) - let str = result.text - // todo recursive - for (const extra of result.extra) { - str += extra.text - } - return str -} diff --git a/prismarine-viewer/viewer/lib/threeJsUtils.ts b/prismarine-viewer/viewer/lib/threeJsUtils.ts deleted file mode 100644 index e4f9404b..00000000 --- a/prismarine-viewer/viewer/lib/threeJsUtils.ts +++ /dev/null @@ -1,12 +0,0 @@ -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?.(); - } - if (obj.children) { - obj.children.forEach(disposeObject); - } -} diff --git a/prismarine-viewer/viewer/lib/utils.electron.js b/prismarine-viewer/viewer/lib/utils.electron.js deleted file mode 100644 index e3066cd5..00000000 --- a/prismarine-viewer/viewer/lib/utils.electron.js +++ /dev/null @@ -1,17 +0,0 @@ -const THREE = require('three') -const path = require('path') - -const textureCache = {} -function loadTexture (texture, cb) { - if (!textureCache[texture]) { - const url = path.resolve(__dirname, '../../public/' + texture) - textureCache[texture] = new THREE.TextureLoader().load(url) - } - cb(textureCache[texture]) -} - -function loadJSON (json, cb) { - cb(require(path.resolve(__dirname, '../../public/' + json))) -} - -module.exports = { loadTexture, loadJSON } diff --git a/prismarine-viewer/viewer/lib/utils.js b/prismarine-viewer/viewer/lib/utils.js deleted file mode 100644 index 332d0d41..00000000 --- a/prismarine-viewer/viewer/lib/utils.js +++ /dev/null @@ -1,57 +0,0 @@ -function safeRequire (path) { - try { - return require(path) - } catch (e) { - return {} - } -} -const { loadImage } = safeRequire('node-canvas-webgl/lib') -const path = require('path') -const THREE = require('three') - -const textureCache = {} -// todo not ideal, export different functions for browser and node -export function loadTexture (texture, cb) { - if (process.platform === 'browser') { - return require('./utils.web').loadTexture(texture, cb) - } - - if (textureCache[texture]) { - cb(textureCache[texture]) - } else { - loadImage(path.resolve(__dirname, '../../public/' + texture)).then(image => { - textureCache[texture] = new THREE.CanvasTexture(image) - cb(textureCache[texture]) - }) - } -} - -export function loadJSON (json, cb) { - if (process.platform === 'browser') { - return require('./utils.web').loadJSON(json, cb) - } - cb(require(path.resolve(__dirname, '../../public/' + json))) -} - -export const loadScript = async function (/** @type {string} */scriptSrc) { - if (document.querySelector(`script[src="${scriptSrc}"]`)) { - return - } - - return new Promise((resolve, reject) => { - const scriptElement = document.createElement('script') - scriptElement.src = scriptSrc - scriptElement.async = true - - scriptElement.addEventListener('load', () => { - resolve(scriptElement) - }) - - scriptElement.onerror = (error) => { - reject(new Error(error.message)) - scriptElement.remove() - } - - document.head.appendChild(scriptElement) - }) -} diff --git a/prismarine-viewer/viewer/lib/utils.web.js b/prismarine-viewer/viewer/lib/utils.web.js deleted file mode 100644 index ffa22808..00000000 --- a/prismarine-viewer/viewer/lib/utils.web.js +++ /dev/null @@ -1,29 +0,0 @@ -/* global XMLHttpRequest */ -const THREE = require('three') - -const textureCache = {} -function loadTexture (texture, cb, onLoad) { - const cached = textureCache[texture] - if (!cached) { - textureCache[texture] = new THREE.TextureLoader().load(texture, onLoad) - } - cb(textureCache[texture]) - if (cached) onLoad?.() -} - -function loadJSON (url, callback) { - const xhr = new XMLHttpRequest() - xhr.open('GET', url, true) - xhr.responseType = 'json' - xhr.onload = function () { - const status = xhr.status - if (status === 200) { - callback(xhr.response) - } else { - throw new Error(url + ' not found') - } - } - xhr.send() -} - -module.exports = { loadTexture, loadJSON } diff --git a/prismarine-viewer/viewer/lib/version.js b/prismarine-viewer/viewer/lib/version.js deleted file mode 100644 index 804bd0c7..00000000 --- a/prismarine-viewer/viewer/lib/version.js +++ /dev/null @@ -1,30 +0,0 @@ -const supportedVersions = require('../../public/supportedVersions.json') - -const lastOfMajor = {} -for (const version of supportedVersions) { - const major = toMajor(version) - if (lastOfMajor[major]) { - if (minor(lastOfMajor[major]) < minor(version)) { - lastOfMajor[major] = version - } - } else { - lastOfMajor[major] = version - } -} - -function toMajor (version) { - const [a, b] = (version + '').split('.') - return a + '.' + b -} - -function minor (version) { - const [, , c] = (version + '.0').split('.') - return parseInt(c, 10) -} - -function getVersion (version) { - if (supportedVersions.indexOf(version) !== -1) return version - return lastOfMajor[toMajor(version)] ?? Object.values(lastOfMajor).at(-1) -} - -module.exports = { getVersion, toMajor } diff --git a/prismarine-viewer/viewer/lib/viewer.ts b/prismarine-viewer/viewer/lib/viewer.ts deleted file mode 100644 index c95127f2..00000000 --- a/prismarine-viewer/viewer/lib/viewer.ts +++ /dev/null @@ -1,222 +0,0 @@ -import * as THREE from 'three' -import { Vec3 } from 'vec3' -import { Entities } from './entities' -import { Primitives } from './primitives' -import { getVersion } from './version' -import EventEmitter from 'events' -import { WorldRendererThree } from './worldrendererThree' -import { generateSpiralMatrix } from 'flying-squid/dist/utils' -import { WorldRendererCommon, WorldRendererConfig, defaultWorldRendererConfig } from './worldrendererCommon' -import { versionToNumber } from '../prepare/utils' - -export class Viewer { - scene: THREE.Scene - ambientLight: THREE.AmbientLight - directionalLight: THREE.DirectionalLight - world: WorldRendererCommon - entities: Entities - // primitives: Primitives - domElement: HTMLCanvasElement - playerHeight = 1.62 - isSneaking = false - threeJsWorld: WorldRendererThree - cameraObjectOverride?: THREE.Object3D // for xr - audioListener: THREE.AudioListener - 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 - renderer.outputColorSpace = THREE.LinearSRGBColorSpace - - this.scene = new THREE.Scene() - this.scene.matrixAutoUpdate = false // for perf - 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) - - this.domElement = renderer.domElement - } - - setWorld () { - this.world = this.threeJsWorld - } - - resetScene () { - this.scene.background = new THREE.Color('lightblue') - - if (this.ambientLight) this.scene.remove(this.ambientLight) - this.ambientLight = new THREE.AmbientLight(0xcc_cc_cc) - this.scene.add(this.ambientLight) - - if (this.directionalLight) this.scene.remove(this.directionalLight) - this.directionalLight = new THREE.DirectionalLight(0xff_ff_ff, 0.5) - this.directionalLight.position.set(1, 1, 0.5).normalize() - this.directionalLight.castShadow = true - this.scene.add(this.directionalLight) - - const size = this.renderer.getSize(new THREE.Vector2()) - this.camera = new THREE.PerspectiveCamera(75, size.x / size.y, 0.1, 1000) - } - - resetAll () { - this.resetScene() - this.world.resetWorld() - this.entities.clear() - // this.primitives.clear() - } - - setVersion (userVersion: string) { - let texturesVersion = getVersion(userVersion) - if (versionToNumber(userVersion) < versionToNumber('1.13')) texturesVersion = '1.13.2' // we normalize to post-flatenning in mesher - console.log('[viewer] Using version:', userVersion, 'textures:', texturesVersion) - this.world.setVersion(userVersion, texturesVersion) - this.entities.clear() - // this.primitives.clear() - } - - addColumn (x, z, chunk, isLightUpdate = false) { - this.world.addColumn(x, z, chunk, isLightUpdate) - } - - removeColumn (x: string, z: string) { - this.world.removeColumn(x, z) - } - - setBlockStateId (pos: Vec3, stateId: number) { - this.world.setBlockStateId(pos, stateId) - } - - updateEntity (e) { - this.entities.update(e, this.processEntityOverrides(e, { - rotation: { - head: { - x: e.headPitch ?? e.pitch, - y: e.headYaw, - z: 0 - } - } - })) - } - - setFirstPersonCamera (pos: Vec3 | null, yaw: number, pitch: number, roll = 0) { - const cam = this.cameraObjectOverride || this.camera - let yOffset = this.playerHeight - if (this.isSneaking) yOffset -= 0.3 - - if (this.world instanceof WorldRendererThree) this.world.camera = cam as THREE.PerspectiveCamera - this.world.updateCamera(pos?.offset(0, yOffset, 0) ?? null, yaw, pitch) - } - - playSound (position: Vec3, path: string, volume = 1) { - if (!this.audioListener) { - this.audioListener = new THREE.AudioListener() - this.camera.add(this.audioListener) - } - - const sound = new THREE.PositionalAudio(this.audioListener) - - const audioLoader = new THREE.AudioLoader() - let start = Date.now() - audioLoader.loadAsync(path).then((buffer) => { - if (Date.now() - start > 500) return - // play - sound.setBuffer(buffer) - sound.setRefDistance(20) - sound.setVolume(volume) - this.scene.add(sound) - // set sound position - sound.position.set(position.x, position.y, position.z) - sound.onEnded = () => { - this.scene.remove(sound) - sound.disconnect() - audioLoader.manager.itemEnd(path) - } - sound.play() - }) - } - - // todo type - listen (emitter: EventEmitter) { - emitter.on('entity', (e) => { - this.updateEntity(e) - }) - - emitter.on('primitive', (p) => { - // this.updatePrimitive(p) - }) - - emitter.on('loadChunk', ({ x, z, chunk, worldConfig, isLightUpdate }) => { - this.world.worldConfig = worldConfig - this.addColumn(x, z, chunk, isLightUpdate) - }) - // todo remove and use other architecture instead so data flow is clear - emitter.on('blockEntities', (blockEntities) => { - if (this.world instanceof WorldRendererThree) this.world.blockEntities = blockEntities - }) - - emitter.on('unloadChunk', ({ x, z }) => { - this.removeColumn(x, z) - }) - - emitter.on('blockUpdate', ({ pos, stateId }) => { - this.setBlockStateId(new Vec3(pos.x, pos.y, pos.z), stateId) - }) - - emitter.on('chunkPosUpdate', ({ pos }) => { - this.world.updateViewerPosition(pos) - }) - - emitter.on('renderDistance', (d) => { - this.world.viewDistance = d - this.world.chunksLength = d === 0 ? 1 : generateSpiralMatrix(d).length - this.world.allChunksFinished = Object.keys(this.world.finishedChunks).length === this.world.chunksLength - }) - - emitter.on('updateLight', ({ pos }) => { - if (this.world instanceof WorldRendererThree) this.world.updateLight(pos.x, pos.z) - }) - - emitter.on('time', (timeOfDay) => { - this.world.timeUpdated?.(timeOfDay) - - let skyLight = 15 - if (timeOfDay < 0 || timeOfDay > 24000) { - throw new Error("Invalid time of day. It should be between 0 and 24000.") - } else if (timeOfDay <= 6000 || timeOfDay >= 18000) { - skyLight = 15 - } else if (timeOfDay > 6000 && timeOfDay < 12000) { - skyLight = 15 - ((timeOfDay - 6000) / 6000) * 15 - } else if (timeOfDay >= 12000 && timeOfDay < 18000) { - skyLight = ((timeOfDay - 12000) / 6000) * 15 - } - - skyLight = Math.floor(skyLight) // todo: remove this after optimization - - if (this.world.mesherConfig.skyLight === skyLight) return - this.world.mesherConfig.skyLight = skyLight - ; (this.world as WorldRendererThree).rerenderAllChunks?.() - }) - - emitter.emit('listening') - } - - render () { - this.world.render() - this.entities.render() - } - - async waitForChunksToRender () { - await this.world.waitForChunksToRender() - } -} diff --git a/prismarine-viewer/viewer/lib/viewerWrapper.ts b/prismarine-viewer/viewer/lib/viewerWrapper.ts deleted file mode 100644 index b8017f38..00000000 --- a/prismarine-viewer/viewer/lib/viewerWrapper.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { statsEnd, statsStart } from '../../../src/topRightStats' - -// wrapper for now -export class ViewerWrapper { - previousWindowWidth: number - previousWindowHeight: number - globalObject = globalThis as any - stopRenderOnBlur = false - addedToPage = false - renderInterval = 0 - renderIntervalUnfocused: number | undefined - fpsInterval - - constructor(public canvas: HTMLCanvasElement, public renderer?: THREE.WebGLRenderer) { - } - addToPage (startRendering = true) { - if (this.addedToPage) throw new Error('Already added to page') - let pixelRatio = window.devicePixelRatio || 1 // todo this value is too high on ios, need to check, probably we should use avg, also need to make it configurable - if (this.renderer) { - if (!this.renderer.capabilities.isWebGL2) pixelRatio = 1 // webgl1 has issues with high pixel ratio (sometimes screen is clipped) - this.renderer.setPixelRatio(pixelRatio) - this.renderer.setSize(window.innerWidth, window.innerHeight) - } else { - this.canvas.width = window.innerWidth * pixelRatio - this.canvas.height = window.innerHeight * pixelRatio - } - this.previousWindowWidth = window.innerWidth - this.previousWindowHeight = window.innerHeight - - this.canvas.id = 'viewer-canvas' - document.body.appendChild(this.canvas) - - if (this.renderer) this.globalObject.renderer = this.renderer - this.addedToPage = true - - let max = 0 - this.fpsInterval = setInterval(() => { - if (max > 0) { - viewer.world.droppedFpsPercentage = this.renderedFps / max - } - max = Math.max(this.renderedFps, max) - this.renderedFps = 0 - }, 1000) - if (startRendering) { - this.globalObject.requestAnimationFrame(this.render.bind(this)) - } - if (typeof window !== 'undefined') { - this.trackWindowFocus() - } - } - - windowFocused = true - trackWindowFocus () { - window.addEventListener('focus', () => { - this.windowFocused = true - }) - window.addEventListener('blur', () => { - this.windowFocused = false - }) - } - - dispose () { - if (!this.addedToPage) throw new Error('Not added to page') - document.body.removeChild(this.canvas) - this.renderer?.dispose() - // this.addedToPage = false - clearInterval(this.fpsInterval) - } - - - renderedFps = 0 - lastTime = performance.now() - delta = 0 - preRender = () => { } - postRender = () => { } - render (time: DOMHighResTimeStamp) { - if (this.globalObject.stopLoop) return - 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 - const renderInterval = (this.windowFocused ? this.renderInterval : this.renderIntervalUnfocused) ?? this.renderInterval - if (renderInterval) { - this.delta += time - this.lastTime - this.lastTime = time - if (this.delta > renderInterval) { - this.delta %= renderInterval - // continue rendering - } else { - return - } - } - this.preRender() - statsStart() - // ios bug: viewport dimensions are updated after the resize event - if (this.previousWindowWidth !== window.innerWidth || this.previousWindowHeight !== window.innerHeight) { - this.resizeHandler() - this.previousWindowWidth = window.innerWidth - this.previousWindowHeight = window.innerHeight - } - viewer.render() - this.renderedFps++ - statsEnd() - this.postRender() - } - - resizeHandler () { - const width = window.innerWidth - const height = window.innerHeight - - viewer.camera.aspect = width / height - viewer.camera.updateProjectionMatrix() - - if (this.renderer) { - this.renderer.setSize(width, height) - } - viewer.world.handleResize() - } -} diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts deleted file mode 100644 index 40cc3413..00000000 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { chunkPos } from './simpleUtils' - -// todo refactor into its own commons module -import { generateSpiralMatrix, ViewRect } from 'flying-squid/dist/utils' -import { Vec3 } from 'vec3' -import { EventEmitter } from 'events' -import { BotEvents } from 'mineflayer' - -export type ChunkPosKey = string -type ChunkPos = { x: number, z: number } - -/** - * Usually connects to mineflayer bot and emits world data (chunks, entities) - * It's up to the consumer to serialize the data if needed - */ -export class WorldDataEmitter extends EventEmitter { - private loadedChunks: Record - private lastPos: Vec3 - private eventListeners: Record = {}; - private emitter: WorldDataEmitter - - constructor(public world: import('prismarine-world').world.World | typeof __type_bot['world'], public viewDistance: number, position: Vec3 = new Vec3(0, 0, 0)) { - super() - this.loadedChunks = {} - this.lastPos = new Vec3(0, 0, 0).update(position) - // todo - this.emitter = this - - this.emitter.on('mouseClick', async (click) => { - const ori = new Vec3(click.origin.x, click.origin.y, click.origin.z) - const dir = new Vec3(click.direction.x, click.direction.y, click.direction.z) - const block = this.world.raycast(ori, dir, 256) - if (!block) return - //@ts-ignore - this.emit('blockClicked', block, block.face, click.button) - }) - } - - updateViewDistance (viewDistance: number) { - this.viewDistance = viewDistance - this.emitter.emit('renderDistance', viewDistance) - } - - 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.eventListeners[bot.username] = { - // 'move': botPosition, - entitySpawn: (e: any) => { - emitEntity(e) - }, - entityUpdate: (e: any) => { - emitEntity(e) - }, - entityMoved: (e: any) => { - emitEntity(e) - }, - entityGone: (e: any) => { - this.emitter.emit('entity', { id: e.id, delete: true }) - }, - chunkColumnLoad: (pos: Vec3) => { - this.loadChunk(pos) - }, - blockUpdate: (oldBlock: any, newBlock: any) => { - const stateId = newBlock.stateId ? newBlock.stateId : ((newBlock.type << 4) | newBlock.metadata) - this.emitter.emit('blockUpdate', { pos: oldBlock.position, stateId }) - }, - time: () => { - this.emitter.emit('time', bot.time.timeOfDay) - }, - } satisfies Partial - - bot._client.on('update_light', ({ chunkX, chunkZ }) => { - const chunkPos = new Vec3(chunkX * 16, 0, chunkZ * 16) - this.loadChunk(chunkPos, true) - }) - - this.emitter.on('listening', () => { - this.emitter.emit('blockEntities', new Proxy({}, { - 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 - }, - })) - this.emitter.emit('renderDistance', this.viewDistance) - this.emitter.emit('time', bot.time.timeOfDay) - }) - // node.js stream data event pattern - if (this.emitter.listenerCount('blockEntities')) { - this.emitter.emit('listening') - } - - for (const [evt, listener] of Object.entries(this.eventListeners[bot.username])) { - bot.on(evt as any, listener) - } - - for (const id in bot.entities) { - const e = bot.entities[id] - emitEntity(e) - } - } - - removeListenersFromBot (bot: import('mineflayer').Bot) { - for (const [evt, listener] of Object.entries(this.eventListeners[bot.username])) { - bot.removeListener(evt as any, listener) - } - delete this.eventListeners[bot.username] - } - - async init (pos: Vec3) { - this.updateViewDistance(this.viewDistance) - this.emitter.emit('chunkPosUpdate', { pos }) - const [botX, botZ] = chunkPos(pos) - - const positions = generateSpiralMatrix(this.viewDistance).map(([x, z]) => new Vec3((botX + x) * 16, 0, (botZ + z) * 16)) - - this.lastPos.update(pos) - await this._loadChunks(positions) - } - - async _loadChunks (positions: Vec3[], sliceSize = 5, waitTime = 0) { - for (let i = 0; i < positions.length; i += sliceSize) { - await new Promise((resolve) => setTimeout(resolve, waitTime)) - await Promise.all(positions.slice(i, i + sliceSize).map((p) => this.loadChunk(p))) - } - } - - 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)) - if (dx <= this.viewDistance && dz <= this.viewDistance) { - const column = await this.world.getColumnAt(pos['y'] ? pos as Vec3 : new Vec3(pos.x, 0, pos.z)) - if (column) { - // todo optimize toJson data, make it clear why it is used - const chunk = column.toJson() - // TODO: blockEntities - const worldConfig = { - minY: column['minY'] ?? 0, - worldHeight: column['worldHeight'] ?? 256, - } - //@ts-ignore - this.emitter.emit('loadChunk', { x: pos.x, z: pos.z, chunk, blockEntities: column.blockEntities, worldConfig, isLightUpdate }) - this.loadedChunks[`${pos.x},${pos.z}`] = true - } - } else { - // console.debug('skipped loading chunk', dx, dz, '>', this.viewDistance) - } - } - - unloadAllChunks () { - for (const coords of Object.keys(this.loadedChunks)) { - const [x, z] = coords.split(',').map(Number) - this.unloadChunk({ x, z }) - } - } - - unloadChunk (pos: ChunkPos) { - this.emitter.emit('unloadChunk', { x: pos.x, z: pos.z }) - delete this.loadedChunks[`${pos.x},${pos.z}`] - } - - async updatePosition (pos: Vec3, force = false) { - const [lastX, lastZ] = chunkPos(this.lastPos) - const [botX, botZ] = chunkPos(pos) - if (lastX !== botX || lastZ !== botZ || force) { - this.emitter.emit('chunkPosUpdate', { pos }) - const newView = new ViewRect(botX, botZ, this.viewDistance) - const chunksToUnload: Vec3[] = [] - for (const coords of Object.keys(this.loadedChunks)) { - const x = parseInt(coords.split(',')[0]) - const z = parseInt(coords.split(',')[1]) - const p = new Vec3(x, 0, z) - const [chunkX, chunkZ] = chunkPos(p) - if (!newView.contains(chunkX, chunkZ)) { - chunksToUnload.push(p) - } - } - console.log('unloading', chunksToUnload.length, 'total now', Object.keys(this.loadedChunks).length) - for (const p of chunksToUnload) { - this.unloadChunk(p) - } - 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(a => !!a) - this.lastPos.update(pos) - await this._loadChunks(positions) - } else { - this.emitter.emit('chunkPosUpdate', { pos }) // todo-low - this.lastPos.update(pos) - } - } -} diff --git a/prismarine-viewer/viewer/lib/worldrendererCommon.ts b/prismarine-viewer/viewer/lib/worldrendererCommon.ts deleted file mode 100644 index d1786650..00000000 --- a/prismarine-viewer/viewer/lib/worldrendererCommon.ts +++ /dev/null @@ -1,300 +0,0 @@ -import * as THREE from 'three' -import { Vec3 } from 'vec3' -import { loadJSON } from './utils' -import { loadTexture } from './utils.web' -import { EventEmitter } from 'events' -import mcDataRaw from 'minecraft-data/data.js' // handled correctly in esbuild plugin -import { dynamicMcDataFiles } from '../../buildMesherConfig.mjs' -import { toMajor } from './version.js' -import { chunkPos } from './simpleUtils' -import { defaultMesherConfig } from './mesher/shared' -import { buildCleanupDecorator } from './cleanupDecorator' - -function mod (x, n) { - return ((x % n) + n) % n -} - -export const worldCleanup = buildCleanupDecorator('resetWorld') - -export const defaultWorldRendererConfig = { - showChunkBorders: false, - numWorkers: 4 -} - -export type WorldRendererConfig = typeof defaultWorldRendererConfig - -export abstract class WorldRendererCommon { - worldConfig = { minY: 0, worldHeight: 256 } - material = new THREE.MeshLambertMaterial({ vertexColors: true, transparent: true, alphaTest: 0.1 }) - - @worldCleanup() - active = false - version = undefined as string | undefined - @worldCleanup() - loadedChunks = {} as Record - @worldCleanup() - finishedChunks = {} as Record - @worldCleanup() - sectionsOutstanding = new Map() - renderUpdateEmitter = new EventEmitter() - customBlockStatesData = undefined as any - customTexturesDataUrl = undefined as string | undefined - downloadedBlockStatesData = undefined as any - downloadedTextureImage = undefined as any - workers: any[] = [] - viewerPosition?: Vec3 - lastCamUpdate = 0 - droppedFpsPercentage = 0 - initialChunksLoad = true - enableChunksLoadDelay = false - texturesVersion?: string - viewDistance = -1 - chunksLength = 0 - @worldCleanup() - allChunksFinished = false - handleResize = () => { } - mesherConfig = defaultMesherConfig - camera: THREE.PerspectiveCamera - - abstract outputFormat: 'threeJs' | 'webgl' - - constructor(public config: WorldRendererConfig) { - // this.initWorkers(1) // preload script on page load - this.snapshotInitialValues() - } - - snapshotInitialValues () { } - - initWorkers (numWorkers = this.config.numWorkers) { - // init workers - for (let i = 0; i < numWorkers; i++) { - // Node environment needs an absolute path, but browser needs the url of the file - const workerName = 'mesher.js' - const src = typeof window === 'undefined' ? `${__dirname}/${workerName}` : workerName - - const worker: any = new Worker(src) - worker.onmessage = async ({ data }) => { - if (!this.active) return - this.handleWorkerMessage(data) - await new Promise(resolve => { - setTimeout(resolve, 0) - }) - if (data.type === 'sectionFinished') { - if (!this.sectionsOutstanding.get(data.key)) throw new Error(`sectionFinished event for non-outstanding section ${data.key}`) - this.sectionsOutstanding.set(data.key, this.sectionsOutstanding.get(data.key)! - 1) - if (this.sectionsOutstanding.get(data.key) === 0) this.sectionsOutstanding.delete(data.key) - - const chunkCoords = data.key.split(',').map(Number) - if (this.loadedChunks[`${chunkCoords[0]},${chunkCoords[2]}`]) { // ensure chunk data was added, not a neighbor chunk update - const loadingKeys = [...this.sectionsOutstanding.keys()] - if (!loadingKeys.some(key => { - const [x, y, z] = key.split(',').map(Number) - return x === chunkCoords[0] && z === chunkCoords[2] - })) { - this.finishedChunks[`${chunkCoords[0]},${chunkCoords[2]}`] = true - } - } - if (this.sectionsOutstanding.size === 0) { - const allFinished = Object.keys(this.finishedChunks).length === this.chunksLength - if (allFinished) { - this.allChunksLoaded?.() - this.allChunksFinished = true - } - } - - this.renderUpdateEmitter.emit('update') - } - } - if (worker.on) worker.on('message', (data) => { worker.onmessage({ data }) }) - this.workers.push(worker) - } - } - - abstract handleWorkerMessage (data: WorkerReceive): void - - abstract updateCamera (pos: Vec3 | null, yaw: number, pitch: number): void - - abstract render (): void - - /** - * Optionally update data that are depedendent on the viewer position - */ - updatePosDataChunk?(key: string): void - - allChunksLoaded?(): void - - timeUpdated?(newTime: number): void - - updateViewerPosition (pos: Vec3) { - this.viewerPosition = pos - for (const [key, value] of Object.entries(this.loadedChunks)) { - if (!value) continue - this.updatePosDataChunk?.(key) - } - } - - sendWorkers (message: WorkerSend) { - for (const worker of this.workers) { - worker.postMessage(message) - } - } - - getDistance (posAbsolute: Vec3) { - const [botX, botZ] = chunkPos(this.viewerPosition!) - const dx = Math.abs(botX - Math.floor(posAbsolute.x / 16)) - const dz = Math.abs(botZ - Math.floor(posAbsolute.z / 16)) - return [dx, dz] as [number, number] - } - - abstract updateShowChunksBorder (value: boolean): void - - resetWorld () { - // destroy workers - for (const worker of this.workers) { - worker.terminate() - } - this.workers = [] - } - - // new game load happens here - setVersion (version, texturesVersion = version) { - this.version = version - this.texturesVersion = texturesVersion - this.resetWorld() - this.initWorkers() - this.active = true - this.mesherConfig.outputFormat = this.outputFormat - this.mesherConfig.version = this.version! - - this.sendMesherMcData() - this.updateTexturesData() - } - - sendMesherMcData () { - const allMcData = mcDataRaw.pc[this.version] ?? mcDataRaw.pc[toMajor(this.version)] - const mcData = Object.fromEntries(Object.entries(allMcData).filter(([key]) => dynamicMcDataFiles.includes(key))) - mcData.version = JSON.parse(JSON.stringify(mcData.version)) - - for (const worker of this.workers) { - worker.postMessage({ type: 'mcData', mcData, config: this.mesherConfig }) - } - } - - updateTexturesData () { - loadTexture(this.customTexturesDataUrl || `textures/${this.texturesVersion}.png`, (texture: import('three').Texture) => { - texture.magFilter = THREE.NearestFilter - texture.minFilter = THREE.NearestFilter - texture.flipY = false - this.material.map = texture - }, () => { - this.downloadedTextureImage = this.material.map!.image - const loadBlockStates = async () => { - return new Promise(resolve => { - if (this.customBlockStatesData) return resolve(this.customBlockStatesData) - return loadJSON(`/blocksStates/${this.texturesVersion}.json`, (data) => { - this.downloadedBlockStatesData = data - this.renderUpdateEmitter.emit('blockStatesDownloaded') - resolve(data) - }) - }) - } - loadBlockStates().then((blockStates) => { - this.mesherConfig.textureSize = this.material.map!.image.width - - for (const worker of this.workers) { - worker.postMessage({ - type: 'mesherData', - json: blockStates, - config: this.mesherConfig, - }) - } - this.renderUpdateEmitter.emit('textureDownloaded') - }) - }) - - } - - 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 - for (const worker of this.workers) { - // todo optimize - worker.postMessage({ type: 'chunk', x, z, chunk }) - } - for (let y = this.worldConfig.minY; y < this.worldConfig.worldHeight; y += 16) { - const loc = new Vec3(x, y, z) - this.setSectionDirty(loc) - 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)) - } - } - } - - removeColumn (x, z) { - delete this.loadedChunks[`${x},${z}`] - for (const worker of this.workers) { - worker.postMessage({ type: 'unloadChunk', x, z }) - } - this.allChunksFinished = Object.keys(this.finishedChunks).length === this.chunksLength - delete this.finishedChunks[`${x},${z}`] - } - - setBlockStateId (pos: Vec3, stateId: number) { - for (const worker of this.workers) { - worker.postMessage({ type: 'blockUpdate', pos, stateId }) - } - this.setSectionDirty(pos) - if ((pos.x & 15) === 0) this.setSectionDirty(pos.offset(-16, 0, 0)) - if ((pos.x & 15) === 15) this.setSectionDirty(pos.offset(16, 0, 0)) - if ((pos.y & 15) === 0) this.setSectionDirty(pos.offset(0, -16, 0)) - if ((pos.y & 15) === 15) this.setSectionDirty(pos.offset(0, 16, 0)) - if ((pos.z & 15) === 0) this.setSectionDirty(pos.offset(0, 0, -16)) - if ((pos.z & 15) === 15) this.setSectionDirty(pos.offset(0, 0, 16)) - } - - setSectionDirty (pos: Vec3, value = true) { - if (this.viewDistance === -1) throw new Error('viewDistance not set') - this.allChunksFinished = false - const distance = this.getDistance(pos) - if (!this.workers.length || distance[0] > this.viewDistance || distance[1] > this.viewDistance) return - const key = `${Math.floor(pos.x / 16) * 16},${Math.floor(pos.y / 16) * 16},${Math.floor(pos.z / 16) * 16}` - // if (this.sectionsOutstanding.has(key)) return - this.renderUpdateEmitter.emit('dirty', pos, value) - // Dispatch sections to workers based on position - // This guarantees uniformity accross workers and that a given section - // 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({ - type: 'dirty', - x: pos.x, - y: pos.y, - z: pos.z, - value, - config: this.mesherConfig, - }) - } - - // Listen for chunk rendering updates emitted if a worker finished a render and resolve if the number - // of sections not rendered are 0 - async waitForChunksToRender () { - return new Promise((resolve, reject) => { - if ([...this.sectionsOutstanding].length === 0) { - resolve() - return - } - - const updateHandler = () => { - if (this.sectionsOutstanding.size === 0) { - this.renderUpdateEmitter.removeListener('update', updateHandler) - resolve() - } - } - this.renderUpdateEmitter.on('update', updateHandler) - }) - } -} diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts deleted file mode 100644 index 60156a50..00000000 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ /dev/null @@ -1,386 +0,0 @@ -import * as THREE from 'three' -import { Vec3 } from 'vec3' -import nbt from 'prismarine-nbt' -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 - blockEntities = {} - sectionObjects: Record = {} - chunkTextures = new Map() - signsCache = new Map() - starField: StarField - - get tilesRendered () { - 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) { - super(config) - this.starField = new StarField(scene) - } - - timeUpdated (newTime: number): void { - const nightTime = 13_500 - const morningStart = 23_000 - const displayStars = newTime > nightTime && newTime < morningStart - if (displayStars && !this.starField.points) { - this.starField.addToScene() - } else if (!displayStars && this.starField.points) { - this.starField.remove() - } - } - - /** - * Optionally update data that are depedendent on the viewer position - */ - 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 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)) { - if (!value) continue - this.updatePosDataChunk(key) - } - } - - handleWorkerMessage (data: any): void { - if (data.type !== 'geometry') return - let object: THREE.Object3D = this.sectionObjects[data.key] - if (object) { - this.scene.remove(object) - disposeObject(object) - delete this.sectionObjects[data.key] - } - - const chunkCoords = data.key.split(',') - if (!this.loadedChunks[chunkCoords[0] + ',' + chunkCoords[2]] || !data.geometry.positions.length || !this.active) return - - // if (!this.initialChunksLoad && this.enableChunksLoadDelay) { - // const newPromise = new Promise(resolve => { - // if (this.droppedFpsPercentage > 0.5) { - // setTimeout(resolve, 1000 / 50 * this.droppedFpsPercentage) - // } else { - // setTimeout(resolve) - // } - // }) - // this.promisesQueue.push(newPromise) - // for (const promise of this.promisesQueue) { - // await promise - // } - // } - - const geometry = new THREE.BufferGeometry() - geometry.setAttribute('position', new THREE.BufferAttribute(data.geometry.positions, 3)) - geometry.setAttribute('normal', new THREE.BufferAttribute(data.geometry.normals, 3)) - geometry.setAttribute('color', new THREE.BufferAttribute(data.geometry.colors, 3)) - geometry.setAttribute('uv', new THREE.BufferAttribute(data.geometry.uvs, 2)) - geometry.setIndex(data.geometry.indices) - - const mesh = new THREE.Mesh(geometry, this.material) - mesh.position.set(data.geometry.sx, data.geometry.sy, data.geometry.sz) - mesh.name = 'mesh' - object = new THREE.Group() - object.add(mesh) - const boxHelper = new THREE.BoxHelper(mesh, 0xffff00) - boxHelper.name = 'helper' - object.add(boxHelper) - object.name = 'chunk' - //@ts-ignore - object.tilesCount = data.geometry.positions.length / 3 / 4 - if (!this.config.showChunkBorders) { - boxHelper.visible = false - } - // should not compute it once - if (Object.keys(data.geometry.signs).length) { - for (const [posKey, { isWall, 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)) - if (!sign) continue - object.add(sign) - } - } - this.sectionObjects[data.key] = object - this.updatePosDataChunk(data.key) - this.scene.add(object) - } - - getSignTexture (position: Vec3, blockEntity, backSide = false) { - const chunk = chunkPos(position) - let textures = this.chunkTextures.get(`${chunk[0]},${chunk[1]}`) - if (!textures) { - textures = {} - this.chunkTextures.set(`${chunk[0]},${chunk[1]}`, textures) - } - const texturekey = `${position.x},${position.y},${position.z}` - // todo investigate bug and remove this so don't need to clean in section dirty - if (textures[texturekey]) return textures[texturekey] - - const PrismarineChat = PrismarineChatLoader(this.version!) - const canvas = renderSign(blockEntity, PrismarineChat) - if (!canvas) return - const tex = new THREE.Texture(canvas) - tex.magFilter = THREE.NearestFilter - tex.minFilter = THREE.NearestFilter - tex.needsUpdate = true - textures[texturekey] = tex - return tex - } - - updateCamera (pos: Vec3 | null, yaw: number, pitch: number): void { - if (pos) { - new tweenJs.Tween(this.camera.position).to({ x: pos.x, y: pos.y, z: pos.z }, 50).start() - } - this.camera.rotation.set(pitch, yaw, 0, 'ZYX') - } - - render () { - tweenJs.update() - this.renderer.render(this.scene, this.camera) - } - - renderSign (position: Vec3, rotation: number, isWall: boolean, blockEntity) { - const tex = this.getSignTexture(position, blockEntity) - - if (!tex) return - - // todo implement - // const key = JSON.stringify({ position, rotation, isWall }) - // if (this.signsCache.has(key)) { - // console.log('cached', key) - // } else { - // this.signsCache.set(key, tex) - // } - - 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? - mesh.scale.set(1, 7 / 16, 1) - if (isWall) { - mesh.position.set(0, 0, -(8 - 1.5) / 16 + 0.001) - } else { - // standing - const faceEnd = 8.75 - mesh.position.set(0, 0, (faceEnd - 16 / 2) / 16 + 0.001) - } - - const group = new THREE.Group() - group.rotation.set(0, -THREE.MathUtils.degToRad( - 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) - return group - } - - updateLight (chunkX: number, chunkZ: number) { - // set all sections in the chunk dirty - for (let y = this.worldConfig.minY; y < this.worldConfig.worldHeight; y += 16) { - this.setSectionDirty(new Vec3(chunkX, y, chunkZ)) - } - } - - async doHmr () { - const oldSections = { ...this.sectionObjects } - this.sectionObjects = {} // skip clearing - worldView!.unloadAllChunks() - this.setVersion(this.version, this.texturesVersion) - this.sectionObjects = oldSections - // this.rerenderAllChunks() - - // supply new data - await worldView!.updatePosition(bot.entity.position, true) - } - - rerenderAllChunks () { // todo not clear what to do with loading chunks - for (const key of Object.keys(this.sectionObjects)) { - const [x, y, z] = key.split(',').map(Number) - this.setSectionDirty(new Vec3(x, y, z)) - } - } - - updateShowChunksBorder (value: boolean) { - this.config.showChunkBorders = value - for (const object of Object.values(this.sectionObjects)) { - for (const child of object.children) { - if (child.name === 'helper') { - child.visible = value - } - } - } - } - - resetWorld () { - super.resetWorld() - - for (const mesh of Object.values(this.sectionObjects)) { - this.scene.remove(mesh) - } - } - - getLoadedChunksRelative (pos: Vec3, includeY = false) { - const [currentX, currentY, currentZ] = sectionPos(pos) - return Object.fromEntries(Object.entries(this.sectionObjects).map(([key, o]) => { - const [xRaw, yRaw, zRaw] = key.split(',').map(Number) - const [x, y, z] = sectionPos({ x: xRaw, y: yRaw, z: zRaw }) - const setKey = includeY ? `${x - currentX},${y - currentY},${z - currentZ}` : `${x - currentX},${z - currentZ}` - return [setKey, o] - })) - } - - cleanChunkTextures (x, z) { - const textures = this.chunkTextures.get(`${Math.floor(x / 16)},${Math.floor(z / 16)}`) ?? {} - for (const key of Object.keys(textures)) { - textures[key].dispose() - delete textures[key] - } - } - - removeColumn (x, z) { - super.removeColumn(x, z) - - this.cleanChunkTextures(x, z) - for (let y = this.worldConfig.minY; y < this.worldConfig.worldHeight; y += 16) { - this.setSectionDirty(new Vec3(x, y, z), false) - const key = `${x},${y},${z}` - const mesh = this.sectionObjects[key] - if (mesh) { - this.scene.remove(mesh) - disposeObject(mesh) - } - delete this.sectionObjects[key] - } - } - - setSectionDirty (pos, value = true) { - this.cleanChunkTextures(pos.x, pos.z) // todo don't do this! - super.setSectionDirty(pos, value) - } -} - -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 - const factor = 7 - const saturation = 10 - const speed = 0.2 - - const geometry = new THREE.BufferGeometry() - - const genStar = r => new THREE.Vector3().setFromSpherical(new THREE.Spherical(r, Math.acos(1 - Math.random() * 2), Math.random() * 2 * Math.PI)) - - const positions = [] as number[] - const colors = [] as number[] - const sizes = Array.from({ length: count }, () => (0.5 + 0.5 * Math.random()) * factor) - const color = new THREE.Color() - let r = radius + depth - const increment = depth / count - for (let i = 0; i < count; i++) { - r -= increment * Math.random() - positions.push(...genStar(r).toArray()) - color.setHSL(i / count, saturation, 0.9) - colors.push(color.r, color.g, color.b) - } - - geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)) - geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)) - geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1)) - - // Create a material - const material = new StarfieldMaterial() - material.blending = THREE.AdditiveBlending - material.depthTest = false - material.transparent = true - - // Create points and add them to the scene - this.points = new THREE.Points(geometry, material) - this.scene.add(this.points) - - const clock = new THREE.Clock(); - this.points.onBeforeRender = (renderer, scene, camera) => { - this.points?.position.copy?.(camera.position) - material.uniforms.time.value = clock.getElapsedTime() * speed - } - } - - remove () { - if (this.points) { - this.points.geometry.dispose(); - (this.points.material as THREE.Material).dispose(); - this.scene.remove(this.points) - - this.points = undefined; - } - } -} - -const version = parseInt(THREE.REVISION.replace(/\D+/g, '')) -class StarfieldMaterial extends THREE.ShaderMaterial { - constructor() { - super({ - uniforms: { time: { value: 0.0 }, fade: { value: 1.0 } }, - vertexShader: /* glsl */ ` - uniform float time; - attribute float size; - varying vec3 vColor; - attribute vec3 color; - void main() { - vColor = color; - vec4 mvPosition = modelViewMatrix * vec4(position, 0.5); - gl_PointSize = size * (30.0 / -mvPosition.z) * (3.0 + sin(time + 100.0)); - gl_Position = projectionMatrix * mvPosition; - }`, - fragmentShader: /* glsl */ ` - uniform sampler2D pointTexture; - uniform float fade; - varying vec3 vColor; - void main() { - float opacity = 1.0; - if (fade == 1.0) { - float d = distance(gl_PointCoord, vec2(0.5, 0.5)); - opacity = 1.0 / (1.0 + exp(16.0 * (d - 0.25))); - } - gl_FragColor = vec4(vColor, opacity); - - #include - #include <${version >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}> - }`, - }) - } -} diff --git a/prismarine-viewer/viewer/prepare/atlas.ts b/prismarine-viewer/viewer/prepare/atlas.ts deleted file mode 100644 index cb30b727..00000000 --- a/prismarine-viewer/viewer/prepare/atlas.ts +++ /dev/null @@ -1,111 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { Canvas, Image } from 'canvas' -import { getAdditionalTextures } from './moreGeneratedBlocks' -import { McAssets } from './modelsBuilder' - -function nextPowerOfTwo (n) { - if (n === 0) return 1 - n-- - n |= n >> 1 - n |= n >> 2 - n |= n >> 4 - n |= n >> 8 - n |= n >> 16 - return n + 1 -} - -const localTextures = ['missing_texture.png'] - -function readTexture (basePath, name) { - if (localTextures.includes(name)) { - // grab ./missing_texture.png - basePath = __dirname - } - return fs.readFileSync(path.join(basePath, name), 'base64') -} - -export type JsonAtlas = { - size: number, - textures: { - [file: string]: { - u: number, - v: number, - } - } -} - -export const makeTextureAtlas = (input: string[], getInputData: (name) => { contents: string, tileWidthMult?: number }, tilesCount = input.length, suSvOptimize: 'remove' | null = null): { - image: Buffer, - canvas: Canvas, - json: JsonAtlas -} => { - const texSize = nextPowerOfTwo(Math.ceil(Math.sqrt(tilesCount))) - const tileSize = 16 - - const imgSize = texSize * tileSize - const canvas = new Canvas(imgSize, imgSize, 'png' as any) - const g = canvas.getContext('2d') - - const texturesIndex = {} - - let offset = 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 - - const img = new Image() - 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) - - const cleanName = keyValue.split('.').slice(0, -1).join('.') || keyValue - texturesIndex[cleanName] = { - u: x / imgSize, - v: y / imgSize, - ...suSvOptimize === 'remove' ? {} : { - su: suSv, - sv: suSv - } - } - } - - return { image: canvas.toBuffer(), canvas, json: { size: suSv, textures: texturesIndex } } -} - -export const writeCanvasStream = (canvas, path, onEnd) => { - const out = fs.createWriteStream(path) - const stream = (canvas as any).pngStream() - stream.on('data', (chunk) => out.write(chunk)) - if (onEnd) stream.on('end', onEnd) - return stream -} - -export function makeBlockTextureAtlas (mcAssets: McAssets) { - const blocksTexturePath = path.join(mcAssets.directory, '/blocks') - const textureFiles = fs.readdirSync(blocksTexturePath).filter(file => file.endsWith('.png')) - // const textureFiles = mostEncounteredBlocks.map(x => x + '.png') - textureFiles.unshift(...localTextures) - - const { generated: additionalTextures, twoTileTextures } = getAdditionalTextures() - textureFiles.push(...Object.keys(additionalTextures)) - - const atlas = makeTextureAtlas(textureFiles, name => { - let contents: string - if (additionalTextures[name]) { - contents = additionalTextures[name] - } else { - contents = 'data:image/png;base64,' + readTexture(blocksTexturePath, name) - } - - return { - contents, - tileWidthMult: twoTileTextures.includes(name) ? 2 : undefined, - } - }) - return atlas -} diff --git a/prismarine-viewer/viewer/prepare/blockStates/chest.json b/prismarine-viewer/viewer/prepare/blockStates/chest.json deleted file mode 100644 index 11053c9d..00000000 --- a/prismarine-viewer/viewer/prepare/blockStates/chest.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "variants": { - "facing=north,type=single": { - "model": "chest" - }, - "facing=east,type=single": { - "model": "chest", - "y": 90 - }, - "facing=south,type=single": { - "model": "chest", - "y": 180 - }, - "facing=west,type=single": { - "model": "chest", - "y": 270 - }, - "facing=north,type=left": { - "model": "chest_left" - }, - "facing=east,type=left": { - "model": "chest_left", - "y": 90 - }, - "facing=south,type=left": { - "model": "chest_left", - "y": 180 - }, - "facing=west,type=left": { - "model": "chest_left", - "y": 270 - }, - "facing=north,type=right": { - "model": "chest_right" - }, - "facing=east,type=right": { - "model": "chest_right", - "y": 90 - }, - "facing=south,type=right": { - "model": "chest_right", - "y": 180 - }, - "facing=west,type=right": { - "model": "chest_right", - "y": 270 - } - } -} diff --git a/prismarine-viewer/viewer/prepare/blockStates/ender_chest.json b/prismarine-viewer/viewer/prepare/blockStates/ender_chest.json deleted file mode 100644 index 7d81b878..00000000 --- a/prismarine-viewer/viewer/prepare/blockStates/ender_chest.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "variants": { - "facing=north": { - "model": "chest" - }, - "facing=east": { - "model": "chest", - "y": 90 - }, - "facing=south": { - "model": "chest", - "y": 180 - }, - "facing=west": { - "model": "chest", - "y": 270 - } - } -} diff --git a/prismarine-viewer/viewer/prepare/blockStates/trapped_chest.json b/prismarine-viewer/viewer/prepare/blockStates/trapped_chest.json deleted file mode 100644 index 11053c9d..00000000 --- a/prismarine-viewer/viewer/prepare/blockStates/trapped_chest.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "variants": { - "facing=north,type=single": { - "model": "chest" - }, - "facing=east,type=single": { - "model": "chest", - "y": 90 - }, - "facing=south,type=single": { - "model": "chest", - "y": 180 - }, - "facing=west,type=single": { - "model": "chest", - "y": 270 - }, - "facing=north,type=left": { - "model": "chest_left" - }, - "facing=east,type=left": { - "model": "chest_left", - "y": 90 - }, - "facing=south,type=left": { - "model": "chest_left", - "y": 180 - }, - "facing=west,type=left": { - "model": "chest_left", - "y": 270 - }, - "facing=north,type=right": { - "model": "chest_right" - }, - "facing=east,type=right": { - "model": "chest_right", - "y": 90 - }, - "facing=south,type=right": { - "model": "chest_right", - "y": 180 - }, - "facing=west,type=right": { - "model": "chest_right", - "y": 270 - } - } -} diff --git a/prismarine-viewer/viewer/prepare/genItemsAtlas.ts b/prismarine-viewer/viewer/prepare/genItemsAtlas.ts deleted file mode 100644 index 788f1b60..00000000 --- a/prismarine-viewer/viewer/prepare/genItemsAtlas.ts +++ /dev/null @@ -1,148 +0,0 @@ -import fs from 'fs' -import McAssets from 'minecraft-assets' -import { join } from 'path' -import { filesize } from 'filesize' -import minecraftDataLoader from 'minecraft-data' -import BlockLoader from 'prismarine-block' -import { JsonAtlas, makeTextureAtlas, writeCanvasStream } from './atlas' -import looksSame from 'looks-same' // ensure after canvas import -import { Version as _Version } from 'minecraft-data' -import { versionToNumber } from './utils' - -// todo move it, remove it -const legacyInvsprite = JSON.parse(fs.readFileSync(join(__dirname, '../../../src/invsprite.json'), 'utf8')) - -//@ts-ignore -const latestMcAssetsVersion = McAssets.versions.at(-1)! -// const latestVersion = minecraftDataLoader.supportedVersions.pc.at(-1) -const mcData = minecraftDataLoader(latestMcAssetsVersion) -const PBlock = BlockLoader(latestMcAssetsVersion) - -function isCube (name) { - const id = mcData.blocksByName[name]?.id - if (!id) return - const block = new PBlock(id, 0, 0) - const shape = block.shapes?.[0] - return block.shapes?.length === 1 && shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1 -} - -export type ItemsAtlasesOutputJson = { - latest: JsonAtlas - legacy: JsonAtlas - legacyMap: [string, string[]][] -} - -export const generateItemsAtlases = async () => { - const latestAssets = McAssets(latestMcAssetsVersion) - const latestItems = fs.readdirSync(join(latestAssets.directory, 'items')).map(f => f.split('.')[0]) - - // item - texture path - const toAddTextures = { - fromBlocks: {} as Record, - remapItems: {} as Record, // todo - } - - const getItemTextureOfBlock = (name: string) => { - const blockModel = latestAssets.blocksModels[name] - // const isPlainBlockDisplay = blockModel?.display?.gui?.rotation?.[0] === 0 && blockModel?.display?.gui?.rotation?.[1] === 0 && blockModel?.display?.gui?.rotation?.[2] === 0 - // it seems that information about cross blocks is hardcoded - if (blockModel?.parent?.endsWith('block/cross')) { - toAddTextures.fromBlocks[name] = `blocks/${blockModel.textures.cross.split('/')[1]}` - return true - } - - if (legacyInvsprite[name]) { - return true - } - - if (fs.existsSync(join(latestAssets.directory, 'blocks', name + '.png'))) { - // very last resort - toAddTextures.fromBlocks[name] = `blocks/${name}` - return true - } - if (name.endsWith('_spawn_egg')) { - // todo also color - toAddTextures.fromBlocks[name] = `items/spawn_egg` - } - } - - for (const item of mcData.itemsArray) { - if (latestItems.includes(item.name)) { - continue - } - // USE IN RUNTIME - if (isCube(item.name)) { - // console.log('cube', block.name) - } else if (!getItemTextureOfBlock(item.name)) { - console.warn('skipping item (not cube, no item texture)', item.name) - } - } - - let fullItemsMap = {} as Record - - const itemsSizes = {} - let saving = 0 - let overallsize = 0 - let prevItemsDir - let prevVersion - for (const version of [...McAssets.versions].reverse()) { - const itemsDir = join(McAssets(version).directory, 'items') - for (const item of fs.readdirSync(itemsDir)) { - const prevItemPath = !prevItemsDir ? undefined : join(prevItemsDir, item) - const itemSize = fs.statSync(join(itemsDir, item)).size - if (prevItemPath && fs.existsSync(prevItemPath) && (await looksSame(join(itemsDir, item), prevItemPath, { strict: true })).equal) { - saving += itemSize - } else { - fullItemsMap[version] ??= [] - fullItemsMap[version].push(item) - } - overallsize += itemSize - } - prevItemsDir = itemsDir - prevVersion = version - } - - fullItemsMap = Object.fromEntries(Object.entries(fullItemsMap).map(([ver, items]) => [ver, items.filter(item => item.endsWith('.png'))])) - const latestVersionItems = fullItemsMap[latestMcAssetsVersion] - delete fullItemsMap[latestMcAssetsVersion] - const legacyItemsSortedEntries = Object.entries(fullItemsMap).sort(([a], [b]) => versionToNumber(a) - versionToNumber(b)).map(([key, value]) => [key, value.map(x => x.replace('.png', ''))] as [typeof key, typeof value]) - // const allItemsLength = Object.values(fullItemsMap).reduce((acc, x) => acc + x.length, 0) - // console.log(`Items to generate: ${allItemsLength} (latest version: ${latestVersionItems.length})`) - const fullLatestItemsObject = { - ...Object.fromEntries(latestVersionItems.map(item => [item, `items/${item.replace('.png', '')}`])), - ...toAddTextures.fromBlocks, - ...toAddTextures.remapItems - } - - const latestAtlas = makeTextureAtlas(Object.keys(fullLatestItemsObject), (name) => { - const contents = `data:image/png;base64,${fs.readFileSync(join(latestAssets.directory, `${fullLatestItemsObject[name]}.png`), 'base64')}` - return { - contents, - } - }, undefined, 'remove') - const texturesPath = join(__dirname, '../../public/textures') - writeCanvasStream(latestAtlas.canvas, join(texturesPath, 'items.png'), () => { - console.log('Generated latest items atlas') - }) - - const legacyItemsMap = legacyItemsSortedEntries.flatMap(([ver, items]) => items.map(item => `${ver}-${item}.png`)) - const legacyItemsAtlas = makeTextureAtlas(legacyItemsMap, (name) => { - const [ver, item] = name.split('-') - const contents = `data:image/png;base64,${fs.readFileSync(join(McAssets(ver).directory, `items/${item}`), 'base64')}` - return { - contents, - } - }, undefined, 'remove') - writeCanvasStream(legacyItemsAtlas.canvas, join(texturesPath, 'items-legacy.png'), () => { - console.log('Generated legacy items atlas') - }) - - const allItemsMaps: ItemsAtlasesOutputJson = { - latest: latestAtlas.json, - legacy: legacyItemsAtlas.json, - legacyMap: legacyItemsSortedEntries - } - fs.writeFileSync(join(texturesPath, 'items.json'), JSON.stringify(allItemsMaps), 'utf8') - - console.log(`Generated items! Input size: ${filesize(overallsize)}, saving: ~${filesize(saving)}`) -} diff --git a/prismarine-viewer/viewer/prepare/generateTextures.ts b/prismarine-viewer/viewer/prepare/generateTextures.ts deleted file mode 100644 index f66fb5d7..00000000 --- a/prismarine-viewer/viewer/prepare/generateTextures.ts +++ /dev/null @@ -1,52 +0,0 @@ -import path from 'path' -import { makeBlockTextureAtlas } from './atlas' -import { prepareBlocksStates } from './modelsBuilder' -import mcAssets from 'minecraft-assets' -import fs from 'fs-extra' -import { prepareMoreGeneratedBlocks } from './moreGeneratedBlocks' -import { generateItemsAtlases } from './genItemsAtlas' -import { versionToNumber } from './utils' - -const publicPath = path.resolve(__dirname, '../../public') - -const texturesPath = path.join(publicPath, 'textures') -fs.mkdirSync(texturesPath, { recursive: true }) - -const blockStatesPath = path.join(publicPath, 'blocksStates') -fs.mkdirSync(blockStatesPath, { recursive: true }) - -const warnings = new Set() -Promise.resolve().then(async () => { - generateItemsAtlases() - console.time('generateTextures') - const versions = process.argv.includes('-l') ? [mcAssets.versions.at(-1)!] : mcAssets.versions - for (const version of versions as typeof mcAssets['versions']) { - // for debugging (e.g. when above is overridden) - if (!versions.includes(version)) { - throw new Error(`Version ${version} is not supported by minecraft-assets`) - } - if (versionToNumber(version) < versionToNumber('1.13')) { - // we normalize data to 1.13 for pre 1.13 versions - continue - } - const assets = mcAssets(version) - const { warnings: _warnings } = await prepareMoreGeneratedBlocks(assets) - _warnings.forEach(x => warnings.add(x)) - // #region texture atlas - const atlas = makeBlockTextureAtlas(assets) - const out = fs.createWriteStream(path.resolve(texturesPath, version + '.png')) - const stream = (atlas.canvas as any).pngStream() - stream.on('data', (chunk) => out.write(chunk)) - stream.on('end', () => console.log('Generated textures/' + version + '.png')) - // #endregion - - const blocksStates = JSON.stringify(prepareBlocksStates(assets, atlas)) - fs.writeFileSync(path.resolve(blockStatesPath, version + '.json'), blocksStates) - - fs.copySync(assets.directory, path.resolve(texturesPath, version), { overwrite: true }) - } - - fs.writeFileSync(path.join(publicPath, 'supportedVersions.json'), '[' + versions.map(v => `"${v}"`).toString() + ']') - warnings.forEach(x => console.warn(x)) - console.timeEnd('generateTextures') -}) diff --git a/prismarine-viewer/viewer/prepare/missing_texture.png b/prismarine-viewer/viewer/prepare/missing_texture.png deleted file mode 100644 index affd9d68..00000000 Binary files a/prismarine-viewer/viewer/prepare/missing_texture.png and /dev/null differ diff --git a/prismarine-viewer/viewer/prepare/modelsBuilder.ts b/prismarine-viewer/viewer/prepare/modelsBuilder.ts deleted file mode 100644 index 2a0cac57..00000000 --- a/prismarine-viewer/viewer/prepare/modelsBuilder.ts +++ /dev/null @@ -1,257 +0,0 @@ -type ModelBasic = { - model: string - x?: number - y?: number - uvlock?: boolean -} - -type BlockApplyModel = ModelBasic | (ModelBasic & { weight })[] - -type BlockStateCondition = { - [name: string]: string | number -} - -type BlockState = { - variants?: { - [name: string | ""]: BlockApplyModel - } - multipart?: { - when: { - [name: string]: string | number - } & { - OR?: BlockStateCondition[] - } - apply: BlockApplyModel - }[] -} - -type BlockModel = { - parent?: string - textures?: { - [name: string]: string - } - elements?: { - from: number[] - to: number[] - faces: { - [name: string]: { - texture: string - uv?: number[] - cullface?: string - } - } - }[] - ambientocclusion?: boolean - x?: number - y?: number - z?: number - ao?: boolean -} - -export type McAssets = { - blocksStates: { - [x: string]: BlockState - } - blocksModels: { - [x: string]: BlockModel - } - directory: string - version: string -} - -export type BlockStatesOutput = { - // states: { - [blockName: string]: any/* ResolvedModel */ - // } - // defaults: { - // su: number - // sv: number - // } -} - -export type ResolvedModel = { - textures: { - [name: string]: { - u: number - v: number - su: number - sv: number - bu: number - bv: number - } - } - elements: { - from: number[] - to: number[] - faces: { - [name: string]: { - texture: { - u: number - v: number - su: number - sv: number - bu: number - bv: number - } - } - } - }[] - ao: boolean - x?: number - y?: number - z?: number -} - -export const addBlockAllModel = (mcAssets: McAssets, name: string, texture = name) => { - mcAssets.blocksStates[name] = { - "variants": { - "": { - "model": name - } - } - } - mcAssets.blocksModels[name] = { - "parent": "block/cube_all", - "textures": { - "all": `blocks/${texture}` - } - } -} - -function cleanupBlockName (name: string) { - if (name.startsWith('block') || name.startsWith('minecraft:block')) return name.split('/')[1] - return name -} - -const objectAssignStrict = > (target: T, source: Partial) => Object.assign(target, source) - -function getFinalModel (name: string, blocksModels: { [x: string]: BlockModel }) { - name = cleanupBlockName(name) - const input = blocksModels[name] - if (!input) { - return null - } - - let out: BlockModel | null = { - textures: {}, - elements: [], - ao: true, - x: input.x, - y: input.y, - z: input.z, - } - - if (input.parent) { - out = getFinalModel(input.parent, blocksModels) - if (!out) return null - } - if (input.textures) { - Object.assign(out.textures!, deepCopy(input.textures)) - } - if (input.elements) out.elements = deepCopy(input.elements) - if (input.ao !== undefined) out.ao = input.ao - return out -} - -const deepCopy = (obj) => JSON.parse(JSON.stringify(obj)) - -const workerUsedTextures = ['particle'] -function prepareModel (model: BlockModel, texturesJson) { - const newModel = {} - - const getFinalTexture = (originalBlockName) => { - // texture name e.g. blocks/anvil_base - const cleanBlockName = cleanupBlockName(originalBlockName); - return { ...texturesJson[cleanBlockName], /* __debugName: cleanBlockName */ } - } - - const finalTextures = [] - - // resolve texture names eg west: #all -> blocks/stone - for (const side in model.textures) { - let texture = model.textures[side] - - while (texture.charAt(0) === '#') { - const textureName = texture.slice(1) - texture = model.textures[textureName] - if (texture === undefined) throw new Error(`Texture ${textureName} in ${JSON.stringify(model.textures)} not found`) - } - - finalTextures[side] = getFinalTexture(texture) - if (workerUsedTextures.includes(side)) { - model.textures[side] = finalTextures[side] - } - } - - for (const elem of model.elements!) { - for (const sideName of Object.keys(elem.faces)) { - const face = elem.faces[sideName] - - const finalTexture = deepCopy( - face.texture.charAt(0) === '#' - ? finalTextures![face.texture.slice(1)] - : getFinalTexture(face.texture) - ) - - const _from = elem.from - const _to = elem.to - // taken from https://github.com/DragonDev1906/Minecraft-Overviewer/ - const uv = face.uv || { - // default UVs - // format: [u1, v1, u2, v2] (u = x, v = y) - north: [_to[0], 16 - _to[1], _from[0], 16 - _from[1]], - east: [_from[2], 16 - _to[1], _to[2], 16 - _from[1]], - south: [_from[0], 16 - _to[1], _to[0], 16 - _from[1]], - west: [_from[2], 16 - _to[1], _to[2], 16 - _from[1]], - up: [_from[0], _from[2], _to[0], _to[2]], - down: [_to[0], _from[2], _from[0], _to[2]] - }[sideName]! - - const su = (uv[2] - uv[0]) / 16 * finalTexture.su - const sv = (uv[3] - uv[1]) / 16 * finalTexture.sv - finalTexture.u += uv[0] / 16 * finalTexture.su - finalTexture.v += uv[1] / 16 * finalTexture.sv - finalTexture.su = su - finalTexture.sv = sv - face.texture = finalTexture - } - } - return model -} - -function resolveModel (name, blocksModels, texturesJson) { - const model = getFinalModel(name, blocksModels) - return prepareModel(model, texturesJson.textures) -} - -export function prepareBlocksStates (mcAssets: McAssets, atlas: { json: any }) { - addBlockAllModel(mcAssets, 'missing_texture') - - const blocksStates = mcAssets.blocksStates - for (const block of Object.values(blocksStates)) { - if (!block) continue - if (block.variants) { - for (const variant of Object.values(block.variants)) { - if (variant instanceof Array) { - for (const v of variant) { - v.model = resolveModel(v.model, mcAssets.blocksModels, atlas.json) as any - } - } else { - variant.model = resolveModel(variant.model, mcAssets.blocksModels, atlas.json) as any - } - } - } - if (block.multipart) { - for (const variant of block.multipart) { - if (variant.apply instanceof Array) { - for (const v of variant.apply) { - v.model = resolveModel(v.model, mcAssets.blocksModels, atlas.json) as any - } - } else { - variant.apply.model = resolveModel(variant.apply.model, mcAssets.blocksModels, atlas.json) as any - } - } - } - } - return blocksStates -} diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts deleted file mode 100644 index ffb1a705..00000000 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ /dev/null @@ -1,466 +0,0 @@ -import Jimp from 'jimp' -import minecraftData from 'minecraft-data' -import { McAssets } from './modelsBuilder' -import path from 'path' -import fs from 'fs' -import { fileURLToPath } from 'url' - -// todo refactor -const twoTileTextures: string[] = [] -let currentImage: Jimp -let currentBlockName: string -let currentMcAssets: McAssets -const __dirname = path.dirname(fileURLToPath(new URL(import.meta.url))) - -type SidesType = { - "up": string - "north": string - "east": string - "south": string - "west": string - "down": string -} - -const getBlockStates = (name: string) => { - const mcData = minecraftData(currentMcAssets.version) - return mcData.blocksByName[name]?.states -} - -export const addBlockCustomSidesModel = (name: string, sides: SidesType) => { - currentMcAssets.blocksStates[name] = { - "variants": { - "": { - "model": name - } - } - } - currentMcAssets.blocksModels[name] = { - "parent": "block/cube", - "textures": sides - } -} - -type TextureMap = [ - x: number, - y: number, - width?: number, - height?: number, -] - -const justCropUV = (x: number, y: number, x1, y1) => { - // input: 0-16, output: 0-currentImage.getWidth() - const width = Math.abs(x1 - x) - const height = Math.abs(y1 - y) - return currentImage.clone().crop( - x / 16 * currentImage.getWidth(), - y / 16 * currentImage.getHeight(), - width / 16 * currentImage.getWidth(), - height / 16 * currentImage.getHeight(), - ) -} -const justCrop = (x: number, y: number, width = 16, height = 16) => { - return currentImage.clone().crop(x, y, width, height) -} - -const combineTextures = (locations: TextureMap[]) => { - const resized: Jimp[] = [] - for (const [x, y, height = 16, width = 16] of locations) { - resized.push(justCrop(x, y, width, height)) - } - - const combinedImage = new Jimp(locations[0]![2] ?? 16, locations[0]![3] ?? 16) - for (const image of resized) { - combinedImage.blit(image, 0, 0) - } - return combinedImage -} - -const generatedImageTextures: { [blockName: string]: /* base64 */string } = {} - -const getBlockTexturesFromJimp = async > (sides: T, withUv = false, textureNameBase = currentBlockName): Promise> => { - const sidesTextures = {} as any - for (const [side, jimp] of Object.entries(sides)) { - const textureName = `${textureNameBase}_${side}` - const sideTexture = withUv ? { uv: [0, 0, jimp.getWidth(), jimp.getHeight()], texture: textureName } : textureName - const base64 = await jimp.getBase64Async(jimp.getMIME()) - if (side === 'side') { - sidesTextures['north'] = sideTexture - sidesTextures['east'] = sideTexture - sidesTextures['south'] = sideTexture - sidesTextures['west'] = sideTexture - } else { - sidesTextures[side] = sideTexture - } - generatedImageTextures[textureName] = base64 - } - - return sidesTextures -} - -const addSimpleCubeWithSides = async (sides: Record) => { - const sidesTextures = await getBlockTexturesFromJimp(sides) - - addBlockCustomSidesModel(currentBlockName, sidesTextures as any) -} - -const handleShulkerBox = async (dataBase: string, match: RegExpExecArray) => { - const [, shulkerColor = ''] = match - currentImage = await Jimp.read(dataBase + `entity/shulker/shulker${shulkerColor && `_${shulkerColor}`}.png`) - - const shulkerBoxTextures = { - // todo do all sides - side: combineTextures([ - [0, 16], // top - [0, 36], // bottom - ]), - up: justCrop(16, 0), - down: justCrop(32, 28) - } - - await addSimpleCubeWithSides(shulkerBoxTextures) -} - -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) -} - -const chestModels = { - chest: { - "parent": "block/block", - "textures": { - "particle": "#particles" - }, - "elements": [ - { - "from": [1, 0, 1], - "to": [15, 10, 15], - "faces": { - "down": { "texture": "#chest", "uv": [3.5, 4.75, 7, 8.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [10.5, 8.25, 14, 10.75], "rotation": 180 }, - "east": { "texture": "#chest", "uv": [0, 8.25, 3.5, 10.75], "rotation": 180 }, - "south": { "texture": "#chest", "uv": [3.5, 8.25, 7, 10.75], "rotation": 180 }, - "west": { "texture": "#chest", "uv": [7, 8.25, 10.5, 10.75], "rotation": 180 } - }, - }, - { - "from": [1, 10, 1], - "to": [15, 14, 15], - "faces": { - "up": { "texture": "#chest", "uv": [3.5, 4.75, 7, 8.25] }, - "north": { "texture": "#chest", "uv": [10.5, 3.75, 14, 4.75], "rotation": 180 }, - "east": { "texture": "#chest", "uv": [0, 3.75, 3.5, 4.75], "rotation": 180 }, - "south": { "texture": "#chest", "uv": [3.5, 3.75, 7, 4.75], "rotation": 180 }, - "west": { "texture": "#chest", "uv": [7, 3.75, 10.5, 4.75], "rotation": 180 } - } - }, - { - "from": [7, 7, 0], - "to": [9, 11, 1], - "faces": { - "down": { "texture": "#chest", "uv": [0.25, 0, 0.75, 0.25], "rotation": 180 }, - "up": { "texture": "#chest", "uv": [0.75, 0, 1.25, 0.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [1, 0.25, 1.5, 1.25], "rotation": 180 }, - "west": { "texture": "#chest", "uv": [0.75, 0.25, 1, 1.25], "rotation": 180 }, - "east": { "texture": "#chest", "uv": [0, 0.25, 0.25, 1.25], "rotation": 180 } - } - } - ] - }, - chest_left: { - "parent": "block/block", - "textures": { - "particle": "#particles" - }, - "elements": [ - { - "from": [1, 0, 1], - "to": [16, 10, 15], - "faces": { - "down": { "texture": "#chest", "uv": [3.5, 4.75, 7.25, 8.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [10.75, 8.25, 14.5, 10.75], "rotation": 180 }, - "south": { "texture": "#chest", "uv": [3.5, 8.25, 7.25, 10.75], "rotation": 180 }, - "west": { "texture": "#chest", "uv": [7.25, 8.25, 10.75, 10.75], "rotation": 180 } - } - }, - { - "from": [1, 10, 1], - "to": [16, 14, 15], - "faces": { - "up": { "texture": "#chest", "uv": [3.5, 4.75, 7.25, 8.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [10.75, 3.75, 14.5, 4.75], "rotation": 180 }, - "south": { "texture": "#chest", "uv": [3.5, 3.75, 7.25, 4.75], "rotation": 180 }, - "west": { "texture": "#chest", "uv": [7.25, 3.75, 10.75, 4.75], "rotation": 180 } - } - }, - { - "from": [15, 7, 0], - "to": [16, 11, 1], - "faces": { - "down": { "texture": "#chest", "uv": [0.25, 0, 0.5, 0.25], "rotation": 180 }, - "up": { "texture": "#chest", "uv": [0.5, 0, 0.75, 0.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [0.75, 0.25, 1, 1.25], "rotation": 180 }, - "west": { "texture": "#chest", "uv": [0.5, 0.25, 0.75, 1.25], "rotation": 180 } - } - } - ] - }, - chest_right: { - "parent": "block/block", - "textures": { - "particle": "#particles" - }, - "elements": [ - { - "from": [0, 0, 1], - "to": [15, 10, 15], - "faces": { - "down": { "texture": "#chest", "uv": [3.5, 4.75, 7.25, 8.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [10.75, 8.25, 14.5, 10.75], "rotation": 180 }, - "east": { "texture": "#chest", "uv": [0, 8.25, 3.5, 10.75], "rotation": 180 }, - "south": { "texture": "#chest", "uv": [3.5, 8.25, 7.25, 10.75], "rotation": 180 } - } - }, - { - "from": [0, 10, 1], - "to": [15, 14, 15], - "faces": { - "up": { "texture": "#chest", "uv": [3.5, 4.75, 7.25, 8.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [10.75, 3.75, 14.5, 4.75], "rotation": 180 }, - "east": { "texture": "#chest", "uv": [0, 3.75, 3.5, 4.75], "rotation": 180 }, - "south": { "texture": "#chest", "uv": [3.5, 3.75, 7.25, 4.75], "rotation": 180 } - } - }, - { - "from": [0, 7, 0], - "to": [1, 11, 1], - "faces": { - "down": { "texture": "#chest", "uv": [0.25, 0, 0.5, 0.25], "rotation": 180 }, - "up": { "texture": "#chest", "uv": [0.5, 0, 0.75, 0.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [0.75, 0.25, 1, 1.25], "rotation": 180 }, - "east": { "texture": "#chest", "uv": [0.0, 0.25, 0.25, 1.25], "rotation": 180 } - } - } - ] - } -} - -// these blockStates / models copied from https://github.com/FakeDomi/FastChest/blob/master/src/main/resources/assets/minecraft/blockstates/ -const chestBlockStatesMap = { - chest: JSON.parse(fs.readFileSync(path.join(__dirname, 'blockStates/chest.json'), 'utf-8')), - trapped_chest: JSON.parse(fs.readFileSync(path.join(__dirname, 'blockStates/trapped_chest.json'), 'utf-8')), - ender_chest: JSON.parse(fs.readFileSync(path.join(__dirname, 'blockStates/ender_chest.json'), 'utf-8')), -} -const handleChest = async (dataBase: string, match: RegExpExecArray) => { - const blockStates = structuredClone(chestBlockStatesMap[currentBlockName]) - - const particle = match[1] === 'ender' ? 'obsidian' : 'oak_planks' - - const blockStatesVariants = Object.values(blockStates.variants) as { model }[] - const neededModels = [...new Set(blockStatesVariants.map((x) => x.model))] - - for (const modelName of neededModels) { - let chestTextureName = { - chest: 'normal', - trapped_chest: 'trapped', - ender_chest: 'ender', - }[currentBlockName] - if (modelName.endsWith('_left')) chestTextureName = `${chestTextureName}_left` - if (modelName.endsWith('_right')) chestTextureName = `${chestTextureName}_right` - - const texture = path.join(currentMcAssets.directory, `../1.19.1/entity/chest/${chestTextureName}.png`) - - currentImage = await Jimp.read(texture) - - const model = structuredClone(chestModels[modelName]) - model.textures.particle = particle - const newModelName = `${currentBlockName}_${modelName}` - for (const variant of blockStatesVariants) { - if (variant.model !== modelName) continue - variant.model = newModelName - } - for (const [i, { faces }] of model.elements.entries()) { - for (const [faceName, face] of Object.entries(faces) as any) { - const { uv } = face - //@ts-ignore - const jimp = justCropUV(...uv) - const key = `${chestTextureName}_${modelName}_${i}_${faceName}` - const texture = await getBlockTexturesFromJimp({ - [key]: jimp - }, true, key).then(a => a[key]) - face.texture = texture.texture - face.uv = texture.uv - } - } - currentMcAssets.blocksModels[newModelName] = model - } - currentMcAssets.blocksStates[currentBlockName] = blockStates -} - -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 - [/(^light|^moving_piston$)/, true], -] as const - -export const tryHandleBlockEntity = async (dataBase, blockName) => { - currentBlockName = blockName - for (const [regex, handler] of handlers) { - const match = regex.exec(blockName) - if (!match) continue - if (handler !== true) { - await handler(dataBase, match) - } - return true - } -} - -export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { - const mcData = minecraftData(mcAssets.version) - 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'] - - for (const theBlock of allTheBlocks) { - try { - if (await tryHandleBlockEntity(mcAssets.directory, theBlock)) { - handledBlocks.push(theBlock) - } - } catch (err) { - // todo remove when all warnings are resolved - console.warn(`[${mcAssets.version}] failed to generate block ${theBlock}`) - } - } - - const warnings: string[] = [] - for (const [name, model] of Object.entries(mcAssets.blocksModels)) { - if (Object.keys(model).length === 1 && model.textures) { - const keys = Object.keys(model.textures) - if (keys.length === 1 && keys[0] === 'particle') { - if (handledBlocks.includes(name) || ignoredBlocks.includes(name)) continue - warnings.push(`unhandled block ${name}`) - } - } - } - - return { warnings } -} - -export const getAdditionalTextures = () => { - return { generated: generatedImageTextures, twoTileTextures } -} diff --git a/prismarine-viewer/viewer/prepare/postinstall.ts b/prismarine-viewer/viewer/prepare/postinstall.ts deleted file mode 100644 index bf70d26c..00000000 --- a/prismarine-viewer/viewer/prepare/postinstall.ts +++ /dev/null @@ -1,12 +0,0 @@ -import path from 'path' -import fs from 'fs' - -const publicPath = path.resolve(__dirname, '../../public') -const texturesPath = path.join(publicPath, 'textures') - -if (fs.existsSync(texturesPath) && !process.argv.includes('-f')) { - console.log('textures folder already exists, skipping...') - process.exit(0) -} else { - import('./generateTextures') -} diff --git a/prismarine-viewer/viewer/prepare/utils.ts b/prismarine-viewer/viewer/prepare/utils.ts deleted file mode 100644 index a33909a9..00000000 --- a/prismarine-viewer/viewer/prepare/utils.ts +++ /dev/null @@ -1,4 +0,0 @@ -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')}` -} diff --git a/prismarine-viewer/viewer/sign-renderer/index.ts b/prismarine-viewer/viewer/sign-renderer/index.ts deleted file mode 100644 index 8c0f488c..00000000 --- a/prismarine-viewer/viewer/sign-renderer/index.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { fromFormattedString, render, RenderNode, TextComponent } from '@xmcl/text-component' -import type { ChatMessage } from 'prismarine-chat' - -type SignBlockEntity = { - Color?: string - GlowingText?: 0 | 1 - Text1?: string - Text2?: string - Text3?: string - Text4?: string -} | { - // todo - is_waxed?: 0 | 1 - front_text: { - color: string - messages: string[] - // todo - has_glowing_text?: 0 | 1 - } - // todo - // back_text: {} -} - -type JsonEncodedType = string | null | Record - -const parseSafe = (text: string, task: string) => { - try { - return JSON.parse(text) - } catch (e) { - console.warn(`Failed to parse ${task}`, e) - return null - } -} - -export const renderSign = (blockEntity: SignBlockEntity, PrismarineChat: typeof ChatMessage, ctxHook = (ctx) => { }) => { - // todo don't use texture rendering, investigate the font rendering when possible - // or increase factor when needed - const factor = 40 - const signboardY = [16, 9] - const heightOffset = signboardY[0] - signboardY[1] - const heightScalar = heightOffset / 16 - - let canvas: HTMLCanvasElement | undefined - let _ctx: CanvasRenderingContext2D | null = null - const getCtx = () => { - if (_ctx) return _ctx - canvas = document.createElement('canvas') - - canvas.width = 16 * factor - canvas.height = heightOffset * factor - - _ctx = canvas.getContext('2d')! - _ctx.imageSmoothingEnabled = false - - ctxHook(_ctx) - return _ctx - } - - const texts = 'front_text' in blockEntity ? /* > 1.20 */ blockEntity.front_text.messages : [ - blockEntity.Text1, - blockEntity.Text2, - blockEntity.Text3, - blockEntity.Text4 - ] - const defaultColor = ('front_text' in blockEntity ? blockEntity.front_text.color : blockEntity.Color) || 'black' - for (let [lineNum, text] of texts.slice(0, 4).entries()) { - // todo: in pre flatenning it seems the format was not json - if (text === 'null') continue - const parsed = text?.startsWith('{') || text?.startsWith('"') ? parseSafe(text ?? '""', 'sign text') : text - if (!parsed || (typeof parsed !== 'object' && typeof parsed !== 'string')) continue - // todo fix type - const message = typeof parsed === 'string' ? fromFormattedString(parsed) : new PrismarineChat(parsed) as never - const patchExtra = ({ extra }: TextComponent) => { - if (!extra) return - for (const child of extra) { - if (child.color) { - child.color = child.color === 'dark_green' ? child.color.toUpperCase() : child.color.toLowerCase() - } - patchExtra(child) - } - } - patchExtra(message) - const rendered = render(message) - - const toRenderCanvas: { - fontStyle: string - fillStyle: string - underlineStyle: boolean - strikeStyle: boolean - text: string - }[] = [] - let plainText = '' - // todo the text should be clipped based on it's render width (needs investigate) - const MAX_LENGTH = 50 // avoid abusing the signboard - const renderText = (node: RenderNode) => { - const { component } = node - let { text } = component - if (plainText.length + text.length > MAX_LENGTH) { - text = text.slice(0, MAX_LENGTH - plainText.length) - if (!text) return false - } - plainText += text - toRenderCanvas.push({ - fontStyle: `${component.bold ? 'bold' : ''} ${component.italic ? 'italic' : ''}`, - fillStyle: node.style['color'] || defaultColor, - underlineStyle: component.underlined ?? false, - strikeStyle: component.strikethrough ?? false, - text - }) - for (const child of node.children) { - const stop = renderText(child) === false - if (stop) return false - } - } - - renderText(rendered) - - // skip rendering empty lines (and possible signs) - if (!plainText.trim()) continue - - const ctx = getCtx() - const fontSize = 1.6 * factor; - ctx.font = `${fontSize}px mojangles` - const textWidth = ctx.measureText(plainText).width - - let renderedWidth = 0 - for (const { fillStyle, fontStyle, strikeStyle, text, underlineStyle } of toRenderCanvas) { - // todo strikeStyle, underlineStyle - ctx.fillStyle = fillStyle - ctx.font = `${fontStyle} ${fontSize}px mojangles` - ctx.fillText(text, (canvas!.width - textWidth) / 2 + renderedWidth, fontSize * (lineNum + 1)) - renderedWidth += ctx.measureText(text).width // todo isn't the font is monospace? - } - } - // ctx.fillStyle = 'red' - // ctx.fillRect(0, 0, canvas.width, canvas.height) - - return canvas -} diff --git a/prismarine-viewer/viewer/supportedVersions.json b/prismarine-viewer/viewer/supportedVersions.json deleted file mode 100644 index d4fcd3d8..00000000 --- a/prismarine-viewer/viewer/supportedVersions.json +++ /dev/null @@ -1 +0,0 @@ -["1.8.8", "1.9.4", "1.10.2", "1.11.2", "1.12.2", "1.13.2", "1.14.4", "1.15.2", "1.16.1", "1.16.4", "1.17.1", "1.18.1", "1.18.2"] \ No newline at end of file diff --git a/prismarine-viewer/webpack.config.js b/prismarine-viewer/webpack.config.js deleted file mode 100644 index d1577c9d..00000000 --- a/prismarine-viewer/webpack.config.js +++ /dev/null @@ -1,88 +0,0 @@ -// eslint-disable-next-line no-unused-vars -const webpack = require('webpack') -const path = require('path') -// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin - -// Minify the index.js by removing unused minecraft data. Since the worker only needs to do meshing, -// we can remove all the other data unrelated to meshing. -const blockedIndexFiles = ['blocksB2J', 'blocksJ2B', 'blockMappings', 'steve', 'recipes'] -const allowedWorkerFiles = ['blocks', 'blockCollisionShapes', 'tints', 'blockStates', - 'biomes', 'features', 'version', 'legacy', 'versions', 'version', 'protocolVersions'] - -const indexConfig = { - entry: './lib/index.js', - mode: 'production', - output: { - path: path.resolve(__dirname, './public'), - filename: './index.js' - }, - resolve: { - fallback: { - zlib: false - } - }, - plugins: [ - // fix "process is not defined" error: - new webpack.ProvidePlugin({ - process: 'process/browser' - }), - new webpack.ProvidePlugin({ - Buffer: ['buffer', 'Buffer'] - }), - new webpack.NormalModuleReplacementPlugin( - // eslint-disable-next-line - /viewer[\/|\\]lib[\/|\\]utils/, - './utils.web.js' - ) - // new BundleAnalyzerPlugin() - ], - externals: [ - function (req, cb) { - if (req.context.includes('minecraft-data') && req.request.endsWith('.json')) { - const fileName = req.request.split('/').pop().replace('.json', '') - if (blockedIndexFiles.includes(fileName)) { - cb(null, []) - return - } - } - cb() - } - ] -} - -const workerConfig = { - entry: './viewer/lib/worker.js', - mode: 'production', - output: { - path: path.join(__dirname, '/public'), - filename: './worker.js' - }, - resolve: { - fallback: { - zlib: false - } - }, - plugins: [ - // fix "process is not defined" error: - new webpack.ProvidePlugin({ - process: 'process/browser' - }), - new webpack.ProvidePlugin({ - Buffer: ['buffer', 'Buffer'] - }) - ], - externals: [ - function (req, cb) { - if (req.context.includes('minecraft-data') && req.request.endsWith('.json')) { - const fileName = req.request.split('/').pop().replace('.json', '') - if (!allowedWorkerFiles.includes(fileName)) { - cb(null, []) - return - } - } - cb() - } - ] -} - -module.exports = [indexConfig, workerConfig] diff --git a/prismarine-viewer/.npmrc b/renderer/.npmrc similarity index 100% rename from prismarine-viewer/.npmrc rename to renderer/.npmrc diff --git a/prismarine-viewer/buildMesherConfig.mjs b/renderer/buildMesherConfig.mjs similarity index 100% rename from prismarine-viewer/buildMesherConfig.mjs rename to renderer/buildMesherConfig.mjs diff --git a/prismarine-viewer/buildMesherWorker.mjs b/renderer/buildMesherWorker.mjs similarity index 85% rename from prismarine-viewer/buildMesherWorker.mjs rename to renderer/buildMesherWorker.mjs index e9f6a16f..d88297a5 100644 --- a/prismarine-viewer/buildMesherWorker.mjs +++ b/renderer/buildMesherWorker.mjs @@ -22,23 +22,28 @@ const buildOptions = { }, platform: 'browser', entryPoints: [path.join(__dirname, './viewer/lib/mesher/mesher.ts')], - minify: true, + minify: !watch, logLevel: 'info', drop: !watch ? [ 'debugger' ] : [], sourcemap: 'linked', + target: watch ? undefined : ['ios14'], write: false, metafile: true, - outdir: path.join(__dirname, './public'), + outdir: path.join(__dirname, './dist'), define: { 'process.env.BROWSER': '"true"', }, + loader: { + '.png': 'dataurl', + '.obj': 'text' + }, plugins: [ ...mesherSharedPlugins, { name: 'external-json', - setup (build) { + setup(build) { build.onResolve({ filter: /\.json$/ }, args => { const fileName = args.path.split('/').pop().replace('.json', '') if (args.resolveDir.includes('minecraft-data')) { @@ -108,15 +113,17 @@ const buildOptions = { }) build.onEnd(({ metafile, outputFiles }) => { if (!metafile) return - fs.writeFileSync(path.join(__dirname, './public/metafile.json'), JSON.stringify(metafile)) - for (const outDir of ['../dist/', './public/']) { + fs.mkdirSync(path.join(__dirname, './dist'), { recursive: true }) + fs.writeFileSync(path.join(__dirname, './dist/metafile.json'), JSON.stringify(metafile)) + for (const outDir of ['../dist/', './dist/']) { for (const outputFile of outputFiles) { if (outDir === '../dist/' && outputFile.path.endsWith('.map')) { // skip writing & browser loading sourcemap there, worker debugging should be done in playground // continue } - fs.mkdirSync(outDir, { recursive: true }) - fs.writeFileSync(path.join(__dirname, outDir, path.basename(outputFile.path)), outputFile.text) + const writePath = path.join(__dirname, outDir, path.basename(outputFile.path)) + fs.mkdirSync(path.dirname(writePath), { recursive: true }) + fs.writeFileSync(writePath, outputFile.text) } } }) diff --git a/prismarine-viewer/package.json b/renderer/package.json similarity index 79% rename from prismarine-viewer/package.json rename to renderer/package.json index 7fd2507f..10049f4f 100644 --- a/prismarine-viewer/package.json +++ b/renderer/package.json @@ -1,12 +1,9 @@ { - "name": "prismarine-viewer", + "name": "renderer", "version": "1.25.0", "description": "Web based viewer", "main": "index.js", - "scripts": { - "postinstall": "pnpm generate-textures && node buildMesherWorker.mjs", - "generate-textures": "tsx viewer/prepare/postinstall.ts" - }, + "scripts": {}, "author": "PrismarineJS", "license": "MIT", "standard": { @@ -21,17 +18,15 @@ "@tweenjs/tween.js": "^20.0.3", "assert": "^2.0.0", "buffer": "^6.0.3", - "canvas": "^2.11.2", "filesize": "^10.0.12", "fs-extra": "^11.0.0", "lil-gui": "^0.18.2", - "looks-same": "^8.2.3", "minecraft-wrap": "^1.3.0", "minecrafthawkeye": "^1.3.6", "prismarine-block": "^1.7.3", "prismarine-chunk": "^1.22.0", "prismarine-schematic": "^1.2.0", - "prismarine-viewer": "link:./", + "renderer": "link:./", "process": "^0.11.10", "socket.io": "^4.0.0", "socket.io-client": "^4.0.0", @@ -41,6 +36,10 @@ "vec3": "^0.1.7" }, "optionalDependencies": { + "canvas": "^2.11.2", "node-canvas-webgl": "^0.3.0" + }, + "devDependencies": { + "live-server": "^1.2.2" } } diff --git a/prismarine-viewer/playground.html b/renderer/playground.html similarity index 58% rename from prismarine-viewer/playground.html rename to renderer/playground.html index fd92009a..258426fe 100644 --- a/prismarine-viewer/playground.html +++ b/renderer/playground.html @@ -1,7 +1,7 @@ - Prismarine Viewer Playground + Renderer Playground + - +
diff --git a/renderer/playground/allEntitiesDebug.ts b/renderer/playground/allEntitiesDebug.ts new file mode 100644 index 00000000..5bc56ca6 --- /dev/null +++ b/renderer/playground/allEntitiesDebug.ts @@ -0,0 +1,170 @@ +import { EntityMesh, rendererSpecialHandled, EntityDebugFlags } from '../viewer/three/entity/EntityMesh' + +export const displayEntitiesDebugList = (version: string) => { + // Create results container + const container = document.createElement('div') + container.style.cssText = ` + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + max-height: 90vh; + overflow-y: auto; + background: rgba(0,0,0,0.8); + color: white; + padding: 20px; + border-radius: 8px; + font-family: monospace; + min-width: 400px; + z-index: 1000; + ` + document.body.appendChild(container) + + // Add title + const title = document.createElement('h2') + title.textContent = 'Minecraft Entity Support' + title.style.cssText = 'margin-top: 0; text-align: center;' + container.appendChild(title) + + // Test entities + const results: Array<{ + entity: string; + supported: boolean; + type?: 'obj' | 'bedrock' | 'special'; + mappedFrom?: string; + textureMap?: boolean; + errors?: string[]; + }> = [] + const { mcData } = window + const entityNames = Object.keys(mcData.entitiesArray.reduce((acc, entity) => { + acc[entity.name] = true + return acc + }, {})) + + // Add loading indicator + const loading = document.createElement('div') + loading.textContent = 'Testing entities...' + loading.style.textAlign = 'center' + container.appendChild(loading) + + for (const entity of entityNames) { + const debugFlags: EntityDebugFlags = {} + + if (rendererSpecialHandled.includes(entity)) { + results.push({ + entity, + supported: true, + type: 'special', + }) + continue + } + + try { + + const { mesh: entityMesh } = new EntityMesh(version, entity, undefined, {}, debugFlags) + // find the most distant pos child + window.objects ??= {} + window.objects[entity] = entityMesh + + results.push({ + entity, + supported: !!debugFlags.type || rendererSpecialHandled.includes(entity), + type: debugFlags.type, + mappedFrom: debugFlags.tempMap, + textureMap: debugFlags.textureMap, + errors: debugFlags.errors + }) + } catch (e) { + console.error(e) + results.push({ + entity, + supported: false, + mappedFrom: debugFlags.tempMap + }) + } + } + + // Remove loading indicator + loading.remove() + + const createSection = (title: string, items: any[], filter: (item: any) => boolean) => { + const section = document.createElement('div') + section.style.marginBottom = '20px' + + const sectionTitle = document.createElement('h3') + sectionTitle.textContent = title + sectionTitle.style.textAlign = 'center' + section.appendChild(sectionTitle) + + const list = document.createElement('ul') + list.style.cssText = 'padding-left: 20px; list-style-type: none; margin: 0;' + + const filteredItems = items.filter(filter) + for (const item of filteredItems) { + const listItem = document.createElement('li') + listItem.style.cssText = 'line-height: 1.4; margin: 8px 0;' + + const entityName = document.createElement('strong') + entityName.style.cssText = 'user-select: text;-webkit-user-select: text;' + entityName.textContent = item.entity + listItem.appendChild(entityName) + + let text = '' + if (item.mappedFrom) { + text += ` -> ${item.mappedFrom}` + } + if (item.type) { + text += ` - ${item.type}` + } + if (item.textureMap) { + text += ' ⚠️' + } + if (item.errors) { + text += ' ❌' + } + + listItem.appendChild(document.createTextNode(text)) + list.appendChild(listItem) + } + + section.appendChild(list) + return { section, count: filteredItems.length } + } + + // Sort results - bedrock first + results.sort((a, b) => { + if (a.type === 'bedrock' && b.type !== 'bedrock') return -1 + if (a.type !== 'bedrock' && b.type === 'bedrock') return 1 + return a.entity.localeCompare(b.entity) + }) + + // Add sections + const sections = [ + { + title: '❌ Unsupported Entities', + filter: (r: any) => !r.supported && !r.mappedFrom + }, + { + title: '⚠️ Partially Supported Entities', + filter: (r: any) => r.mappedFrom + }, + { + title: '✅ Supported Entities', + filter: (r: any) => r.supported && !r.mappedFrom + } + ] + + for (const { title, filter } of sections) { + const { section, count } = createSection(title, results, filter) + if (count > 0) { + container.appendChild(section) + } + } + + // log object with errors per entity + const errors = results.filter(r => r.errors).map(r => ({ + entity: r.entity, + errors: r.errors + })) + console.log(errors) +} diff --git a/renderer/playground/baseScene.ts b/renderer/playground/baseScene.ts new file mode 100644 index 00000000..b9e7791d --- /dev/null +++ b/renderer/playground/baseScene.ts @@ -0,0 +1,414 @@ +//@ts-nocheck +import { Vec3 } from 'vec3' +import * as THREE from 'three' +import '../../src/getCollisionShapes' +import { IndexedData } from 'minecraft-data' +import BlockLoader from 'prismarine-block' +import blockstatesModels from 'mc-assets/dist/blockStatesModels.json' +import ChunkLoader from 'prismarine-chunk' +import WorldLoader from 'prismarine-world' + +//@ts-expect-error +import { OrbitControls } from 'three/addons/controls/OrbitControls.js' +// eslint-disable-next-line import/no-named-as-default +import GUI from 'lil-gui' +import _ from 'lodash' +import { toMajorVersion } from '../../src/utils' +import { WorldDataEmitter } from '../viewer' +import { Viewer } from '../viewer/lib/viewer' +import { BlockNames } from '../../src/mcDataTypes' +import { initWithRenderer, statsEnd, statsStart } from '../../src/topRightStats' +import { defaultWorldRendererConfig } from '../viewer/lib/worldrendererCommon' +import { getSyncWorld } from './shared' + +window.THREE = THREE + +export class BasePlaygroundScene { + continuousRender = false + stopRender = false + guiParams = {} + viewDistance = 0 + targetPos = new Vec3(2, 90, 2) + params = {} as Record + paramOptions = {} as Partial> + version = new URLSearchParams(window.location.search).get('version') || globalThis.includedVersions.at(-1) + Chunk: typeof import('prismarine-chunk/types/index').PCChunk + Block: typeof import('prismarine-block').Block + ignoreResize = false + enableCameraControls = true // not finished + enableCameraOrbitControl = true + gui = new GUI() + onParamUpdate = {} as Record void> + alwaysIgnoreQs = [] as string[] + skipUpdateQs = false + controls: any + windowHidden = false + world: ReturnType + + _worldConfig = defaultWorldRendererConfig + get worldConfig () { + return this._worldConfig + } + set worldConfig (value) { + this._worldConfig = value + viewer.world.config = value + } + + constructor () { + void this.initData().then(() => { + this.addKeyboardShortcuts() + }) + } + + onParamsUpdate (paramName: string, object: any) {} + updateQs (paramName: string, valueSet: any) { + if (this.skipUpdateQs) return + const newQs = new URLSearchParams(window.location.search) + // if (oldQs.get('scene')) { + // newQs.set('scene', oldQs.get('scene')!) + // } + for (const [key, value] of Object.entries({ [paramName]: valueSet })) { + if (typeof value === 'function' || this.params.skipQs?.includes(key) || this.alwaysIgnoreQs.includes(key)) continue + if (value) { + newQs.set(key, value) + } else { + newQs.delete(key) + } + } + window.history.replaceState({}, '', `${window.location.pathname}?${newQs.toString()}`) + } + + // async initialSetup () {} + renderFinish () { + this.render() + } + + initGui () { + const qs = new URLSearchParams(window.location.search) + for (const key of Object.keys(this.params)) { + const value = qs.get(key) + if (!value) continue + const parsed = /^-?\d+$/.test(value) ? Number(value) : value === 'true' ? true : value === 'false' ? false : value + this.params[key] = parsed + } + + for (const param of Object.keys(this.params)) { + const option = this.paramOptions[param] + if (option?.hide) continue + this.gui.add(this.params, param, option?.options ?? option?.min, option?.max) + } + if (window.innerHeight < 700) { + this.gui.open(false) + } else { + // const observer = new MutationObserver(() => { + // this.gui.domElement.classList.remove('transition') + // }) + // observer.observe(this.gui.domElement, { + // attributes: true, + // attributeFilter: ['class'], + // }) + setTimeout(() => { + this.gui.domElement.classList.remove('transition') + }, 500) + } + + this.gui.onChange(({ property, object }) => { + if (object === this.params) { + this.onParamUpdate[property]?.() + this.onParamsUpdate(property, object) + const value = this.params[property] + if (this.paramOptions[property]?.reloadOnChange && (typeof value === 'boolean' || this.paramOptions[property].options)) { + setTimeout(() => { + window.location.reload() + }) + } + this.updateQs(property, value) + } else { + this.onParamsUpdate(property, object) + } + }) + } + + // mainChunk: import('prismarine-chunk/types/index').PCChunk + + // overridables + setupWorld () { } + sceneReset () {} + + // eslint-disable-next-line max-params + addWorldBlock (xOffset: number, yOffset: number, zOffset: number, blockName: BlockNames, properties?: Record) { + if (xOffset > 16 || yOffset > 16 || zOffset > 16) throw new Error('Offset too big') + const block = + properties ? + this.Block.fromProperties(loadedData.blocksByName[blockName].id, properties ?? {}, 0) : + this.Block.fromStateId(loadedData.blocksByName[blockName].defaultState, 0) + this.world.setBlock(this.targetPos.offset(xOffset, yOffset, zOffset), block) + } + + resetCamera () { + const { targetPos } = this + this.controls?.target.set(targetPos.x + 0.5, targetPos.y + 0.5, targetPos.z + 0.5) + + const cameraPos = targetPos.offset(2, 2, 2) + const pitch = THREE.MathUtils.degToRad(-45) + const yaw = THREE.MathUtils.degToRad(45) + viewer.camera.rotation.set(pitch, yaw, 0, 'ZYX') + viewer.camera.lookAt(targetPos.x + 0.5, targetPos.y + 0.5, targetPos.z + 0.5) + viewer.camera.position.set(cameraPos.x + 0.5, cameraPos.y + 0.5, cameraPos.z + 0.5) + this.controls?.update() + } + + async initData () { + await window._LOAD_MC_DATA() + const mcData: IndexedData = require('minecraft-data')(this.version) + window.loadedData = window.mcData = mcData + + this.Chunk = (ChunkLoader as any)(this.version) + this.Block = (BlockLoader as any)(this.version) + + const world = getSyncWorld(this.version) + world.setBlockStateId(this.targetPos, 0) + this.world = world + + this.initGui() + + const worldView = new WorldDataEmitter(world, this.viewDistance, this.targetPos) + worldView.addWaitTime = 0 + window.worldView = worldView + + // Create three.js context, add to page + const renderer = new THREE.WebGLRenderer({ alpha: true, ...localStorage['renderer'] }) + renderer.setPixelRatio(window.devicePixelRatio || 1) + renderer.setSize(window.innerWidth, window.innerHeight) + + // Create viewer + const viewer = new Viewer(renderer, this.worldConfig) + window.viewer = viewer + window.world = window.viewer.world + const isWebgpu = false + const promises = [] as Array> + if (isWebgpu) { + // promises.push(initWebgpuRenderer(() => { }, true, true)) // todo + } else { + initWithRenderer(renderer.domElement) + renderer.domElement.id = 'viewer-canvas' + document.body.appendChild(renderer.domElement) + } + viewer.addChunksBatchWaitTime = 0 + viewer.world.blockstatesModels = blockstatesModels + viewer.entities.setDebugMode('basic') + viewer.setVersion(this.version) + viewer.entities.onSkinUpdate = () => { + viewer.render() + } + viewer.world.mesherConfig.enableLighting = false + await Promise.all(promises) + this.setupWorld() + + viewer.connect(worldView) + + await worldView.init(this.targetPos) + + if (this.enableCameraControls) { + const { targetPos } = this + const canvas = document.querySelector('#viewer-canvas') + const controls = this.enableCameraOrbitControl ? new OrbitControls(viewer.camera, canvas) : undefined + this.controls = controls + + this.resetCamera() + + // #region camera rotation param + const cameraSet = this.params.camera || localStorage.camera + if (cameraSet) { + const [x, y, z, rx, ry] = cameraSet.split(',').map(Number) + viewer.camera.position.set(x, y, z) + viewer.camera.rotation.set(rx, ry, 0, 'ZYX') + this.controls?.update() + } + const throttledCamQsUpdate = _.throttle(() => { + const { camera } = viewer + // params.camera = `${camera.rotation.x.toFixed(2)},${camera.rotation.y.toFixed(2)}` + // this.updateQs() + localStorage.camera = [ + camera.position.x.toFixed(2), + camera.position.y.toFixed(2), + camera.position.z.toFixed(2), + camera.rotation.x.toFixed(2), + camera.rotation.y.toFixed(2), + ].join(',') + }, 200) + if (this.controls) { + this.controls.addEventListener('change', () => { + throttledCamQsUpdate() + this.render() + }) + } else { + setInterval(() => { + throttledCamQsUpdate() + }, 200) + } + // #endregion + } + + if (!this.enableCameraOrbitControl) { + // mouse + let mouseMoveCounter = 0 + const mouseMove = (e: PointerEvent) => { + if ((e.target as HTMLElement).closest('.lil-gui')) return + if (e.buttons === 1 || e.pointerType === 'touch') { + mouseMoveCounter++ + viewer.camera.rotation.x -= e.movementY / 100 + //viewer.camera. + viewer.camera.rotation.y -= e.movementX / 100 + if (viewer.camera.rotation.x < -Math.PI / 2) viewer.camera.rotation.x = -Math.PI / 2 + if (viewer.camera.rotation.x > Math.PI / 2) viewer.camera.rotation.x = Math.PI / 2 + + // yaw += e.movementY / 20; + // pitch += e.movementX / 20; + } + if (e.buttons === 2) { + viewer.camera.position.set(0, 0, 0) + } + } + setInterval(() => { + // updateTextEvent(`Mouse Events: ${mouseMoveCounter}`) + mouseMoveCounter = 0 + }, 1000) + window.addEventListener('pointermove', mouseMove) + } + + // await this.initialSetup() + this.onResize() + window.addEventListener('resize', () => this.onResize()) + void viewer.waitForChunksToRender().then(async () => { + this.renderFinish() + }) + + viewer.world.renderUpdateEmitter.addListener('update', () => { + this.render() + }) + + this.loop() + } + + loop () { + if (this.continuousRender && !this.windowHidden) { + this.render(true) + requestAnimationFrame(() => this.loop()) + } + } + + render (fromLoop = false) { + if (!fromLoop && this.continuousRender) return + if (this.stopRender) return + statsStart() + viewer.render() + statsEnd() + } + + addKeyboardShortcuts () { + document.addEventListener('keydown', (e) => { + if (!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) { + if (e.code === 'KeyR') { + this.controls?.reset() + this.resetCamera() + } + if (e.code === 'KeyE') { // refresh block (main) + worldView!.setBlockStateId(this.targetPos, this.world.getBlockStateId(this.targetPos)) + } + if (e.code === 'KeyF') { // reload all chunks + this.sceneReset() + worldView!.unloadAllChunks() + void worldView!.init(this.targetPos) + } + } + }) + document.addEventListener('visibilitychange', () => { + this.windowHidden = document.visibilityState === 'hidden' + }) + document.addEventListener('blur', () => { + this.windowHidden = true + }) + document.addEventListener('focus', () => { + this.windowHidden = false + }) + + const updateKeys = () => { + if (pressedKeys.has('ControlLeft') || pressedKeys.has('MetaLeft')) { + return + } + // if (typeof viewer === 'undefined') return + // Create a vector that points in the direction the camera is looking + const direction = new THREE.Vector3(0, 0, 0) + if (pressedKeys.has('KeyW')) { + direction.z = -0.5 + } + if (pressedKeys.has('KeyS')) { + direction.z += 0.5 + } + if (pressedKeys.has('KeyA')) { + direction.x -= 0.5 + } + if (pressedKeys.has('KeyD')) { + direction.x += 0.5 + } + + + if (pressedKeys.has('ShiftLeft')) { + viewer.camera.position.y -= 0.5 + } + if (pressedKeys.has('Space')) { + viewer.camera.position.y += 0.5 + } + direction.applyQuaternion(viewer.camera.quaternion) + direction.y = 0 + + if (pressedKeys.has('ShiftLeft')) { + direction.y *= 2 + direction.x *= 2 + direction.z *= 2 + } + // Add the vector to the camera's position to move the camera + viewer.camera.position.add(direction.normalize()) + this.controls?.update() + this.render() + } + setInterval(updateKeys, 1000 / 30) + + const pressedKeys = new Set() + const keys = (e) => { + const { code } = e + const pressed = e.type === 'keydown' + if (pressed) { + pressedKeys.add(code) + } else { + pressedKeys.delete(code) + } + } + + window.addEventListener('keydown', keys) + window.addEventListener('keyup', keys) + window.addEventListener('blur', (e) => { + for (const key of pressedKeys) { + keys(new KeyboardEvent('keyup', { code: key })) + } + }) + } + + onResize () { + if (this.ignoreResize) return + + const { camera, renderer } = viewer + viewer.camera.aspect = window.innerWidth / window.innerHeight + viewer.camera.updateProjectionMatrix() + renderer.setSize(window.innerWidth, window.innerHeight) + + this.render() + } +} diff --git a/renderer/playground/playground.ts b/renderer/playground/playground.ts new file mode 100644 index 00000000..de201d8f --- /dev/null +++ b/renderer/playground/playground.ts @@ -0,0 +1,12 @@ +if (!new URL(location.href).searchParams.get('playground')) location.href = '/?playground=true' +// import { BasePlaygroundScene } from './baseScene' +// import { playgroundGlobalUiState } from './playgroundUi' +// import * as scenes from './scenes' + +// const qsScene = new URLSearchParams(window.location.search).get('scene') +// const Scene: typeof BasePlaygroundScene = qsScene ? scenes[qsScene] : scenes.main +// playgroundGlobalUiState.scenes = ['main', 'railsCobweb', 'floorRandom', 'lightingStarfield', 'transparencyIssue', 'entities', 'frequentUpdates', 'slabsOptimization', 'allEntities'] +// playgroundGlobalUiState.selected = qsScene ?? 'main' + +// const scene = new Scene() +// globalThis.scene = scene diff --git a/renderer/playground/playgroundUi.tsx b/renderer/playground/playgroundUi.tsx new file mode 100644 index 00000000..ed183d78 --- /dev/null +++ b/renderer/playground/playgroundUi.tsx @@ -0,0 +1,175 @@ +import { renderToDom } from '@zardoy/react-util' +import { useEffect } from 'react' +import { proxy, useSnapshot } from 'valtio' +import { LeftTouchArea, RightTouchArea, useInterfaceState } from '@dimaka/interface' +import { css } from '@emotion/css' +import { Vec3 } from 'vec3' +import useLongPress from '../../src/react/useLongPress' +import { isMobile } from '../viewer/lib/simpleUtils' + +export const playgroundGlobalUiState = proxy({ + scenes: [] as string[], + selected: '', + selectorOpened: false, + actions: {} as Record void>, +}) + +renderToDom() + +function Playground () { + useEffect(() => { + const style = document.createElement('style') + style.innerHTML = /* css */ ` + .lil-gui { + top: 60px !important; + right: 0 !important; + } + ` + document.body.appendChild(style) + return () => { + style.remove() + } + }, []) + + return
+ + + +
+} + +function SceneSelector () { + const mobile = isMobile() + const { scenes, selected } = useSnapshot(playgroundGlobalUiState) + const longPressEvents = useLongPress(() => { + playgroundGlobalUiState.selectorOpened = true + }, () => { }) + + return
+ {scenes.map(scene =>
{ + const qs = new URLSearchParams(window.location.search) + qs.set('scene', scene) + location.search = qs.toString() + }} + >{scene}
)} +
+} + +const ActionsSelector = () => { + const { actions, selectorOpened } = useSnapshot(playgroundGlobalUiState) + + if (!selectorOpened) return null + return
{Object.entries({ + ...actions, + 'Close' () { + playgroundGlobalUiState.selectorOpened = false + } + }).map(([name, action]) =>
{ + action() + playgroundGlobalUiState.selectorOpened = false + }} + >{name}
)}
+} + +const Controls = () => { + // todo setting + const usingTouch = navigator.maxTouchPoints > 0 + + useEffect(() => { + window.addEventListener('touchstart', (e) => { + e.preventDefault() + }) + + const pressedKeys = new Set() + useInterfaceState.setState({ + isFlying: false, + uiCustomization: { + touchButtonSize: 40, + }, + updateCoord ([coord, state]) { + const vec3 = new Vec3(0, 0, 0) + vec3[coord] = state + let key: string | undefined + if (vec3.z < 0) key = 'KeyW' + if (vec3.z > 0) key = 'KeyS' + if (vec3.y > 0) key = 'Space' + if (vec3.y < 0) key = 'ShiftLeft' + if (vec3.x < 0) key = 'KeyA' + if (vec3.x > 0) key = 'KeyD' + if (key) { + if (!pressedKeys.has(key)) { + pressedKeys.add(key) + window.dispatchEvent(new KeyboardEvent('keydown', { code: key })) + } + } + for (const k of pressedKeys) { + if (k !== key) { + window.dispatchEvent(new KeyboardEvent('keyup', { code: k })) + pressedKeys.delete(k) + } + } + } + }) + }, []) + + if (!usingTouch) return null + return ( +
div { + pointer-events: auto; + } + `} + > + +
+ +
+ ) +} diff --git a/renderer/playground/scenes/allEntities.ts b/renderer/playground/scenes/allEntities.ts new file mode 100644 index 00000000..281af807 --- /dev/null +++ b/renderer/playground/scenes/allEntities.ts @@ -0,0 +1,13 @@ +import { BasePlaygroundScene } from '../baseScene' +import { EntityDebugFlags, EntityMesh, rendererSpecialHandled } from '../../viewer/three/entity/EntityMesh' +import { displayEntitiesDebugList } from '../allEntitiesDebug' + +export default class AllEntities extends BasePlaygroundScene { + continuousRender = false + enableCameraControls = false + + async initData () { + await super.initData() + displayEntitiesDebugList(this.version) + } +} diff --git a/renderer/playground/scenes/entities.ts b/renderer/playground/scenes/entities.ts new file mode 100644 index 00000000..5b5d0582 --- /dev/null +++ b/renderer/playground/scenes/entities.ts @@ -0,0 +1,37 @@ +//@ts-nocheck +import * as THREE from 'three' +import { Vec3 } from 'vec3' +import { BasePlaygroundScene } from '../baseScene' +import { WorldRendererThree } from '../../viewer/three/worldrendererThree' + +export default class extends BasePlaygroundScene { + continuousRender = true + + override initGui (): void { + this.params = { + starfield: false, + entity: 'player', + count: 4 + } + } + + override renderFinish (): void { + if (this.params.starfield) { + ;(viewer.world as WorldRendererThree).scene.background = new THREE.Color(0x00_00_00) + ;(viewer.world as WorldRendererThree).starField.enabled = true + ;(viewer.world as WorldRendererThree).starField.addToScene() + } + + for (let i = 0; i < this.params.count; i++) { + for (let j = 0; j < this.params.count; j++) { + for (let k = 0; k < this.params.count; k++) { + viewer.entities.update({ + id: i * 1000 + j * 100 + k, + name: this.params.entity, + pos: this.targetPos.offset(i, j, k) + } as any, {}) + } + } + } + } +} diff --git a/renderer/playground/scenes/floorRandom.ts b/renderer/playground/scenes/floorRandom.ts new file mode 100644 index 00000000..c6d2ccf1 --- /dev/null +++ b/renderer/playground/scenes/floorRandom.ts @@ -0,0 +1,33 @@ +import { BasePlaygroundScene } from '../baseScene' + +export default class RailsCobwebScene extends BasePlaygroundScene { + viewDistance = 5 + continuousRender = true + + override initGui (): void { + this.params = { + squareSize: 50 + } + + super.initGui() + } + + setupWorld () { + const squareSize = this.params.squareSize ?? 30 + const maxSquareSize = this.viewDistance * 16 * 2 + if (squareSize > maxSquareSize) throw new Error(`Square size too big, max is ${maxSquareSize}`) + // const fullBlocks = loadedData.blocksArray.map(x => x.name) + const fullBlocks = loadedData.blocksArray.filter(block => { + const b = this.Block.fromStateId(block.defaultState, 0) + if (b.shapes?.length !== 1) return false + const shape = b.shapes[0] + return shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1 + }) + for (let x = -squareSize; x <= squareSize; x++) { + for (let z = -squareSize; z <= squareSize; z++) { + const i = Math.abs(x + z) * squareSize + worldView!.world.setBlock(this.targetPos.offset(x, 0, z), this.Block.fromStateId(fullBlocks[i % fullBlocks.length].defaultState, 0)) + } + } + } +} diff --git a/renderer/playground/scenes/frequentUpdates.ts b/renderer/playground/scenes/frequentUpdates.ts new file mode 100644 index 00000000..caaf7207 --- /dev/null +++ b/renderer/playground/scenes/frequentUpdates.ts @@ -0,0 +1,148 @@ +//@ts-nocheck +import { Vec3 } from 'vec3' +import { BasePlaygroundScene } from '../baseScene' + +export default class extends BasePlaygroundScene { + viewDistance = 5 + continuousRender = true + + override initGui (): void { + this.params = { + testActive: false, + testUpdatesPerSecond: 10, + testInitialUpdate: false, + stopGeometryUpdate: false, + manualTest: () => { + this.updateBlock() + }, + testNeighborUpdates: () => { + this.testNeighborUpdates() + } + } + + super.initGui() + } + + lastUpdatedOffset = 0 + lastUpdatedId = 2 + updateBlock () { + const x = this.lastUpdatedOffset % 16 + const z = Math.floor(this.lastUpdatedOffset / 16) + const y = 90 + worldView!.setBlockStateId(new Vec3(x, y, z), this.lastUpdatedId++) + this.lastUpdatedOffset++ + if (this.lastUpdatedOffset > 16 * 16) this.lastUpdatedOffset = 0 + if (this.lastUpdatedId > 500) this.lastUpdatedId = 1 + } + + testNeighborUpdates () { + viewer.world.setBlockStateId(new Vec3(15, 95, 15), 1) + viewer.world.setBlockStateId(new Vec3(0, 95, 15), 1) + viewer.world.setBlockStateId(new Vec3(15, 95, 0), 1) + viewer.world.setBlockStateId(new Vec3(0, 95, 0), 1) + + viewer.world.setBlockStateId(new Vec3(16, 95, 15), 1) + viewer.world.setBlockStateId(new Vec3(-1, 95, 15), 1) + viewer.world.setBlockStateId(new Vec3(15, 95, -1), 1) + viewer.world.setBlockStateId(new Vec3(-1, 95, 0), 1) + setTimeout(() => { + viewer.world.setBlockStateId(new Vec3(16, 96, 16), 1) + viewer.world.setBlockStateId(new Vec3(-1, 96, 16), 1) + viewer.world.setBlockStateId(new Vec3(16, 96, -1), 1) + viewer.world.setBlockStateId(new Vec3(-1, 96, -1), 1) + }, 3000) + } + + setupTimer () { + // this.stopRender = true + + let lastTime = 0 + const tick = () => { + viewer.world.debugStopGeometryUpdate = this.params.stopGeometryUpdate + const updateEach = 1000 / this.params.testUpdatesPerSecond + requestAnimationFrame(tick) + if (!this.params.testActive) return + const updateCount = Math.floor(performance.now() - lastTime) / updateEach + for (let i = 0; i < updateCount; i++) { + this.updateBlock() + } + lastTime = performance.now() + } + + requestAnimationFrame(tick) + + // const limit = 1000 + // const limit = 100 + // const limit = 1 + // const updatedChunks = new Set() + // const updatedBlocks = new Set() + // let lastSecond = 0 + // setInterval(() => { + // const second = Math.floor(performance.now() / 1000) + // if (lastSecond !== second) { + // lastSecond = second + // updatedChunks.clear() + // updatedBlocks.clear() + // } + // const isEven = second % 2 === 0 + // if (updatedBlocks.size > limit) { + // return + // } + // const changeBlock = (x, z) => { + // const chunkKey = `${Math.floor(x / 16)},${Math.floor(z / 16)}` + // const key = `${x},${z}` + // if (updatedBlocks.has(chunkKey)) return + + // updatedChunks.add(chunkKey) + // worldView!.world.setBlock(this.targetPos.offset(x, 0, z), this.Block.fromStateId(isEven ? 2 : 3, 0)) + // updatedBlocks.add(key) + // } + // const { squareSize } = this.params + // const xStart = -squareSize + // const zStart = -squareSize + // const xEnd = squareSize + // const zEnd = squareSize + // for (let x = xStart; x <= xEnd; x += 16) { + // for (let z = zStart; z <= zEnd; z += 16) { + // const key = `${x},${z}` + // if (updatedChunks.has(key)) continue + // changeBlock(x, z) + // return + // } + // } + // for (let x = xStart; x <= xEnd; x += 16) { + // for (let z = zStart; z <= zEnd; z += 16) { + // const key = `${x},${z}` + // if (updatedChunks.has(key)) continue + // changeBlock(x, z) + // return + // } + // } + // }, 1) + } + + setupWorld () { + this.worldConfig.showChunkBorders = true + + const maxSquareRadius = this.viewDistance * 16 + // const fullBlocks = loadedData.blocksArray.map(x => x.name) + const squareSize = maxSquareRadius + for (let x = -squareSize; x <= squareSize; x++) { + for (let z = -squareSize; z <= squareSize; z++) { + const i = Math.abs(x + z) * squareSize + worldView!.world.setBlock(this.targetPos.offset(x, 0, z), this.Block.fromStateId(1, 0)) + } + } + let done = false + viewer.world.renderUpdateEmitter.on('update', () => { + if (!viewer.world.allChunksFinished || done) return + done = true + this.setupTimer() + }) + setTimeout(() => { + if (this.params.testInitialUpdate) { + this.updateBlock() + } + }) + } +} diff --git a/renderer/playground/scenes/index.ts b/renderer/playground/scenes/index.ts new file mode 100644 index 00000000..bf881812 --- /dev/null +++ b/renderer/playground/scenes/index.ts @@ -0,0 +1,11 @@ +// export { default as rotation } from './rotation' +export { default as main } from './main' +export { default as railsCobweb } from './railsCobweb' +export { default as floorRandom } from './floorRandom' +export { default as lightingStarfield } from './lightingStarfield' +export { default as transparencyIssue } from './transparencyIssue' +export { default as rotationIssue } from './rotationIssue' +export { default as entities } from './entities' +export { default as frequentUpdates } from './frequentUpdates' +export { default as slabsOptimization } from './slabsOptimization' +export { default as allEntities } from './allEntities' diff --git a/renderer/playground/scenes/lightingStarfield.ts b/renderer/playground/scenes/lightingStarfield.ts new file mode 100644 index 00000000..eec0a7d3 --- /dev/null +++ b/renderer/playground/scenes/lightingStarfield.ts @@ -0,0 +1,40 @@ +//@ts-nocheck +import * as THREE from 'three' +import { Vec3 } from 'vec3' +import { BasePlaygroundScene } from '../baseScene' +import { WorldRendererThree } from '../../viewer/three/worldrendererThree' + +export default class extends BasePlaygroundScene { + continuousRender = true + + override setupWorld (): void { + viewer.world.mesherConfig.enableLighting = true + viewer.world.mesherConfig.skyLight = 0 + this.addWorldBlock(0, 0, 0, 'stone') + this.addWorldBlock(0, 0, 1, 'stone') + this.addWorldBlock(1, 0, 0, 'stone') + this.addWorldBlock(1, 0, 1, 'stone') + // chess like + worldView?.world.setBlockLight(this.targetPos.offset(0, 1, 0), 15) + worldView?.world.setBlockLight(this.targetPos.offset(0, 1, 1), 0) + worldView?.world.setBlockLight(this.targetPos.offset(1, 1, 0), 0) + worldView?.world.setBlockLight(this.targetPos.offset(1, 1, 1), 15) + } + + override renderFinish (): void { + viewer.scene.background = new THREE.Color(0x00_00_00) + // starfield and test entities + ;(viewer.world as WorldRendererThree).starField.enabled = true + ;(viewer.world as WorldRendererThree).starField.addToScene() + viewer.entities.update({ + id: 0, + name: 'player', + pos: this.targetPos.clone() + } as any, {}) + viewer.entities.update({ + id: 1, + name: 'creeper', + pos: this.targetPos.offset(1, 0, 0) + } as any, {}) + } +} diff --git a/renderer/playground/scenes/main.ts b/renderer/playground/scenes/main.ts new file mode 100644 index 00000000..64925f61 --- /dev/null +++ b/renderer/playground/scenes/main.ts @@ -0,0 +1,314 @@ +//@ts-nocheck +// eslint-disable-next-line import/no-named-as-default +import GUI, { Controller } from 'lil-gui' +import * as THREE from 'three' +import JSZip from 'jszip' +import { BasePlaygroundScene } from '../baseScene' +import { TWEEN_DURATION } from '../../viewer/three/entities' +import { EntityMesh } from '../../viewer/three/entity/EntityMesh' + +class MainScene extends BasePlaygroundScene { + // eslint-disable-next-line @typescript-eslint/no-useless-constructor + constructor (...args) { + //@ts-expect-error + super(...args) + } + + override initGui (): void { + // initial values + this.params = { + version: globalThis.includedVersions.at(-1), + skipQs: '', + block: '', + metadata: 0, + supportBlock: false, + entity: '', + removeEntity () { + this.entity = '' + }, + entityRotate: false, + camera: '', + playSound () { }, + blockIsomorphicRenderBundle () { }, + modelVariant: 0 + } + this.metadataGui = this.gui.add(this.params, 'metadata') + this.paramOptions = { + version: { + options: globalThis.includedVersions, + hide: false + }, + block: { + options: mcData.blocksArray.map(b => b.name).sort((a, b) => a.localeCompare(b)) + }, + entity: { + options: mcData.entitiesArray.map(b => b.name).sort((a, b) => a.localeCompare(b)) + }, + camera: { + hide: true, + } + } + super.initGui() + } + + blockProps = {} + metadataFolder: GUI | undefined + metadataGui: Controller + + override onParamUpdate = { + version () { + // if (initialUpdate) return + // viewer.world.texturesVersion = params.version + // viewer.world.updateTexturesData() + // todo warning + }, + block: () => { + this.blockProps = {} + this.metadataFolder?.destroy() + const block = mcData.blocksByName[this.params.block] + if (!block) return + console.log('block', block.name) + const props = new this.Block(block.id, 0, 0).getProperties() + const { states } = mcData.blocksByStateId[this.getBlock()?.minStateId] ?? {} + this.metadataFolder = this.gui.addFolder('metadata') + if (states) { + for (const state of states) { + let defaultValue: string | number | boolean + if (state.values) { // int, enum + defaultValue = state.values[0] + } else { + switch (state.type) { + case 'bool': + defaultValue = false + break + case 'int': + defaultValue = 0 + break + case 'direction': + defaultValue = 'north' + break + + default: + continue + } + } + this.blockProps[state.name] = defaultValue + if (state.values) { + this.metadataFolder.add(this.blockProps, state.name, state.values) + } else { + this.metadataFolder.add(this.blockProps, state.name) + } + } + } else { + for (const [name, value] of Object.entries(props)) { + this.blockProps[name] = value + this.metadataFolder.add(this.blockProps, name) + } + } + console.log('props', this.blockProps) + this.metadataFolder.open() + }, + entity: () => { + this.continuousRender = this.params.entity === 'player' + this.entityUpdateShared() + if (!this.params.entity) return + if (this.params.entity === 'player') { + viewer.entities.updatePlayerSkin('id', viewer.entities.entities.id.username, undefined, true, true) + viewer.entities.playAnimation('id', 'running') + } + // let prev = false + // setInterval(() => { + // viewer.entities.playAnimation('id', prev ? 'running' : 'idle') + // prev = !prev + // }, 1000) + + EntityMesh.getStaticData(this.params.entity) + // entityRotationFolder.destroy() + // entityRotationFolder = gui.addFolder('entity metadata') + // entityRotationFolder.add(params, 'entityRotate') + // entityRotationFolder.open() + }, + supportBlock: () => { + viewer.setBlockStateId(this.targetPos.offset(0, -1, 0), this.params.supportBlock ? 1 : 0) + }, + modelVariant: () => { + viewer.world.mesherConfig.debugModelVariant = this.params.modelVariant === 0 ? undefined : [this.params.modelVariant] + } + } + + entityUpdateShared () { + viewer.entities.clear() + if (!this.params.entity) return + worldView!.emit('entity', { + id: 'id', name: this.params.entity, pos: this.targetPos.offset(0.5, 1, 0.5), width: 1, height: 1, username: localStorage.testUsername, yaw: Math.PI, pitch: 0 + }) + const enableSkeletonDebug = (obj) => { + const { children, isSkeletonHelper } = obj + if (!Array.isArray(children)) return + if (isSkeletonHelper) { + obj.visible = true + return + } + for (const child of children) { + if (typeof child === 'object') enableSkeletonDebug(child) + } + } + enableSkeletonDebug(viewer.entities.entities['id']) + setTimeout(() => { + viewer.render() + }, TWEEN_DURATION) + } + + blockIsomorphicRenderBundle () { + const { renderer } = viewer + + const canvas = renderer.domElement + const onlyCurrent = !confirm('Ok - render all blocks, Cancel - render only current one') + const sizeRaw = prompt('Size', '512') + if (!sizeRaw) return + const size = parseInt(sizeRaw, 10) + // const size = 512 + + this.ignoreResize = true + canvas.width = size + canvas.height = size + renderer.setSize(size, size) + + viewer.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 10) + viewer.scene.background = null + + const rad = THREE.MathUtils.degToRad(-120) + viewer.directionalLight.position.set( + Math.cos(rad), + Math.sin(rad), + 0.2 + ).normalize() + viewer.directionalLight.intensity = 1 + + const cameraPos = this.targetPos.offset(2, 2, 2) + const pitch = THREE.MathUtils.degToRad(-30) + const yaw = THREE.MathUtils.degToRad(45) + viewer.camera.rotation.set(pitch, yaw, 0, 'ZYX') + // viewer.camera.lookAt(center.x + 0.5, center.y + 0.5, center.z + 0.5) + viewer.camera.position.set(cameraPos.x + 1, cameraPos.y + 0.5, cameraPos.z + 1) + + const allBlocks = mcData.blocksArray.map(b => b.name) + // const allBlocks = ['stone', 'warped_slab'] + + let blockCount = 1 + let blockName = allBlocks[0] + + const updateBlock = () => { + // viewer.setBlockStateId(targetPos, mcData.blocksByName[blockName].minStateId) + this.params.block = blockName + // todo cleanup (introduce getDefaultState) + // TODO + // onUpdate.block() + // applyChanges(false, true) + } + void viewer.waitForChunksToRender().then(async () => { + // wait for next macro task + await new Promise(resolve => { + setTimeout(resolve, 0) + }) + if (onlyCurrent) { + viewer.render() + onWorldUpdate() + } else { + // will be called on every render update + viewer.world.renderUpdateEmitter.addListener('update', onWorldUpdate) + updateBlock() + } + }) + + const zip = new JSZip() + zip.file('description.txt', 'Generated with mcraft.fun/playground') + + const end = async () => { + // download zip file + + const a = document.createElement('a') + const blob = await zip.generateAsync({ type: 'blob' }) + const dataUrlZip = URL.createObjectURL(blob) + a.href = dataUrlZip + a.download = 'blocks_render.zip' + a.click() + URL.revokeObjectURL(dataUrlZip) + console.log('end') + + viewer.world.renderUpdateEmitter.removeListener('update', onWorldUpdate) + } + + async function onWorldUpdate () { + // await new Promise(resolve => { + // setTimeout(resolve, 50) + // }) + const dataUrl = canvas.toDataURL('image/png') + + zip.file(`${blockName}.png`, dataUrl.split(',')[1], { base64: true }) + + if (onlyCurrent) { + end() + } else { + nextBlock() + } + } + const nextBlock = async () => { + blockName = allBlocks[blockCount++] + console.log(allBlocks.length, '/', blockCount, blockName) + if (blockCount % 5 === 0) { + await new Promise(resolve => { + setTimeout(resolve, 100) + }) + } + if (blockName) { + updateBlock() + } else { + end() + } + } + } + + getBlock () { + return mcData.blocksByName[this.params.block || 'air'] + } + + // applyChanges (metadataUpdate = false, skipQs = false) { + override onParamsUpdate (paramName: string, object: any) { + const metadataUpdate = paramName === 'metadata' + + const blockId = this.getBlock()?.id + let block: import('prismarine-block').Block + if (metadataUpdate) { + block = new this.Block(blockId, 0, this.params.metadata) + Object.assign(this.blockProps, block.getProperties()) + for (const _child of this.metadataFolder!.children) { + const child = _child as import('lil-gui').Controller + child.updateDisplay() + } + } else { + try { + block = this.Block.fromProperties(blockId ?? -1, this.blockProps, 0) + } catch (err) { + console.error(err) + block = this.Block.fromStateId(0, 0) + } + } + + worldView!.setBlockStateId(this.targetPos, block.stateId ?? 0) + console.log('up stateId', block.stateId) + this.params.metadata = block.metadata + this.metadataGui.updateDisplay() + } + + override renderFinish () { + for (const update of Object.values(this.onParamUpdate)) { + // update(true) + update() + } + this.onParamsUpdate('', {}) + this.gui.openAnimated() + } +} + +export default MainScene diff --git a/renderer/playground/scenes/railsCobweb.ts b/renderer/playground/scenes/railsCobweb.ts new file mode 100644 index 00000000..bc1c271a --- /dev/null +++ b/renderer/playground/scenes/railsCobweb.ts @@ -0,0 +1,14 @@ +import { BasePlaygroundScene } from '../baseScene' + +export default class RailsCobwebScene extends BasePlaygroundScene { + setupWorld () { + this.addWorldBlock(0, 0, 0, 'cobweb') + this.addWorldBlock(0, -1, 0, 'cobweb') + this.addWorldBlock(1, -1, 0, 'cobweb') + this.addWorldBlock(1, 0, 0, 'cobweb') + + this.addWorldBlock(0, 0, 1, 'powered_rail', { shape: 'north_south', waterlogged: false }) + this.addWorldBlock(0, 0, 2, 'powered_rail', { shape: 'ascending_south', waterlogged: false }) + this.addWorldBlock(0, 1, 3, 'powered_rail', { shape: 'north_south', waterlogged: false }) + } +} diff --git a/renderer/playground/scenes/rotationIssue.ts b/renderer/playground/scenes/rotationIssue.ts new file mode 100644 index 00000000..2c56876a --- /dev/null +++ b/renderer/playground/scenes/rotationIssue.ts @@ -0,0 +1,7 @@ +import { BasePlaygroundScene } from '../baseScene' + +export default class RotationIssueScene extends BasePlaygroundScene { + setupWorld () { + // todo + } +} diff --git a/renderer/playground/scenes/slabsOptimization.ts b/renderer/playground/scenes/slabsOptimization.ts new file mode 100644 index 00000000..9035a777 --- /dev/null +++ b/renderer/playground/scenes/slabsOptimization.ts @@ -0,0 +1,15 @@ +import { BasePlaygroundScene } from '../baseScene' + +export default class extends BasePlaygroundScene { + expectedNumberOfFaces = 30 + + setupWorld () { + this.addWorldBlock(0, 1, 0, 'stone_slab') + this.addWorldBlock(0, 0, 0, 'stone') + this.addWorldBlock(0, -1, 0, 'stone_slab', { type: 'top', waterlogged: false }) + this.addWorldBlock(0, -1, -1, 'stone_slab', { type: 'top', waterlogged: false }) + this.addWorldBlock(0, -1, 1, 'stone_slab', { type: 'top', waterlogged: false }) + this.addWorldBlock(-1, -1, 0, 'stone_slab', { type: 'top', waterlogged: false }) + this.addWorldBlock(1, -1, 0, 'stone_slab', { type: 'top', waterlogged: false }) + } +} diff --git a/renderer/playground/scenes/transparencyIssue.ts b/renderer/playground/scenes/transparencyIssue.ts new file mode 100644 index 00000000..9ce1b967 --- /dev/null +++ b/renderer/playground/scenes/transparencyIssue.ts @@ -0,0 +1,11 @@ +import { BasePlaygroundScene } from '../baseScene' + +export default class extends BasePlaygroundScene { + setupWorld () { + this.addWorldBlock(0, 0, 0, 'water') + this.addWorldBlock(0, 1, 0, 'lime_stained_glass') + this.addWorldBlock(0, 0, -1, 'lime_stained_glass') + this.addWorldBlock(0, -1, 0, 'lime_stained_glass') + this.addWorldBlock(0, -1, -1, 'stone') + } +} diff --git a/renderer/playground/shared.ts b/renderer/playground/shared.ts new file mode 100644 index 00000000..9d12fae9 --- /dev/null +++ b/renderer/playground/shared.ts @@ -0,0 +1,79 @@ +import WorldLoader, { world } from 'prismarine-world' +import ChunkLoader from 'prismarine-chunk' + +export type BlockFaceType = { + side: number + textureIndex: number + tint?: [number, number, number] + isTransparent?: boolean + + // for testing + face?: string + neighbor?: string + light?: number +} + +export type BlockType = { + faces: BlockFaceType[] + + // for testing + block: string +} + +export const makeError = (str: string) => { + reportError?.(str) +} +export const makeErrorCritical = (str: string) => { + throw new Error(str) +} + +export const getSyncWorld = (version: string): world.WorldSync => { + const World = (WorldLoader as any)(version) + const Chunk = (ChunkLoader as any)(version) + + const world = new World(version).sync + + const methods = getAllMethods(world) + for (const method of methods) { + if (method.startsWith('set') && method !== 'setColumn') { + const oldMethod = world[method].bind(world) + world[method] = (...args) => { + const arg = args[0] + if (arg.x !== undefined && !world.getColumnAt(arg)) { + world.setColumn(Math.floor(arg.x / 16), Math.floor(arg.z / 16), new Chunk(undefined as any)) + } + oldMethod(...args) + } + } + } + + return world +} + +function getAllMethods (obj) { + const methods = new Set() + let currentObj = obj + + do { + for (const name of Object.getOwnPropertyNames(currentObj)) { + if (typeof obj[name] === 'function' && name !== 'constructor') { + methods.add(name) + } + } + } while ((currentObj = Object.getPrototypeOf(currentObj))) + + return [...methods] as string[] +} + +export const delayedIterator = async (arr: T[], delay: number, exec: (item: T, index: number) => Promise, chunkSize = 1) => { + // if delay is 0 then don't use setTimeout + for (let i = 0; i < arr.length; i += chunkSize) { + if (delay) { + // eslint-disable-next-line no-await-in-loop + await new Promise(resolve => { + setTimeout(resolve, delay) + }) + } + await exec(arr[i], i) + } +} diff --git a/renderer/rsbuild.config.ts b/renderer/rsbuild.config.ts new file mode 100644 index 00000000..2b40e79c --- /dev/null +++ b/renderer/rsbuild.config.ts @@ -0,0 +1,59 @@ +import { defineConfig, mergeRsbuildConfig, RsbuildPluginAPI } from '@rsbuild/core'; +import supportedVersions from '../src/supportedVersions.mjs' +import childProcess from 'child_process' +import path, { dirname, join } from 'path' +import { pluginReact } from '@rsbuild/plugin-react'; +import { pluginNodePolyfill } from '@rsbuild/plugin-node-polyfill'; +import fs from 'fs' +import fsExtra from 'fs-extra' +import { appAndRendererSharedConfig, rspackViewerConfig } from './rsbuildSharedConfig'; + +const mcDataPath = join(__dirname, '../generated/minecraft-data-optimized.json') + +// if (!fs.existsSync('./playground/textures')) { +// fsExtra.copySync('node_modules/mc-assets/dist/other-textures/latest/entity', './playground/textures/entity') +// } + +if (!fs.existsSync(mcDataPath)) { + childProcess.execSync('tsx ./scripts/makeOptimizedMcData.mjs', { stdio: 'inherit', cwd: path.join(__dirname, '..') }) +} + +export default mergeRsbuildConfig( + appAndRendererSharedConfig(), + defineConfig({ + html: { + template: join(__dirname, './playground.html'), + }, + output: { + cleanDistPath: false, + distPath: { + root: join(__dirname, './dist'), + }, + }, + server: { + port: 9090, + }, + source: { + entry: { + index: join(__dirname, './playground/playground.ts') + }, + define: { + 'globalThis.includedVersions': JSON.stringify(supportedVersions), + }, + }, + plugins: [ + { + name: 'test', + setup (build: RsbuildPluginAPI) { + const prep = async () => { + fsExtra.copySync(join(__dirname, '../node_modules/mc-assets/dist/other-textures/latest/entity'), join(__dirname, './dist/textures/entity')) + } + build.onBeforeBuild(async () => { + await prep() + }) + build.onBeforeStartDevServer(() => prep()) + }, + }, + ], + }) +) diff --git a/renderer/rsbuildSharedConfig.ts b/renderer/rsbuildSharedConfig.ts new file mode 100644 index 00000000..45da30b1 --- /dev/null +++ b/renderer/rsbuildSharedConfig.ts @@ -0,0 +1,124 @@ +import { defineConfig, ModifyRspackConfigUtils } from '@rsbuild/core'; +import { pluginNodePolyfill } from '@rsbuild/plugin-node-polyfill'; +import { pluginReact } from '@rsbuild/plugin-react'; +import path from 'path' +import fs from 'fs' + +export const appAndRendererSharedConfig = () => defineConfig({ + dev: { + progressBar: true, + writeToDisk: true, + watchFiles: { + paths: [ + path.join(__dirname, './dist/webgpuRendererWorker.js'), + path.join(__dirname, './dist/mesher.js'), + ] + }, + }, + output: { + polyfill: 'usage', + // 50kb limit for data uri + dataUriLimit: 50 * 1024, + assetPrefix: './', + }, + source: { + alias: { + fs: path.join(__dirname, `../src/shims/fs.js`), + http: 'http-browserify', + stream: 'stream-browserify', + net: 'net-browserify', + 'minecraft-protocol$': 'minecraft-protocol/src/index.js', + 'buffer$': 'buffer', + // avoid bundling, not used on client side + 'prismarine-auth': path.join(__dirname, `../src/shims/prismarineAuthReplacement.ts`), + perf_hooks: path.join(__dirname, `../src/shims/perf_hooks_replacement.js`), + crypto: path.join(__dirname, `../src/shims/crypto.js`), + dns: path.join(__dirname, `../src/shims/dns.js`), + yggdrasil: path.join(__dirname, `../src/shims/yggdrasilReplacement.ts`), + 'three$': 'three/src/Three.js', + 'stats.js$': 'stats.js/src/Stats.js', + }, + define: { + 'process.platform': '"browser"', + }, + decorators: { + version: 'legacy', // default is a lie + }, + }, + server: { + htmlFallback: false, + // publicDir: false, + headers: { + // enable shared array buffer + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp', + }, + open: process.env.OPEN_BROWSER === 'true', + }, + plugins: [ + pluginReact(), + pluginNodePolyfill() + ], + tools: { + rspack (config, helpers) { + const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8')) + const hasFileProtocol = Object.values(packageJson.pnpm.overrides).some((dep) => (dep as string).startsWith('file:')) + if (hasFileProtocol) { + // enable node_modules watching + config.watchOptions.ignored = /\.git/ + } + rspackViewerConfig(config, helpers) + } + }, +}) + +export const rspackViewerConfig = (config, { appendPlugins, addRules, rspack }: ModifyRspackConfigUtils) => { + appendPlugins(new rspack.NormalModuleReplacementPlugin(/data|prismarine-physics/, (resource) => { + let absolute: string + const request = resource.request.replaceAll('\\', '/') + absolute = path.join(resource.context, request).replaceAll('\\', '/') + if (request.includes('minecraft-data/data/pc/1.') || request.includes('prismarine-physics')) { + console.log('Error: incompatible resource', request, 'from', resource.contextInfo.issuer) + process.exit(1) + // throw new Error(`${resource.request} was requested by ${resource.contextInfo.issuer}`) + } + if (absolute.endsWith('/minecraft-data/data.js')) { + resource.request = path.join(__dirname, `../src/shims/minecraftData.ts`) + } + if (absolute.endsWith('/minecraft-data/data/bedrock/common/legacy.json')) { + resource.request = path.join(__dirname, `../src/shims/empty.ts`) + } + if (absolute.endsWith('/minecraft-data/data/pc/common/legacy.json')) { + resource.request = path.join(__dirname, `../src/preflatMap.json`) + } + })) + addRules([ + { + test: /\.obj$/, + type: 'asset/source', + }, + { + test: /\.wgsl$/, + type: 'asset/source', + }, + { + test: /\.mp3$/, + type: 'asset/source', + }, + { + test: /\.txt$/, + type: 'asset/source', + }, + { + test: /\.log$/, + type: 'asset/source', + } + ]) + config.ignoreWarnings = [ + /the request of a dependency is an expression/, + /Unsupported pseudo class or element: xr-overlay/ + ] + if (process.env.SINGLE_FILE_BUILD === 'true') { + config.module!.parser!.javascript!.dynamicImportMode = 'eager' + } +} diff --git a/prismarine-viewer/viewer/.gitignore b/renderer/viewer/.gitignore similarity index 100% rename from prismarine-viewer/viewer/.gitignore rename to renderer/viewer/.gitignore diff --git a/renderer/viewer/baseGraphicsBackend.ts b/renderer/viewer/baseGraphicsBackend.ts new file mode 100644 index 00000000..486c930f --- /dev/null +++ b/renderer/viewer/baseGraphicsBackend.ts @@ -0,0 +1,27 @@ +import { proxy } from 'valtio' +import { NonReactiveState, RendererReactiveState } from '../../src/appViewer' + +export const getDefaultRendererState = (): { + reactive: RendererReactiveState + nonReactive: NonReactiveState +} => { + return { + reactive: proxy({ + world: { + chunksLoaded: new Set(), + heightmaps: new Map(), + allChunksLoaded: true, + mesherWork: false, + intersectMedia: null + }, + renderer: '', + preventEscapeMenu: false + }), + nonReactive: { + world: { + chunksLoaded: new Set(), + chunksTotalNumber: 0, + } + } + } +} diff --git a/renderer/viewer/common/utils.ts b/renderer/viewer/common/utils.ts new file mode 100644 index 00000000..958273f3 --- /dev/null +++ b/renderer/viewer/common/utils.ts @@ -0,0 +1,18 @@ +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/renderer/viewer/lib/DebugGui.ts b/renderer/viewer/lib/DebugGui.ts new file mode 100644 index 00000000..f296c873 --- /dev/null +++ b/renderer/viewer/lib/DebugGui.ts @@ -0,0 +1,174 @@ +// eslint-disable-next-line import/no-named-as-default +import GUI from 'lil-gui' + +export interface ParamMeta { + min?: number + max?: number + step?: number +} + +export class DebugGui { + private gui: GUI + private readonly storageKey: string + private target: any + private readonly params: string[] + private readonly paramsMeta: Record + private _visible = false // Default to not visible + private readonly initialValues: Record = {} // Store initial values + private initialized = false + + constructor (id: string, target: any, params?: string[], paramsMeta?: Record) { + this.gui = new GUI() + this.storageKey = `debug_params_${id}` + this.target = target + this.paramsMeta = paramsMeta ?? {} + this.params = params ?? Object.keys(target) + + // Store initial values + for (const param of this.params) { + this.initialValues[param] = target[param] + } + + // Hide by default + this.gui.domElement.style.display = 'none' + } + + // Initialize and show the GUI + activate () { + if (!this.initialized) { + this.loadSavedValues() + this.setupControls() + this.initialized = true + } + this.show() + return this + } + + // Getter for visibility + get visible (): boolean { + return this._visible + } + + // Setter for visibility + set visible (value: boolean) { + this._visible = value + this.gui.domElement.style.display = value ? 'block' : 'none' + this.saveVisibility() + } + + private loadSavedValues () { + try { + const saved = localStorage.getItem(this.storageKey) + if (saved) { + const values = JSON.parse(saved) + // Apply saved values to target + for (const param of this.params) { + if (param in values) { + const value = values[param] + if (value !== null) { + this.target[param] = value + } + } + } + } + } catch (e) { + console.warn('Failed to load debug values:', e) + } + } + + private saveValues (deleteKey = false) { + try { + const values = {} + for (const param of this.params) { + values[param] = this.target[param] + } + if (deleteKey) { + localStorage.removeItem(this.storageKey) + } else { + localStorage.setItem(this.storageKey, JSON.stringify(values)) + } + } catch (e) { + console.warn('Failed to save debug values:', e) + } + } + + private saveVisibility () { + try { + localStorage.setItem(`${this.storageKey}_visible`, this._visible.toString()) + } catch (e) { + console.warn('Failed to save debug visibility:', e) + } + } + + private setupControls () { + // Add visibility toggle at the top + this.gui.add(this, 'visible').name('Show Controls') + this.gui.add({ resetAll: () => { + for (const param of this.params) { + this.target[param] = this.initialValues[param] + } + this.saveValues(true) + this.gui.destroy() + this.gui = new GUI() + this.setupControls() + } }, 'resetAll').name('Reset All Parameters') + + for (const param of this.params) { + const value = this.target[param] + const meta = this.paramsMeta[param] ?? {} + + if (typeof value === 'number') { + // For numbers, use meta values or calculate reasonable defaults + const min = meta.min ?? value - Math.abs(value * 2) + const max = meta.max ?? value + Math.abs(value * 2) + const step = meta.step ?? Math.abs(value) / 100 + + this.gui.add(this.target, param, min, max, step) + .onChange(() => this.saveValues()) + } else if (typeof value === 'boolean') { + // For booleans, create a checkbox + this.gui.add(this.target, param) + .onChange(() => this.saveValues()) + } else if (typeof value === 'string' && ['x', 'y', 'z'].includes(param)) { + // Special case for xyz coordinates + const min = meta.min ?? -10 + const max = meta.max ?? 10 + const step = meta.step ?? 0.1 + + this.gui.add(this.target, param, min, max, step) + .onChange(() => this.saveValues()) + } else if (Array.isArray(value)) { + // For arrays, create a dropdown + this.gui.add(this.target, param, value) + .onChange(() => this.saveValues()) + } + } + } + + // Method to manually trigger save + save () { + this.saveValues() + this.saveVisibility() + } + + // Method to destroy the GUI and clean up + destroy () { + this.saveVisibility() + this.gui.destroy() + } + + // Toggle visibility + toggle () { + this.visible = !this.visible + } + + // Show the GUI + show () { + this.visible = true + } + + // Hide the GUI + hide () { + this.visible = false + } +} diff --git a/renderer/viewer/lib/animationController.ts b/renderer/viewer/lib/animationController.ts new file mode 100644 index 00000000..329d0e24 --- /dev/null +++ b/renderer/viewer/lib/animationController.ts @@ -0,0 +1,85 @@ +import * as tweenJs from '@tweenjs/tween.js' + +export class AnimationController { + private currentAnimation: tweenJs.Group | null = null + private isAnimating = false + private cancelRequested = false + private completionCallbacks: Array<() => void> = [] + private currentCancelCallback: (() => void) | null = null + + /** Main method */ + async startAnimation (createAnimation: () => tweenJs.Group, onCancelled?: () => void): Promise { + if (this.isAnimating) { + await this.cancelCurrentAnimation() + } + + return new Promise((resolve) => { + this.isAnimating = true + this.cancelRequested = false + this.currentCancelCallback = onCancelled ?? null + this.currentAnimation = createAnimation() + + this.completionCallbacks.push(() => { + this.isAnimating = false + this.currentAnimation = null + resolve() + }) + }) + } + + /** Main method */ + async cancelCurrentAnimation (): Promise { + if (!this.isAnimating) return + + if (this.currentCancelCallback) { + const callback = this.currentCancelCallback + this.currentCancelCallback = null + callback() + } + + return new Promise((resolve) => { + this.cancelRequested = true + this.completionCallbacks.push(() => { + resolve() + }) + }) + } + + animationCycleFinish () { + if (this.cancelRequested) this.forceFinish() + } + + forceFinish (callComplete = true) { + if (!this.isAnimating) return + + if (this.currentAnimation) { + for (const tween of this.currentAnimation.getAll()) tween.stop() + this.currentAnimation.removeAll() + this.currentAnimation = null + } + + this.isAnimating = false + this.cancelRequested = false + + const callbacks = [...this.completionCallbacks] + this.completionCallbacks = [] + if (callComplete) { + for (const cb of callbacks) cb() + } + } + + /** Required method */ + update () { + if (this.currentAnimation) { + this.currentAnimation.update() + } + } + + get isActive () { + return this.isAnimating + } + + get shouldCancel () { + return this.cancelRequested + } +} diff --git a/renderer/viewer/lib/basePlayerState.ts b/renderer/viewer/lib/basePlayerState.ts new file mode 100644 index 00000000..9cf1350a --- /dev/null +++ b/renderer/viewer/lib/basePlayerState.ts @@ -0,0 +1,87 @@ +import { ItemSelector } from 'mc-assets/dist/itemDefinitions' +import { GameMode, Team } from 'mineflayer' +import { proxy } from 'valtio' +import type { HandItemBlock } from '../three/holdingBlock' + +export type MovementState = 'NOT_MOVING' | 'WALKING' | 'SPRINTING' | 'SNEAKING' +export type ItemSpecificContextProperties = Partial> +export type CameraPerspective = 'first_person' | 'third_person_back' | 'third_person_front' + +export type BlockShape = { position: any; width: any; height: any; depth: any; } +export type BlocksShapes = BlockShape[] + +// edit src/mineflayer/playerState.ts for implementation of player state from mineflayer +export const getInitialPlayerState = () => proxy({ + playerSkin: undefined as string | undefined, + inWater: false, + waterBreathing: false, + backgroundColor: [0, 0, 0] as [number, number, number], + ambientLight: 0, + directionalLight: 0, + eyeHeight: 0, + gameMode: undefined as GameMode | undefined, + lookingAtBlock: undefined as { + x: number + y: number + z: number + face?: number + shapes: BlocksShapes + } | undefined, + diggingBlock: undefined as { + x: number + y: number + z: number + stage: number + face?: number + mergedShape: BlockShape | undefined + } | undefined, + movementState: 'NOT_MOVING' as MovementState, + onGround: true, + sneaking: false, + flying: false, + sprinting: false, + itemUsageTicks: 0, + username: '', + onlineMode: false, + lightingDisabled: false, + shouldHideHand: false, + heldItemMain: undefined as HandItemBlock | undefined, + heldItemOff: undefined as HandItemBlock | undefined, + perspective: 'first_person' as CameraPerspective, + onFire: false, + + cameraSpectatingEntity: undefined as number | undefined, + + team: undefined as Team | undefined, +}) + +export const getPlayerStateUtils = (reactive: PlayerStateReactive) => ({ + isSpectator () { + return reactive.gameMode === 'spectator' + }, + isSpectatingEntity () { + return reactive.cameraSpectatingEntity !== undefined && reactive.gameMode === 'spectator' + }, + isThirdPerson () { + if ((this as PlayerStateUtils).isSpectatingEntity()) return false + return reactive.perspective === 'third_person_back' || reactive.perspective === 'third_person_front' + } +}) + +export const getInitialPlayerStateRenderer = () => ({ + reactive: getInitialPlayerState() +}) + +export type PlayerStateReactive = ReturnType +export type PlayerStateUtils = ReturnType + +export type PlayerStateRenderer = PlayerStateReactive + +export const getItemSelector = (playerState: PlayerStateRenderer, specificProperties: ItemSpecificContextProperties, item?: import('prismarine-item').Item) => { + return { + ...specificProperties, + 'minecraft:date': new Date(), + // "minecraft:context_dimension": bot.entityp, + // 'minecraft:time': bot.time.timeOfDay / 24_000, + } +} diff --git a/renderer/viewer/lib/cameraBobbing.ts b/renderer/viewer/lib/cameraBobbing.ts new file mode 100644 index 00000000..6bf32c76 --- /dev/null +++ b/renderer/viewer/lib/cameraBobbing.ts @@ -0,0 +1,94 @@ +export class CameraBobbing { + private walkDistance = 0 + private prevWalkDistance = 0 + private bobAmount = 0 + private prevBobAmount = 0 + private readonly gameTimer = new GameTimer() + + // eslint-disable-next-line max-params + constructor ( + private readonly BOB_FREQUENCY: number = Math.PI, // How fast the bob cycles + private readonly BOB_BASE_AMPLITUDE: number = 0.5, // Base amplitude of the bob + private readonly VERTICAL_MULTIPLIER: number = 1, // Vertical movement multiplier + private readonly ROTATION_MULTIPLIER_Z: number = 3, // Roll rotation multiplier + private readonly ROTATION_MULTIPLIER_X: number = 5 // Pitch rotation multiplier + ) {} + + // Call this when player is moving + public updateWalkDistance (distance: number): void { + this.prevWalkDistance = this.walkDistance + this.walkDistance = distance + } + + // Call this when player is moving to update bob amount + public updateBobAmount (isMoving: boolean): void { + const targetBob = isMoving ? 1 : 0 + this.prevBobAmount = this.bobAmount + + // Update timing + const ticks = this.gameTimer.update() + const deltaTime = ticks / 20 // Convert ticks to seconds assuming 20 TPS + + // Smooth transition for bob amount + const bobDelta = (targetBob - this.bobAmount) * Math.min(1, deltaTime * 10) + this.bobAmount += bobDelta + } + + // Call this in your render/animation loop + public getBobbing (): { position: { x: number, y: number }, rotation: { x: number, z: number } } { + // Interpolate walk distance + const walkDist = this.prevWalkDistance + + (this.walkDistance - this.prevWalkDistance) * this.gameTimer.partialTick + + // Interpolate bob amount + const bob = this.prevBobAmount + + (this.bobAmount - this.prevBobAmount) * this.gameTimer.partialTick + + // Calculate total distance for bob cycle + const totalDist = -(walkDist * this.BOB_FREQUENCY) + + // Calculate offsets + const xOffset = Math.sin(totalDist) * bob * this.BOB_BASE_AMPLITUDE + const yOffset = -Math.abs(Math.cos(totalDist) * bob) * this.VERTICAL_MULTIPLIER + + // Calculate rotations (in radians) + const zRot = (Math.sin(totalDist) * bob * this.ROTATION_MULTIPLIER_Z) * (Math.PI / 180) + const xRot = (Math.abs(Math.cos(totalDist - 0.2) * bob) * this.ROTATION_MULTIPLIER_X) * (Math.PI / 180) + + return { + position: { x: xOffset, y: yOffset }, + rotation: { x: xRot, z: zRot } + } + } +} + +class GameTimer { + private readonly msPerTick: number + private lastMs: number + public partialTick = 0 + + constructor (tickRate = 20) { + this.msPerTick = 1000 / tickRate + this.lastMs = performance.now() + } + + update (): number { + const currentMs = performance.now() + const deltaSinceLastTick = currentMs - this.lastMs + + // Calculate how much of a tick has passed + const tickDelta = deltaSinceLastTick / this.msPerTick + this.lastMs = currentMs + + // Add to accumulated partial ticks + this.partialTick += tickDelta + + // Get whole number of ticks that should occur + const wholeTicks = Math.floor(this.partialTick) + + // Keep the remainder as the new partial tick + this.partialTick -= wholeTicks + + return wholeTicks + } +} diff --git a/prismarine-viewer/viewer/lib/cleanupDecorator.ts b/renderer/viewer/lib/cleanupDecorator.ts similarity index 81% rename from prismarine-viewer/viewer/lib/cleanupDecorator.ts rename to renderer/viewer/lib/cleanupDecorator.ts index 476546a6..79b35828 100644 --- a/prismarine-viewer/viewer/lib/cleanupDecorator.ts +++ b/renderer/viewer/lib/cleanupDecorator.ts @@ -1,6 +1,6 @@ export function buildCleanupDecorator (cleanupMethod: string) { return function () { - return function (_target: {snapshotInitialValues}, propertyKey: string) { + return function (_target: { snapshotInitialValues }, propertyKey: string) { const target = _target as any // Store the initial value of the property if (!target._snapshotMethodPatched) { @@ -19,7 +19,8 @@ export function buildCleanupDecorator (cleanupMethod: string) { for (const key of target._toCleanup) { this[key] = this._initialValues[key] } - originalMethod.apply(this, arguments) + // eslint-disable-next-line prefer-rest-params + Reflect.apply(originalMethod, this, arguments) } } target._cleanupPatched = true diff --git a/renderer/viewer/lib/createPlayerObject.ts b/renderer/viewer/lib/createPlayerObject.ts new file mode 100644 index 00000000..836c8062 --- /dev/null +++ b/renderer/viewer/lib/createPlayerObject.ts @@ -0,0 +1,55 @@ +import { PlayerObject, PlayerAnimation } from 'skinview3d' +import * as THREE from 'three' +import { WalkingGeneralSwing } from '../three/entity/animations' +import { loadSkinImage, stevePngUrl } from './utils/skins' + +export type PlayerObjectType = PlayerObject & { + animation?: PlayerAnimation + realPlayerUuid: string + realUsername: string +} + +export function createPlayerObject (options: { + username?: string + uuid?: string + scale?: number +}): { + playerObject: PlayerObjectType + wrapper: THREE.Group + } { + const wrapper = new THREE.Group() + const playerObject = new PlayerObject() as PlayerObjectType + + playerObject.realPlayerUuid = options.uuid ?? '' + playerObject.realUsername = options.username ?? '' + playerObject.position.set(0, 16, 0) + + // fix issues with starfield + playerObject.traverse((obj) => { + if (obj instanceof THREE.Mesh && obj.material instanceof THREE.MeshStandardMaterial) { + obj.material.transparent = true + } + }) + + wrapper.add(playerObject as any) + const scale = options.scale ?? (1 / 16) + wrapper.scale.set(scale, scale, scale) + wrapper.rotation.set(0, Math.PI, 0) + + // Set up animation + playerObject.animation = new WalkingGeneralSwing() + ;(playerObject.animation as WalkingGeneralSwing).isMoving = false + playerObject.animation.update(playerObject, 0) + + return { playerObject, wrapper } +} + +export const applySkinToPlayerObject = async (playerObject: PlayerObjectType, skinUrl: string) => { + return loadSkinImage(skinUrl || stevePngUrl).then(({ canvas }) => { + const skinTexture = new THREE.CanvasTexture(canvas) + skinTexture.magFilter = THREE.NearestFilter + skinTexture.minFilter = THREE.NearestFilter + skinTexture.needsUpdate = true + playerObject.skin.map = skinTexture as any + }).catch(console.error) +} diff --git a/renderer/viewer/lib/guiRenderer.ts b/renderer/viewer/lib/guiRenderer.ts new file mode 100644 index 00000000..709941dc --- /dev/null +++ b/renderer/viewer/lib/guiRenderer.ts @@ -0,0 +1,282 @@ +// Import placeholders - replace with actual imports for your environment +import { ItemRenderer, Identifier, ItemStack, NbtString, Structure, StructureRenderer, ItemRendererResources, BlockDefinition, BlockModel, TextureAtlas, Resources, ItemModel } from 'deepslate' +import { mat4, vec3 } from 'gl-matrix' +import { AssetsParser } from 'mc-assets/dist/assetsParser' +import { getLoadedImage, versionToNumber } from 'mc-assets/dist/utils' +import { BlockModel as BlockModelMcAssets, AtlasParser } from 'mc-assets' +import { getLoadedBlockstatesStore, getLoadedModelsStore } from 'mc-assets/dist/stores' +import { makeTextureAtlas } from 'mc-assets/dist/atlasCreator' +import { proxy, ref } from 'valtio' +import { getItemDefinition } from 'mc-assets/dist/itemDefinitions' + +export const getNonFullBlocksModels = () => { + let version = appViewer.resourcesManager.currentResources!.version ?? 'latest' + if (versionToNumber(version) < versionToNumber('1.13')) version = '1.13' + const itemsDefinitions = appViewer.resourcesManager.itemsDefinitionsStore.data.latest + const blockModelsResolved = {} as Record + const itemsModelsResolved = {} as Record + const fullBlocksWithNonStandardDisplay = [] as string[] + const handledItemsWithDefinitions = new Set() + const assetsParser = new AssetsParser(version, getLoadedBlockstatesStore(appViewer.resourcesManager.currentResources!.blockstatesModels), getLoadedModelsStore(appViewer.resourcesManager.currentResources!.blockstatesModels)) + + const standardGuiDisplay = { + 'rotation': [ + 30, + 225, + 0 + ], + 'translation': [ + 0, + 0, + 0 + ], + 'scale': [ + 0.625, + 0.625, + 0.625 + ] + } + + const arrEqual = (a: number[], b: number[]) => a.length === b.length && a.every((x, i) => x === b[i]) + const addModelIfNotFullblock = (name: string, model: BlockModelMcAssets) => { + if (blockModelsResolved[name]) return + if (!model?.elements?.length) return + const isFullBlock = model.elements.length === 1 && arrEqual(model.elements[0].from, [0, 0, 0]) && arrEqual(model.elements[0].to, [16, 16, 16]) + if (isFullBlock) return + const hasBetterPrerender = assetsParser.blockModelsStore.data.latest[`item/${name}`]?.textures?.['layer0']?.startsWith('invsprite_') + if (hasBetterPrerender) return + model['display'] ??= {} + model['display']['gui'] ??= standardGuiDisplay + blockModelsResolved[name] = model + } + + for (const [name, definition] of Object.entries(itemsDefinitions)) { + const item = getItemDefinition(appViewer.resourcesManager.itemsDefinitionsStore, { + version, + name, + properties: { + 'minecraft:display_context': 'gui', + }, + }) + if (item) { + const { resolvedModel } = assetsParser.getResolvedModelsByModel((item.special ? name : item.model).replace('minecraft:', '')) ?? {} + if (resolvedModel) { + handledItemsWithDefinitions.add(name) + } + if (resolvedModel?.elements) { + let hasStandardDisplay = true + if (resolvedModel['display']?.gui) { + hasStandardDisplay = + arrEqual(resolvedModel['display'].gui.rotation, standardGuiDisplay.rotation) + && arrEqual(resolvedModel['display'].gui.translation, standardGuiDisplay.translation) + && arrEqual(resolvedModel['display'].gui.scale, standardGuiDisplay.scale) + } + + addModelIfNotFullblock(name, resolvedModel) + + if (!blockModelsResolved[name] && !hasStandardDisplay) { + fullBlocksWithNonStandardDisplay.push(name) + } + const notSideLight = resolvedModel['gui_light'] && resolvedModel['gui_light'] !== 'side' + if (!hasStandardDisplay || notSideLight) { + blockModelsResolved[name] = resolvedModel + } + } + if (!blockModelsResolved[name] && item.tints && resolvedModel) { + resolvedModel['tints'] = item.tints + if (resolvedModel.elements) { + blockModelsResolved[name] = resolvedModel + } else { + itemsModelsResolved[name] = resolvedModel + } + } + } + } + + for (const [name, blockstate] of Object.entries(appViewer.resourcesManager.currentResources!.blockstatesModels.blockstates.latest)) { + if (handledItemsWithDefinitions.has(name)) { + continue + } + const resolvedModel = assetsParser.getResolvedModelFirst({ name: name.replace('minecraft:', ''), properties: {} }, true) + if (resolvedModel) { + addModelIfNotFullblock(name, resolvedModel[0]) + } + } + + return { + blockModelsResolved, + itemsModelsResolved + } +} + +// customEvents.on('gameLoaded', () => { +// const res = getNonFullBlocksModels() +// }) + +const RENDER_SIZE = 64 + +const generateItemsGui = async (models: Record, isItems = false) => { + const { currentResources } = appViewer.resourcesManager + const imgBitmap = isItems ? currentResources!.itemsAtlasImage : currentResources!.blocksAtlasImage + const canvasTemp = document.createElement('canvas') + canvasTemp.width = imgBitmap.width + canvasTemp.height = imgBitmap.height + canvasTemp.style.imageRendering = 'pixelated' + const ctx = canvasTemp.getContext('2d')! + ctx.imageSmoothingEnabled = false + ctx.drawImage(imgBitmap, 0, 0) + + const atlasParser = isItems ? appViewer.resourcesManager.itemsAtlasParser : appViewer.resourcesManager.blocksAtlasParser + const textureAtlas = new TextureAtlas( + ctx.getImageData(0, 0, imgBitmap.width, imgBitmap.height), + Object.fromEntries(Object.entries(atlasParser.atlas.latest.textures).map(([key, value]) => { + return [key, [ + value.u, + value.v, + (value.u + (value.su ?? atlasParser.atlas.latest.suSv)), + (value.v + (value.sv ?? atlasParser.atlas.latest.suSv)), + ]] as [string, [number, number, number, number]] + })) + ) + + const PREVIEW_ID = Identifier.parse('preview:preview') + const PREVIEW_DEFINITION = new BlockDefinition({ '': { model: PREVIEW_ID.toString() } }, undefined) + + let textureWasRequested = false + let modelData: any + let currentModelName: string | undefined + const resources: ItemRendererResources = { + getBlockModel (id) { + if (id.equals(PREVIEW_ID)) { + return BlockModel.fromJson(modelData ?? {}) + } + return null + }, + getTextureUV (texture) { + textureWasRequested = true + return textureAtlas.getTextureUV(texture.toString().replace('minecraft:', '').replace('block/', '').replace('item/', '').replace('blocks/', '').replace('items/', '') as any) + }, + getTextureAtlas () { + return textureAtlas.getTextureAtlas() + }, + getItemComponents (id) { + return new Map() + }, + getItemModel (id) { + // const isSpecial = currentModelName === 'shield' || currentModelName === 'conduit' || currentModelName === 'trident' + const isSpecial = false + if (id.equals(PREVIEW_ID)) { + return ItemModel.fromJson({ + type: isSpecial ? 'minecraft:special' : 'minecraft:model', + model: isSpecial ? { + type: currentModelName, + } : PREVIEW_ID.toString(), + base: PREVIEW_ID.toString(), + tints: modelData?.tints, + }) + } + return null + }, + } + + const canvas = document.createElement('canvas') + canvas.width = RENDER_SIZE + canvas.height = RENDER_SIZE + const gl = canvas.getContext('webgl2', { preserveDrawingBuffer: true }) + if (!gl) { + throw new Error('Cannot get WebGL2 context') + } + + function resetGLContext (gl) { + gl.clearColor(0, 0, 0, 0) + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT) + } + + // const includeOnly = ['powered_repeater', 'wooden_door'] + const includeOnly = [] as string[] + + const images: Record = {} + const item = new ItemStack(PREVIEW_ID, 1, new Map(Object.entries({ + 'minecraft:item_model': new NbtString(PREVIEW_ID.toString()), + }))) + const renderer = new ItemRenderer(gl, item, resources, { display_context: 'gui' }) + const missingTextures = new Set() + for (const [modelName, model] of Object.entries(models)) { + textureWasRequested = false + if (includeOnly.length && !includeOnly.includes(modelName)) continue + + const patchMissingTextures = () => { + for (const element of model.elements ?? []) { + for (const [faceName, face] of Object.entries(element.faces)) { + if (face.texture.startsWith('#')) { + missingTextures.add(`${modelName} ${faceName}: ${face.texture}`) + face.texture = 'block/unknown' + } + } + } + } + patchMissingTextures() + // TODO eggs + + modelData = model + currentModelName = modelName + resetGLContext(gl) + if (!modelData) continue + renderer.setItem(item, { display_context: 'gui' }) + renderer.drawItem() + if (!textureWasRequested) continue + const url = canvas.toDataURL() + // eslint-disable-next-line no-await-in-loop + const img = await getLoadedImage(url) + images[modelName] = img + } + + if (missingTextures.size) { + console.warn(`[guiRenderer] Missing textures in ${[...missingTextures].join(', ')}`) + } + + return images +} + +/** + * @mainThread + */ +const generateAtlas = async (images: Record) => { + const atlas = makeTextureAtlas({ + input: Object.keys(images), + tileSize: RENDER_SIZE, + getLoadedImage (name) { + return { + image: images[name], + } + }, + }) + + // const atlasParser = new AtlasParser({ latest: atlas.json }, atlas.canvas.toDataURL()) + // const a = document.createElement('a') + // a.href = await atlasParser.createDebugImage(true) + // a.download = 'blocks_atlas.png' + // a.click() + + appViewer.resourcesManager.currentResources!.guiAtlas = { + json: atlas.json, + image: await createImageBitmap(atlas.canvas), + } + + return atlas +} + +export const generateGuiAtlas = async () => { + const { blockModelsResolved, itemsModelsResolved } = getNonFullBlocksModels() + + // Generate blocks atlas + console.time('generate blocks gui atlas') + const blockImages = await generateItemsGui(blockModelsResolved, false) + console.timeEnd('generate blocks gui atlas') + console.time('generate items gui atlas') + const itemImages = await generateItemsGui(itemsModelsResolved, true) + console.timeEnd('generate items gui atlas') + await generateAtlas({ ...blockImages, ...itemImages }) + appViewer.resourcesManager.currentResources!.guiAtlasVersion++ + // await generateAtlas(blockImages) +} diff --git a/renderer/viewer/lib/mesher/mesher.ts b/renderer/viewer/lib/mesher/mesher.ts new file mode 100644 index 00000000..a063d77f --- /dev/null +++ b/renderer/viewer/lib/mesher/mesher.ts @@ -0,0 +1,239 @@ +import { Vec3 } from 'vec3' +import { World } from './world' +import { getSectionGeometry, setBlockStatesData as setMesherData } from './models' +import { BlockStateModelInfo } from './shared' +import { INVISIBLE_BLOCKS } from './worldConstants' + +globalThis.structuredClone ??= (value) => JSON.parse(JSON.stringify(value)) + +if (module.require) { + // If we are in a node environement, we need to fake some env variables + const r = module.require + const { parentPort } = r('worker_threads') + global.self = parentPort + global.postMessage = (value, transferList) => { parentPort.postMessage(value, transferList) } + global.performance = r('perf_hooks').performance +} + +let workerIndex = 0 +let world: World +let dirtySections = new Map() +let allDataReady = false + +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 + const z = Math.floor(pos.z / 16) * 16 + const key = sectionKey(x, y, z) + if (!value) { + dirtySections.delete(key) + postMessage({ type: 'sectionFinished', key, workerIndex }) + return + } + + const chunk = world.getColumn(x, z) + if (chunk?.getSection(pos)) { + dirtySections.set(key, (dirtySections.get(key) || 0) + 1) + } else { + postMessage({ type: 'sectionFinished', key, workerIndex }) + } +} + +const softCleanup = () => { + // clean block cache and loaded chunks + world = new World(world.config.version) + globalThis.world = world +} + +const handleMessage = data => { + const globalVar: any = globalThis + + if (data.type === 'mcData') { + globalVar.mcData = data.mcData + globalVar.loadedData = data.mcData + } + + if (data.config) { + if (data.type === 'mesherData' && world) { + // reset models + world.blockCache = {} + world.erroredBlockModel = undefined + } + + world ??= new World(data.config.version) + world.config = { ...world.config, ...data.config } + globalThis.world = world + globalThis.Vec3 = Vec3 + } + + switch (data.type) { + case 'mesherData': { + setMesherData(data.blockstatesModels, data.blocksAtlas, data.config.outputFormat === 'webgpu') + allDataReady = true + workerIndex = data.workerIndex + + break + } + case 'dirty': { + const loc = new Vec3(data.x, data.y, data.z) + setSectionDirty(loc, data.value) + + break + } + case 'chunk': { + world.addColumn(data.x, data.z, data.chunk) + if (data.customBlockModels) { + const chunkKey = `${data.x},${data.z}` + world.customBlockModels.set(chunkKey, data.customBlockModels) + } + break + } + case 'unloadChunk': { + world.removeColumn(data.x, data.z) + world.customBlockModels.delete(`${data.x},${data.z}`) + if (Object.keys(world.columns).length === 0) softCleanup() + break + } + case 'blockUpdate': { + const loc = new Vec3(data.pos.x, data.pos.y, data.pos.z).floored() + if (data.stateId !== undefined && data.stateId !== null) { + world?.setBlockStateId(loc, data.stateId) + } + + const chunkKey = `${Math.floor(loc.x / 16) * 16},${Math.floor(loc.z / 16) * 16}` + if (data.customBlockModels) { + world?.customBlockModels.set(chunkKey, data.customBlockModels) + } + break + } + case 'reset': { + world = undefined as any + // blocksStates = null + dirtySections = new Map() + // todo also remove cached + globalVar.mcData = null + globalVar.loadedData = null + allDataReady = false + + break + } + case 'getCustomBlockModel': { + const pos = new Vec3(data.pos.x, data.pos.y, data.pos.z) + const chunkKey = `${Math.floor(pos.x / 16) * 16},${Math.floor(pos.z / 16) * 16}` + const customBlockModel = world.customBlockModels.get(chunkKey)?.[`${pos.x},${pos.y},${pos.z}`] + global.postMessage({ type: 'customBlockModel', chunkKey, customBlockModel }) + break + } + case 'getHeightmap': { + const heightmap = new Uint8Array(256) + + const blockPos = new Vec3(0, 0, 0) + for (let z = 0; z < 16; z++) { + for (let x = 0; x < 16; x++) { + const blockX = x + data.x + const blockZ = z + data.z + blockPos.x = blockX + blockPos.z = blockZ + blockPos.y = world.config.worldMaxY + let block = world.getBlock(blockPos) + while (block && INVISIBLE_BLOCKS.has(block.name) && blockPos.y > world.config.worldMinY) { + blockPos.y -= 1 + block = world.getBlock(blockPos) + } + const index = z * 16 + x + heightmap[index] = block ? blockPos.y : 0 + } + } + postMessage({ type: 'heightmap', key: `${Math.floor(data.x / 16)},${Math.floor(data.z / 16)}`, heightmap }) + + break + } + // No default + } +} + +// eslint-disable-next-line no-restricted-globals -- TODO +self.onmessage = ({ data }) => { + if (Array.isArray(data)) { + // eslint-disable-next-line unicorn/no-array-for-each + data.forEach(handleMessage) + return + } + + handleMessage(data) +} + +setInterval(() => { + if (world === null || !allDataReady) return + + if (dirtySections.size === 0) return + // console.log(sections.length + ' dirty sections') + + // const start = performance.now() + for (const key of dirtySections.keys()) { + const [x, y, z] = key.split(',').map(v => parseInt(v, 10)) + const chunk = world.getColumn(x, z) + let processTime = 0 + if (chunk?.getSection(new Vec3(x, y, z))) { + const start = performance.now() + const geometry = getSectionGeometry(x, y, z, world) + const transferable = [geometry.positions?.buffer, geometry.normals?.buffer, geometry.colors?.buffer, geometry.uvs?.buffer].filter(Boolean) + //@ts-expect-error + postMessage({ type: 'geometry', key, geometry, workerIndex }, transferable) + processTime = performance.now() - start + } else { + // console.info('[mesher] Missing section', x, y, z) + } + const dirtyTimes = dirtySections.get(key) + if (!dirtyTimes) throw new Error('dirtySections.get(key) is falsy') + for (let i = 0; i < dirtyTimes; i++) { + postMessage({ type: 'sectionFinished', key, workerIndex, processTime }) + processTime = 0 + } + dirtySections.delete(key) + } + + // Send new block state model info if any + if (world.blockStateModelInfo.size > 0) { + const newBlockStateInfo: Record = {} + for (const [cacheKey, info] of world.blockStateModelInfo) { + if (!world.sentBlockStateModels.has(cacheKey)) { + newBlockStateInfo[cacheKey] = info + world.sentBlockStateModels.add(cacheKey) + } + } + if (Object.keys(newBlockStateInfo).length > 0) { + postMessage({ type: 'blockStateModelInfo', info: newBlockStateInfo }) + } + } + + // const time = performance.now() - start + // console.log(`Processed ${sections.length} sections in ${time} ms (${time / sections.length} ms/section)`) +}, 50) diff --git a/renderer/viewer/lib/mesher/models.ts b/renderer/viewer/lib/mesher/models.ts new file mode 100644 index 00000000..aca47e15 --- /dev/null +++ b/renderer/viewer/lib/mesher/models.ts @@ -0,0 +1,745 @@ +import { Vec3 } from 'vec3' +import worldBlockProvider, { WorldBlockProvider } from 'mc-assets/dist/worldBlockProvider' +import legacyJson from '../../../../src/preflatMap.json' +import { BlockType } from '../../../playground/shared' +import { World, BlockModelPartsResolved, WorldBlock as Block, WorldBlock } from './world' +import { BlockElement, buildRotationMatrix, elemFaces, matmul3, matmulmat3, vecadd3, vecsub3 } from './modelsGeometryCommon' +import { INVISIBLE_BLOCKS } from './worldConstants' +import { MesherGeometryOutput, HighestBlockInfo } from './shared' + + +let blockProvider: WorldBlockProvider + +const tints: any = {} +let needTiles = false + +let tintsData +try { + tintsData = require('esbuild-data').tints +} catch (err) { + tintsData = require('minecraft-data/minecraft-data/data/pc/1.16.2/tints.json') +} +for (const key of Object.keys(tintsData)) { + tints[key] = prepareTints(tintsData[key]) +} + +type Tiles = { + [blockPos: string]: BlockType +} + +function prepareTints (tints) { + const map = new Map() + const defaultValue = tintToGl(tints.default) + for (let { keys, color } of tints.data) { + color = tintToGl(color) + for (const key of keys) { + map.set(`${key}`, color) + } + } + return new Proxy(map, { + get (target, key) { + return target.has(key) ? target.get(key) : defaultValue + } + }) +} + +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 = {} + let changed = false + 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' + changed = true + } + } + return changed ? props : undefined + } + // case 'gate_in_wall': {} + case 'block_snowy': { + const aboveIsSnow = world.getBlock(position.offset(0, 1, 0))?.name === 'snow' + if (aboveIsSnow) { + return { + snowy: `${aboveIsSnow}` + } + } else { + return + } + } + case 'door': { + // upper half matches lower in + const { half } = block.getProperties() + 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 + const b = tint & 0xff + return [r / 255, g / 255, b / 255] +} + +function getLiquidRenderHeight (world: World, block: WorldBlock | null, type: number, pos: Vec3, isWater: boolean, isRealWater: boolean) { + if ((isWater && !isRealWater) || (block && isBlockWaterlogged(block))) return 8 / 9 + if (!block || block.type !== type) return 1 / 9 + if (block.metadata === 0) { // source block + const blockAbove = world.getBlock(pos.offset(0, 1, 0)) + if (blockAbove && blockAbove.type === type) return 1 + return 8 / 9 + } + return ((block.metadata >= 8 ? 8 : 7 - block.metadata) + 1) / 9 +} + + +const isCube = (block: Block) => { + if (!block || block.transparent) return false + if (block.isCube) return true + if (!block.models?.length || block.models.length !== 1) return false + // all variants + return block.models[0].every(v => v.elements.every(e => { + return e.from[0] === 0 && e.from[1] === 0 && e.from[2] === 0 && e.to[0] === 16 && e.to[1] === 16 && e.to[2] === 16 + })) +} + +const getVec = (v: Vec3, dir: Vec3) => { + for (const coord of ['x', 'y', 'z']) { + if (Math.abs(dir[coord]) > 0) v[coord] = 0 + } + return v.plus(dir) +} + +function renderLiquid (world: World, cursor: Vec3, texture: any | undefined, type: number, biome: string, water: boolean, attr: MesherGeometryOutput, isRealWater: boolean) { + const heights: number[] = [] + for (let z = -1; z <= 1; z++) { + for (let x = -1; x <= 1; x++) { + const pos = cursor.offset(x, 0, z) + heights.push(getLiquidRenderHeight(world, world.getBlock(pos), type, pos, water, isRealWater)) + } + } + const cornerHeights = [ + Math.max(Math.max(heights[0], heights[1]), Math.max(heights[3], heights[4])), + Math.max(Math.max(heights[1], heights[2]), Math.max(heights[4], heights[5])), + Math.max(Math.max(heights[3], heights[4]), Math.max(heights[6], heights[7])), + Math.max(Math.max(heights[4], heights[5]), Math.max(heights[7], heights[8])) + ] + + // eslint-disable-next-line guard-for-in + for (const face in elemFaces) { + const { dir, corners, mask1, mask2 } = elemFaces[face] + const isUp = dir[1] === 1 + + const neighborPos = cursor.offset(...dir as [number, number, number]) + const neighbor = world.getBlock(neighborPos) + if (!neighbor) continue + if (neighbor.type === type || (water && (neighbor.name === 'water' || isBlockWaterlogged(neighbor)))) continue + if (isCube(neighbor) && !isUp) continue + + let tint = [1, 1, 1] + if (water) { + let m = 1 // Fake lighting to improve lisibility + if (Math.abs(dir[0]) > 0) m = 0.6 + else if (Math.abs(dir[2]) > 0) m = 0.8 + tint = tints.water[biome] + tint = [tint[0] * m, tint[1] * m, tint[2] * m] + } + + if (needTiles) { + const tiles = attr.tiles as Tiles + tiles[`${cursor.x},${cursor.y},${cursor.z}`] ??= { + block: 'water', + faces: [], + } + tiles[`${cursor.x},${cursor.y},${cursor.z}`].faces.push({ + face, + neighbor: `${neighborPos.x},${neighborPos.y},${neighborPos.z}`, + side: 0, // todo + textureIndex: 0, + // texture: eFace.texture.name, + }) + } + + const { u } = texture + const { v } = texture + const { su } = texture + const { sv } = texture + + // Get base light value for the face + const baseLight = world.getLight(neighborPos, undefined, undefined, water ? 'water' : 'lava') / 15 + + for (const pos of corners) { + const height = cornerHeights[pos[2] * 2 + pos[0]] + const OFFSET = 0.0001 + attr.t_positions!.push( + (pos[0] ? 1 - OFFSET : OFFSET) + (cursor.x & 15) - 8, + (pos[1] ? height - OFFSET : OFFSET) + (cursor.y & 15) - 8, + (pos[2] ? 1 - OFFSET : OFFSET) + (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) + + let cornerLightResult = baseLight + if (world.config.smoothLighting) { + const dx = pos[0] * 2 - 1 + const dy = pos[1] * 2 - 1 + const dz = pos[2] * 2 - 1 + const cornerDir: [number, number, number] = [dx, dy, dz] + const side1Dir: [number, number, number] = [dx * mask1[0], dy * mask1[1], dz * mask1[2]] + const side2Dir: [number, number, number] = [dx * mask2[0], dy * mask2[1], dz * mask2[2]] + + const dirVec = new Vec3(...dir as [number, number, number]) + + const side1LightDir = getVec(new Vec3(...side1Dir), dirVec) + const side1Light = world.getLight(cursor.plus(side1LightDir)) / 15 + const side2DirLight = getVec(new Vec3(...side2Dir), dirVec) + const side2Light = world.getLight(cursor.plus(side2DirLight)) / 15 + const cornerLightDir = getVec(new Vec3(...cornerDir), dirVec) + const cornerLight = world.getLight(cursor.plus(cornerLightDir)) / 15 + // interpolate + const lights = [side1Light, side2Light, cornerLight, baseLight] + cornerLightResult = lights.reduce((acc, cur) => acc + cur, 0) / lights.length + } + + // Apply light value to tint + attr.t_colors!.push(tint[0] * cornerLightResult, tint[1] * cornerLightResult, tint[2] * cornerLightResult) + } + } +} + +const identicalCull = (currentElement: BlockElement, neighbor: Block, direction: Vec3) => { + const dirStr = `${direction.x},${direction.y},${direction.z}` + const lookForOppositeSide = { + '0,1,0': 'down', + '0,-1,0': 'up', + '1,0,0': 'east', + '-1,0,0': 'west', + '0,0,1': 'south', + '0,0,-1': 'north', + }[dirStr]! + const elemCompareForm = { + '0,1,0': (e: BlockElement) => `${e.from[0]},${e.from[2]}:${e.to[0]},${e.to[2]}`, + '0,-1,0': (e: BlockElement) => `${e.to[0]},${e.to[2]}:${e.from[0]},${e.from[2]}`, + '1,0,0': (e: BlockElement) => `${e.from[2]},${e.from[1]}:${e.to[2]},${e.to[1]}`, + '-1,0,0': (e: BlockElement) => `${e.to[2]},${e.to[1]}:${e.from[2]},${e.from[1]}`, + '0,0,1': (e: BlockElement) => `${e.from[1]},${e.from[2]}:${e.to[1]},${e.to[2]}`, + '0,0,-1': (e: BlockElement) => `${e.to[1]},${e.to[2]}:${e.from[1]},${e.from[2]}`, + }[dirStr]! + const elementEdgeValidator = { + '0,1,0': (e: BlockElement) => currentElement.from[1] === 0 && e.to[2] === 16, + '0,-1,0': (e: BlockElement) => currentElement.from[1] === 0 && e.to[2] === 16, + '1,0,0': (e: BlockElement) => currentElement.from[0] === 0 && e.to[1] === 16, + '-1,0,0': (e: BlockElement) => currentElement.from[0] === 0 && e.to[1] === 16, + '0,0,1': (e: BlockElement) => currentElement.from[2] === 0 && e.to[0] === 16, + '0,0,-1': (e: BlockElement) => currentElement.from[2] === 0 && e.to[0] === 16, + }[dirStr]! + const useVar = 0 + const models = neighbor.models?.map(m => m[useVar] ?? m[0]) ?? [] + // TODO we should support it! rewrite with optimizing general pipeline + if (models.some(m => m.x || m.y || m.z)) return + return models.every(model => { + return (model.elements ?? []).every(element => { + // todo check alfa on texture + return !!(element.faces[lookForOppositeSide]?.cullface && elemCompareForm(currentElement) === elemCompareForm(element) && elementEdgeValidator(element)) + }) + }) +} + +let needSectionRecomputeOnChange = false + +function renderElement (world: World, cursor: Vec3, element: BlockElement, doAO: boolean, attr: MesherGeometryOutput, globalMatrix: any, globalShift: any, block: Block, biome: string) { + const position = cursor + // const key = `${position.x},${position.y},${position.z}` + // if (!globalThis.allowedBlocks.includes(key)) return + const cullIfIdentical = block.name.includes('glass') || block.name.includes('ice') + + // eslint-disable-next-line guard-for-in + for (const face in element.faces) { + const eFace = element.faces[face] + const { corners, mask1, mask2, side } = elemFaces[face] + const dir = matmul3(globalMatrix, elemFaces[face].dir) + + if (eFace.cullface) { + const neighbor = world.getBlock(cursor.plus(new Vec3(...dir)), blockProvider, {}) + if (neighbor) { + if (cullIfIdentical && neighbor.stateId === block.stateId) continue + if (!neighbor.transparent && (isCube(neighbor) || identicalCull(element, neighbor, new Vec3(...dir)))) continue + } else { + needSectionRecomputeOnChange = true + // continue + } + } + + const minx = element.from[0] + const miny = element.from[1] + const minz = element.from[2] + const maxx = element.to[0] + const maxy = element.to[1] + const maxz = element.to[2] + + const texture = eFace.texture as any + const { u } = texture + const { v } = texture + const { su } = texture + const { sv } = texture + + const ndx = Math.floor(attr.positions.length / 3) + + let tint = [1, 1, 1] + if (eFace.tintindex !== undefined) { + if (eFace.tintindex === 0) { + if (block.name === 'redstone_wire') { + tint = tints.redstone[`${block.getProperties().power}`] + } else if (block.name === 'birch_leaves' || + block.name === 'spruce_leaves' || + block.name === 'lily_pad') { + tint = tints.constant[block.name] + } else if (block.name.includes('leaves') || block.name === 'vine') { + tint = tints.foliage[biome] + } else { + tint = tints.grass[biome] + } + } + } + + // UV rotation + let r = eFace.rotation || 0 + if (face === 'down') { + r += 180 + } + const uvcs = Math.cos(r * Math.PI / 180) + const uvsn = -Math.sin(r * Math.PI / 180) + + let localMatrix = null as any + let localShift = null as any + + if (element.rotation && !needTiles) { + // Rescale support for block model rotations + localMatrix = buildRotationMatrix( + element.rotation.axis, + element.rotation.angle + ) + + localShift = vecsub3( + element.rotation.origin, + matmul3( + localMatrix, + element.rotation.origin + ) + ) + + // Apply rescale if specified + if (element.rotation.rescale) { + const FIT_TO_BLOCK_SCALE_MULTIPLIER = 2 - Math.sqrt(2) + const angleRad = element.rotation.angle * Math.PI / 180 + const scale = Math.abs(Math.sin(angleRad)) * FIT_TO_BLOCK_SCALE_MULTIPLIER + + // Get axis vector components (1 for the rotation axis, 0 for others) + const axisX = element.rotation.axis === 'x' ? 1 : 0 + const axisY = element.rotation.axis === 'y' ? 1 : 0 + const axisZ = element.rotation.axis === 'z' ? 1 : 0 + + // Create scale matrix: scale = (1 - axisComponent) * scaleFactor + 1 + const scaleMatrix = [ + [(1 - axisX) * scale + 1, 0, 0], + [0, (1 - axisY) * scale + 1, 0], + [0, 0, (1 - axisZ) * scale + 1] + ] + + // Apply scaling to the transformation matrix + localMatrix = matmulmat3(localMatrix, scaleMatrix) + + // Recalculate shift with the new matrix + localShift = vecsub3( + element.rotation.origin, + matmul3( + localMatrix, + element.rotation.origin + ) + ) + } + } + + const aos: number[] = [] + const neighborPos = position.plus(new Vec3(...dir)) + // 10% + const baseLight = world.getLight(neighborPos, undefined, undefined, block.name) / 15 + for (const pos of corners) { + let vertex = [ + (pos[0] ? maxx : minx), + (pos[1] ? maxy : miny), + (pos[2] ? maxz : minz) + ] + + if (!needTiles) { // 10% + vertex = vecadd3(matmul3(localMatrix, vertex), localShift) + vertex = vecadd3(matmul3(globalMatrix, vertex), globalShift) + vertex = vertex.map(v => v / 16) + + attr.positions.push( + vertex[0] + (cursor.x & 15) - 8, + vertex[1] + (cursor.y & 15) - 8, + vertex[2] + (cursor.z & 15) - 8 + ) + + attr.normals.push(...dir) + + const baseu = (pos[3] - 0.5) * uvcs - (pos[4] - 0.5) * uvsn + 0.5 + const basev = (pos[3] - 0.5) * uvsn + (pos[4] - 0.5) * uvcs + 0.5 + attr.uvs.push(baseu * su + u, basev * sv + v) + } + + let light = 1 + const { smoothLighting } = world.config + // const smoothLighting = true + if (doAO) { + const dx = pos[0] * 2 - 1 + const dy = pos[1] * 2 - 1 + const dz = pos[2] * 2 - 1 + const cornerDir = matmul3(globalMatrix, [dx, dy, dz]) + const side1Dir = matmul3(globalMatrix, [dx * mask1[0], dy * mask1[1], dz * mask1[2]]) + const side2Dir = matmul3(globalMatrix, [dx * mask2[0], dy * mask2[1], dz * mask2[2]]) + const side1 = world.getBlock(cursor.offset(...side1Dir)) + const side2 = world.getBlock(cursor.offset(...side2Dir)) + const corner = world.getBlock(cursor.offset(...cornerDir)) + + let cornerLightResult = baseLight * 15 + + if (smoothLighting) { + const dirVec = new Vec3(...dir) + const getVec = (v: Vec3) => { + for (const coord of ['x', 'y', 'z']) { + if (Math.abs(dirVec[coord]) > 0) v[coord] = 0 + } + return v.plus(dirVec) + } + const side1LightDir = getVec(new Vec3(...side1Dir)) + const side1Light = world.getLight(cursor.plus(side1LightDir)) + const side2DirLight = getVec(new Vec3(...side2Dir)) + const side2Light = world.getLight(cursor.plus(side2DirLight)) + const cornerLightDir = getVec(new Vec3(...cornerDir)) + const cornerLight = world.getLight(cursor.plus(cornerLightDir)) + // interpolate + const lights = [side1Light, side2Light, cornerLight, baseLight * 15] + cornerLightResult = lights.reduce((acc, cur) => acc + cur, 0) / lights.length + } + + const side1Block = world.shouldMakeAo(side1) ? 1 : 0 + const side2Block = world.shouldMakeAo(side2) ? 1 : 0 + const cornerBlock = world.shouldMakeAo(corner) ? 1 : 0 + + // TODO: correctly interpolate ao light based on pos (evaluate once for each corner of the block) + + const ao = (side1Block && side2Block) ? 0 : (3 - (side1Block + side2Block + cornerBlock)) + // todo light should go upper on lower blocks + light = (ao + 1) / 4 * (cornerLightResult / 15) + aos.push(ao) + } + + if (!needTiles) { + attr.colors.push(tint[0] * light, tint[1] * light, tint[2] * light) + } + } + + const lightWithColor = [baseLight * tint[0], baseLight * tint[1], baseLight * tint[2]] as [number, number, number] + + if (needTiles) { + const tiles = attr.tiles as Tiles + tiles[`${cursor.x},${cursor.y},${cursor.z}`] ??= { + block: block.name, + faces: [], + } + const needsOnlyOneFace = false + const isTilesEmpty = tiles[`${cursor.x},${cursor.y},${cursor.z}`].faces.length < 1 + if (isTilesEmpty || !needsOnlyOneFace) { + tiles[`${cursor.x},${cursor.y},${cursor.z}`].faces.push({ + face, + side, + textureIndex: eFace.texture.tileIndex, + neighbor: `${neighborPos.x},${neighborPos.y},${neighborPos.z}`, + light: baseLight, + tint: lightWithColor, + //@ts-expect-error debug prop + texture: eFace.texture.debugName || block.name, + } satisfies BlockType['faces'][number]) + } + } + + if (!needTiles) { + if (doAO && aos[0] + aos[3] >= aos[1] + aos[2]) { + attr.indices[attr.indicesCount++] = ndx + attr.indices[attr.indicesCount++] = ndx + 3 + attr.indices[attr.indicesCount++] = ndx + 2 + attr.indices[attr.indicesCount++] = ndx + attr.indices[attr.indicesCount++] = ndx + 1 + attr.indices[attr.indicesCount++] = ndx + 3 + } else { + attr.indices[attr.indicesCount++] = ndx + attr.indices[attr.indicesCount++] = ndx + 1 + attr.indices[attr.indicesCount++] = ndx + 2 + attr.indices[attr.indicesCount++] = ndx + 2 + attr.indices[attr.indicesCount++] = ndx + 1 + attr.indices[attr.indicesCount++] = ndx + 3 + } + } + } +} + +const ALWAYS_WATERLOGGED = new Set([ + 'seagrass', + 'tall_seagrass', + 'kelp', + 'kelp_plant', + 'bubble_column' +]) +const isBlockWaterlogged = (block: Block) => { + return block.getProperties().waterlogged === true || block.getProperties().waterlogged === 'true' || ALWAYS_WATERLOGGED.has(block.name) +} + +let unknownBlockModel: BlockModelPartsResolved +export function getSectionGeometry (sx: number, sy: number, sz: number, world: World) { + let delayedRender = [] as Array<() => void> + + const attr: MesherGeometryOutput = { + sx: sx + 8, + sy: sy + 8, + sz: sz + 8, + positions: [], + normals: [], + colors: [], + uvs: [], + t_positions: [], + t_normals: [], + t_colors: [], + t_uvs: [], + indices: [], + indicesCount: 0, // Track current index position + using32Array: true, + tiles: {}, + // todo this can be removed here + heads: {}, + signs: {}, + // isFull: true, + hadErrors: false, + blocksCount: 0 + } + + const cursor = new Vec3(0, 0, 0) + for (cursor.y = sy; cursor.y < sy + 16; cursor.y++) { + for (cursor.z = sz; cursor.z < sz + 16; cursor.z++) { + for (cursor.x = sx; cursor.x < sx + 16; cursor.x++) { + let block = world.getBlock(cursor, blockProvider, attr)! + if (INVISIBLE_BLOCKS.has(block.name)) continue + if ((block.name.includes('_sign') || block.name === 'sign') && !world.config.disableSignsMapsSupport) { + const key = `${cursor.x},${cursor.y},${cursor.z}` + const props: any = block.getProperties() + const facingRotationMap = { + 'north': 2, + 'south': 0, + 'west': 1, + 'east': 3 + } + 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 + } + } else if (block.name === 'player_head' || block.name === 'player_wall_head') { + const key = `${cursor.x},${cursor.y},${cursor.z}` + const props: any = block.getProperties() + const facingRotationMap = { + 'north': 0, + 'south': 2, + 'west': 3, + 'east': 1 + } + const isWall = block.name === 'player_wall_head' + attr.heads[key] = { + isWall, + rotation: isWall ? facingRotationMap[props.facing] : +props.rotation + } + } + const biome = block.biome.name + + if (world.preflat) { // 10% perf + const patchProperties = preflatBlockCalculation(block, world, cursor) + if (patchProperties) { + block._originalProperties ??= block._properties + block._properties = { ...block._originalProperties, ...patchProperties } + if (block.models && JSON.stringify(block._originalProperties) !== JSON.stringify(block._properties)) { + // recompute models + block.models = undefined + block = world.getBlock(cursor, blockProvider, attr)! + } + } else { + block._properties = block._originalProperties ?? block._properties + block._originalProperties = undefined + } + } + + const isWaterlogged = isBlockWaterlogged(block) + if (block.name === 'water' || isWaterlogged) { + const pos = cursor.clone() + // eslint-disable-next-line @typescript-eslint/no-loop-func + delayedRender.push(() => { + renderLiquid(world, pos, blockProvider.getTextureInfo('water_still'), block.type, biome, true, attr, !isWaterlogged) + }) + attr.blocksCount++ + } else if (block.name === 'lava') { + renderLiquid(world, cursor, blockProvider.getTextureInfo('lava_still'), block.type, biome, false, attr, false) + attr.blocksCount++ + } + if (block.name !== 'water' && block.name !== 'lava' && !INVISIBLE_BLOCKS.has(block.name)) { + // cache + let { models } = block + + models ??= unknownBlockModel + + const firstForceVar = world.config.debugModelVariant?.[0] + let part = 0 + for (const modelVars of models ?? []) { + const pos = cursor.clone() + // const variantRuntime = mod(Math.floor(pos.x / 16) + Math.floor(pos.y / 16) + Math.floor(pos.z / 16), modelVars.length) + const variantRuntime = 0 + const useVariant = world.config.debugModelVariant?.[part] ?? firstForceVar ?? variantRuntime + part++ + const model = modelVars[useVariant] ?? modelVars[0] + if (!model) continue + + // #region 10% + let globalMatrix = null as any + let globalShift = null as any + for (const axis of ['x', 'y', 'z'] as const) { + if (axis in model) { + globalMatrix = globalMatrix ? + matmulmat3(globalMatrix, buildRotationMatrix(axis, -(model[axis] ?? 0))) : + buildRotationMatrix(axis, -(model[axis] ?? 0)) + } + } + if (globalMatrix) { + globalShift = [8, 8, 8] + globalShift = vecsub3(globalShift, matmul3(globalMatrix, globalShift)) + } + // #endregion + + for (const element of model.elements ?? []) { + const ao = model.ao ?? true + if (block.transparent) { + const pos = cursor.clone() + delayedRender.push(() => { + renderElement(world, pos, element, ao, attr, globalMatrix, globalShift, block, biome) + }) + } else { + // 60% + renderElement(world, cursor, element, ao, attr, globalMatrix, globalShift, block, biome) + } + } + } + if (part > 0) attr.blocksCount++ + } + } + } + } + + for (const render of delayedRender) { + render() + } + delayedRender = [] + + let ndx = attr.positions.length / 3 + for (let i = 0; i < attr.t_positions!.length / 12; i++) { + attr.indices[attr.indicesCount++] = ndx + attr.indices[attr.indicesCount++] = ndx + 1 + attr.indices[attr.indicesCount++] = ndx + 2 + attr.indices[attr.indicesCount++] = ndx + 2 + attr.indices[attr.indicesCount++] = ndx + 1 + attr.indices[attr.indicesCount++] = ndx + 3 + // back face + attr.indices[attr.indicesCount++] = ndx + attr.indices[attr.indicesCount++] = ndx + 2 + attr.indices[attr.indicesCount++] = ndx + 1 + attr.indices[attr.indicesCount++] = ndx + 2 + attr.indices[attr.indicesCount++] = ndx + 3 + attr.indices[attr.indicesCount++] = ndx + 1 + ndx += 4 + } + + attr.positions.push(...attr.t_positions!) + attr.normals.push(...attr.t_normals!) + attr.colors.push(...attr.t_colors!) + attr.uvs.push(...attr.t_uvs!) + + delete attr.t_positions + delete attr.t_normals + delete attr.t_colors + delete attr.t_uvs + + attr.positions = new Float32Array(attr.positions) as any + attr.normals = new Float32Array(attr.normals) as any + attr.colors = new Float32Array(attr.colors) as any + attr.uvs = new Float32Array(attr.uvs) as any + attr.using32Array = arrayNeedsUint32(attr.indices) + if (attr.using32Array) { + attr.indices = new Uint32Array(attr.indices) + } else { + attr.indices = new Uint16Array(attr.indices) + } + + if (needTiles) { + delete attr.positions + delete attr.normals + delete attr.colors + delete attr.uvs + } + + return attr +} + +// copied from three.js +function arrayNeedsUint32 (array) { + + // assumes larger values usually on last + + for (let i = array.length - 1; i >= 0; -- i) { + + if (array[i] >= 65_535) return true // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 + + } + + return false + +} + +export const setBlockStatesData = (blockstatesModels, blocksAtlas: any, _needTiles = false, useUnknownBlockModel = true, version = 'latest') => { + blockProvider = worldBlockProvider(blockstatesModels, blocksAtlas, version) + globalThis.blockProvider = blockProvider + if (useUnknownBlockModel) { + unknownBlockModel = blockProvider.getAllResolvedModels0_1({ name: 'unknown', properties: {} }) + } + + needTiles = _needTiles +} diff --git a/renderer/viewer/lib/mesher/modelsGeometryCommon.ts b/renderer/viewer/lib/mesher/modelsGeometryCommon.ts new file mode 100644 index 00000000..3df20556 --- /dev/null +++ b/renderer/viewer/lib/mesher/modelsGeometryCommon.ts @@ -0,0 +1,142 @@ +import { BlockModelPartsResolved } from './world' + +export type BlockElement = NonNullable[0] + + +export function buildRotationMatrix (axis, degree) { + const radians = degree / 180 * Math.PI + const cos = Math.cos(radians) + const sin = Math.sin(radians) + + const axis0 = { x: 0, y: 1, z: 2 }[axis] + const axis1 = (axis0 + 1) % 3 + const axis2 = (axis0 + 2) % 3 + + const matrix = [ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0] + ] + + matrix[axis0][axis0] = 1 + matrix[axis1][axis1] = cos + matrix[axis1][axis2] = -sin + matrix[axis2][axis1] = +sin + matrix[axis2][axis2] = cos + + return matrix +} + +export function vecadd3 (a, b) { + if (!b) return a + return [a[0] + b[0], a[1] + b[1], a[2] + b[2]] +} + +export function vecsub3 (a, b) { + if (!b) return a + return [a[0] - b[0], a[1] - b[1], a[2] - b[2]] +} + +export function matmul3 (matrix, vector): [number, number, number] { + if (!matrix) return vector + return [ + matrix[0][0] * vector[0] + matrix[0][1] * vector[1] + matrix[0][2] * vector[2], + matrix[1][0] * vector[0] + matrix[1][1] * vector[1] + matrix[1][2] * vector[2], + matrix[2][0] * vector[0] + matrix[2][1] * vector[1] + matrix[2][2] * vector[2] + ] +} + +export function matmulmat3 (a, b) { + const te = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] + + const a11 = a[0][0]; const a12 = a[1][0]; const a13 = a[2][0] + const a21 = a[0][1]; const a22 = a[1][1]; const a23 = a[2][1] + const a31 = a[0][2]; const a32 = a[1][2]; const a33 = a[2][2] + + const b11 = b[0][0]; const b12 = b[1][0]; const b13 = b[2][0] + const b21 = b[0][1]; const b22 = b[1][1]; const b23 = b[2][1] + const b31 = b[0][2]; const b32 = b[1][2]; const b33 = b[2][2] + + te[0][0] = a11 * b11 + a12 * b21 + a13 * b31 + te[1][0] = a11 * b12 + a12 * b22 + a13 * b32 + te[2][0] = a11 * b13 + a12 * b23 + a13 * b33 + + te[0][1] = a21 * b11 + a22 * b21 + a23 * b31 + te[1][1] = a21 * b12 + a22 * b22 + a23 * b32 + te[2][1] = a21 * b13 + a22 * b23 + a23 * b33 + + te[0][2] = a31 * b11 + a32 * b21 + a33 * b31 + te[1][2] = a31 * b12 + a32 * b22 + a33 * b32 + te[2][2] = a31 * b13 + a32 * b23 + a33 * b33 + + return te +} + +export const elemFaces = { + up: { + dir: [0, 1, 0], + mask1: [1, 1, 0], + mask2: [0, 1, 1], + corners: [ + [0, 1, 1, 0, 1], + [1, 1, 1, 1, 1], + [0, 1, 0, 0, 0], + [1, 1, 0, 1, 0] + ] + }, + down: { + dir: [0, -1, 0], + mask1: [1, 1, 0], + mask2: [0, 1, 1], + corners: [ + [1, 0, 1, 0, 1], + [0, 0, 1, 1, 1], + [1, 0, 0, 0, 0], + [0, 0, 0, 1, 0] + ] + }, + east: { + dir: [1, 0, 0], + mask1: [1, 1, 0], + mask2: [1, 0, 1], + corners: [ + [1, 1, 1, 0, 0], + [1, 0, 1, 0, 1], + [1, 1, 0, 1, 0], + [1, 0, 0, 1, 1] + ] + }, + west: { + dir: [-1, 0, 0], + mask1: [1, 1, 0], + mask2: [1, 0, 1], + corners: [ + [0, 1, 0, 0, 0], + [0, 0, 0, 0, 1], + [0, 1, 1, 1, 0], + [0, 0, 1, 1, 1] + ] + }, + north: { + dir: [0, 0, -1], + mask1: [1, 0, 1], + mask2: [0, 1, 1], + corners: [ + [1, 0, 0, 1, 1], + [0, 0, 0, 0, 1], + [1, 1, 0, 1, 0], + [0, 1, 0, 0, 0] + ] + }, + south: { + dir: [0, 0, 1], + mask1: [1, 0, 1], + mask2: [0, 1, 1], + corners: [ + [0, 0, 1, 0, 1], + [1, 0, 1, 1, 1], + [0, 1, 1, 0, 0], + [1, 1, 1, 1, 0] + ] + } +} diff --git a/renderer/viewer/lib/mesher/shared.ts b/renderer/viewer/lib/mesher/shared.ts new file mode 100644 index 00000000..230db6b9 --- /dev/null +++ b/renderer/viewer/lib/mesher/shared.ts @@ -0,0 +1,70 @@ +import { BlockType } from '../../../playground/shared' + +// only here for easier testing +export const defaultMesherConfig = { + version: '', + worldMaxY: 256, + worldMinY: 0, + enableLighting: true, + skyLight: 15, + smoothLighting: true, + outputFormat: 'threeJs' as 'threeJs' | 'webgpu', + // textureSize: 1024, // for testing + debugModelVariant: undefined as undefined | number[], + clipWorldBelowY: undefined as undefined | number, + disableSignsMapsSupport: false +} + +export type CustomBlockModels = { + [blockPosKey: string]: string // blockPosKey is "x,y,z" -> model name +} + +export type MesherConfig = typeof defaultMesherConfig + +export type MesherGeometryOutput = { + sx: number, + sy: number, + sz: number, + // resulting: float32array + positions: any, + normals: any, + colors: any, + uvs: any, + t_positions?: number[], + t_normals?: number[], + t_colors?: number[], + t_uvs?: number[], + + indices: Uint32Array | Uint16Array | number[], + indicesCount: number, + using32Array: boolean, + tiles: Record, + heads: Record, + signs: Record, + // isFull: boolean + hadErrors: boolean + blocksCount: number + customBlockModels?: CustomBlockModels +} + +export interface MesherMainEvents { + geometry: { type: 'geometry'; key: string; geometry: MesherGeometryOutput; workerIndex: number }; + sectionFinished: { type: 'sectionFinished'; key: string; workerIndex: number; processTime?: number }; + blockStateModelInfo: { type: 'blockStateModelInfo'; info: Record }; + heightmap: { type: 'heightmap'; key: string; heightmap: Uint8Array }; +} + +export type MesherMainEvent = MesherMainEvents[keyof MesherMainEvents] + +export type HighestBlockInfo = { y: number, stateId: number | undefined, biomeId: number | undefined } + +export type BlockStateModelInfo = { + cacheKey: string + issues: string[] + modelNames: string[] + conditions: string[] +} + +export const getBlockAssetsCacheKey = (stateId: number, modelNameOverride?: string) => { + return modelNameOverride ? `${stateId}:${modelNameOverride}` : String(stateId) +} diff --git a/renderer/viewer/lib/mesher/standaloneRenderer.ts b/renderer/viewer/lib/mesher/standaloneRenderer.ts new file mode 100644 index 00000000..3d468dce --- /dev/null +++ b/renderer/viewer/lib/mesher/standaloneRenderer.ts @@ -0,0 +1,270 @@ +/* eslint-disable @stylistic/function-call-argument-newline */ +import { Vec3 } from 'vec3' +import { Block } from 'prismarine-block' +import { IndexedData } from 'minecraft-data' +import * as THREE from 'three' +import { BlockModelPartsResolved } from './world' +import { BlockElement, buildRotationMatrix, elemFaces, matmul3, matmulmat3, vecadd3, vecsub3 } from './modelsGeometryCommon' + +type NeighborSide = 'up' | 'down' | 'east' | 'west' | 'north' | 'south' + +function tintToGl (tint) { + const r = (tint >> 16) & 0xff + const g = (tint >> 8) & 0xff + const b = tint & 0xff + return [r / 255, g / 255, b / 255] +} + +type Neighbors = Partial> +function renderElement (element: BlockElement, doAO: boolean, attr, globalMatrix, globalShift, block: Block | undefined, biome: string, neighbors: Neighbors) { + const cursor = new Vec3(0, 0, 0) + + // const key = `${position.x},${position.y},${position.z}` + // if (!globalThis.allowedBlocks.includes(key)) return + // const cullIfIdentical = block.name.indexOf('glass') >= 0 + + // eslint-disable-next-line guard-for-in + for (const face in element.faces) { + const eFace = element.faces[face] + const { corners, mask1, mask2 } = elemFaces[face] + const dir = matmul3(globalMatrix, elemFaces[face].dir) + + if (eFace.cullface) { + if (neighbors[face]) continue + } + + const minx = element.from[0] + const miny = element.from[1] + const minz = element.from[2] + const maxx = element.to[0] + const maxy = element.to[1] + const maxz = element.to[2] + + const texture = eFace.texture as any + const { u } = texture + const { v } = texture + const { su } = texture + const { sv } = texture + + const ndx = Math.floor(attr.positions.length / 3) + + let tint = [1, 1, 1] + if (eFace.tintindex !== undefined) { + if (eFace.tintindex === 0) { + // TODO + // if (block.name === 'redstone_wire') { + // tint = tints.redstone[`${block.getProperties().power}`] + // } else if (block.name === 'birch_leaves' || + // block.name === 'spruce_leaves' || + // block.name === 'lily_pad') { + // tint = tints.constant[block.name] + // } else if (block.name.includes('leaves') || block.name === 'vine') { + // tint = tints.foliage[biome] + // } else { + // tint = tints.grass[biome] + // } + const grassTint = [145 / 255, 189 / 255, 89 / 255] + tint = grassTint + } + } + + // UV rotation + const r = eFace.rotation || 0 + const uvcs = Math.cos(r * Math.PI / 180) + const uvsn = -Math.sin(r * Math.PI / 180) + + let localMatrix = null as any + let localShift = null as any + + if (element.rotation) { + // todo do we support rescale? + localMatrix = buildRotationMatrix( + element.rotation.axis, + element.rotation.angle + ) + + localShift = vecsub3( + element.rotation.origin, + matmul3( + localMatrix, + element.rotation.origin + ) + ) + } + + const aos: number[] = [] + // const neighborPos = position.plus(new Vec3(...dir)) + // const baseLight = world.getLight(neighborPos, undefined, undefined, block.name) / 15 + const baseLight = 1 + for (const pos of corners) { + let vertex = [ + (pos[0] ? maxx : minx), + (pos[1] ? maxy : miny), + (pos[2] ? maxz : minz) + ] + + vertex = vecadd3(matmul3(localMatrix, vertex), localShift) + vertex = vecadd3(matmul3(globalMatrix, vertex), globalShift) + vertex = vertex.map(v => v / 16) + + attr.positions.push( + vertex[0]/* + (cursor.x & 15) - 8 */, + vertex[1]/* + (cursor.y & 15) x */, + vertex[2]/* + (cursor.z & 15) - 8 */ + ) + + attr.normals.push(...dir) + + const baseu = (pos[3] - 0.5) * uvcs - (pos[4] - 0.5) * uvsn + 0.5 + const basev = (pos[3] - 0.5) * uvsn + (pos[4] - 0.5) * uvcs + 0.5 + attr.uvs.push(baseu * su + u, basev * sv + v) + + let light = 1 + if (doAO) { + const cornerLightResult = 15 + + const side1Block = 0 + const side2Block = 0 + const cornerBlock = 0 + + const ao = (side1Block && side2Block) ? 0 : (3 - (side1Block + side2Block + cornerBlock)) + // todo light should go upper on lower blocks + light = (ao + 1) / 4 * (cornerLightResult / 15) + aos.push(ao) + } + + attr.colors.push(baseLight * tint[0] * light, baseLight * tint[1] * light, baseLight * tint[2] * light) + } + + // if (needTiles) { + // attr.tiles[`${cursor.x},${cursor.y},${cursor.z}`] ??= { + // block: block.name, + // faces: [], + // } + // attr.tiles[`${cursor.x},${cursor.y},${cursor.z}`].faces.push({ + // face, + // neighbor: `${neighborPos.x},${neighborPos.y},${neighborPos.z}`, + // light: baseLight + // // texture: eFace.texture.name, + // }) + // } + + if (doAO && aos[0] + aos[3] >= aos[1] + aos[2]) { + attr.indices.push( + + ndx, ndx + 3, ndx + 2, + ndx, ndx + 1, ndx + 3 + ) + } else { + attr.indices.push( + + ndx, ndx + 1, ndx + 2, + ndx + 2, ndx + 1, ndx + 3 + ) + } + } +} + +export const renderBlockThreeAttr = (models: BlockModelPartsResolved, block: Block | undefined, biome: string, mcData: IndexedData, variants = [], neighbors: Neighbors = {}) => { + const sx = 0 + const sy = 0 + const sz = 0 + + const attr = { + sx: sx + 0.5, + sy: sy + 0.5, + sz: sz + 0.5, + positions: [], + normals: [], + colors: [], + uvs: [], + t_positions: [], + t_normals: [], + t_colors: [], + t_uvs: [], + indices: [], + tiles: {}, + } as Record + + for (const [i, modelVars] of models.entries()) { + const model = modelVars[variants[i]] ?? modelVars[0] + if (!model) continue + let globalMatrix = null as any + let globalShift = null as any + for (const axis of ['x', 'y', 'z'] as const) { + if (axis in model) { + if (globalMatrix) { globalMatrix = matmulmat3(globalMatrix, buildRotationMatrix(axis, -(model[axis] ?? 0))) } else { globalMatrix = buildRotationMatrix(axis, -(model[axis] ?? 0)) } + } + } + if (globalMatrix) { + globalShift = [8, 8, 8] + globalShift = vecsub3(globalShift, matmul3(globalMatrix, globalShift)) + } + + const ao = model.ao ?? true + + for (const element of model.elements ?? []) { + renderElement(element, ao, attr, globalMatrix, globalShift, block, biome, neighbors) + } + } + + let ndx = attr.positions.length / 3 + for (let i = 0; i < attr.t_positions.length / 12; i++) { + attr.indices.push( + ndx, ndx + 1, ndx + 2, ndx + 2, ndx + 1, ndx + 3, + // back face + ndx, ndx + 2, ndx + 1, ndx + 2, ndx + 3, ndx + 1 + ) + ndx += 4 + } + + attr.positions.push(...attr.t_positions) + attr.normals.push(...attr.t_normals) + attr.colors.push(...attr.t_colors) + attr.uvs.push(...attr.t_uvs) + + delete attr.t_positions + delete attr.t_normals + delete attr.t_colors + delete attr.t_uvs + + attr.positions = new Float32Array(attr.positions) as any + attr.normals = new Float32Array(attr.normals) as any + attr.colors = new Float32Array(attr.colors) as any + attr.uvs = new Float32Array(attr.uvs) as any + + return attr +} + +export const renderBlockThree = (...args: Parameters) => { + const attr = renderBlockThreeAttr(...args) + const data = { + geometry: attr + } + + const geometry = new THREE.BufferGeometry() + geometry.setAttribute('position', new THREE.BufferAttribute(data.geometry.positions, 3)) + geometry.setAttribute('normal', new THREE.BufferAttribute(data.geometry.normals, 3)) + geometry.setAttribute('color', new THREE.BufferAttribute(data.geometry.colors, 3)) + geometry.setAttribute('uv', new THREE.BufferAttribute(data.geometry.uvs, 2)) + geometry.setIndex(data.geometry.indices) + geometry.name = 'block-geometry' + + return geometry +} + +export const getThreeBlockModelGroup = (material: THREE.Material, ...args: Parameters) => { + const geometry = renderBlockThree(...args) + const mesh = new THREE.Mesh(geometry, material) + mesh.position.set(-0.5, -0.5, -0.5) + const group = new THREE.Group() + group.add(mesh) + group.rotation.set(0, -THREE.MathUtils.degToRad(90), 0, 'ZYX') + globalThis.mesh = group + return group + // return new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshPhongMaterial({ color: 0x00_00_ff, transparent: true, opacity: 0.5 })) +} + +export const setBlockPosition = (object: THREE.Object3D, position: { x: number, y: number, z: number }) => { + object.position.set(position.x + 0.5, position.y + 0.5, position.z + 0.5) +} diff --git a/renderer/viewer/lib/mesher/test/mesherTester.ts b/renderer/viewer/lib/mesher/test/mesherTester.ts new file mode 100644 index 00000000..e75d803d --- /dev/null +++ b/renderer/viewer/lib/mesher/test/mesherTester.ts @@ -0,0 +1,76 @@ +import ChunkLoader, { PCChunk } from 'prismarine-chunk' +import { Vec3 } from 'vec3' +import MinecraftData from 'minecraft-data' +import blocksAtlasesJson from 'mc-assets/dist/blocksAtlases.json' +import { World as MesherWorld } from '../world' +import { setBlockStatesData, getSectionGeometry } from '../models' + +export const setup = (version, initialBlocks: Array<[number[], string]>) => { + const mcData = MinecraftData(version) + const blockStatesModels = require(`mc-assets/dist/blockStatesModels.json`) + const mesherWorld = new MesherWorld(version) + const Chunk = ChunkLoader(version) + const chunk1 = new Chunk(undefined as any) + + const pos = new Vec3(2, 5, 2) + for (const [addPos, name] of initialBlocks) { + chunk1.setBlockStateId(pos.offset(addPos[0], addPos[1], addPos[2]), mcData.blocksByName[name].defaultState) + } + + const getGeometry = () => { + const sectionGeometry = getSectionGeometry(0, 0, 0, mesherWorld) + const centerFaces = sectionGeometry.tiles[`${pos.x},${pos.y},${pos.z}`]?.faces.length ?? 0 + const totalTiles = Object.values(sectionGeometry.tiles).reduce((acc, val: any) => acc + val.faces.length, 0) + const centerTileNeighbors = Object.entries(sectionGeometry.tiles).reduce((acc, [key, val]: any) => { + return acc + val.faces.filter((face: any) => face.neighbor === `${pos.x},${pos.y},${pos.z}`).length + }, 0) + return { + centerFaces, + totalTiles, + centerTileNeighbors, + faces: sectionGeometry.tiles[`${pos.x},${pos.y},${pos.z}`]?.faces ?? [], + attr: sectionGeometry + } + } + + setBlockStatesData(blockStatesModels, blocksAtlasesJson, true, false, version) + const reload = () => { + mesherWorld.removeColumn(0, 0) + mesherWorld.addColumn(0, 0, chunk1.toJson()) + } + reload() + + const getLights = () => { + return Object.fromEntries(getGeometry().faces.map(({ face, light }) => ([face, (light ?? 0) * 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, + reload, + chunk: chunk1 as PCChunk + } +} + +// surround it +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'], +] diff --git a/renderer/viewer/lib/mesher/test/playground.ts b/renderer/viewer/lib/mesher/test/playground.ts new file mode 100644 index 00000000..0441dd60 --- /dev/null +++ b/renderer/viewer/lib/mesher/test/playground.ts @@ -0,0 +1,20 @@ +import { BlockNames } from '../../../../../src/mcDataTypes' +import { setup } from './mesherTester' + +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'], +] as const + +const { mesherWorld, getGeometry, pos, mcData } = setup('1.21.1', addPositions as any) + +// mesherWorld.setBlockStateId(pos, 712) +// mesherWorld.setBlockStateId(pos, mcData.blocksByName.stone_slab.defaultState) +mesherWorld.setBlockStateId(pos, 11_225) + +console.log(getGeometry().centerTileNeighbors) diff --git a/renderer/viewer/lib/mesher/test/tests.test.ts b/renderer/viewer/lib/mesher/test/tests.test.ts new file mode 100644 index 00000000..2c3dc6a5 --- /dev/null +++ b/renderer/viewer/lib/mesher/test/tests.test.ts @@ -0,0 +1,56 @@ +import { test, expect } from 'vitest' +import supportedVersions from '../../../../../src/supportedVersions.mjs' +import { INVISIBLE_BLOCKS } from '../worldConstants' +import { setup } from './mesherTester' + +const lastVersion = supportedVersions.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'], +] as const + +test('Known blocks are not rendered', () => { + const { mesherWorld, getGeometry, pos, mcData } = setup(lastVersion, addPositions as any) + const ignoreAsExpected = new Set([...INVISIBLE_BLOCKS, 'water', 'lava']) + + let time = 0 + let times = 0 + const missingBlocks = {}/* as {[number, number]} */ + const erroredBlocks = {}/* as {[number, number]} */ + for (const block of mcData.blocksArray) { + if (ignoreAsExpected.has(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, attr } = getGeometry() + time += performance.now() - start + times++ + if (centerFaces === 0) { + const objAdd = attr.hadErrors ? erroredBlocks : missingBlocks + if (objAdd[block.name]) continue + objAdd[block.name] = true + // invalidBlocks[block.name] = [i - block.defaultState!, centerTileNeighbors] + // console.log('INVALID', block.name, centerTileNeighbors, i - block.minStateId) + } + } + } + console.log('Checking blocks of version', lastVersion) + console.log('Average time', time / times) + // should be fixed, but to avoid regressions & for visibility + // TODO resolve creaking_heart issue (1.21.3) + expect(missingBlocks).toMatchInlineSnapshot(` + { + "structure_void": true, + } + `) + expect(erroredBlocks).toMatchInlineSnapshot('{}') +}) diff --git a/prismarine-viewer/viewer/lib/mesher/world.ts b/renderer/viewer/lib/mesher/world.ts similarity index 50% rename from prismarine-viewer/viewer/lib/mesher/world.ts rename to renderer/viewer/lib/mesher/world.ts index 5f3a281d..f2757ae6 100644 --- a/prismarine-viewer/viewer/lib/mesher/world.ts +++ b/renderer/viewer/lib/mesher/world.ts @@ -1,10 +1,12 @@ import Chunks from 'prismarine-chunk' import mcData from 'minecraft-data' -import { Block } from "prismarine-block" +import { Block } from 'prismarine-block' import { Vec3 } from 'vec3' +import { WorldBlockProvider } from 'mc-assets/dist/worldBlockProvider' import moreBlockDataGeneratedJson from '../moreBlockDataGenerated.json' -import { defaultMesherConfig } from './shared' import legacyJson from '../../../../src/preflatMap.json' +import { defaultMesherConfig, CustomBlockModels, BlockStateModelInfo, getBlockAssetsCacheKey } from './shared' +import { INVISIBLE_BLOCKS } from './worldConstants' const ignoreAoBlocks = Object.keys(moreBlockDataGeneratedJson.noOcclusions) @@ -18,13 +20,17 @@ function isCube (shapes) { return shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1 } +export type BlockModelPartsResolved = ReturnType + export type WorldBlock = Omit & { - variant?: any // todo isCube: boolean + /** cache */ + models?: BlockModelPartsResolved | null + _originalProperties?: Record + _properties?: Record } - export class World { config = defaultMesherConfig Chunk: typeof import('prismarine-chunk/types/index').PCChunk @@ -32,8 +38,12 @@ export class World { blockCache = {} biomeCache: { [id: number]: mcData.Biome } preflat: boolean + erroredBlockModel?: BlockModelPartsResolved + customBlockModels = new Map() // chunkKey -> blockModels + sentBlockStateModels = new Set() + blockStateModelInfo = new Map() - constructor(version) { + constructor (version) { this.Chunk = Chunks(version) as any this.biomeCache = mcData(version).biomes this.preflat = !mcData(version).supportFeature('blockStateId') @@ -41,6 +51,8 @@ export class World { } getLight (pos: Vec3, isNeighbor = false, skipMoreChecks = false, curBlockName = '') { + // for easier testing + if (!(pos instanceof Vec3)) pos = new Vec3(...pos as [number, number, number]) const { enableLighting, skyLight } = this.config if (!enableLighting) return 15 // const key = `${pos.x},${pos.y},${pos.z}` @@ -55,7 +67,7 @@ export class World { ) + 2 ) // lightsCache.set(key, result) - if (result === 2 && [this.getBlock(pos)?.name ?? '', curBlockName].some(x => x.match(/_stairs|slab|glass_pane/)) && !skipMoreChecks) { // todo this is obviously wrong + if (result === 2 && [this.getBlock(pos)?.name ?? '', curBlockName].some(x => /_stairs|slab|glass_pane/.exec(x)) && !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), @@ -64,8 +76,10 @@ export class World { 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 (lights.length) { + const min = Math.min(...lights) + result = min + } } if (isNeighbor && result === 2) result = 15 // TODO return result @@ -102,10 +116,12 @@ export class World { return this.getColumn(Math.floor(pos.x / 16) * 16, Math.floor(pos.z / 16) * 16) } - getBlock (pos: Vec3): WorldBlock | null { + getBlock (pos: Vec3, blockProvider?: WorldBlockProvider, attr?: { hadErrors?: boolean }): 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 blockPosKey = `${pos.x},${pos.y},${pos.z}` + const modelOverride = this.customBlockModels.get(key)?.[blockPosKey] const column = this.columns[key] // null column means chunk not loaded @@ -115,39 +131,108 @@ export class World { const locInChunk = posInChunk(loc) const stateId = column.getBlockStateId(locInChunk) - if (!this.blockCache[stateId]) { - const b = column.getBlock(locInChunk) - //@ts-expect-error + const cacheKey = getBlockAssetsCacheKey(stateId, modelOverride) + + if (!this.blockCache[cacheKey]) { + const b = column.getBlock(locInChunk) as unknown as WorldBlock + if (modelOverride) { + b.name = modelOverride + } b.isCube = isCube(b.shapes) - this.blockCache[stateId] = b + this.blockCache[cacheKey] = b Object.defineProperty(b, 'position', { get () { 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 = {} + b._properties = {} + + const namePropsStr = legacyJson.blocks[b.type + ':' + b.metadata] || findClosestLegacyBlockFallback(b.type, b.metadata, pos) + if (namePropsStr) { + 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('=') + if (!isNaN(val)) val = parseInt(val, 10) + return [key, val] + })) + b._properties = newProperties + } } } } - const block = this.blockCache[stateId] + const block: WorldBlock = this.blockCache[cacheKey] + + if (block.models === undefined && blockProvider) { + if (!attr) throw new Error('attr is required') + const props = block.getProperties() + + try { + // fixme + if (this.preflat) { + if (block.name === 'cobblestone_wall') { + props.up = 'true' + for (const key of ['north', 'south', 'east', 'west']) { + const val = props[key] + if (val === 'false' || val === 'true') { + props[key] = val === 'true' ? 'low' : 'none' + } + } + } + } + + const useFallbackModel = !!(this.preflat || modelOverride) + const issues = [] as string[] + const resolvedModelNames = [] as string[] + const resolvedConditions = [] as string[] + block.models = blockProvider.getAllResolvedModels0_1( + { + name: block.name, + properties: props, + }, + useFallbackModel, + issues, + resolvedModelNames, + resolvedConditions + )! + + // Track block state model info + if (!this.sentBlockStateModels.has(cacheKey)) { + this.blockStateModelInfo.set(cacheKey, { + cacheKey, + issues, + modelNames: resolvedModelNames, + conditions: resolvedConditions + }) + } + + if (!block.models.length) { + if (block.name !== 'water' && block.name !== 'lava' && !INVISIBLE_BLOCKS.has(block.name)) { + console.debug('[mesher] block to render not found', block.name, props) + } + block.models = null + } + + if (block.models && modelOverride) { + const model = block.models[0] + block.transparent = model[0]?.['transparent'] ?? block.transparent + } + } catch (err) { + this.erroredBlockModel ??= blockProvider.getAllResolvedModels0_1({ name: 'errored', properties: {} }) + block.models ??= this.erroredBlockModel + console.error(`Critical assets error. Unable to get block model for ${block.name}[${JSON.stringify(props)}]: ` + err.message, err.stack) + attr.hadErrors = true + } + } + if (block.name === 'flowing_water') block.name = 'water' if (block.name === 'flowing_lava') block.name = 'lava' + if (block.name === 'bubble_column') block.name = 'water' // TODO need to distinguish between water and bubble column // block.position = loc // it overrides position of all currently loaded blocks + //@ts-expect-error block.biome = this.biomeCache[column.getBiome(locInChunk)] ?? this.biomeCache[1] ?? this.biomeCache[0] if (block.name === 'redstone_ore') block.transparent = false return block @@ -158,6 +243,15 @@ export class World { } } +const findClosestLegacyBlockFallback = (id, metadata, pos) => { + console.warn(`[mesher] Unknown block with ${id}:${metadata} at ${pos}, falling back`) // todo has known issues + for (const [key, value] of Object.entries(legacyJson.blocks)) { + const [idKey, meta] = key.split(':') + if (idKey === id) return value + } + return null +} + // todo export in chunk instead const hasChunkSection = (column, pos) => { if (column._getSection) return column._getSection(pos) diff --git a/renderer/viewer/lib/mesher/worldConstants.ts b/renderer/viewer/lib/mesher/worldConstants.ts new file mode 100644 index 00000000..6aa0e0fc --- /dev/null +++ b/renderer/viewer/lib/mesher/worldConstants.ts @@ -0,0 +1 @@ +export const INVISIBLE_BLOCKS = new Set(['air', 'void_air', 'cave_air', 'barrier', 'light', 'moving_piston']) diff --git a/renderer/viewer/lib/mesherlogReader.ts b/renderer/viewer/lib/mesherlogReader.ts new file mode 100644 index 00000000..0f1e74c0 --- /dev/null +++ b/renderer/viewer/lib/mesherlogReader.ts @@ -0,0 +1,131 @@ +/* eslint-disable no-await-in-loop */ +import { Vec3 } from 'vec3' + +// import log from '../../../../../Downloads/mesher (2).log' +import { WorldRendererCommon } from './worldrendererCommon' +const log = '' + + +export class MesherLogReader { + chunksToReceive: Array<{ + x: number + z: number + chunkLength: number + }> = [] + messagesQueue: Array<{ + fromWorker: boolean + workerIndex: number + message: any + }> = [] + + sectionFinishedToReceive = null as { + messagesLeft: string[] + resolve: () => void + } | null + replayStarted = false + + constructor (private readonly worldRenderer: WorldRendererCommon) { + this.parseMesherLog() + } + + chunkReceived (x: number, z: number, chunkLength: number) { + // remove existing chunks with same x and z + const existingChunkIndex = this.chunksToReceive.findIndex(chunk => chunk.x === x && chunk.z === z) + if (existingChunkIndex === -1) { + // console.error('Chunk not found', x, z) + } else { + // warn if chunkLength is different + if (this.chunksToReceive[existingChunkIndex].chunkLength !== chunkLength) { + // console.warn('Chunk length mismatch', x, z, this.chunksToReceive[existingChunkIndex].chunkLength, chunkLength) + } + // remove chunk + this.chunksToReceive = this.chunksToReceive.filter((chunk, index) => chunk.x !== x || chunk.z !== z) + } + this.maybeStartReplay() + } + + async maybeStartReplay () { + if (this.chunksToReceive.length !== 0 || this.replayStarted) return + const lines = log.split('\n') + console.log('starting replay') + this.replayStarted = true + const waitForWorkersMessages = async () => { + if (!this.sectionFinishedToReceive) return + await new Promise(resolve => { + this.sectionFinishedToReceive!.resolve = resolve + }) + } + + for (const line of lines) { + if (line.includes('dispatchMessages dirty')) { + await waitForWorkersMessages() + this.worldRenderer.stopMesherMessagesProcessing = true + const message = JSON.parse(line.slice(line.indexOf('{'), line.lastIndexOf('}') + 1)) + if (!message.value) continue + const index = line.split(' ')[1] + const type = line.split(' ')[3] + // console.log('sending message', message.x, message.y, message.z) + this.worldRenderer.forceCallFromMesherReplayer = true + this.worldRenderer.setSectionDirty(new Vec3(message.x, message.y, message.z), message.value) + this.worldRenderer.forceCallFromMesherReplayer = false + } + if (line.includes('-> blockUpdate')) { + await waitForWorkersMessages() + this.worldRenderer.stopMesherMessagesProcessing = true + const message = JSON.parse(line.slice(line.indexOf('{'), line.lastIndexOf('}') + 1)) + this.worldRenderer.forceCallFromMesherReplayer = true + this.worldRenderer.setBlockStateIdInner(new Vec3(message.pos.x, message.pos.y, message.pos.z), message.stateId) + this.worldRenderer.forceCallFromMesherReplayer = false + } + + if (line.includes(' sectionFinished ')) { + if (!this.sectionFinishedToReceive) { + console.log('starting worker message processing validating') + this.worldRenderer.stopMesherMessagesProcessing = false + this.sectionFinishedToReceive = { + messagesLeft: [], + resolve: () => { + this.sectionFinishedToReceive = null + } + } + } + const parts = line.split(' ') + const coordsPart = parts.find(part => part.split(',').length === 3) + if (!coordsPart) throw new Error(`no coords part found ${line}`) + const [x, y, z] = coordsPart.split(',').map(Number) + this.sectionFinishedToReceive.messagesLeft.push(`${x},${y},${z}`) + } + } + } + + workerMessageReceived (type: string, message: any) { + if (type === 'sectionFinished') { + const { key } = message + if (!this.sectionFinishedToReceive) { + console.warn(`received sectionFinished message but no sectionFinishedToReceive ${key}`) + return + } + + const idx = this.sectionFinishedToReceive.messagesLeft.indexOf(key) + if (idx === -1) { + console.warn(`received sectionFinished message for non-outstanding section ${key}`) + return + } + this.sectionFinishedToReceive.messagesLeft.splice(idx, 1) + if (this.sectionFinishedToReceive.messagesLeft.length === 0) { + this.sectionFinishedToReceive.resolve() + } + } + } + + parseMesherLog () { + const lines = log.split('\n') + for (const line of lines) { + if (line.startsWith('-> chunk')) { + const chunk = JSON.parse(line.slice('-> chunk'.length)) + this.chunksToReceive.push(chunk) + continue + } + } + } +} diff --git a/prismarine-viewer/viewer/lib/moreBlockDataGenerated.json b/renderer/viewer/lib/moreBlockDataGenerated.json similarity index 100% rename from prismarine-viewer/viewer/lib/moreBlockDataGenerated.json rename to renderer/viewer/lib/moreBlockDataGenerated.json diff --git a/prismarine-viewer/viewer/lib/simpleUtils.ts b/renderer/viewer/lib/simpleUtils.ts similarity index 67% rename from prismarine-viewer/viewer/lib/simpleUtils.ts rename to renderer/viewer/lib/simpleUtils.ts index 3f17e5ad..2d0b6255 100644 --- a/prismarine-viewer/viewer/lib/simpleUtils.ts +++ b/renderer/viewer/lib/simpleUtils.ts @@ -1,14 +1,12 @@ -export function getBufferFromStream (stream) { - return new Promise( - (resolve, reject) => { - let buffer = Buffer.from([]) - stream.on('data', buf => { - buffer = Buffer.concat([buffer, buf]) - }) - stream.on('end', () => resolve(buffer)) - stream.on('error', reject) - } - ) +export async function getBufferFromStream (stream) { + return new Promise((resolve, reject) => { + let buffer = Buffer.from([]) + stream.on('data', buf => { + buffer = Buffer.concat([buffer, buf]) + }) + stream.on('end', () => resolve(buffer)) + stream.on('error', reject) + }) } export function openURL (url, newTab = true) { diff --git a/renderer/viewer/lib/smoothSwitcher.ts b/renderer/viewer/lib/smoothSwitcher.ts new file mode 100644 index 00000000..74eb1171 --- /dev/null +++ b/renderer/viewer/lib/smoothSwitcher.ts @@ -0,0 +1,168 @@ +import * as tweenJs from '@tweenjs/tween.js' +import { AnimationController } from './animationController' + +export type StateProperties = Record +export type StateGetterFn = () => StateProperties +export type StateSetterFn = (property: string, value: number) => void + +// Speed in units per second for each property type +const DEFAULT_SPEEDS = { + x: 3000, // pixels/units per second + y: 3000, + z: 3000, + rotation: Math.PI, // radians per second + scale: 1, // scale units per second + default: 3000 // default speed for unknown properties +} + +export class SmoothSwitcher { + private readonly animationController = new AnimationController() + // private readonly currentState: StateProperties = {} + private readonly defaultState: StateProperties + private readonly speeds: Record + public currentStateName = '' + public transitioningToStateName = '' + + constructor ( + public getState: StateGetterFn, + public setState: StateSetterFn, + speeds?: Partial> + ) { + + // Initialize speeds with defaults and overrides + this.speeds = { ...DEFAULT_SPEEDS } + if (speeds) { + Object.assign(this.speeds, speeds) + } + + // Store initial values + this.defaultState = this.getState() + } + + /** + * Calculate transition duration based on the largest property change + */ + private calculateDuration (newState: Partial): number { + let maxDuration = 0 + const currentState = this.getState() + + for (const [key, targetValue] of Object.entries(newState)) { + const currentValue = currentState[key] + const diff = Math.abs(targetValue! - currentValue) + const speed = this.getPropertySpeed(key) + const duration = (diff / speed) * 1000 // Convert to milliseconds + + maxDuration = Math.max(maxDuration, duration) + } + + // Ensure minimum duration of 50ms and maximum of 2000ms + return Math.min(Math.max(maxDuration, 200), 2000) + } + + private getPropertySpeed (property: string): number { + // Check for specific property speed + if (property in this.speeds) { + return this.speeds[property] + } + + // Check for property type (rotation, scale, etc.) + if (property.toLowerCase().includes('rotation')) return this.speeds.rotation + if (property.toLowerCase().includes('scale')) return this.speeds.scale + if (property.toLowerCase() === 'x' || property.toLowerCase() === 'y' || property.toLowerCase() === 'z') { + return this.speeds[property] + } + + return this.speeds.default + } + + /** + * Start a transition to a new state + * @param newState Partial state - only need to specify properties that change + * @param easing Easing function to use + */ + startTransition ( + newState: Partial, + stateName?: string, + onEnd?: () => void, + easing: (amount: number) => number = tweenJs.Easing.Linear.None, + onCancelled?: () => void + ): void { + if (this.isTransitioning) { + this.animationController.forceFinish(false) + } + + this.transitioningToStateName = stateName ?? '' + const state = this.getState() + + const duration = this.calculateDuration(newState) + // console.log('duration', duration, JSON.stringify(state), JSON.stringify(newState)) + + void this.animationController.startAnimation(() => { + const group = new tweenJs.Group() + new tweenJs.Tween(state, group) + .to(newState, duration) + .easing(easing) + .onUpdate((obj) => { + for (const key of Object.keys(obj)) { + this.setState(key, obj[key]) + } + }) + .onComplete(() => { + this.animationController.forceFinish() + this.currentStateName = this.transitioningToStateName + this.transitioningToStateName = '' + onEnd?.() + }) + .start() + return group + }, onCancelled) + } + + /** + * Reset to default state + */ + reset (): void { + this.startTransition(this.defaultState) + } + + + /** + * Update the animation (should be called in your render/update loop) + */ + update (): void { + this.animationController.update() + } + + /** + * Force finish the current transition + */ + forceFinish (): void { + this.animationController.forceFinish() + } + + /** + * Start a new transition to the specified state + */ + transitionTo ( + newState: Partial, + stateName?: string, + onEnd?: () => void, + onCancelled?: () => void + ): void { + this.startTransition(newState, stateName, onEnd, tweenJs.Easing.Linear.None, onCancelled) + } + + /** + * Get the current value of a property + */ + getCurrentValue (property: string): number { + return this.getState()[property] + } + + /** + * Check if currently transitioning + */ + get isTransitioning (): boolean { + return this.animationController.isActive + } +} diff --git a/renderer/viewer/lib/ui/newStats.ts b/renderer/viewer/lib/ui/newStats.ts new file mode 100644 index 00000000..4a1b0a0f --- /dev/null +++ b/renderer/viewer/lib/ui/newStats.ts @@ -0,0 +1,112 @@ +/* eslint-disable unicorn/prefer-dom-node-text-content */ +const rightOffset = 0 + +const stats = {} + +let lastY = 40 +export const addNewStat = (id: string, width = 80, x = rightOffset, y = lastY) => { + const pane = document.createElement('div') + pane.style.position = 'fixed' + pane.style.top = `${y ?? lastY}px` + pane.style.right = `${x}px` + // gray bg + pane.style.backgroundColor = 'rgba(0, 0, 0, 0.7)' + pane.style.color = 'white' + pane.style.padding = '2px' + pane.style.fontFamily = 'monospace' + pane.style.fontSize = '12px' + pane.style.zIndex = '100' + pane.style.pointerEvents = 'none' + document.body.appendChild(pane) + stats[id] = pane + if (y === undefined && x === rightOffset) { // otherwise it's a custom position + // rightOffset += width + lastY += 20 + } + + return { + updateText (text: string) { + if (pane.innerText === text) return + pane.innerText = text + }, + setVisibility (visible: boolean) { + pane.style.display = visible ? 'block' : 'none' + } + } +} + +export const addNewStat2 = (id: string, { top, bottom, right, left, displayOnlyWhenWider }: { top?: number, bottom?: number, right?: number, left?: number, displayOnlyWhenWider?: number }) => { + if (top === undefined && bottom === undefined) top = 0 + const pane = document.createElement('div') + pane.style.position = 'fixed' + if (top !== undefined) { + pane.style.top = `${top}px` + } + if (bottom !== undefined) { + pane.style.bottom = `${bottom}px` + } + if (left !== undefined) { + pane.style.left = `${left}px` + } + if (right !== undefined) { + pane.style.right = `${right}px` + } + // gray bg + pane.style.backgroundColor = 'rgba(0, 0, 0, 0.7)' + pane.style.color = 'white' + pane.style.padding = '2px' + pane.style.fontFamily = 'monospace' + pane.style.fontSize = '12px' + pane.style.zIndex = '10000' + pane.style.pointerEvents = 'none' + document.body.appendChild(pane) + stats[id] = pane + + const resizeCheck = () => { + if (!displayOnlyWhenWider) return + pane.style.display = window.innerWidth > displayOnlyWhenWider ? 'block' : 'none' + } + window.addEventListener('resize', resizeCheck) + resizeCheck() + + return { + updateText (text: string) { + pane.innerText = text + }, + setVisibility (visible: boolean) { + pane.style.display = visible ? 'block' : 'none' + } + } +} + +export const updateStatText = (id, text) => { + if (!stats[id]) return + stats[id].innerText = text +} + +export const updatePanesVisibility = (visible: boolean) => { + // eslint-disable-next-line guard-for-in + for (const id in stats) { + stats[id].style.display = visible ? 'block' : 'none' + } +} + +export const removeAllStats = () => { + // eslint-disable-next-line guard-for-in + for (const id in stats) { + removeStat(id) + } +} + +export const removeStat = (id) => { + if (!stats[id]) return + stats[id].remove() + delete stats[id] +} + +if (typeof customEvents !== 'undefined') { + customEvents.on('gameLoaded', () => { + const chunksLoaded = addNewStat('chunks-loaded', 80, 0, 0) + const chunksTotal = addNewStat('chunks-read', 80, 0, 0) + }) +} diff --git a/renderer/viewer/lib/utils.ts b/renderer/viewer/lib/utils.ts new file mode 100644 index 00000000..f471aa9d --- /dev/null +++ b/renderer/viewer/lib/utils.ts @@ -0,0 +1,57 @@ +export const loadScript = async function (scriptSrc: string, highPriority = true): Promise { + const existingScript = document.querySelector(`script[src="${scriptSrc}"]`) + if (existingScript) { + return existingScript + } + + return new Promise((resolve, reject) => { + const scriptElement = document.createElement('script') + scriptElement.src = scriptSrc + + if (highPriority) { + scriptElement.fetchPriority = 'high' + } + scriptElement.async = true + + scriptElement.addEventListener('load', () => { + resolve(scriptElement) + }) + + scriptElement.onerror = (error) => { + reject(new Error(typeof error === 'string' ? error : (error as any).message)) + scriptElement.remove() + } + + document.head.appendChild(scriptElement) + }) +} + +const detectFullOffscreenCanvasSupport = () => { + if (typeof OffscreenCanvas === 'undefined') return false + try { + const canvas = new OffscreenCanvas(1, 1) + // Try to get a WebGL context - this will fail on iOS where only 2D is supported (iOS 16) + const gl = canvas.getContext('webgl2') || canvas.getContext('webgl') + return gl !== null + } catch (e) { + return false + } +} + +const hasFullOffscreenCanvasSupport = detectFullOffscreenCanvasSupport() + +export const createCanvas = (width: number, height: number): OffscreenCanvas => { + if (hasFullOffscreenCanvasSupport) { + return new OffscreenCanvas(width, height) + } + const canvas = document.createElement('canvas') + canvas.width = width + canvas.height = height + return canvas as unknown as OffscreenCanvas // todo-low +} + +export async function loadImageFromUrl (imageUrl: string): Promise { + const response = await fetch(imageUrl) + const blob = await response.blob() + return createImageBitmap(blob) +} diff --git a/renderer/viewer/lib/utils/proxy.ts b/renderer/viewer/lib/utils/proxy.ts new file mode 100644 index 00000000..d30ceb7e --- /dev/null +++ b/renderer/viewer/lib/utils/proxy.ts @@ -0,0 +1,23 @@ +import { subscribeKey } from 'valtio/utils' + +// eslint-disable-next-line max-params +export function watchProperty, K> (asyncGetter: (value: T[keyof T]) => Promise, valtioProxy: T, key: keyof T, readySetter: (res: K) => void, cleanup?: (res: K) => void) { + let i = 0 + let lastRes: K | undefined + const request = async () => { + const req = ++i + const res = await asyncGetter(valtioProxy[key]) + if (req === i) { + if (lastRes) { + cleanup?.(lastRes) + } + readySetter(res) + lastRes = res + } else { + // rejected + cleanup?.(res) + } + } + void request() + return subscribeKey(valtioProxy, key, request) +} diff --git a/renderer/viewer/lib/utils/skins.ts b/renderer/viewer/lib/utils/skins.ts new file mode 100644 index 00000000..3163702c --- /dev/null +++ b/renderer/viewer/lib/utils/skins.ts @@ -0,0 +1,59 @@ +import { loadSkinToCanvas } from 'skinview-utils' +import { createCanvas, loadImageFromUrl } from '../utils' + +export { default as stevePngUrl } from 'mc-assets/dist/other-textures/latest/entity/player/wide/steve.png' + +const config = { + apiEnabled: true, +} + +export const setSkinsConfig = (newConfig: Partial) => { + Object.assign(config, newConfig) +} + +export async function loadSkinFromUsername (username: string, type: 'skin' | 'cape'): Promise { + if (!config.apiEnabled) return + + if (type === 'cape') return + const url = `https://playerdb.co/api/player/minecraft/${username}` + const response = await fetch(url) + if (!response.ok) return + + const data: { + data: { + player: { + skin_texture: string + } + } + } = await response.json() + return data.data.player.skin_texture +} + +export const parseSkinTexturesValue = (value: string) => { + const decodedData: { + textures: { + SKIN: { + url: string + } + } + } = JSON.parse(Buffer.from(value, 'base64').toString()) + return decodedData.textures?.SKIN?.url +} + +export async function loadSkinImage (skinUrl: string): Promise<{ canvas: OffscreenCanvas, image: ImageBitmap }> { + if (!skinUrl.startsWith('data:')) { + skinUrl = await fetchAndConvertBase64Skin(skinUrl.replace('http://', 'https://')) + } + + const image = await loadImageFromUrl(skinUrl) + const skinCanvas = createCanvas(64, 64) + loadSkinToCanvas(skinCanvas, image) + return { canvas: skinCanvas, image } +} + +const fetchAndConvertBase64Skin = async (skinUrl: string) => { + const response = await fetch(skinUrl, { }) + const arrayBuffer = await response.arrayBuffer() + const base64 = Buffer.from(arrayBuffer).toString('base64') + return `data:image/png;base64,${base64}` +} diff --git a/renderer/viewer/lib/workerProxy.ts b/renderer/viewer/lib/workerProxy.ts new file mode 100644 index 00000000..2b38dca9 --- /dev/null +++ b/renderer/viewer/lib/workerProxy.ts @@ -0,0 +1,92 @@ +import { proxy, getVersion, subscribe } from 'valtio' + +export function createWorkerProxy void | Promise>> (handlers: T, channel?: MessagePort): { __workerProxy: T } { + const target = channel ?? globalThis + target.addEventListener('message', (event: any) => { + const { type, args, msgId } = event.data + if (handlers[type]) { + const result = handlers[type](...args) + if (result instanceof Promise) { + void result.then((result) => { + target.postMessage({ + type: 'result', + msgId, + args: [result] + }) + }) + } + } + }) + return null as any +} + +/** + * in main thread + * ```ts + * // either: + * import type { importedTypeWorkerProxy } from './worker' + * // or: + * type importedTypeWorkerProxy = import('./worker').importedTypeWorkerProxy + * + * const workerChannel = useWorkerProxy(worker) + * ``` + */ +export const useWorkerProxy = void> }> (worker: Worker | MessagePort, autoTransfer = true): T['__workerProxy'] & { + transfer: (...args: Transferable[]) => T['__workerProxy'] +} => { + let messageId = 0 + // in main thread + return new Proxy({} as any, { + get (target, prop) { + if (prop === 'transfer') { + return (...transferable: Transferable[]) => { + return new Proxy({}, { + get (target, prop) { + return (...args: any[]) => { + worker.postMessage({ + type: prop, + args, + }, transferable) + } + } + }) + } + } + return (...args: any[]) => { + const msgId = messageId++ + const transfer = autoTransfer ? args.filter(arg => { + return arg instanceof ArrayBuffer || arg instanceof MessagePort + || (typeof ImageBitmap !== 'undefined' && arg instanceof ImageBitmap) + || (typeof OffscreenCanvas !== 'undefined' && arg instanceof OffscreenCanvas) + || (typeof ImageData !== 'undefined' && arg instanceof ImageData) + }) : [] + worker.postMessage({ + type: prop, + msgId, + args, + }, transfer) + return { + // eslint-disable-next-line unicorn/no-thenable + then (onfulfilled: (value: any) => void) { + const handler = ({ data }: MessageEvent): void => { + if (data.type === 'result' && data.msgId === msgId) { + onfulfilled(data.args[0]) + worker.removeEventListener('message', handler as EventListener) + } + } + worker.addEventListener('message', handler as EventListener) + } + } + } + } + }) +} + +// const workerProxy = createWorkerProxy({ +// startRender (canvas: HTMLCanvasElement) { +// }, +// }) + +// const worker = useWorkerProxy(null, workerProxy) + +// worker. diff --git a/renderer/viewer/lib/worldDataEmitter.ts b/renderer/viewer/lib/worldDataEmitter.ts new file mode 100644 index 00000000..dfbdb35c --- /dev/null +++ b/renderer/viewer/lib/worldDataEmitter.ts @@ -0,0 +1,431 @@ +/* eslint-disable guard-for-in */ + +// todo refactor into its own commons module +import { EventEmitter } from 'events' +import { generateSpiralMatrix, ViewRect } from 'flying-squid/dist/utils' +import { Vec3 } from 'vec3' +import { BotEvents } from 'mineflayer' +import { proxy } from 'valtio' +import TypedEmitter from 'typed-emitter' +import { Biome } from 'minecraft-data' +import { delayedIterator } from '../../playground/shared' +import { chunkPos } from './simpleUtils' + +export type ChunkPosKey = string // like '16,16' +type ChunkPos = { x: number, z: number } // like { x: 16, z: 16 } + +export type WorldDataEmitterEvents = { + chunkPosUpdate: (data: { pos: Vec3 }) => void + blockUpdate: (data: { pos: Vec3, stateId: number }) => void + entity: (data: any) => void + entityMoved: (data: any) => void + playerEntity: (data: any) => void + time: (data: number) => void + renderDistance: (viewDistance: number) => void + blockEntities: (data: Record | { blockEntities: Record }) => void + markAsLoaded: (data: { x: number, z: number }) => void + unloadChunk: (data: { x: number, z: number }) => void + loadChunk: (data: { x: number, z: number, chunk: string, blockEntities: any, worldConfig: any, isLightUpdate: boolean }) => void + updateLight: (data: { pos: Vec3 }) => void + onWorldSwitch: () => void + end: () => void + biomeUpdate: (data: { biome: Biome }) => void + biomeReset: () => void +} + +export class WorldDataEmitterWorker extends (EventEmitter as new () => TypedEmitter) { + static readonly restorerName = 'WorldDataEmitterWorker' +} + +export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter) { + spiralNumber = 0 + gotPanicLastTime = false + panicChunksReload = () => {} + loadedChunks: Record + private inLoading = false + private chunkReceiveTimes: number[] = [] + private lastChunkReceiveTime = 0 + public lastChunkReceiveTimeAvg = 0 + private panicTimeout?: NodeJS.Timeout + readonly lastPos: Vec3 + private eventListeners: Record = {} + private readonly emitter: WorldDataEmitter + debugChunksInfo: Record + // blockUpdates: number + }> = {} + + waitingSpiralChunksLoad = {} as Record void> + + addWaitTime = 1 + /* config */ keepChunksDistance = 0 + /* config */ isPlayground = false + /* config */ allowPositionUpdate = true + + constructor (public world: typeof __type_bot['world'], public viewDistance: number, position: Vec3 = new Vec3(0, 0, 0)) { + // eslint-disable-next-line constructor-super + super() + this.loadedChunks = {} + this.lastPos = new Vec3(0, 0, 0).update(position) + // todo + this.emitter = this + } + + setBlockStateId (position: Vec3, stateId: number) { + const val = this.world.setBlockStateId(position, stateId) as Promise | void + if (val) throw new Error('setBlockStateId returned promise (not supported)') + // const chunkX = Math.floor(position.x / 16) + // const chunkZ = Math.floor(position.z / 16) + // if (!this.loadedChunks[`${chunkX},${chunkZ}`] && !this.waitingSpiralChunksLoad[`${chunkX},${chunkZ}`]) { + // void this.loadChunk({ x: chunkX, z: chunkZ }) + // return + // } + + this.emit('blockUpdate', { pos: position, stateId }) + } + + updateViewDistance (viewDistance: number) { + this.viewDistance = viewDistance + this.emitter.emit('renderDistance', viewDistance) + } + + listenToBot (bot: typeof __type_bot) { + const entitiesObjectData = new Map() + bot._client.prependListener('spawn_entity', (data) => { + if (data.objectData && data.entityId !== undefined) { + entitiesObjectData.set(data.entityId, data.objectData) + } + }) + + const emitEntity = (e, name = 'entity') => { + if (!e) return + if (e === bot.entity) { + if (name === 'entity') { + this.emitter.emit('playerEntity', e) + } + return + } + if (!e.name) return // mineflayer received update for not spawned entity + e.objectData = entitiesObjectData.get(e.id) + this.emitter.emit(name as any, { + ...e, + pos: e.position, + username: e.username, + team: bot.teamMap[e.username] || bot.teamMap[e.uuid], + // set debugTree (obj) { + // e.debugTree = obj + // } + }) + } + + this.eventListeners = { + // 'move': botPosition, + entitySpawn (e: any) { + if (e.name === 'item_frame' || e.name === 'glow_item_frame') { + // Item frames use block positions in the protocol, not their center. Fix that. + e.position.translate(0.5, 0.5, 0.5) + } + emitEntity(e) + }, + entityUpdate (e: any) { + emitEntity(e) + }, + entityEquip (e: any) { + emitEntity(e) + }, + entityMoved (e: any) { + emitEntity(e, 'entityMoved') + }, + entityGone: (e: any) => { + this.emitter.emit('entity', { id: e.id, delete: true }) + }, + chunkColumnLoad: (pos: Vec3) => { + const now = performance.now() + if (this.lastChunkReceiveTime) { + this.chunkReceiveTimes.push(now - this.lastChunkReceiveTime) + } + this.lastChunkReceiveTime = now + + if (this.waitingSpiralChunksLoad[`${pos.x},${pos.z}`]) { + this.waitingSpiralChunksLoad[`${pos.x},${pos.z}`](true) + delete this.waitingSpiralChunksLoad[`${pos.x},${pos.z}`] + } else if (this.loadedChunks[`${pos.x},${pos.z}`]) { + void this.loadChunk(pos, false, 'Received another chunkColumnLoad event while already loaded') + } + this.chunkProgress() + }, + chunkColumnUnload: (pos: Vec3) => { + this.unloadChunk(pos) + }, + blockUpdate: (oldBlock: any, newBlock: any) => { + const stateId = newBlock.stateId ?? ((newBlock.type << 4) | newBlock.metadata) + this.emitter.emit('blockUpdate', { pos: oldBlock.position, stateId }) + }, + time: () => { + this.emitter.emit('time', bot.time.timeOfDay) + }, + end: () => { + this.emitter.emit('end') + }, + // when dimension might change + login: () => { + void this.updatePosition(bot.entity.position, true) + this.emitter.emit('playerEntity', bot.entity) + }, + respawn: () => { + void this.updatePosition(bot.entity.position, true) + this.emitter.emit('playerEntity', bot.entity) + this.emitter.emit('onWorldSwitch') + }, + } satisfies Partial + + + bot._client.on('update_light', ({ chunkX, chunkZ }) => { + const chunkPos = new Vec3(chunkX * 16, 0, chunkZ * 16) + if (!this.waitingSpiralChunksLoad[`${chunkX},${chunkZ}`] && this.loadedChunks[`${chunkX},${chunkZ}`]) { + void this.loadChunk(chunkPos, true, 'update_light') + } + }) + + for (const [evt, listener] of Object.entries(this.eventListeners)) { + bot.on(evt as any, listener) + } + + for (const id in bot.entities) { + const e = bot.entities[id] + try { + emitEntity(e) + } catch (err) { + // reportError?.(err) + console.error('error processing entity', err) + } + } + } + + emitterGotConnected () { + this.emitter.emit('blockEntities', new Proxy({}, { + 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 + }, + })) + } + + removeListenersFromBot (bot: import('mineflayer').Bot) { + for (const [evt, listener] of Object.entries(this.eventListeners)) { + bot.removeListener(evt as any, listener) + } + } + + async init (pos: Vec3) { + this.updateViewDistance(this.viewDistance) + this.emitter.emit('chunkPosUpdate', { pos }) + if (bot?.time?.timeOfDay) { + this.emitter.emit('time', bot.time.timeOfDay) + } + if (bot?.entity) { + this.emitter.emit('playerEntity', bot.entity) + } + this.emitterGotConnected() + const [botX, botZ] = chunkPos(pos) + + const positions = generateSpiralMatrix(this.viewDistance).map(([x, z]) => new Vec3((botX + x) * 16, 0, (botZ + z) * 16)) + + this.lastPos.update(pos) + await this._loadChunks(positions, pos) + } + + chunkProgress () { + if (this.panicTimeout) clearTimeout(this.panicTimeout) + if (this.chunkReceiveTimes.length >= 5) { + const avgReceiveTime = this.chunkReceiveTimes.reduce((a, b) => a + b, 0) / this.chunkReceiveTimes.length + this.lastChunkReceiveTimeAvg = avgReceiveTime + const timeoutDelay = avgReceiveTime * 2 + 1000 // 2x average + 1 second + + // Clear any existing timeout + if (this.panicTimeout) clearTimeout(this.panicTimeout) + + // Set new timeout for panic reload + this.panicTimeout = setTimeout(() => { + if (!this.gotPanicLastTime && this.inLoading) { + console.warn('Chunk loading seems stuck, triggering panic reload') + this.gotPanicLastTime = true + this.panicChunksReload() + } + }, timeoutDelay) + } + } + + async _loadChunks (positions: Vec3[], centerPos: Vec3) { + this.spiralNumber++ + const { spiralNumber } = this + // stop loading previous chunks + for (const pos of Object.keys(this.waitingSpiralChunksLoad)) { + this.waitingSpiralChunksLoad[pos](false) + delete this.waitingSpiralChunksLoad[pos] + } + + let continueLoading = true + this.inLoading = true + await delayedIterator(positions, this.addWaitTime, async (pos) => { + if (!continueLoading || this.loadedChunks[`${pos.x},${pos.z}`]) return + + // Wait for chunk to be available from server + if (!this.world.getColumnAt(pos)) { + continueLoading = await new Promise(resolve => { + this.waitingSpiralChunksLoad[`${pos.x},${pos.z}`] = resolve + }) + } + if (!continueLoading) return + await this.loadChunk(pos, undefined, `spiral ${spiralNumber} from ${centerPos.x},${centerPos.z}`) + this.chunkProgress() + }) + if (this.panicTimeout) clearTimeout(this.panicTimeout) + this.inLoading = false + this.gotPanicLastTime = false + this.chunkReceiveTimes = [] + this.lastChunkReceiveTime = 0 + } + + readdDebug () { + const clonedLoadedChunks = { ...this.loadedChunks } + this.unloadAllChunks() + console.time('readdDebug') + for (const loadedChunk in clonedLoadedChunks) { + const [x, z] = loadedChunk.split(',').map(Number) + void this.loadChunk(new Vec3(x, 0, z)) + } + const interval = setInterval(() => { + if (appViewer.rendererState.world.allChunksLoaded) { + clearInterval(interval) + console.timeEnd('readdDebug') + } + }, 100) + } + + // debugGotChunkLatency = [] as number[] + // lastTime = 0 + + async loadChunk (pos: ChunkPos, isLightUpdate = false, reason = 'spiral') { + 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)) + if (dx <= this.viewDistance && dz <= this.viewDistance) { + // eslint-disable-next-line @typescript-eslint/await-thenable -- todo allow to use async world provider but not sure if needed + const column = await this.world.getColumnAt(pos['y'] ? pos as Vec3 : new Vec3(pos.x, 0, pos.z)) + if (column) { + // const latency = Math.floor(performance.now() - this.lastTime) + // this.debugGotChunkLatency.push(latency) + // this.lastTime = performance.now() + // todo optimize toJson data, make it clear why it is used + const chunk = column.toJson() + // TODO: blockEntities + const worldConfig = { + minY: column['minY'] ?? 0, + worldHeight: column['worldHeight'] ?? 256, + } + //@ts-expect-error + this.emitter.emit('loadChunk', { x: pos.x, z: pos.z, chunk, blockEntities: column.blockEntities, worldConfig, isLightUpdate }) + this.loadedChunks[`${pos.x},${pos.z}`] = true + + this.debugChunksInfo[`${pos.x},${pos.z}`] ??= { + loads: [] + } + this.debugChunksInfo[`${pos.x},${pos.z}`].loads.push({ + dataLength: chunk.length, + reason, + time: Date.now(), + }) + } else if (this.isPlayground) { // don't allow in real worlds pre-flag chunks as loaded to avoid race condition when the chunk might still be loading. In playground it's assumed we always pre-load all chunks first + this.emitter.emit('markAsLoaded', { x: pos.x, z: pos.z }) + } + } else { + // console.debug('skipped loading chunk', dx, dz, '>', this.viewDistance) + } + } + + unloadAllChunks () { + for (const coords of Object.keys(this.loadedChunks)) { + const [x, z] = coords.split(',').map(Number) + this.unloadChunk({ x, z }) + } + } + + unloadChunk (pos: ChunkPos) { + this.emitter.emit('unloadChunk', { x: pos.x, z: pos.z }) + delete this.loadedChunks[`${pos.x},${pos.z}`] + delete this.debugChunksInfo[`${pos.x},${pos.z}`] + } + + lastBiomeId: number | null = null + + udpateBiome (pos: Vec3) { + try { + const biomeId = this.world.getBiome(pos) + if (biomeId !== this.lastBiomeId) { + this.lastBiomeId = biomeId + const biomeData = loadedData.biomes[biomeId] + if (biomeData) { + this.emitter.emit('biomeUpdate', { + biome: biomeData + }) + } else { + // unknown biome + this.emitter.emit('biomeReset') + } + } + } catch (e) { + console.error('error updating biome', e) + } + } + + lastPosCheck: Vec3 | null = null + async updatePosition (pos: Vec3, force = false) { + if (!this.allowPositionUpdate) return + const posFloored = pos.floored() + if (!force && this.lastPosCheck && this.lastPosCheck.equals(posFloored)) return + this.lastPosCheck = posFloored + + this.udpateBiome(pos) + + const [lastX, lastZ] = chunkPos(this.lastPos) + const [botX, botZ] = chunkPos(pos) + if (lastX !== botX || lastZ !== botZ || force) { + this.emitter.emit('chunkPosUpdate', { pos }) + + // unload chunks that are no longer in view + const newViewToUnload = new ViewRect(botX, botZ, this.viewDistance + this.keepChunksDistance) + const chunksToUnload: Vec3[] = [] + for (const coords of Object.keys(this.loadedChunks)) { + const x = parseInt(coords.split(',')[0], 10) + const z = parseInt(coords.split(',')[1], 10) + const p = new Vec3(x, 0, z) + const [chunkX, chunkZ] = chunkPos(p) + if (!newViewToUnload.contains(chunkX, chunkZ)) { + chunksToUnload.push(p) + } + } + for (const p of chunksToUnload) { + this.unloadChunk(p) + } + + // load new chunks + 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(a => !!a) + this.lastPos.update(pos) + void this._loadChunks(positions, pos) + } else { + this.emitter.emit('chunkPosUpdate', { pos }) // todo-low + this.lastPos.update(pos) + } + } +} diff --git a/renderer/viewer/lib/worldrendererCommon.ts b/renderer/viewer/lib/worldrendererCommon.ts new file mode 100644 index 00000000..4140e3fa --- /dev/null +++ b/renderer/viewer/lib/worldrendererCommon.ts @@ -0,0 +1,1087 @@ +/* eslint-disable guard-for-in */ +import { EventEmitter } from 'events' +import { Vec3 } from 'vec3' +import mcDataRaw from 'minecraft-data/data.js' // note: using alias +import TypedEmitter from 'typed-emitter' +import { WorldBlockProvider } from 'mc-assets/dist/worldBlockProvider' +import { generateSpiralMatrix } from 'flying-squid/dist/utils' +import { subscribeKey } from 'valtio/utils' +import { proxy } from 'valtio' +import { dynamicMcDataFiles } from '../../buildMesherConfig.mjs' +import type { ResourcesManagerTransferred } from '../../../src/resourcesManager' +import { DisplayWorldOptions, GraphicsInitOptions, RendererReactiveState } from '../../../src/appViewer' +import { SoundSystem } from '../three/threeJsSound' +import { buildCleanupDecorator } from './cleanupDecorator' +import { HighestBlockInfo, CustomBlockModels, BlockStateModelInfo, getBlockAssetsCacheKey, MesherConfig, MesherMainEvent } from './mesher/shared' +import { chunkPos } from './simpleUtils' +import { addNewStat, removeAllStats, updatePanesVisibility, updateStatText } from './ui/newStats' +import { WorldDataEmitterWorker } from './worldDataEmitter' +import { getPlayerStateUtils, PlayerStateReactive, PlayerStateRenderer, PlayerStateUtils } from './basePlayerState' +import { MesherLogReader } from './mesherlogReader' +import { setSkinsConfig } from './utils/skins' + +function mod (x, n) { + return ((x % n) + n) % n +} + +const toMajorVersion = version => { + const [a, b] = (String(version)).split('.') + return `${a}.${b}` +} + +export const worldCleanup = buildCleanupDecorator('resetWorld') + +export const defaultWorldRendererConfig = { + // Debug settings + showChunkBorders: false, + enableDebugOverlay: false, + + // Performance settings + mesherWorkers: 4, + addChunksBatchWaitTime: 200, + _experimentalSmoothChunkLoading: true, + _renderByChunks: false, + + // Rendering engine settings + dayCycle: true, + smoothLighting: true, + enableLighting: true, + starfield: true, + defaultSkybox: true, + renderEntities: true, + extraBlockRenderers: true, + foreground: true, + fov: 75, + volume: 1, + + // Camera visual related settings + showHand: false, + viewBobbing: false, + renderEars: true, + highlightBlockColor: 'blue', + + // Player models + fetchPlayerSkins: true, + skinTexturesProxy: undefined as string | undefined, + + // VR settings + vrSupport: true, + vrPageGameRendering: true, + + // World settings + clipWorldBelowY: undefined as number | undefined, + isPlayground: false +} + +export type WorldRendererConfig = typeof defaultWorldRendererConfig + +export abstract class WorldRendererCommon { + worldReadyResolvers = Promise.withResolvers() + worldReadyPromise = this.worldReadyResolvers.promise + timeOfTheDay = 0 + worldSizeParams = { minY: 0, worldHeight: 256 } + reactiveDebugParams = proxy({ + stopRendering: false, + chunksRenderAboveOverride: undefined as number | undefined, + chunksRenderAboveEnabled: false, + chunksRenderBelowOverride: undefined as number | undefined, + chunksRenderBelowEnabled: false, + chunksRenderDistanceOverride: undefined as number | undefined, + chunksRenderDistanceEnabled: false, + disableEntities: false, + // disableParticles: false + }) + + active = false + + // #region CHUNK & SECTIONS TRACKING + @worldCleanup() + loadedChunks = {} as Record // data is added for these chunks and they might be still processing + + @worldCleanup() + finishedChunks = {} as Record // these chunks are fully loaded into the world (scene) + + @worldCleanup() + finishedSections = {} as Record // these sections are fully loaded into the world (scene) + + @worldCleanup() + // loading sections (chunks) + sectionsWaiting = new Map() + + @worldCleanup() + queuedChunks = new Set() + queuedFunctions = [] as Array<() => void> + // #endregion + + renderUpdateEmitter = new EventEmitter() as unknown as TypedEmitter<{ + dirty (pos: Vec3, value: boolean): void + update (/* pos: Vec3, value: boolean */): void + chunkFinished (key: string): void + heightmap (key: string, heightmap: Uint8Array): void + }> + customTexturesDataUrl = undefined as string | undefined + workers: any[] = [] + viewerChunkPosition?: Vec3 + lastCamUpdate = 0 + droppedFpsPercentage = 0 + initialChunkLoadWasStartedIn: number | undefined + initialChunksLoad = true + enableChunksLoadDelay = false + texturesVersion?: string + viewDistance = -1 + chunksLength = 0 + allChunksFinished = false + messageQueue: any[] = [] + isProcessingQueue = false + ONMESSAGE_TIME_LIMIT = 30 // ms + + handleResize = () => { } + highestBlocksByChunks = new Map() + blockEntities = {} + + workersProcessAverageTime = 0 + workersProcessAverageTimeCount = 0 + maxWorkersProcessTime = 0 + geometryReceiveCount = {} as Record + allLoadedIn: undefined | number + onWorldSwitched = [] as Array<() => void> + renderTimeMax = 0 + renderTimeAvg = 0 + renderTimeAvgCount = 0 + edgeChunks = {} as Record + lastAddChunk = null as null | { + timeout: any + x: number + z: number + } + neighborChunkUpdates = true + lastChunkDistance = 0 + debugStopGeometryUpdate = false + + protocolCustomBlocks = new Map() + + @worldCleanup() + blockStateModelInfo = new Map() + + abstract outputFormat: 'threeJs' | 'webgpu' + worldBlockProvider: WorldBlockProvider + soundSystem: SoundSystem | undefined + + abstract changeBackgroundColor (color: [number, number, number]): void + + worldRendererConfig: WorldRendererConfig + playerStateReactive: PlayerStateReactive + playerStateUtils: PlayerStateUtils + reactiveState: RendererReactiveState + mesherLogReader: MesherLogReader | undefined + forceCallFromMesherReplayer = false + stopMesherMessagesProcessing = false + + abortController = new AbortController() + lastRendered = 0 + renderingActive = true + geometryReceiveCountPerSec = 0 + mesherLogger = { + contents: [] as string[], + active: new URL(location.href).searchParams.get('mesherlog') === 'true' + } + currentRenderedFrames = 0 + fpsAverage = 0 + lastFps = 0 + fpsWorst = undefined as number | undefined + fpsSamples = 0 + mainThreadRendering = true + backendInfoReport = '-' + chunksFullInfo = '-' + workerCustomHandleTime = 0 + + get version () { + return this.displayOptions.version + } + + get displayAdvancedStats () { + return (this.initOptions.config.statsVisible ?? 0) > 1 + } + + constructor (public readonly resourcesManager: ResourcesManagerTransferred, public displayOptions: DisplayWorldOptions, public initOptions: GraphicsInitOptions) { + this.snapshotInitialValues() + this.worldRendererConfig = displayOptions.inWorldRenderingConfig + this.playerStateReactive = displayOptions.playerStateReactive + this.playerStateUtils = getPlayerStateUtils(this.playerStateReactive) + this.reactiveState = displayOptions.rendererState + // this.mesherLogReader = new MesherLogReader(this) + this.renderUpdateEmitter.on('update', () => { + const loadedChunks = Object.keys(this.finishedChunks).length + updateStatText('loaded-chunks', `${loadedChunks}/${this.chunksLength} chunks (${this.lastChunkDistance}/${this.viewDistance})`) + }) + + addNewStat('downloaded-chunks', 100, 140, 20) + + this.connect(this.displayOptions.worldView) + + const interval = setInterval(() => { + this.geometryReceiveCountPerSec = Object.values(this.geometryReceiveCount).reduce((acc, curr) => acc + curr, 0) + this.geometryReceiveCount = {} + updatePanesVisibility(this.displayAdvancedStats) + this.updateChunksStats() + if (this.mainThreadRendering) { + this.fpsUpdate() + } + }, 500) + this.abortController.signal.addEventListener('abort', () => { + clearInterval(interval) + }) + } + + fpsUpdate () { + this.fpsSamples++ + this.fpsAverage = (this.fpsAverage * (this.fpsSamples - 1) + this.currentRenderedFrames) / this.fpsSamples + if (this.fpsWorst === undefined) { + this.fpsWorst = this.currentRenderedFrames + } else { + this.fpsWorst = Math.min(this.fpsWorst, this.currentRenderedFrames) + } + this.lastFps = this.currentRenderedFrames + this.currentRenderedFrames = 0 + } + + logWorkerWork (message: string | (() => string)) { + if (!this.mesherLogger.active) return + this.mesherLogger.contents.push(typeof message === 'function' ? message() : message) + } + + async init () { + if (this.active) throw new Error('WorldRendererCommon is already initialized') + + await Promise.all([ + this.resetWorkers(), + (async () => { + if (this.resourcesManager.currentResources?.allReady) { + await this.updateAssetsData() + } + })() + ]) + + this.resourcesManager.on('assetsTexturesUpdated', async () => { + if (!this.active) return + await this.updateAssetsData() + }) + + this.watchReactivePlayerState() + this.watchReactiveConfig() + this.worldReadyResolvers.resolve() + } + + snapshotInitialValues () { } + + wasChunkSentToWorker (chunkKey: string) { + return this.loadedChunks[chunkKey] + } + + async getHighestBlocks (chunkKey: string) { + return this.highestBlocksByChunks.get(chunkKey) + } + + updateCustomBlock (chunkKey: string, blockPos: string, model: string) { + this.protocolCustomBlocks.set(chunkKey, { + ...this.protocolCustomBlocks.get(chunkKey), + [blockPos]: model + }) + this.logWorkerWork(() => `-> updateCustomBlock ${chunkKey} ${blockPos} ${model} ${this.wasChunkSentToWorker(chunkKey)}`) + if (this.wasChunkSentToWorker(chunkKey)) { + const [x, y, z] = blockPos.split(',').map(Number) + this.setBlockStateId(new Vec3(x, y, z), undefined) + } + } + + async getBlockInfo (blockPos: { x: number, y: number, z: number }, stateId: number) { + const chunkKey = `${Math.floor(blockPos.x / 16) * 16},${Math.floor(blockPos.z / 16) * 16}` + const customBlockName = this.protocolCustomBlocks.get(chunkKey)?.[`${blockPos.x},${blockPos.y},${blockPos.z}`] + const cacheKey = getBlockAssetsCacheKey(stateId, customBlockName) + const modelInfo = this.blockStateModelInfo.get(cacheKey) + return { + customBlockName, + modelInfo + } + } + + initWorkers (numWorkers = this.worldRendererConfig.mesherWorkers) { + // init workers + for (let i = 0; i < numWorkers + 1; i++) { + const worker = initMesherWorker((data) => { + if (Array.isArray(data)) { + this.messageQueue.push(...data) + } else { + this.messageQueue.push(data) + } + void this.processMessageQueue('worker') + }) + this.workers.push(worker) + } + } + + onReactivePlayerStateUpdated(key: T, callback: (value: PlayerStateReactive[T]) => void, initial = true) { + if (initial) { + callback(this.playerStateReactive[key]) + } + subscribeKey(this.playerStateReactive, key, callback) + } + + onReactiveConfigUpdated(key: T, callback: (value: typeof this.worldRendererConfig[T]) => void) { + callback(this.worldRendererConfig[key]) + subscribeKey(this.worldRendererConfig, key, callback) + } + + onReactiveDebugUpdated(key: T, callback: (value: typeof this.reactiveDebugParams[T]) => void) { + callback(this.reactiveDebugParams[key]) + subscribeKey(this.reactiveDebugParams, key, callback) + } + + watchReactivePlayerState () { + this.onReactivePlayerStateUpdated('backgroundColor', (value) => { + this.changeBackgroundColor(value) + }) + } + + watchReactiveConfig () { + this.onReactiveConfigUpdated('fetchPlayerSkins', (value) => { + setSkinsConfig({ apiEnabled: value }) + }) + } + + async processMessageQueue (source: string) { + if (this.isProcessingQueue || this.messageQueue.length === 0) return + this.logWorkerWork(`# ${source} processing queue`) + if (this.lastRendered && performance.now() - this.lastRendered > this.ONMESSAGE_TIME_LIMIT && this.worldRendererConfig._experimentalSmoothChunkLoading && this.renderingActive) { + const start = performance.now() + await new Promise(resolve => { + requestAnimationFrame(resolve) + }) + this.logWorkerWork(`# processing got delayed by ${performance.now() - start}ms`) + } + this.isProcessingQueue = true + + const startTime = performance.now() + let processedCount = 0 + + while (this.messageQueue.length > 0) { + const processingStopped = this.stopMesherMessagesProcessing + if (!processingStopped) { + const data = this.messageQueue.shift()! + this.handleMessage(data) + processedCount++ + } + + // Check if we've exceeded the time limit + if (processingStopped || (performance.now() - startTime > this.ONMESSAGE_TIME_LIMIT && this.renderingActive && this.worldRendererConfig._experimentalSmoothChunkLoading)) { + // If we have more messages and exceeded time limit, schedule next batch + if (this.messageQueue.length > 0) { + requestAnimationFrame(async () => { + this.isProcessingQueue = false + void this.processMessageQueue('queue-delay') + }) + return + } + break + } + } + + this.isProcessingQueue = false + } + + handleMessage (rawData: any) { + const data = rawData as MesherMainEvent + if (!this.active) return + this.mesherLogReader?.workerMessageReceived(data.type, data) + if (data.type !== 'geometry' || !this.debugStopGeometryUpdate) { + const start = performance.now() + this.handleWorkerMessage(data as WorkerReceive) + this.workerCustomHandleTime += performance.now() - start + } + if (data.type === 'geometry') { + this.logWorkerWork(() => `-> ${data.workerIndex} geometry ${data.key} ${JSON.stringify({ dataSize: JSON.stringify(data).length })}`) + this.geometryReceiveCount[data.workerIndex] ??= 0 + this.geometryReceiveCount[data.workerIndex]++ + const chunkCoords = data.key.split(',').map(Number) + this.lastChunkDistance = Math.max(...this.getDistance(new Vec3(chunkCoords[0], 0, chunkCoords[2]))) + } + if (data.type === 'sectionFinished') { // on after load & unload section + this.logWorkerWork(`<- ${data.workerIndex} sectionFinished ${data.key} ${JSON.stringify({ processTime: data.processTime })}`) + if (!this.sectionsWaiting.has(data.key)) throw new Error(`sectionFinished event for non-outstanding section ${data.key}`) + this.sectionsWaiting.set(data.key, this.sectionsWaiting.get(data.key)! - 1) + if (this.sectionsWaiting.get(data.key) === 0) { + this.sectionsWaiting.delete(data.key) + this.finishedSections[data.key] = true + } + + const chunkCoords = data.key.split(',').map(Number) + const chunkKey = `${chunkCoords[0]},${chunkCoords[2]}` + if (this.loadedChunks[chunkKey]) { // ensure chunk data was added, not a neighbor chunk update + let loaded = true + for (let y = this.worldMinYRender; y < this.worldSizeParams.worldHeight; y += 16) { + if (!this.finishedSections[`${chunkCoords[0]},${y},${chunkCoords[2]}`]) { + loaded = false + break + } + } + if (loaded) { + // CHUNK FINISHED + this.finishedChunks[chunkKey] = true + this.reactiveState.world.chunksLoaded.add(`${Math.floor(chunkCoords[0] / 16)},${Math.floor(chunkCoords[2] / 16)}`) + this.renderUpdateEmitter.emit(`chunkFinished`, `${chunkCoords[0]},${chunkCoords[2]}`) + this.checkAllFinished() + // merge highest blocks by sections into highest blocks by chunks + // for (let y = this.worldMinYRender; y < this.worldSizeParams.worldHeight; y += 16) { + // const sectionKey = `${chunkCoords[0]},${y},${chunkCoords[2]}` + // for (let x = 0; x < 16; x++) { + // for (let z = 0; z < 16; z++) { + // const posInsideKey = `${chunkCoords[0] + x},${chunkCoords[2] + z}` + // let block = null as HighestBlockInfo | null + // const highestBlock = this.highestBlocksBySections[sectionKey]?.[posInsideKey] + // if (!highestBlock) continue + // if (!block || highestBlock.y > block.y) { + // block = highestBlock + // } + // if (block) { + // this.highestBlocksByChunks[chunkKey] ??= {} + // this.highestBlocksByChunks[chunkKey][posInsideKey] = block + // } + // } + // } + // delete this.highestBlocksBySections[sectionKey] + // } + } + } + + this.renderUpdateEmitter.emit('update') + if (data.processTime) { + this.workersProcessAverageTimeCount++ + this.workersProcessAverageTime = ((this.workersProcessAverageTime * (this.workersProcessAverageTimeCount - 1)) + data.processTime) / this.workersProcessAverageTimeCount + this.maxWorkersProcessTime = Math.max(this.maxWorkersProcessTime, data.processTime) + } + } + + if (data.type === 'blockStateModelInfo') { + for (const [cacheKey, info] of Object.entries(data.info)) { + this.blockStateModelInfo.set(cacheKey, info) + } + } + + if (data.type === 'heightmap') { + this.reactiveState.world.heightmaps.set(data.key, new Uint8Array(data.heightmap)) + } + } + + downloadMesherLog () { + const a = document.createElement('a') + a.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(this.mesherLogger.contents.join('\n')) + a.download = 'mesher.log' + a.click() + } + + checkAllFinished () { + if (this.sectionsWaiting.size === 0) { + this.reactiveState.world.mesherWork = false + } + // todo check exact surrounding chunks + const allFinished = Object.keys(this.finishedChunks).length >= this.chunksLength + if (allFinished) { + this.allChunksLoaded?.() + this.allChunksFinished = true + this.allLoadedIn ??= Date.now() - this.initialChunkLoadWasStartedIn! + } + this.updateChunksStats() + } + + changeHandSwingingState (isAnimationPlaying: boolean, isLeftHand: boolean): void { } + + abstract handleWorkerMessage (data: WorkerReceive): void + + abstract updateCamera (pos: Vec3 | null, yaw: number, pitch: number): void + + abstract render (): void + + /** + * Optionally update data that are depedendent on the viewer position + */ + updatePosDataChunk? (key: string): void + + allChunksLoaded? (): void + + timeUpdated? (newTime: number): void + + biomeUpdated? (biome: any): void + + biomeReset? (): void + + updateViewerPosition (pos: Vec3) { + this.viewerChunkPosition = pos + for (const [key, value] of Object.entries(this.loadedChunks)) { + if (!value) continue + this.updatePosDataChunk?.(key) + } + } + + sendWorkers (message: WorkerSend) { + for (const worker of this.workers) { + worker.postMessage(message) + } + } + + getDistance (posAbsolute: Vec3) { + const [botX, botZ] = chunkPos(this.viewerChunkPosition!) + const dx = Math.abs(botX - Math.floor(posAbsolute.x / 16)) + const dz = Math.abs(botZ - Math.floor(posAbsolute.z / 16)) + return [dx, dz] as [number, number] + } + + abstract updateShowChunksBorder (value: boolean): void + + resetWorld () { + // destroy workers + for (const worker of this.workers) { + worker.terminate() + } + this.workers = [] + } + + async resetWorkers () { + this.resetWorld() + + // for workers in single file build + if (typeof document !== 'undefined' && document?.readyState === 'loading') { + await new Promise(resolve => { + document.addEventListener('DOMContentLoaded', resolve) + }) + } + + this.initWorkers() + this.active = true + + this.sendMesherMcData() + } + + getMesherConfig (): MesherConfig { + let skyLight = 15 + const timeOfDay = this.timeOfTheDay + if (timeOfDay < 0 || timeOfDay > 24_000) { + // + } else if (timeOfDay <= 6000 || timeOfDay >= 18_000) { + skyLight = 15 + } else if (timeOfDay > 6000 && timeOfDay < 12_000) { + skyLight = 15 - ((timeOfDay - 6000) / 6000) * 15 + } else if (timeOfDay >= 12_000 && timeOfDay < 18_000) { + skyLight = ((timeOfDay - 12_000) / 6000) * 15 + } + + skyLight = Math.floor(skyLight) + return { + version: this.version, + enableLighting: this.worldRendererConfig.enableLighting, + skyLight, + smoothLighting: this.worldRendererConfig.smoothLighting, + outputFormat: this.outputFormat, + // textureSize: this.resourcesManager.currentResources!.blocksAtlasParser.atlas.latest.width, + debugModelVariant: undefined, + clipWorldBelowY: this.worldRendererConfig.clipWorldBelowY, + disableSignsMapsSupport: !this.worldRendererConfig.extraBlockRenderers, + worldMinY: this.worldMinYRender, + worldMaxY: this.worldMinYRender + this.worldSizeParams.worldHeight, + } + } + + sendMesherMcData () { + const allMcData = mcDataRaw.pc[this.version] ?? mcDataRaw.pc[toMajorVersion(this.version)] + const mcData = { + version: JSON.parse(JSON.stringify(allMcData.version)) + } + for (const key of dynamicMcDataFiles) { + mcData[key] = allMcData[key] + } + + for (const worker of this.workers) { + worker.postMessage({ type: 'mcData', mcData, config: this.getMesherConfig() }) + } + this.logWorkerWork('# mcData sent') + } + + async updateAssetsData () { + const resources = this.resourcesManager.currentResources + + if (this.workers.length === 0) throw new Error('workers not initialized yet') + for (const [i, worker] of this.workers.entries()) { + const { blockstatesModels } = resources + + worker.postMessage({ + type: 'mesherData', + workerIndex: i, + blocksAtlas: { + latest: resources.blocksAtlasJson + }, + blockstatesModels, + config: this.getMesherConfig(), + }) + } + + this.logWorkerWork('# mesherData sent') + console.log('textures loaded') + } + + get worldMinYRender () { + return Math.floor(Math.max(this.worldSizeParams.minY, this.worldRendererConfig.clipWorldBelowY ?? -Infinity) / 16) * 16 + } + + updateChunksStats () { + const loadedChunks = Object.keys(this.finishedChunks) + this.displayOptions.nonReactiveState.world.chunksLoaded = new Set(loadedChunks) + this.displayOptions.nonReactiveState.world.chunksTotalNumber = this.chunksLength + this.reactiveState.world.allChunksLoaded = this.allChunksFinished + + const text = `Q: ${this.messageQueue.length} ${Object.keys(this.loadedChunks).length}/${Object.keys(this.finishedChunks).length}/${this.chunksLength} chunks (${this.workers.length}:${this.workersProcessAverageTime.toFixed(0)}ms/${this.geometryReceiveCountPerSec}ss/${this.allLoadedIn?.toFixed(1) ?? '-'}s)` + this.chunksFullInfo = text + updateStatText('downloaded-chunks', text) + } + + 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.initialChunkLoadWasStartedIn ??= Date.now() + this.loadedChunks[`${x},${z}`] = true + this.updateChunksStats() + + const chunkKey = `${x},${z}` + const customBlockModels = this.protocolCustomBlocks.get(chunkKey) + + for (const worker of this.workers) { + worker.postMessage({ + type: 'chunk', + x, + z, + chunk, + customBlockModels: customBlockModels || undefined + }) + } + this.workers[0].postMessage({ + type: 'getHeightmap', + x, + z, + }) + this.logWorkerWork(() => `-> chunk ${JSON.stringify({ x, z, chunkLength: chunk.length, customBlockModelsLength: customBlockModels ? Object.keys(customBlockModels).length : 0 })}`) + this.mesherLogReader?.chunkReceived(x, z, chunk.length) + for (let y = this.worldMinYRender; y < this.worldSizeParams.worldHeight; y += 16) { + const loc = new Vec3(x, y, z) + this.setSectionDirty(loc) + if (this.neighborChunkUpdates && (!isLightUpdate || this.worldRendererConfig.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)) + } + } + } + + markAsLoaded (x, z) { + this.loadedChunks[`${x},${z}`] = true + this.finishedChunks[`${x},${z}`] = true + this.logWorkerWork(`-> markAsLoaded ${JSON.stringify({ x, z })}`) + this.checkAllFinished() + } + + removeColumn (x, z) { + delete this.loadedChunks[`${x},${z}`] + for (const worker of this.workers) { + worker.postMessage({ type: 'unloadChunk', x, z }) + } + this.logWorkerWork(`-> unloadChunk ${JSON.stringify({ x, z })}`) + delete this.finishedChunks[`${x},${z}`] + this.allChunksFinished = Object.keys(this.finishedChunks).length === this.chunksLength + if (Object.keys(this.finishedChunks).length === 0) { + this.allLoadedIn = undefined + this.initialChunkLoadWasStartedIn = undefined + } + for (let y = this.worldSizeParams.minY; y < this.worldSizeParams.worldHeight; y += 16) { + this.setSectionDirty(new Vec3(x, y, z), false) + delete this.finishedSections[`${x},${y},${z}`] + } + this.highestBlocksByChunks.delete(`${x},${z}`) + + this.updateChunksStats() + + if (Object.keys(this.loadedChunks).length === 0) { + this.mesherLogger.contents = [] + this.logWorkerWork('# all chunks unloaded. New log started') + void this.mesherLogReader?.maybeStartReplay() + } + } + + setBlockStateId (pos: Vec3, stateId: number | undefined, needAoRecalculation = true) { + const set = async () => { + const sectionX = Math.floor(pos.x / 16) * 16 + const sectionZ = Math.floor(pos.z / 16) * 16 + if (this.queuedChunks.has(`${sectionX},${sectionZ}`)) { + await new Promise(resolve => { + this.queuedFunctions.push(() => { + resolve() + }) + }) + } + if (!this.loadedChunks[`${sectionX},${sectionZ}`]) { + // console.debug('[should be unreachable] setBlockStateId called for unloaded chunk', pos) + } + this.setBlockStateIdInner(pos, stateId, needAoRecalculation) + } + void set() + } + + updateEntity (e: any, isUpdate = false) { } + + abstract updatePlayerEntity? (e: any): void + + lightUpdate (chunkX: number, chunkZ: number) { } + + connect (worldView: WorldDataEmitterWorker) { + const worldEmitter = worldView + + worldEmitter.on('entity', (e) => { + this.updateEntity(e, false) + }) + worldEmitter.on('entityMoved', (e) => { + this.updateEntity(e, true) + }) + worldEmitter.on('playerEntity', (e) => { + this.updatePlayerEntity?.(e) + }) + + let currentLoadChunkBatch = null as { + timeout + data + } | null + worldEmitter.on('loadChunk', ({ x, z, chunk, worldConfig, isLightUpdate }) => { + this.worldSizeParams = worldConfig + this.queuedChunks.add(`${x},${z}`) + const args = [x, z, chunk, isLightUpdate] + if (!currentLoadChunkBatch) { + // add a setting to use debounce instead + currentLoadChunkBatch = { + data: [], + timeout: setTimeout(() => { + for (const args of currentLoadChunkBatch!.data) { + this.queuedChunks.delete(`${args[0]},${args[1]}`) + this.addColumn(...args as Parameters) + } + for (const fn of this.queuedFunctions) { + fn() + } + this.queuedFunctions = [] + currentLoadChunkBatch = null + }, this.worldRendererConfig.addChunksBatchWaitTime) + } + } + currentLoadChunkBatch.data.push(args) + }) + // todo remove and use other architecture instead so data flow is clear + worldEmitter.on('blockEntities', (blockEntities) => { + this.blockEntities = blockEntities + }) + + worldEmitter.on('unloadChunk', ({ x, z }) => { + this.removeColumn(x, z) + }) + + worldEmitter.on('blockUpdate', ({ pos, stateId }) => { + this.setBlockStateId(new Vec3(pos.x, pos.y, pos.z), stateId) + }) + + worldEmitter.on('chunkPosUpdate', ({ pos }) => { + this.updateViewerPosition(pos) + }) + + worldEmitter.on('end', () => { + this.worldStop?.() + }) + + + worldEmitter.on('renderDistance', (d) => { + this.viewDistance = d + this.chunksLength = d === 0 ? 1 : generateSpiralMatrix(d).length + }) + + worldEmitter.on('renderDistance', (d) => { + this.viewDistance = d + this.chunksLength = d === 0 ? 1 : generateSpiralMatrix(d).length + this.allChunksFinished = Object.keys(this.finishedChunks).length === this.chunksLength + }) + + worldEmitter.on('markAsLoaded', ({ x, z }) => { + this.markAsLoaded(x, z) + }) + + worldEmitter.on('updateLight', ({ pos }) => { + this.lightUpdate(pos.x, pos.z) + }) + + worldEmitter.on('onWorldSwitch', () => { + for (const fn of this.onWorldSwitched) { + try { + fn() + } catch (e) { + setTimeout(() => { + console.log('[Renderer Backend] Error in onWorldSwitched:') + throw e + }, 0) + } + } + }) + + worldEmitter.on('time', (timeOfDay) => { + if (!this.worldRendererConfig.dayCycle) return + this.timeUpdated?.(timeOfDay) + + this.timeOfTheDay = timeOfDay + + // if (this.worldRendererConfig.skyLight === skyLight) return + // this.worldRendererConfig.skyLight = skyLight + // if (this instanceof WorldRendererThree) { + // (this).rerenderAllChunks?.() + // } + }) + + worldEmitter.on('biomeUpdate', ({ biome }) => { + this.biomeUpdated?.(biome) + }) + + worldEmitter.on('biomeReset', () => { + this.biomeReset?.() + }) + } + + setBlockStateIdInner (pos: Vec3, stateId: number | undefined, needAoRecalculation = true) { + const chunkKey = `${Math.floor(pos.x / 16) * 16},${Math.floor(pos.z / 16) * 16}` + const blockPosKey = `${pos.x},${pos.y},${pos.z}` + const customBlockModels = this.protocolCustomBlocks.get(chunkKey) || {} + + for (const worker of this.workers) { + worker.postMessage({ + type: 'blockUpdate', + pos, + stateId, + customBlockModels + }) + } + this.logWorkerWork(`-> blockUpdate ${JSON.stringify({ pos, stateId, customBlockModels })}`) + this.setSectionDirty(pos, true, true) + if (this.neighborChunkUpdates) { + if ((pos.x & 15) === 0) this.setSectionDirty(pos.offset(-16, 0, 0), true, true) + if ((pos.x & 15) === 15) this.setSectionDirty(pos.offset(16, 0, 0), true, true) + if ((pos.y & 15) === 0) this.setSectionDirty(pos.offset(0, -16, 0), true, true) + if ((pos.y & 15) === 15) this.setSectionDirty(pos.offset(0, 16, 0), true, true) + if ((pos.z & 15) === 0) this.setSectionDirty(pos.offset(0, 0, -16), true, true) + if ((pos.z & 15) === 15) this.setSectionDirty(pos.offset(0, 0, 16), true, true) + + if (needAoRecalculation) { + // top view neighbors + if ((pos.x & 15) === 0 && (pos.z & 15) === 0) this.setSectionDirty(pos.offset(-16, 0, -16), true, true) + if ((pos.x & 15) === 15 && (pos.z & 15) === 0) this.setSectionDirty(pos.offset(16, 0, -16), true, true) + if ((pos.x & 15) === 0 && (pos.z & 15) === 15) this.setSectionDirty(pos.offset(-16, 0, 16), true, true) + if ((pos.x & 15) === 15 && (pos.z & 15) === 15) this.setSectionDirty(pos.offset(16, 0, 16), true, true) + + // side view neighbors (but ignore updates above) + // z view neighbors + if ((pos.x & 15) === 0 && (pos.y & 15) === 0) this.setSectionDirty(pos.offset(-16, -16, 0), true, true) + if ((pos.x & 15) === 15 && (pos.y & 15) === 0) this.setSectionDirty(pos.offset(16, -16, 0), true, true) + + // x view neighbors + if ((pos.z & 15) === 0 && (pos.y & 15) === 0) this.setSectionDirty(pos.offset(0, -16, -16), true, true) + if ((pos.z & 15) === 15 && (pos.y & 15) === 0) this.setSectionDirty(pos.offset(0, -16, 16), true, true) + + // x & z neighbors + if ((pos.y & 15) === 0 && (pos.x & 15) === 0 && (pos.z & 15) === 0) this.setSectionDirty(pos.offset(-16, -16, -16), true, true) + if ((pos.y & 15) === 0 && (pos.x & 15) === 15 && (pos.z & 15) === 0) this.setSectionDirty(pos.offset(16, -16, -16), true, true) + if ((pos.y & 15) === 0 && (pos.x & 15) === 0 && (pos.z & 15) === 15) this.setSectionDirty(pos.offset(-16, -16, 16), true, true) + if ((pos.y & 15) === 0 && (pos.x & 15) === 15 && (pos.z & 15) === 15) this.setSectionDirty(pos.offset(16, -16, 16), true, true) + } + } + } + + abstract worldStop? () + + queueAwaited = false + toWorkerMessagesQueue = {} as { [workerIndex: string]: any[] } + + getWorkerNumber (pos: Vec3, updateAction = false) { + if (updateAction) { + const key = `${Math.floor(pos.x / 16) * 16},${Math.floor(pos.y / 16) * 16},${Math.floor(pos.z / 16) * 16}` + const cantUseChangeWorker = this.sectionsWaiting.get(key) && !this.finishedSections[key] + if (!cantUseChangeWorker) return 0 + } + + const hash = mod(Math.floor(pos.x / 16) + Math.floor(pos.y / 16) + Math.floor(pos.z / 16), this.workers.length - 1) + return hash + 1 + } + + async debugGetWorkerCustomBlockModel (pos: Vec3) { + const data = [] as Array> + for (const worker of this.workers) { + data.push(new Promise((resolve) => { + worker.addEventListener('message', (e) => { + if (e.data.type === 'customBlockModel') { + resolve(e.data.customBlockModel) + } + }) + })) + worker.postMessage({ + type: 'getCustomBlockModel', + pos + }) + } + return Promise.all(data) + } + + setSectionDirty (pos: Vec3, value = true, useChangeWorker = false) { // value false is used for unloading chunks + if (!this.forceCallFromMesherReplayer && this.mesherLogReader) return + + if (this.viewDistance === -1) throw new Error('viewDistance not set') + this.reactiveState.world.mesherWork = true + const distance = this.getDistance(pos) + // todo shouldnt we check loadedChunks instead? + if (!this.workers.length || distance[0] > this.viewDistance || distance[1] > this.viewDistance) return + const key = `${Math.floor(pos.x / 16) * 16},${Math.floor(pos.y / 16) * 16},${Math.floor(pos.z / 16) * 16}` + // if (this.sectionsOutstanding.has(key)) return + this.renderUpdateEmitter.emit('dirty', pos, value) + // Dispatch sections to workers based on position + // This guarantees uniformity accross workers and that a given section + // is always dispatched to the same worker + const hash = this.getWorkerNumber(pos, useChangeWorker && this.mesherLogger.active) + this.sectionsWaiting.set(key, (this.sectionsWaiting.get(key) ?? 0) + 1) + if (this.forceCallFromMesherReplayer) { + this.workers[hash].postMessage({ + type: 'dirty', + x: pos.x, + y: pos.y, + z: pos.z, + value, + config: this.getMesherConfig(), + }) + } else { + this.toWorkerMessagesQueue[hash] ??= [] + this.toWorkerMessagesQueue[hash].push({ + // this.workers[hash].postMessage({ + type: 'dirty', + x: pos.x, + y: pos.y, + z: pos.z, + value, + config: this.getMesherConfig(), + }) + this.dispatchMessages() + } + } + + dispatchMessages () { + if (this.queueAwaited) return + this.queueAwaited = true + setTimeout(() => { + // group messages and send as one + for (const workerIndex in this.toWorkerMessagesQueue) { + const worker = this.workers[Number(workerIndex)] + worker.postMessage(this.toWorkerMessagesQueue[workerIndex]) + for (const message of this.toWorkerMessagesQueue[workerIndex]) { + this.logWorkerWork(`-> ${workerIndex} dispatchMessages ${message.type} ${JSON.stringify({ x: message.x, y: message.y, z: message.z, value: message.value })}`) + } + } + this.toWorkerMessagesQueue = {} + this.queueAwaited = false + }) + } + + // Listen for chunk rendering updates emitted if a worker finished a render and resolve if the number + // of sections not rendered are 0 + async waitForChunksToRender () { + return new Promise((resolve, reject) => { + if ([...this.sectionsWaiting].length === 0) { + resolve() + return + } + + const updateHandler = () => { + if (this.sectionsWaiting.size === 0) { + this.renderUpdateEmitter.removeListener('update', updateHandler) + resolve() + } + } + this.renderUpdateEmitter.on('update', updateHandler) + }) + } + + async waitForChunkToLoad (pos: Vec3) { + return new Promise((resolve, reject) => { + const key = `${Math.floor(pos.x / 16) * 16},${Math.floor(pos.z / 16) * 16}` + if (this.loadedChunks[key]) { + resolve() + return + } + const updateHandler = () => { + if (this.loadedChunks[key]) { + this.renderUpdateEmitter.removeListener('update', updateHandler) + resolve() + } + } + this.renderUpdateEmitter.on('update', updateHandler) + }) + } + + destroy () { + // Stop all workers + for (const worker of this.workers) { + worker.terminate() + } + this.workers = [] + + // Stop and destroy sound system + if (this.soundSystem) { + this.soundSystem.destroy() + this.soundSystem = undefined + } + + this.active = false + + this.renderUpdateEmitter.removeAllListeners() + this.abortController.abort() + removeAllStats() + } +} + +export const initMesherWorker = (onGotMessage: (data: any) => void) => { + // Node environment needs an absolute path, but browser needs the url of the file + const workerName = 'mesher.js' + + let worker: any + if (process.env.SINGLE_FILE_BUILD) { + const workerCode = document.getElementById('mesher-worker-code')!.textContent! + const blob = new Blob([workerCode], { type: 'text/javascript' }) + worker = new Worker(window.URL.createObjectURL(blob)) + } else { + worker = new Worker(workerName) + } + + worker.onmessage = ({ data }) => { + onGotMessage(data) + } + if (worker.on) worker.on('message', (data) => { worker.onmessage({ data }) }) + return worker +} + +export const meshersSendMcData = (workers: Worker[], version: string, addData = {} as Record) => { + const allMcData = mcDataRaw.pc[version] ?? mcDataRaw.pc[toMajorVersion(version)] + const mcData = { + version: JSON.parse(JSON.stringify(allMcData.version)) + } + for (const key of dynamicMcDataFiles) { + mcData[key] = allMcData[key] + } + + for (const worker of workers) { + worker.postMessage({ type: 'mcData', mcData, ...addData }) + } +} diff --git a/prismarine-viewer/viewer/sign-renderer/index.html b/renderer/viewer/sign-renderer/index.html similarity index 100% rename from prismarine-viewer/viewer/sign-renderer/index.html rename to renderer/viewer/sign-renderer/index.html diff --git a/renderer/viewer/sign-renderer/index.ts b/renderer/viewer/sign-renderer/index.ts new file mode 100644 index 00000000..f14b9b4c --- /dev/null +++ b/renderer/viewer/sign-renderer/index.ts @@ -0,0 +1,216 @@ +import type { ChatMessage } from 'prismarine-chat' +import { createCanvas } from '../lib/utils' + +type SignBlockEntity = { + Color?: string + GlowingText?: 0 | 1 + Text1?: string + Text2?: string + Text3?: string + Text4?: string +} | { + // todo + is_waxed?: 0 | 1 + front_text: { + color: string + messages: string[] + // todo + has_glowing_text?: 0 | 1 + } + // todo + // back_text: {} +} + +type JsonEncodedType = string | null | Record + +const parseSafe = (text: string, task: string) => { + try { + return JSON.parse(text) + } catch (e) { + console.warn(`Failed to parse ${task}`, e) + return null + } +} + +const LEGACY_COLORS = { + black: '#000000', + dark_blue: '#0000AA', + dark_green: '#00AA00', + dark_aqua: '#00AAAA', + dark_red: '#AA0000', + dark_purple: '#AA00AA', + gold: '#FFAA00', + gray: '#AAAAAA', + dark_gray: '#555555', + blue: '#5555FF', + green: '#55FF55', + aqua: '#55FFFF', + red: '#FF5555', + light_purple: '#FF55FF', + yellow: '#FFFF55', + white: '#FFFFFF', +} + +export const renderSign = ( + blockEntity: SignBlockEntity, + isHanging: boolean, + PrismarineChat: typeof ChatMessage, + ctxHook = (ctx) => { }, + canvasCreator = (width, height): OffscreenCanvas => { return createCanvas(width, height) } +) => { + // todo don't use texture rendering, investigate the font rendering when possible + // or increase factor when needed + const factor = 40 + const fontSize = 1.6 * factor + const signboardY = [16, 9] + const heightOffset = signboardY[0] - signboardY[1] + const heightScalar = heightOffset / 16 + // todo the text should be clipped based on it's render width (needs investigate) + + const texts = 'front_text' in blockEntity ? /* > 1.20 */ blockEntity.front_text.messages : [ + blockEntity.Text1, + blockEntity.Text2, + blockEntity.Text3, + blockEntity.Text4 + ] + + if (!texts.some((text) => text !== 'null')) { + return undefined + } + + const canvas = canvasCreator(16 * factor, heightOffset * factor) + + const _ctx = canvas.getContext('2d')! + + ctxHook(_ctx) + const defaultColor = ('front_text' in blockEntity ? blockEntity.front_text.color : blockEntity.Color) || 'black' + for (const [lineNum, text] of texts.slice(0, 4).entries()) { + if (text === 'null') continue + renderComponent(text, PrismarineChat, canvas, fontSize, defaultColor, fontSize * (lineNum + 1) + (isHanging ? 0 : -8)) + } + return canvas +} + +export const renderComponent = ( + text: JsonEncodedType | string | undefined, + PrismarineChat: typeof ChatMessage, + canvas: OffscreenCanvas, + fontSize: number, + defaultColor: string, + offset = 0 +) => { + // todo: in pre flatenning it seems the format was not json + const parsed = typeof text === 'string' && (text?.startsWith('{') || text?.startsWith('"')) ? parseSafe(text ?? '""', 'sign text') : text + if (!parsed || (typeof parsed !== 'object' && typeof parsed !== 'string')) return + // todo fix type + + const ctx = canvas.getContext('2d')! + if (!ctx) throw new Error('Could not get 2d context') + ctx.imageSmoothingEnabled = false + ctx.font = `${fontSize}px mojangles` + + type Formatting = { + color: string | undefined + underlined: boolean | undefined + strikethrough: boolean | undefined + bold: boolean | undefined + italic: boolean | undefined + } + + type Message = ChatMessage & Formatting & { text: string } + + const message = new PrismarineChat(parsed) as Message + + const toRenderCanvas: Array<{ + fontStyle: string + fillStyle: string + underlineStyle: boolean + strikeStyle: boolean + offset: number + text: string + }> = [] + let visibleFormatting = false + let plainText = '' + let textOffset = offset + const textWidths: number[] = [] + + const renderText = (component: Message, parentFormatting?: Formatting | undefined) => { + const { text } = component + const formatting = { + color: component.color ?? parentFormatting?.color, + underlined: component.underlined ?? parentFormatting?.underlined, + strikethrough: component.strikethrough ?? parentFormatting?.strikethrough, + bold: component.bold ?? parentFormatting?.bold, + italic: component.italic ?? parentFormatting?.italic + } + visibleFormatting = visibleFormatting || formatting.underlined || formatting.strikethrough || false + if (text?.includes('\n')) { + for (const line of text.split('\n')) { + addTextPart(line, formatting) + textOffset += fontSize + plainText = '' + } + } else if (text) { + addTextPart(text, formatting) + } + if (component.extra) { + for (const child of component.extra) { + renderText(child as Message, formatting) + } + } + } + + const addTextPart = (text: string, formatting: Formatting) => { + plainText += text + textWidths[textOffset] = ctx.measureText(plainText).width + let color = formatting.color ?? defaultColor + if (!color.startsWith('#')) { + color = LEGACY_COLORS[color.toLowerCase()] || color + } + toRenderCanvas.push({ + fontStyle: `${formatting.bold ? 'bold' : ''} ${formatting.italic ? 'italic' : ''}`, + fillStyle: color, + underlineStyle: formatting.underlined ?? false, + strikeStyle: formatting.strikethrough ?? false, + offset: textOffset, + text + }) + } + + renderText(message) + + // skip rendering empty lines + if (!visibleFormatting && !message.toString().trim()) return + + let renderedWidth = 0 + let previousOffsetY = 0 + for (const { fillStyle, fontStyle, underlineStyle, strikeStyle, offset: offsetY, text } of toRenderCanvas) { + if (previousOffsetY !== offsetY) { + renderedWidth = 0 + } + previousOffsetY = offsetY + ctx.fillStyle = fillStyle + ctx.textRendering = 'optimizeLegibility' + ctx.font = `${fontStyle} ${fontSize}px mojangles` + const textWidth = textWidths[offsetY] ?? ctx.measureText(text).width + const offsetX = (canvas.width - textWidth) / 2 + renderedWidth + ctx.fillText(text, offsetX, offsetY) + if (strikeStyle) { + ctx.lineWidth = fontSize / 8 + ctx.strokeStyle = fillStyle + ctx.beginPath() + ctx.moveTo(offsetX, offsetY - ctx.lineWidth * 2.5) + ctx.lineTo(offsetX + ctx.measureText(text).width, offsetY - ctx.lineWidth * 2.5) + ctx.stroke() + } + if (underlineStyle) { + ctx.lineWidth = fontSize / 8 + ctx.strokeStyle = fillStyle + ctx.beginPath() + ctx.moveTo(offsetX, offsetY + ctx.lineWidth) + ctx.lineTo(offsetX + ctx.measureText(text).width, offsetY + ctx.lineWidth) + ctx.stroke() + } + renderedWidth += ctx.measureText(text).width + } +} diff --git a/prismarine-viewer/viewer/sign-renderer/noop.js b/renderer/viewer/sign-renderer/noop.js similarity index 100% rename from prismarine-viewer/viewer/sign-renderer/noop.js rename to renderer/viewer/sign-renderer/noop.js diff --git a/prismarine-viewer/viewer/sign-renderer/package.json b/renderer/viewer/sign-renderer/package.json similarity index 100% rename from prismarine-viewer/viewer/sign-renderer/package.json rename to renderer/viewer/sign-renderer/package.json diff --git a/prismarine-viewer/viewer/sign-renderer/playground.ts b/renderer/viewer/sign-renderer/playground.ts similarity index 69% rename from prismarine-viewer/viewer/sign-renderer/playground.ts rename to renderer/viewer/sign-renderer/playground.ts index 4182b1c9..a7438092 100644 --- a/prismarine-viewer/viewer/sign-renderer/playground.ts +++ b/renderer/viewer/sign-renderer/playground.ts @@ -1,5 +1,5 @@ -import { renderSign } from '.' import PrismarineChatLoader from 'prismarine-chat' +import { renderSign } from '.' const PrismarineChat = PrismarineChatLoader({ language: {} } as any) @@ -11,19 +11,24 @@ await new Promise(resolve => { }) const blockEntity = { - "GlowingText": 0, - "Color": "black", - "Text4": "{\"text\":\"\"}", - "Text3": "{\"text\":\"\"}", - "Text2": "{\"text\":\"\"}", - "Text1": "{\"extra\":[{\"color\":\"dark_green\",\"text\":\"Minecraft \"},{\"text\":\"Tools\"}],\"text\":\"\"}" + 'GlowingText': 0, + 'Color': 'black', + 'Text4': '{"text":""}', + 'Text3': '{"text":""}', + 'Text2': '{"text":""}', + 'Text1': '{"extra":[{"color":"dark_green","text":"Minecraft "},{"text":"Tools"}],"text":""}' } as const await document.fonts.load('1em mojangles') -const canvas = renderSign(blockEntity, PrismarineChat, (ctx) => { +const canvas = renderSign(blockEntity, false, PrismarineChat, (ctx) => { ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height) -}) +}, (width, height) => { + const canvas = document.createElement('canvas') + canvas.width = width + canvas.height = height + return canvas as unknown as OffscreenCanvas +}) as unknown as HTMLCanvasElement if (canvas) { canvas.style.imageRendering = 'pixelated' diff --git a/prismarine-viewer/viewer/sign-renderer/tests.test.ts b/renderer/viewer/sign-renderer/tests.test.ts similarity index 70% rename from prismarine-viewer/viewer/sign-renderer/tests.test.ts rename to renderer/viewer/sign-renderer/tests.test.ts index 4549c6f4..ab268849 100644 --- a/prismarine-viewer/viewer/sign-renderer/tests.test.ts +++ b/renderer/viewer/sign-renderer/tests.test.ts @@ -1,6 +1,6 @@ import { test, expect } from 'vitest' -import { renderSign } from '.' import PrismarineChatLoader from 'prismarine-chat' +import { renderSign } from '.' const PrismarineChat = PrismarineChatLoader({ language: {} } as any) let ctxTexts = [] as any[] @@ -22,25 +22,21 @@ global.document = { const render = (entity) => { ctxTexts = [] - renderSign(entity, PrismarineChat) + renderSign(entity, true, PrismarineChat) return ctxTexts.map(({ text, y }) => [y / 64, text]) } test('sign renderer', () => { let blockEntity = { - "GlowingText": 0, - "Color": "black", - "Text4": "{\"text\":\"\"}", - "Text3": "{\"text\":\"\"}", - "Text2": "{\"text\":\"\"}", - "Text1": "{\"extra\":[{\"color\":\"dark_green\",\"text\":\"Minecraft \"},{\"text\":\"Tools\"}],\"text\":\"\"}" + 'GlowingText': 0, + 'Color': 'black', + 'Text4': '{"text":""}', + 'Text3': '{"text":""}', + 'Text2': '{"text":""}', + 'Text1': '{"extra":[{"color":"dark_green","text":"Minecraft "},{"text":"Tools"}],"text":""}' } as any expect(render(blockEntity)).toMatchInlineSnapshot(` [ - [ - 1, - "", - ], [ 1, "Minecraft ", @@ -53,10 +49,10 @@ test('sign renderer', () => { `) blockEntity = { // pre flatenning - "Text1": "Welcome to", - "Text2": "", - "Text3": "null", - "Text4": "\"Version 2.1\"", + 'Text1': 'Welcome to', + 'Text2': '', + 'Text3': 'null', + 'Text4': '"Version 2.1"', } as const expect(render(blockEntity)).toMatchInlineSnapshot(` [ diff --git a/prismarine-viewer/viewer/sign-renderer/vite.config.ts b/renderer/viewer/sign-renderer/vite.config.ts similarity index 58% rename from prismarine-viewer/viewer/sign-renderer/vite.config.ts rename to renderer/viewer/sign-renderer/vite.config.ts index 896ac865..aebfc20c 100644 --- a/prismarine-viewer/viewer/sign-renderer/vite.config.ts +++ b/renderer/viewer/sign-renderer/vite.config.ts @@ -3,8 +3,8 @@ import { defineConfig } from 'vite' export default defineConfig({ resolve: { alias: { - 'prismarine-registry': "./noop.js", - 'prismarine-nbt': "./noop.js" + 'prismarine-registry': './noop.js', + 'prismarine-nbt': './noop.js' }, }, }) diff --git a/renderer/viewer/three/appShared.ts b/renderer/viewer/three/appShared.ts new file mode 100644 index 00000000..5be9e10b --- /dev/null +++ b/renderer/viewer/three/appShared.ts @@ -0,0 +1,74 @@ +import { BlockModel } from 'mc-assets/dist/types' +import { ItemSpecificContextProperties, PlayerStateRenderer } from 'renderer/viewer/lib/basePlayerState' +import { GeneralInputItem, getItemModelName } from '../../../src/mineflayer/items' +import { ResourcesManager, ResourcesManagerTransferred } from '../../../src/resourcesManager' +import { renderSlot } from './renderSlot' + +export const getItemUv = (item: Record, specificProps: ItemSpecificContextProperties, resourcesManager: ResourcesManagerTransferred, playerState: PlayerStateRenderer): { + u: number + v: number + su: number + sv: number + renderInfo?: ReturnType + // texture: ImageBitmap + modelName: string +} | { + resolvedModel: BlockModel + modelName: string +} => { + const resources = resourcesManager.currentResources + if (!resources) throw new Error('Resources not loaded') + const idOrName = item.itemId ?? item.blockId ?? item.name + const { blockState } = item + try { + const name = + blockState + ? loadedData.blocksByStateId[blockState]?.name + : typeof idOrName === 'number' ? loadedData.items[idOrName]?.name : idOrName + if (!name) throw new Error(`Item not found: ${idOrName}`) + + const model = getItemModelName({ + ...item, + name, + } as GeneralInputItem, specificProps, resourcesManager, playerState) + + const renderInfo = renderSlot({ + modelName: model, + }, resourcesManager, false, true) + + if (!renderInfo) throw new Error(`Failed to get render info for item ${name}`) + + const img = renderInfo.texture === 'blocks' ? resources.blocksAtlasImage : resources.itemsAtlasImage + + if (renderInfo.blockData) { + return { + resolvedModel: renderInfo.blockData.resolvedModel, + modelName: renderInfo.modelName! + } + } + if (renderInfo.slice) { + // Get slice coordinates from either block or item texture + const [x, y, w, h] = renderInfo.slice + const [u, v, su, sv] = [x / img.width, y / img.height, (w / img.width), (h / img.height)] + return { + u, v, su, sv, + renderInfo, + // texture: img, + modelName: renderInfo.modelName! + } + } + + throw new Error(`Invalid render info for item ${name}`) + } catch (err) { + reportError?.(err) + // Return default UV coordinates for missing texture + return { + u: 0, + v: 0, + su: 16 / resources.blocksAtlasImage.width, + sv: 16 / resources.blocksAtlasImage.width, + // texture: resources.blocksAtlasImage, + modelName: 'missing' + } + } +} diff --git a/renderer/viewer/three/cameraShake.ts b/renderer/viewer/three/cameraShake.ts new file mode 100644 index 00000000..7b159509 --- /dev/null +++ b/renderer/viewer/three/cameraShake.ts @@ -0,0 +1,120 @@ +import * as THREE from 'three' +import { WorldRendererThree } from './worldrendererThree' + +export class CameraShake { + private rollAngle = 0 + private get damageRollAmount () { return 5 } + private get damageAnimDuration () { return 200 } + private rollAnimation?: { startTime: number, startRoll: number, targetRoll: number, duration: number, returnToZero?: boolean } + private basePitch = 0 + private baseYaw = 0 + + constructor (public worldRenderer: WorldRendererThree, public onRenderCallbacks: Array<() => void>) { + onRenderCallbacks.push(() => { + this.update() + }) + } + + setBaseRotation (pitch: number, yaw: number) { + this.basePitch = pitch + this.baseYaw = yaw + this.update() + } + + getBaseRotation () { + return { pitch: this.basePitch, yaw: this.baseYaw } + } + + shakeFromDamage (yaw?: number) { + // Add roll animation + const startRoll = this.rollAngle + const targetRoll = startRoll + (yaw ?? (Math.random() < 0.5 ? -1 : 1)) * this.damageRollAmount + + this.rollAnimation = { + startTime: performance.now(), + startRoll, + targetRoll, + duration: this.damageAnimDuration / 2 + } + } + + update () { + if (this.worldRenderer.playerStateUtils.isSpectatingEntity()) { + // Remove any shaking when spectating + this.rollAngle = 0 + this.rollAnimation = undefined + } + // Update roll animation + if (this.rollAnimation) { + const now = performance.now() + const elapsed = now - this.rollAnimation.startTime + const progress = Math.min(elapsed / this.rollAnimation.duration, 1) + + if (this.rollAnimation.returnToZero) { + // Ease back to zero + this.rollAngle = this.rollAnimation.startRoll * (1 - this.easeInOut(progress)) + if (progress === 1) { + this.rollAnimation = undefined + } + } else { + // Initial roll + this.rollAngle = this.rollAnimation.startRoll + (this.rollAnimation.targetRoll - this.rollAnimation.startRoll) * this.easeOut(progress) + if (progress === 1) { + // Start return to zero animation + this.rollAnimation = { + startTime: now, + startRoll: this.rollAngle, + targetRoll: 0, + duration: this.damageAnimDuration / 2, + returnToZero: true + } + } + } + } + + const camera = this.worldRenderer.cameraObject + + if (this.worldRenderer.cameraGroupVr) { + // For VR camera, only apply yaw rotation + const yawQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), this.baseYaw) + camera.setRotationFromQuaternion(yawQuat) + } else { + // For regular camera, apply all rotations + // Add tiny offsets to prevent z-fighting at ideal angles (90, 180, 270 degrees) + const pitchOffset = this.addAntiZfightingOffset(this.basePitch) + const yawOffset = this.addAntiZfightingOffset(this.baseYaw) + + const pitchQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), pitchOffset) + const yawQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), yawOffset) + const rollQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 0, 1), THREE.MathUtils.degToRad(this.rollAngle)) + // Combine rotations in the correct order: pitch -> yaw -> roll + const finalQuat = yawQuat.multiply(pitchQuat).multiply(rollQuat) + camera.setRotationFromQuaternion(finalQuat) + } + } + + private easeOut (t: number): number { + return 1 - (1 - t) * (1 - t) + } + + private easeInOut (t: number): number { + return t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2 + } + + private addAntiZfightingOffset (angle: number): number { + const offset = 0.001 // Very small offset in radians (about 0.057 degrees) + + // Check if the angle is close to ideal angles (0, π/2, π, 3π/2) + const normalizedAngle = ((angle % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2) + const tolerance = 0.01 // Tolerance for considering an angle "ideal" + + if (Math.abs(normalizedAngle) < tolerance || + Math.abs(normalizedAngle - Math.PI / 2) < tolerance || + Math.abs(normalizedAngle - Math.PI) < tolerance || + Math.abs(normalizedAngle - 3 * Math.PI / 2) < tolerance) { + return angle + offset + } + + return angle + } +} diff --git a/renderer/viewer/three/documentRenderer.ts b/renderer/viewer/three/documentRenderer.ts new file mode 100644 index 00000000..a5dc060d --- /dev/null +++ b/renderer/viewer/three/documentRenderer.ts @@ -0,0 +1,328 @@ +import * as THREE from 'three' +import Stats from 'stats.js' +import StatsGl from 'stats-gl' +import * as tween from '@tweenjs/tween.js' +import { GraphicsBackendConfig, GraphicsInitOptions } from '../../../src/appViewer' +import { WorldRendererConfig } from '../lib/worldrendererCommon' + +export class DocumentRenderer { + canvas: HTMLCanvasElement | OffscreenCanvas + readonly renderer: THREE.WebGLRenderer + private animationFrameId?: number + private timeoutId?: number + private lastRenderTime = 0 + + private previousCanvasWidth = 0 + private previousCanvasHeight = 0 + private currentWidth = 0 + private currentHeight = 0 + + private renderedFps = 0 + private fpsInterval: any + private readonly stats: TopRightStats | undefined + private paused = false + disconnected = false + preRender = () => { } + render = (sizeChanged: boolean) => { } + postRender = () => { } + sizeChanged = () => { } + droppedFpsPercentage: number + config: GraphicsBackendConfig + onRender = [] as Array<(sizeChanged: boolean) => void> + inWorldRenderingConfig: WorldRendererConfig | undefined + + constructor (initOptions: GraphicsInitOptions, public externalCanvas?: OffscreenCanvas) { + this.config = initOptions.config + + // Handle canvas creation/transfer based on context + if (externalCanvas) { + this.canvas = externalCanvas + } else { + this.addToPage() + } + + try { + this.renderer = new THREE.WebGLRenderer({ + canvas: this.canvas, + preserveDrawingBuffer: true, + logarithmicDepthBuffer: true, + powerPreference: this.config.powerPreference + }) + } catch (err) { + initOptions.callbacks.displayCriticalError(new Error(`Failed to create WebGL context, not possible to render (restart browser): ${err.message}`)) + throw err + } + this.renderer.outputColorSpace = THREE.LinearSRGBColorSpace + if (!externalCanvas) { + this.updatePixelRatio() + } + this.sizeUpdated() + // Initialize previous dimensions + this.previousCanvasWidth = this.canvas.width + this.previousCanvasHeight = this.canvas.height + + const supportsWebGL2 = 'WebGL2RenderingContext' in window + // Only initialize stats and DOM-related features in main thread + if (!externalCanvas && supportsWebGL2) { + this.stats = new TopRightStats(this.canvas as HTMLCanvasElement, this.config.statsVisible) + this.setupFpsTracking() + } + + this.startRenderLoop() + } + + updatePixelRatio () { + let pixelRatio = window.devicePixelRatio || 1 // todo this value is too high on ios, need to check, probably we should use avg, also need to make it configurable + if (!this.renderer.capabilities.isWebGL2) { + pixelRatio = 1 // webgl1 has issues with high pixel ratio (sometimes screen is clipped) + } + this.renderer.setPixelRatio(pixelRatio) + } + + sizeUpdated () { + this.renderer.setSize(this.currentWidth, this.currentHeight, false) + } + + private addToPage () { + this.canvas = addCanvasToPage() + this.updateCanvasSize() + } + + updateSizeExternal (newWidth: number, newHeight: number, pixelRatio: number) { + this.currentWidth = newWidth + this.currentHeight = newHeight + this.renderer.setPixelRatio(pixelRatio) + this.sizeUpdated() + } + + private updateCanvasSize () { + if (!this.externalCanvas) { + const innnerWidth = window.innerWidth + const innnerHeight = window.innerHeight + if (this.currentWidth !== innnerWidth) { + this.currentWidth = innnerWidth + } + if (this.currentHeight !== innnerHeight) { + this.currentHeight = innnerHeight + } + } + } + + private setupFpsTracking () { + let max = 0 + this.fpsInterval = setInterval(() => { + if (max > 0) { + this.droppedFpsPercentage = this.renderedFps / max + } + max = Math.max(this.renderedFps, max) + this.renderedFps = 0 + }, 1000) + } + + private startRenderLoop () { + const animate = () => { + if (this.disconnected) return + + if (this.config.timeoutRendering) { + this.timeoutId = setTimeout(animate, this.config.fpsLimit ? 1000 / this.config.fpsLimit : 0) as unknown as number + } else { + this.animationFrameId = requestAnimationFrame(animate) + } + + if (this.paused || (this.renderer.xr.isPresenting && !this.inWorldRenderingConfig?.vrPageGameRendering)) return + + // Handle FPS limiting + if (this.config.fpsLimit) { + const now = performance.now() + const elapsed = now - this.lastRenderTime + const fpsInterval = 1000 / this.config.fpsLimit + + if (elapsed < fpsInterval) { + return + } + + this.lastRenderTime = now - (elapsed % fpsInterval) + } + + let sizeChanged = false + this.updateCanvasSize() + if (this.previousCanvasWidth !== this.currentWidth || this.previousCanvasHeight !== this.currentHeight) { + this.previousCanvasWidth = this.currentWidth + this.previousCanvasHeight = this.currentHeight + this.sizeUpdated() + sizeChanged = true + } + + this.frameRender(sizeChanged) + + // Update stats visibility each frame (main thread only) + if (this.config.statsVisible !== undefined) { + this.stats?.setVisibility(this.config.statsVisible) + } + } + + animate() + } + + frameRender (sizeChanged: boolean) { + this.preRender() + this.stats?.markStart() + tween.update() + if (!globalThis.freezeRender) { + this.render(sizeChanged) + } + for (const fn of this.onRender) { + fn(sizeChanged) + } + this.renderedFps++ + this.stats?.markEnd() + this.postRender() + } + + setPaused (paused: boolean) { + this.paused = paused + } + + dispose () { + this.disconnected = true + if (this.animationFrameId) { + cancelAnimationFrame(this.animationFrameId) + } + if (this.timeoutId) { + clearTimeout(this.timeoutId) + } + if (this.canvas instanceof HTMLCanvasElement) { + this.canvas.remove() + } + clearInterval(this.fpsInterval) + this.stats?.dispose() + this.renderer.dispose() + } +} + +class TopRightStats { + private readonly stats: Stats + private readonly stats2: Stats + private readonly statsGl: StatsGl + private total = 0 + private readonly denseMode: boolean + + constructor (private readonly canvas: HTMLCanvasElement, initialStatsVisible = 0) { + this.stats = new Stats() + this.stats2 = new Stats() + this.statsGl = new StatsGl({ minimal: true }) + this.stats2.showPanel(2) + this.denseMode = process.env.NODE_ENV === 'production' || window.innerHeight < 500 + + this.initStats() + this.setVisibility(initialStatsVisible) + } + + private addStat (dom: HTMLElement, size = 80) { + dom.style.position = 'absolute' + if (this.denseMode) dom.style.height = '12px' + dom.style.overflow = 'hidden' + dom.style.left = '' + dom.style.top = '0' + dom.style.right = `${this.total}px` + dom.style.width = '80px' + dom.style.zIndex = '1' + dom.style.opacity = '0.8' + document.body.appendChild(dom) + this.total += size + } + + private initStats () { + const hasRamPanel = this.stats2.dom.children.length === 3 + + this.addStat(this.stats.dom) + if (process.env.NODE_ENV === 'development' && document.exitPointerLock) { + this.stats.dom.style.top = '' + this.stats.dom.style.bottom = '0' + } + if (hasRamPanel) { + this.addStat(this.stats2.dom) + } + + this.statsGl.init(this.canvas) + this.statsGl.container.style.display = 'flex' + this.statsGl.container.style.justifyContent = 'flex-end' + + let i = 0 + for (const _child of this.statsGl.container.children) { + const child = _child as HTMLElement + if (i++ === 0) { + child.style.display = 'none' + } + child.style.position = '' + } + } + + setVisibility (level: number) { + const visible = level > 0 + if (visible) { + this.stats.dom.style.display = 'block' + this.stats2.dom.style.display = level >= 2 ? 'block' : 'none' + this.statsGl.container.style.display = level >= 2 ? 'block' : 'none' + } else { + this.stats.dom.style.display = 'none' + this.stats2.dom.style.display = 'none' + this.statsGl.container.style.display = 'none' + } + } + + markStart () { + this.stats.begin() + this.stats2.begin() + this.statsGl.begin() + } + + markEnd () { + this.stats.end() + this.stats2.end() + this.statsGl.end() + } + + dispose () { + this.stats.dom.remove() + this.stats2.dom.remove() + this.statsGl.container.remove() + } +} + +const addCanvasToPage = () => { + const canvas = document.createElement('canvas') + canvas.id = 'viewer-canvas' + document.body.appendChild(canvas) + return canvas +} + +export const addCanvasForWorker = () => { + const canvas = addCanvasToPage() + const transferred = canvas.transferControlToOffscreen() + let removed = false + let onSizeChanged = (w, h) => { } + let oldSize = { width: 0, height: 0 } + const checkSize = () => { + if (removed) return + if (oldSize.width !== window.innerWidth || oldSize.height !== window.innerHeight) { + onSizeChanged(window.innerWidth, window.innerHeight) + oldSize = { width: window.innerWidth, height: window.innerHeight } + } + requestAnimationFrame(checkSize) + } + requestAnimationFrame(checkSize) + return { + canvas: transferred, + destroy () { + removed = true + canvas.remove() + }, + onSizeChanged (cb: (width: number, height: number) => void) { + onSizeChanged = cb + }, + get size () { + return { width: window.innerWidth, height: window.innerHeight } + } + } +} diff --git a/renderer/viewer/three/entities.ts b/renderer/viewer/three/entities.ts new file mode 100644 index 00000000..fad30182 --- /dev/null +++ b/renderer/viewer/three/entities.ts @@ -0,0 +1,1493 @@ +//@ts-check +import { UnionToIntersection } from 'type-fest' +import nbt from 'prismarine-nbt' +import * as TWEEN from '@tweenjs/tween.js' +import * as THREE from 'three' +import { PlayerAnimation, PlayerObject } from 'skinview3d' +import { inferModelType, loadCapeToCanvas, loadEarsToCanvasFromSkin } from 'skinview-utils' +// todo replace with url +import { degreesToRadians } from '@nxg-org/mineflayer-tracker/lib/mathUtils' +import { NameTagObject } from 'skinview3d/libs/nametag' +import { flat, fromFormattedString } from '@xmcl/text-component' +import mojangson from 'mojangson' +import { snakeCase } from 'change-case' +import { Item } from 'prismarine-item' +import { isEntityAttackable } from 'mineflayer-mouse/dist/attackableEntity' +import { Team } from 'mineflayer' +import PrismarineChatLoader from 'prismarine-chat' +import { EntityMetadataVersions } from '../../../src/mcDataTypes' +import { ItemSpecificContextProperties } from '../lib/basePlayerState' +import { loadSkinFromUsername, loadSkinImage, stevePngUrl } from '../lib/utils/skins' +import { renderComponent } from '../sign-renderer' +import { createCanvas } from '../lib/utils' +import { PlayerObjectType } from '../lib/createPlayerObject' +import { getBlockMeshFromModel } from './holdingBlock' +import { createItemMesh } from './itemMesh' +import * as Entity from './entity/EntityMesh' +import { getMesh } from './entity/EntityMesh' +import { WalkingGeneralSwing } from './entity/animations' +import { disposeObject, loadTexture, loadThreeJsTextureFromUrl } from './threeJsUtils' +import { armorModel, armorTextures, elytraTexture } from './entity/armorModels' +import { WorldRendererThree } from './worldrendererThree' + +export const steveTexture = loadThreeJsTextureFromUrl(stevePngUrl) + +export const TWEEN_DURATION = 120 + +function convert2sComplementToHex (complement: number) { + if (complement < 0) { + complement = (0xFF_FF_FF_FF + complement + 1) >>> 0 + } + return complement.toString(16) +} + +function toRgba (color: string | undefined) { + if (color === undefined) { + return undefined + } + if (parseInt(color, 10) === 0) { + return 'rgba(0, 0, 0, 0)' + } + const hex = convert2sComplementToHex(parseInt(color, 10)) + if (hex.length === 8) { + return `#${hex.slice(2, 8)}${hex.slice(0, 2)}` + } else { + return `#${hex}` + } +} + +function toQuaternion (quaternion: any, defaultValue?: THREE.Quaternion) { + if (quaternion === undefined) { + return defaultValue + } + if (quaternion instanceof THREE.Quaternion) { + return quaternion + } + if (Array.isArray(quaternion)) { + return new THREE.Quaternion(quaternion[0], quaternion[1], quaternion[2], quaternion[3]) + } + return new THREE.Quaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w) +} + +function poseToEuler (pose: any, defaultValue?: THREE.Euler) { + if (pose === undefined) { + return defaultValue ?? new THREE.Euler() + } + if (pose instanceof THREE.Euler) { + return pose + } + if (pose['yaw'] !== undefined && pose['pitch'] !== undefined && pose['roll'] !== undefined) { + // Convert Minecraft pitch, yaw, roll definitions to our angle system + return new THREE.Euler(-degreesToRadians(pose.pitch), -degreesToRadians(pose.yaw), degreesToRadians(pose.roll), 'ZYX') + } + if (pose['x'] !== undefined && pose['y'] !== undefined && pose['z'] !== undefined) { + return new THREE.Euler(pose.z, pose.y, pose.x, 'ZYX') + } + if (Array.isArray(pose)) { + return new THREE.Euler(pose[0], pose[1], pose[2]) + } + return defaultValue ?? new THREE.Euler() +} + +function getUsernameTexture ({ + username, + nameTagBackgroundColor = 'rgba(0, 0, 0, 0.3)', + nameTagTextOpacity = 255 +}: any, { fontFamily = 'mojangles' }: any, version: string) { + const canvas = createCanvas(64, 64) + + const PrismarineChat = PrismarineChatLoader(version) + + const ctx = canvas.getContext('2d') + if (!ctx) throw new Error('Could not get 2d context') + + const fontSize = 48 + const padding = 5 + ctx.font = `${fontSize}px ${fontFamily}` + + const plainLines = String(typeof username === 'string' ? username : new PrismarineChat(username).toString()).split('\n') + let textWidth = 0 + for (const line of plainLines) { + const width = ctx.measureText(line).width + padding * 2 + if (width > textWidth) textWidth = width + } + + canvas.width = textWidth + canvas.height = (fontSize + padding) * plainLines.length + + ctx.fillStyle = nameTagBackgroundColor + ctx.fillRect(0, 0, canvas.width, canvas.height) + + ctx.globalAlpha = nameTagTextOpacity / 255 + + renderComponent(username, PrismarineChat, canvas, fontSize, 'white', -padding + fontSize) + + ctx.globalAlpha = 1 + + return canvas +} + +const addNametag = (entity, options: { fontFamily: string }, mesh, version: string) => { + for (const c of mesh.children) { + if (c.name === 'nametag') { + c.removeFromParent() + } + } + if (entity.username !== undefined) { + const canvas = getUsernameTexture(entity, options, version) + const tex = new THREE.Texture(canvas) + tex.needsUpdate = true + let nameTag: THREE.Object3D + if (entity.nameTagFixed) { + const geometry = new THREE.PlaneGeometry() + const material = new THREE.MeshBasicMaterial({ map: tex }) + material.transparent = true + nameTag = new THREE.Mesh(geometry, material) + nameTag.rotation.set(entity.pitch, THREE.MathUtils.degToRad(entity.yaw + 180), 0) + nameTag.position.y += entity.height + 0.3 + } else { + const spriteMat = new THREE.SpriteMaterial({ map: tex }) + nameTag = new THREE.Sprite(spriteMat) + nameTag.position.y += entity.height + 0.6 + } + nameTag.renderOrder = 1000 + nameTag.scale.set(canvas.width * 0.005, canvas.height * 0.005, 1) + if (entity.nameTagRotationRight) { + nameTag.applyQuaternion(entity.nameTagRotationRight) + } + if (entity.nameTagScale) { + nameTag.scale.multiply(entity.nameTagScale) + } + if (entity.nameTagRotationLeft) { + nameTag.applyQuaternion(entity.nameTagRotationLeft) + } + if (entity.nameTagTranslation) { + nameTag.position.add(entity.nameTagTranslation) + } + nameTag.name = 'nametag' + + mesh.add(nameTag) + return nameTag + } +} + +// todo cleanup +const nametags = {} + +const isFirstUpperCase = (str) => str.charAt(0) === str.charAt(0).toUpperCase() + +function getEntityMesh (entity: import('prismarine-entity').Entity & { delete?: any; pos?: any; name?: any }, world: WorldRendererThree, options: { fontFamily: string }, overrides) { + if (entity.name) { + try { + // https://github.com/PrismarineJS/prismarine-viewer/pull/410 + const entityName = (isFirstUpperCase(entity.name) ? snakeCase(entity.name) : entity.name).toLowerCase() + const e = new Entity.EntityMesh('1.16.4', entityName, world, overrides) + + if (e.mesh) { + addNametag(entity, options, e.mesh, world.version) + return e.mesh + } + } catch (err) { + reportError?.(err) + } + } + + if (!isEntityAttackable(loadedData, entity)) return + const geometry = new THREE.BoxGeometry(entity.width, entity.height, entity.width) + geometry.translate(0, entity.height / 2, 0) + const material = new THREE.MeshBasicMaterial({ color: 0xff_00_ff }) + const cube = new THREE.Mesh(geometry, material) + const nametagCount = (nametags[entity.name] = (nametags[entity.name] || 0) + 1) + if (nametagCount < 6) { + addNametag({ + username: entity.name, + height: entity.height, + }, options, cube, world.version) + } + return cube +} + +export type SceneEntity = THREE.Object3D & { + playerObject?: PlayerObjectType + username?: string + uuid?: string + additionalCleanup?: () => void + originalEntity: import('prismarine-entity').Entity & { delete?; pos?, name, team?: Team } +} + +export class Entities { + entities = {} as Record + playerEntity: SceneEntity | null = null // Special entity for the player in third person + entitiesOptions = { + fontFamily: 'mojangles' + } + debugMode: string + onSkinUpdate: () => void + clock = new THREE.Clock() + currentlyRendering = true + cachedMapsImages = {} as Record + itemFrameMaps = {} as Record>> + + get entitiesByName (): Record { + const byName: Record = {} + for (const entity of Object.values(this.entities)) { + if (!entity['realName']) continue + byName[entity['realName']] = byName[entity['realName']] || [] + byName[entity['realName']].push(entity) + } + return byName + } + + get entitiesRenderingCount (): number { + return Object.values(this.entities).filter(entity => entity.visible).length + } + + getDebugString (): string { + const totalEntities = Object.keys(this.entities).length + const visibleEntities = this.entitiesRenderingCount + + const playerEntities = Object.values(this.entities).filter(entity => entity.playerObject) + const visiblePlayerEntities = playerEntities.filter(entity => entity.visible) + + return `${visibleEntities}/${totalEntities} ${visiblePlayerEntities.length}/${playerEntities.length}` + } + + constructor (public worldRenderer: WorldRendererThree) { + this.debugMode = 'none' + this.onSkinUpdate = () => { } + this.watchResourcesUpdates() + } + + handlePlayerEntity (playerData: SceneEntity['originalEntity']) { + // Create player entity if it doesn't exist + if (!this.playerEntity) { + // Create the player entity similar to how normal entities are created + const group = new THREE.Group() as unknown as SceneEntity + group.originalEntity = { ...playerData, name: 'player' } as SceneEntity['originalEntity'] + + const wrapper = new THREE.Group() + const playerObject = this.setupPlayerObject(playerData, wrapper, {}) + group.playerObject = playerObject + group.add(wrapper) + + group.name = 'player_entity' + this.playerEntity = group + this.worldRenderer.scene.add(group) + + void this.updatePlayerSkin(playerData.id, playerData.username, playerData.uuid ?? undefined, stevePngUrl) + } + + // Update position and rotation + if (playerData.position) { + this.playerEntity.position.set(playerData.position.x, playerData.position.y, playerData.position.z) + } + if (playerData.yaw !== undefined) { + this.playerEntity.rotation.y = playerData.yaw + } + + this.updateEntityEquipment(this.playerEntity, playerData) + } + + clear () { + for (const mesh of Object.values(this.entities)) { + this.worldRenderer.scene.remove(mesh) + disposeObject(mesh) + } + this.entities = {} + + // Clean up player entity + if (this.playerEntity) { + this.worldRenderer.scene.remove(this.playerEntity) + disposeObject(this.playerEntity) + this.playerEntity = null + } + } + + reloadEntities () { + for (const entity of Object.values(this.entities)) { + // update all entities textures like held items, armour, etc + // todo update entity textures itself + this.update({ ...entity.originalEntity, delete: true, } as SceneEntity['originalEntity'], {}) + this.update(entity.originalEntity, {}) + } + } + + watchResourcesUpdates () { + this.worldRenderer.resourcesManager.on('assetsTexturesUpdated', () => this.reloadEntities()) + this.worldRenderer.resourcesManager.on('assetsInventoryReady', () => this.reloadEntities()) + } + + setDebugMode (mode: string, entity: THREE.Object3D | null = null) { + this.debugMode = mode + for (const mesh of entity ? [entity] : Object.values(this.entities)) { + const boxHelper = mesh.children.find(c => c.name === 'debug')! + boxHelper.visible = false + if (this.debugMode === 'basic') { + boxHelper.visible = true + } + // todo advanced + } + } + + setRendering (rendering: boolean, entity: THREE.Object3D | null = null) { + this.currentlyRendering = rendering + for (const ent of entity ? [entity] : Object.values(this.entities)) { + if (rendering) { + if (!this.worldRenderer.scene.children.includes(ent)) this.worldRenderer.scene.add(ent) + } else { + this.worldRenderer.scene.remove(ent) + } + } + } + + render () { + const renderEntitiesConfig = this.worldRenderer.worldRendererConfig.renderEntities + if (renderEntitiesConfig !== this.currentlyRendering) { + this.setRendering(renderEntitiesConfig) + } + + const dt = this.clock.getDelta() + const botPos = this.worldRenderer.viewerChunkPosition + const VISIBLE_DISTANCE = 10 * 10 + + // Update regular entities + for (const [entityId, entity] of [...Object.entries(this.entities), ['player_entity', this.playerEntity] as [string, SceneEntity | null]]) { + if (!entity) continue + const { playerObject } = entity + + // Update animations + if (playerObject?.animation) { + playerObject.animation.update(playerObject, dt) + } + + // Update visibility based on distance and chunk load status + if (botPos && entity.position) { + const dx = entity.position.x - botPos.x + const dy = entity.position.y - botPos.y + const dz = entity.position.z - botPos.z + const distanceSquared = dx * dx + dy * dy + dz * dz + + // Entity is visible if within 20 blocks OR in a finished chunk + entity.visible = !!(distanceSquared < VISIBLE_DISTANCE || this.worldRenderer.shouldObjectVisible(entity)) + + this.maybeRenderPlayerSkin(entityId) + } + + if (entity.visible) { + // Update armor positions + this.syncArmorPositions(entity) + } + + if (entityId === 'player_entity') { + entity.visible = this.worldRenderer.playerStateUtils.isThirdPerson() + + if (entity.visible) { + // sync + const yOffset = this.worldRenderer.playerStateReactive.eyeHeight + const pos = this.worldRenderer.cameraObject.position.clone().add(new THREE.Vector3(0, -yOffset, 0)) + entity.position.set(pos.x, pos.y, pos.z) + + const rotation = this.worldRenderer.cameraShake.getBaseRotation() + entity.rotation.set(0, rotation.yaw, 0) + + // Sync head rotation + entity.traverse((c) => { + if (c.name === 'head') { + c.rotation.set(-rotation.pitch, 0, 0) + } + }) + } + } + } + } + + private syncArmorPositions (entity: SceneEntity) { + if (!entity.playerObject) return + + // todo-low use property access for less loop iterations (small performance gain) + entity.traverse((armor) => { + if (!armor.name.startsWith('geometry_armor_')) return + + const { skin } = entity.playerObject! + + switch (armor.name) { + case 'geometry_armor_head': + // Head armor sync + if (armor.children[0]?.children[0]) { + armor.children[0].children[0].rotation.set( + -skin.head.rotation.x, + skin.head.rotation.y, + skin.head.rotation.z, + skin.head.rotation.order + ) + } + break + + case 'geometry_armor_legs': + // Legs armor sync + if (armor.children[0]) { + // Left leg + if (armor.children[0].children[2]) { + armor.children[0].children[2].rotation.set( + -skin.leftLeg.rotation.x, + skin.leftLeg.rotation.y, + skin.leftLeg.rotation.z, + skin.leftLeg.rotation.order + ) + } + // Right leg + if (armor.children[0].children[1]) { + armor.children[0].children[1].rotation.set( + -skin.rightLeg.rotation.x, + skin.rightLeg.rotation.y, + skin.rightLeg.rotation.z, + skin.rightLeg.rotation.order + ) + } + } + break + + case 'geometry_armor_feet': + // Boots armor sync + if (armor.children[0]) { + // Right boot + if (armor.children[0].children[0]) { + armor.children[0].children[0].rotation.set( + -skin.rightLeg.rotation.x, + skin.rightLeg.rotation.y, + skin.rightLeg.rotation.z, + skin.rightLeg.rotation.order + ) + } + // Left boot (reversed Z rotation) + if (armor.children[0].children[1]) { + armor.children[0].children[1].rotation.set( + -skin.leftLeg.rotation.x, + skin.leftLeg.rotation.y, + -skin.leftLeg.rotation.z, + skin.leftLeg.rotation.order + ) + } + } + break + } + }) + } + + getPlayerObject (entityId: string | number) { + if (this.playerEntity?.originalEntity.id === entityId) return this.playerEntity?.playerObject + const playerObject = this.entities[entityId]?.playerObject + return playerObject + } + + uuidPerSkinUrlsCache = {} as Record + + private isCanvasBlank (canvas: HTMLCanvasElement): boolean { + return !canvas.getContext('2d') + ?.getImageData(0, 0, canvas.width, canvas.height).data + .some(channel => channel !== 0) + } + + // todo true/undefined doesnt reset the skin to the default one + // eslint-disable-next-line max-params + async updatePlayerSkin (entityId: string | number, username: string | undefined, uuidCache: string | undefined, skinUrl: string | true, capeUrl: string | true | undefined = undefined) { + const isCustomSkin = skinUrl !== stevePngUrl + if (isCustomSkin) { + this.loadedSkinEntityIds.add(String(entityId)) + } + if (uuidCache) { + if (typeof skinUrl === 'string' || typeof capeUrl === 'string') this.uuidPerSkinUrlsCache[uuidCache] = {} + if (typeof skinUrl === 'string') this.uuidPerSkinUrlsCache[uuidCache].skinUrl = skinUrl + if (typeof capeUrl === 'string') this.uuidPerSkinUrlsCache[uuidCache].capeUrl = capeUrl + if (skinUrl === true) { + skinUrl = this.uuidPerSkinUrlsCache[uuidCache]?.skinUrl ?? skinUrl + } + capeUrl ??= this.uuidPerSkinUrlsCache[uuidCache]?.capeUrl + } + + const playerObject = this.getPlayerObject(entityId) + if (!playerObject) return + + if (skinUrl === true) { + if (!username) return + const newSkinUrl = await loadSkinFromUsername(username, 'skin') + if (!this.getPlayerObject(entityId)) return + if (!newSkinUrl) return + skinUrl = newSkinUrl + } + + if (typeof skinUrl !== 'string') throw new Error('Invalid skin url') + const renderEars = this.worldRenderer.worldRendererConfig.renderEars || username === 'deadmau5' + void this.loadAndApplySkin(entityId, skinUrl, renderEars).then(async () => { + if (capeUrl) { + if (capeUrl === true && username) { + const newCapeUrl = await loadSkinFromUsername(username, 'cape') + if (!this.getPlayerObject(entityId)) return + if (!newCapeUrl) return + capeUrl = newCapeUrl + } + if (typeof capeUrl === 'string') { + void this.loadAndApplyCape(entityId, capeUrl) + } + } + }) + + + playerObject.cape.visible = false + if (!capeUrl) { + playerObject.backEquipment = null + playerObject.elytra.map = null + if (playerObject.cape.map) { + playerObject.cape.map.dispose() + } + playerObject.cape.map = null + } + } + + private async loadAndApplySkin (entityId: string | number, skinUrl: string, renderEars: boolean) { + let playerObject = this.getPlayerObject(entityId) + if (!playerObject) return + + try { + let playerCustomSkinImage: ImageBitmap | undefined + + playerObject = this.getPlayerObject(entityId) + if (!playerObject) return + + let skinTexture: THREE.Texture + let skinCanvas: OffscreenCanvas + if (skinUrl === stevePngUrl) { + skinTexture = await steveTexture + const canvas = createCanvas(64, 64) + const ctx = canvas.getContext('2d') + if (!ctx) throw new Error('Failed to get context') + ctx.drawImage(skinTexture.image, 0, 0) + skinCanvas = canvas + } else { + const { canvas, image } = await loadSkinImage(skinUrl) + playerCustomSkinImage = image + skinTexture = new THREE.CanvasTexture(canvas) + skinCanvas = canvas + } + + skinTexture.magFilter = THREE.NearestFilter + skinTexture.minFilter = THREE.NearestFilter + skinTexture.needsUpdate = true + playerObject.skin.map = skinTexture as any + playerObject.skin.modelType = inferModelType(skinCanvas) + + let earsCanvas: HTMLCanvasElement | undefined + if (!playerCustomSkinImage) { + renderEars = false + } else if (renderEars) { + earsCanvas = document.createElement('canvas') + loadEarsToCanvasFromSkin(earsCanvas, playerCustomSkinImage) + renderEars = !this.isCanvasBlank(earsCanvas) + } + if (renderEars) { + const earsTexture = new THREE.CanvasTexture(earsCanvas!) + earsTexture.magFilter = THREE.NearestFilter + earsTexture.minFilter = THREE.NearestFilter + earsTexture.needsUpdate = true + //@ts-expect-error + playerObject.ears.map = earsTexture + playerObject.ears.visible = true + } else { + playerObject.ears.map = null + playerObject.ears.visible = false + } + this.onSkinUpdate?.() + } catch (error) { + console.error('Error loading skin:', error) + } + } + + private async loadAndApplyCape (entityId: string | number, capeUrl: string) { + let playerObject = this.getPlayerObject(entityId) + if (!playerObject) return + + try { + const { canvas: capeCanvas, image: capeImage } = await loadSkinImage(capeUrl) + + playerObject = this.getPlayerObject(entityId) + if (!playerObject) return + + loadCapeToCanvas(capeCanvas, capeImage) + const capeTexture = new THREE.CanvasTexture(capeCanvas) + capeTexture.magFilter = THREE.NearestFilter + capeTexture.minFilter = THREE.NearestFilter + capeTexture.needsUpdate = true + //@ts-expect-error + playerObject.cape.map = capeTexture + playerObject.cape.visible = true + //@ts-expect-error + playerObject.elytra.map = capeTexture + this.onSkinUpdate?.() + + if (!playerObject.backEquipment) { + playerObject.backEquipment = 'cape' + } + } catch (error) { + console.error('Error loading cape:', error) + } + } + + debugSwingArm () { + const playerObject = Object.values(this.entities).find(entity => entity.playerObject?.animation instanceof WalkingGeneralSwing) + if (!playerObject) return + (playerObject.playerObject!.animation as WalkingGeneralSwing).swingArm() + } + + playAnimation (entityPlayerId, animation: 'walking' | 'running' | 'oneSwing' | 'idle' | 'crouch' | 'crouchWalking') { + // TODO CLEANUP! + // Handle special player entity ID for bot entity in third person + if (entityPlayerId === 'player_entity' && this.playerEntity?.playerObject) { + const { playerObject } = this.playerEntity + if (animation === 'oneSwing') { + if (!(playerObject.animation instanceof WalkingGeneralSwing)) throw new Error('Expected WalkingGeneralSwing') + playerObject.animation.swingArm() + return + } + + if (playerObject.animation instanceof WalkingGeneralSwing) { + playerObject.animation.switchAnimationCallback = () => { + if (!(playerObject.animation instanceof WalkingGeneralSwing)) throw new Error('Expected WalkingGeneralSwing') + playerObject.animation.isMoving = animation === 'walking' || animation === 'running' || animation === 'crouchWalking' + playerObject.animation.isRunning = animation === 'running' + playerObject.animation.isCrouched = animation === 'crouch' || animation === 'crouchWalking' + } + } + return + } + + // Handle regular entities + const playerObject = this.getPlayerObject(entityPlayerId) + if (playerObject) { + if (animation === 'oneSwing') { + if (!(playerObject.animation instanceof WalkingGeneralSwing)) throw new Error('Expected WalkingGeneralSwing') + playerObject.animation.swingArm() + return + } + + if (playerObject.animation instanceof WalkingGeneralSwing) { + playerObject.animation.switchAnimationCallback = () => { + if (!(playerObject.animation instanceof WalkingGeneralSwing)) throw new Error('Expected WalkingGeneralSwing') + playerObject.animation.isMoving = animation === 'walking' || animation === 'running' || animation === 'crouchWalking' + playerObject.animation.isRunning = animation === 'running' + playerObject.animation.isCrouched = animation === 'crouch' || animation === 'crouchWalking' + } + } + return + } + + // Handle player entity (for third person view) - fallback for backwards compatibility + if (this.playerEntity?.playerObject) { + const { playerObject: playerEntityObject } = this.playerEntity + if (animation === 'oneSwing') { + if (!(playerEntityObject.animation instanceof WalkingGeneralSwing)) throw new Error('Expected WalkingGeneralSwing') + playerEntityObject.animation.swingArm() + return + } + + if (playerEntityObject.animation instanceof WalkingGeneralSwing) { + playerEntityObject.animation.switchAnimationCallback = () => { + if (!(playerEntityObject.animation instanceof WalkingGeneralSwing)) throw new Error('Expected WalkingGeneralSwing') + playerEntityObject.animation.isMoving = animation === 'walking' || animation === 'running' || animation === 'crouchWalking' + playerEntityObject.animation.isRunning = animation === 'running' + playerEntityObject.animation.isCrouched = animation === 'crouch' || animation === 'crouchWalking' + } + } + } + } + + parseEntityLabel (jsonLike) { + if (!jsonLike) return + try { + if (jsonLike.type === 'string') { + return jsonLike.value + } + const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike) + const text = flat(parsed).map(this.textFromComponent) + return text.join('') + } catch (err) { + return jsonLike + } + } + + private textFromComponent (component) { + return typeof component === 'string' ? component : component.text ?? '' + } + + getItemMesh (item, specificProps: ItemSpecificContextProperties, faceCamera = false, previousModel?: string) { + if (!item.nbt && item.nbtData) item.nbt = item.nbtData + const textureUv = this.worldRenderer.getItemRenderData(item, specificProps) + if (previousModel && previousModel === textureUv?.modelName) return undefined + + if (textureUv && 'resolvedModel' in textureUv) { + const mesh = getBlockMeshFromModel(this.worldRenderer.material, textureUv.resolvedModel, textureUv.modelName, this.worldRenderer.resourcesManager.currentResources.worldBlockProvider!) + let SCALE = 1 + if (specificProps['minecraft:display_context'] === 'ground') { + SCALE = 0.5 + } else if (specificProps['minecraft:display_context'] === 'thirdperson') { + SCALE = 6 + } + mesh.scale.set(SCALE, SCALE, SCALE) + const outerGroup = new THREE.Group() + outerGroup.add(mesh) + return { + mesh: outerGroup, + isBlock: true, + modelName: textureUv.modelName, + } + } + + // Render proper 3D model for items + if (textureUv) { + const textureThree = textureUv.renderInfo?.texture === 'blocks' ? this.worldRenderer.material.map! : this.worldRenderer.itemsTexture + const { u, v, su, sv } = textureUv + const sizeX = su ?? 1 // su is actually width + const sizeY = sv ?? 1 // sv is actually height + + // Use the new unified item mesh function + const result = createItemMesh(textureThree, { + u, + v, + sizeX, + sizeY + }, { + faceCamera, + use3D: !faceCamera, // Only use 3D for non-camera-facing items + }) + + let SCALE = 1 + if (specificProps['minecraft:display_context'] === 'ground') { + SCALE = 0.5 + } else if (specificProps['minecraft:display_context'] === 'thirdperson') { + SCALE = 6 + } + result.mesh.scale.set(SCALE, SCALE, SCALE) + + return { + mesh: result.mesh, + isBlock: false, + modelName: textureUv.modelName, + cleanup: result.cleanup + } + } + } + + setVisible (mesh: THREE.Object3D, visible: boolean) { + //mesh.visible = visible + //TODO: Fix workaround for visibility setting + if (visible) { + mesh.scale.set(1, 1, 1) + } else { + mesh.scale.set(0, 0, 0) + } + } + + update (entity: SceneEntity['originalEntity'], overrides) { + const isPlayerModel = entity.name === 'player' + if (entity.name === 'zombie_villager' || entity.name === 'husk') { + overrides.texture = `textures/1.16.4/entity/${entity.name === 'zombie_villager' ? 'zombie_villager/zombie_villager.png' : `zombie/${entity.name}.png`}` + } + if (entity.name === 'glow_item_frame') { + if (!overrides.textures) overrides.textures = [] + overrides.textures['background'] = 'block:glow_item_frame' + } + // this can be undefined in case where packet entity_destroy was sent twice (so it was already deleted) + let e = this.entities[entity.id] + const justAdded = !e + + if (entity.delete) { + if (!e) return + if (e.additionalCleanup) e.additionalCleanup() + e.traverse(c => { + if (c['additionalCleanup']) c['additionalCleanup']() + }) + this.onRemoveEntity(entity) + this.worldRenderer.scene.remove(e) + disposeObject(e) + // todo dispose textures as well ? + delete this.entities[entity.id] + return + } + + let mesh: THREE.Object3D | undefined + if (e === undefined) { + const group = new THREE.Group() as unknown as SceneEntity + group.originalEntity = entity + if (entity.name === 'item' || entity.name === 'tnt' || entity.name === 'falling_block' || entity.name === 'snowball' + || entity.name === 'egg' || entity.name === 'ender_pearl' || entity.name === 'experience_bottle' + || entity.name === 'splash_potion' || entity.name === 'lingering_potion') { + const item = entity.name === 'tnt' || entity.type === 'projectile' + ? { name: entity.name } + : entity.name === 'falling_block' + ? { blockState: entity['objectData'] } + : entity.metadata?.find((m: any) => typeof m === 'object' && m?.itemCount) + if (item) { + const object = this.getItemMesh(item, { + 'minecraft:display_context': 'ground', + }, entity.type === 'projectile') + if (object) { + mesh = object.mesh + if (entity.name === 'item' || entity.type === 'projectile') { + mesh.scale.set(0.5, 0.5, 0.5) + mesh.position.set(0, entity.name === 'item' ? 0.2 : 0.1, 0) + } else { + mesh.scale.set(2, 2, 2) + mesh.position.set(0, 0.5, 0) + } + // set faces + // mesh.position.set(targetPos.x + 0.5 + 2, targetPos.y + 0.5, targetPos.z + 0.5) + // viewer.scene.add(mesh) + if (entity.name === 'item') { + const clock = new THREE.Clock() + mesh.onBeforeRender = () => { + const delta = clock.getDelta() + mesh!.rotation.y += delta + } + } + + // TNT blinking + // if (entity.name === 'tnt') { + // let lastBlink = 0 + // const blinkInterval = 500 // ms between blinks + // mesh.onBeforeRender = () => { + // const now = Date.now() + // if (now - lastBlink > blinkInterval) { + // lastBlink = now + // mesh.traverse((child) => { + // if (child instanceof THREE.Mesh) { + // const material = child.material as THREE.MeshLambertMaterial + // material.color.set(material.color?.equals(new THREE.Color(0xff_ff_ff)) + // ? new THREE.Color(0xff_00_00) + // : new THREE.Color(0xff_ff_ff)) + // } + // }) + // } + // } + // } + + group.additionalCleanup = () => { + // important: avoid texture memory leak and gpu slowdown + if (object.cleanup) { + object.cleanup() + } + } + } + } + } else if (isPlayerModel) { + const wrapper = new THREE.Group() + const playerObject = this.setupPlayerObject(entity, wrapper, overrides) + group.playerObject = playerObject + mesh = wrapper + + if (entity.username) { + const nametag = addNametag(entity, { fontFamily: 'mojangles' }, wrapper, this.worldRenderer.version) + if (nametag) { + nametag.position.y = playerObject.position.y + playerObject.scale.y * 16 + 3 + nametag.scale.multiplyScalar(12) + } + } + } else { + mesh = getEntityMesh(entity, this.worldRenderer, this.entitiesOptions, { ...overrides, customModel: entity['customModel'] }) + } + if (!mesh) return + mesh.name = 'mesh' + // set initial position so there are no weird jumps update after + const pos = entity.pos ?? entity.position + group.position.set(pos.x, pos.y, pos.z) + + // todo use width and height instead + const boxHelper = new THREE.BoxHelper( + mesh, + entity.type === 'hostile' ? 0xff_00_00 : + entity.type === 'mob' ? 0x00_ff_00 : + entity.type === 'player' ? 0x00_00_ff : + 0xff_a5_00, + ) + boxHelper.name = 'debug' + group.add(mesh) + group.add(boxHelper) + boxHelper.visible = false + this.worldRenderer.scene.add(group) + + e = group + e.name = 'entity' + e['realName'] = entity.name + this.entities[entity.id] = e + + this.onAddEntity(entity) + + if (isPlayerModel) { + void this.updatePlayerSkin(entity.id, entity.username, overrides?.texture ? entity.uuid : undefined, overrides?.texture || stevePngUrl) + } + this.setDebugMode(this.debugMode, group) + this.setRendering(this.currentlyRendering, group) + } else { + mesh = e.children.find(c => c.name === 'mesh') + } + + // Update equipment + this.updateEntityEquipment(e, entity) + + const meta = getGeneralEntitiesMetadata(entity) + + const isInvisible = ((entity.metadata?.[0] ?? 0) as unknown as number) & 0x20 || (this.worldRenderer.playerStateReactive.cameraSpectatingEntity === entity.id && this.worldRenderer.playerStateUtils.isSpectator()) + for (const child of mesh!.children ?? []) { + if (child.name !== 'nametag') { + child.visible = !isInvisible + } + } + // --- + // set baby size + if (meta.baby) { + e.scale.set(0.5, 0.5, 0.5) + } else { + e.scale.set(1, 1, 1) + } + // entity specific meta + const textDisplayMeta = getSpecificEntityMetadata('text_display', entity) + const displayTextRaw = textDisplayMeta?.text || meta.custom_name_visible && meta.custom_name + if (entity.name !== 'player' && displayTextRaw) { + const nameTagFixed = textDisplayMeta && (textDisplayMeta.billboard_render_constraints === 'fixed' || !textDisplayMeta.billboard_render_constraints) + const nameTagBackgroundColor = (textDisplayMeta && (parseInt(textDisplayMeta.style_flags, 10) & 0x04) === 0) ? toRgba(textDisplayMeta.background_color) : undefined + let nameTagTextOpacity: any + if (textDisplayMeta?.text_opacity) { + const rawOpacity = parseInt(textDisplayMeta?.text_opacity, 10) + nameTagTextOpacity = rawOpacity > 0 ? rawOpacity : 256 - rawOpacity + } + addNametag( + { ...entity, username: typeof displayTextRaw === 'string' ? mojangson.simplify(mojangson.parse(displayTextRaw)) : nbt.simplify(displayTextRaw), + nameTagBackgroundColor, nameTagTextOpacity, nameTagFixed, + nameTagScale: textDisplayMeta?.scale, nameTagTranslation: textDisplayMeta && (textDisplayMeta.translation || new THREE.Vector3(0, 0, 0)), + nameTagRotationLeft: toQuaternion(textDisplayMeta?.left_rotation), nameTagRotationRight: toQuaternion(textDisplayMeta?.right_rotation) }, + this.entitiesOptions, + mesh, + this.worldRenderer.version + ) + } + + const armorStandMeta = getSpecificEntityMetadata('armor_stand', entity) + if (armorStandMeta) { + const isSmall = (parseInt(armorStandMeta.client_flags, 10) & 0x01) !== 0 + const hasArms = (parseInt(armorStandMeta.client_flags, 10) & 0x04) !== 0 + const hasBasePlate = (parseInt(armorStandMeta.client_flags, 10) & 0x08) === 0 + const isMarker = (parseInt(armorStandMeta.client_flags, 10) & 0x10) !== 0 + mesh!.castShadow = !isMarker + mesh!.receiveShadow = !isMarker + if (isSmall) { + e.scale.set(0.5, 0.5, 0.5) + } else { + e.scale.set(1, 1, 1) + } + e.traverse(c => { + switch (c.name) { + case 'bone_baseplate': + this.setVisible(c, hasBasePlate) + c.rotation.y = -e.rotation.y + break + case 'bone_head': + if (armorStandMeta.head_pose) { + c.setRotationFromEuler(poseToEuler(armorStandMeta.head_pose)) + } + break + case 'bone_body': + if (armorStandMeta.body_pose) { + c.setRotationFromEuler(poseToEuler(armorStandMeta.body_pose)) + } + break + case 'bone_rightarm': + if (c.parent?.name !== 'bone_armor') { + this.setVisible(c, hasArms) + } + if (armorStandMeta.left_arm_pose) { + c.setRotationFromEuler(poseToEuler(armorStandMeta.left_arm_pose)) + } else { + c.setRotationFromEuler(poseToEuler({ 'yaw': -10, 'pitch': -10, 'roll': 0 })) + } + break + case 'bone_leftarm': + if (c.parent?.name !== 'bone_armor') { + this.setVisible(c, hasArms) + } + if (armorStandMeta.right_arm_pose) { + c.setRotationFromEuler(poseToEuler(armorStandMeta.right_arm_pose)) + } else { + c.setRotationFromEuler(poseToEuler({ 'yaw': 10, 'pitch': -10, 'roll': 0 })) + } + break + case 'bone_rightleg': + if (armorStandMeta.left_leg_pose) { + c.setRotationFromEuler(poseToEuler(armorStandMeta.left_leg_pose)) + } else { + c.setRotationFromEuler(poseToEuler({ 'yaw': -1, 'pitch': -1, 'roll': 0 })) + } + break + case 'bone_leftleg': + if (armorStandMeta.right_leg_pose) { + c.setRotationFromEuler(poseToEuler(armorStandMeta.right_leg_pose)) + } else { + c.setRotationFromEuler(poseToEuler({ 'yaw': 1, 'pitch': 1, 'roll': 0 })) + } + break + } + }) + } + + // todo handle map, map_chunks events + let itemFrameMeta = getSpecificEntityMetadata('item_frame', entity) + if (!itemFrameMeta) { + itemFrameMeta = getSpecificEntityMetadata('glow_item_frame', entity) + } + if (itemFrameMeta) { + // TODO: fix type + // todo! fix errors in mc-data (no entities data prior 1.18.2) + const item = (itemFrameMeta?.item ?? entity.metadata?.[8]) as any as { itemId, blockId, components, nbtData: { value: { map: { value: number } } } } + mesh!.scale.set(1, 1, 1) + mesh!.position.set(0, 0, -0.5) + + e.rotation.x = -entity.pitch + e.children.find(c => { + if (c.name.startsWith('map_')) { + disposeObject(c) + const existingMapNumber = parseInt(c.name.split('_')[1], 10) + this.itemFrameMaps[existingMapNumber] = this.itemFrameMaps[existingMapNumber]?.filter(mesh => mesh !== c) + if (c instanceof THREE.Mesh) { + c.material?.map?.dispose() + } + return true + } else if (c.name === 'item') { + disposeObject(c) + return true + } + return false + })?.removeFromParent() + + if (item && (item.itemId ?? item.blockId ?? 0) !== 0) { + // Get rotation from metadata, default to 0 if not present + // Rotation is stored in 45° increments (0-7) for items, 90° increments (0-3) for maps + const rotation = (itemFrameMeta.rotation as any as number) ?? 0 + const mapNumber = item.nbtData?.value?.map?.value ?? item.components?.find(x => x.type === 'map_id')?.data + if (mapNumber) { + // TODO: Use proper larger item frame model when a map exists + mesh!.scale.set(16 / 12, 16 / 12, 1) + // Handle map rotation (4 possibilities, 90° increments) + this.addMapModel(e, mapNumber, rotation) + } else { + // Handle regular item rotation (8 possibilities, 45° increments) + const itemMesh = this.getItemMesh(item, { + 'minecraft:display_context': 'fixed', + }) + if (itemMesh) { + itemMesh.mesh.position.set(0, 0, -0.05) + // itemMesh.mesh.position.set(0, 0, 0.43) + if (itemMesh.isBlock) { + itemMesh.mesh.scale.set(0.25, 0.25, 0.25) + } else { + itemMesh.mesh.scale.set(0.5, 0.5, 0.5) + } + // Rotate 180° around Y axis first + itemMesh.mesh.rotateY(Math.PI) + // Then apply the 45° increment rotation + itemMesh.mesh.rotateZ(-rotation * Math.PI / 4) + itemMesh.mesh.name = 'item' + e.add(itemMesh.mesh) + } + } + } + } + + if (entity.username !== undefined) { + e.username = entity.username + } + + this.updateNameTagVisibility(e) + + this.updateEntityPosition(entity, justAdded, overrides) + } + + updateEntityPosition (entity: import('prismarine-entity').Entity, justAdded: boolean, overrides: { rotation?: { head?: { y: number, x: number } } }) { + const e = this.entities[entity.id] + if (!e) return + const ANIMATION_DURATION = justAdded ? 0 : TWEEN_DURATION + if (entity.position) { + new TWEEN.Tween(e.position).to({ x: entity.position.x, y: entity.position.y, z: entity.position.z }, ANIMATION_DURATION).start() + } + if (entity.yaw) { + const da = (entity.yaw - e.rotation.y) % (Math.PI * 2) + const dy = 2 * da % (Math.PI * 2) - da + new TWEEN.Tween(e.rotation).to({ y: e.rotation.y + dy }, ANIMATION_DURATION).start() + } + + if (e?.playerObject && overrides?.rotation?.head) { + const { playerObject } = e + const headRotationDiff = overrides.rotation.head.y ? overrides.rotation.head.y - entity.yaw : 0 + playerObject.skin.head.rotation.y = -headRotationDiff + playerObject.skin.head.rotation.x = overrides.rotation.head.x ? - overrides.rotation.head.x : 0 + } + } + + onAddEntity (entity: import('prismarine-entity').Entity) { + } + + loadedSkinEntityIds = new Set() + maybeRenderPlayerSkin (entityId: string) { + let mesh = this.entities[entityId] + if (entityId === 'player_entity') { + mesh = this.playerEntity! + entityId = this.playerEntity?.originalEntity.id as any + } + if (!mesh) return + if (!mesh.playerObject) return + if (!mesh.visible) return + + const MAX_DISTANCE_SKIN_LOAD = 128 + const cameraPos = this.worldRenderer.cameraObject.position + const distance = mesh.position.distanceTo(cameraPos) + if (distance < MAX_DISTANCE_SKIN_LOAD && distance < (this.worldRenderer.viewDistance * 16)) { + if (this.loadedSkinEntityIds.has(String(entityId))) return + void this.updatePlayerSkin(entityId, mesh.playerObject.realUsername, mesh.playerObject.realPlayerUuid, true, true) + } + } + + playerPerAnimation = {} as Record + onRemoveEntity (entity: import('prismarine-entity').Entity) { + this.loadedSkinEntityIds.delete(entity.id.toString()) + } + + updateMap (mapNumber: string | number, data: string) { + this.cachedMapsImages[mapNumber] = data + let itemFrameMeshes = this.itemFrameMaps[mapNumber] + if (!itemFrameMeshes) return + itemFrameMeshes = itemFrameMeshes.filter(mesh => mesh.parent) + this.itemFrameMaps[mapNumber] = itemFrameMeshes + if (itemFrameMeshes) { + for (const mesh of itemFrameMeshes) { + mesh.material.map = this.loadMap(data) + mesh.material.needsUpdate = true + mesh.visible = true + } + } + } + + updateNameTagVisibility (entity: SceneEntity) { + const playerTeam = this.worldRenderer.playerStateReactive.team + const entityTeam = entity.originalEntity.team + const nameTagVisibility = entityTeam?.nameTagVisibility || 'always' + const showNameTag = nameTagVisibility === 'always' || + (nameTagVisibility === 'hideForOwnTeam' && entityTeam?.team !== playerTeam?.team) || + (nameTagVisibility === 'hideForOtherTeams' && (entityTeam?.team === playerTeam?.team || playerTeam === undefined)) + entity.traverse(c => { + if (c.name === 'nametag') { + c.visible = showNameTag + } + }) + } + + addMapModel (entityMesh: THREE.Object3D, mapNumber: number, rotation: number) { + const imageData = this.cachedMapsImages?.[mapNumber] + let texture: THREE.Texture | null = null + if (imageData) { + texture = this.loadMap(imageData) + } + const parameters = { + transparent: true, + alphaTest: 0.1, + } + if (texture) { + parameters['map'] = texture + } + const material = new THREE.MeshLambertMaterial(parameters) + + const mapMesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), material) + + mapMesh.rotation.set(0, Math.PI, 0) + entityMesh.add(mapMesh) + let isInvisible = true + entityMesh.traverseVisible(c => { + if (c.name === 'geometry_frame') { + isInvisible = false + } + }) + if (isInvisible) { + mapMesh.position.set(0, 0, 0.499) + } else { + mapMesh.position.set(0, 0, 0.437) + } + // Apply 90° increment rotation for maps (0-3) + mapMesh.rotateZ(Math.PI * 2 - rotation * Math.PI / 2) + mapMesh.name = `map_${mapNumber}` + + if (!texture) { + mapMesh.visible = false + } + + if (!this.itemFrameMaps[mapNumber]) { + this.itemFrameMaps[mapNumber] = [] + } + this.itemFrameMaps[mapNumber].push(mapMesh) + } + + loadMap (data: any) { + const texture = new THREE.TextureLoader().load(data) + if (texture) { + texture.magFilter = THREE.NearestFilter + texture.minFilter = THREE.NearestFilter + texture.needsUpdate = true + } + return texture + } + + addItemModel (entityMesh: SceneEntity, hand: 'left' | 'right', item: Item, isPlayer = false) { + const bedrockParentName = `bone_${hand}item` + const itemName = `custom_item_${hand}` + + // remove existing item + entityMesh.traverse(c => { + if (c.name === itemName) { + c.removeFromParent() + if (c['additionalCleanup']) c['additionalCleanup']() + } + }) + if (!item) return + + const itemObject = this.getItemMesh(item, { + 'minecraft:display_context': 'thirdperson', + }) + if (itemObject?.mesh) { + entityMesh.traverse(c => { + if (c.name.toLowerCase() === bedrockParentName || c.name === `${hand}Arm`) { + const group = new THREE.Object3D() + group['additionalCleanup'] = () => { + // important: avoid texture memory leak and gpu slowdown + if (itemObject.cleanup) { + itemObject.cleanup() + } + } + const itemMesh = itemObject.mesh + group.rotation.z = -Math.PI / 16 + if (itemObject.isBlock) { + group.rotation.y = Math.PI / 4 + } else { + itemMesh.rotation.z = -Math.PI / 4 + group.rotation.y = Math.PI / 2 + group.scale.multiplyScalar(2) + } + + // if player, move item below and forward a bit + if (isPlayer) { + group.position.y = -8 + group.position.z = 5 + group.position.x = hand === 'left' ? 1 : -1 + group.rotation.x = Math.PI + } + + group.add(itemMesh) + + group.name = itemName + c.add(group) + } + }) + } + } + + handleDamageEvent (entityId, damageAmount) { + const entityMesh = this.entities[entityId]?.children.find(c => c.name === 'mesh') + if (entityMesh) { + entityMesh.traverse((child) => { + if (child instanceof THREE.Mesh && child.material.clone) { + const clonedMaterial = child.material.clone() + clonedMaterial.dispose() + child.material = child.material.clone() + const originalColor = child.material.color.clone() + child.material.color.set(0xff_00_00) + new TWEEN.Tween(child.material.color) + .to(originalColor, 500) + .start() + } + }) + } + } + + raycastSceneDebug () { + // return any object from scene. raycast from camera + const raycaster = new THREE.Raycaster() + raycaster.setFromCamera(new THREE.Vector2(0, 0), this.worldRenderer.camera) + const intersects = raycaster.intersectObjects(this.worldRenderer.scene.children) + return intersects[0]?.object + } + + private setupPlayerObject (entity: SceneEntity['originalEntity'], wrapper: THREE.Group, overrides: { texture?: string }): PlayerObjectType { + const playerObject = new PlayerObject() as PlayerObjectType + playerObject.realPlayerUuid = entity.uuid ?? '' + playerObject.realUsername = entity.username ?? '' + playerObject.position.set(0, 16, 0) + + // fix issues with starfield + playerObject.traverse((obj) => { + if (obj instanceof THREE.Mesh && obj.material instanceof THREE.MeshStandardMaterial) { + obj.material.transparent = true + } + }) + + wrapper.add(playerObject as any) + const scale = 1 / 16 + wrapper.scale.set(scale, scale, scale) + wrapper.rotation.set(0, Math.PI, 0) + + // Set up animation + playerObject.animation = new WalkingGeneralSwing() + //@ts-expect-error + playerObject.animation.isMoving = false + + return playerObject + } + + private updateEntityEquipment (entityMesh: SceneEntity, entity: SceneEntity['originalEntity']) { + if (!entityMesh || !entity.equipment) return + + const isPlayer = entity.type === 'player' + this.addItemModel(entityMesh, isPlayer ? 'right' : 'left', entity.equipment[0], isPlayer) + this.addItemModel(entityMesh, isPlayer ? 'left' : 'right', entity.equipment[1], isPlayer) + addArmorModel(this.worldRenderer, entityMesh, 'feet', entity.equipment[2]) + addArmorModel(this.worldRenderer, entityMesh, 'legs', entity.equipment[3], 2) + addArmorModel(this.worldRenderer, entityMesh, 'chest', entity.equipment[4]) + addArmorModel(this.worldRenderer, entityMesh, 'head', entity.equipment[5]) + + // Update player-specific equipment + if (isPlayer && entityMesh.playerObject) { + const { playerObject } = entityMesh + playerObject.backEquipment = entity.equipment.some((item) => item?.name === 'elytra') ? 'elytra' : 'cape' + if (playerObject.backEquipment === 'elytra') { + void this.loadAndApplyCape(entity.id, elytraTexture) + } + if (playerObject.cape.map === null) { + playerObject.cape.visible = false + } + } + } +} + +function getGeneralEntitiesMetadata (entity: { name; metadata }): Partial> { + const entityData = loadedData.entitiesByName[entity.name] + return new Proxy({}, { + get (target, p, receiver) { + if (typeof p !== 'string' || !entityData) return + const index = entityData.metadataKeys?.indexOf(p) + return entity.metadata?.[index ?? -1] + }, + }) +} + +function getSpecificEntityMetadata (name: T, entity): EntityMetadataVersions[T] | undefined { + if (entity.name !== name) return + return getGeneralEntitiesMetadata(entity) as any +} + +function addArmorModel (worldRenderer: WorldRendererThree, entityMesh: THREE.Object3D, slotType: string, item: Item, layer = 1, overlay = false) { + if (!item) { + removeArmorModel(entityMesh, slotType) + return + } + const itemParts = item.name.split('_') + let texturePath + const isPlayerHead = slotType === 'head' && item.name === 'player_head' + if (isPlayerHead) { + removeArmorModel(entityMesh, slotType) + if (item.nbt) { + const itemNbt = nbt.simplify(item.nbt) + try { + let textureData + if (itemNbt.SkullOwner) { + textureData = itemNbt.SkullOwner.Properties.textures[0]?.Value + } else { + textureData = itemNbt['minecraft:profile']?.Properties?.find(p => p.name === 'textures')?.value + } + if (textureData) { + const decodedData = JSON.parse(Buffer.from(textureData, 'base64').toString()) + texturePath = decodedData.textures?.SKIN?.url + const { skinTexturesProxy } = this.worldRenderer.worldRendererConfig + if (skinTexturesProxy) { + texturePath = texturePath?.replace('http://textures.minecraft.net/', skinTexturesProxy) + .replace('https://textures.minecraft.net/', skinTexturesProxy) + } + } + } catch (err) { + console.error('Error decoding player head texture:', err) + } + } else { + texturePath = stevePngUrl + } + } + const armorMaterial = itemParts[0] + if (!texturePath) { + // TODO: Support mirroring on certain parts of the model + const armorTextureName = `${armorMaterial}_layer_${layer}${overlay ? '_overlay' : ''}` + texturePath = worldRenderer.resourcesManager.currentResources.customTextures.armor?.textures[armorTextureName]?.src ?? armorTextures[armorTextureName] + } + if (!texturePath || !armorModel[slotType]) { + removeArmorModel(entityMesh, slotType) + return + } + + const meshName = `geometry_armor_${slotType}${overlay ? '_overlay' : ''}` + let mesh = entityMesh.children.findLast(c => c.name === meshName) as THREE.Mesh + let material + if (mesh) { + material = mesh.material + void loadTexture(texturePath, texture => { + texture.magFilter = THREE.NearestFilter + texture.minFilter = THREE.NearestFilter + texture.flipY = false + texture.wrapS = THREE.MirroredRepeatWrapping + texture.wrapT = THREE.MirroredRepeatWrapping + material.map = texture + }) + } else { + mesh = getMesh(worldRenderer, texturePath, armorModel[slotType]) + // // enable debug mode to see the mesh + // mesh.traverse(c => { + // if (c instanceof THREE.Mesh) { + // c.material.wireframe = true + // } + // }) + if (slotType === 'head') { + // avoid z-fighting with the head + mesh.children[0].position.y += 0.01 + } + mesh.name = meshName + material = mesh.material + if (!isPlayerHead) { + material.side = THREE.DoubleSide + } + } + if (armorMaterial === 'leather' && !overlay) { + const color = (item.nbt?.value as any)?.display?.value?.color?.value + if (color) { + const r = color >> 16 & 0xff + const g = color >> 8 & 0xff + const b = color & 0xff + material.color.setRGB(r / 255, g / 255, b / 255) + } else { + material.color.setHex(0xB5_6D_51) // default brown color + } + addArmorModel(worldRenderer, entityMesh, slotType, item, layer, true) + } else { + material.color.setHex(0xFF_FF_FF) + } + const group = new THREE.Object3D() + group.name = `armor_${slotType}${overlay ? '_overlay' : ''}` + group.add(mesh) + + entityMesh.add(mesh) +} + +function removeArmorModel (entityMesh: THREE.Object3D, slotType: string) { + for (const c of entityMesh.children) { + if (c.name === `geometry_armor_${slotType}` || c.name === `geometry_armor_${slotType}_overlay`) { + c.removeFromParent() + } + } +} diff --git a/renderer/viewer/three/entity/EntityMesh.ts b/renderer/viewer/three/entity/EntityMesh.ts new file mode 100644 index 00000000..229da6d5 --- /dev/null +++ b/renderer/viewer/three/entity/EntityMesh.ts @@ -0,0 +1,550 @@ +import * as THREE from 'three' +import { OBJLoader } from 'three-stdlib' +import huskPng from 'mc-assets/dist/other-textures/latest/entity/zombie/husk.png' +import { Vec3 } from 'vec3' +import ocelotPng from '../../../../node_modules/mc-assets/dist/other-textures/latest/entity/cat/ocelot.png' +import arrowTexture from '../../../../node_modules/mc-assets/dist/other-textures/1.21.2/entity/projectiles/arrow.png' +import spectralArrowTexture from '../../../../node_modules/mc-assets/dist/other-textures/1.21.2/entity/projectiles/spectral_arrow.png' +import tippedArrowTexture from '../../../../node_modules/mc-assets/dist/other-textures/1.21.2/entity/projectiles/tipped_arrow.png' +import { loadTexture } from '../threeJsUtils' +import { WorldRendererThree } from '../worldrendererThree' +import entities from './entities.json' +import { externalModels } from './objModels' +import externalTexturesJson from './externalTextures.json' + +interface ElemFace { + dir: [number, number, number] + u0: [number, number, number] + v0: [number, number, number] + u1: [number, number, number] + v1: [number, number, number] + corners: Array<[number, number, number, number, number]> +} + +interface GeoData { + positions: number[] + normals: number[] + uvs: number[] + indices: number[] + skinIndices: number[] + skinWeights: number[] +} + +interface JsonBone { + name: string + pivot?: [number, number, number] + bind_pose_rotation?: [number, number, number] + rotation?: [number, number, number] + parent?: string + cubes?: JsonCube[] + mirror?: boolean +} + +interface JsonCube { + origin: [number, number, number] + size: [number, number, number] + uv: [number, number] + inflate?: number + rotation?: [number, number, number] +} + +interface JsonModel { + texturewidth?: number + textureheight?: number + bones: JsonBone[] +} + +interface EntityOverrides { + textures?: Record + rotation?: Record +} + +const elemFaces: Record = { + up: { + dir: [0, 1, 0], + u0: [0, 0, 1], + v0: [0, 0, 0], + u1: [1, 0, 1], + v1: [0, 0, 1], + corners: [ + [0, 1, 1, 0, 0], + [1, 1, 1, 1, 0], + [0, 1, 0, 0, 1], + [1, 1, 0, 1, 1] + ] + }, + down: { + dir: [0, -1, 0], + u0: [1, 0, 1], + v0: [0, 0, 0], + u1: [2, 0, 1], + v1: [0, 0, 1], + corners: [ + [1, 0, 1, 0, 0], + [0, 0, 1, 1, 0], + [1, 0, 0, 0, 1], + [0, 0, 0, 1, 1] + ] + }, + east: { + dir: [1, 0, 0], + u0: [0, 0, 0], + v0: [0, 0, 1], + u1: [0, 0, 1], + v1: [0, 1, 1], + corners: [ + [1, 1, 1, 0, 0], + [1, 0, 1, 0, 1], + [1, 1, 0, 1, 0], + [1, 0, 0, 1, 1] + ] + }, + west: { + dir: [-1, 0, 0], + u0: [1, 0, 1], + v0: [0, 0, 1], + u1: [1, 0, 2], + v1: [0, 1, 1], + corners: [ + [0, 1, 0, 0, 0], + [0, 0, 0, 0, 1], + [0, 1, 1, 1, 0], + [0, 0, 1, 1, 1] + ] + }, + north: { + dir: [0, 0, -1], + u0: [0, 0, 1], + v0: [0, 0, 1], + u1: [1, 0, 1], + v1: [0, 1, 1], + corners: [ + [1, 0, 0, 0, 1], + [0, 0, 0, 1, 1], + [1, 1, 0, 0, 0], + [0, 1, 0, 1, 0] + ] + }, + south: { + dir: [0, 0, 1], + u0: [1, 0, 2], + v0: [0, 0, 1], + u1: [2, 0, 2], + v1: [0, 1, 1], + corners: [ + [0, 0, 1, 0, 1], + [1, 0, 1, 1, 1], + [0, 1, 1, 0, 0], + [1, 1, 1, 1, 0] + ] + } +} + +function dot (a: number[], b: number[]): number { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] +} + +function addCube ( + attr: GeoData, + boneId: number, + bone: THREE.Bone, + cube: JsonCube, + sameTextureForAllFaces = false, + texWidth = 64, + texHeight = 64, + mirror = false, + errors: string[] = [] +): void { + const cubeRotation = new THREE.Euler(0, 0, 0) + if (cube.rotation) { + cubeRotation.x = -cube.rotation[0] * Math.PI / 180 + cubeRotation.y = -cube.rotation[1] * Math.PI / 180 + cubeRotation.z = -cube.rotation[2] * Math.PI / 180 + } + for (const { dir, corners, u0, v0, u1, v1 } of Object.values(elemFaces)) { + const ndx = Math.floor(attr.positions.length / 3) + + const eastOrWest = dir[0] !== 0 + const faceUvs: number[] = [] + for (const pos of corners) { + let u: number + let v: number + if (sameTextureForAllFaces) { + u = (cube.uv[0] + pos[3] * cube.size[0]) / texWidth + v = (cube.uv[1] + pos[4] * cube.size[1]) / texHeight + } else { + u = (cube.uv[0] + dot(pos[3] ? u1 : u0, cube.size)) / texWidth + v = (cube.uv[1] + dot(pos[4] ? v1 : v0, cube.size)) / texHeight + } + // if (isNaN(u) || isNaN(v)) { + // errors.push(`NaN u: ${u}, v: ${v}`) + // continue + // } + // if (u < 0 || u > 1 || v < 0 || v > 1) { + // errors.push(`u: ${u}, v: ${v} out of range`) + // continue + // } + + const posX = eastOrWest && mirror ? pos[0] ^ 1 : pos[0] + const posY = pos[1] + const posZ = eastOrWest && mirror ? pos[2] ^ 1 : pos[2] + const inflate = cube.inflate ?? 0 + let vecPos = new THREE.Vector3( + cube.origin[0] + posX * cube.size[0] + (posX ? inflate : -inflate), + cube.origin[1] + posY * cube.size[1] + (posY ? inflate : -inflate), + cube.origin[2] + posZ * cube.size[2] + (posZ ? inflate : -inflate) + ) + + vecPos = vecPos.applyEuler(cubeRotation) + vecPos = vecPos.sub(bone.position) + vecPos = vecPos.applyEuler(bone.rotation) + vecPos = vecPos.add(bone.position) + + attr.positions.push(vecPos.x, vecPos.y, vecPos.z) + attr.normals.push(dir[0], dir[1], dir[2]) + faceUvs.push(u, v) + attr.skinIndices.push(boneId, 0, 0, 0) + attr.skinWeights.push(1, 0, 0, 0) + } + + if (mirror) { + for (let i = 0; i + 1 < corners.length; i += 2) { + const faceIndex = i * 2 + const tempFaceUvs = faceUvs.slice(faceIndex, faceIndex + 4) + faceUvs[faceIndex] = tempFaceUvs[2] + faceUvs[faceIndex + 1] = tempFaceUvs[eastOrWest ? 1 : 3] + faceUvs[faceIndex + 2] = tempFaceUvs[0] + faceUvs[faceIndex + 3] = tempFaceUvs[eastOrWest ? 3 : 1] + } + } + attr.uvs.push(...faceUvs) + + attr.indices.push(ndx, ndx + 1, ndx + 2, ndx + 2, ndx + 1, ndx + 3) + } +} + +export function getMesh ( + worldRenderer: WorldRendererThree | undefined, + texture: string, + jsonModel: JsonModel, + overrides: EntityOverrides = {}, + debugFlags: EntityDebugFlags = {} +): THREE.SkinnedMesh { + let textureWidth = jsonModel.texturewidth ?? 64 + let textureHeight = jsonModel.textureheight ?? 64 + let textureOffset: number[] | undefined + const useBlockTexture = texture.startsWith('block:') + const blocksTexture = worldRenderer?.material.map + if (useBlockTexture) { + if (!worldRenderer) throw new Error('worldRenderer is required for block textures') + const blockName = texture.slice(6) + const textureInfo = worldRenderer.resourcesManager.currentResources.blocksAtlasJson.textures[blockName] + if (textureInfo) { + textureWidth = blocksTexture?.image.width ?? textureWidth + textureHeight = blocksTexture?.image.height ?? textureHeight + // todo support su/sv + textureOffset = [textureInfo.u, textureInfo.v] + } else { + console.error(`Unknown block ${blockName}`) + } + } + + const bones: Record = {} + + const geoData: GeoData = { + positions: [], + normals: [], + uvs: [], + indices: [], + skinIndices: [], + skinWeights: [] + } + let i = 0 + for (const jsonBone of jsonModel.bones) { + const bone = new THREE.Bone() + if (jsonBone.pivot) { + bone.position.x = jsonBone.pivot[0] + bone.position.y = jsonBone.pivot[1] + bone.position.z = jsonBone.pivot[2] + } + if (jsonBone.bind_pose_rotation) { + bone.rotation.x = -jsonBone.bind_pose_rotation[0] * Math.PI / 180 + bone.rotation.y = -jsonBone.bind_pose_rotation[1] * Math.PI / 180 + bone.rotation.z = -jsonBone.bind_pose_rotation[2] * Math.PI / 180 + } else if (jsonBone.rotation) { + bone.rotation.x = -jsonBone.rotation[0] * Math.PI / 180 + bone.rotation.y = -jsonBone.rotation[1] * Math.PI / 180 + bone.rotation.z = -jsonBone.rotation[2] * Math.PI / 180 + } + if (overrides.rotation?.[jsonBone.name]) { + bone.rotation.x -= (overrides.rotation[jsonBone.name].x ?? 0) * Math.PI / 180 + bone.rotation.y -= (overrides.rotation[jsonBone.name].y ?? 0) * Math.PI / 180 + bone.rotation.z -= (overrides.rotation[jsonBone.name].z ?? 0) * Math.PI / 180 + } + bone.name = `bone_${jsonBone.name}` + bones[jsonBone.name] = bone + + if (jsonBone.cubes) { + for (const cube of jsonBone.cubes) { + const errors: string[] = [] + addCube(geoData, i, bone, cube, useBlockTexture, textureWidth, textureHeight, jsonBone.mirror, errors) + if (errors.length) { + debugFlags.errors ??= [] + debugFlags.errors.push(...errors.map(error => `Bone ${jsonBone.name}: ${error}`)) + } + } + } + i++ + } + + const rootBones: THREE.Object3D[] = [] + for (const jsonBone of jsonModel.bones) { + if (jsonBone.parent && bones[jsonBone.parent]) { + bones[jsonBone.parent].add(bones[jsonBone.name]) + } else { + rootBones.push(bones[jsonBone.name]) + } + } + + const skeleton = new THREE.Skeleton(Object.values(bones)) + + const geometry = new THREE.BufferGeometry() + geometry.setAttribute('position', new THREE.Float32BufferAttribute(geoData.positions, 3)) + geometry.setAttribute('normal', new THREE.Float32BufferAttribute(geoData.normals, 3)) + geometry.setAttribute('uv', new THREE.Float32BufferAttribute(geoData.uvs, 2)) + geometry.setAttribute('skinIndex', new THREE.Uint16BufferAttribute(geoData.skinIndices, 4)) + geometry.setAttribute('skinWeight', new THREE.Float32BufferAttribute(geoData.skinWeights, 4)) + geometry.setIndex(geoData.indices) + + const material = new THREE.MeshLambertMaterial({ transparent: true, alphaTest: 0.1 }) + const mesh = new THREE.SkinnedMesh(geometry, material) + mesh.add(...rootBones) + mesh.bind(skeleton) + mesh.scale.set(1 / 16, 1 / 16, 1 / 16) + + if (textureOffset) { + // todo(memory) dont clone + const loadedTexture = blocksTexture!.clone() + loadedTexture.offset.set(textureOffset[0], textureOffset[1]) + loadedTexture.needsUpdate = true + material.map = loadedTexture + } else { + void loadTexture(texture, loadedTexture => { + if (material.map) { + // texture is already loaded + return + } + loadedTexture.magFilter = THREE.NearestFilter + loadedTexture.minFilter = THREE.NearestFilter + loadedTexture.flipY = false + loadedTexture.wrapS = THREE.RepeatWrapping + loadedTexture.wrapT = THREE.RepeatWrapping + material.map = loadedTexture + }, () => { + // This callback runs after the texture is fully loaded + const actualWidth = material.map!.image.width + if (actualWidth && textureWidth !== actualWidth) { + material.map!.repeat.x = textureWidth / actualWidth + } + const actualHeight = material.map!.image.height + if (actualHeight && textureHeight !== actualHeight) { + material.map!.repeat.y = textureHeight / actualHeight + } + material.needsUpdate = true + }) + } + + return mesh +} + +export const rendererSpecialHandled = ['item_frame', 'item', 'player'] + +type EntityMapping = { + pattern: string | RegExp + target: string +} + +const temporaryMappings: EntityMapping[] = [ + // Exact matches + { pattern: 'furnace_minecart', target: 'minecart' }, + { pattern: 'spawner_minecart', target: 'minecart' }, + { pattern: 'chest_minecart', target: 'minecart' }, + { pattern: 'hopper_minecart', target: 'minecart' }, + { pattern: 'command_block_minecart', target: 'minecart' }, + { pattern: 'tnt_minecart', target: 'minecart' }, + { pattern: 'glow_item_frame', target: 'item_frame' }, + { pattern: 'glow_squid', target: 'squid' }, + { pattern: 'trader_llama', target: 'llama' }, + { pattern: 'chest_boat', target: 'boat' }, + { pattern: 'spectral_arrow', target: 'arrow' }, + { pattern: 'husk', target: 'zombie' }, + { pattern: 'zombie_horse', target: 'horse' }, + { pattern: 'donkey', target: 'horse' }, + { pattern: 'skeleton_horse', target: 'horse' }, + { pattern: 'mule', target: 'horse' }, + { pattern: 'ocelot', target: 'cat' }, + // Regex patterns + { pattern: /_minecraft$/, target: 'minecraft' }, + { pattern: /_boat$/, target: 'boat' }, + { pattern: /_raft$/, target: 'boat' }, + { pattern: /_horse$/, target: 'horse' }, + { pattern: /_zombie$/, target: 'zombie' }, + { pattern: /_arrow$/, target: 'zombie' }, +] + +function getEntityMapping (type: string): string | undefined { + for (const mapping of temporaryMappings) { + if (typeof mapping.pattern === 'string') { + if (mapping.pattern === type) return mapping.target + } else if (mapping.pattern.test(type)) { return mapping.target } + } + return undefined +} + +const getEntity = (name: string) => { + return entities[name] +} + +const scaleEntity: Record = { + zombie: 1.85, + husk: 1.85, + arrow: 0.0025 +} + +const offsetEntity: Record = { + zombie: new Vec3(0, 1, 0), + husk: new Vec3(0, 1, 0), + boat: new Vec3(0, -1, 0), + arrow: new Vec3(0, -0.9, 0) +} + +interface EntityGeometry { + geometry: Array<{ + name: string; + [key: string]: any; + }>; +} + +export type EntityDebugFlags = { + type?: 'obj' | 'bedrock' + tempMap?: string + textureMap?: boolean + errors?: string[] + isHardcodedTexture?: boolean +} + +export class EntityMesh { + mesh: THREE.Object3D + + constructor ( + version: string, + type: string, + worldRenderer?: WorldRendererThree, + overrides: EntityOverrides = {}, + debugFlags: EntityDebugFlags = {} + ) { + const originalType = type + const mappedValue = getEntityMapping(type) + if (mappedValue) { + type = mappedValue + debugFlags.tempMap = mappedValue + } + + if (externalModels[type]) { + const objLoader = new OBJLoader() + const texturePathMap = { + 'zombie_horse': `textures/${version}/entity/horse/horse_zombie.png`, + 'husk': huskPng, + 'skeleton_horse': `textures/${version}/entity/horse/horse_skeleton.png`, + 'donkey': `textures/${version}/entity/horse/donkey.png`, + 'mule': `textures/${version}/entity/horse/mule.png`, + 'ocelot': ocelotPng, + 'arrow': arrowTexture, + 'spectral_arrow': spectralArrowTexture, + 'tipped_arrow': tippedArrowTexture + } + const tempTextureMap = texturePathMap[originalType] || texturePathMap[type] + if (tempTextureMap) { + debugFlags.textureMap = true + } + const texturePath = tempTextureMap || externalTexturesJson[type] + if (externalTexturesJson[type]) { + debugFlags.isHardcodedTexture = true + } + if (!texturePath) throw new Error(`No texture for ${type}`) + const texture = new THREE.TextureLoader().load(texturePath) + texture.minFilter = THREE.NearestFilter + texture.magFilter = THREE.NearestFilter + const material = new THREE.MeshBasicMaterial({ + map: texture, + transparent: true, + alphaTest: 0.1 + }) + const obj = objLoader.parse(externalModels[type]) + const scale = scaleEntity[originalType] || scaleEntity[type] + if (scale) obj.scale.set(scale, scale, scale) + const offset = offsetEntity[originalType] + if (offset) obj.position.set(offset.x, offset.y, offset.z) + obj.traverse((child) => { + if (child instanceof THREE.Mesh) { + child.material = material + // todo + if (child.name === 'Head layer') child.visible = false + if (child.name === 'Head' && overrides.rotation?.head) { // todo + child.rotation.x -= (overrides.rotation.head.x ?? 0) * Math.PI / 180 + child.rotation.y -= (overrides.rotation.head.y ?? 0) * Math.PI / 180 + child.rotation.z -= (overrides.rotation.head.z ?? 0) * Math.PI / 180 + } + } + }) + this.mesh = obj + debugFlags.type = 'obj' + return + } + + if (originalType === 'arrow') { + // overrides.textures = { + // 'default': testArrow, + // ...overrides.textures, + // } + } + + const e = getEntity(type) + if (!e) { + // if (knownNotHandled.includes(type)) return + // throw new Error(`Unknown entity ${type}`) + return + } + + this.mesh = new THREE.Object3D() + for (const [name, jsonModel] of Object.entries(e.geometry)) { + const texture = overrides.textures?.[name] ?? e.textures[name] + if (!texture) continue + // console.log(JSON.stringify(jsonModel, null, 2)) + const mesh = getMesh(worldRenderer, + texture.endsWith('.png') || texture.startsWith('data:image/') || texture.startsWith('block:') + ? texture : texture + '.png', + jsonModel, + overrides, + debugFlags) + mesh.name = `geometry_${name}` + this.mesh.add(mesh) + } + debugFlags.type = 'bedrock' + } + + static getStaticData (name: string): { boneNames: string[] } { + name = getEntityMapping(name) || name + if (externalModels[name]) { + return { + boneNames: [] // todo + } + } + const e = getEntity(name) as EntityGeometry + if (!e) throw new Error(`Unknown entity ${name}`) + return { + boneNames: Object.values(e.geometry).flatMap(x => x.name) + } + } +} +globalThis.EntityMesh = EntityMesh diff --git a/renderer/viewer/three/entity/animations.js b/renderer/viewer/three/entity/animations.js new file mode 100644 index 00000000..3295556f --- /dev/null +++ b/renderer/viewer/three/entity/animations.js @@ -0,0 +1,171 @@ +//@ts-check +import { PlayerAnimation } from 'skinview3d' + +export class WalkingGeneralSwing extends PlayerAnimation { + + switchAnimationCallback + + isRunning = false + isMoving = true + isCrouched = false + + _startArmSwing + + swingArm() { + this._startArmSwing = this.progress + } + + animate(player) { + // Multiply by animation's natural speed + let t = 0 + const updateT = () => { + if (!this.isMoving) { + t = 0 + return + } + if (this.isRunning) { + t = this.progress * 10 + Math.PI * 0.5 + } else { + t = this.progress * 8 + } + } + updateT() + let reset = false + + croughAnimation(player, this.isCrouched) + + if ((this.isRunning ? Math.cos(t) : Math.sin(t)) < 0.01) { + if (this.switchAnimationCallback) { + reset = true + this.progress = 0 + updateT() + } + } + + if (this.isRunning) { + // Leg swing with larger amplitude + player.skin.leftLeg.rotation.x = Math.cos(t + Math.PI) * 1.3 + player.skin.rightLeg.rotation.x = Math.cos(t) * 1.3 + } else { + // Leg swing + player.skin.leftLeg.rotation.x = Math.sin(t) * 0.5 + player.skin.rightLeg.rotation.x = Math.sin(t + Math.PI) * 0.5 + } + + if (this._startArmSwing) { + const tHand = (this.progress - this._startArmSwing) * 18 + Math.PI * 0.5 + // player.skin.rightArm.rotation.x = Math.cos(tHand) * 1.5 + // const basicArmRotationZ = Math.PI * 0.1 + // player.skin.rightArm.rotation.z = Math.cos(t + Math.PI) * 0.3 - basicArmRotationZ + HitAnimation.animate((this.progress - this._startArmSwing), player, this.isMoving) + + if (tHand > Math.PI + Math.PI) { + this._startArmSwing = null + player.skin.rightArm.rotation.z = 0 + } + } + + if (this.isRunning) { + player.skin.leftArm.rotation.x = Math.cos(t) * 1.5 + if (!this._startArmSwing) { + player.skin.rightArm.rotation.x = Math.cos(t + Math.PI) * 1.5 + } + const basicArmRotationZ = Math.PI * 0.1 + player.skin.leftArm.rotation.z = Math.cos(t) * 0.1 + basicArmRotationZ + if (!this._startArmSwing) { + player.skin.rightArm.rotation.z = Math.cos(t + Math.PI) * 0.1 - basicArmRotationZ + } + } else { + // Arm swing + player.skin.leftArm.rotation.x = Math.sin(t + Math.PI) * 0.5 + if (!this._startArmSwing) { + player.skin.rightArm.rotation.x = Math.sin(t) * 0.5 + } + const basicArmRotationZ = Math.PI * 0.02 + player.skin.leftArm.rotation.z = Math.cos(t) * 0.03 + basicArmRotationZ + if (!this._startArmSwing) { + player.skin.rightArm.rotation.z = Math.cos(t + Math.PI) * 0.03 - basicArmRotationZ + } + } + + if (this.isRunning) { + player.rotation.z = Math.cos(t + Math.PI) * 0.01 + } + if (this.isRunning) { + const basicCapeRotationX = Math.PI * 0.3 + player.cape.rotation.x = Math.sin(t * 2) * 0.1 + basicCapeRotationX + } else { + // Always add an angle for cape around the x axis + const basicCapeRotationX = Math.PI * 0.06 + player.cape.rotation.x = Math.sin(t / 1.5) * 0.06 + basicCapeRotationX + } + + if (reset) { + this.switchAnimationCallback() + this.switchAnimationCallback = null + } + } +} + +const HitAnimation = { + animate(progress, player, isMovingOrRunning) { + const t = progress * 18 + player.skin.rightArm.rotation.x = -0.453_786_055_2 * 2 + 2 * Math.sin(t + Math.PI) * 0.3 + + if (!isMovingOrRunning) { + const basicArmRotationZ = 0.01 * Math.PI + 0.06 + player.skin.rightArm.rotation.z = -Math.cos(t) * 0.403 + basicArmRotationZ + player.skin.body.rotation.y = -Math.cos(t) * 0.06 + player.skin.leftArm.rotation.x = Math.sin(t + Math.PI) * 0.077 + player.skin.leftArm.rotation.z = -Math.cos(t) * 0.015 + 0.13 - 0.05 + player.skin.leftArm.position.z = Math.cos(t) * 0.3 + player.skin.leftArm.position.x = 5 - Math.cos(t) * 0.05 + } + }, +} + +const croughAnimation = (player, isCrouched) => { + const erp = 0 + + // let pr = this.progress * 8; + let pr = isCrouched ? 1 : 0 + const showProgress = false + if (showProgress) { + pr = Math.floor(pr) + } + player.skin.body.rotation.x = 0.453_786_055_2 * Math.abs(Math.sin((pr * Math.PI) / 2)) + player.skin.body.position.z = + 1.325_618_1 * Math.abs(Math.sin((pr * Math.PI) / 2)) - 3.450_031_037_7 * Math.abs(Math.sin((pr * Math.PI) / 2)) + player.skin.body.position.y = -6 - 2.103_677_462 * Math.abs(Math.sin((pr * Math.PI) / 2)) + player.cape.position.y = 8 - 1.851_236_166_577_372 * Math.abs(Math.sin((pr * Math.PI) / 2)) + player.cape.rotation.x = (10.8 * Math.PI) / 180 + 0.294_220_265_771 * Math.abs(Math.sin((pr * Math.PI) / 2)) + player.cape.position.z = + -2 + 3.786_619_432 * Math.abs(Math.sin((pr * Math.PI) / 2)) - 3.450_031_037_7 * Math.abs(Math.sin((pr * Math.PI) / 2)) + player.elytra.position.x = player.cape.position.x + player.elytra.position.y = player.cape.position.y + player.elytra.position.z = player.cape.position.z + player.elytra.rotation.x = player.cape.rotation.x - (10.8 * Math.PI) / 180 + // const pr1 = this.progress / this.speed; + const pr1 = 1 + if (Math.abs(Math.sin((pr * Math.PI) / 2)) === 1) { + player.elytra.leftWing.rotation.z = + 0.261_799_44 + 0.458_200_6 * Math.abs(Math.sin((Math.min(pr1 - erp, 1) * Math.PI) / 2)) + player.elytra.updateRightWing() + } else if (isCrouched !== undefined) { + player.elytra.leftWing.rotation.z = + 0.72 - 0.458_200_6 * Math.abs(Math.sin((Math.min(pr1 - erp, 1) * Math.PI) / 2)) + player.elytra.updateRightWing() + } + player.skin.head.position.y = -3.618_325_234_674 * Math.abs(Math.sin((pr * Math.PI) / 2)) + player.skin.leftArm.position.z = + 3.618_325_234_674 * Math.abs(Math.sin((pr * Math.PI) / 2)) - 3.450_031_037_7 * Math.abs(Math.sin((pr * Math.PI) / 2)) + player.skin.rightArm.position.z = player.skin.leftArm.position.z + player.skin.leftArm.rotation.x = 0.410_367_746_202 * Math.abs(Math.sin((pr * Math.PI) / 2)) + player.skin.rightArm.rotation.x = player.skin.leftArm.rotation.x + player.skin.leftArm.rotation.z = 0.1 + player.skin.rightArm.rotation.z = -player.skin.leftArm.rotation.z + player.skin.leftArm.position.y = -2 - 2.539_433_18 * Math.abs(Math.sin((pr * Math.PI) / 2)) + player.skin.rightArm.position.y = player.skin.leftArm.position.y + player.skin.rightLeg.position.z = -3.450_031_037_7 * Math.abs(Math.sin((pr * Math.PI) / 2)) + player.skin.leftLeg.position.z = player.skin.rightLeg.position.z +} diff --git a/renderer/viewer/three/entity/armorModels.json b/renderer/viewer/three/entity/armorModels.json new file mode 100644 index 00000000..d7a77d4c --- /dev/null +++ b/renderer/viewer/three/entity/armorModels.json @@ -0,0 +1,204 @@ +{ + "skull": { + "bones": [ + { + "name": "head", + "pivot": [0, 12, 0], + "cubes": [ + { + "origin": [-4, 0, -4], + "size": [8, 8, 8], + "uv": [0, 0], + "inflate": 1 + } + ] + }, + { + "name": "overlay", + "parent": "head", + "pivot": [0, 12, 0], + "cubes": [ + { + "origin": [-4, 0, -4], + "size": [8, 8, 8], + "uv": [32, 0], + "inflate": 1.2 + } + ] + } + ], + "visible_bounds_width": 1.5, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 32 + }, + "head": { + "bones": [ + {"name": "armor", "pivot": [0, 12, 0]}, + { + "name": "head", + "parent": "armor", + "pivot": [0, 12, 0], + "cubes": [ + { + "origin": [-4, 23, -4], + "size": [8, 8, 8], + "uv": [0, 0], + "inflate": 1 + } + ] + }, + { + "name": "overlay", + "parent": "head", + "pivot": [0, 12, 0], + "cubes": [ + { + "origin": [-4, 23, -4], + "size": [8, 8, 8], + "uv": [32, 0], + "inflate": 1.2 + } + ] + } + ], + "visible_bounds_width": 1.5, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 32 + }, + "chest": { + "bones": [ + {"name": "armor", "pivot": [0, 12, 0]}, + { + "name": "body", + "parent": "armor", + "pivot": [0, 13, 0], + "cubes": [ + { + "origin": [-4, 12, -2], + "size": [8, 12, 4], + "uv": [16, 16], + "inflate": 1 + } + ] + }, + { + "name": "leftarm", + "parent": "armor", + "pivot": [5, 10, 0], + "cubes": [ + { + "origin": [4, 12, -2], + "size": [4, 12, 4], + "uv": [40, 16], + "inflate": 0.85 + } + ] + }, + { + "name": "rightarm", + "parent": "armor", + "pivot": [-5, 10, 0], + "cubes": [ + { + "origin": [-8, 12, -2], + "size": [4, 12, 4], + "uv": [40, 16], + "inflate": 0.85 + } + ], + "mirror": true + } + ], + "visible_bounds_width": 1.5, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 32 + }, + "legs": { + "bones": [ + {"name": "armor", "pivot": [0, 12, 0]}, + { + "name": "body", + "parent": "armor", + "pivot": [0, 13, 0], + "cubes": [ + { + "origin": [-4, 12, -2], + "size": [8, 12, 4], + "uv": [16, 16], + "inflate": 0.5 + } + ] + }, + { + "name": "leftleg", + "parent": "armor", + "pivot": [1.9, 1, 0], + "cubes": [ + { + "origin": [-0.1, 0, -2], + "size": [4, 12, 4], + "uv": [0, 16], + "inflate": 0.5 + } + ] + }, + { + "name": "rightleg", + "parent": "armor", + "pivot": [-1.9, 1, 0], + "cubes": [ + { + "origin": [-3.9, 0, -2.01], + "size": [4, 12, 4], + "uv": [0, 16], + "inflate": 0.5 + } + ], + "mirror": true + } + ], + "visible_bounds_width": 1.5, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 32 + }, + "feet": { + "bones": [ + {"name": "armor", "pivot": [0, 12, 0]}, + { + "name": "leftleg", + "parent": "armor", + "pivot": [1.9, 1, 0], + "cubes": [ + { + "origin": [-0.1, 0, -2], + "size": [4, 12, 4], + "uv": [0, 16], + "inflate": 0.8 + } + ] + }, + { + "name": "rightleg", + "parent": "armor", + "pivot": [-1.9, 1, 0], + "cubes": [ + { + "origin": [-3.9, 0.01, -2.01], + "size": [4, 12, 4], + "uv": [0, 16], + "inflate": 0.8 + } + ], + "mirror": true + } + ], + "visible_bounds_width": 1.5, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 32 + } +} \ No newline at end of file diff --git a/renderer/viewer/three/entity/armorModels.ts b/renderer/viewer/three/entity/armorModels.ts new file mode 100644 index 00000000..3681344c --- /dev/null +++ b/renderer/viewer/three/entity/armorModels.ts @@ -0,0 +1,36 @@ +import { default as chainmailLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/chainmail_layer_1.png' +import { default as chainmailLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/chainmail_layer_2.png' +import { default as diamondLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/diamond_layer_1.png' +import { default as diamondLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/diamond_layer_2.png' +import { default as goldenLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/gold_layer_1.png' +import { default as goldenLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/gold_layer_2.png' +import { default as ironLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/iron_layer_1.png' +import { default as ironLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/iron_layer_2.png' +import { default as leatherLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/leather_layer_1.png' +import { default as leatherLayer1Overlay } from 'mc-assets/dist/other-textures/latest/models/armor/leather_layer_1_overlay.png' +import { default as leatherLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/leather_layer_2.png' +import { default as leatherLayer2Overlay } from 'mc-assets/dist/other-textures/latest/models/armor/leather_layer_2_overlay.png' +import { default as netheriteLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/netherite_layer_1.png' +import { default as netheriteLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/netherite_layer_2.png' +import { default as turtleLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/turtle_layer_1.png' + +export { default as elytraTexture } from 'mc-assets/dist/other-textures/latest/entity/elytra.png' +export { default as armorModel } from './armorModels.json' + +export const armorTextures = { + 'leather_layer_1': leatherLayer1, + 'leather_layer_1_overlay': leatherLayer1Overlay, + 'leather_layer_2': leatherLayer2, + 'leather_layer_2_overlay': leatherLayer2Overlay, + 'chainmail_layer_1': chainmailLayer1, + 'chainmail_layer_2': chainmailLayer2, + 'iron_layer_1': ironLayer1, + 'iron_layer_2': ironLayer2, + 'diamond_layer_1': diamondLayer1, + 'diamond_layer_2': diamondLayer2, + 'golden_layer_1': goldenLayer1, + 'golden_layer_2': goldenLayer2, + 'netherite_layer_1': netheriteLayer1, + 'netherite_layer_2': netheriteLayer2, + 'turtle_layer_1': turtleLayer1 +} diff --git a/renderer/viewer/three/entity/entities.json b/renderer/viewer/three/entity/entities.json new file mode 100644 index 00000000..feca5dc7 --- /dev/null +++ b/renderer/viewer/three/entity/entities.json @@ -0,0 +1,6230 @@ +{ + "armor_stand": { + "identifier": "minecraft:armor_stand", + "min_engine_version": "1.8.0", + "materials": {"default": "armor_stand"}, + "textures": {"default": "textures/entity/armorstand/wood"}, + "geometry": { + "default": { + "bones": [ + { + "name": "baseplate", + "parent": "waist", + "cubes": [ + {"origin": [-6, 0, -6], "size": [12, 1, 12], "uv": [0, 32]} + ] + }, + {"name": "waist", "pivot": [0, 12, 0]}, + { + "name": "body", + "parent": "waist", + "pivot": [0, 13, 0], + "cubes": [ + {"origin": [-6, 21, -1.5], "size": [12, 3, 3], "uv": [0, 26]}, + {"origin": [-3, 14, -1], "size": [2, 7, 2], "uv": [16, 0]}, + {"origin": [1, 14, -1], "size": [2, 7, 2], "uv": [48, 16]}, + {"origin": [-4, 12, -1], "size": [8, 2, 2], "uv": [0, 48]} + ] + }, + { + "name": "head", + "parent": "waist", + "pivot": [0, 12, 0], + "cubes": [{"origin": [-1, 24, -1], "size": [2, 7, 2], "uv": [0, 0]}] + }, + { + "name": "hat", + "parent": "head", + "pivot": [0, 12, 0], + "cubes": [ + {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [32, 0]} + ] + }, + { + "name": "leftarm", + "parent": "waist", + "mirror": true, + "pivot": [5, 10, 0], + "cubes": [ + {"origin": [5, 12, -1], "size": [2, 12, 2], "uv": [32, 16]} + ] + }, + {"name": "leftitem", "parent": "leftarm", "pivot": [1, -9, -5]}, + { + "name": "leftleg", + "parent": "waist", + "mirror": true, + "pivot": [1.9, 1, 0], + "cubes": [ + {"origin": [0.9, 1, -1], "size": [2, 11, 2], "uv": [40, 16]} + ] + }, + { + "name": "rightarm", + "parent": "waist", + "pivot": [-5, 10, 0], + "cubes": [ + {"origin": [-7, 12, -1], "size": [2, 12, 2], "uv": [24, 0]} + ] + }, + {"name": "rightitem", "parent": "rightarm", "pivot": [-1, -9, -5]}, + { + "name": "rightleg", + "parent": "waist", + "pivot": [-1.9, 1, 0], + "cubes": [ + {"origin": [-2.9, 1, -1], "size": [2, 11, 2], "uv": [8, 0]} + ] + } + ], + "visible_bounds_width": 1.5, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 64 + } + }, + "render_controllers": ["controller.render.armor_stand"], + "enable_attachables": true + }, + "arrow": { + "identifier": "minecraft:arrow", + "materials": {"default": "arrow"}, + "textures": {"default": "textures/entity/arrow"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 1, 0], + "cubes": [ + { + "origin": [0, -2.5, -3], + "rotation": [0, 0, 45], + "size": [0, 5, 16], + "uv": {"east": {"uv": [0, 0]}} + }, + { + "origin": [0, -2.5, -3], + "rotation": [0, 0, -45], + "size": [0, 5, 16], + "uv": {"east": {"uv": [0, 0]}} + }, + { + "origin": [-2.5, -2.5, 12], + "rotation": [0, 0, 45], + "size": [5, 5, 0], + "uv": {"south": {"uv": [0, 5]}} + } + ] + } + ], + "texturewidth": 32, + "textureheight": 32 + } + }, + "render_controllers": ["controller.render.arrow"] + }, + "bat": { + "identifier": "minecraft:bat", + "materials": {"default": "bat"}, + "textures": {"default": "textures/entity/bat"}, + "geometry": { + "default": { + "visible_bounds_width": 1, + "visible_bounds_height": 1, + "visible_bounds_offset": [0, 0.5, 0], + "bones": [ + { + "name": "head", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-3, 21, -3], "size": [6, 6, 6], "uv": [0, 0]}] + }, + { + "name": "rightEar", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 26, -2], "size": [3, 4, 1], "uv": [24, 0]} + ], + "parent": "head" + }, + { + "name": "leftEar", + "mirror": true, + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [1, 26, -2], "size": [3, 4, 1], "uv": [24, 0]} + ], + "parent": "head" + }, + { + "name": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-3, 8, -3], "size": [6, 12, 6], "uv": [0, 16]}, + {"origin": [-5, -8, 0], "size": [10, 16, 1], "uv": [0, 34]} + ] + }, + { + "name": "rightWing", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-12, 7, 1.5], "size": [10, 16, 1], "uv": [42, 0]} + ], + "parent": "body" + }, + { + "name": "rightWingTip", + "pivot": [-12, 23, 1.5], + "cubes": [ + {"origin": [-20, 10, 1.5], "size": [8, 12, 1], "uv": [24, 16]} + ], + "parent": "rightWing" + }, + { + "name": "leftWing", + "mirror": true, + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [2, 7, 1.5], "size": [10, 16, 1], "uv": [42, 0]} + ], + "parent": "body" + }, + { + "name": "leftWingTip", + "mirror": true, + "pivot": [12, 23, 1.5], + "cubes": [ + {"origin": [12, 10, 1.5], "size": [8, 12, 1], "uv": [24, 16]} + ], + "parent": "leftWing" + } + ] + } + }, + "render_controllers": ["controller.render.bat"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 18} + }, + "bee": { + "identifier": "minecraft:bee", + "materials": {"default": "bee"}, + "textures": { + "default": "textures/entity/bee/bee", + "angry": "textures/entity/bee/bee_angry", + "nectar": "textures/entity/bee/bee_nectar", + "angry_nectar": "textures/entity/bee/bee_angry_nectar" + }, + "geometry": { + "default": { + "texturewidth": 64, + "textureheight": 64, + "visible_bounds_width": 1.5, + "visible_bounds_height": 1.5, + "visible_bounds_offset": [0, 0.25, 0], + "bones": [ + { + "name": "body", + "pivot": [0.5, 5, 0], + "cubes": [ + {"origin": [-3, 2, -5], "size": [7, 7, 10], "uv": [0, 0]}, + {"origin": [2, 7, -8], "size": [1, 2, 3], "uv": [2, 0]}, + {"origin": [-2, 7, -8], "size": [1, 2, 3], "uv": [2, 3]} + ], + "locators": {"lead": [0, 4, -1]} + }, + { + "name": "stinger", + "parent": "body", + "pivot": [0.5, 6, 1], + "cubes": [{"origin": [0.5, 5, 5], "size": [0, 1, 2], "uv": [26, 7]}] + }, + { + "name": "rightwing_bone", + "parent": "body", + "pivot": [-1, 9, -3], + "rotation": [15, -15, 0], + "cubes": [ + {"origin": [-10, 9, -3], "size": [9, 0, 6], "uv": [0, 18]} + ] + }, + { + "name": "leftwing_bone", + "parent": "body", + "pivot": [2, 9, -3], + "rotation": [15, 15, 0], + "cubes": [{"origin": [2, 9, -3], "size": [9, 0, 6], "uv": [9, 24]}] + }, + { + "name": "leg_front", + "parent": "body", + "pivot": [2, 2, -2], + "cubes": [{"origin": [-3, 0, -2], "size": [7, 2, 0], "uv": [26, 1]}] + }, + { + "name": "leg_mid", + "parent": "body", + "pivot": [2, 2, 0], + "cubes": [{"origin": [-3, 0, 0], "size": [7, 2, 0], "uv": [26, 3]}] + }, + { + "name": "leg_back", + "parent": "body", + "pivot": [2, 2, 2], + "cubes": [{"origin": [-3, 0, 2], "size": [7, 2, 0], "uv": [26, 5]}] + } + ] + } + }, + "particle_effects": {"nectar_dripping": "minecraft:nectar_drip_particle"}, + "render_controllers": ["controller.render.bee"], + "spawn_egg": {"texture": "egg_bee", "texture_index": 0} + }, + "cave_spider": { + "identifier": "minecraft:cave_spider", + "min_engine_version": "1.8.0", + "materials": {"default": "spider", "invisible": "spider_invisible"}, + "textures": {"default": "textures/entity/spider/cave_spider"}, + "geometry": { + "default": { + "visible_bounds_width": 2, + "visible_bounds_height": 1, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "head", + "pivot": [0, 9, -3], + "cubes": [ + {"origin": [-4, 5, -11], "size": [8, 8, 8], "uv": [32, 4]} + ], + "parent": "body0" + }, + { + "name": "body0", + "pivot": [0, 9, 0], + "cubes": [{"origin": [-3, 6, -3], "size": [6, 6, 6], "uv": [0, 0]}] + }, + { + "name": "body1", + "pivot": [0, 9, 9], + "cubes": [ + {"origin": [-5, 5, 3], "size": [10, 8, 12], "uv": [0, 12]} + ], + "parent": "body0" + }, + { + "name": "leg0", + "pivot": [-4, 9, 2], + "cubes": [ + {"origin": [-19, 8, 1], "size": [16, 2, 2], "uv": [18, 0]} + ], + "parent": "body0" + }, + { + "name": "leg1", + "pivot": [4, 9, 2], + "cubes": [{"origin": [3, 8, 1], "size": [16, 2, 2], "uv": [18, 0]}], + "parent": "body0" + }, + { + "name": "leg2", + "pivot": [-4, 9, 1], + "cubes": [ + {"origin": [-19, 8, 0], "size": [16, 2, 2], "uv": [18, 0]} + ], + "parent": "body0" + }, + { + "name": "leg3", + "pivot": [4, 9, 1], + "cubes": [{"origin": [3, 8, 0], "size": [16, 2, 2], "uv": [18, 0]}], + "parent": "body0" + }, + { + "name": "leg4", + "pivot": [-4, 9, 0], + "cubes": [ + {"origin": [-19, 8, -1], "size": [16, 2, 2], "uv": [18, 0]} + ], + "parent": "body0" + }, + { + "name": "leg5", + "pivot": [4, 9, 0], + "cubes": [ + {"origin": [3, 8, -1], "size": [16, 2, 2], "uv": [18, 0]} + ], + "parent": "body0" + }, + { + "name": "leg6", + "pivot": [-4, 9, -1], + "cubes": [ + {"origin": [-19, 8, -2], "size": [16, 2, 2], "uv": [18, 0]} + ], + "parent": "body0" + }, + { + "name": "leg7", + "pivot": [4, 9, -1], + "cubes": [ + {"origin": [3, 8, -2], "size": [16, 2, 2], "uv": [18, 0]} + ], + "parent": "body0" + } + ] + } + }, + "render_controllers": ["controller.render.spider"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 22} + }, + "chest_minecart": { + "identifier": "minecraft:chest_minecart", + "min_engine_version": "1.8.0", + "materials": {"default": "minecart"}, + "textures": {"default": "textures/entity/minecart"}, + "geometry": { + "default": { + "bones": [ + { + "name": "bottom", + "pivot": [0, 6, 0], + "cubes": [ + { + "origin": [-10, -6.5, -1], + "size": [20, 16, 2], + "rotation": [90, 0, 0], + "uv": [0, 10] + } + ] + }, + { + "name": "back", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-17, 2.5, -1], + "size": [16, 8, 2], + "rotation": [0, 270, 0], + "uv": [0, 0] + } + ], + "parent": "bottom" + }, + { + "name": "front", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [1, 2.5, -1], + "size": [16, 8, 2], + "rotation": [0, 90, 0], + "uv": [0, 0] + } + ], + "parent": "bottom" + }, + { + "name": "right", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, 2.5, -8], + "size": [16, 8, 2], + "rotation": [0, 180, 0], + "uv": [0, 0] + } + ], + "parent": "bottom" + }, + { + "name": "left", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-8, 2.5, 6], "size": [16, 8, 2], "uv": [0, 0]} + ], + "parent": "bottom" + } + ], + "texturewidth": 64, + "textureheight": 32 + } + }, + "render_controllers": ["controller.render.minecart"] + }, + "command_block_minecart": { + "identifier": "minecraft:command_block_minecart", + "min_engine_version": "1.8.0", + "materials": {"default": "minecart"}, + "textures": {"default": "textures/entity/minecart"}, + "geometry": { + "default": { + "bones": [ + { + "name": "bottom", + "pivot": [0, 6, 0], + "cubes": [ + { + "origin": [-10, -6.5, -1], + "size": [20, 16, 2], + "rotation": [90, 0, 0], + "uv": [0, 10] + } + ] + }, + { + "name": "back", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-17, 2.5, -1], + "size": [16, 8, 2], + "rotation": [0, 270, 0], + "uv": [0, 0] + } + ], + "parent": "bottom" + }, + { + "name": "front", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [1, 2.5, -1], + "size": [16, 8, 2], + "rotation": [0, 90, 0], + "uv": [0, 0] + } + ], + "parent": "bottom" + }, + { + "name": "right", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, 2.5, -8], + "size": [16, 8, 2], + "rotation": [0, 180, 0], + "uv": [0, 0] + } + ], + "parent": "bottom" + }, + { + "name": "left", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-8, 2.5, 6], "size": [16, 8, 2], "uv": [0, 0]} + ], + "parent": "bottom" + } + ], + "texturewidth": 64, + "textureheight": 32 + } + }, + "render_controllers": ["controller.render.minecart"] + }, + "cow": { + "identifier": "minecraft:cow", + "min_engine_version": "1.8.0", + "materials": {"default": "cow"}, + "textures": {"default": "textures/entity/cow/cow"}, + "geometry": { + "default": { + "visible_bounds_width": 2, + "visible_bounds_height": 1.75, + "visible_bounds_offset": [0, 0.75, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "body", + "pivot": [0, 19, 2], + "bind_pose_rotation": [90, 0, 0], + "cubes": [ + {"origin": [-6, 11, -5], "size": [12, 18, 10], "uv": [18, 4]}, + {"origin": [-2, 11, -6], "size": [4, 6, 1], "uv": [52, 0]} + ] + }, + { + "name": "head", + "parent": "body", + "pivot": [0, 20, -8], + "locators": {"lead": [0, 20, -8]}, + "cubes": [ + {"origin": [-4, 16, -14], "size": [8, 8, 6], "uv": [0, 0]}, + {"origin": [-5, 22, -12], "size": [1, 3, 1], "uv": [22, 0]}, + {"origin": [4, 22, -12], "size": [1, 3, 1], "uv": [22, 0]} + ] + }, + { + "name": "leg0", + "parent": "body", + "pivot": [-4, 12, 7], + "cubes": [{"origin": [-6, 0, 5], "size": [4, 12, 4], "uv": [0, 16]}] + }, + { + "name": "leg1", + "parent": "body", + "mirror": true, + "pivot": [4, 12, 7], + "cubes": [{"origin": [2, 0, 5], "size": [4, 12, 4], "uv": [0, 16]}] + }, + { + "name": "leg2", + "parent": "body", + "pivot": [-4, 12, -6], + "cubes": [ + {"origin": [-6, 0, -7], "size": [4, 12, 4], "uv": [0, 16]} + ] + }, + { + "name": "leg3", + "parent": "body", + "mirror": true, + "pivot": [4, 12, -6], + "cubes": [{"origin": [2, 0, -7], "size": [4, 12, 4], "uv": [0, 16]}] + } + ] + } + }, + "render_controllers": ["controller.render.cow"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 1} + }, + "dragon_fireball": { + "identifier": "minecraft:dragon_fireball", + "materials": {"default": "fireball"}, + "textures": {"default": "textures/entity/enderdragon/dragon_fireball"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, -4, 0], + "size": [16, 16, 0], + "uv": {"south": {"uv": [0, 0]}} + } + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + } + }, + "render_controllers": ["controller.render.fireball"] + }, + "drowned": { + "identifier": "minecraft:drowned", + "min_engine_version": "1.16.0", + "materials": {"default": "drowned"}, + "textures": {"default": "textures/entity/zombie/drowned"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} + ] + }, + { + "name": "jacket", + "parent": "body", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-4, 12, -2], + "size": [8, 12, 4], + "uv": [16, 32], + "inflate": 0.5 + } + ] + }, + { + "name": "head", + "parent": "body", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-4, 24, -4], + "size": [8, 8, 8], + "uv": [0, 0], + "inflate": 0.5 + } + ] + }, + { + "name": "hat", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-4, 24, -4], + "size": [8, 8, 8], + "uv": [32, 0], + "inflate": 1 + } + ] + }, + { + "name": "rightArm", + "parent": "body", + "pivot": [-5, 22, 0], + "cubes": [ + {"origin": [-7, 12, -2], "size": [4, 12, 4], "uv": [0, 16]} + ] + }, + { + "name": "leftArm", + "parent": "body", + "pivot": [5, 22, 0], + "cubes": [ + { + "origin": [4, 12, -2], + "size": [4, 12, 4], + "uv": [40, 16], + "mirror": true + } + ] + }, + { + "name": "rightSleeve", + "parent": "rightArm", + "pivot": [-5, 22, 0], + "cubes": [ + { + "origin": [-7, 12, -2], + "size": [4, 12, 4], + "uv": [48, 48], + "inflate": 0.5 + } + ] + }, + { + "name": "leftSleeve", + "parent": "leftArm", + "pivot": [5, 22, 0], + "cubes": [ + { + "origin": [4, 12, -2], + "size": [4, 12, 4], + "uv": [40, 32], + "inflate": 0.5, + "mirror": true + } + ] + }, + { + "name": "rightLeg", + "parent": "body", + "pivot": [-1.9, 12, 0], + "cubes": [ + {"origin": [-4.05, 0, -2], "size": [4, 12, 4], "uv": [16, 48]} + ] + }, + { + "name": "leftLeg", + "parent": "body", + "pivot": [1.9, 12, 0], + "cubes": [ + { + "origin": [0.05, 0, -2], + "size": [4, 12, 4], + "uv": [32, 48], + "mirror": true + } + ] + }, + { + "name": "rightPants", + "parent": "rightLeg", + "pivot": [-1.9, 12, 0], + "cubes": [ + { + "origin": [-4.25, 0, -2], + "size": [4, 12, 4], + "uv": [0, 48], + "inflate": 0.25 + } + ] + }, + { + "name": "leftPants", + "parent": "leftLeg", + "pivot": [1.9, 12, 0], + "cubes": [ + { + "origin": [0.25, 0, -2], + "size": [4, 12, 4], + "uv": [0, 32], + "inflate": 0.25, + "mirror": true + } + ] + }, + {"name": "waist", "parent": "body", "pivot": [0, 12, 0]}, + {"name": "rightItem", "parent": "rightArm", "pivot": [-1, -45, -5]}, + {"name": "leftItem", "parent": "leftArm", "pivot": [1, -45, -5]} + ], + "visible_bounds_width": 2.5, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [0, 1.25, 0], + "texturewidth": 64, + "textureheight": 64 + } + }, + "render_controllers": ["controller.render.drowned"], + "enable_attachables": true, + "spawn_egg": {"texture": "spawn_egg", "texture_index": 48} + }, + "egg": { + "identifier": "minecraft:egg", + "materials": {"default": "egg"}, + "textures": {"default": "textures/items/egg"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, -8, 0], + "size": [16, 16, 0], + "uv": [0, 0], + "rotation": [0, 0, 0] + } + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + } + }, + "render_controllers": ["controller.render.item_sprite"] + }, + "elder_guardian": { + "identifier": "minecraft:elder_guardian", + "min_engine_version": "1.8.0", + "materials": {"default": "guardian", "ghost": "guardian_ghost"}, + "textures": { + "default": "textures/entity/guardian", + "elder": "textures/entity/guardian_elder", + "beam": "textures/entity/guardian_beam" + }, + "geometry": { + "default": { + "visible_bounds_width": 3.5, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 64, + "bones": [ + { + "name": "head", + "pivot": [0, 0, 0], + "mirror": true, + "cubes": [ + { + "mirror": false, + "origin": [-6, 2, -8], + "size": [12, 12, 16], + "uv": [0, 0] + }, + { + "mirror": false, + "origin": [-8, 2, -6], + "size": [2, 12, 12], + "uv": [0, 28] + }, + {"origin": [6, 2, -6], "size": [2, 12, 12], "uv": [0, 28]}, + {"origin": [-6, 14, -6], "size": [12, 2, 12], "uv": [16, 40]}, + {"origin": [-6, 0, -6], "size": [12, 2, 12], "uv": [16, 40]} + ] + }, + { + "name": "eye", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-1, 6, 0], "size": [2, 2, 1], "uv": [8, 0]}] + }, + { + "name": "tailpart0", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-2, 6, 7], "size": [4, 4, 8], "uv": [40, 0]}] + }, + { + "name": "tailpart1", + "parent": "tailpart0", + "pivot": [0, 24, 0], + "cubes": [{"origin": [0, 7, 0], "size": [3, 3, 7], "uv": [0, 54]}] + }, + { + "name": "tailpart2", + "parent": "tailpart1", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [0, 8, 0], "size": [2, 2, 6], "uv": [41, 32]}, + {"origin": [1, 4.5, 3], "size": [1, 9, 9], "uv": [25, 19]} + ] + }, + { + "name": "spikepart0", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart1", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart2", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart3", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart4", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart5", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart6", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart7", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart8", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart9", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart10", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart11", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + } + ] + }, + "ghost": { + "visible_bounds_width": 3.5, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 64, + "bones": [ + { + "name": "head", + "pivot": [0, 24, 0], + "mirror": true, + "cubes": [ + { + "mirror": false, + "origin": [-6, 2, -8], + "size": [12, 12, 16], + "uv": [0, 0] + }, + { + "mirror": false, + "origin": [-8, 2, -6], + "size": [2, 12, 12], + "uv": [0, 28] + }, + {"origin": [6, 2, -6], "size": [2, 12, 12], "uv": [0, 28]}, + {"origin": [-6, 14, -6], "size": [12, 2, 12], "uv": [16, 40]}, + {"origin": [-6, 0, -6], "size": [12, 2, 12], "uv": [16, 40]} + ] + }, + { + "name": "eye", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-1, 7, 0], "size": [2, 2, 1], "uv": [8, 0]}] + }, + { + "name": "tailpart0", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-2, 6, 7], "size": [4, 4, 8], "uv": [40, 0]}] + }, + { + "name": "tailpart1", + "parent": "tailpart0", + "pivot": [0, 24, 0], + "cubes": [{"origin": [0, 7, 0], "size": [3, 3, 7], "uv": [0, 54]}] + }, + { + "name": "tailpart2", + "parent": "tailpart1", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [0, 8, 0], "size": [2, 2, 6], "uv": [41, 32]}, + {"origin": [1, 4.5, 3], "size": [1, 9, 9], "uv": [25, 19]} + ] + }, + { + "name": "spikepart0", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart1", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart2", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart3", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart4", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart5", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart6", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart7", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart8", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart9", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart10", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + }, + { + "name": "spikepart11", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-1, 19.5, -1], "size": [2, 9, 2], "uv": [0, 0]} + ] + } + ] + } + }, + "render_controllers": ["controller.render.guardian"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 36} + }, + "eye_of_ender": { + "identifier": "minecraft:eye_of_ender_signal", + "materials": {"default": "eye_of_ender_signal"}, + "textures": {"default": "textures/items/ender_eye"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, -8, 0], + "size": [16, 16, 0], + "uv": [0, 0], + "rotation": [0, 0, 0] + } + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + } + }, + "render_controllers": ["controller.render.item_sprite"] + }, + "ender_pearl": { + "identifier": "minecraft:ender_pearl", + "materials": {"default": "ender_pearl"}, + "textures": {"default": "textures/items/ender_pearl"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, -8, 0], + "size": [16, 16, 0], + "uv": [0, 0], + "rotation": [0, 0, 0] + } + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + } + }, + "render_controllers": ["controller.render.item_sprite"] + }, + "evoker_fangs": { + "identifier": "minecraft:evocation_fang", + "materials": {"default": "fang"}, + "textures": {"default": "textures/entity/illager/evoker_fangs"}, + "geometry": { + "default": { + "visible_bounds_width": 1.5, + "visible_bounds_height": 3, + "visible_bounds_offset": [0, 1.5, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "upper_jaw", + "parent": "base", + "pivot": [0, 11, 0], + "cubes": [ + { + "origin": [-1.5, 0, -4], + "size": [4, 14, 8], + "uv": [40, 0], + "inflate": 0.01 + } + ] + }, + { + "name": "lower_jaw", + "parent": "base", + "pivot": [0, 11, 0], + "bind_pose_rotation": [0, 180, 0], + "cubes": [ + {"origin": [-1.5, 0, -4], "size": [4, 14, 8], "uv": [40, 0]} + ] + }, + { + "name": "base", + "pivot": [0, 0, 0], + "bind_pose_rotation": [0, 90, 0], + "cubes": [ + {"origin": [-5, 0, -5], "size": [10, 12, 10], "uv": [0, 0]} + ] + } + ] + } + }, + "render_controllers": ["controller.render.evocation_fang"] + }, + "evoker": { + "identifier": "minecraft:evocation_illager", + "min_engine_version": "1.8.0", + "materials": {"default": "evoker"}, + "textures": {"default": "textures/entity/illager/evoker"}, + "geometry": { + "default": { + "visible_bounds_width": 1.5, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [0, 1.25, 0], + "texturewidth": 64, + "textureheight": 64, + "bones": [ + { + "name": "head", + "parent": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 24, -4], "size": [8, 10, 8], "uv": [0, 0]} + ] + }, + { + "name": "nose", + "parent": "head", + "pivot": [0, 26, 0], + "cubes": [ + {"origin": [-1, 23, -6], "size": [2, 4, 2], "uv": [24, 0]} + ] + }, + { + "name": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 12, -3], "size": [8, 12, 6], "uv": [16, 20]}, + { + "origin": [-4, 6, -3], + "size": [8, 18, 6], + "uv": [0, 38], + "inflate": 0.5 + } + ] + }, + { + "name": "arms", + "parent": "body", + "pivot": [0, 22, 0], + "cubes": [ + {"origin": [-8, 16, -2], "size": [4, 8, 4], "uv": [44, 22]}, + {"origin": [4, 16, -2], "size": [4, 8, 4], "uv": [44, 22]}, + {"origin": [-4, 16, -2], "size": [8, 4, 4], "uv": [40, 38]} + ] + }, + { + "name": "leg0", + "parent": "body", + "pivot": [-2, 12, 0], + "cubes": [ + {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 22]} + ] + }, + { + "name": "leg1", + "parent": "body", + "pivot": [2, 12, 0], + "mirror": true, + "cubes": [{"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [0, 22]}] + }, + { + "name": "rightArm", + "parent": "body", + "pivot": [-5, 22, 0], + "locators": {"right_hand": [-6, 12, 0]}, + "cubes": [ + {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 46]} + ] + }, + { + "name": "rightItem", + "pivot": [-5.5, 16, 0.5], + "neverRender": true, + "parent": "rightArm" + }, + { + "name": "leftArm", + "parent": "body", + "pivot": [5, 22, 0], + "locators": {"left_hand": [6, 12, 0]}, + "mirror": true, + "cubes": [ + {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 46]} + ] + } + ] + } + }, + "particle_effects": {"spell": "minecraft:evoker_spell"}, + "render_controllers": ["controller.render.evoker"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 40} + }, + "experience_bottle": { + "identifier": "minecraft:xp_bottle", + "materials": {"default": "xp_bottle"}, + "textures": { + "default": "textures/items/experience_bottle", + "enchanted": "textures/misc/enchanted_item_glint" + }, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, -8, 0], + "size": [16, 16, 0], + "uv": [0, 0], + "rotation": [0, 0, 0] + } + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + } + }, + "render_controllers": ["controller.render.experience_bottle"] + }, + "experience_orb": { + "identifier": "minecraft:xp_orb", + "materials": {"default": "experience_orb"}, + "textures": {"default": "textures/entity/experience_orb"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [8, 8, 0], + "cubes": [ + { + "origin": [0, 0, 0], + "size": [16, 16, 0], + "uv": {"south": {"uv": [0, 0]}} + } + ] + } + ], + "texturewidth": 64, + "textureheight": 64 + } + }, + "render_controllers": ["controller.render.experience_orb"] + }, + "fireball": { + "identifier": "minecraft:fireball", + "materials": {"default": "fireball"}, + "textures": {"default": "textures/items/fire_charge"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, -4, 0], + "size": [16, 16, 0], + "uv": {"south": {"uv": [0, 0]}} + } + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + } + }, + "render_controllers": ["controller.render.fireball"] + }, + "firework_rocket": { + "identifier": "minecraft:fireworks_rocket", + "materials": {"default": "fireworks_rocket"}, + "textures": {"default": "textures/entity/fireworks"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, -8, 0], + "rotation": [0, 90, 0], + "size": [16, 16, 0], + "uv": {"north": {"uv": [0, 0]}} + }, + { + "origin": [-8, -8, 0], + "rotation": [90, 90, 0], + "size": [16, 16, 0], + "uv": {"north": {"uv": [0, 0]}} + } + ] + } + ], + "texturewidth": 32, + "textureheight": 32 + } + }, + "render_controllers": ["controller.render.fireworks_rocket"] + }, + "fishing_bobber": { + "identifier": "minecraft:fishing_hook", + "materials": {"default": "fishing_hook"}, + "textures": {"default": "textures/entity/fishing_hook"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-1.5, -1.5, -1.5], + "size": [3, 3, 3], + "rotation": [0, 0, 180], + "uv": { + "up": {"uv": [0, 0]}, + "down": {"uv": [3, 0]}, + "south": {"uv": [9, 0], "uv_size": [-3, 3]}, + "north": {"uv": [9, 0]}, + "east": {"uv": [12, 0]}, + "west": {"uv": [15, 0]} + } + }, + { + "origin": [0, -4.5, -0.5], + "size": [0, 3, 3], + "uv": {"east": {"uv": [18, 0]}} + }, + { + "origin": [0, 1.5, -1.5], + "size": [0, 3, 3], + "uv": {"east": {"uv": [21, 0]}} + }, + { + "origin": [-1.5, 1.5, 0], + "size": [3, 3, 0], + "uv": {"north": {"uv": [21, 0]}} + } + ] + } + ], + "texturewidth": 24, + "textureheight": 3 + } + }, + "render_controllers": ["controller.render.fishing_hook"] + }, + "hoglin": { + "identifier": "minecraft:hoglin", + "materials": {"default": "hoglin"}, + "textures": {"default": "textures/entity/hoglin/hoglin"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 19, -3], + "cubes": [ + { + "origin": [-8, 11, -7], + "size": [16, 14, 26], + "inflate": 0.02, + "uv": [1, 1] + }, + { + "origin": [0, 22, -10], + "size": [0, 10, 19], + "inflate": 0.02, + "uv": [90, 33] + } + ], + "locators": {"lead": [0, 20, -5]} + }, + { + "name": "head", + "parent": "body", + "pivot": [0, 22, -5], + "rotation": [50, 0, 0], + "cubes": [ + {"origin": [-7, 21, -24], "size": [14, 6, 19], "uv": [61, 1]}, + {"origin": [-8, 22, -19], "size": [2, 11, 2], "uv": [1, 13]}, + {"origin": [6, 22, -19], "size": [2, 11, 2], "uv": [1, 13]} + ] + }, + { + "name": "right_ear", + "parent": "head", + "pivot": [-7, 27, -7], + "rotation": [0, 0, -50], + "cubes": [ + {"origin": [-13, 26, -10], "size": [6, 1, 4], "uv": [1, 1]} + ] + }, + { + "name": "left_ear", + "parent": "head", + "pivot": [7, 27, -7], + "rotation": [0, 0, 50], + "cubes": [{"origin": [7, 26, -10], "size": [6, 1, 4], "uv": [1, 6]}] + }, + { + "name": "leg_back_right", + "pivot": [6, 8, 17], + "cubes": [ + {"origin": [-8, 0, 13], "size": [5, 11, 5], "uv": [21, 45]} + ] + }, + { + "name": "leg_back_left", + "pivot": [-6, 8, 17], + "cubes": [{"origin": [3, 0, 13], "size": [5, 11, 5], "uv": [0, 45]}] + }, + { + "name": "leg_front_right", + "pivot": [-6, 12, -3], + "cubes": [ + {"origin": [-8, 0, -6], "size": [6, 14, 6], "uv": [66, 42]} + ] + }, + { + "name": "leg_front_left", + "pivot": [6, 12, -3], + "cubes": [ + {"origin": [2, 0, -6], "size": [6, 14, 6], "uv": [41, 42]} + ] + } + ], + "visible_bounds_width": 4, + "visible_bounds_height": 3, + "visible_bounds_offset": [0, 1.5, 0], + "texturewidth": 128, + "textureheight": 64 + } + }, + "spawn_egg": {"base_color": "#C66E55", "overlay_color": "#5f6464"}, + "render_controllers": ["controller.render.hoglin"] + }, + "hopper_minecart": { + "identifier": "minecraft:hopper_minecart", + "min_engine_version": "1.8.0", + "materials": {"default": "minecart"}, + "textures": {"default": "textures/entity/minecart"}, + "geometry": { + "default": { + "bones": [ + { + "name": "bottom", + "pivot": [0, 6, 0], + "cubes": [ + { + "origin": [-10, -6.5, -1], + "size": [20, 16, 2], + "rotation": [90, 0, 0], + "uv": [0, 10] + } + ] + }, + { + "name": "back", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-17, 2.5, -1], + "size": [16, 8, 2], + "rotation": [0, 270, 0], + "uv": [0, 0] + } + ], + "parent": "bottom" + }, + { + "name": "front", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [1, 2.5, -1], + "size": [16, 8, 2], + "rotation": [0, 90, 0], + "uv": [0, 0] + } + ], + "parent": "bottom" + }, + { + "name": "right", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, 2.5, -8], + "size": [16, 8, 2], + "rotation": [0, 180, 0], + "uv": [0, 0] + } + ], + "parent": "bottom" + }, + { + "name": "left", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-8, 2.5, 6], "size": [16, 8, 2], "uv": [0, 0]} + ], + "parent": "bottom" + } + ], + "texturewidth": 64, + "textureheight": 32 + } + }, + "render_controllers": ["controller.render.minecart"] + }, + "husk": { + "identifier": "minecraft:husk", + "min_engine_version": "1.8.0", + "materials": {"default": "husk"}, + "textures": {"default": "textures/entity/zombie/husk"}, + "geometry": { + "default": { + "visible_bounds_width": 1.5, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [0, 1.25, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} + ], + "parent": "waist" + }, + {"name": "waist", "neverRender": true, "pivot": [0, 12, 0]}, + { + "name": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]} + ], + "parent": "body" + }, + { + "name": "hat", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-4, 24, -4], + "size": [8, 8, 8], + "uv": [32, 0], + "inflate": 0.5 + } + ], + "neverRender": true, + "parent": "head" + }, + { + "name": "rightArm", + "pivot": [-5, 22, 0], + "cubes": [ + {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} + ], + "parent": "body" + }, + { + "name": "rightItem", + "pivot": [-1, -45, -5], + "neverRender": true, + "parent": "rightArm" + }, + { + "name": "leftArm", + "pivot": [5, 22, 0], + "cubes": [ + {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} + ], + "mirror": true, + "parent": "body" + }, + { + "name": "leftItem", + "pivot": [1, -45, -5], + "neverRender": true, + "parent": "leftArm" + }, + { + "name": "rightLeg", + "pivot": [-1.9, 12, 0], + "cubes": [ + {"origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} + ], + "parent": "body" + }, + { + "name": "leftLeg", + "pivot": [1.9, 12, 0], + "cubes": [ + {"origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} + ], + "mirror": true, + "parent": "body" + } + ] + } + }, + "scripts": { + "pre_animation": [ + "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;" + ] + }, + "animations": { + "humanoid_big_head": {"loop": true, "bones": {"head": {"scale": 1.4}}}, + "look_at_target_default": { + "loop": true, + "bones": { + "head": { + "relative_to": {"rotation": "entity"}, + "rotation": [ + "query.target_x_rotation", + "query.target_y_rotation", + 0 + ] + } + } + }, + "look_at_target_gliding": { + "loop": true, + "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} + }, + "look_at_target_swimming": { + "loop": true, + "bones": { + "head": { + "rotation": [ + "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", + "query.target_y_rotation", + 0 + ] + } + } + }, + "move": { + "loop": true, + "bones": { + "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, + "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, + "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, + "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} + } + }, + "riding.arms": { + "loop": true, + "bones": { + "leftarm": {"rotation": [-36, 0, 0]}, + "rightarm": {"rotation": [-36, 0, 0]} + } + }, + "riding.legs": { + "loop": true, + "bones": { + "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, + "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} + } + }, + "holding": { + "loop": true, + "bones": { + "leftarm": { + "rotation": [ + "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", + 0, + 0 + ] + }, + "rightarm": { + "rotation": [ + "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", + 0, + 0 + ] + } + } + }, + "brandish_spear": { + "loop": true, + "bones": { + "rightarm": { + "rotation": [ + "this * -0.5 - 157.5 - 22.5 * variable.charge_amount", + "-this", + 0 + ] + } + } + }, + "charging": { + "loop": true, + "bones": { + "rightarm": { + "rotation": ["22.5 * variable.charge_amount - this", "-this", 0] + } + } + }, + "attack.rotations": { + "loop": true, + "bones": { + "body": { + "rotation": [ + 0, + "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46 - this", + 0 + ] + }, + "leftarm": { + "rotation": [ + "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46", + 0, + 0 + ] + }, + "rightarm": { + "rotation": [ + "math.sin(1.0 - math.pow(1.0 - variable.attack_time, 3.0) * 180.0) * (variable.is_brandishing_spear ? -1.0 : 1.0 )", + "variable.is_brandishing_spear ? 0.0 : (math.sin(math.sqrt(variable.attack_time) * 360) * 11.46) * 2.0", + 0 + ] + } + } + }, + "sneaking": { + "loop": true, + "bones": { + "body": {"rotation": ["0.5 - this", 0, 0]}, + "head": {"position": [0, 1, 0]}, + "leftarm": {"rotation": [72, 0, 0]}, + "leftleg": {"position": [0, -3, 4]}, + "rightarm": {"rotation": [72, 0, 0]}, + "rightleg": {"position": [0, -3, 4]} + } + }, + "bob": { + "loop": true, + "bones": { + "leftarm": { + "rotation": [ + 0, + 0, + "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" + ] + }, + "rightarm": { + "rotation": [ + 0, + 0, + "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" + ] + } + } + }, + "damage_nearby_mobs": { + "loop": true, + "bones": { + "leftarm": {"rotation": ["-45.0-this", "-this", "-this"]}, + "leftleg": {"rotation": ["45.0-this", "-this", "-this"]}, + "rightarm": {"rotation": ["45.0-this", "-this", "-this"]}, + "rightleg": {"rotation": ["-45.0-this", "-this", "-this"]} + } + }, + "bow_and_arrow": { + "loop": true, + "bones": { + "leftarm": { + "rotation": [ + "query.target_x_rotation - 90.0 - math.sin(query.life_time * 76.8) * 2.865 - this", + "query.target_y_rotation + 28.65", + "-(math.cos(query.life_time * 103.2) * 2.865) - 2.865" + ] + }, + "rightarm": { + "rotation": [ + "query.target_x_rotation - 90.0 + math.sin(query.life_time * 76.8) * 2.865 - this", + "query.target_y_rotation - 5.73", + "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" + ] + } + } + }, + "use_item_progress": { + "loop": true, + "bones": { + "rightarm": { + "rotation": [ + "variable.use_item_startup_progress * -60.0 + variable.use_item_interval_progress * 11.25", + "variable.use_item_startup_progress * -22.5 + variable.use_item_interval_progress * 11.25", + "variable.use_item_startup_progress * -5.625 + variable.use_item_interval_progress * 11.25" + ] + } + } + }, + "zombie_attack_bare_hand": { + "loop": true, + "bones": { + "leftarm": { + "rotation": [ + "-90.0 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) - (math.sin(query.life_time * 76.776372) * 2.865) - this", + "5.73 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 0.6) - this", + "math.cos(query.life_time * 103.13244) * -2.865 - 2.865 - this" + ] + }, + "rightarm": { + "rotation": [ + "90.0 * (variable.is_brandishing_spear - 1.0) - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) + (math.sin(query.life_time * 76.776372) * 2.865) - this", + "(math.sin(variable.attack_time * 180.0) * 57.3) * 0.6 - 5.73 - this", + "math.cos(query.life_time * 103.13244) * 2.865 + 2.865 - this" + ] + } + } + }, + "swimming": { + "loop": true, + "bones": { + "body": { + "position": [ + 0, + "variable.swim_amount * -10.0 - this", + "variable.swim_amount * 9.0 - this" + ], + "rotation": [ + "variable.swim_amount * (90.0 + query.target_x_rotation)", + 0, + 0 + ] + }, + "leftarm": { + "rotation": [ + "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) - (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", + "math.lerp(this, 14.325, variable.swim_amount) - this", + "math.lerp(this, 14.325, variable.swim_amount) - (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" + ] + }, + "leftleg": { + "rotation": [ + "math.lerp(this, math.cos(query.life_time * 390.0 + 180.0) * 0.3, variable.swim_amount)", + 0, + 0 + ] + }, + "rightarm": { + "rotation": [ + "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) + (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", + "math.lerp(this, 14.325, variable.swim_amount) - this", + "math.lerp(this, -14.325, variable.swim_amount) + (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" + ] + }, + "rightleg": { + "rotation": [ + "math.lerp(this, math.cos(query.life_time * 390.0) * 0.3, variable.swim_amount)", + 0, + 0 + ] + } + } + } + }, + "animation_controllers": { + "humanoid_baby_big_head": { + "initial_state": "default", + "states": { + "baby": { + "animations": ["humanoid_big_head"], + "transitions": [{"default": "!query.is_baby"}] + }, + "default": {"transitions": [{"baby": "query.is_baby"}]} + } + }, + "look_at_target": { + "initial_state": "default", + "states": { + "default": { + "animations": ["look_at_target_default"], + "transitions": [ + {"gliding": "query.is_gliding"}, + {"swimming": "query.is_swimming"} + ] + }, + "gliding": { + "animations": ["look_at_target_gliding"], + "transitions": [ + {"swimming": "query.is_swimming"}, + {"default": "!query.is_gliding"} + ] + }, + "swimming": { + "animations": ["look_at_target_swimming"], + "transitions": [ + {"gliding": "query.is_gliding"}, + {"default": "!query.is_swimming"} + ] + } + } + }, + "move": { + "initial_state": "default", + "states": {"default": {"animations": ["move"]}} + }, + "riding": { + "initial_state": "default", + "states": { + "default": {"transitions": [{"riding": "query.is_riding"}]}, + "riding": { + "animations": ["riding.arms", "riding.legs"], + "transitions": [{"default": "!query.is_riding"}] + } + } + }, + "holding": { + "initial_state": "default", + "states": {"default": {"animations": ["holding"]}} + }, + "brandish_spear": { + "initial_state": "default", + "states": { + "brandish_spear": { + "animations": ["brandish_spear"], + "transitions": [{"default": "!variable.is_brandishing_spear"}] + }, + "default": { + "transitions": [{"brandish_spear": "variable.is_brandishing_spear"}] + } + } + }, + "charging": { + "initial_state": "default", + "states": { + "charging": { + "animations": ["charging"], + "transitions": [{"default": "!query.is_charging"}] + }, + "default": {"transitions": [{"charging": "query.is_charging"}]} + } + }, + "attack": { + "initial_state": "default", + "states": { + "attacking": { + "animations": ["attack.rotations"], + "transitions": [{"default": "variable.attack_time < 0.0"}] + }, + "default": { + "transitions": [{"attacking": "variable.attack_time >= 0.0"}] + } + } + }, + "sneaking": { + "initial_state": "default", + "states": { + "default": {"transitions": [{"sneaking": "query.is_sneaking"}]}, + "sneaking": { + "animations": ["sneaking"], + "transitions": [{"default": "!query.is_sneaking"}] + } + } + }, + "bob": { + "initial_state": "default", + "states": {"default": {"animations": ["bob"]}} + }, + "damage_nearby_mobs": { + "initial_state": "default", + "states": { + "damage_nearby_mobs": { + "animations": ["damage_nearby_mobs"], + "transitions": [{"default": "!variable.damage_nearby_mobs"}] + }, + "default": { + "transitions": [ + {"damage_nearby_mobs": "variable.damage_nearby_mobs"} + ] + } + } + }, + "bow_and_arrow": { + "initial_state": "default", + "states": { + "bow_and_arrow": { + "animations": ["bow_and_arrow"], + "transitions": [{"default": "!query.has_target"}] + }, + "default": {"transitions": [{"bow_and_arrow": "query.has_target"}]} + } + }, + "use_item_progress": { + "initial_state": "default", + "states": { + "default": { + "transitions": [ + { + "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 )" + } + ] + }, + "use_item_progress": { + "animations": ["use_item_progress"], + "transitions": [ + { + "default": "( variable.use_item_interval_progress <= 0.0 ) && ( variable.use_item_startup_progress <= 0.0 )" + } + ] + } + } + }, + "zombie_attack_bare_hand": { + "initial_state": "default", + "states": { + "default": { + "transitions": [{"is_bare_hand": "variable.is_holding_left != 1.0"}] + }, + "is_bare_hand": { + "animations": ["zombie_attack_bare_hand"], + "transitions": [{"default": "variable.is_holding_left == 1.0"}] + } + } + }, + "swimming": { + "initial_state": "default", + "states": { + "default": { + "transitions": [{"is_swimming": "variable.swim_amount > 0.0"}] + }, + "is_swimming": { + "animations": ["swimming"], + "transitions": [{"default": "variable.swim_amount <= 0.0"}] + } + } + } + }, + "render_controllers": ["controller.render.husk"], + "enable_attachables": true, + "spawn_egg": {"texture": "spawn_egg", "texture_index": 28} + }, + "iron_golem": { + "identifier": "minecraft:iron_golem", + "materials": {"default": "iron_golem"}, + "textures": {"default": "textures/entity/iron_golem/iron_golem"}, + "geometry": { + "default": { + "visible_bounds_width": 3, + "visible_bounds_height": 3, + "visible_bounds_offset": [0, 1.5, 0], + "texturewidth": 128, + "textureheight": 128, + "bones": [ + { + "name": "body", + "pivot": [0, 31, 0], + "cubes": [ + {"origin": [-9, 21, -6], "size": [18, 12, 11], "uv": [0, 40]}, + { + "origin": [-4.5, 16, -3], + "size": [9, 5, 6], + "uv": [0, 70], + "inflate": 0.5 + } + ] + }, + { + "name": "head", + "parent": "body", + "pivot": [0, 31, -2], + "locators": {"lead": [0, 31, -2]}, + "cubes": [ + {"origin": [-4, 33, -7.5], "size": [8, 10, 8], "uv": [0, 0]}, + {"origin": [-1, 32, -9.5], "size": [2, 4, 2], "uv": [24, 0]} + ] + }, + { + "name": "arm0", + "parent": "body", + "pivot": [0, 31, 0], + "cubes": [ + {"origin": [-13, 3.5, -3], "size": [4, 30, 6], "uv": [60, 21]} + ] + }, + { + "name": "arm1", + "parent": "body", + "pivot": [0, 31, 0], + "cubes": [ + {"origin": [9, 3.5, -3], "size": [4, 30, 6], "uv": [60, 58]} + ] + }, + { + "name": "leg0", + "parent": "body", + "pivot": [-4, 13, 0], + "cubes": [ + {"origin": [-7.5, 0, -3], "size": [6, 16, 5], "uv": [37, 0]} + ] + }, + { + "name": "leg1", + "parent": "body", + "mirror": true, + "pivot": [5, 13, 0], + "cubes": [ + {"origin": [1.5, 0, -3], "size": [6, 16, 5], "uv": [60, 0]} + ] + } + ] + } + }, + "render_controllers": ["controller.render.iron_golem"] + }, + "item_frame": { + "identifier": "minecraft:item_frame", + "materials": {"default": "item_frame"}, + "textures": { + "background": "block:item_frame", + "frame": "block:oak_planks" + }, + "geometry": { + "background": { + "bones": [ + { + "name": "base" + }, + { + "name": "background", + "parent": "base", + "rotation": [0, 180, 0], + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-5, -5, -8], "size": [10, 10, 0.5], "uv": [3, 3]} + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + }, + "frame": { + "bones": [ + { + "name": "frame", + "parent": "base", + "rotation": [0, 180, 0], + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-6, -6, -8], "size": [12, 1, 1], "uv": [2, 2]}, + {"origin": [-6, 5, -8], "size": [12, 1, 1], "uv": [2, 13]}, + {"origin": [-6, -5, -8], "size": [1, 10, 1], "uv": [2, 3]}, + {"origin": [5, -5, -8], "size": [1, 10, 1], "uv": [13, 3]} + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + } + }, + "render_controllers": ["controller.render.item_frame"] + }, + "leash_knot": { + "identifier": "minecraft:leash_knot", + "materials": {"default": "leash_knot"}, + "textures": {"default": "textures/entity/lead_knot"}, + "geometry": { + "default": { + "bones": [ + { + "name": "knot", + "rotation": [0, 180, 0], + "cubes": [{"origin": [5, 6, 5], "size": [6, 8, 6], "uv": [0, 0]}] + } + ], + "texturewidth": 32, + "textureheight": 32 + } + }, + "render_controllers": ["controller.render.leash_knot"] + }, + "llama_spit": { + "identifier": "minecraft:llama_spit", + "materials": {"default": "llama_spit"}, + "textures": {"default": "textures/entity/llama/spit"}, + "geometry": { + "default": { + "visible_bounds_width": 1, + "visible_bounds_height": 1, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 64, + "bones": [ + { + "name": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 22, 0], "size": [2, 2, 2], "uv": [0, 0]}, + {"origin": [0, 26, 0], "size": [2, 2, 2], "uv": [0, 0]}, + {"origin": [0, 22, -4], "size": [2, 2, 2], "uv": [0, 0]}, + {"origin": [0, 22, 0], "size": [2, 2, 2], "uv": [0, 0]}, + {"origin": [2, 22, 0], "size": [2, 2, 2], "uv": [0, 0]}, + {"origin": [0, 20, 0], "size": [2, 2, 2], "uv": [0, 0]}, + {"origin": [0, 22, 2], "size": [2, 2, 2], "uv": [0, 0]} + ] + } + ] + } + }, + "render_controllers": ["controller.render.llama_spit"] + }, + "magma_cube": { + "identifier": "minecraft:magma_cube", + "materials": {"default": "magma_cube"}, + "textures": {"default": "textures/entity/slime/magmacube"}, + "geometry": { + "default": { + "visible_bounds_width": 2.5, + "visible_bounds_height": 5, + "visible_bounds_offset": [0, 2.5, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "bodyCube_0", + "parent": "insideCube", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-4, 7, -4], "size": [8, 1, 8], "uv": [0, 0]}] + }, + { + "name": "bodyCube_1", + "parent": "insideCube", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-4, 6, -4], "size": [8, 1, 8], "uv": [0, 1]}] + }, + { + "name": "bodyCube_2", + "parent": "insideCube", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 5, -4], "size": [8, 1, 8], "uv": [24, 10]} + ] + }, + { + "name": "bodyCube_3", + "parent": "insideCube", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 4, -4], "size": [8, 1, 8], "uv": [24, 19]} + ] + }, + { + "name": "bodyCube_4", + "parent": "insideCube", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-4, 3, -4], "size": [8, 1, 8], "uv": [0, 4]}] + }, + { + "name": "bodyCube_5", + "parent": "insideCube", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-4, 2, -4], "size": [8, 1, 8], "uv": [0, 5]}] + }, + { + "name": "bodyCube_6", + "parent": "insideCube", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-4, 1, -4], "size": [8, 1, 8], "uv": [0, 6]}] + }, + { + "name": "bodyCube_7", + "parent": "insideCube", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-4, 0, -4], "size": [8, 1, 8], "uv": [0, 7]}] + }, + { + "name": "insideCube", + "pivot": [0, 0, 0], + "cubes": [{"origin": [-2, 2, -2], "size": [4, 4, 4], "uv": [0, 16]}] + } + ] + } + }, + "render_controllers": ["controller.render.magma_cube"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 20} + }, + "mooshroom": { + "identifier": "minecraft:mooshroom", + "min_engine_version": "1.8.0", + "materials": {"default": "mooshroom"}, + "textures": { + "default": "textures/entity/cow/red_mooshroom", + "brown": "textures/entity/cow/brown_mooshroom" + }, + "geometry": { + "default": { + "visible_bounds_width": 2, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 1, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "body", + "pivot": [0, 19, 2], + "bind_pose_rotation": [90, 0, 0], + "cubes": [ + {"origin": [-6, 11, -5], "size": [12, 18, 10], "uv": [18, 4]}, + {"origin": [-2, 11, -6], "size": [4, 6, 1], "uv": [52, 0]} + ] + }, + { + "name": "head", + "pivot": [0, 20, -8], + "locators": {"lead": [0, 20, -8]}, + "cubes": [ + {"origin": [-4, 16, -14], "size": [8, 8, 6], "uv": [0, 0]}, + {"origin": [-5, 22, -12], "size": [1, 3, 1], "uv": [22, 0]}, + {"origin": [4, 22, -12], "size": [1, 3, 1], "uv": [22, 0]} + ] + }, + { + "name": "leg0", + "parent": "body", + "pivot": [-4, 12, 7], + "cubes": [{"origin": [-6, 0, 5], "size": [4, 12, 4], "uv": [0, 16]}] + }, + { + "name": "leg1", + "parent": "body", + "mirror": true, + "pivot": [4, 12, 7], + "cubes": [{"origin": [2, 0, 5], "size": [4, 12, 4], "uv": [0, 16]}] + }, + { + "name": "leg2", + "parent": "body", + "pivot": [-4, 12, -6], + "cubes": [ + {"origin": [-6, 0, -7], "size": [4, 12, 4], "uv": [0, 16]} + ] + }, + { + "name": "leg3", + "parent": "body", + "mirror": true, + "pivot": [4, 12, -6], + "cubes": [{"origin": [2, 0, -7], "size": [4, 12, 4], "uv": [0, 16]}] + } + ] + } + }, + "render_controllers": ["controller.render.mooshroom"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 5} + }, + "panda": { + "identifier": "minecraft:panda", + "materials": {"default": "panda"}, + "textures": { + "default": "textures/entity/panda/panda", + "lazy": "textures/entity/panda/lazy_panda", + "worried": "textures/entity/panda/worried_panda", + "playful": "textures/entity/panda/playful_panda", + "brown": "textures/entity/panda/brown_panda", + "weak": "textures/entity/panda/weak_panda", + "aggressive": "textures/entity/panda/aggressive_panda" + }, + "geometry": { + "default": { + "texturewidth": 64, + "textureheight": 64, + "bones": [ + { + "name": "head", + "parent": "body", + "pivot": [0, 12.5, -17], + "locators": {"lead": [0, 14, -16]}, + "cubes": [ + {"origin": [-6.5, 7.5, -21], "size": [13, 10, 9], "uv": [0, 6]}, + {"origin": [-3.5, 7.5, -23], "size": [7, 5, 2], "uv": [45, 16]}, + {"origin": [-8.5, 16.5, -18], "size": [5, 4, 1], "uv": [52, 25]}, + {"origin": [3.5, 16.5, -18], "size": [5, 4, 1], "uv": [52, 25]} + ] + }, + { + "name": "body", + "pivot": [0, 14, 0], + "bind_pose_rotation": [90, 0, 0], + "cubes": [ + {"origin": [-9.5, 1, -6.5], "size": [19, 26, 13], "uv": [0, 25]} + ] + }, + { + "name": "leg0", + "parent": "body", + "pivot": [-5.5, 9, 9], + "cubes": [ + {"origin": [-8.5, 0, 6], "size": [6, 9, 6], "uv": [40, 0]} + ] + }, + { + "name": "leg1", + "parent": "body", + "pivot": [5.5, 9, 9], + "cubes": [{"origin": [2.5, 0, 6], "size": [6, 9, 6], "uv": [40, 0]}] + }, + { + "name": "leg2", + "parent": "body", + "pivot": [-5.5, 9, -9], + "cubes": [ + {"origin": [-8.5, 0, -12], "size": [6, 9, 6], "uv": [40, 0]} + ] + }, + { + "name": "leg3", + "parent": "body", + "pivot": [5.5, 9, -9], + "cubes": [ + {"origin": [2.5, 0, -12], "size": [6, 9, 6], "uv": [40, 0]} + ] + } + ] + } + }, + "render_controllers": ["controller.render.panda"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 54} + }, + "phantom": { + "identifier": "minecraft:phantom", + "materials": {"default": "phantom", "invisible": "phantom_invisible"}, + "textures": {"default": "textures/entity/phantom"}, + "geometry": { + "default": { + "texturewidth": 64, + "textureheight": 64, + "bones": [ + { + "name": "body", + "pivot": [0, 24, 0], + "bind_pose_rotation": [0, 0, 0], + "cubes": [{"origin": [-3, 23, -8], "size": [5, 3, 9], "uv": [0, 8]}] + }, + { + "name": "wing0", + "pivot": [2, 26, -8], + "bind_pose_rotation": [0, 0, 5.7], + "cubes": [ + {"origin": [2, 24, -8], "size": [6, 2, 9], "uv": [23, 12]} + ], + "parent": "body" + }, + { + "name": "wingtip0", + "pivot": [8, 26, -8], + "bind_pose_rotation": [0, 0, 5.7], + "locators": {"left_wing": [21, 26, 0]}, + "cubes": [ + {"origin": [8, 25, -8], "size": [13, 1, 9], "uv": [16, 24]} + ], + "parent": "wing0" + }, + { + "name": "wing1", + "pivot": [-3, 26, -8], + "bind_pose_rotation": [0, 0, -5.7], + "mirror": true, + "cubes": [ + {"origin": [-9, 24, -8], "size": [6, 2, 9], "uv": [23, 12]} + ], + "parent": "body" + }, + { + "name": "wingtip1", + "pivot": [-9, 24, -8], + "bind_pose_rotation": [0, 0, -5.7], + "locators": {"right_wing": [-22, 24, 0]}, + "mirror": true, + "cubes": [ + {"origin": [-22, 25, -8], "size": [13, 1, 9], "uv": [16, 24]} + ], + "parent": "wing1" + }, + { + "name": "head", + "pivot": [0, 23, -7], + "bind_pose_rotation": [11.5, 0, 0], + "cubes": [ + {"origin": [-4, 22, -12], "size": [7, 3, 5], "uv": [0, 0]} + ], + "parent": "body" + }, + { + "name": "tail", + "pivot": [0, 26, 1], + "bind_pose_rotation": [0, 0, 0], + "cubes": [ + {"origin": [-2, 24, 1], "size": [3, 2, 6], "uv": [3, 20]} + ], + "parent": "body" + }, + { + "name": "tailtip", + "pivot": [0, 25.5, 7], + "bind_pose_rotation": [0, 0, 0], + "cubes": [ + {"origin": [-1, 24.5, 7], "size": [1, 1, 6], "uv": [4, 29]} + ], + "parent": "tail" + } + ] + } + }, + "particle_effects": {"wing_dust": "minecraft:phantom_trail_particle"}, + "sound_effects": {"flap": "mob.phantom.flap"}, + "render_controllers": ["controller.render.phantom"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 51} + }, + "pig": { + "identifier": "minecraft:pig", + "min_engine_version": "1.8.0", + "materials": {"default": "pig"}, + "textures": { + "default": "textures/entity/pig/pig", + "saddled": "textures/entity/pig/pig_saddle" + }, + "geometry": { + "default": { + "visible_bounds_width": 2, + "visible_bounds_height": 1.5, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "body", + "pivot": [0, 13, 2], + "bind_pose_rotation": [90, 0, 0], + "cubes": [ + {"origin": [-5, 7, -5], "size": [10, 16, 8], "uv": [28, 8]} + ] + }, + { + "name": "head", + "parent": "body", + "pivot": [0, 12, -6], + "locators": {"lead": [0, 14, -6]}, + "cubes": [ + {"origin": [-4, 8, -14], "size": [8, 8, 8], "uv": [0, 0]}, + {"origin": [-2, 9, -15], "size": [4, 3, 1], "uv": [16, 16]} + ] + }, + { + "name": "leg0", + "parent": "body", + "pivot": [-3, 6, 7], + "cubes": [{"origin": [-5, 0, 5], "size": [4, 6, 4], "uv": [0, 16]}] + }, + { + "name": "leg1", + "parent": "body", + "mirror": true, + "pivot": [3, 6, 7], + "cubes": [{"origin": [1, 0, 5], "size": [4, 6, 4], "uv": [0, 16]}] + }, + { + "name": "leg2", + "parent": "body", + "pivot": [-3, 6, -5], + "cubes": [{"origin": [-5, 0, -7], "size": [4, 6, 4], "uv": [0, 16]}] + }, + { + "name": "leg3", + "parent": "body", + "mirror": true, + "pivot": [3, 6, -5], + "cubes": [{"origin": [1, 0, -7], "size": [4, 6, 4], "uv": [0, 16]}] + } + ] + } + }, + "render_controllers": ["controller.render.pig"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 2} + }, + "piglin_brute": { + "identifier": "minecraft:piglin_brute", + "materials": {"default": "piglin_brute"}, + "textures": {"default": "textures/entity/piglin/piglin_brute"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]}, + { + "origin": [-4, 12, -2], + "size": [8, 12, 4], + "uv": [16, 32], + "inflate": 0.25 + } + ] + }, + { + "name": "head", + "parent": "body", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-5, 24, -4], + "size": [10, 8, 8], + "uv": [0, 0], + "inflate": -0.02 + }, + {"origin": [-2, 24, -5], "size": [4, 4, 1], "uv": [31, 1]}, + {"origin": [2, 24, -5], "size": [1, 2, 1], "uv": [2, 4]}, + {"origin": [-3, 24, -5], "size": [1, 2, 1], "uv": [2, 0]} + ], + "inflate": -0.02 + }, + { + "name": "leftear", + "parent": "head", + "pivot": [5, 30, 0], + "rotation": [0, 0, -30], + "cubes": [{"origin": [4, 25, -2], "size": [1, 5, 4], "uv": [51, 6]}] + }, + { + "name": "rightear", + "parent": "head", + "pivot": [-5, 30, 0], + "rotation": [0, 0, 30], + "cubes": [ + {"origin": [-5, 25, -2], "size": [1, 5, 4], "uv": [39, 6]} + ] + }, + {"name": "hat", "parent": "head", "pivot": [0, 24, 0]}, + { + "name": "rightarm", + "parent": "body", + "pivot": [-5, 22, 0], + "cubes": [ + {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]}, + { + "origin": [-8, 12, -2], + "size": [4, 12, 4], + "uv": [40, 32], + "inflate": 0.25 + } + ] + }, + {"name": "rightItem", "parent": "rightarm", "pivot": [-1, -45, -5]}, + { + "name": "leftarm", + "parent": "body", + "pivot": [5, 22, 0], + "cubes": [ + {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [32, 48]}, + { + "origin": [4, 12, -2], + "size": [4, 12, 4], + "uv": [48, 48], + "inflate": 0.25 + } + ] + }, + {"name": "leftItem", "parent": "leftArm", "pivot": [1, -45, -5]}, + { + "name": "rightleg", + "parent": "body", + "pivot": [-1.9, 12, 0], + "cubes": [ + {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 16]}, + { + "origin": [-4, 0, -2], + "size": [4, 12, 4], + "uv": [0, 32], + "inflate": 0.25 + } + ] + }, + { + "name": "leftleg", + "parent": "body", + "pivot": [1.9, 12, 0], + "cubes": [ + {"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [16, 48]}, + { + "origin": [0, 0, -2], + "size": [4, 12, 4], + "uv": [0, 48], + "inflate": 0.25 + } + ] + } + ], + "visible_bounds_width": 2, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 1, 0], + "texturewidth": 64, + "textureheight": 64 + } + }, + "spawn_egg": {"base_color": "#592A10", "overlay_color": "#F9F3A4"}, + "render_controllers": ["controller.render.piglin_brute"], + "enable_attachables": true + }, + "polar_bear": { + "identifier": "minecraft:polar_bear", + "materials": {"default": "polar_bear"}, + "textures": {"default": "textures/entity/bear/polarbear"}, + "geometry": { + "default": { + "visible_bounds_width": 3, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 128, + "textureheight": 64, + "bones": [ + { + "name": "head", + "parent": "body", + "pivot": [0, 14, -16], + "locators": {"lead": [0, 14, -16]}, + "mirror": true, + "cubes": [ + { + "mirror": false, + "origin": [-3.5, 10, -19], + "size": [7, 7, 7], + "uv": [0, 0] + }, + { + "mirror": false, + "origin": [-2.5, 10, -22], + "size": [5, 3, 3], + "uv": [0, 44] + }, + { + "mirror": false, + "origin": [-4.5, 16, -17], + "size": [2, 2, 1], + "uv": [26, 0] + }, + {"origin": [2.5, 16, -17], "size": [2, 2, 1], "uv": [26, 0]} + ] + }, + { + "name": "body", + "pivot": [-2, 15, 12], + "bind_pose_rotation": [90, 0, 0], + "cubes": [ + {"origin": [-7, 14, 5], "size": [14, 14, 11], "uv": [0, 19]}, + {"origin": [-6, 28, 5], "size": [12, 12, 10], "uv": [39, 0]} + ] + }, + { + "name": "leg0", + "parent": "body", + "pivot": [-4.5, 10, 6], + "cubes": [ + {"origin": [-6.5, 0, 4], "size": [4, 10, 8], "uv": [50, 22]} + ] + }, + { + "name": "leg1", + "parent": "body", + "pivot": [4.5, 10, 6], + "cubes": [ + {"origin": [2.5, 0, 4], "size": [4, 10, 8], "uv": [50, 22]} + ] + }, + { + "name": "leg2", + "parent": "body", + "pivot": [-3.5, 10, -8], + "cubes": [ + {"origin": [-5.5, 0, -10], "size": [4, 10, 6], "uv": [50, 40]} + ] + }, + { + "name": "leg3", + "parent": "body", + "pivot": [3.5, 10, -8], + "cubes": [ + {"origin": [1.5, 0, -10], "size": [4, 10, 6], "uv": [50, 40]} + ] + } + ] + } + }, + "render_controllers": ["controller.render.polarbear"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 37} + }, + "pufferfish": { + "identifier": "minecraft:pufferfish", + "min_engine_version": "1.8.0", + "materials": {"default": "pufferfish"}, + "textures": {"default": "textures/entity/fish/pufferfish"}, + "geometry": { + "default": { + "visible_bounds_width": 0.5, + "visible_bounds_height": 0.5, + "texturewidth": 32, + "textureheight": 32, + "bones": [ + { + "name": "body", + "cubes": [ + {"origin": [-1.5, 0, -1.5], "size": [3, 2, 3], "uv": [0, 27]}, + {"origin": [0.5, 2, -1.5], "size": [1, 1, 1], "uv": [24, 6]}, + {"origin": [-1.5, 2, -1.5], "size": [1, 1, 1], "uv": [28, 6]} + ], + "locators": {"lead": [0, 0, 0]} + }, + { + "name": "tailfin", + "parent": "body", + "cubes": [ + {"origin": [-1.5, 1, 1.5], "size": [3, 0, 3], "uv": [-3, 0]} + ] + }, + { + "name": "leftFin", + "parent": "body", + "pivot": [6.5, 5, 0.5], + "cubes": [ + { + "origin": [1.5, 0, -1.5], + "size": [1, 1, 2], + "uv": [25, 0], + "mirror": true + } + ] + }, + { + "name": "rightFin", + "parent": "body", + "pivot": [-6.5, 5, 0.5], + "cubes": [ + {"origin": [-2.5, 0, -1.5], "size": [1, 1, 2], "uv": [25, 0]} + ] + } + ] + }, + "mid": { + "visible_bounds_width": 0.5, + "visible_bounds_height": 0.5, + "texturewidth": 32, + "textureheight": 32, + "bones": [ + { + "name": "body", + "cubes": [ + {"origin": [-2.5, 1, -2.5], "size": [5, 5, 5], "uv": [12, 22]} + ] + }, + { + "name": "leftFin", + "parent": "body", + "pivot": [2.5, 5, 0.5], + "cubes": [ + {"origin": [2.5, 4, -1.5], "size": [2, 1, 2], "uv": [24, 3]} + ] + }, + { + "name": "rightFin", + "parent": "body", + "pivot": [-2.5, 5, 0.5], + "cubes": [ + {"origin": [-4.5, 4, -1.5], "size": [2, 1, 2], "uv": [24, 0]} + ] + }, + { + "name": "spines_top_front", + "parent": "body", + "bind_pose_rotation": [45, 0, 0], + "pivot": [0, 6, -2.5], + "cubes": [ + {"origin": [-2.5, 6, -2.5], "size": [5, 1, 0], "uv": [19, 17]} + ] + }, + { + "name": "spines_top_back", + "parent": "body", + "bind_pose_rotation": [-45, 0, 0], + "pivot": [0, 6, 2.5], + "cubes": [ + {"origin": [-2.5, 6, 2.5], "size": [5, 1, 0], "uv": [11, 17]} + ] + }, + { + "name": "spines_bottom_front", + "parent": "body", + "bind_pose_rotation": [-45, 0, 0], + "pivot": [0, 1, -2.5], + "cubes": [ + {"origin": [-2.5, 0, -2.5], "size": [5, 1, 0], "uv": [18, 20]} + ] + }, + { + "name": "spines_bottom_back", + "parent": "body", + "bind_pose_rotation": [45, 0, 0], + "pivot": [0, 1, 2.5], + "rotation": [45, 0, 0], + "cubes": [ + {"origin": [-2.5, 0, 2.5], "size": [5, 1, 0], "uv": [18, 20]} + ] + }, + { + "name": "spines_left_front", + "parent": "body", + "bind_pose_rotation": [0, 45, 0], + "pivot": [2.5, 0, -2.5], + "rotation": [0, 45, 0], + "cubes": [ + {"origin": [2.5, 1, -2.5], "size": [1, 5, 0], "uv": [1, 17]} + ] + }, + { + "name": "spines_left_back", + "parent": "body", + "bind_pose_rotation": [0, -45, 0], + "pivot": [2.5, 0, 2.5], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [2.5, 1, 2.5], "size": [1, 5, 0], "uv": [1, 17]} + ] + }, + { + "name": "spines_right_front", + "parent": "body", + "bind_pose_rotation": [0, -45, 0], + "pivot": [-2.5, 0, -2.5], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-3.5, 1, -2.5], "size": [1, 5, 0], "uv": [5, 17]} + ] + }, + { + "name": "spines_right_back", + "parent": "body", + "bind_pose_rotation": [0, 45, 0], + "pivot": [-2.5, 0, 2.5], + "rotation": [0, 45, 0], + "cubes": [ + {"origin": [-3.5, 1, 2.5], "size": [1, 5, 0], "uv": [9, 17]} + ] + } + ] + }, + "large": { + "visible_bounds_width": 0.5, + "visible_bounds_height": 0.5, + "texturewidth": 32, + "textureheight": 32, + "bones": [ + { + "name": "body", + "cubes": [{"origin": [-4, 0, -4], "size": [8, 8, 8], "uv": [0, 0]}] + }, + { + "name": "leftFin", + "parent": "body", + "pivot": [4, 7, 1], + "cubes": [ + {"origin": [4, 6, -2.9904], "size": [2, 1, 2], "uv": [24, 3]} + ] + }, + { + "name": "rightFin", + "parent": "body", + "pivot": [-4, 7, 1], + "cubes": [ + {"origin": [-5.9968, 6, -2.992], "size": [2, 1, 2], "uv": [24, 0]} + ] + }, + { + "name": "spines_top_front", + "parent": "body", + "pivot": [-4, 8, -4], + "bind_pose_rotation": [45, 0, 0], + "cubes": [ + {"origin": [-4, 8, -4], "size": [8, 1, 1], "uv": [14, 16]} + ] + }, + { + "name": "spines_top_mid", + "parent": "body", + "pivot": [0, 8, 0], + "cubes": [{"origin": [-4, 8, 0], "size": [8, 1, 1], "uv": [14, 16]}] + }, + { + "name": "spines_top_back", + "parent": "body", + "pivot": [0, 8, 4], + "bind_pose_rotation": [-45, 0, 0], + "cubes": [{"origin": [-4, 8, 4], "size": [8, 1, 1], "uv": [14, 16]}] + }, + { + "name": "spines_bottom_front", + "parent": "body", + "pivot": [0, 0, -4], + "bind_pose_rotation": [-45, 0, 0], + "cubes": [ + {"origin": [-4, -1, -4], "size": [8, 1, 1], "uv": [14, 19]} + ] + }, + { + "name": "spines_bottom_mid", + "parent": "body", + "pivot": [0, -1, 0], + "cubes": [ + {"origin": [-4, -1, 0], "size": [8, 1, 1], "uv": [14, 19]} + ] + }, + { + "name": "spines_bottom_back", + "parent": "body", + "pivot": [0, 0, 4], + "bind_pose_rotation": [45, 0, 0], + "cubes": [ + {"origin": [-4, -1, 4], "size": [8, 1, 1], "uv": [14, 19]} + ] + }, + { + "name": "spines_left_front", + "parent": "body", + "pivot": [4, 0, -4], + "bind_pose_rotation": [0, 45, 0], + "cubes": [{"origin": [4, 0, -4], "size": [1, 8, 1], "uv": [0, 16]}] + }, + { + "name": "spines_left_mid", + "parent": "body", + "pivot": [4, 0, 0], + "cubes": [ + { + "origin": [4, 0, 0], + "size": [1, 8, 1], + "uv": [4, 16], + "mirror": true + } + ] + }, + { + "name": "spines_left_back", + "parent": "body", + "pivot": [4, 0, 4], + "bind_pose_rotation": [0, -45, 0], + "cubes": [ + { + "origin": [4, 0, 4], + "size": [1, 8, 1], + "uv": [8, 16], + "mirror": true + } + ] + }, + { + "name": "spines_right_front", + "parent": "body", + "pivot": [-4, 0, -4], + "bind_pose_rotation": [0, -45, 0], + "cubes": [{"origin": [-5, 0, -4], "size": [1, 8, 1], "uv": [4, 16]}] + }, + { + "name": "spines_right_mid", + "parent": "body", + "pivot": [-4, 0, 0], + "cubes": [{"origin": [-5, 0, 0], "size": [1, 8, 1], "uv": [8, 16]}] + }, + { + "name": "spines_right_back", + "parent": "body", + "pivot": [-4, 0, 4], + "bind_pose_rotation": [0, 45, 0], + "cubes": [{"origin": [-5, 0, 4], "size": [1, 8, 1], "uv": [8, 16]}] + } + ] + } + }, + "render_controllers": [ + {"controller.render.pufferfish.small": "query.variant == 0"}, + {"controller.render.pufferfish.medium": "query.variant == 1"}, + {"controller.render.pufferfish.large": "query.variant == 2"} + ], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 46} + }, + "rabbit": { + "identifier": "minecraft:rabbit", + "min_engine_version": "1.8.0", + "materials": {"default": "rabbit"}, + "textures": { + "brown": "textures/entity/rabbit/brown", + "white": "textures/entity/rabbit/white", + "black": "textures/entity/rabbit/black", + "white_splotched": "textures/entity/rabbit/white_splotched", + "gold": "textures/entity/rabbit/gold", + "salt": "textures/entity/rabbit/salt", + "toast": "textures/entity/rabbit/toast" + }, + "geometry": { + "default": { + "visible_bounds_width": 1, + "visible_bounds_height": 1, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "rearFootLeft", + "pivot": [3, 6.5, 3.7], + "mirror": true, + "parent": "body", + "cubes": [{"origin": [2, 0, 0], "size": [2, 1, 7], "uv": [8, 24]}] + }, + { + "name": "rearFootRight", + "pivot": [-3, 6.5, 3.7], + "mirror": true, + "parent": "body", + "cubes": [{"origin": [-4, 0, 0], "size": [2, 1, 7], "uv": [26, 24]}] + }, + { + "name": "haunchLeft", + "pivot": [3, 6.5, 3.7], + "bind_pose_rotation": [-20, 0, 0], + "mirror": true, + "parent": "body", + "cubes": [ + {"origin": [2, 2.5, 3.7], "size": [2, 4, 5], "uv": [16, 15]} + ] + }, + { + "name": "haunchRight", + "pivot": [-3, 6.5, 3.7], + "bind_pose_rotation": [-20, 0, 0], + "mirror": true, + "parent": "body", + "cubes": [ + {"origin": [-4, 2.5, 3.7], "size": [2, 4, 5], "uv": [30, 15]} + ] + }, + { + "name": "body", + "pivot": [0, 5, 8], + "bind_pose_rotation": [-20, 0, 0], + "mirror": true, + "cubes": [{"origin": [-3, 2, -2], "size": [6, 5, 10], "uv": [0, 0]}] + }, + { + "name": "frontLegLeft", + "pivot": [3, 7, -1], + "bind_pose_rotation": [-10, 0, 0], + "mirror": true, + "parent": "body", + "cubes": [{"origin": [2, 0, -2], "size": [2, 7, 2], "uv": [8, 15]}] + }, + { + "name": "frontLegRight", + "pivot": [-3, 7, -1], + "bind_pose_rotation": [-10, 0, 0], + "mirror": true, + "parent": "body", + "cubes": [{"origin": [-4, 0, -2], "size": [2, 7, 2], "uv": [0, 15]}] + }, + { + "name": "head", + "pivot": [0, 8, -1], + "locators": {"lead": [0, 8, -1]}, + "mirror": true, + "parent": "body", + "cubes": [ + {"origin": [-2.5, 8, -6], "size": [5, 4, 5], "uv": [32, 0]} + ] + }, + { + "name": "earRight", + "pivot": [0, 8, -1], + "bind_pose_rotation": [0, -15, 0], + "mirror": true, + "parent": "body", + "cubes": [ + {"origin": [-2.5, 12, -2], "size": [2, 5, 1], "uv": [58, 0]} + ] + }, + { + "name": "earLeft", + "pivot": [0, 8, -1], + "bind_pose_rotation": [0, 15, 0], + "mirror": true, + "parent": "body", + "cubes": [ + {"origin": [0.5, 12, -2], "size": [2, 5, 1], "uv": [52, 0]} + ] + }, + { + "name": "tail", + "pivot": [0, 4, 7], + "bind_pose_rotation": [-20, 0, 0], + "mirror": true, + "parent": "body", + "cubes": [ + {"origin": [-1.5, 2.5, 7], "size": [3, 3, 2], "uv": [52, 6]} + ] + }, + { + "name": "nose", + "pivot": [0, 8, -1], + "mirror": true, + "parent": "body", + "cubes": [ + {"origin": [-0.5, 9.5, -6.5], "size": [1, 1, 1], "uv": [32, 9]} + ] + } + ] + } + }, + "render_controllers": ["controller.render.rabbit"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 24} + }, + "ravager": { + "identifier": "minecraft:ravager", + "textures": {"default": "textures/entity/illager/ravager"}, + "materials": {"default": "ravager"}, + "geometry": { + "default": { + "bones": [ + { + "pivot": [0, 19, 2], + "rotation": [90, 0, 0], + "cubes": [ + {"origin": [-7, 10, -2], "size": [14, 16, 20], "uv": [0, 55]}, + {"origin": [-6, -3, -2], "size": [12, 13, 18], "uv": [0, 91]} + ], + "name": "body" + }, + { + "pivot": [0, 15, -10], + "cubes": [ + {"origin": [-8, 13, -24], "size": [16, 3, 16], "uv": [0, 36]} + ], + "name": "mouth", + "parent": "head" + }, + { + "pivot": [0, 20, -20], + "cubes": [ + {"origin": [-5, 21, -10], "size": [10, 10, 18], "uv": [68, 73]} + ], + "name": "neck" + }, + { + "locators": {"stun": [0, 32, -15]}, + "pivot": [0, 28, -10], + "cubes": [ + {"origin": [-8, 14, -24], "size": [16, 20, 16], "uv": [0, 0]}, + {"origin": [-2, 12, -28], "size": [4, 8, 4], "uv": [0, 0]} + ], + "name": "head", + "parent": "neck" + }, + { + "pivot": [-12, 30, 22], + "cubes": [ + {"origin": [-12, 0, 17], "size": [8, 37, 8], "uv": [96, 0]} + ], + "name": "leg0" + }, + { + "pivot": [4, 30, 22], + "cubes": [ + {"origin": [4, 0, 17], "size": [8, 37, 8], "uv": [96, 0]} + ], + "name": "leg1" + }, + { + "pivot": [-4, 26, -4], + "cubes": [ + {"origin": [-12, 0, -8], "size": [8, 37, 8], "uv": [64, 0]} + ], + "name": "leg2" + }, + { + "pivot": [-4, 26, -4], + "cubes": [ + {"origin": [4, 0, -8], "size": [8, 37, 8], "uv": [64, 0]} + ], + "name": "leg3" + }, + { + "pivot": [-5, 27, -19], + "rotation": [60, 0, 0], + "cubes": [ + {"origin": [-10, 27, -20], "size": [2, 14, 4], "uv": [74, 55]}, + {"origin": [8, 27, -20], "size": [2, 14, 4], "uv": [74, 55]} + ], + "name": "horns", + "parent": "head" + } + ], + "texturewidth": 128, + "textureheight": 128, + "visible_bounds_width": 4, + "visible_bounds_height": 3.5, + "visible_bounds_offset": [0, 1.25, 0] + } + }, + "render_controllers": ["controller.render.ravager"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 57}, + "particle_effects": {"stun_particles": "minecraft:stunned_emitter"} + }, + "salmon": { + "identifier": "minecraft:salmon", + "materials": {"default": "salmon"}, + "textures": {"default": "textures/entity/fish/salmon"}, + "geometry": { + "default": { + "visible_bounds_width": 0.5, + "visible_bounds_height": 0.5, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 32, + "textureheight": 32, + "bones": [ + { + "name": "body_front", + "pivot": [0, 0, -4], + "cubes": [ + {"origin": [-1.5, 3.5, -4], "size": [3, 5, 8], "uv": [0, 0]} + ] + }, + { + "name": "body_back", + "parent": "body_front", + "pivot": [0, 0, 4], + "cubes": [ + {"origin": [-1.5, 3.5, 4], "size": [3, 5, 8], "uv": [0, 13]} + ] + }, + { + "name": "dorsal_front", + "parent": "body_front", + "pivot": [0, 5, 2], + "cubes": [{"origin": [0, 8.5, 2], "size": [0, 2, 2], "uv": [4, 2]}] + }, + { + "name": "dorsal_back", + "parent": "body_back", + "pivot": [0, 5, 4], + "cubes": [{"origin": [0, 8.5, 4], "size": [0, 2, 3], "uv": [2, 3]}] + }, + { + "name": "tailfin", + "parent": "body_back", + "pivot": [0, 0, 12], + "cubes": [ + {"origin": [0, 3.5, 12], "size": [0, 5, 6], "uv": [20, 10]} + ] + }, + { + "name": "head", + "parent": "body_front", + "pivot": [0, 3, -4], + "locators": {"lead": [0, 3, -4]}, + "cubes": [ + {"origin": [-1, 4.5, -7], "size": [2, 4, 3], "uv": [22, 0]} + ] + }, + { + "name": "leftFin", + "parent": "body_front", + "pivot": [1.5, 1, -4], + "rotation": [0, 0, 35], + "cubes": [ + { + "origin": [-0.50752, 3.86703, -4], + "size": [2, 0, 2], + "uv": [2, 0] + } + ] + }, + { + "name": "rightFin", + "parent": "body_front", + "pivot": [-1.5, 1, -4], + "rotation": [0, 0, -35], + "cubes": [ + { + "origin": [-1.49258, 3.86703, -4], + "size": [2, 0, 2], + "uv": [-2, 0] + } + ] + } + ] + } + }, + "render_controllers": ["controller.render.salmon"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 47} + }, + "shulker_bullet": { + "identifier": "minecraft:shulker_bullet", + "materials": {"default": "shulker_bullet"}, + "textures": {"default": "textures/entity/shulker/spark"}, + "geometry": { + "default": { + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "body", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-4, -4, -1], "size": [8, 8, 2], "uv": [0, 0]}, + {"origin": [-1, -4, -4], "size": [2, 8, 8], "uv": [0, 10]}, + {"origin": [-4, -1, -4], "size": [8, 2, 8], "uv": [20, 0]} + ] + } + ] + } + }, + "render_controllers": ["controller.render.shulker_bullet"] + }, + "silverfish": { + "identifier": "minecraft:silverfish", + "materials": {"default": "silverfish", "body_layer": "silverfish_layers"}, + "textures": {"default": "textures/entity/silverfish"}, + "geometry": { + "default": { + "visible_bounds_width": 1.5, + "visible_bounds_height": 1, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "bodyPart_0", + "parent": "bodyPart_2", + "pivot": [0, 2, -3.5], + "cubes": [ + {"origin": [-1.5, 0, -4.5], "size": [3, 2, 2], "uv": [0, 0]} + ] + }, + { + "name": "bodyPart_1", + "parent": "bodyPart_2", + "pivot": [0, 3, -1.5], + "cubes": [ + {"origin": [-2, 0, -2.5], "size": [4, 3, 2], "uv": [0, 4]} + ] + }, + { + "name": "bodyPart_2", + "pivot": [0, 4, 1], + "cubes": [ + {"origin": [-3, 0, -0.5], "size": [6, 4, 3], "uv": [0, 9]} + ] + }, + { + "name": "bodyPart_3", + "parent": "bodyPart_2", + "pivot": [0, 3, 4], + "cubes": [ + {"origin": [-1.5, 0, 2.5], "size": [3, 3, 3], "uv": [0, 16]} + ] + }, + { + "name": "bodyPart_4", + "parent": "bodyPart_2", + "pivot": [0, 2, 7], + "cubes": [ + {"origin": [-1, 0, 5.5], "size": [2, 2, 3], "uv": [0, 22]} + ] + }, + { + "name": "bodyPart_5", + "parent": "bodyPart_2", + "pivot": [0, 1, 9.5], + "cubes": [ + {"origin": [-1, 0, 8.5], "size": [2, 1, 2], "uv": [11, 0]} + ] + }, + { + "name": "bodyPart_6", + "parent": "bodyPart_2", + "pivot": [0, 1, 11.5], + "cubes": [ + {"origin": [-0.5, 0, 10.5], "size": [1, 1, 2], "uv": [13, 4]} + ] + }, + { + "name": "bodyLayer_0", + "parent": "bodyPart_2", + "pivot": [0, 8, 1], + "cubes": [ + {"origin": [-5, 0, -0.5], "size": [10, 8, 3], "uv": [20, 0]} + ] + }, + { + "name": "bodyLayer_1", + "parent": "bodyPart_4", + "pivot": [0, 4, 7], + "cubes": [ + {"origin": [-3, 0, 5.5], "size": [6, 4, 3], "uv": [20, 11]} + ] + }, + { + "name": "bodyLayer_2", + "parent": "bodyPart_1", + "pivot": [0, 5, -1.5], + "cubes": [ + {"origin": [-3, 0, -3], "size": [6, 5, 2], "uv": [20, 18]} + ] + } + ] + } + }, + "render_controllers": ["controller.render.silverfish"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 8} + }, + "skeleton": { + "identifier": "minecraft:skeleton", + "min_engine_version": "1.8.0", + "materials": {"default": "skeleton"}, + "textures": {"default": "textures/entity/skeleton/skeleton"}, + "geometry": { + "default": { + "texturewidth": 64, + "textureheight": 32, + "visible_bounds_width": 2, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 1, 0], + "bones": [ + { + "name": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} + ], + "parent": "waist" + }, + {"name": "waist", "pivot": [0, 12, 0]}, + { + "name": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]} + ], + "parent": "body" + }, + { + "name": "hat", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-4, 24, -4], + "size": [8, 8, 8], + "uv": [32, 0], + "inflate": 0.5 + } + ], + "neverRender": true, + "parent": "head" + }, + { + "name": "rightArm", + "pivot": [-5, 22, 0], + "cubes": [ + {"origin": [-6, 12, -1], "size": [2, 12, 2], "uv": [40, 16]} + ], + "parent": "body" + }, + { + "name": "rightItem", + "pivot": [-1, -45, -5], + "neverRender": true, + "parent": "rightArm" + }, + { + "name": "leftArm", + "pivot": [5, 22, 0], + "cubes": [ + {"origin": [4, 12, -1], "size": [2, 12, 2], "uv": [40, 16]} + ], + "mirror": true, + "parent": "body" + }, + { + "name": "leftItem", + "pivot": [1, -45, -5], + "neverRender": true, + "parent": "leftArm" + }, + { + "name": "rightLeg", + "pivot": [-2, 12, 0], + "cubes": [ + {"origin": [-3, 0, -1], "size": [2, 12, 2], "uv": [0, 16]} + ], + "parent": "body" + }, + { + "name": "leftLeg", + "pivot": [2, 12, 0], + "cubes": [ + {"origin": [1, 0, -1], "size": [2, 12, 2], "uv": [0, 16]} + ], + "mirror": true, + "parent": "body" + } + ] + } + }, + "spawn_egg": {"texture": "spawn_egg", "texture_index": 9}, + "render_controllers": ["controller.render.skeleton"], + "enable_attachables": true + }, + "skeleton_horse": { + "identifier": "minecraft:skeleton_horse", + "textures": { + "base_brown": "textures/entity/horse/horse_brown", + "base_white": "textures/entity/horse/horse_white", + "base_chestnut": "textures/entity/horse/horse_chestnut", + "base_creamy": "textures/entity/horse/horse_creamy", + "base_black": "textures/entity/horse/horse_black", + "base_gray": "textures/entity/horse/horse_gray", + "base_darkbrown": "textures/entity/horse/horse_darkbrown", + "markings_none": "textures/entity/horse/horse_markings_none", + "markings_white": "textures/entity/horse/horse_markings_white", + "markings_whitefield": "textures/entity/horse/horse_markings_whitefield", + "markings_whitedots": "textures/entity/horse/horse_markings_whitedots", + "markings_blackdots": "textures/entity/horse/horse_markings_blackdots", + "mule": "textures/entity/horse/mule", + "donkey": "textures/entity/horse/donkey", + "skeleton": "textures/entity/horse/horse_skeleton", + "zombie": "textures/entity/horse/horse_zombie", + "armor_none": "textures/entity/horse/armor/horse_armor_none", + "armor_leather": "textures/entity/horse/armor/horse_armor_leather", + "armor_iron": "textures/entity/horse/armor/horse_armor_iron", + "armor_gold": "textures/entity/horse/armor/horse_armor_gold", + "armor_diamond": "textures/entity/horse/armor/horse_armor_diamond" + }, + "geometry": { + "default": { + "visible_bounds_width": 2, + "visible_bounds_height": 3, + "visible_bounds_offset": [0, 1, 0], + "texturewidth": 128, + "textureheight": 128, + "bones": [ + { + "name": "Body", + "pivot": [0, 13, 9], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-5, 11, -10], "size": [10, 10, 24], "uv": [0, 34]} + ] + }, + { + "name": "TailA", + "pivot": [0, 21, 14], + "rotation": [-65, 0, 0], + "cubes": [ + {"origin": [-1, 20, 14], "size": [2, 2, 3], "uv": [44, 0]} + ] + }, + { + "name": "TailB", + "pivot": [0, 21, 14], + "rotation": [-65, 0, 0], + "cubes": [ + {"origin": [-1.5, 19, 17], "size": [3, 4, 7], "uv": [38, 7]} + ] + }, + { + "name": "TailC", + "pivot": [0, 21, 14], + "rotation": [-80.34, 0, 0], + "cubes": [ + {"origin": [-1.5, 21.5, 23], "size": [3, 4, 7], "uv": [24, 3]} + ] + }, + { + "name": "Leg1A", + "pivot": [4, 15, 11], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [1.5, 8, 8.5], "size": [4, 9, 5], "uv": [78, 29]} + ] + }, + { + "name": "Leg1B", + "pivot": [4, 8, 11], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [2, 3, 9.5], "size": [3, 5, 3], "uv": [78, 43]} + ] + }, + { + "name": "Leg1C", + "pivot": [4, 8, 11], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [1.5, -0.1, 9], "size": [4, 3, 4], "uv": [78, 51]} + ] + }, + { + "name": "Leg2A", + "pivot": [-4, 15, 11], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-5.5, 8, 8.5], "size": [4, 9, 5], "uv": [96, 29]} + ] + }, + { + "name": "Leg2B", + "pivot": [-4, 8, 11], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-5, 3, 9.5], "size": [3, 5, 3], "uv": [96, 43]} + ] + }, + { + "name": "Leg2C", + "pivot": [-4, 8, 11], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-5.5, -0.1, 9], "size": [4, 3, 4], "uv": [96, 51]} + ] + }, + { + "name": "Leg3A", + "pivot": [4, 15, -8], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [2.1, 8, -10.1], "size": [3, 8, 4], "uv": [44, 29]} + ] + }, + { + "name": "Leg3B", + "pivot": [4, 8, -8], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [2.1, 3, -9.6], "size": [3, 5, 3], "uv": [44, 41]} + ] + }, + { + "name": "Leg3C", + "pivot": [4, 8, -8], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [1.6, -0.1, -10.1], "size": [4, 3, 4], "uv": [44, 51]} + ] + }, + { + "name": "Leg4A", + "pivot": [-4, 15, -8], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-5.1, 8, -10.1], "size": [3, 8, 4], "uv": [60, 29]} + ] + }, + { + "name": "Leg4B", + "pivot": [-4, 8, -8], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-5.1, 3, -9.6], "size": [3, 5, 3], "uv": [60, 41]} + ] + }, + { + "name": "Leg4C", + "pivot": [-4, 8, -8], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-5.6, -0.1, -10.1], "size": [4, 3, 4], "uv": [60, 51]} + ] + }, + { + "name": "Head", + "pivot": [0, 20, -10], + "rotation": [30, 0, 0], + "cubes": [ + {"origin": [-2.5, 25, -11.5], "size": [5, 5, 7], "uv": [0, 0]} + ] + }, + { + "name": "UMouth", + "pivot": [0, 20.05, -10], + "rotation": [30, 0, 0], + "cubes": [ + {"origin": [-2, 27.05, -17], "size": [4, 3, 6], "uv": [24, 18]} + ] + }, + { + "name": "LMouth", + "pivot": [0, 20, -10], + "rotation": [30, 0, 0], + "cubes": [ + {"origin": [-2, 25, -16.5], "size": [4, 2, 5], "uv": [24, 27]} + ] + }, + { + "name": "Ear1", + "pivot": [0, 20, -10], + "rotation": [30, 0, 0], + "cubes": [ + {"origin": [0.45, 29, -6], "size": [2, 3, 1], "uv": [0, 0]} + ] + }, + { + "name": "Ear2", + "pivot": [0, 20, -10], + "rotation": [30, 0, 0], + "cubes": [ + {"origin": [-2.45, 29, -6], "size": [2, 3, 1], "uv": [0, 0]} + ] + }, + { + "name": "MuleEarL", + "pivot": [0, 20, -10], + "rotation": [30, 0, 15], + "cubes": [ + {"origin": [-2, 29, -6], "size": [2, 7, 1], "uv": [0, 12]} + ] + }, + { + "name": "MuleEarR", + "pivot": [0, 20, -10], + "rotation": [30, 0, -15], + "cubes": [{"origin": [0, 29, -6], "size": [2, 7, 1], "uv": [0, 12]}] + }, + { + "name": "Neck", + "pivot": [0, 20, -10], + "rotation": [30, 0, 0], + "cubes": [ + {"origin": [-2.05, 15.8, -12], "size": [4, 14, 8], "uv": [0, 12]} + ] + }, + { + "name": "Bag1", + "pivot": [-7.5, 21, 10], + "rotation": [0, 90, 0], + "cubes": [ + {"origin": [-10.5, 13, 10], "size": [8, 8, 3], "uv": [0, 34]} + ] + }, + { + "name": "Bag2", + "pivot": [4.5, 21, 10], + "rotation": [0, 90, 0], + "cubes": [ + {"origin": [1.5, 13, 10], "size": [8, 8, 3], "uv": [0, 47]} + ] + }, + { + "name": "Saddle", + "pivot": [0, 22, 2], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-5, 21, -1], "size": [10, 1, 8], "uv": [80, 0]} + ] + }, + { + "name": "SaddleB", + "pivot": [0, 22, 2], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-1.5, 22, -1], "size": [3, 1, 2], "uv": [106, 9]} + ] + }, + { + "name": "SaddleC", + "pivot": [0, 22, 2], + "rotation": [0, 0, 0], + "cubes": [{"origin": [-4, 22, 5], "size": [8, 1, 2], "uv": [80, 9]}] + }, + { + "name": "SaddleL2", + "pivot": [5, 21, 2], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [4.5, 13, 1], "size": [1, 2, 2], "uv": [74, 0]} + ] + }, + { + "name": "SaddleL", + "pivot": [5, 21, 2], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [4.5, 15, 1.5], "size": [1, 6, 1], "uv": [70, 0]} + ] + }, + { + "name": "SaddleR2", + "pivot": [-5, 21, 2], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-5.5, 13, 1], "size": [1, 2, 2], "uv": [74, 4]} + ] + }, + { + "name": "SaddleR", + "pivot": [-5, 21, 2], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-5.5, 15, 1.5], "size": [1, 6, 1], "uv": [80, 0]} + ] + }, + { + "name": "SaddleMouthL", + "pivot": [0, 20, -10], + "rotation": [30, 0, 0], + "cubes": [ + {"origin": [1.5, 26, -14], "size": [1, 2, 2], "uv": [74, 13]} + ] + }, + { + "name": "SaddleMouthR", + "pivot": [0, 20, -10], + "rotation": [30, 0, 0], + "cubes": [ + {"origin": [-2.5, 26, -14], "size": [1, 2, 2], "uv": [74, 13]} + ] + }, + { + "name": "SaddleMouthLine", + "pivot": [0, 20, -10], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [2.6, 23, -16], "size": [0, 3, 16], "uv": [44, 10]} + ] + }, + { + "name": "SaddleMouthLineR", + "pivot": [0, 20, -10], + "rotation": [0, 0, 0], + "cubes": [ + {"origin": [-2.6, 23, -16], "size": [0, 3, 16], "uv": [44, 5]} + ] + }, + { + "name": "Mane", + "pivot": [0, 20, -10], + "rotation": [30, 0, 0], + "cubes": [ + {"origin": [-1, 15.5, -5], "size": [2, 16, 4], "uv": [58, 0]} + ] + }, + { + "name": "HeadSaddle", + "pivot": [0, 20, -10], + "rotation": [30, 0, 0], + "cubes": [ + { + "origin": [-2.5, 25.1, -17], + "size": [5, 5, 12], + "uv": [80, 12], + "inflate": 0.05 + } + ] + } + ] + } + }, + "spawn_egg": {"texture": "spawn_egg", "texture_index": 32} + }, + "slime": { + "identifier": "minecraft:slime", + "materials": {"default": "slime", "outer": "slime_outer"}, + "textures": {"default": "textures/entity/slime/slime"}, + "geometry": { + "default": { + "visible_bounds_width": 5, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 1, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "cube", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-3, 1, -3], "size": [6, 6, 6], "uv": [0, 16]}] + }, + { + "name": "eye0", + "parent": "cube", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-3.3, 4, -3.5], "size": [2, 2, 2], "uv": [32, 0]} + ] + }, + { + "name": "eye1", + "parent": "cube", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [1.3, 4, -3.5], "size": [2, 2, 2], "uv": [32, 4]} + ] + }, + { + "name": "mouth", + "parent": "cube", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [0, 2, -3.5], "size": [1, 1, 1], "uv": [32, 8]} + ] + } + ] + }, + "armor": { + "visible_bounds_width": 1, + "visible_bounds_height": 1, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "cube", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-4, 0, -4], "size": [8, 8, 8], "uv": [0, 0]}] + }, + { + "name": "eye0", + "parent": "cube", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-3.3, 4, -3.5], "size": [2, 2, 2], "uv": [32, 0]} + ] + }, + { + "name": "eye1", + "parent": "cube", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [1.3, 4, -3.5], "size": [2, 2, 2], "uv": [32, 4]} + ] + }, + { + "name": "mouth", + "parent": "cube", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [0, 2, -3.5], "size": [1, 1, 1], "uv": [32, 8]} + ] + } + ] + } + }, + "render_controllers": [ + "controller.render.slime", + "controller.render.slime_armor" + ], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 10} + }, + "small_fireball": { + "identifier": "minecraft:small_fireball", + "materials": {"default": "fireball"}, + "textures": {"default": "textures/items/fire_charge"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, -4, 0], + "size": [16, 16, 0], + "uv": {"south": {"uv": [0, 0]}} + } + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + } + }, + "render_controllers": ["controller.render.fireball"] + }, + "snow_golem": { + "identifier": "minecraft:snow_golem", + "min_engine_version": "1.8.0", + "materials": {"default": "snow_golem", "head": "snow_golem_pumpkin"}, + "textures": {"default": "textures/entity/snow_golem"}, + "geometry": { + "default": { + "visible_bounds_width": 1, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 1, 0], + "bones": [ + { + "name": "head", + "parent": "piece1", + "pivot": [0, 20, 0], + "locators": {"lead": [0, 20, 0]}, + "cubes": [ + { + "origin": [-4, 20, -4], + "size": [8, 8, 8], + "uv": [0, 0], + "inflate": -0.5 + } + ] + }, + { + "name": "arm1", + "parent": "piece1", + "pivot": [0, 18, 0], + "bind_pose_rotation": [0, 0, 57.3], + "cubes": [ + { + "origin": [1, 20, -1], + "size": [12, 2, 2], + "uv": [32, 0], + "inflate": -0.5 + } + ] + }, + { + "name": "arm2", + "parent": "piece1", + "pivot": [0, 18, 0], + "bind_pose_rotation": [0, 180, -57.3], + "cubes": [ + { + "origin": [1, 20, -1], + "size": [12, 2, 2], + "uv": [32, 0], + "inflate": -0.5 + } + ] + }, + { + "name": "piece1", + "parent": "piece2", + "pivot": [0, 11, 0], + "cubes": [ + { + "origin": [-5, 11, -5], + "size": [10, 10, 10], + "uv": [0, 16], + "inflate": -0.5 + } + ] + }, + { + "name": "piece2", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-6, 0, -6], + "size": [12, 12, 12], + "uv": [0, 36], + "inflate": -0.5 + } + ] + } + ] + } + }, + "render_controllers": ["controller.render.snowgolem"] + }, + "snowball": { + "identifier": "minecraft:snowball", + "materials": {"default": "snowball"}, + "textures": {"default": "textures/items/snowball"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, -8, 0], + "size": [16, 16, 0], + "uv": [0, 0], + "rotation": [0, 0, 0] + } + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + } + }, + "render_controllers": ["controller.render.item_sprite"] + }, + "potion": { + "identifier": "minecraft:splash_potion", + "materials": {"default": "splash_potion_enchanted"}, + "textures": { + "moveSlowdown": "textures/items/potion_bottle_splash_moveSlowdown", + "moveSpeed": "textures/items/potion_bottle_splash_moveSpeed", + "digSlowdown": "textures/items/potion_bottle_splash_digSlowdown", + "digSpeed": "textures/items/potion_bottle_splash_digSpeed", + "damageBoost": "textures/items/potion_bottle_splash_damageBoost", + "heal": "textures/items/potion_bottle_splash_heal", + "harm": "textures/items/potion_bottle_splash_harm", + "jump": "textures/items/potion_bottle_splash_jump", + "confusion": "textures/items/potion_bottle_splash_confusion", + "regeneration": "textures/items/potion_bottle_splash_regeneration", + "resistance": "textures/items/potion_bottle_splash_resistance", + "fireResistance": "textures/items/potion_bottle_splash_fireResistance", + "waterBreathing": "textures/items/potion_bottle_splash_waterBreathing", + "invisibility": "textures/items/potion_bottle_splash_invisibility", + "blindness": "textures/items/potion_bottle_splash_blindness", + "nightVision": "textures/items/potion_bottle_splash_nightVision", + "hunger": "textures/items/potion_bottle_splash_hunger", + "weakness": "textures/items/potion_bottle_splash_weakness", + "poison": "textures/items/potion_bottle_splash_poison", + "wither": "textures/items/potion_bottle_splash_wither", + "healthBoost": "textures/items/potion_bottle_splash_healthBoost", + "absorption": "textures/items/potion_bottle_splash_absorption", + "saturation": "textures/items/potion_bottle_splash_saturation", + "levitation": "textures/items/potion_bottle_splash_levitation", + "turtleMaster": "textures/items/potion_bottle_splash_turtleMaster", + "slowFall": "textures/items/potion_bottle_splash_slowFall", + "default": "textures/items/potion_bottle_splash", + "enchanted": "textures/misc/enchanted_item_glint" + }, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, -8, 0], + "size": [16, 16, 0], + "uv": [0, 0], + "rotation": [0, 0, 0] + } + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + } + }, + "render_controllers": ["controller.render.splash_potion"] + }, + "squid": { + "identifier": "minecraft:squid", + "materials": {"default": "squid"}, + "textures": {"default": "textures/entity/squid"}, + "geometry": { + "default": { + "visible_bounds_width": 3, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 0.5, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "body", + "cubes": [ + {"origin": [-6, -8, -6], "size": [12, 16, 12], "uv": [0, 0]} + ] + }, + { + "name": "tentacle1", + "parent": "body", + "pivot": [5, -7, 0], + "cubes": [ + {"origin": [4, -25, -1], "size": [2, 18, 2], "uv": [48, 0]} + ], + "rotation": [0, 90, 0] + }, + { + "name": "tentacle2", + "parent": "body", + "pivot": [3.5, -7, 3.5], + "cubes": [ + {"origin": [2.5, -25, 2.5], "size": [2, 18, 2], "uv": [48, 0]} + ], + "rotation": [0, 45, 0] + }, + { + "name": "tentacle3", + "parent": "body", + "pivot": [0, -7, 5], + "cubes": [ + {"origin": [-1, -25, 4], "size": [2, 18, 2], "uv": [48, 0]} + ], + "rotation": [0, 0, 0] + }, + { + "name": "tentacle4", + "parent": "body", + "pivot": [-3.5, -7, 3.5], + "cubes": [ + {"origin": [-4.5, -25, 2.5], "size": [2, 18, 2], "uv": [48, 0]} + ], + "rotation": [0, -45, 0] + }, + { + "name": "tentacle5", + "parent": "body", + "pivot": [-5, -7, 0], + "cubes": [ + {"origin": [-6, -25, -1], "size": [2, 18, 2], "uv": [48, 0]} + ], + "rotation": [0, -90, 0] + }, + { + "name": "tentacle6", + "parent": "body", + "pivot": [-3.5, -7, -3.5], + "cubes": [ + {"origin": [-4.5, -25, -4.5], "size": [2, 18, 2], "uv": [48, 0]} + ], + "rotation": [0, -135, 0] + }, + { + "name": "tentacle7", + "parent": "body", + "pivot": [0, -7, -5], + "cubes": [ + {"origin": [-1, -25, -6], "size": [2, 18, 2], "uv": [48, 0]} + ], + "rotation": [0, -180, 0] + }, + { + "name": "tentacle8", + "parent": "body", + "pivot": [3.5, -7, -3.5], + "cubes": [ + {"origin": [2.5, -25, -4.5], "size": [2, 18, 2], "uv": [48, 0]} + ], + "rotation": [0, -225, 0] + } + ] + } + }, + "render_controllers": ["controller.render.squid"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 15} + }, + "stray": { + "identifier": "minecraft:stray", + "min_engine_version": "1.8.0", + "materials": {"default": "stray", "overlay": "stray_clothes"}, + "textures": { + "default": "textures/entity/skeleton/stray", + "overlay": "textures/entity/skeleton/stray_overlay" + }, + "geometry": { + "default": { + "visible_bounds_width": 1.5, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 1, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} + ], + "parent": "waist" + }, + {"name": "waist", "pivot": [0, 12, 0]}, + { + "name": "head", + "pivot": [0, 24, 0], + "locators": {"lead": [0, 24, 0]}, + "cubes": [ + {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]} + ], + "parent": "body" + }, + { + "name": "hat", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-4, 24, -4], + "size": [8, 8, 8], + "uv": [32, 0], + "inflate": 0.5 + } + ], + "neverRender": true, + "parent": "head" + }, + { + "name": "rightArm", + "pivot": [-5, 22, 0], + "cubes": [ + {"origin": [-6, 12, -1], "size": [2, 12, 2], "uv": [40, 16]} + ], + "parent": "body" + }, + { + "name": "rightItem", + "pivot": [-1, -45, -5], + "neverRender": true, + "parent": "rightArm" + }, + { + "name": "leftArm", + "pivot": [5, 22, 0], + "cubes": [ + {"origin": [4, 12, -1], "size": [2, 12, 2], "uv": [40, 16]} + ], + "mirror": true, + "parent": "body" + }, + { + "name": "leftItem", + "pivot": [1, -45, -5], + "neverRender": true, + "parent": "leftArm" + }, + { + "name": "rightLeg", + "pivot": [-2, 12, 0], + "cubes": [ + {"origin": [-3, 0, -1], "size": [2, 12, 2], "uv": [0, 16]} + ], + "parent": "body" + }, + { + "name": "leftLeg", + "pivot": [2, 12, 0], + "cubes": [ + {"origin": [1, 0, -1], "size": [2, 12, 2], "uv": [0, 16]} + ], + "mirror": true, + "parent": "body" + } + ] + }, + "overlay": { + "visible_bounds_width": 2, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 1, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "body", + "parent": "waist", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} + ], + "inflate": 0.25 + }, + {"name": "waist", "neverRender": true, "pivot": [0, 12, 0]}, + { + "name": "head", + "parent": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]} + ], + "inflate": 0.25 + }, + { + "name": "hat", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-4, 24, -4], + "size": [8, 8, 8], + "uv": [32, 0], + "inflate": 0.5 + } + ], + "neverRender": true + }, + { + "name": "rightArm", + "parent": "body", + "pivot": [-5, 22, 0], + "cubes": [ + {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} + ], + "inflate": 0.25 + }, + { + "name": "rightItem", + "parent": "rightArm", + "pivot": [-6, 15, 1], + "neverRender": true + }, + { + "name": "leftArm", + "parent": "body", + "pivot": [5, 22, 0], + "cubes": [ + {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} + ], + "mirror": true, + "inflate": 0.25 + }, + { + "name": "rightLeg", + "parent": "body", + "pivot": [-1.9, 12, 0], + "cubes": [ + {"origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} + ], + "inflate": 0.25 + }, + { + "name": "leftLeg", + "parent": "body", + "pivot": [1.9, 12, 0], + "cubes": [ + {"origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} + ], + "inflate": 0.25, + "mirror": true + } + ] + } + }, + "spawn_egg": {"texture": "spawn_egg", "texture_index": 27}, + "render_controllers": [ + "controller.render.stray_clothes", + "controller.render.stray" + ], + "enable_attachables": true + }, + "strider": { + "identifier": "minecraft:strider", + "materials": {"default": "strider"}, + "textures": { + "default": "textures/entity/strider/strider", + "saddled": "textures/entity/strider/strider", + "suffocated": "textures/entity/strider/strider_cold", + "suffocated_saddled": "textures/entity/strider/strider_cold" + }, + "geometry": { + "default": { + "bones": [ + { + "name": "right_leg", + "pivot": [-4, 16, 0], + "cubes": [ + {"origin": [-6, 0, -2], "size": [4, 16, 4], "uv": [0, 32]} + ] + }, + { + "name": "left_leg", + "pivot": [4, 16, 0], + "cubes": [{"origin": [2, 0, -2], "size": [4, 16, 4], "uv": [0, 55]}] + }, + { + "name": "body", + "pivot": [0, 16, 0], + "cubes": [ + {"origin": [-8, 14, -8], "size": [16, 14, 16], "uv": [0, 0]} + ], + "locators": {"lead": [0, 15, -1]} + }, + { + "name": "bristle5", + "parent": "body", + "pivot": [8, 19, 0], + "cubes": [ + { + "origin": [8, 19, -8], + "size": [12, 0, 16], + "pivot": [8, 19, 0], + "rotation": [0, 0, 70], + "uv": [16, 65] + } + ] + }, + { + "name": "bristle4", + "parent": "body", + "pivot": [8, 24, 0], + "cubes": [ + { + "origin": [8, 24, -8], + "size": [12, 0, 16], + "pivot": [8, 24, 0], + "rotation": [0, 0, 65], + "uv": [16, 49] + } + ] + }, + { + "name": "bristle3", + "parent": "body", + "pivot": [8, 28, 0], + "cubes": [ + { + "origin": [8, 28, -8], + "size": [12, 0, 16], + "pivot": [8, 28, 0], + "rotation": [0, 0, 50], + "uv": [16, 33] + } + ] + }, + { + "name": "bristle2", + "parent": "body", + "pivot": [-8, 28, 0], + "cubes": [ + { + "origin": [-20, 28, -8], + "size": [12, 0, 16], + "pivot": [-8, 28, 0], + "rotation": [0, 0, -50], + "uv": [16, 33], + "mirror": true + } + ] + }, + { + "name": "bristle1", + "parent": "body", + "pivot": [-8, 24, 0], + "cubes": [ + { + "origin": [-20, 24, -8], + "size": [12, 0, 16], + "pivot": [-8, 24, 0], + "rotation": [0, 0, -65], + "uv": [16, 49], + "mirror": true + } + ] + }, + { + "name": "bristle0", + "parent": "body", + "pivot": [-8, 19, 0], + "cubes": [ + { + "origin": [-20, 19, -8], + "size": [12, 0, 16], + "pivot": [-8, 19, 0], + "rotation": [0, 0, -70], + "uv": [16, 65], + "mirror": true + } + ] + } + ], + "visible_bounds_width": 3, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 1, 0], + "texturewidth": 64, + "textureheight": 128 + } + }, + "spawn_egg": {"base_color": "#9c3436", "overlay_color": "#4d494d"}, + "render_controllers": ["controller.render.strider"] + }, + "text_display": { + "identifier": "minecraft:text_display", + "geometry": {} + }, + "trident": { + "identifier": "minecraft:thrown_trident", + "textures": { + "default": "textures/entity/trident", + "loyalty_rope": "textures/entity/lead_knot" + }, + "geometry": { + "default": { + "texturewidth": 32, + "textureheight": 32, + "bones": [ + { + "name": "pole", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-0.5, -3, -0.5], + "size": [1, 31, 1], + "inflate": 0.01, + "uv": [0, 0] + }, + {"origin": [-1.5, 22, -0.5], "size": [3, 2, 1], "uv": [4, 0]}, + {"origin": [-2.5, 23, -0.5], "size": [1, 4, 1], "uv": [4, 3]}, + {"origin": [1.5, 23, -0.5], "size": [1, 4, 1], "uv": [4, 3]} + ] + } + ] + } + } + }, + "tnt_minecart": { + "identifier": "minecraft:tnt_minecart", + "min_engine_version": "1.8.0", + "materials": {"default": "minecart"}, + "textures": {"default": "textures/entity/minecart"}, + "geometry": { + "default": { + "bones": [ + { + "name": "bottom", + "pivot": [0, 6, 0], + "cubes": [ + { + "origin": [-10, -6.5, -1], + "size": [20, 16, 2], + "rotation": [90, 0, 0], + "uv": [0, 10] + } + ] + }, + { + "name": "back", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-17, 2.5, -1], + "size": [16, 8, 2], + "rotation": [0, 270, 0], + "uv": [0, 0] + } + ], + "parent": "bottom" + }, + { + "name": "front", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [1, 2.5, -1], + "size": [16, 8, 2], + "rotation": [0, 90, 0], + "uv": [0, 0] + } + ], + "parent": "bottom" + }, + { + "name": "right", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-8, 2.5, -8], + "size": [16, 8, 2], + "rotation": [0, 180, 0], + "uv": [0, 0] + } + ], + "parent": "bottom" + }, + { + "name": "left", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-8, 2.5, 6], "size": [16, 8, 2], "uv": [0, 0]} + ], + "parent": "bottom" + } + ], + "texturewidth": 64, + "textureheight": 32 + } + }, + "render_controllers": ["controller.render.minecart"] + }, + "tropical_fish": { + "identifier": "minecraft:tropicalfish", + "materials": {"default": "tropicalfish"}, + "textures": { + "typeA": "textures/entity/fish/tropical_a", + "typeB": "textures/entity/fish/tropical_b", + "aPattern1": "textures/entity/fish/tropical_a_pattern_1", + "aPattern2": "textures/entity/fish/tropical_a_pattern_2", + "aPattern3": "textures/entity/fish/tropical_a_pattern_3", + "aPattern4": "textures/entity/fish/tropical_a_pattern_4", + "aPattern5": "textures/entity/fish/tropical_a_pattern_5", + "aPattern6": "textures/entity/fish/tropical_a_pattern_6", + "bPattern1": "textures/entity/fish/tropical_b_pattern_1", + "bPattern2": "textures/entity/fish/tropical_b_pattern_2", + "bPattern3": "textures/entity/fish/tropical_b_pattern_3", + "bPattern4": "textures/entity/fish/tropical_b_pattern_4", + "bPattern5": "textures/entity/fish/tropical_b_pattern_5", + "bPattern6": "textures/entity/fish/tropical_b_pattern_6" + }, + "geometry": { + "typeA": { + "visible_bounds_width": 0.5, + "visible_bounds_height": 0.5, + "bones": [ + { + "pivot": [-0.5, 0, 0], + "cubes": [ + {"origin": [-1, 0, -3], "size": [2, 3, 6], "uv": [0, 0]}, + {"origin": [0, 3, -2.9992], "size": [0, 4, 6], "uv": [10, -6]} + ], + "name": "body" + }, + { + "pivot": [0, 0, 3], + "cubes": [{"origin": [0, 0, 3], "size": [0, 3, 4], "uv": [24, -4]}], + "name": "tailfin", + "parent": "body" + }, + { + "pivot": [0.5, 0, 1], + "bind_pose_rotation": [0, -35, 0], + "cubes": [ + {"origin": [0.336, 0, -0.10594], "size": [2, 2, 0], "uv": [2, 12]} + ], + "name": "leftFin", + "parent": "body" + }, + { + "pivot": [-0.5, 0, 1], + "bind_pose_rotation": [0, 35, 0], + "cubes": [ + { + "origin": [-2.336, 0, -0.10594], + "size": [2, 2, 0], + "uv": [2, 16] + } + ], + "name": "rightFin", + "parent": "body" + } + ], + "texturewidth": 32, + "textureheight": 32 + }, + "typeB": { + "visible_bounds_width": 0.5, + "visible_bounds_height": 0.5, + "bones": [ + { + "pivot": [-0.5, 0, 0], + "cubes": [ + {"origin": [-1, 0, -0.0008], "size": [2, 6, 6], "uv": [0, 20]}, + {"origin": [0, -5, -0.0008], "size": [0, 5, 6], "uv": [20, 21]}, + {"origin": [0, 6, -0.0008], "size": [0, 5, 6], "uv": [20, 10]} + ], + "name": "body" + }, + { + "pivot": [0, 0, 6], + "cubes": [ + {"origin": [0, 0.0008, 6], "size": [0, 6, 5], "uv": [21, 16]} + ], + "name": "tailfin", + "parent": "body" + }, + { + "pivot": [0.5, 0, 1], + "bind_pose_rotation": [0, -35, 0], + "cubes": [ + { + "origin": [2.05673, 0, 2.35152], + "size": [2, 2, 0], + "uv": [2, 12] + } + ], + "name": "leftFin", + "parent": "body" + }, + { + "pivot": [-0.5, 0, 1], + "bind_pose_rotation": [0, 35, 0], + "cubes": [ + { + "origin": [-4.05673, 0, 2.35152], + "size": [2, 2, 0], + "uv": [2, 16] + } + ], + "name": "rightFin", + "parent": "body" + } + ], + "texturewidth": 32, + "textureheight": 32 + } + }, + "render_controllers": ["controller.render.tropicalfish"], + "spawn_egg": {"texture": "spawn_egg", "texture_index": 44} + }, + "vindicator": { + "identifier": "minecraft:vindicator", + "min_engine_version": "1.8.0", + "materials": {"default": "vindicator"}, + "textures": {"default": "textures/entity/illager/vindicator"}, + "geometry": { + "default": { + "visible_bounds_width": 1.5, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [0, 1.25, 0], + "texturewidth": 64, + "textureheight": 64, + "bones": [ + { + "name": "head", + "parent": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 24, -4], "size": [8, 10, 8], "uv": [0, 0]} + ] + }, + { + "name": "nose", + "parent": "head", + "pivot": [0, 26, 0], + "cubes": [ + {"origin": [-1, 23, -6], "size": [2, 4, 2], "uv": [24, 0]} + ] + }, + { + "name": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 12, -3], "size": [8, 12, 6], "uv": [16, 20]}, + { + "origin": [-4, 6, -3], + "size": [8, 18, 6], + "uv": [0, 38], + "inflate": 0.5 + } + ] + }, + { + "name": "arms", + "parent": "body", + "pivot": [0, 22, 0], + "cubes": [ + {"origin": [-8, 16, -2], "size": [4, 8, 4], "uv": [44, 22]}, + {"origin": [4, 16, -2], "size": [4, 8, 4], "uv": [44, 22]}, + {"origin": [-4, 16, -2], "size": [8, 4, 4], "uv": [40, 38]} + ] + }, + { + "name": "leg0", + "parent": "body", + "pivot": [-2, 12, 0], + "cubes": [ + {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 22]} + ] + }, + { + "name": "leg1", + "parent": "body", + "pivot": [2, 12, 0], + "mirror": true, + "cubes": [{"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [0, 22]}] + }, + { + "name": "rightArm", + "parent": "body", + "pivot": [-5, 22, 0], + "cubes": [ + {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 46]} + ] + }, + { + "name": "rightItem", + "pivot": [-5.5, 16, 0.5], + "neverRender": true, + "parent": "rightArm" + }, + { + "name": "leftArm", + "parent": "body", + "pivot": [5, 22, 0], + "mirror": true, + "cubes": [ + {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 46]} + ] + } + ] + } + }, + "spawn_egg": {"texture": "spawn_egg", "texture_index": 39}, + "render_controllers": ["controller.render.vindicator"], + "enable_attachables": true + }, + "wandering_trader": { + "identifier": "minecraft:wandering_trader", + "materials": {"default": "wandering_trader"}, + "textures": {"default": "textures/entity/wandering_trader"}, + "geometry": { + "default": { + "visible_bounds_width": 1.5, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [0, 1.25, 0], + "bones": [ + { + "name": "head", + "parent": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 24, -4], "size": [8, 10, 8], "uv": [0, 0]} + ] + }, + { + "name": "helmet", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-4, 24, -4], + "size": [8, 10, 8], + "uv": [32, 0], + "inflate": 0.5 + } + ] + }, + { + "name": "brim", + "parent": "head", + "pivot": [0, 24, 0], + "bind_pose_rotation": [-90, 0, 0], + "cubes": [ + { + "origin": [-8, 16, -6], + "size": [16, 16, 1], + "uv": [30, 47], + "inflate": 0.1 + } + ] + }, + { + "name": "nose", + "parent": "head", + "pivot": [0, 26, 0], + "cubes": [ + {"origin": [-1, 23, -6], "size": [2, 4, 2], "uv": [24, 0]} + ] + }, + { + "name": "body", + "locators": {"lead_hold": [0, 40, 0]}, + "cubes": [ + {"origin": [-4, 12, -3], "size": [8, 12, 6], "uv": [16, 20]}, + { + "origin": [-4, 6, -3], + "size": [8, 18, 6], + "uv": [0, 38], + "inflate": 0.5 + } + ] + }, + { + "name": "arms", + "parent": "body", + "pivot": [0, 22, 0], + "cubes": [ + {"origin": [-4, 16, -2], "size": [8, 4, 4], "uv": [40, 38]}, + {"origin": [-8, 16, -2], "size": [4, 8, 4], "uv": [44, 22]}, + { + "origin": [4, 16, -2], + "size": [4, 8, 4], + "uv": [44, 22], + "mirror": true + } + ] + }, + {"name": "held_item", "parent": "arms", "pivot": [0, 0, 0]}, + { + "name": "leg0", + "parent": "body", + "pivot": [-2, 12, 0], + "cubes": [ + {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 22]} + ] + }, + { + "name": "leg1", + "parent": "body", + "pivot": [2, 12, 0], + "cubes": [ + { + "origin": [0, 0, -2], + "size": [4, 12, 4], + "uv": [0, 22], + "mirror": true + } + ] + } + ] + } + }, + "render_controllers": ["controller.render.wandering_trader"], + "spawn_egg": {"texture": "spawn_egg_wandering_trader"} + }, + "wither": { + "identifier": "minecraft:wither", + "min_engine_version": "1.8.0", + "materials": {"default": "wither_boss", "armor": "wither_boss_armor"}, + "textures": { + "default": "textures/entity/wither/wither", + "armor_white": "textures/entity/wither/wither_armor", + "armor_blue": "textures/entity/wither/wither_armor", + "invulnerable": "textures/entity/wither/wither_invulnerable" + }, + "geometry": { + "default": { + "visible_bounds_width": 3, + "visible_bounds_height": 4, + "visible_bounds_offset": [0, 2, 0], + "texturewidth": 64, + "textureheight": 64, + "bones": [ + { + "name": "upperBodyPart1", + "cubes": [ + {"origin": [-10, 17.1, -0.5], "size": [20, 3, 3], "uv": [0, 16]} + ] + }, + { + "name": "upperBodyPart2", + "parent": "upperBodyPart1", + "pivot": [-2, 17.1, -0.5], + "cubes": [ + {"origin": [-2, 7.1, -0.5], "size": [3, 10, 3], "uv": [0, 22]}, + {"origin": [-6, 13.6, 0], "size": [11, 2, 2], "uv": [24, 22]}, + {"origin": [-6, 11.1, 0], "size": [11, 2, 2], "uv": [24, 22]}, + {"origin": [-6, 8.6, 0], "size": [11, 2, 2], "uv": [24, 22]} + ] + }, + { + "name": "upperBodyPart3", + "parent": "upperBodyPart2", + "pivot": [0, 24, 0], + "cubes": [{"origin": [0, 18, 0], "size": [3, 6, 3], "uv": [12, 22]}] + }, + { + "name": "head1", + "parent": "upperBodyPart1", + "pivot": [0, 20, 0], + "cubes": [{"origin": [-4, 20, -4], "size": [8, 8, 8], "uv": [0, 0]}] + }, + { + "name": "head2", + "parent": "upperBodyPart1", + "pivot": [-9, 18, -1], + "cubes": [ + {"origin": [-12, 18, -4], "size": [6, 6, 6], "uv": [32, 0]} + ] + }, + { + "name": "head3", + "parent": "upperBodyPart1", + "pivot": [9, 18, -1], + "cubes": [{"origin": [6, 18, -4], "size": [6, 6, 6], "uv": [32, 0]}] + } + ] + }, + "armor": { + "visible_bounds_width": 3, + "visible_bounds_height": 4, + "visible_bounds_offset": [0, 2, 0], + "texturewidth": 64, + "textureheight": 64, + "bones": [ + { + "name": "upperBodyPart1", + "cubes": [ + {"origin": [-10, 17.1, -0.5], "size": [20, 3, 3], "uv": [0, 16]} + ], + "inflate": 2 + }, + { + "name": "upperBodyPart2", + "parent": "upperBodyPart1", + "pivot": [-2, 17.1, -0.5], + "cubes": [ + {"origin": [-2, 7.1, -0.5], "size": [3, 10, 3], "uv": [0, 22]}, + {"origin": [-6, 13.6, 0], "size": [11, 2, 2], "uv": [24, 22]}, + {"origin": [-6, 11.1, 0], "size": [11, 2, 2], "uv": [24, 22]}, + {"origin": [-6, 8.6, 0], "size": [11, 2, 2], "uv": [24, 22]} + ], + "inflate": 2 + }, + { + "name": "upperBodyPart3", + "parent": "upperBodyPart2", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [0, 18, 0], "size": [3, 6, 3], "uv": [12, 22]} + ], + "inflate": 2 + }, + { + "name": "head1", + "parent": "upperBodyPart1", + "pivot": [0, 20, 0], + "cubes": [ + {"origin": [-4, 20, -4], "size": [8, 8, 8], "uv": [0, 0]} + ], + "inflate": 2 + }, + { + "name": "head2", + "parent": "upperBodyPart1", + "pivot": [-9, 18, -1], + "cubes": [ + {"origin": [-12, 18, -4], "size": [6, 6, 6], "uv": [32, 0]} + ], + "inflate": 2 + }, + { + "name": "head3", + "parent": "upperBodyPart1", + "pivot": [9, 18, -1], + "cubes": [ + {"origin": [6, 18, -4], "size": [6, 6, 6], "uv": [32, 0]} + ], + "inflate": 2 + } + ] + } + }, + "render_controllers": [ + "controller.render.wither_boss", + "controller.render.wither_boss_armor_white", + "controller.render.wither_boss_armor_blue" + ] + }, + "wither_skeleton": { + "identifier": "minecraft:wither_skeleton", + "min_engine_version": "1.8.0", + "materials": {"default": "skeleton"}, + "textures": {"default": "textures/entity/skeleton/wither_skeleton"}, + "geometry": { + "default": { + "texturewidth": 64, + "textureheight": 32, + "visible_bounds_width": 1.5, + "visible_bounds_height": 3, + "visible_bounds_offset": [0, 1.5, 0], + "bones": [ + { + "name": "body", + "parent": "waist", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} + ] + }, + {"name": "waist", "pivot": [0, 12, 0]}, + { + "name": "head", + "parent": "body", + "pivot": [0, 24, 0], + "cubes": [{"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]}] + }, + { + "name": "hat", + "parent": "head", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-4, 24, -4], + "size": [8, 8, 8], + "uv": [32, 0], + "inflate": 0.5 + } + ], + "neverRender": true + }, + { + "name": "rightArm", + "parent": "body", + "pivot": [-5, 22, 0], + "cubes": [ + {"origin": [-6, 12, -1], "size": [2, 12, 2], "uv": [40, 16]} + ] + }, + { + "name": "rightItem", + "parent": "rightArm", + "pivot": [-1, -45, -5], + "neverRender": true + }, + { + "name": "leftArm", + "parent": "body", + "pivot": [5, 22, 0], + "cubes": [ + {"origin": [4, 12, -1], "size": [2, 12, 2], "uv": [40, 16]} + ], + "mirror": true + }, + { + "name": "leftItem", + "parent": "leftArm", + "pivot": [1, -45, -5], + "neverRender": true + }, + { + "name": "rightLeg", + "parent": "body", + "pivot": [-2, 12, 0], + "cubes": [ + {"origin": [-3, 0, -1], "size": [2, 12, 2], "uv": [0, 16]} + ] + }, + { + "name": "leftLeg", + "parent": "body", + "pivot": [2, 12, 0], + "cubes": [ + {"origin": [1, 0, -1], "size": [2, 12, 2], "uv": [0, 16]} + ], + "mirror": true + } + ] + } + }, + "render_controllers": ["controller.render.wither_skeleton"], + "enable_attachables": true, + "spawn_egg": {"texture": "spawn_egg", "texture_index": 29} + }, + "wither_skull": { + "identifier": "minecraft:wither_skull", + "materials": {"default": "wither_skull"}, + "textures": {"default": "textures/entity/wither/wither"}, + "geometry": { + "default": { + "bones": [ + { + "name": "head", + "cubes": [{"origin": [-4, 0, -4], "size": [8, 8, 8], "uv": [0, 35]}] + } + ], + "visible_bounds_width": 1, + "visible_bounds_height": 1, + "texturewidth": 64, + "textureheight": 64 + } + }, + "render_controllers": ["controller.render.wither_skull"] + }, + "zoglin": { + "identifier": "minecraft:zoglin", + "materials": {"default": "zoglin"}, + "textures": {"default": "textures/entity/hoglin/zoglin"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 19, -3], + "cubes": [ + { + "origin": [-8, 11, -7], + "size": [16, 14, 26], + "inflate": 0.02, + "uv": [1, 1] + }, + { + "origin": [0, 22, -10], + "size": [0, 10, 19], + "inflate": 0.02, + "uv": [90, 33] + } + ], + "locators": {"lead": [0, 20, -5]} + }, + { + "name": "head", + "parent": "body", + "pivot": [0, 22, -5], + "rotation": [50, 0, 0], + "cubes": [ + {"origin": [-7, 21, -24], "size": [14, 6, 19], "uv": [61, 1]}, + {"origin": [-8, 22, -19], "size": [2, 11, 2], "uv": [1, 13]}, + {"origin": [6, 22, -19], "size": [2, 11, 2], "uv": [1, 13]} + ] + }, + { + "name": "right_ear", + "parent": "head", + "pivot": [-7, 27, -7], + "rotation": [0, 0, -50], + "cubes": [ + {"origin": [-13, 26, -10], "size": [6, 1, 4], "uv": [1, 1]} + ] + }, + { + "name": "left_ear", + "parent": "head", + "pivot": [7, 27, -7], + "rotation": [0, 0, 50], + "cubes": [{"origin": [7, 26, -10], "size": [6, 1, 4], "uv": [1, 6]}] + }, + { + "name": "leg_back_right", + "pivot": [6, 8, 17], + "cubes": [ + {"origin": [-8, 0, 13], "size": [5, 11, 5], "uv": [21, 45]} + ] + }, + { + "name": "leg_back_left", + "pivot": [-6, 8, 17], + "cubes": [{"origin": [3, 0, 13], "size": [5, 11, 5], "uv": [0, 45]}] + }, + { + "name": "leg_front_right", + "pivot": [-6, 12, -3], + "cubes": [ + {"origin": [-8, 0, -6], "size": [6, 14, 6], "uv": [66, 42]} + ] + }, + { + "name": "leg_front_left", + "pivot": [6, 12, -3], + "cubes": [ + {"origin": [2, 0, -6], "size": [6, 14, 6], "uv": [41, 42]} + ] + } + ], + "visible_bounds_width": 4, + "visible_bounds_height": 3, + "visible_bounds_offset": [0, 1.5, 0], + "texturewidth": 128, + "textureheight": 64 + } + }, + "spawn_egg": {"base_color": "#c66e55", "overlay_color": "#e6e6e6"}, + "render_controllers": ["controller.render.zoglin"] + }, + "zombie": { + "identifier": "minecraft:zombie", + "min_engine_version": "1.8.0", + "materials": {"default": "zombie"}, + "textures": {"default": "textures/entity/zombie/zombie"}, + "geometry": { + "default": { + "visible_bounds_width": 2, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 1, 0], + "texturewidth": 64, + "textureheight": 32, + "bones": [ + { + "name": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]} + ], + "parent": "waist" + }, + {"name": "waist", "neverRender": true, "pivot": [0, 12, 0]}, + { + "name": "head", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [0, 0]} + ], + "parent": "body" + }, + { + "name": "hat", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-4, 24, -4], + "size": [8, 8, 8], + "uv": [32, 0], + "inflate": 0.5 + } + ], + "neverRender": true, + "parent": "head" + }, + { + "name": "rightArm", + "pivot": [-5, 22, 0], + "cubes": [ + {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} + ], + "parent": "body" + }, + { + "name": "rightItem", + "pivot": [-1, -45, -5], + "neverRender": true, + "parent": "rightArm" + }, + { + "name": "leftArm", + "pivot": [5, 22, 0], + "cubes": [ + {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [40, 16]} + ], + "mirror": true, + "parent": "body" + }, + { + "name": "leftItem", + "pivot": [1, -45, -5], + "neverRender": true, + "parent": "leftArm" + }, + { + "name": "rightLeg", + "pivot": [-1.9, 12, 0], + "cubes": [ + {"origin": [-3.9, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} + ], + "parent": "body" + }, + { + "name": "leftLeg", + "pivot": [1.9, 12, 0], + "cubes": [ + {"origin": [-0.1, 0, -2], "size": [4, 12, 4], "uv": [0, 16]} + ], + "mirror": true, + "parent": "body" + } + ] + } + }, + "spawn_egg": {"texture": "spawn_egg", "texture_index": 12}, + "scripts": { + "pre_animation": [ + "variable.tcos0 = (Math.cos(query.modified_distance_moved * 38.17) * query.modified_move_speed / variable.gliding_speed_value) * 57.3;" + ] + }, + "animations": { + "humanoid_big_head": {"loop": true, "bones": {"head": {"scale": 1.4}}}, + "look_at_target_default": { + "loop": true, + "bones": { + "head": { + "relative_to": {"rotation": "entity"}, + "rotation": [ + "query.target_x_rotation", + "query.target_y_rotation", + 0 + ] + } + } + }, + "look_at_target_gliding": { + "loop": true, + "bones": {"head": {"rotation": [-45, "query.target_y_rotation", 0]}} + }, + "look_at_target_swimming": { + "loop": true, + "bones": { + "head": { + "rotation": [ + "math.lerp(query.target_x_rotation, -45.0, variable.swim_amount)", + "query.target_y_rotation", + 0 + ] + } + } + }, + "move": { + "loop": true, + "bones": { + "leftarm": {"rotation": ["variable.tcos0", 0, 0]}, + "leftleg": {"rotation": ["variable.tcos0 * -1.4", 0, 0]}, + "rightarm": {"rotation": ["-variable.tcos0", 0, 0]}, + "rightleg": {"rotation": ["variable.tcos0 * 1.4", 0, 0]} + } + }, + "riding.arms": { + "loop": true, + "bones": { + "leftarm": {"rotation": [-36, 0, 0]}, + "rightarm": {"rotation": [-36, 0, 0]} + } + }, + "riding.legs": { + "loop": true, + "bones": { + "leftleg": {"rotation": ["-72.0 - this", "-18.0 - this", "-this"]}, + "rightleg": {"rotation": ["-72.0 - this", "18.0 - this", "-this"]} + } + }, + "holding": { + "loop": true, + "bones": { + "leftarm": { + "rotation": [ + "variable.is_holding_left ? (-this * 0.5 - 18.0) : 0.0", + 0, + 0 + ] + }, + "rightarm": { + "rotation": [ + "variable.is_holding_right ? (-this * 0.5 - 18.0) : 0.0", + 0, + 0 + ] + } + } + }, + "brandish_spear": { + "loop": true, + "bones": { + "rightarm": { + "rotation": [ + "this * -0.5 - 157.5 - 22.5 * variable.charge_amount", + "-this", + 0 + ] + } + } + }, + "charging": { + "loop": true, + "bones": { + "rightarm": { + "rotation": ["22.5 * variable.charge_amount - this", "-this", 0] + } + } + }, + "attack.rotations": { + "loop": true, + "bones": { + "body": { + "rotation": [ + 0, + "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46 - this", + 0 + ] + }, + "leftarm": { + "rotation": [ + "math.sin(math.sqrt(variable.attack_time) * 360) * 11.46", + 0, + 0 + ] + }, + "rightarm": { + "rotation": [ + "math.sin(1.0 - math.pow(1.0 - variable.attack_time, 3.0) * 180.0) * (variable.is_brandishing_spear ? -1.0 : 1.0 )", + "variable.is_brandishing_spear ? 0.0 : (math.sin(math.sqrt(variable.attack_time) * 360) * 11.46) * 2.0", + 0 + ] + } + } + }, + "sneaking": { + "loop": true, + "bones": { + "body": {"rotation": ["0.5 - this", 0, 0]}, + "head": {"position": [0, 1, 0]}, + "leftarm": {"rotation": [72, 0, 0]}, + "leftleg": {"position": [0, -3, 4]}, + "rightarm": {"rotation": [72, 0, 0]}, + "rightleg": {"position": [0, -3, 4]} + } + }, + "bob": { + "loop": true, + "bones": { + "leftarm": { + "rotation": [ + 0, + 0, + "((math.cos(query.life_time * 103.2) * 2.865) + 2.865) *-1.0" + ] + }, + "rightarm": { + "rotation": [ + 0, + 0, + "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" + ] + } + } + }, + "damage_nearby_mobs": { + "loop": true, + "bones": { + "leftarm": {"rotation": ["-45.0-this", "-this", "-this"]}, + "leftleg": {"rotation": ["45.0-this", "-this", "-this"]}, + "rightarm": {"rotation": ["45.0-this", "-this", "-this"]}, + "rightleg": {"rotation": ["-45.0-this", "-this", "-this"]} + } + }, + "bow_and_arrow": { + "loop": true, + "bones": { + "leftarm": { + "rotation": [ + "query.target_x_rotation - 90.0 - math.sin(query.life_time * 76.8) * 2.865 - this", + "query.target_y_rotation + 28.65", + "-(math.cos(query.life_time * 103.2) * 2.865) - 2.865" + ] + }, + "rightarm": { + "rotation": [ + "query.target_x_rotation - 90.0 + math.sin(query.life_time * 76.8) * 2.865 - this", + "query.target_y_rotation - 5.73", + "(math.cos(query.life_time * 103.2) * 2.865) + 2.865" + ] + } + } + }, + "use_item_progress": { + "loop": true, + "bones": { + "rightarm": { + "rotation": [ + "variable.use_item_startup_progress * -60.0 + variable.use_item_interval_progress * 11.25", + "variable.use_item_startup_progress * -22.5 + variable.use_item_interval_progress * 11.25", + "variable.use_item_startup_progress * -5.625 + variable.use_item_interval_progress * 11.25" + ] + } + } + }, + "zombie_attack_bare_hand": { + "loop": true, + "bones": { + "leftarm": { + "rotation": [ + "-90.0 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) - (math.sin(query.life_time * 76.776372) * 2.865) - this", + "5.73 - ((math.sin(variable.attack_time * 180.0) * 57.3) * 0.6) - this", + "math.cos(query.life_time * 103.13244) * -2.865 - 2.865 - this" + ] + }, + "rightarm": { + "rotation": [ + "90.0 * (variable.is_brandishing_spear - 1.0) - ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4) + (math.sin(query.life_time * 76.776372) * 2.865) - this", + "(math.sin(variable.attack_time * 180.0) * 57.3) * 0.6 - 5.73 - this", + "math.cos(query.life_time * 103.13244) * 2.865 + 2.865 - this" + ] + } + } + }, + "swimming": { + "loop": true, + "bones": { + "body": { + "position": [ + 0, + "variable.swim_amount * -10.0 - this", + "variable.swim_amount * 9.0 - this" + ], + "rotation": [ + "variable.swim_amount * (90.0 + query.target_x_rotation)", + 0, + 0 + ] + }, + "leftarm": { + "rotation": [ + "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) - (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", + "math.lerp(this, 14.325, variable.swim_amount) - this", + "math.lerp(this, 14.325, variable.swim_amount) - (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" + ] + }, + "leftleg": { + "rotation": [ + "math.lerp(this, math.cos(query.life_time * 390.0 + 180.0) * 0.3, variable.swim_amount)", + 0, + 0 + ] + }, + "rightarm": { + "rotation": [ + "math.lerp(this, -180.0, variable.swim_amount) - (variable.swim_amount * ((math.sin(variable.attack_time * 180.0) * 57.3) * 1.2 - (math.sin((1.0 - (1.0 - variable.attack_time) * (1.0 - variable.attack_time)) * 180.0) * 57.3) * 0.4)) + (variable.swim_amount * (math.sin(query.life_time * 76.776372) * 2.865)) - this", + "math.lerp(this, 14.325, variable.swim_amount) - this", + "math.lerp(this, -14.325, variable.swim_amount) + (variable.swim_amount * (math.cos(query.life_time * 103.13244) * 2.865 + 2.865)) - this" + ] + }, + "rightleg": { + "rotation": [ + "math.lerp(this, math.cos(query.life_time * 390.0) * 0.3, variable.swim_amount)", + 0, + 0 + ] + } + } + } + }, + "animation_controllers": { + "humanoid_baby_big_head": { + "initial_state": "default", + "states": { + "baby": { + "animations": ["humanoid_big_head"], + "transitions": [{"default": "!query.is_baby"}] + }, + "default": {"transitions": [{"baby": "query.is_baby"}]} + } + }, + "look_at_target": { + "initial_state": "default", + "states": { + "default": { + "animations": ["look_at_target_default"], + "transitions": [ + {"gliding": "query.is_gliding"}, + {"swimming": "query.is_swimming"} + ] + }, + "gliding": { + "animations": ["look_at_target_gliding"], + "transitions": [ + {"swimming": "query.is_swimming"}, + {"default": "!query.is_gliding"} + ] + }, + "swimming": { + "animations": ["look_at_target_swimming"], + "transitions": [ + {"gliding": "query.is_gliding"}, + {"default": "!query.is_swimming"} + ] + } + } + }, + "move": { + "initial_state": "default", + "states": {"default": {"animations": ["move"]}} + }, + "riding": { + "initial_state": "default", + "states": { + "default": {"transitions": [{"riding": "query.is_riding"}]}, + "riding": { + "animations": ["riding.arms", "riding.legs"], + "transitions": [{"default": "!query.is_riding"}] + } + } + }, + "holding": { + "initial_state": "default", + "states": {"default": {"animations": ["holding"]}} + }, + "brandish_spear": { + "initial_state": "default", + "states": { + "brandish_spear": { + "animations": ["brandish_spear"], + "transitions": [{"default": "!variable.is_brandishing_spear"}] + }, + "default": { + "transitions": [{"brandish_spear": "variable.is_brandishing_spear"}] + } + } + }, + "charging": { + "initial_state": "default", + "states": { + "charging": { + "animations": ["charging"], + "transitions": [{"default": "!query.is_charging"}] + }, + "default": {"transitions": [{"charging": "query.is_charging"}]} + } + }, + "attack": { + "initial_state": "default", + "states": { + "attacking": { + "animations": ["attack.rotations"], + "transitions": [{"default": "variable.attack_time < 0.0"}] + }, + "default": { + "transitions": [{"attacking": "variable.attack_time >= 0.0"}] + } + } + }, + "sneaking": { + "initial_state": "default", + "states": { + "default": {"transitions": [{"sneaking": "query.is_sneaking"}]}, + "sneaking": { + "animations": ["sneaking"], + "transitions": [{"default": "!query.is_sneaking"}] + } + } + }, + "bob": { + "initial_state": "default", + "states": {"default": {"animations": ["bob"]}} + }, + "damage_nearby_mobs": { + "initial_state": "default", + "states": { + "damage_nearby_mobs": { + "animations": ["damage_nearby_mobs"], + "transitions": [{"default": "!variable.damage_nearby_mobs"}] + }, + "default": { + "transitions": [ + {"damage_nearby_mobs": "variable.damage_nearby_mobs"} + ] + } + } + }, + "bow_and_arrow": { + "initial_state": "default", + "states": { + "bow_and_arrow": { + "animations": ["bow_and_arrow"], + "transitions": [{"default": "!query.has_target"}] + }, + "default": {"transitions": [{"bow_and_arrow": "query.has_target"}]} + } + }, + "use_item_progress": { + "initial_state": "default", + "states": { + "default": { + "transitions": [ + { + "use_item_progress": "( variable.use_item_interval_progress > 0.0 ) || ( variable.use_item_startup_progress > 0.0 )" + } + ] + }, + "use_item_progress": { + "animations": ["use_item_progress"], + "transitions": [ + { + "default": "( variable.use_item_interval_progress <= 0.0 ) && ( variable.use_item_startup_progress <= 0.0 )" + } + ] + } + } + }, + "zombie_attack_bare_hand": { + "initial_state": "default", + "states": { + "default": { + "transitions": [{"is_bare_hand": "variable.is_holding_left != 1.0"}] + }, + "is_bare_hand": { + "animations": ["zombie_attack_bare_hand"], + "transitions": [{"default": "variable.is_holding_left == 1.0"}] + } + } + }, + "swimming": { + "initial_state": "default", + "states": { + "default": { + "transitions": [{"is_swimming": "variable.swim_amount > 0.0"}] + }, + "is_swimming": { + "animations": ["swimming"], + "transitions": [{"default": "variable.swim_amount <= 0.0"}] + } + } + } + }, + "render_controllers": ["controller.render.zombie"], + "enable_attachables": true + }, + "zombified_piglin": { + "identifier": "minecraft:zombie_pigman", + "min_engine_version": "1.8.0", + "materials": {"default": "zombie"}, + "textures": {"default": "textures/entity/piglin/zombified_piglin"}, + "geometry": { + "default": { + "bones": [ + { + "name": "body", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 12, -2], "size": [8, 12, 4], "uv": [16, 16]}, + { + "origin": [-4, 12, -2], + "size": [8, 12, 4], + "uv": [16, 32], + "inflate": 0.25 + } + ] + }, + { + "name": "head", + "parent": "body", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-5, 24, -4], + "size": [10, 8, 8], + "uv": [0, 0], + "inflate": -0.02 + }, + {"origin": [-2, 24, -5], "size": [4, 4, 1], "uv": [31, 1]}, + {"origin": [2, 24, -5], "size": [1, 2, 1], "uv": [2, 4]}, + {"origin": [-3, 24, -5], "size": [1, 2, 1], "uv": [2, 0]} + ], + "inflate": -0.02 + }, + { + "name": "leftear", + "parent": "head", + "pivot": [5, 30, 0], + "rotation": [0, 0, -30], + "cubes": [{"origin": [4, 25, -2], "size": [1, 5, 4], "uv": [51, 6]}] + }, + { + "name": "rightear", + "parent": "head", + "pivot": [-5, 30, 0], + "rotation": [0, 0, 30], + "cubes": [ + {"origin": [-5, 25, -2], "size": [1, 5, 4], "uv": [39, 6]} + ] + }, + {"name": "hat", "parent": "head", "pivot": [0, 24, 0]}, + { + "name": "rightarm", + "parent": "body", + "pivot": [-5, 22, 0], + "cubes": [ + {"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]}, + { + "origin": [-8, 12, -2], + "size": [4, 12, 4], + "uv": [40, 32], + "inflate": 0.25 + } + ] + }, + {"name": "rightItem", "parent": "rightarm", "pivot": [-1, -45, -5]}, + { + "name": "leftarm", + "parent": "body", + "pivot": [5, 22, 0], + "cubes": [ + {"origin": [4, 12, -2], "size": [4, 12, 4], "uv": [32, 48]}, + { + "origin": [4, 12, -2], + "size": [4, 12, 4], + "uv": [48, 48], + "inflate": 0.25 + } + ] + }, + {"name": "leftItem", "parent": "leftArm", "pivot": [1, -45, -5]}, + { + "name": "rightleg", + "parent": "body", + "pivot": [-1.9, 12, 0], + "cubes": [ + {"origin": [-4, 0, -2], "size": [4, 12, 4], "uv": [0, 16]}, + { + "origin": [-4, 0, -2], + "size": [4, 12, 4], + "uv": [0, 32], + "inflate": 0.25 + } + ] + }, + { + "name": "leftleg", + "parent": "body", + "pivot": [1.9, 12, 0], + "cubes": [ + {"origin": [0, 0, -2], "size": [4, 12, 4], "uv": [16, 48]}, + { + "origin": [0, 0, -2], + "size": [4, 12, 4], + "uv": [0, 48], + "inflate": 0.25 + } + ] + } + ], + "visible_bounds_width": 2, + "visible_bounds_height": 2, + "visible_bounds_offset": [0, 1, 0], + "texturewidth": 64, + "textureheight": 64 + } + }, + "spawn_egg": {"texture": "spawn_egg", "texture_index": 13}, + "render_controllers": ["controller.render.zombie_pigman"], + "enable_attachables": true + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/lib/entity/exportedModels.js b/renderer/viewer/three/entity/exportedModels.js similarity index 94% rename from prismarine-viewer/viewer/lib/entity/exportedModels.js rename to renderer/viewer/three/entity/exportedModels.js index b43658ec..fde9391f 100644 --- a/prismarine-viewer/viewer/lib/entity/exportedModels.js +++ b/renderer/viewer/three/entity/exportedModels.js @@ -22,7 +22,8 @@ export { default as parrot } from './models/parrot.obj' export { default as piglin } from './models/piglin.obj' export { default as pillager } from './models/pillager.obj' export { default as rabbit } from './models/rabbit.obj' -// export { default as sheep } from './models/sheep.obj' +export { default as sheep } from './models/sheep.obj' +export { default as arrow } from './models/arrow.obj' export { default as shulker } from './models/shulker.obj' export { default as sniffer } from './models/sniffer.obj' export { default as spider } from './models/spider.obj' @@ -34,5 +35,4 @@ export { default as warden } from './models/warden.obj' export { default as witch } from './models/witch.obj' export { default as wolf } from './models/wolf.obj' export { default as zombie_villager } from './models/zombie_villager.obj' -export { default as zombie } from './models/zombie.obj' export { default as boat } from './models/boat.obj' diff --git a/prismarine-viewer/viewer/lib/entity/externalTextures.json b/renderer/viewer/three/entity/externalTextures.json similarity index 100% rename from prismarine-viewer/viewer/lib/entity/externalTextures.json rename to renderer/viewer/three/entity/externalTextures.json diff --git a/prismarine-viewer/viewer/lib/entity/models/allay.obj b/renderer/viewer/three/entity/models/allay.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/allay.obj rename to renderer/viewer/three/entity/models/allay.obj diff --git a/renderer/viewer/three/entity/models/arrow.obj b/renderer/viewer/three/entity/models/arrow.obj new file mode 100644 index 00000000..469dd6cd --- /dev/null +++ b/renderer/viewer/three/entity/models/arrow.obj @@ -0,0 +1,60 @@ +# Aspose.3D Wavefront OBJ Exporter +# Copyright 2004-2024 Aspose Pty Ltd. +# File created: 02/12/2025 20:01:28 + +mtllib material.lib +g Arrow + +# +# object Arrow +# + +v -160 8.146034E-06 50 +v 160 8.146034E-06 50 +v -160 -8.146034E-06 -50 +v 160 -8.146034E-06 -50 +v -160 -50 1.1920929E-05 +v 160 -50 1.1920929E-05 +v -160 50 -1.1920929E-05 +v 160 50 -1.1920929E-05 +v -140 -49.999992 50.000008 +v -140 50.000008 49.999992 +v -140 -50.000008 -49.999992 +v -140 49.999992 -50.000008 +# 12 vertices + +vn 0 1 -1.6292068E-07 +vn 0 1 -1.6292068E-07 +vn 0 1 -1.6292068E-07 +vn 0 1 -1.6292068E-07 +vn 0 3.1391647E-07 1 +vn 0 3.1391647E-07 1 +vn 0 3.1391647E-07 1 +vn 0 3.1391647E-07 1 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +# 12 vertex normals + +vt 0 0.84375 0 +vt 0.5 1 0 +vt 0.5 1 0 +vt 0.5 0.84375 0 +vt 0 1 0 +vt 0.15625 0.84375 0 +vt 0.15625 0.6875 0 +vt 0 0.84375 0 +vt 0.5 0.84375 0 +vt 0 1 0 +vt 0 0.6875 0 +vt 0 0.84375 0 +# 12 texture coords + +usemtl Arrow +s 1 +f 1/1/1 2/9/2 4/2/3 3/10/4 +f 5/8/5 6/4/6 8/3/7 7/5/8 +f 9/11/9 10/7/10 12/6/11 11/12/12 +#3 polygons + diff --git a/prismarine-viewer/viewer/lib/entity/models/axolotl.obj b/renderer/viewer/three/entity/models/axolotl.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/axolotl.obj rename to renderer/viewer/three/entity/models/axolotl.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/blaze.obj b/renderer/viewer/three/entity/models/blaze.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/blaze.obj rename to renderer/viewer/three/entity/models/blaze.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/boat.obj b/renderer/viewer/three/entity/models/boat.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/boat.obj rename to renderer/viewer/three/entity/models/boat.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/camel.obj b/renderer/viewer/three/entity/models/camel.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/camel.obj rename to renderer/viewer/three/entity/models/camel.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/cat.obj b/renderer/viewer/three/entity/models/cat.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/cat.obj rename to renderer/viewer/three/entity/models/cat.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/chicken.obj b/renderer/viewer/three/entity/models/chicken.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/chicken.obj rename to renderer/viewer/three/entity/models/chicken.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/cod.obj b/renderer/viewer/three/entity/models/cod.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/cod.obj rename to renderer/viewer/three/entity/models/cod.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/creeper.obj b/renderer/viewer/three/entity/models/creeper.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/creeper.obj rename to renderer/viewer/three/entity/models/creeper.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/dolphin.obj b/renderer/viewer/three/entity/models/dolphin.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/dolphin.obj rename to renderer/viewer/three/entity/models/dolphin.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/ender_dragon.obj b/renderer/viewer/three/entity/models/ender_dragon.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/ender_dragon.obj rename to renderer/viewer/three/entity/models/ender_dragon.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/enderman.obj b/renderer/viewer/three/entity/models/enderman.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/enderman.obj rename to renderer/viewer/three/entity/models/enderman.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/endermite.obj b/renderer/viewer/three/entity/models/endermite.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/endermite.obj rename to renderer/viewer/three/entity/models/endermite.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/fox.obj b/renderer/viewer/three/entity/models/fox.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/fox.obj rename to renderer/viewer/three/entity/models/fox.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/frog.obj b/renderer/viewer/three/entity/models/frog.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/frog.obj rename to renderer/viewer/three/entity/models/frog.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/ghast.obj b/renderer/viewer/three/entity/models/ghast.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/ghast.obj rename to renderer/viewer/three/entity/models/ghast.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/goat.obj b/renderer/viewer/three/entity/models/goat.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/goat.obj rename to renderer/viewer/three/entity/models/goat.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/guardian.obj b/renderer/viewer/three/entity/models/guardian.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/guardian.obj rename to renderer/viewer/three/entity/models/guardian.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/horse.obj b/renderer/viewer/three/entity/models/horse.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/horse.obj rename to renderer/viewer/three/entity/models/horse.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/llama.obj b/renderer/viewer/three/entity/models/llama.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/llama.obj rename to renderer/viewer/three/entity/models/llama.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/minecart.obj b/renderer/viewer/three/entity/models/minecart.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/minecart.obj rename to renderer/viewer/three/entity/models/minecart.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/parrot.obj b/renderer/viewer/three/entity/models/parrot.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/parrot.obj rename to renderer/viewer/three/entity/models/parrot.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/piglin.obj b/renderer/viewer/three/entity/models/piglin.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/piglin.obj rename to renderer/viewer/three/entity/models/piglin.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/pillager.obj b/renderer/viewer/three/entity/models/pillager.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/pillager.obj rename to renderer/viewer/three/entity/models/pillager.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/rabbit.obj b/renderer/viewer/three/entity/models/rabbit.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/rabbit.obj rename to renderer/viewer/three/entity/models/rabbit.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/sheep.obj b/renderer/viewer/three/entity/models/sheep.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/sheep.obj rename to renderer/viewer/three/entity/models/sheep.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/shulker.obj b/renderer/viewer/three/entity/models/shulker.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/shulker.obj rename to renderer/viewer/three/entity/models/shulker.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/sniffer.obj b/renderer/viewer/three/entity/models/sniffer.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/sniffer.obj rename to renderer/viewer/three/entity/models/sniffer.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/spider.obj b/renderer/viewer/three/entity/models/spider.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/spider.obj rename to renderer/viewer/three/entity/models/spider.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/tadpole.obj b/renderer/viewer/three/entity/models/tadpole.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/tadpole.obj rename to renderer/viewer/three/entity/models/tadpole.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/turtle.obj b/renderer/viewer/three/entity/models/turtle.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/turtle.obj rename to renderer/viewer/three/entity/models/turtle.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/vex.obj b/renderer/viewer/three/entity/models/vex.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/vex.obj rename to renderer/viewer/three/entity/models/vex.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/villager.obj b/renderer/viewer/three/entity/models/villager.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/villager.obj rename to renderer/viewer/three/entity/models/villager.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/warden.obj b/renderer/viewer/three/entity/models/warden.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/warden.obj rename to renderer/viewer/three/entity/models/warden.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/witch.obj b/renderer/viewer/three/entity/models/witch.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/witch.obj rename to renderer/viewer/three/entity/models/witch.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/wolf.obj b/renderer/viewer/three/entity/models/wolf.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/wolf.obj rename to renderer/viewer/three/entity/models/wolf.obj diff --git a/prismarine-viewer/viewer/lib/entity/models/zombie_villager.obj b/renderer/viewer/three/entity/models/zombie_villager.obj similarity index 100% rename from prismarine-viewer/viewer/lib/entity/models/zombie_villager.obj rename to renderer/viewer/three/entity/models/zombie_villager.obj diff --git a/renderer/viewer/three/entity/objModels.js b/renderer/viewer/three/entity/objModels.js new file mode 100644 index 00000000..edff440b --- /dev/null +++ b/renderer/viewer/three/entity/objModels.js @@ -0,0 +1 @@ +export * as externalModels from './exportedModels' diff --git a/renderer/viewer/three/graphicsBackend.ts b/renderer/viewer/three/graphicsBackend.ts new file mode 100644 index 00000000..04cb00ca --- /dev/null +++ b/renderer/viewer/three/graphicsBackend.ts @@ -0,0 +1,166 @@ +import * as THREE from 'three' +import { Vec3 } from 'vec3' +import { GraphicsBackendLoader, GraphicsBackend, GraphicsInitOptions, DisplayWorldOptions } from '../../../src/appViewer' +import { ProgressReporter } from '../../../src/core/progressReporter' +import { showNotification } from '../../../src/react/NotificationProvider' +import { displayEntitiesDebugList } from '../../playground/allEntitiesDebug' +import supportedVersions from '../../../src/supportedVersions.mjs' +import { ResourcesManager } from '../../../src/resourcesManager' +import { WorldRendererThree } from './worldrendererThree' +import { DocumentRenderer } from './documentRenderer' +import { PanoramaRenderer } from './panorama' +import { initVR } from './world/vr' + +// https://discourse.threejs.org/t/updates-to-color-management-in-three-js-r152/50791 +THREE.ColorManagement.enabled = false +globalThis.THREE = THREE + +const getBackendMethods = (worldRenderer: WorldRendererThree) => { + return { + updateMap: worldRenderer.entities.updateMap.bind(worldRenderer.entities), + updateCustomBlock: worldRenderer.updateCustomBlock.bind(worldRenderer), + getBlockInfo: worldRenderer.getBlockInfo.bind(worldRenderer), + playEntityAnimation: worldRenderer.entities.playAnimation.bind(worldRenderer.entities), + damageEntity: worldRenderer.entities.handleDamageEvent.bind(worldRenderer.entities), + updatePlayerSkin: worldRenderer.entities.updatePlayerSkin.bind(worldRenderer.entities), + changeHandSwingingState: worldRenderer.changeHandSwingingState.bind(worldRenderer), + getHighestBlocks: worldRenderer.getHighestBlocks.bind(worldRenderer), + reloadWorld: worldRenderer.reloadWorld.bind(worldRenderer), + + addMedia: worldRenderer.media.addMedia.bind(worldRenderer.media), + destroyMedia: worldRenderer.media.destroyMedia.bind(worldRenderer.media), + setVideoPlaying: worldRenderer.media.setVideoPlaying.bind(worldRenderer.media), + setVideoSeeking: worldRenderer.media.setVideoSeeking.bind(worldRenderer.media), + setVideoVolume: worldRenderer.media.setVideoVolume.bind(worldRenderer.media), + setVideoSpeed: worldRenderer.media.setVideoSpeed.bind(worldRenderer.media), + + addSectionAnimation (id: string, animation: typeof worldRenderer.sectionsOffsetsAnimations[string]) { + worldRenderer.sectionsOffsetsAnimations[id] = animation + }, + removeSectionAnimation (id: string) { + delete worldRenderer.sectionsOffsetsAnimations[id] + }, + + shakeFromDamage: worldRenderer.cameraShake.shakeFromDamage.bind(worldRenderer.cameraShake), + onPageInteraction: worldRenderer.media.onPageInteraction.bind(worldRenderer.media), + downloadMesherLog: worldRenderer.downloadMesherLog.bind(worldRenderer), + + addWaypoint: worldRenderer.waypoints.addWaypoint.bind(worldRenderer.waypoints), + removeWaypoint: worldRenderer.waypoints.removeWaypoint.bind(worldRenderer.waypoints), + + // New method for updating skybox + setSkyboxImage: worldRenderer.skyboxRenderer.setSkyboxImage.bind(worldRenderer.skyboxRenderer) + } +} + +export type ThreeJsBackendMethods = ReturnType + +const createGraphicsBackend: GraphicsBackendLoader = (initOptions: GraphicsInitOptions) => { + // Private state + const documentRenderer = new DocumentRenderer(initOptions) + globalThis.renderer = documentRenderer.renderer + + let panoramaRenderer: PanoramaRenderer | null = null + let worldRenderer: WorldRendererThree | null = null + + const startPanorama = async () => { + if (!documentRenderer) throw new Error('Document renderer not initialized') + if (worldRenderer) return + const qs = new URLSearchParams(location.search) + if (qs.get('debugEntities')) { + const fullResourceManager = initOptions.resourcesManager as ResourcesManager + fullResourceManager.currentConfig = { version: qs.get('version') || supportedVersions.at(-1)!, noInventoryGui: true } + await fullResourceManager.updateAssetsData({ }) + + displayEntitiesDebugList(fullResourceManager.currentConfig.version) + return + } + + if (!panoramaRenderer) { + panoramaRenderer = new PanoramaRenderer(documentRenderer, initOptions, !!process.env.SINGLE_FILE_BUILD_MODE) + globalThis.panoramaRenderer = panoramaRenderer + callModsMethod('panoramaCreated', panoramaRenderer) + await panoramaRenderer.start() + callModsMethod('panoramaReady', panoramaRenderer) + } + } + + const startWorld = async (displayOptions: DisplayWorldOptions) => { + if (panoramaRenderer) { + panoramaRenderer.dispose() + panoramaRenderer = null + } + worldRenderer = new WorldRendererThree(documentRenderer.renderer, initOptions, displayOptions) + void initVR(worldRenderer, documentRenderer) + await worldRenderer.worldReadyPromise + documentRenderer.render = (sizeChanged: boolean) => { + worldRenderer?.render(sizeChanged) + } + documentRenderer.inWorldRenderingConfig = displayOptions.inWorldRenderingConfig + window.world = worldRenderer + callModsMethod('worldReady', worldRenderer) + } + + const disconnect = () => { + if (panoramaRenderer) { + panoramaRenderer.dispose() + panoramaRenderer = null + } + if (documentRenderer) { + documentRenderer.dispose() + } + if (worldRenderer) { + worldRenderer.destroy() + worldRenderer = null + } + } + + // Public interface + const backend: GraphicsBackend = { + id: 'threejs', + displayName: `three.js ${THREE.REVISION}`, + startPanorama, + startWorld, + disconnect, + setRendering (rendering) { + documentRenderer.setPaused(!rendering) + if (worldRenderer) worldRenderer.renderingActive = rendering + }, + getDebugOverlay: () => ({ + get entitiesString () { + return worldRenderer?.entities.getDebugString() + }, + }), + updateCamera (pos: Vec3 | null, yaw: number, pitch: number) { + worldRenderer?.setFirstPersonCamera(pos, yaw, pitch) + }, + get soundSystem () { + return worldRenderer?.soundSystem + }, + get backendMethods () { + if (!worldRenderer) return undefined + return getBackendMethods(worldRenderer) + } + } + + globalThis.threeJsBackend = backend + globalThis.resourcesManager = initOptions.resourcesManager + callModsMethod('default', backend) + + return backend +} + +const callModsMethod = (method: string, ...args: any[]) => { + for (const mod of Object.values((window.loadedMods ?? {}) as Record)) { + try { + mod.threeJsBackendModule?.[method]?.(...args) + } catch (err) { + const errorMessage = `[mod three.js] Error calling ${method} on ${mod.name}: ${err}` + showNotification(errorMessage, 'error') + throw new Error(errorMessage) + } + } +} + +createGraphicsBackend.id = 'threejs' +export default createGraphicsBackend diff --git a/renderer/viewer/three/hand.ts b/renderer/viewer/three/hand.ts new file mode 100644 index 00000000..2bd3832b --- /dev/null +++ b/renderer/viewer/three/hand.ts @@ -0,0 +1,89 @@ +import * as THREE from 'three' +import { loadSkinFromUsername, loadSkinImage } from '../lib/utils/skins' +import { steveTexture } from './entities' + + +export const getMyHand = async (image?: string, userName?: string) => { + let newMap: THREE.Texture + if (!image && !userName) { + newMap = await steveTexture + } else { + if (!image) { + image = await loadSkinFromUsername(userName!, 'skin') + } + if (!image) { + return + } + const { canvas } = await loadSkinImage(image) + newMap = new THREE.CanvasTexture(canvas) + } + + newMap.magFilter = THREE.NearestFilter + newMap.minFilter = THREE.NearestFilter + // right arm + const box = new THREE.BoxGeometry() + const material = new THREE.MeshStandardMaterial() + const slim = false + const mesh = new THREE.Mesh(box, material) + mesh.scale.x = slim ? 3 : 4 + mesh.scale.y = 12 + mesh.scale.z = 4 + setSkinUVs(box, 40, 16, slim ? 3 : 4, 12, 4) + material.map = newMap + material.needsUpdate = true + const group = new THREE.Group() + group.add(mesh) + group.scale.set(0.1, 0.1, 0.1) + mesh.rotation.z = Math.PI + return group +} + +function setUVs ( + box: THREE.BoxGeometry, + u: number, + v: number, + width: number, + height: number, + depth: number, + textureWidth: number, + textureHeight: number +): void { + const toFaceVertices = (x1: number, y1: number, x2: number, y2: number) => [ + new THREE.Vector2(x1 / textureWidth, 1 - y2 / textureHeight), + new THREE.Vector2(x2 / textureWidth, 1 - y2 / textureHeight), + new THREE.Vector2(x2 / textureWidth, 1 - y1 / textureHeight), + new THREE.Vector2(x1 / textureWidth, 1 - y1 / textureHeight), + ] + + const top = toFaceVertices(u + depth, v, u + width + depth, v + depth) + const bottom = toFaceVertices(u + width + depth, v, u + width * 2 + depth, v + depth) + const left = toFaceVertices(u, v + depth, u + depth, v + depth + height) + const front = toFaceVertices(u + depth, v + depth, u + width + depth, v + depth + height) + const right = toFaceVertices(u + width + depth, v + depth, u + width + depth * 2, v + height + depth) + const back = toFaceVertices(u + width + depth * 2, v + depth, u + width * 2 + depth * 2, v + height + depth) + + const uvAttr = box.attributes.uv as THREE.BufferAttribute + const uvRight = [right[3], right[2], right[0], right[1]] + const uvLeft = [left[3], left[2], left[0], left[1]] + const uvTop = [top[3], top[2], top[0], top[1]] + const uvBottom = [bottom[0], bottom[1], bottom[3], bottom[2]] + const uvFront = [front[3], front[2], front[0], front[1]] + const uvBack = [back[3], back[2], back[0], back[1]] + + // Create a new array to hold the modified UV data + const newUVData = [] as number[] + + // Iterate over the arrays and copy the data to uvData + for (const uvArray of [uvRight, uvLeft, uvTop, uvBottom, uvFront, uvBack]) { + for (const uv of uvArray) { + newUVData.push(uv.x, uv.y) + } + } + + uvAttr.set(new Float32Array(newUVData)) + uvAttr.needsUpdate = true +} + +function setSkinUVs (box: THREE.BoxGeometry, u: number, v: number, width: number, height: number, depth: number): void { + setUVs(box, u, v, width, height, depth, 64, 64) +} diff --git a/renderer/viewer/three/holdingBlock.ts b/renderer/viewer/three/holdingBlock.ts new file mode 100644 index 00000000..f9d00f0e --- /dev/null +++ b/renderer/viewer/three/holdingBlock.ts @@ -0,0 +1,933 @@ +import * as THREE from 'three' +import * as tweenJs from '@tweenjs/tween.js' +import PrismarineItem from 'prismarine-item' +import worldBlockProvider, { WorldBlockProvider } from 'mc-assets/dist/worldBlockProvider' +import { BlockModel } from 'mc-assets' +import { getThreeBlockModelGroup, renderBlockThree, setBlockPosition } from '../lib/mesher/standaloneRenderer' +import { MovementState, PlayerStateRenderer } from '../lib/basePlayerState' +import { DebugGui } from '../lib/DebugGui' +import { SmoothSwitcher } from '../lib/smoothSwitcher' +import { watchProperty } from '../lib/utils/proxy' +import { WorldRendererConfig } from '../lib/worldrendererCommon' +import { getMyHand } from './hand' +import { WorldRendererThree } from './worldrendererThree' +import { disposeObject } from './threeJsUtils' + +export type HandItemBlock = { + name? + properties? + fullItem? + type: 'block' | 'item' | 'hand' + id?: number +} + +const rotationPositionData = { + itemRight: { + 'rotation': [ + 0, + -90, + 25 + ], + 'translation': [ + 1.13, + 3.2, + 1.13 + ], + 'scale': [ + 0.68, + 0.68, + 0.68 + ] + }, + itemLeft: { + 'rotation': [ + 0, + 90, + -25 + ], + 'translation': [ + 1.13, + 3.2, + 1.13 + ], + 'scale': [ + 0.68, + 0.68, + 0.68 + ] + }, + blockRight: { + 'rotation': [ + 0, + 45, + 0 + ], + 'translation': [ + 0, + 0, + 0 + ], + 'scale': [ + 0.4, + 0.4, + 0.4 + ] + }, + blockLeft: { + 'rotation': [ + 0, + 225, + 0 + ], + 'translation': [ + 0, + 0, + 0 + ], + 'scale': [ + 0.4, + 0.4, + 0.4 + ] + } +} + +export default class HoldingBlock { + // TODO refactor with the tree builder for better visual understanding + holdingBlock: THREE.Object3D | undefined = undefined + blockSwapAnimation: { + switcher: SmoothSwitcher + // hidden: boolean + } | undefined = undefined + cameraGroup = new THREE.Mesh() + objectOuterGroup = new THREE.Group() // 3 + objectInnerGroup = new THREE.Group() // 4 + holdingBlockInnerGroup = new THREE.Group() // 5 + camera = new THREE.PerspectiveCamera(75, 1, 0.1, 100) + stopUpdate = false + lastHeldItem: HandItemBlock | undefined + isSwinging = false + nextIterStopCallbacks: Array<() => void> | undefined + idleAnimator: HandIdleAnimator | undefined + ready = false + lastUpdate = 0 + playerHand: THREE.Object3D | undefined + offHandDisplay = false + offHandModeLegacy = false + + swingAnimator: HandSwingAnimator | undefined + config: WorldRendererConfig + + constructor (public worldRenderer: WorldRendererThree, public offHand = false) { + this.initCameraGroup() + this.worldRenderer.onReactivePlayerStateUpdated('heldItemMain', () => { + if (!this.offHand) { + this.updateItem() + } + }, false) + this.worldRenderer.onReactivePlayerStateUpdated('heldItemOff', () => { + if (this.offHand) { + this.updateItem() + } + }, false) + this.config = worldRenderer.displayOptions.inWorldRenderingConfig + + this.offHandDisplay = this.offHand + // this.offHandDisplay = true + if (!this.offHand) { + // load default hand + void getMyHand().then((hand) => { + this.playerHand = hand + // trigger update + this.updateItem() + }).then(() => { + // now watch over the player skin + watchProperty( + async () => { + return getMyHand(this.worldRenderer.playerStateReactive.playerSkin, this.worldRenderer.playerStateReactive.onlineMode ? this.worldRenderer.playerStateReactive.username : undefined) + }, + this.worldRenderer.playerStateReactive, + 'playerSkin', + (newHand) => { + if (newHand) { + this.playerHand = newHand + // trigger update + this.updateItem() + } + }, + (oldHand) => { + disposeObject(oldHand!, true) + } + ) + }) + } + } + + updateItem () { + if (!this.ready) return + const item = this.offHand ? this.worldRenderer.playerStateReactive.heldItemOff : this.worldRenderer.playerStateReactive.heldItemMain + if (item) { + void this.setNewItem(item) + } else if (this.offHand) { + void this.setNewItem() + } else { + void this.setNewItem({ + type: 'hand', + }) + } + } + + initCameraGroup () { + this.cameraGroup = new THREE.Mesh() + } + + startSwing () { + this.swingAnimator?.startSwing() + } + + stopSwing () { + this.swingAnimator?.stopSwing() + } + + render (originalCamera: THREE.PerspectiveCamera, renderer: THREE.WebGLRenderer, ambientLight: THREE.AmbientLight, directionalLight: THREE.DirectionalLight) { + if (!this.lastHeldItem) return + const now = performance.now() + if (this.lastUpdate && now - this.lastUpdate > 50) { // one tick + void this.replaceItemModel(this.lastHeldItem) + } + + // Only update idle animation if not swinging + if (this.swingAnimator?.isCurrentlySwinging() || this.swingAnimator?.debugParams.animationStage) { + this.swingAnimator?.update() + } else { + this.idleAnimator?.update() + } + + this.blockSwapAnimation?.switcher.update() + + const scene = new THREE.Scene() + scene.add(this.cameraGroup) + // if (this.camera.aspect !== originalCamera.aspect) { + // this.camera.aspect = originalCamera.aspect + // this.camera.updateProjectionMatrix() + // } + this.updateCameraGroup() + scene.add(ambientLight.clone()) + scene.add(directionalLight.clone()) + + const viewerSize = renderer.getSize(new THREE.Vector2()) + const minSize = Math.min(viewerSize.width, viewerSize.height) + const x = viewerSize.width - minSize + + // Mirror the scene for offhand by scaling + const { offHandDisplay } = this + if (offHandDisplay) { + this.cameraGroup.scale.x = -1 + } + + renderer.autoClear = false + renderer.clearDepth() + if (this.offHandDisplay) { + renderer.setViewport(0, 0, minSize, minSize) + } else { + const x = viewerSize.width - minSize + // if (x) x -= x / 4 + renderer.setViewport(x, 0, minSize, minSize) + } + renderer.render(scene, this.camera) + renderer.setViewport(0, 0, viewerSize.width, viewerSize.height) + + // Reset the mirroring after rendering + if (offHandDisplay) { + this.cameraGroup.scale.x = 1 + } + } + + // worldTest () { + // const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshPhongMaterial({ color: 0x00_00_ff, transparent: true, opacity: 0.5 })) + // mesh.position.set(0.5, 0.5, 0.5) + // const group = new THREE.Group() + // group.add(mesh) + // group.position.set(-0.5, -0.5, -0.5) + // const outerGroup = new THREE.Group() + // outerGroup.add(group) + // outerGroup.position.set(this.camera.position.x, this.camera.position.y, this.camera.position.z) + // this.scene.add(outerGroup) + + // new tweenJs.Tween(group.rotation).to({ z: THREE.MathUtils.degToRad(90) }, 1000).yoyo(true).repeat(Infinity).start() + // } + + async playBlockSwapAnimation (forceState: 'appeared' | 'disappeared') { + this.blockSwapAnimation ??= { + switcher: new SmoothSwitcher( + () => ({ + y: this.objectInnerGroup.position.y + }), + (property, value) => { + if (property === 'y') this.objectInnerGroup.position.y = value + }, + { + y: 16 // units per second + } + ) + } + + const newState = forceState + // if (forceState && newState !== forceState) { + // throw new Error(`forceState does not match current state ${forceState} !== ${newState}`) + // } + + const targetY = this.objectInnerGroup.position.y + (this.objectInnerGroup.scale.y * 1.5 * (newState === 'appeared' ? 1 : -1)) + + // if (newState === this.blockSwapAnimation.switcher.transitioningToStateName) { + // return false + // } + + let cancelled = false + return new Promise((resolve) => { + this.blockSwapAnimation!.switcher.transitionTo( + { y: targetY }, + newState, + () => { + if (!cancelled) { + resolve(true) + } + }, + () => { + cancelled = true + resolve(false) + } + ) + }) + } + + isDifferentItem (block: HandItemBlock | undefined) { + const Item = PrismarineItem(this.worldRenderer.version) + if (!this.lastHeldItem) { + return true + } + if (this.lastHeldItem.name !== block?.name) { + return true + } + // eslint-disable-next-line sonarjs/prefer-single-boolean-return + if (!Item.equal(this.lastHeldItem.fullItem, block?.fullItem ?? {}) || JSON.stringify(this.lastHeldItem.fullItem.components) !== JSON.stringify(block?.fullItem?.components)) { + return true + } + + return false + } + + updateCameraGroup () { + if (this.stopUpdate) return + const { camera } = this + this.cameraGroup.position.copy(camera.position) + this.cameraGroup.rotation.copy(camera.rotation) + + // const viewerSize = viewer.renderer.getSize(new THREE.Vector2()) + // const aspect = viewerSize.width / viewerSize.height + const aspect = 1 + + + // Adjust the position based on the aspect ratio + const { position, scale: scaleData } = this.getHandHeld3d() + const distance = -position.z + const side = this.offHandModeLegacy ? -1 : 1 + this.objectOuterGroup.position.set( + distance * position.x * aspect * side, + distance * position.y, + -distance + ) + + // const scale = Math.min(0.8, Math.max(1, 1 * aspect)) + const scale = scaleData * 2.22 * 0.2 + this.objectOuterGroup.scale.set(scale, scale, scale) + } + + lastItemModelName: string | undefined + private async createItemModel (handItem: HandItemBlock): Promise<{ model: THREE.Object3D; type: 'hand' | 'block' | 'item' } | undefined> { + this.lastUpdate = performance.now() + if (!handItem || (handItem.type === 'hand' && !this.playerHand)) return undefined + + let blockInner: THREE.Object3D | undefined + if (handItem.type === 'item' || handItem.type === 'block') { + const result = this.worldRenderer.entities.getItemMesh({ + ...handItem.fullItem, + itemId: handItem.id, + }, { + 'minecraft:display_context': 'firstperson', + 'minecraft:use_duration': this.worldRenderer.playerStateReactive.itemUsageTicks, + 'minecraft:using_item': !!this.worldRenderer.playerStateReactive.itemUsageTicks, + }, false, this.lastItemModelName) + if (result) { + const { mesh: itemMesh, isBlock, modelName } = result + if (isBlock) { + blockInner = itemMesh + handItem.type = 'block' + } else { + itemMesh.position.set(0.5, 0.5, 0.5) + blockInner = itemMesh + handItem.type = 'item' + } + this.lastItemModelName = modelName + } + } else { + blockInner = this.playerHand! + } + if (!blockInner) return + blockInner.name = 'holdingBlock' + + const rotationDeg = this.getHandHeld3d().rotation + blockInner.rotation.x = THREE.MathUtils.degToRad(rotationDeg.x) + blockInner.rotation.y = THREE.MathUtils.degToRad(rotationDeg.y) + blockInner.rotation.z = THREE.MathUtils.degToRad(rotationDeg.z) + + return { model: blockInner, type: handItem.type } + } + + async replaceItemModel (handItem?: HandItemBlock): Promise { + // if switch animation is in progress, do not replace the item + if (this.blockSwapAnimation?.switcher.isTransitioning) return + + if (!handItem) { + this.holdingBlock?.removeFromParent() + this.holdingBlock = undefined + this.swingAnimator?.stopSwing() + this.swingAnimator = undefined + this.idleAnimator = undefined + return + } + + const result = await this.createItemModel(handItem) + if (!result) return + + // Update the model without changing the group structure + this.holdingBlock?.removeFromParent() + this.holdingBlock = result.model + this.holdingBlockInnerGroup.add(result.model) + + + } + + testUnknownBlockSwitch () { + void this.setNewItem({ + type: 'item', + name: 'minecraft:some-unknown-block', + id: 0, + fullItem: {} + }) + } + + switchRequest = 0 + async setNewItem (handItem?: HandItemBlock) { + if (!this.isDifferentItem(handItem)) return + this.lastItemModelName = undefined + const switchRequest = ++this.switchRequest + this.lastHeldItem = handItem + let playAppearAnimation = false + if (this.holdingBlock) { + // play disappear animation + playAppearAnimation = true + const result = await this.playBlockSwapAnimation('disappeared') + if (!result) return + this.holdingBlock?.removeFromParent() + this.holdingBlock = undefined + } + + if (!handItem) { + this.swingAnimator?.stopSwing() + this.swingAnimator = undefined + this.idleAnimator = undefined + this.blockSwapAnimation = undefined + return + } + + if (switchRequest !== this.switchRequest) return + const result = await this.createItemModel(handItem) + if (!result || switchRequest !== this.switchRequest) return + + const blockOuterGroup = new THREE.Group() + this.holdingBlockInnerGroup.removeFromParent() + this.holdingBlockInnerGroup = new THREE.Group() + this.holdingBlockInnerGroup.add(result.model) + blockOuterGroup.add(this.holdingBlockInnerGroup) + this.holdingBlock = result.model + this.objectInnerGroup = new THREE.Group() + this.objectInnerGroup.add(blockOuterGroup) + this.objectInnerGroup.position.set(-0.5, -0.5, -0.5) + if (playAppearAnimation) { + this.objectInnerGroup.position.y -= this.objectInnerGroup.scale.y * 1.5 + } + Object.assign(blockOuterGroup.position, { x: 0.5, y: 0.5, z: 0.5 }) + + this.objectOuterGroup = new THREE.Group() + this.objectOuterGroup.add(this.objectInnerGroup) + + this.cameraGroup.add(this.objectOuterGroup) + const rotationDeg = this.getHandHeld3d().rotation + this.objectOuterGroup.rotation.y = THREE.MathUtils.degToRad(rotationDeg.yOuter) + + if (playAppearAnimation) { + await this.playBlockSwapAnimation('appeared') + } + + this.swingAnimator = new HandSwingAnimator(this.holdingBlockInnerGroup) + this.swingAnimator.type = result.type + if (this.config.viewBobbing) { + this.idleAnimator = new HandIdleAnimator(this.holdingBlockInnerGroup, this.worldRenderer.playerStateReactive) + } + } + + getHandHeld3d () { + const type = this.lastHeldItem?.type ?? 'hand' + const side = this.offHandModeLegacy ? 'Left' : 'Right' + + let scale = 0.8 * 1.15 // default scale for hand + let position = { + x: 0.4, + y: -0.7, + z: -0.45 + } + let rotation = { + x: -32.4, + y: 42.8, + z: -41.3, + yOuter: 0 + } + + if (type === 'item') { + const itemData = rotationPositionData[`item${side}`] + position = { + x: -0.05, + y: -0.7, + z: -0.45 + } + rotation = { + x: itemData.rotation[0], + y: itemData.rotation[1], + z: itemData.rotation[2], + yOuter: 0 + } + scale = itemData.scale[0] * 1.15 + } else if (type === 'block') { + const blockData = rotationPositionData[`block${side}`] + position = { + x: 0.4, + y: -0.7, + z: -0.45 + } + rotation = { + x: blockData.rotation[0], + y: blockData.rotation[1], + z: blockData.rotation[2], + yOuter: 0 + } + scale = blockData.scale[0] * 1.15 + } + + return { + rotation, + position, + scale + } + } +} + +class HandIdleAnimator { + globalTime = 0 + lastTime = 0 + currentState: MovementState + targetState: MovementState + defaultPosition: { x: number; y: number; z: number; rotationX: number; rotationY: number; rotationZ: number } + private readonly idleOffset = { y: 0, rotationZ: 0 } + private readonly tween = new tweenJs.Group() + private idleTween: tweenJs.Tween<{ y: number; rotationZ: number }> | null = null + private readonly stateSwitcher: SmoothSwitcher + + // Debug parameters + private readonly debugParams = { + // Transition durations for different state changes + walkingSpeed: 8, + sprintingSpeed: 16, + walkingAmplitude: { x: 1 / 30, y: 1 / 10, rotationZ: 0.25 }, + sprintingAmplitude: { x: 1 / 30, y: 1 / 10, rotationZ: 0.4 } + } + + private readonly debugGui: DebugGui + + constructor (public handMesh: THREE.Object3D, public playerState: PlayerStateRenderer) { + this.handMesh = handMesh + this.globalTime = 0 + this.currentState = 'NOT_MOVING' + this.targetState = 'NOT_MOVING' + + this.defaultPosition = { + x: handMesh.position.x, + y: handMesh.position.y, + z: handMesh.position.z, + rotationX: handMesh.rotation.x, + rotationY: handMesh.rotation.y, + rotationZ: handMesh.rotation.z + } + + // Initialize state switcher with appropriate speeds + this.stateSwitcher = new SmoothSwitcher( + () => { + return { + x: this.handMesh.position.x, + y: this.handMesh.position.y, + z: this.handMesh.position.z, + rotationX: this.handMesh.rotation.x, + rotationY: this.handMesh.rotation.y, + rotationZ: this.handMesh.rotation.z + } + }, + (property, value) => { + switch (property) { + case 'x': this.handMesh.position.x = value; break + case 'y': this.handMesh.position.y = value; break + case 'z': this.handMesh.position.z = value; break + case 'rotationX': this.handMesh.rotation.x = value; break + case 'rotationY': this.handMesh.rotation.y = value; break + case 'rotationZ': this.handMesh.rotation.z = value; break + } + }, + { + x: 2, // units per second + y: 2, + z: 2, + rotation: Math.PI // radians per second + } + ) + + // Initialize debug GUI + this.debugGui = new DebugGui('idle_animator', this.debugParams) + // this.debugGui.activate() + } + + private startIdleAnimation () { + if (this.idleTween) { + this.idleTween.stop() + } + + // Start from current position for smooth transition + this.idleOffset.y = this.handMesh.position.y - this.defaultPosition.y + this.idleOffset.rotationZ = this.handMesh.rotation.z - this.defaultPosition.rotationZ + + this.idleTween = new tweenJs.Tween(this.idleOffset, this.tween) + .to({ + y: 0.05, + rotationZ: 0.05 + }, 3000) + .easing(tweenJs.Easing.Sinusoidal.InOut) + .yoyo(true) + .repeat(Infinity) + .start() + } + + private stopIdleAnimation () { + if (this.idleTween) { + this.idleTween.stop() + this.idleOffset.y = 0 + this.idleOffset.rotationZ = 0 + } + } + + private getStateTransform (state: MovementState, time: number) { + switch (state) { + case 'NOT_MOVING': + case 'SNEAKING': + return { + x: this.defaultPosition.x, + y: this.defaultPosition.y, + z: this.defaultPosition.z, + rotationX: this.defaultPosition.rotationX, + rotationY: this.defaultPosition.rotationY, + rotationZ: this.defaultPosition.rotationZ + } + case 'WALKING': + case 'SPRINTING': { + const speed = state === 'SPRINTING' ? this.debugParams.sprintingSpeed : this.debugParams.walkingSpeed + const amplitude = state === 'SPRINTING' ? this.debugParams.sprintingAmplitude : this.debugParams.walkingAmplitude + + return { + x: this.defaultPosition.x + Math.sin(time * speed) * amplitude.x, + y: this.defaultPosition.y - Math.abs(Math.cos(time * speed)) * amplitude.y, + z: this.defaultPosition.z, + rotationX: this.defaultPosition.rotationX, + rotationY: this.defaultPosition.rotationY, + // rotationZ: this.defaultPosition.rotationZ + Math.sin(time * speed) * amplitude.rotationZ + rotationZ: this.defaultPosition.rotationZ + } + } + } + } + + setState (newState: MovementState) { + if (newState === this.targetState) return + + this.targetState = newState + const noTransition = false + if (this.currentState !== newState) { + // Stop idle animation during state transitions + this.stopIdleAnimation() + + // Calculate new state transform + if (!noTransition) { + // this.globalTime = 0 + const stateTransform = this.getStateTransform(newState, this.globalTime) + + // Start transition to new state + this.stateSwitcher.transitionTo(stateTransform, newState) + // this.updated = false + } + this.currentState = newState + } + } + + updated = false + update () { + this.stateSwitcher.update() + + const now = performance.now() + const deltaTime = (now - this.lastTime) / 1000 + this.lastTime = now + + // Update global time based on current state + if (!this.stateSwitcher.isTransitioning) { + switch (this.currentState) { + case 'NOT_MOVING': + case 'SNEAKING': + this.globalTime = Math.PI / 4 + break + case 'SPRINTING': + case 'WALKING': + this.globalTime += deltaTime + break + } + } + + // Check for state changes from player state + if (this.playerState) { + const newState = this.playerState.movementState + if (newState !== this.targetState) { + this.setState(newState) + } + } + + // If we're not transitioning between states and in a stable state that should have idle animation + if (!this.stateSwitcher.isTransitioning && + (this.currentState === 'NOT_MOVING' || this.currentState === 'SNEAKING')) { + // Start idle animation if not already running + if (!this.idleTween?.isPlaying()) { + this.startIdleAnimation() + } + // Update idle animation + this.tween.update() + + // Apply idle offsets + this.handMesh.position.y = this.defaultPosition.y + this.idleOffset.y + this.handMesh.rotation.z = this.defaultPosition.rotationZ + this.idleOffset.rotationZ + } + + // If we're in a movement state and not transitioning, update the movement animation + if (!this.stateSwitcher.isTransitioning && + (this.currentState === 'WALKING' || this.currentState === 'SPRINTING')) { + const stateTransform = this.getStateTransform(this.currentState, this.globalTime) + Object.assign(this.handMesh.position, stateTransform) + Object.assign(this.handMesh.rotation, { + x: stateTransform.rotationX, + y: stateTransform.rotationY, + z: stateTransform.rotationZ + }) + // this.stateSwitcher.transitionTo(stateTransform, this.currentState) + } + } + + getCurrentState () { + return this.currentState + } + + destroy () { + this.stopIdleAnimation() + this.stateSwitcher.forceFinish() + } +} + +class HandSwingAnimator { + private readonly PI = Math.PI + private animationTimer = 0 + private lastTime = 0 + private isAnimating = false + private stopRequested = false + private readonly originalRotation: THREE.Euler + private readonly originalPosition: THREE.Vector3 + private readonly originalScale: THREE.Vector3 + + readonly debugParams = { + // Animation timing + animationTime: 250, + animationStage: 0, + useClassicSwing: true, + + // Item/Block animation parameters + itemSwingXPosScale: -0.8, + itemSwingYPosScale: 0.2, + itemSwingZPosScale: -0.2, + itemHeightScale: -0.6, + itemPreswingRotY: 45, + itemSwingXRotAmount: -30, + itemSwingYRotAmount: -35, + itemSwingZRotAmount: -5, + + // Hand/Arm animation parameters + armSwingXPosScale: -0.3, + armSwingYPosScale: 0.4, + armSwingZPosScale: -0.4, + armSwingYRotAmount: 70, + armSwingZRotAmount: -20, + armHeightScale: -0.6 + } + + private readonly debugGui: DebugGui + + public type: 'hand' | 'block' | 'item' = 'hand' + + constructor (public handMesh: THREE.Object3D) { + this.handMesh = handMesh + // Store initial transforms + this.originalRotation = handMesh.rotation.clone() + this.originalPosition = handMesh.position.clone() + this.originalScale = handMesh.scale.clone() + + // Initialize debug GUI + this.debugGui = new DebugGui('hand_animator', this.debugParams, undefined, { + animationStage: { + min: 0, + max: 1, + step: 0.01 + }, + // Add ranges for all animation parameters + itemSwingXPosScale: { min: -2, max: 2, step: 0.1 }, + itemSwingYPosScale: { min: -2, max: 2, step: 0.1 }, + itemSwingZPosScale: { min: -2, max: 2, step: 0.1 }, + itemHeightScale: { min: -2, max: 2, step: 0.1 }, + itemPreswingRotY: { min: -180, max: 180, step: 5 }, + itemSwingXRotAmount: { min: -180, max: 180, step: 5 }, + itemSwingYRotAmount: { min: -180, max: 180, step: 5 }, + itemSwingZRotAmount: { min: -180, max: 180, step: 5 }, + armSwingXPosScale: { min: -2, max: 2, step: 0.1 }, + armSwingYPosScale: { min: -2, max: 2, step: 0.1 }, + armSwingZPosScale: { min: -2, max: 2, step: 0.1 }, + armSwingYRotAmount: { min: -180, max: 180, step: 5 }, + armSwingZRotAmount: { min: -180, max: 180, step: 5 }, + armHeightScale: { min: -2, max: 2, step: 0.1 } + }) + // this.debugGui.activate() + } + + update () { + if (!this.isAnimating && !this.debugParams.animationStage) { + // If not animating, ensure we're at original position + this.handMesh.rotation.copy(this.originalRotation) + this.handMesh.position.copy(this.originalPosition) + this.handMesh.scale.copy(this.originalScale) + return + } + + const now = performance.now() + const deltaTime = (now - this.lastTime) / 1000 + this.lastTime = now + + // Update animation progress + this.animationTimer += deltaTime * 1000 // Convert to ms + + // Calculate animation stage (0 to 1) + const stage = this.debugParams.animationStage || Math.min(this.animationTimer / this.debugParams.animationTime, 1) + + if (stage >= 1) { + // Animation complete + if (this.stopRequested) { + // If stop was requested, actually stop now that we've completed a swing + this.isAnimating = false + this.stopRequested = false + this.animationTimer = 0 + this.handMesh.rotation.copy(this.originalRotation) + this.handMesh.position.copy(this.originalPosition) + this.handMesh.scale.copy(this.originalScale) + return + } + // Otherwise reset timer and continue + this.animationTimer = 0 + return + } + + // Start from original transforms + this.handMesh.rotation.copy(this.originalRotation) + this.handMesh.position.copy(this.originalPosition) + this.handMesh.scale.copy(this.originalScale) + + // Calculate swing progress + const swingProgress = stage + const sqrtProgress = Math.sqrt(swingProgress) + const sinProgress = Math.sin(swingProgress * this.PI) + const sinSqrtProgress = Math.sin(sqrtProgress * this.PI) + + if (this.type === 'hand') { + // Hand animation + const xOffset = this.debugParams.armSwingXPosScale * sinSqrtProgress + const yOffset = this.debugParams.armSwingYPosScale * Math.sin(sqrtProgress * this.PI * 2) + const zOffset = this.debugParams.armSwingZPosScale * sinProgress + + this.handMesh.position.x += xOffset + this.handMesh.position.y += yOffset + this.debugParams.armHeightScale * swingProgress + this.handMesh.position.z += zOffset + + // Rotations + this.handMesh.rotation.y += THREE.MathUtils.degToRad(this.debugParams.armSwingYRotAmount * sinSqrtProgress) + this.handMesh.rotation.z += THREE.MathUtils.degToRad(this.debugParams.armSwingZRotAmount * sinProgress) + } else { + // Item/Block animation + const xOffset = this.debugParams.itemSwingXPosScale * sinSqrtProgress + const yOffset = this.debugParams.itemSwingYPosScale * Math.sin(sqrtProgress * this.PI * 2) + const zOffset = this.debugParams.itemSwingZPosScale * sinProgress + + this.handMesh.position.x += xOffset + this.handMesh.position.y += yOffset + this.debugParams.itemHeightScale * swingProgress + this.handMesh.position.z += zOffset + + // Pre-swing rotation + this.handMesh.rotation.y += THREE.MathUtils.degToRad(this.debugParams.itemPreswingRotY) + + // Swing rotations + this.handMesh.rotation.x += THREE.MathUtils.degToRad(this.debugParams.itemSwingXRotAmount * sinProgress) + this.handMesh.rotation.y += THREE.MathUtils.degToRad(this.debugParams.itemSwingYRotAmount * sinSqrtProgress) + this.handMesh.rotation.z += THREE.MathUtils.degToRad(this.debugParams.itemSwingZRotAmount * sinProgress) + } + } + + startSwing () { + this.stopRequested = false + if (this.isAnimating) return + + this.isAnimating = true + this.animationTimer = 0 + this.lastTime = performance.now() + } + + stopSwing () { + if (!this.isAnimating) return + this.stopRequested = true + } + + isCurrentlySwinging () { + return this.isAnimating + } +} + +export const getBlockMeshFromModel = (material: THREE.Material, model: BlockModel, name: string, blockProvider: WorldBlockProvider) => { + const worldRenderModel = blockProvider.transformModel(model, { + name, + properties: {} + }) as any + return getThreeBlockModelGroup(material, [[worldRenderModel]], undefined, 'plains', loadedData) +} diff --git a/renderer/viewer/three/itemMesh.ts b/renderer/viewer/three/itemMesh.ts new file mode 100644 index 00000000..3fa069b9 --- /dev/null +++ b/renderer/viewer/three/itemMesh.ts @@ -0,0 +1,427 @@ +import * as THREE from 'three' + +export interface Create3DItemMeshOptions { + depth: number + pixelSize?: number +} + +export interface Create3DItemMeshResult { + geometry: THREE.BufferGeometry + totalVertices: number + totalTriangles: number +} + +/** + * Creates a 3D item geometry with front/back faces and connecting edges + * from a canvas containing the item texture + */ +export function create3DItemMesh ( + canvas: HTMLCanvasElement, + options: Create3DItemMeshOptions +): Create3DItemMeshResult { + const { depth, pixelSize } = options + + // Validate canvas dimensions + if (canvas.width <= 0 || canvas.height <= 0) { + throw new Error(`Invalid canvas dimensions: ${canvas.width}x${canvas.height}`) + } + + const ctx = canvas.getContext('2d')! + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height) + const { data } = imageData + + const w = canvas.width + const h = canvas.height + const halfDepth = depth / 2 + const actualPixelSize = pixelSize ?? (1 / Math.max(w, h)) + + // Find opaque pixels + const isOpaque = (x: number, y: number) => { + if (x < 0 || y < 0 || x >= w || y >= h) return false + const i = (y * w + x) * 4 + return data[i + 3] > 128 // alpha > 128 + } + + const vertices: number[] = [] + const indices: number[] = [] + const uvs: number[] = [] + const normals: number[] = [] + + let vertexIndex = 0 + + // Helper to add a vertex + const addVertex = (x: number, y: number, z: number, u: number, v: number, nx: number, ny: number, nz: number) => { + vertices.push(x, y, z) + uvs.push(u, v) + normals.push(nx, ny, nz) + return vertexIndex++ + } + + // Helper to add a quad (two triangles) + const addQuad = (v0: number, v1: number, v2: number, v3: number) => { + indices.push(v0, v1, v2, v0, v2, v3) + } + + // Convert pixel coordinates to world coordinates + const pixelToWorld = (px: number, py: number) => { + const x = (px / w - 0.5) * actualPixelSize * w + const y = -(py / h - 0.5) * actualPixelSize * h + return { x, y } + } + + // Create a grid of vertices for front and back faces + const frontVertices: Array> = Array.from({ length: h + 1 }, () => Array.from({ length: w + 1 }, () => null)) + const backVertices: Array> = Array.from({ length: h + 1 }, () => Array.from({ length: w + 1 }, () => null)) + + // Create vertices at pixel corners + for (let py = 0; py <= h; py++) { + for (let px = 0; px <= w; px++) { + const { x, y } = pixelToWorld(px - 0.5, py - 0.5) + + // UV coordinates should map to the texture space of the extracted tile + const u = px / w + const v = py / h + + // Check if this vertex is needed for any face or edge + let needVertex = false + + // Check all 4 adjacent pixels to see if any are opaque + const adjacentPixels = [ + [px - 1, py - 1], // top-left pixel + [px, py - 1], // top-right pixel + [px - 1, py], // bottom-left pixel + [px, py] // bottom-right pixel + ] + + for (const [adjX, adjY] of adjacentPixels) { + if (isOpaque(adjX, adjY)) { + needVertex = true + break + } + } + + if (needVertex) { + frontVertices[py][px] = addVertex(x, y, halfDepth, u, v, 0, 0, 1) + backVertices[py][px] = addVertex(x, y, -halfDepth, u, v, 0, 0, -1) + } + } + } + + // Create front and back faces + for (let py = 0; py < h; py++) { + for (let px = 0; px < w; px++) { + if (!isOpaque(px, py)) continue + + const v00 = frontVertices[py][px] + const v10 = frontVertices[py][px + 1] + const v11 = frontVertices[py + 1][px + 1] + const v01 = frontVertices[py + 1][px] + + const b00 = backVertices[py][px] + const b10 = backVertices[py][px + 1] + const b11 = backVertices[py + 1][px + 1] + const b01 = backVertices[py + 1][px] + + if (v00 !== null && v10 !== null && v11 !== null && v01 !== null) { + // Front face + addQuad(v00, v10, v11, v01) + } + + if (b00 !== null && b10 !== null && b11 !== null && b01 !== null) { + // Back face (reversed winding) + addQuad(b10, b00, b01, b11) + } + } + } + + // Create edge faces for each side of the pixel with proper UVs + for (let py = 0; py < h; py++) { + for (let px = 0; px < w; px++) { + if (!isOpaque(px, py)) continue + + const pixelU = (px + 0.5) / w // Center of current pixel + const pixelV = (py + 0.5) / h + + // Left edge (x = px) + if (!isOpaque(px - 1, py)) { + const f0 = frontVertices[py][px] + const f1 = frontVertices[py + 1][px] + const b0 = backVertices[py][px] + const b1 = backVertices[py + 1][px] + + if (f0 !== null && f1 !== null && b0 !== null && b1 !== null) { + // Create new vertices for edge with current pixel's UV + const ef0 = addVertex(vertices[f0 * 3], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2], pixelU, pixelV, -1, 0, 0) + const ef1 = addVertex(vertices[f1 * 3], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2], pixelU, pixelV, -1, 0, 0) + const eb1 = addVertex(vertices[b1 * 3], vertices[b1 * 3 + 1], vertices[b1 * 3 + 2], pixelU, pixelV, -1, 0, 0) + const eb0 = addVertex(vertices[b0 * 3], vertices[b0 * 3 + 1], vertices[b0 * 3 + 2], pixelU, pixelV, -1, 0, 0) + addQuad(ef0, ef1, eb1, eb0) + } + } + + // Right edge (x = px + 1) + if (!isOpaque(px + 1, py)) { + const f0 = frontVertices[py + 1][px + 1] + const f1 = frontVertices[py][px + 1] + const b0 = backVertices[py + 1][px + 1] + const b1 = backVertices[py][px + 1] + + if (f0 !== null && f1 !== null && b0 !== null && b1 !== null) { + const ef0 = addVertex(vertices[f0 * 3], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2], pixelU, pixelV, 1, 0, 0) + const ef1 = addVertex(vertices[f1 * 3], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2], pixelU, pixelV, 1, 0, 0) + const eb1 = addVertex(vertices[b1 * 3], vertices[b1 * 3 + 1], vertices[b1 * 3 + 2], pixelU, pixelV, 1, 0, 0) + const eb0 = addVertex(vertices[b0 * 3], vertices[b0 * 3 + 1], vertices[b0 * 3 + 2], pixelU, pixelV, 1, 0, 0) + addQuad(ef0, ef1, eb1, eb0) + } + } + + // Top edge (y = py) + if (!isOpaque(px, py - 1)) { + const f0 = frontVertices[py][px] + const f1 = frontVertices[py][px + 1] + const b0 = backVertices[py][px] + const b1 = backVertices[py][px + 1] + + if (f0 !== null && f1 !== null && b0 !== null && b1 !== null) { + const ef0 = addVertex(vertices[f0 * 3], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2], pixelU, pixelV, 0, -1, 0) + const ef1 = addVertex(vertices[f1 * 3], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2], pixelU, pixelV, 0, -1, 0) + const eb1 = addVertex(vertices[b1 * 3], vertices[b1 * 3 + 1], vertices[b1 * 3 + 2], pixelU, pixelV, 0, -1, 0) + const eb0 = addVertex(vertices[b0 * 3], vertices[b0 * 3 + 1], vertices[b0 * 3 + 2], pixelU, pixelV, 0, -1, 0) + addQuad(ef0, ef1, eb1, eb0) + } + } + + // Bottom edge (y = py + 1) + if (!isOpaque(px, py + 1)) { + const f0 = frontVertices[py + 1][px + 1] + const f1 = frontVertices[py + 1][px] + const b0 = backVertices[py + 1][px + 1] + const b1 = backVertices[py + 1][px] + + if (f0 !== null && f1 !== null && b0 !== null && b1 !== null) { + const ef0 = addVertex(vertices[f0 * 3], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2], pixelU, pixelV, 0, 1, 0) + const ef1 = addVertex(vertices[f1 * 3], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2], pixelU, pixelV, 0, 1, 0) + const eb1 = addVertex(vertices[b1 * 3], vertices[b1 * 3 + 1], vertices[b1 * 3 + 2], pixelU, pixelV, 0, 1, 0) + const eb0 = addVertex(vertices[b0 * 3], vertices[b0 * 3 + 1], vertices[b0 * 3 + 2], pixelU, pixelV, 0, 1, 0) + addQuad(ef0, ef1, eb1, eb0) + } + } + } + } + + const geometry = new THREE.BufferGeometry() + geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)) + geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2)) + geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3)) + geometry.setIndex(indices) + + // Compute normals properly + geometry.computeVertexNormals() + + return { + geometry, + totalVertices: vertexIndex, + totalTriangles: indices.length / 3 + } +} + +export interface ItemTextureInfo { + u: number + v: number + sizeX: number + sizeY: number +} + +export interface ItemMeshResult { + mesh: THREE.Object3D + itemsTexture?: THREE.Texture + itemsTextureFlipped?: THREE.Texture + cleanup?: () => void +} + +/** + * Extracts item texture region to a canvas + */ +export function extractItemTextureToCanvas ( + sourceTexture: THREE.Texture, + textureInfo: ItemTextureInfo +): HTMLCanvasElement { + const { u, v, sizeX, sizeY } = textureInfo + + // Calculate canvas size - fix the calculation + const canvasWidth = Math.max(1, Math.floor(sizeX * sourceTexture.image.width)) + const canvasHeight = Math.max(1, Math.floor(sizeY * sourceTexture.image.height)) + + const canvas = document.createElement('canvas') + canvas.width = canvasWidth + canvas.height = canvasHeight + + const ctx = canvas.getContext('2d')! + ctx.imageSmoothingEnabled = false + + // Draw the item texture region to canvas + ctx.drawImage( + sourceTexture.image, + u * sourceTexture.image.width, + v * sourceTexture.image.height, + sizeX * sourceTexture.image.width, + sizeY * sourceTexture.image.height, + 0, + 0, + canvas.width, + canvas.height + ) + + return canvas +} + +/** + * Creates either a 2D or 3D item mesh based on parameters + */ +export function createItemMesh ( + sourceTexture: THREE.Texture, + textureInfo: ItemTextureInfo, + options: { + faceCamera?: boolean + use3D?: boolean + depth?: number + } = {} +): ItemMeshResult { + const { faceCamera = false, use3D = true, depth = 0.04 } = options + const { u, v, sizeX, sizeY } = textureInfo + + if (faceCamera) { + // Create sprite for camera-facing items + const itemsTexture = sourceTexture.clone() + itemsTexture.flipY = true + itemsTexture.offset.set(u, 1 - v - sizeY) + itemsTexture.repeat.set(sizeX, sizeY) + itemsTexture.needsUpdate = true + itemsTexture.magFilter = THREE.NearestFilter + itemsTexture.minFilter = THREE.NearestFilter + + const spriteMat = new THREE.SpriteMaterial({ + map: itemsTexture, + transparent: true, + alphaTest: 0.1, + }) + const mesh = new THREE.Sprite(spriteMat) + + return { + mesh, + itemsTexture, + cleanup () { + itemsTexture.dispose() + } + } + } + + if (use3D) { + // Try to create 3D mesh + try { + const canvas = extractItemTextureToCanvas(sourceTexture, textureInfo) + const { geometry } = create3DItemMesh(canvas, { depth }) + + // Create texture from canvas for the 3D mesh + const itemsTexture = new THREE.CanvasTexture(canvas) + itemsTexture.magFilter = THREE.NearestFilter + itemsTexture.minFilter = THREE.NearestFilter + itemsTexture.wrapS = itemsTexture.wrapT = THREE.ClampToEdgeWrapping + itemsTexture.flipY = false + itemsTexture.needsUpdate = true + + const material = new THREE.MeshStandardMaterial({ + map: itemsTexture, + side: THREE.DoubleSide, + transparent: true, + alphaTest: 0.1, + }) + + const mesh = new THREE.Mesh(geometry, material) + + return { + mesh, + itemsTexture, + cleanup () { + itemsTexture.dispose() + geometry.dispose() + if (material.map) material.map.dispose() + material.dispose() + } + } + } catch (error) { + console.warn('Failed to create 3D item mesh, falling back to 2D:', error) + // Fall through to 2D rendering + } + } + + // Fallback to 2D flat rendering + const itemsTexture = sourceTexture.clone() + itemsTexture.flipY = true + itemsTexture.offset.set(u, 1 - v - sizeY) + itemsTexture.repeat.set(sizeX, sizeY) + itemsTexture.needsUpdate = true + itemsTexture.magFilter = THREE.NearestFilter + itemsTexture.minFilter = THREE.NearestFilter + + const itemsTextureFlipped = itemsTexture.clone() + itemsTextureFlipped.repeat.x *= -1 + itemsTextureFlipped.needsUpdate = true + itemsTextureFlipped.offset.set(u + sizeX, 1 - v - sizeY) + + const material = new THREE.MeshStandardMaterial({ + map: itemsTexture, + transparent: true, + alphaTest: 0.1, + }) + const materialFlipped = new THREE.MeshStandardMaterial({ + map: itemsTextureFlipped, + transparent: true, + alphaTest: 0.1, + }) + const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 0), [ + new THREE.MeshBasicMaterial({ color: 0x00_00_00 }), new THREE.MeshBasicMaterial({ color: 0x00_00_00 }), + new THREE.MeshBasicMaterial({ color: 0x00_00_00 }), new THREE.MeshBasicMaterial({ color: 0x00_00_00 }), + material, materialFlipped, + ]) + + return { + mesh, + itemsTexture, + itemsTextureFlipped, + cleanup () { + itemsTexture.dispose() + itemsTextureFlipped.dispose() + material.dispose() + materialFlipped.dispose() + } + } +} + +/** + * Creates a complete 3D item mesh from a canvas texture + */ +export function createItemMeshFromCanvas ( + canvas: HTMLCanvasElement, + options: Create3DItemMeshOptions +): THREE.Mesh { + const { geometry } = create3DItemMesh(canvas, options) + + // Base color texture for the item + const colorTexture = new THREE.CanvasTexture(canvas) + colorTexture.magFilter = THREE.NearestFilter + colorTexture.minFilter = THREE.NearestFilter + colorTexture.wrapS = colorTexture.wrapT = THREE.ClampToEdgeWrapping + colorTexture.flipY = false // Important for canvas textures + colorTexture.needsUpdate = true + + // Material - no transparency, no alpha test needed for edges + const material = new THREE.MeshBasicMaterial({ + map: colorTexture, + side: THREE.DoubleSide, + transparent: true, + alphaTest: 0.1 + }) + + return new THREE.Mesh(geometry, material) +} diff --git a/renderer/viewer/three/panorama.ts b/renderer/viewer/three/panorama.ts new file mode 100644 index 00000000..254b980c --- /dev/null +++ b/renderer/viewer/three/panorama.ts @@ -0,0 +1,302 @@ +import { join } from 'path' +import * as THREE from 'three' +import { getSyncWorld } from 'renderer/playground/shared' +import { Vec3 } from 'vec3' +import * as tweenJs from '@tweenjs/tween.js' +import type { GraphicsInitOptions } from '../../../src/appViewer' +import { WorldDataEmitter } from '../lib/worldDataEmitter' +import { defaultWorldRendererConfig, WorldRendererCommon } from '../lib/worldrendererCommon' +import { getDefaultRendererState } from '../baseGraphicsBackend' +import { ResourcesManager } from '../../../src/resourcesManager' +import { getInitialPlayerStateRenderer } from '../lib/basePlayerState' +import { loadThreeJsTextureFromUrl, loadThreeJsTextureFromUrlSync } from './threeJsUtils' +import { WorldRendererThree } from './worldrendererThree' +import { EntityMesh } from './entity/EntityMesh' +import { DocumentRenderer } from './documentRenderer' +import { PANORAMA_VERSION } from './panoramaShared' + +const panoramaFiles = [ + 'panorama_3.png', // right (+x) + 'panorama_1.png', // left (-x) + 'panorama_4.png', // top (+y) + 'panorama_5.png', // bottom (-y) + 'panorama_0.png', // front (+z) + 'panorama_2.png', // back (-z) +] + +export class PanoramaRenderer { + private readonly camera: THREE.PerspectiveCamera + private scene: THREE.Scene + private readonly ambientLight: THREE.AmbientLight + private readonly directionalLight: THREE.DirectionalLight + private panoramaGroup: THREE.Object3D | null = null + private time = 0 + private readonly abortController = new AbortController() + private worldRenderer: WorldRendererCommon | WorldRendererThree | undefined + public WorldRendererClass = WorldRendererThree + public startTimes = new Map() + + constructor (private readonly documentRenderer: DocumentRenderer, private readonly options: GraphicsInitOptions, private readonly doWorldBlocksPanorama = false) { + this.scene = new THREE.Scene() + // #324568 + this.scene.background = new THREE.Color(0x32_45_68) + + // Add ambient light + this.ambientLight = new THREE.AmbientLight(0xcc_cc_cc) + this.scene.add(this.ambientLight) + + // Add directional light + this.directionalLight = new THREE.DirectionalLight(0xff_ff_ff, 0.5) + this.directionalLight.position.set(1, 1, 0.5).normalize() + this.directionalLight.castShadow = true + this.scene.add(this.directionalLight) + + this.camera = new THREE.PerspectiveCamera(85, this.documentRenderer.canvas.width / this.documentRenderer.canvas.height, 0.05, 1000) + this.camera.position.set(0, 0, 0) + this.camera.rotation.set(0, 0, 0) + } + + async start () { + if (this.doWorldBlocksPanorama) { + await this.worldBlocksPanorama() + } else { + this.addClassicPanorama() + } + + + this.documentRenderer.render = (sizeChanged = false) => { + if (sizeChanged) { + this.camera.aspect = this.documentRenderer.canvas.width / this.documentRenderer.canvas.height + this.camera.updateProjectionMatrix() + } + this.documentRenderer.renderer.render(this.scene, this.camera) + } + } + + async debugImageInFrontOfCamera () { + const image = await loadThreeJsTextureFromUrl(join('background', 'panorama_0.png')) + const mesh = new THREE.Mesh(new THREE.PlaneGeometry(1000, 1000), new THREE.MeshBasicMaterial({ map: image })) + mesh.position.set(0, 0, -500) + mesh.rotation.set(0, 0, 0) + this.scene.add(mesh) + } + + addClassicPanorama () { + const panorGeo = new THREE.BoxGeometry(1000, 1000, 1000) + const panorMaterials = [] as THREE.MeshBasicMaterial[] + const fadeInDuration = 200 + + // void this.debugImageInFrontOfCamera() + + for (const file of panoramaFiles) { + const load = async () => { + const { texture } = loadThreeJsTextureFromUrlSync(join('background', file)) + + // Instead of using repeat/offset to flip, we'll use the texture matrix + texture.matrixAutoUpdate = false + texture.matrix.set( + -1, 0, 1, 0, 1, 0, 0, 0, 1 + ) + + texture.wrapS = THREE.ClampToEdgeWrapping + texture.wrapT = THREE.ClampToEdgeWrapping + texture.minFilter = THREE.LinearFilter + texture.magFilter = THREE.LinearFilter + + const material = new THREE.MeshBasicMaterial({ + map: texture, + transparent: true, + side: THREE.DoubleSide, + depthWrite: false, + opacity: 0 // Start with 0 opacity + }) + + // Start fade-in when texture is loaded + this.startTimes.set(material, Date.now()) + panorMaterials.push(material) + } + + void load() + } + + const panoramaBox = new THREE.Mesh(panorGeo, panorMaterials) + panoramaBox.onBeforeRender = () => { + this.time += 0.01 + panoramaBox.rotation.y = Math.PI + this.time * 0.01 + panoramaBox.rotation.z = Math.sin(-this.time * 0.001) * 0.001 + + // Time-based fade in animation for each material + for (const material of panorMaterials) { + const startTime = this.startTimes.get(material) + if (startTime) { + const elapsed = Date.now() - startTime + const progress = Math.min(1, elapsed / fadeInDuration) + material.opacity = progress + } + } + } + + const group = new THREE.Object3D() + group.add(panoramaBox) + + // Add squids + for (let i = 0; i < 20; i++) { + const m = new EntityMesh('1.16.4', 'squid').mesh + m.position.set(Math.random() * 30 - 15, Math.random() * 20 - 10, Math.random() * 10 - 17) + m.rotation.set(0, Math.PI + Math.random(), -Math.PI / 4, 'ZYX') + const v = Math.random() * 0.01 + m.children[0].onBeforeRender = () => { + m.rotation.y += v + m.rotation.z = Math.cos(panoramaBox.rotation.y * 3) * Math.PI / 4 - Math.PI / 2 + } + group.add(m) + } + + this.scene.add(group) + this.panoramaGroup = group + } + + async worldBlocksPanorama () { + const version = PANORAMA_VERSION + const fullResourceManager = this.options.resourcesManager as ResourcesManager + fullResourceManager.currentConfig = { version, noInventoryGui: true, } + await fullResourceManager.updateAssetsData({ }) + if (this.abortController.signal.aborted) return + console.time('load panorama scene') + const world = getSyncWorld(version) + const PrismarineBlock = require('prismarine-block') + const Block = PrismarineBlock(version) + const fullBlocks = loadedData.blocksArray.filter(block => { + // if (block.name.includes('leaves')) return false + if (/* !block.name.includes('wool') && */!block.name.includes('stained_glass')/* && !block.name.includes('terracotta') */) return false + const b = Block.fromStateId(block.defaultState, 0) + if (b.shapes?.length !== 1) return false + const shape = b.shapes[0] + return shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1 + }) + const Z = -15 + const sizeX = 100 + const sizeY = 100 + for (let x = -sizeX; x < sizeX; x++) { + for (let y = -sizeY; y < sizeY; y++) { + const block = fullBlocks[Math.floor(Math.random() * fullBlocks.length)] + world.setBlockStateId(new Vec3(x, y, Z), block.defaultState) + } + } + this.camera.updateProjectionMatrix() + this.camera.position.set(0.5, sizeY / 2 + 0.5, 0.5) + this.camera.rotation.set(0, 0, 0) + const initPos = new Vec3(...this.camera.position.toArray()) + const worldView = new WorldDataEmitter(world, 2, initPos) + // worldView.addWaitTime = 0 + if (this.abortController.signal.aborted) return + + this.worldRenderer = new this.WorldRendererClass( + this.documentRenderer.renderer, + this.options, + { + version, + worldView, + inWorldRenderingConfig: defaultWorldRendererConfig, + playerStateReactive: getInitialPlayerStateRenderer().reactive, + rendererState: getDefaultRendererState().reactive, + nonReactiveState: getDefaultRendererState().nonReactive + } + ) + if (this.worldRenderer instanceof WorldRendererThree) { + this.scene = this.worldRenderer.scene + } + void worldView.init(initPos) + + await this.worldRenderer.waitForChunksToRender() + if (this.abortController.signal.aborted) return + // add small camera rotation to side on mouse move depending on absolute position of the cursor + const { camera } = this + const initX = camera.position.x + const initY = camera.position.y + let prevTwin: tweenJs.Tween | undefined + document.body.addEventListener('pointermove', (e) => { + if (e.pointerType !== 'mouse') return + const pos = new THREE.Vector2(e.clientX, e.clientY) + const SCALE = 0.2 + /* -0.5 - 0.5 */ + const xRel = pos.x / window.innerWidth - 0.5 + const yRel = -(pos.y / window.innerHeight - 0.5) + prevTwin?.stop() + const to = { + x: initX + (xRel * SCALE), + y: initY + (yRel * SCALE) + } + prevTwin = new tweenJs.Tween(camera.position).to(to, 0) // todo use the number depending on diff // todo use the number depending on diff + // prevTwin.easing(tweenJs.Easing.Exponential.InOut) + prevTwin.start() + camera.updateProjectionMatrix() + }, { + signal: this.abortController.signal + }) + + console.timeEnd('load panorama scene') + } + + dispose () { + this.scene.clear() + this.worldRenderer?.destroy() + this.abortController.abort() + } +} + +// export class ClassicPanoramaRenderer { +// panoramaGroup: THREE.Object3D + +// constructor (private readonly backgroundFiles: string[], onRender: Array<(sizeChanged: boolean) => void>, addSquids = true) { +// const panorGeo = new THREE.BoxGeometry(1000, 1000, 1000) +// const loader = new THREE.TextureLoader() +// const panorMaterials = [] as THREE.MeshBasicMaterial[] + +// for (const file of this.backgroundFiles) { +// const texture = loader.load(file) + +// // Instead of using repeat/offset to flip, we'll use the texture matrix +// texture.matrixAutoUpdate = false +// texture.matrix.set( +// -1, 0, 1, 0, 1, 0, 0, 0, 1 +// ) + +// texture.wrapS = THREE.ClampToEdgeWrapping // Changed from RepeatWrapping +// texture.wrapT = THREE.ClampToEdgeWrapping // Changed from RepeatWrapping +// texture.minFilter = THREE.LinearFilter +// texture.magFilter = THREE.LinearFilter + +// panorMaterials.push(new THREE.MeshBasicMaterial({ +// map: texture, +// transparent: true, +// side: THREE.DoubleSide, +// depthWrite: false, +// })) +// } + +// const panoramaBox = new THREE.Mesh(panorGeo, panorMaterials) +// panoramaBox.onBeforeRender = () => { +// } + +// const group = new THREE.Object3D() +// group.add(panoramaBox) + +// if (addSquids) { +// // Add squids +// for (let i = 0; i < 20; i++) { +// const m = new EntityMesh('1.16.4', 'squid').mesh +// m.position.set(Math.random() * 30 - 15, Math.random() * 20 - 10, Math.random() * 10 - 17) +// m.rotation.set(0, Math.PI + Math.random(), -Math.PI / 4, 'ZYX') +// const v = Math.random() * 0.01 +// onRender.push(() => { +// m.rotation.y += v +// m.rotation.z = Math.cos(panoramaBox.rotation.y * 3) * Math.PI / 4 - Math.PI / 2 +// }) +// group.add(m) +// } +// } + +// this.panoramaGroup = group +// } +// } diff --git a/renderer/viewer/three/panoramaShared.ts b/renderer/viewer/three/panoramaShared.ts new file mode 100644 index 00000000..ad80367f --- /dev/null +++ b/renderer/viewer/three/panoramaShared.ts @@ -0,0 +1 @@ +export const PANORAMA_VERSION = '1.21.4' diff --git a/prismarine-viewer/viewer/lib/primitives.js b/renderer/viewer/three/primitives.js similarity index 95% rename from prismarine-viewer/viewer/lib/primitives.js rename to renderer/viewer/three/primitives.js index c8a0c006..08c1c49e 100644 --- a/prismarine-viewer/viewer/lib/primitives.js +++ b/renderer/viewer/three/primitives.js @@ -1,7 +1,9 @@ +/* eslint-disable unicorn/no-abusive-eslint-disable */ +/* eslint-disable */ const THREE = require('three') const { MeshLine, MeshLineMaterial } = require('three.meshline') -function getMesh (primitive, camera) { +function getMesh(primitive, camera) { if (primitive.type === 'line') { const color = primitive.color ? primitive.color : 0xff0000 const resolution = new THREE.Vector2(window.innerWidth / camera.zoom, window.innerHeight / camera.zoom) @@ -53,7 +55,7 @@ class Primitives { this.primitives = {} } - clear () { + clear() { for (const mesh of Object.values(this.primitives)) { this.scene.remove(mesh) disposeObject(mesh) @@ -61,7 +63,7 @@ class Primitives { this.primitives = {} } - update (primitive) { + update(primitive) { if (this.primitives[primitive.id]) { this.scene.remove(this.primitives[primitive.id]) disposeObject(this.primitives[primitive.id]) @@ -75,7 +77,7 @@ class Primitives { } } -function GridBoxGeometry (geometry, independent) { +function GridBoxGeometry(geometry, independent) { if (!(geometry instanceof THREE.BoxBufferGeometry)) { console.log("GridBoxGeometry: the parameter 'geometry' has to be of the type THREE.BoxBufferGeometry") return geometry @@ -113,7 +115,7 @@ function GridBoxGeometry (geometry, independent) { newGeometry.setIndex(fullIndices) - function indexSide (x, y, shift) { + function indexSide(x, y, shift) { const indices = [] for (let i = 0; i < y + 1; i++) { let index11 = 0 diff --git a/renderer/viewer/three/renderSlot.ts b/renderer/viewer/three/renderSlot.ts new file mode 100644 index 00000000..321633eb --- /dev/null +++ b/renderer/viewer/three/renderSlot.ts @@ -0,0 +1,82 @@ +import { getRenamedData } from 'flying-squid/dist/blockRenames' +import { BlockModel } from 'mc-assets' +import { versionToNumber } from 'mc-assets/dist/utils' +import type { ResourcesManagerCommon } from '../../../src/resourcesManager' + +export type ResolvedItemModelRender = { + modelName: string, + originalItemName?: string +} + +export const renderSlot = (model: ResolvedItemModelRender, resourcesManager: ResourcesManagerCommon, debugIsQuickbar = false, fullBlockModelSupport = false): { + texture: string, + blockData: Record & { resolvedModel: BlockModel } | null, + scale: number | null, + slice: number[] | null, + modelName: string | null, +} => { + let itemModelName = model.modelName + const isItem = loadedData.itemsByName[itemModelName] + + // #region normalize item name + if (versionToNumber(bot.version) < versionToNumber('1.13')) itemModelName = getRenamedData(isItem ? 'items' : 'blocks', itemModelName, bot.version, '1.13.1') as string + // #endregion + + + let itemTexture + + if (!fullBlockModelSupport) { + const atlas = resourcesManager.currentResources?.guiAtlas?.json + // todo atlas holds all rendered blocks, not all possibly rendered item/block models, need to request this on demand instead (this is how vanilla works) + const tryGetAtlasTexture = (name?: string) => name && atlas?.textures[name.replace('minecraft:', '').replace('block/', '').replace('blocks/', '').replace('item/', '').replace('items/', '').replace('_inventory', '')] + const item = tryGetAtlasTexture(itemModelName) ?? tryGetAtlasTexture(model.originalItemName) + if (item) { + const x = item.u * atlas.width + const y = item.v * atlas.height + return { + texture: 'gui', + slice: [x, y, atlas.tileSize, atlas.tileSize], + scale: 0.25, + blockData: null, + modelName: null + } + } + } + + const blockToTopTexture = (r) => r.top ?? r + + try { + if (!appViewer.resourcesManager.currentResources?.itemsRenderer) throw new Error('Items renderer is not available') + itemTexture = + appViewer.resourcesManager.currentResources.itemsRenderer.getItemTexture(itemModelName, {}, false, fullBlockModelSupport) + ?? (model.originalItemName ? appViewer.resourcesManager.currentResources.itemsRenderer.getItemTexture(model.originalItemName, {}, false, fullBlockModelSupport) : undefined) + ?? appViewer.resourcesManager.currentResources.itemsRenderer.getItemTexture('item/missing_texture')! + } catch (err) { + // get resourcepack from resource manager + reportError?.(`Failed to render item ${itemModelName} (original: ${model.originalItemName}) on ${bot.version} (resourcepack: TODO!): ${err.stack}`) + itemTexture = blockToTopTexture(appViewer.resourcesManager.currentResources!.itemsRenderer.getItemTexture('errored')!) + } + + itemTexture ??= blockToTopTexture(appViewer.resourcesManager.currentResources!.itemsRenderer.getItemTexture('unknown')!) + + + if ('type' in itemTexture) { + // is item + return { + texture: itemTexture.type, + slice: itemTexture.slice, + modelName: itemModelName, + blockData: null, + scale: null + } + } else { + // is block + return { + texture: 'blocks', + blockData: itemTexture, + modelName: itemModelName, + slice: null, + scale: null + } + } +} diff --git a/renderer/viewer/three/skyboxRenderer.ts b/renderer/viewer/three/skyboxRenderer.ts new file mode 100644 index 00000000..fb9edae6 --- /dev/null +++ b/renderer/viewer/three/skyboxRenderer.ts @@ -0,0 +1,406 @@ +import * as THREE from 'three' +import { DebugGui } from '../lib/DebugGui' + +export const DEFAULT_TEMPERATURE = 0.75 + +export class SkyboxRenderer { + private texture: THREE.Texture | null = null + private mesh: THREE.Mesh | null = null + private skyMesh: THREE.Mesh | null = null + private voidMesh: THREE.Mesh | null = null + + // World state + private worldTime = 0 + private partialTicks = 0 + private viewDistance = 4 + private temperature = DEFAULT_TEMPERATURE + private inWater = false + private waterBreathing = false + private fogBrightness = 0 + private prevFogBrightness = 0 + private readonly fogOrangeness = 0 // Debug property to control sky color orangeness + private readonly distanceFactor = 2.7 + + private readonly brightnessAtPosition = 1 + debugGui: DebugGui + + constructor (private readonly scene: THREE.Scene, public defaultSkybox: boolean, public initialImage: string | null) { + this.debugGui = new DebugGui('skybox_renderer', this, [ + 'temperature', + 'worldTime', + 'inWater', + 'waterBreathing', + 'fogOrangeness', + 'brightnessAtPosition', + 'distanceFactor' + ], { + brightnessAtPosition: { min: 0, max: 1, step: 0.01 }, + temperature: { min: 0, max: 1, step: 0.01 }, + worldTime: { min: 0, max: 24_000, step: 1 }, + fogOrangeness: { min: -1, max: 1, step: 0.01 }, + distanceFactor: { min: 0, max: 5, step: 0.01 }, + }) + + if (!initialImage) { + this.createGradientSky() + } + // this.debugGui.activate() + } + + async init () { + if (this.initialImage) { + await this.setSkyboxImage(this.initialImage) + } + } + + async setSkyboxImage (imageUrl: string) { + // Dispose old textures if they exist + if (this.texture) { + this.texture.dispose() + } + + // Load the equirectangular texture + const textureLoader = new THREE.TextureLoader() + this.texture = await new Promise((resolve) => { + textureLoader.load( + imageUrl, + (texture) => { + texture.mapping = THREE.EquirectangularReflectionMapping + texture.encoding = THREE.sRGBEncoding + // Keep pixelated look + texture.minFilter = THREE.NearestFilter + texture.magFilter = THREE.NearestFilter + texture.needsUpdate = true + resolve(texture) + } + ) + }) + + // Create or update the skybox + if (this.mesh) { + // Just update the texture on the existing material + this.mesh.material.map = this.texture + this.mesh.material.needsUpdate = true + } else { + // Create a large sphere geometry for the skybox + const geometry = new THREE.SphereGeometry(500, 60, 40) + // Flip the geometry inside out + geometry.scale(-1, 1, 1) + + // Create material using the loaded texture + const material = new THREE.MeshBasicMaterial({ + map: this.texture, + side: THREE.FrontSide // Changed to FrontSide since we're flipping the geometry + }) + + // Create and add the skybox mesh + this.mesh = new THREE.Mesh(geometry, material) + this.scene.add(this.mesh) + } + } + + update (cameraPosition: THREE.Vector3, newViewDistance: number) { + if (newViewDistance !== this.viewDistance) { + this.viewDistance = newViewDistance + this.updateSkyColors() + } + + if (this.mesh) { + // Update skybox position + this.mesh.position.copy(cameraPosition) + } else if (this.skyMesh) { + // Update gradient sky position + this.skyMesh.position.copy(cameraPosition) + this.voidMesh?.position.copy(cameraPosition) + this.updateSkyColors() // Update colors based on time of day + } + } + + // Update world time + updateTime (timeOfDay: number, partialTicks = 0) { + if (this.debugGui.visible) return + this.worldTime = timeOfDay + this.partialTicks = partialTicks + this.updateSkyColors() + } + + // Update view distance + updateViewDistance (viewDistance: number) { + this.viewDistance = viewDistance + this.updateSkyColors() + } + + // Update temperature (for biome support) + updateTemperature (temperature: number) { + if (this.debugGui.visible) return + this.temperature = temperature + this.updateSkyColors() + } + + // Update water state + updateWaterState (inWater: boolean, waterBreathing: boolean) { + if (this.debugGui.visible) return + this.inWater = inWater + this.waterBreathing = waterBreathing + this.updateSkyColors() + } + + // Update default skybox setting + updateDefaultSkybox (defaultSkybox: boolean) { + if (this.debugGui.visible) return + this.defaultSkybox = defaultSkybox + this.updateSkyColors() + } + + private createGradientSky () { + const size = 64 + const scale = 256 / size + 2 + + { + const geometry = new THREE.PlaneGeometry(size * scale * 2, size * scale * 2) + geometry.rotateX(-Math.PI / 2) + geometry.translate(0, 16, 0) + + const material = new THREE.MeshBasicMaterial({ + color: 0xff_ff_ff, + side: THREE.DoubleSide, + depthTest: false + }) + + this.skyMesh = new THREE.Mesh(geometry, material) + this.scene.add(this.skyMesh) + } + + { + const geometry = new THREE.PlaneGeometry(size * scale * 2, size * scale * 2) + geometry.rotateX(-Math.PI / 2) + geometry.translate(0, -16, 0) + + const material = new THREE.MeshBasicMaterial({ + color: 0xff_ff_ff, + side: THREE.DoubleSide, + depthTest: false + }) + + this.voidMesh = new THREE.Mesh(geometry, material) + this.scene.add(this.voidMesh) + } + + this.updateSkyColors() + } + + private getFogColor (partialTicks = 0): THREE.Vector3 { + const angle = this.getCelestialAngle(partialTicks) + let rotation = Math.cos(angle * Math.PI * 2) * 2 + 0.5 + rotation = Math.max(0, Math.min(1, rotation)) + + let x = 0.752_941_2 + let y = 0.847_058_83 + let z = 1 + + x *= (rotation * 0.94 + 0.06) + y *= (rotation * 0.94 + 0.06) + z *= (rotation * 0.91 + 0.09) + + return new THREE.Vector3(x, y, z) + } + + private getSkyColor (x = 0, z = 0, partialTicks = 0): THREE.Vector3 { + const angle = this.getCelestialAngle(partialTicks) + let brightness = Math.cos(angle * 3.141_593 * 2) * 2 + 0.5 + + if (brightness < 0) brightness = 0 + if (brightness > 1) brightness = 1 + + const temperature = this.getTemperature(x, z) + const rgb = this.getSkyColorByTemp(temperature) + + const red = ((rgb >> 16) & 0xff) / 255 + const green = ((rgb >> 8) & 0xff) / 255 + const blue = (rgb & 0xff) / 255 + + return new THREE.Vector3( + red * brightness, + green * brightness, + blue * brightness + ) + } + + private calculateCelestialAngle (time: number, partialTicks: number): number { + const modTime = (time % 24_000) + let angle = (modTime + partialTicks) / 24_000 - 0.25 + + if (angle < 0) { + angle++ + } + if (angle > 1) { + angle-- + } + + angle = 1 - ((Math.cos(angle * Math.PI) + 1) / 2) + angle += (angle - angle) / 3 + + return angle + } + + private getCelestialAngle (partialTicks: number): number { + return this.calculateCelestialAngle(this.worldTime, partialTicks) + } + + private getTemperature (x: number, z: number): number { + return this.temperature + } + + private getSkyColorByTemp (temperature: number): number { + temperature /= 3 + if (temperature < -1) temperature = -1 + if (temperature > 1) temperature = 1 + + // Apply debug fog orangeness to hue - positive values make it more orange, negative make it less orange + const baseHue = 0.622_222_2 - temperature * 0.05 + // Orange is around hue 0.08-0.15, so we need to shift from blue-purple (0.62) toward orange + // Use a more dramatic shift and also increase saturation for more noticeable effect + const orangeHue = 0.12 // Orange hue value + const hue = this.fogOrangeness > 0 + ? baseHue + (orangeHue - baseHue) * this.fogOrangeness * 0.8 // Blend toward orange + : baseHue + this.fogOrangeness * 0.1 // Subtle shift for negative values + const saturation = 0.5 + temperature * 0.1 + Math.abs(this.fogOrangeness) * 0.3 // Increase saturation with orangeness + const brightness = 1 + + return this.hsbToRgb(hue, saturation, brightness) + } + + private hsbToRgb (hue: number, saturation: number, brightness: number): number { + let r = 0; let g = 0; let b = 0 + if (saturation === 0) { + r = g = b = Math.floor(brightness * 255 + 0.5) + } else { + const h = (hue - Math.floor(hue)) * 6 + const f = h - Math.floor(h) + const p = brightness * (1 - saturation) + const q = brightness * (1 - saturation * f) + const t = brightness * (1 - (saturation * (1 - f))) + switch (Math.floor(h)) { + case 0: + r = Math.floor(brightness * 255 + 0.5) + g = Math.floor(t * 255 + 0.5) + b = Math.floor(p * 255 + 0.5) + break + case 1: + r = Math.floor(q * 255 + 0.5) + g = Math.floor(brightness * 255 + 0.5) + b = Math.floor(p * 255 + 0.5) + break + case 2: + r = Math.floor(p * 255 + 0.5) + g = Math.floor(brightness * 255 + 0.5) + b = Math.floor(t * 255 + 0.5) + break + case 3: + r = Math.floor(p * 255 + 0.5) + g = Math.floor(q * 255 + 0.5) + b = Math.floor(brightness * 255 + 0.5) + break + case 4: + r = Math.floor(t * 255 + 0.5) + g = Math.floor(p * 255 + 0.5) + b = Math.floor(brightness * 255 + 0.5) + break + case 5: + r = Math.floor(brightness * 255 + 0.5) + g = Math.floor(p * 255 + 0.5) + b = Math.floor(q * 255 + 0.5) + break + } + } + return 0xff_00_00_00 | (r << 16) | (g << 8) | (Math.trunc(b)) + } + + private updateSkyColors () { + if (!this.skyMesh || !this.voidMesh) return + + // If default skybox is disabled, hide the skybox meshes + if (!this.defaultSkybox) { + this.skyMesh.visible = false + this.voidMesh.visible = false + if (this.mesh) { + this.mesh.visible = false + } + return + } + + // Show skybox meshes when default skybox is enabled + this.skyMesh.visible = true + this.voidMesh.visible = true + if (this.mesh) { + this.mesh.visible = true + } + + // Update fog brightness with smooth transition + this.prevFogBrightness = this.fogBrightness + const renderDistance = this.viewDistance / 32 + const targetBrightness = this.brightnessAtPosition * (1 - renderDistance) + renderDistance + this.fogBrightness += (targetBrightness - this.fogBrightness) * 0.1 + + // Handle water fog + if (this.inWater) { + const waterViewDistance = this.waterBreathing ? 100 : 5 + this.scene.fog = new THREE.Fog(new THREE.Color(0, 0, 1), 0.0025, waterViewDistance) + this.scene.background = new THREE.Color(0, 0, 1) + + // Update sky and void colors for underwater effect + ;(this.skyMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(0, 0, 1)) + ;(this.voidMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(0, 0, 0.6)) + return + } + + // Normal sky colors + const viewDistance = this.viewDistance * 16 + const viewFactor = 1 - (0.25 + 0.75 * this.viewDistance / 32) ** 0.25 + + const angle = this.getCelestialAngle(this.partialTicks) + const skyColor = this.getSkyColor(0, 0, this.partialTicks) + const fogColor = this.getFogColor(this.partialTicks) + + const brightness = Math.cos(angle * Math.PI * 2) * 2 + 0.5 + const clampedBrightness = Math.max(0, Math.min(1, brightness)) + + // Interpolate fog brightness + const interpolatedBrightness = this.prevFogBrightness + (this.fogBrightness - this.prevFogBrightness) * this.partialTicks + + const red = (fogColor.x + (skyColor.x - fogColor.x) * viewFactor) * clampedBrightness * interpolatedBrightness + const green = (fogColor.y + (skyColor.y - fogColor.y) * viewFactor) * clampedBrightness * interpolatedBrightness + const blue = (fogColor.z + (skyColor.z - fogColor.z) * viewFactor) * clampedBrightness * interpolatedBrightness + + this.scene.background = new THREE.Color(red, green, blue) + this.scene.fog = new THREE.Fog(new THREE.Color(red, green, blue), 0.0025, viewDistance * this.distanceFactor) + + ;(this.skyMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(skyColor.x, skyColor.y, skyColor.z)) + ;(this.voidMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color( + skyColor.x * 0.2 + 0.04, + skyColor.y * 0.2 + 0.04, + skyColor.z * 0.6 + 0.1 + )) + } + + dispose () { + if (this.texture) { + this.texture.dispose() + } + if (this.mesh) { + this.mesh.geometry.dispose() + ;(this.mesh.material as THREE.Material).dispose() + this.scene.remove(this.mesh) + } + if (this.skyMesh) { + this.skyMesh.geometry.dispose() + ;(this.skyMesh.material as THREE.Material).dispose() + this.scene.remove(this.skyMesh) + } + if (this.voidMesh) { + this.voidMesh.geometry.dispose() + ;(this.voidMesh.material as THREE.Material).dispose() + this.scene.remove(this.voidMesh) + } + } +} diff --git a/renderer/viewer/three/threeJsMedia.ts b/renderer/viewer/three/threeJsMedia.ts new file mode 100644 index 00000000..582273d1 --- /dev/null +++ b/renderer/viewer/three/threeJsMedia.ts @@ -0,0 +1,599 @@ +import * as THREE from 'three' +import { sendVideoPlay, sendVideoStop } from '../../../src/customChannels' +import { WorldRendererThree } from './worldrendererThree' +import { ThreeJsSound } from './threeJsSound' + +interface MediaProperties { + position: { x: number, y: number, z: number } + size: { width: number, height: number } + src: string + rotation?: 0 | 1 | 2 | 3 // 0-3 for 0°, 90°, 180°, 270° + doubleSide?: boolean + background?: number // Hexadecimal color (e.g., 0x000000 for black) + opacity?: number // 0-1 value for transparency + uvMapping?: { startU: number, endU: number, startV: number, endV: number } + allowOrigins?: string[] | boolean + loop?: boolean + volume?: number + autoPlay?: boolean + + allowLighting?: boolean +} + +export class ThreeJsMedia { + customMedia = new Map void + positionalAudio?: THREE.PositionalAudio + hadAutoPlayError?: boolean + }>() + + constructor (private readonly worldRenderer: WorldRendererThree) { + this.worldRenderer.onWorldSwitched.push(() => { + this.onWorldGone() + }) + + this.worldRenderer.onRender.push(() => { + this.render() + }) + } + + onWorldGone () { + for (const [id, videoData] of this.customMedia.entries()) { + this.destroyMedia(id) + } + } + + onWorldStop () { + for (const [id, videoData] of this.customMedia.entries()) { + this.setVideoPlaying(id, false) + } + } + + private createErrorTexture (width: number, height: number, background = 0x00_00_00, error = 'Failed to load'): THREE.CanvasTexture { + const canvas = document.createElement('canvas') + const MAX_DIMENSION = 100 + + canvas.width = MAX_DIMENSION + canvas.height = MAX_DIMENSION + + const ctx = canvas.getContext('2d') + if (!ctx) return new THREE.CanvasTexture(canvas) + + // Clear with transparent background + ctx.clearRect(0, 0, canvas.width, canvas.height) + + // Add background color + ctx.fillStyle = `rgba(${background >> 16 & 255}, ${background >> 8 & 255}, ${background & 255}, 0.5)` + ctx.fillRect(0, 0, canvas.width, canvas.height) + + // Add red text with size relative to canvas dimensions + ctx.fillStyle = '#ff0000' + ctx.font = 'bold 10px sans-serif' + ctx.textAlign = 'center' + ctx.textBaseline = 'middle' + ctx.fillText(error, canvas.width / 2, canvas.height / 2, canvas.width) + + const texture = new THREE.CanvasTexture(canvas) + texture.minFilter = THREE.LinearFilter + texture.magFilter = THREE.LinearFilter + return texture + } + + private createBackgroundTexture (width: number, height: number, color = 0x00_00_00, opacity = 1): THREE.CanvasTexture { + const canvas = document.createElement('canvas') + canvas.width = 1 + canvas.height = 1 + + const ctx = canvas.getContext('2d') + if (!ctx) return new THREE.CanvasTexture(canvas) + + // Convert hex color to rgba + const r = (color >> 16) & 255 + const g = (color >> 8) & 255 + const b = color & 255 + + ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${opacity})` + ctx.fillRect(0, 0, 1, 1) + + const texture = new THREE.CanvasTexture(canvas) + texture.minFilter = THREE.NearestFilter + texture.magFilter = THREE.NearestFilter + return texture + } + + validateOrigin (src: string, allowOrigins: string[] | boolean) { + if (allowOrigins === true) return true + if (allowOrigins === false) return false + const url = new URL(src) + return allowOrigins.some(origin => url.origin.endsWith(origin)) + } + + onPageInteraction () { + for (const [id, videoData] of this.customMedia.entries()) { + if (videoData.hadAutoPlayError) { + videoData.hadAutoPlayError = false + void videoData.video?.play() + .catch(err => { + if (err.name === 'AbortError') return + console.error('Failed to play video:', err) + videoData.hadAutoPlayError = true + return true + }) + .then((fromCatch) => { + if (fromCatch) return + if (videoData.positionalAudio) { + // workaround: audio has to be recreated + this.addMedia(id, videoData.props) + } + }) + } + } + } + + addMedia (id: string, props: MediaProperties) { + const originalProps = structuredClone(props) + this.destroyMedia(id) + + const { scene } = this.worldRenderer + + const originSecurityError = props.allowOrigins !== undefined && !this.validateOrigin(props.src, props.allowOrigins) + if (originSecurityError) { + console.warn('Remote resource blocked due to security policy', props.src, 'allowed origins:', props.allowOrigins, 'you can control it with `remoteContentNotSameOrigin` option') + props.src = '' + } + + const isImage = props.src.endsWith('.png') || props.src.endsWith('.jpg') || props.src.endsWith('.jpeg') + + let video: HTMLVideoElement | undefined + let positionalAudio: THREE.PositionalAudio | undefined + if (!isImage) { + video = document.createElement('video') + video.src = props.src.endsWith('.gif') ? props.src.replace('.gif', '.mp4') : props.src + video.loop = props.loop ?? true + video.volume = props.volume ?? 1 + video.playsInline = true + video.crossOrigin = 'anonymous' + + // Create positional audio + const soundSystem = this.worldRenderer.soundSystem as ThreeJsSound + soundSystem.initAudioListener() + if (!soundSystem.audioListener) throw new Error('Audio listener not initialized') + positionalAudio = new THREE.PositionalAudio(soundSystem.audioListener) + positionalAudio.setRefDistance(6) + positionalAudio.setVolume(props.volume ?? 1) + scene.add(positionalAudio) + positionalAudio.position.set(props.position.x, props.position.y, props.position.z) + + // Connect video to positional audio + positionalAudio.setMediaElementSource(video) + positionalAudio.connect() + + video.addEventListener('pause', () => { + positionalAudio?.pause() + sendVideoStop(id, 'paused', video!.currentTime) + }) + video.addEventListener('play', () => { + positionalAudio?.play() + sendVideoPlay(id) + }) + video.addEventListener('seeked', () => { + if (positionalAudio && video) { + positionalAudio.offset = video.currentTime + } + }) + video.addEventListener('stalled', () => { + sendVideoStop(id, 'stalled', video!.currentTime) + }) + video.addEventListener('waiting', () => { + sendVideoStop(id, 'waiting', video!.currentTime) + }) + video.addEventListener('error', ({ error }) => { + sendVideoStop(id, `error: ${error}`, video!.currentTime) + }) + video.addEventListener('ended', () => { + sendVideoStop(id, 'ended', video!.currentTime) + }) + } + + + // Create background texture first + const backgroundTexture = this.createBackgroundTexture( + props.size.width, + props.size.height, + props.background, + // props.opacity ?? 1 + ) + + const handleError = (text?: string) => { + const errorTexture = this.createErrorTexture(props.size.width, props.size.height, props.background, text) + material.map = errorTexture + material.needsUpdate = true + } + + // Create a plane geometry with configurable UV mapping + const geometry = new THREE.PlaneGeometry(1, 1) + + // Create material with initial properties using background texture + const MaterialClass = props.allowLighting ? THREE.MeshLambertMaterial : THREE.MeshBasicMaterial + const material = new MaterialClass({ + map: backgroundTexture, + transparent: true, + side: props.doubleSide ? THREE.DoubleSide : THREE.FrontSide, + alphaTest: 0.1 + }) + + const texture = video + ? new THREE.VideoTexture(video) + : new THREE.TextureLoader().load(props.src, () => { + if (this.customMedia.get(id)?.texture === texture) { + material.map = texture + material.needsUpdate = true + } + }, undefined, () => handleError()) // todo cache + texture.minFilter = THREE.NearestFilter + texture.magFilter = THREE.NearestFilter + // texture.format = THREE.RGBAFormat + // texture.colorSpace = THREE.SRGBColorSpace + texture.generateMipmaps = false + + // Create inner mesh for offsets + const mesh = new THREE.Mesh(geometry, material) + + const { mesh: panel } = this.positionMeshExact(mesh, THREE.MathUtils.degToRad((props.rotation ?? 0) * 90), props.position, props.size.width, props.size.height) + + scene.add(panel) + + if (video) { + // Start playing the video + video.play().catch(err => { + if (err.name === 'AbortError') return + console.error('Failed to play video:', err) + videoData.hadAutoPlayError = true + handleError(err.name === 'NotAllowedError' ? 'Waiting for user interaction' : 'Failed to auto play') + }) + + // Update texture in animation loop + mesh.onBeforeRender = () => { + if (video.readyState === video.HAVE_ENOUGH_DATA && (!video.paused || !videoData?.hadAutoPlayError)) { + if (material.map !== texture) { + material.map = texture + material.needsUpdate = true + } + texture.needsUpdate = true + + // Sync audio position with video position + if (positionalAudio) { + positionalAudio.position.copy(panel.position) + positionalAudio.rotation.copy(panel.rotation) + } + } + } + } + + // UV mapping configuration + const updateUVMapping = (config: { startU: number, endU: number, startV: number, endV: number }) => { + const uvs = geometry.attributes.uv.array as Float32Array + uvs[0] = config.startU + uvs[1] = config.startV + uvs[2] = config.endU + uvs[3] = config.startV + uvs[4] = config.endU + uvs[5] = config.endV + uvs[6] = config.startU + uvs[7] = config.endV + geometry.attributes.uv.needsUpdate = true + } + + // Apply initial UV mapping if provided + if (props.uvMapping) { + updateUVMapping(props.uvMapping) + } + + const videoData = { + mesh: panel, + video, + texture, + updateUVMapping, + positionalAudio, + props: originalProps, + hadAutoPlayError: false + } + // Store video data + this.customMedia.set(id, videoData) + + return id + } + + render () { + for (const [id, videoData] of this.customMedia.entries()) { + const chunkX = Math.floor(videoData.props.position.x / 16) * 16 + const chunkZ = Math.floor(videoData.props.position.z / 16) * 16 + const sectionY = Math.floor(videoData.props.position.y / 16) * 16 + + const chunkKey = `${chunkX},${chunkZ}` + const sectionKey = `${chunkX},${sectionY},${chunkZ}` + videoData.mesh.visible = !!this.worldRenderer.sectionObjects[sectionKey] || !!this.worldRenderer.finishedChunks[chunkKey] + } + } + + setVideoPlaying (id: string, playing: boolean) { + const videoData = this.customMedia.get(id) + if (videoData?.video) { + if (playing) { + videoData.video.play().catch(console.error) + } else { + videoData.video.pause() + } + } + } + + setVideoSeeking (id: string, seconds: number) { + const videoData = this.customMedia.get(id) + if (videoData?.video) { + videoData.video.currentTime = seconds + } + } + + setVideoVolume (id: string, volume: number) { + const videoData = this.customMedia.get(id) + if (videoData?.video) { + videoData.video.volume = volume + } + } + + setVideoSpeed (id: string, speed: number) { + const videoData = this.customMedia.get(id) + if (videoData?.video) { + videoData.video.playbackRate = speed + } + } + + destroyMedia (id: string) { + const { scene } = this.worldRenderer + const mediaData = this.customMedia.get(id) + if (mediaData) { + if (mediaData.video) { + mediaData.video.pause() + mediaData.video.src = '' + mediaData.video.remove() + } + if (mediaData.positionalAudio) { + // mediaData.positionalAudio.stop() + // mediaData.positionalAudio.disconnect() + scene.remove(mediaData.positionalAudio) + } + scene.remove(mediaData.mesh) + mediaData.texture.dispose() + + // Get the inner mesh from the group + const mesh = mediaData.mesh.children[0] as THREE.Mesh + if (mesh) { + mesh.geometry.dispose() + if (mesh.material instanceof THREE.Material) { + mesh.material.dispose() + } + } + + this.customMedia.delete(id) + } + } + + /** + * Positions a mesh exactly at startPosition and extends it along the rotation direction + * with the specified width and height + * + * @param mesh The mesh to position + * @param rotation Rotation in radians (applied to Y axis) + * @param startPosition The exact starting position (corner) of the mesh + * @param width Width of the mesh + * @param height Height of the mesh + * @param depth Depth of the mesh (default: 1) + * @returns The positioned mesh for chaining + */ + positionMeshExact ( + mesh: THREE.Mesh, + rotation: number, + startPosition: { x: number, y: number, z: number }, + width: number, + height: number, + depth = 1 + ) { + // avoid z-fighting with the ground plane + if (rotation === 0) { + startPosition.z += 0.001 + } + if (rotation === Math.PI / 2) { + startPosition.x -= 0.001 + } + if (rotation === Math.PI) { + startPosition.z -= 0.001 + } + if (rotation === 3 * Math.PI / 2) { + startPosition.x += 0.001 + } + + // rotation normalize coordinates + if (rotation === 0) { + startPosition.z += 1 + } + if (rotation === Math.PI) { + startPosition.x += 1 + } + if (rotation === 3 * Math.PI / 2) { + startPosition.z += 1 + startPosition.x += 1 + } + + + // First, clean up any previous transformations + mesh.matrix.identity() + mesh.position.set(0, 0, 0) + mesh.rotation.set(0, 0, 0) + mesh.scale.set(1, 1, 1) + + // By default, PlaneGeometry creates a plane in the XY plane (facing +Z) + // We need to set up the proper orientation for our use case + // Rotate the plane to face the correct direction based on the rotation parameter + mesh.rotateY(rotation) + if (rotation === Math.PI / 2 || rotation === 3 * Math.PI / 2) { + mesh.rotateZ(-Math.PI) + mesh.rotateX(-Math.PI) + } + + // Scale it to the desired size + mesh.scale.set(width, height, depth) + + // For a PlaneGeometry, if we want the corner at the origin, we need to offset + // by half the dimensions after scaling + mesh.geometry.translate(0.5, 0.5, 0) + mesh.geometry.attributes.position.needsUpdate = true + + // Now place the mesh at the start position + mesh.position.set(startPosition.x, startPosition.y, startPosition.z) + + // Create a group to hold our mesh and markers + const debugGroup = new THREE.Group() + debugGroup.add(mesh) + + // Add a marker at the starting position (should be exactly at pos) + const startMarker = new THREE.Mesh( + new THREE.BoxGeometry(0.1, 0.1, 0.1), + new THREE.MeshBasicMaterial({ color: 0xff_00_00 }) + ) + startMarker.position.copy(new THREE.Vector3(startPosition.x, startPosition.y, startPosition.z)) + debugGroup.add(startMarker) + + // Add a marker at the end position (width units away in the rotated direction) + const endX = startPosition.x + Math.cos(rotation) * width + const endZ = startPosition.z + Math.sin(rotation) * width + const endYMarker = new THREE.Mesh( + new THREE.BoxGeometry(0.1, 0.1, 0.1), + new THREE.MeshBasicMaterial({ color: 0x00_00_ff }) + ) + endYMarker.position.set(startPosition.x, startPosition.y + height, startPosition.z) + debugGroup.add(endYMarker) + + // Add a marker at the width endpoint + const endWidthMarker = new THREE.Mesh( + new THREE.BoxGeometry(0.1, 0.1, 0.1), + new THREE.MeshBasicMaterial({ color: 0xff_ff_00 }) + ) + endWidthMarker.position.set(endX, startPosition.y, endZ) + debugGroup.add(endWidthMarker) + + // Add a marker at the corner diagonal endpoint (both width and height) + const endCornerMarker = new THREE.Mesh( + new THREE.BoxGeometry(0.1, 0.1, 0.1), + new THREE.MeshBasicMaterial({ color: 0xff_00_ff }) + ) + endCornerMarker.position.set(endX, startPosition.y + height, endZ) + debugGroup.add(endCornerMarker) + + // Also add a visual helper to show the rotation direction + const directionHelper = new THREE.ArrowHelper( + new THREE.Vector3(Math.cos(rotation), 0, Math.sin(rotation)), + new THREE.Vector3(startPosition.x, startPosition.y, startPosition.z), + 1, + 0xff_00_00 + ) + debugGroup.add(directionHelper) + + return { + mesh, + debugGroup + } + } + + createTestCanvasTexture () { + const canvas = document.createElement('canvas') + canvas.width = 100 + canvas.height = 100 + const ctx = canvas.getContext('2d') + if (!ctx) return null + ctx.font = '10px Arial' + ctx.fillStyle = 'red' + ctx.fillText('Hello World', 0, 10) // at + return new THREE.CanvasTexture(canvas) + } + + /** + * Creates a test mesh that demonstrates the exact positioning + */ + addTestMeshExact (rotationNum: number) { + const pos = window.cursorBlockRel().position + console.log('Creating exact positioned test mesh at:', pos) + + // Create a plane mesh with a wireframe to visualize boundaries + const plane = new THREE.Mesh( + new THREE.PlaneGeometry(1, 1), + new THREE.MeshBasicMaterial({ + // side: THREE.DoubleSide, + map: this.createTestCanvasTexture() + }) + ) + + const width = 2 + const height = 1 + const rotation = THREE.MathUtils.degToRad(rotationNum * 90) // 90 degrees in radians + + // Position the mesh exactly where we want it + const { debugGroup } = this.positionMeshExact(plane, rotation, pos, width, height) + + this.worldRenderer.scene.add(debugGroup) + console.log('Exact test mesh added with dimensions:', width, height, 'and rotation:', rotation) + } + + lastCheck = 0 + THROTTLE_TIME = 100 + tryIntersectMedia () { + // hack: need to optimize this by pulling only in distance of interaction instead and throttle + if (this.customMedia.size === 0) return + if (Date.now() - this.lastCheck < this.THROTTLE_TIME) return + this.lastCheck = Date.now() + + const { camera, scene } = this.worldRenderer + const raycaster = new THREE.Raycaster() + + // Get mouse position at center of screen + const mouse = new THREE.Vector2(0, 0) + + // Update the raycaster + raycaster.setFromCamera(mouse, camera) + + // Check intersection with all objects in scene + const intersects = raycaster.intersectObjects(scene.children, true) + if (intersects.length > 0) { + const intersection = intersects[0] + const intersectedObject = intersection.object + + // Find if this object belongs to any media + for (const [id, videoData] of this.customMedia.entries()) { + // Check if the intersected object is part of our media mesh + if (intersectedObject === videoData.mesh || + videoData.mesh.children.includes(intersectedObject)) { + const { uv } = intersection + if (uv) { + const result = { + id, + x: uv.x, + y: uv.y + } + this.worldRenderer.reactiveState.world.intersectMedia = result + this.worldRenderer['debugVideo'] = videoData + this.worldRenderer.cursorBlock.cursorLinesHidden = true + return + } + } + } + } + + // No media intersection found + this.worldRenderer.reactiveState.world.intersectMedia = null + this.worldRenderer['debugVideo'] = null + this.worldRenderer.cursorBlock.cursorLinesHidden = false + } +} diff --git a/renderer/viewer/three/threeJsMethods.ts b/renderer/viewer/three/threeJsMethods.ts new file mode 100644 index 00000000..629909c9 --- /dev/null +++ b/renderer/viewer/three/threeJsMethods.ts @@ -0,0 +1,15 @@ +import type { GraphicsBackend } from '../../../src/appViewer' +import type { ThreeJsBackendMethods } from './graphicsBackend' + +export function getThreeJsRendererMethods (): ThreeJsBackendMethods | undefined { + const renderer = appViewer.backend + if (renderer?.id !== 'threejs' || !renderer.backendMethods) return + return new Proxy(renderer.backendMethods, { + get (target, prop) { + return async (...args) => { + const result = await (target[prop as any] as any)(...args) + return result + } + } + }) as ThreeJsBackendMethods +} diff --git a/renderer/viewer/three/threeJsParticles.ts b/renderer/viewer/three/threeJsParticles.ts new file mode 100644 index 00000000..993f2b62 --- /dev/null +++ b/renderer/viewer/three/threeJsParticles.ts @@ -0,0 +1,160 @@ +import * as THREE from 'three' + +interface ParticleMesh extends THREE.Mesh { + velocity: THREE.Vector3; +} + +interface ParticleConfig { + fountainHeight: number; + resetHeight: number; + xVelocityRange: number; + zVelocityRange: number; + particleCount: number; + particleRadiusRange: { min: number; max: number }; + yVelocityRange: { min: number; max: number }; +} + +export interface FountainOptions { + position?: { x: number, y: number, z: number } + particleConfig?: Partial; +} + +export class Fountain { + private readonly particles: ParticleMesh[] = [] + private readonly config: { particleConfig: ParticleConfig } + private readonly position: THREE.Vector3 + container: THREE.Object3D | undefined + + constructor (public sectionId: string, options: FountainOptions = {}) { + this.position = options.position ? new THREE.Vector3(options.position.x, options.position.y, options.position.z) : new THREE.Vector3(0, 0, 0) + this.config = this.createConfig(options.particleConfig) + } + + private createConfig ( + particleConfigOverride?: Partial + ): { particleConfig: ParticleConfig } { + const particleConfig: ParticleConfig = { + fountainHeight: 10, + resetHeight: 0, + xVelocityRange: 0.4, + zVelocityRange: 0.4, + particleCount: 400, + particleRadiusRange: { min: 0.1, max: 0.6 }, + yVelocityRange: { min: 0.1, max: 2 }, + ...particleConfigOverride + } + + return { particleConfig } + } + + + createParticles (container: THREE.Object3D): void { + this.container = container + const colorStart = new THREE.Color(0xff_ff_00) + const colorEnd = new THREE.Color(0xff_a5_00) + + for (let i = 0; i < this.config.particleConfig.particleCount; i++) { + const radius = Math.random() * + (this.config.particleConfig.particleRadiusRange.max - this.config.particleConfig.particleRadiusRange.min) + + this.config.particleConfig.particleRadiusRange.min + const geometry = new THREE.SphereGeometry(radius) + const material = new THREE.MeshBasicMaterial({ + color: colorStart.clone().lerp(colorEnd, Math.random()) + }) + const mesh = new THREE.Mesh(geometry, material) + const particle = mesh as unknown as ParticleMesh + + particle.position.set( + this.position.x + (Math.random() - 0.5) * this.config.particleConfig.xVelocityRange * 2, + this.position.y + this.config.particleConfig.fountainHeight, + this.position.z + (Math.random() - 0.5) * this.config.particleConfig.zVelocityRange * 2 + ) + + particle.velocity = new THREE.Vector3( + (Math.random() - 0.5) * this.config.particleConfig.xVelocityRange, + -Math.random() * this.config.particleConfig.yVelocityRange.max, + (Math.random() - 0.5) * this.config.particleConfig.zVelocityRange + ) + + this.particles.push(particle) + this.container.add(particle) + + // this.container.onBeforeRender = () => { + // this.render() + // } + } + } + + render (): void { + for (const particle of this.particles) { + particle.velocity.y -= 0.01 + Math.random() * 0.1 + particle.position.add(particle.velocity) + + if (particle.position.y < this.position.y + this.config.particleConfig.resetHeight) { + particle.position.set( + this.position.x + (Math.random() - 0.5) * this.config.particleConfig.xVelocityRange * 2, + this.position.y + this.config.particleConfig.fountainHeight, + this.position.z + (Math.random() - 0.5) * this.config.particleConfig.zVelocityRange * 2 + ) + particle.velocity.set( + (Math.random() - 0.5) * this.config.particleConfig.xVelocityRange, + -Math.random() * this.config.particleConfig.yVelocityRange.max, + (Math.random() - 0.5) * this.config.particleConfig.zVelocityRange + ) + } + } + } + + private updateParticleCount (newCount: number): void { + if (newCount !== this.config.particleConfig.particleCount) { + this.config.particleConfig.particleCount = newCount + const currentCount = this.particles.length + + if (newCount > currentCount) { + this.addParticles(newCount - currentCount) + } else if (newCount < currentCount) { + this.removeParticles(currentCount - newCount) + } + } + } + + private addParticles (count: number): void { + const geometry = new THREE.SphereGeometry(0.1) + const material = new THREE.MeshBasicMaterial({ color: 0x00_ff_00 }) + + for (let i = 0; i < count; i++) { + const mesh = new THREE.Mesh(geometry, material) + const particle = mesh as unknown as ParticleMesh + particle.position.copy(this.position) + particle.velocity = new THREE.Vector3( + Math.random() * this.config.particleConfig.xVelocityRange - + this.config.particleConfig.xVelocityRange / 2, + Math.random() * 2, + Math.random() * this.config.particleConfig.zVelocityRange - + this.config.particleConfig.zVelocityRange / 2 + ) + this.particles.push(particle) + this.container!.add(particle) + } + } + + private removeParticles (count: number): void { + for (let i = 0; i < count; i++) { + const particle = this.particles.pop() + if (particle) { + this.container!.remove(particle) + } + } + } + + public dispose (): void { + for (const particle of this.particles) { + particle.geometry.dispose() + if (Array.isArray(particle.material)) { + for (const material of particle.material) material.dispose() + } else { + particle.material.dispose() + } + } + } +} diff --git a/renderer/viewer/three/threeJsSound.ts b/renderer/viewer/three/threeJsSound.ts new file mode 100644 index 00000000..699bb2cc --- /dev/null +++ b/renderer/viewer/three/threeJsSound.ts @@ -0,0 +1,99 @@ +import * as THREE from 'three' +import { WorldRendererThree } from './worldrendererThree' + +export interface SoundSystem { + playSound: (position: { x: number, y: number, z: number }, path: string, volume?: number, pitch?: number, timeout?: number) => void + destroy: () => void +} + +export class ThreeJsSound implements SoundSystem { + audioListener: THREE.AudioListener | undefined + private readonly activeSounds = new Set() + private readonly audioContext: AudioContext | undefined + private readonly soundVolumes = new Map() + baseVolume = 1 + + constructor (public worldRenderer: WorldRendererThree) { + worldRenderer.onWorldSwitched.push(() => { + this.stopAll() + }) + + worldRenderer.onReactiveConfigUpdated('volume', (volume) => { + this.changeVolume(volume) + }) + } + + initAudioListener () { + if (this.audioListener) return + this.audioListener = new THREE.AudioListener() + this.worldRenderer.camera.add(this.audioListener) + } + + playSound (position: { x: number, y: number, z: number }, path: string, volume = 1, pitch = 1, timeout = 500) { + this.initAudioListener() + + const sound = new THREE.PositionalAudio(this.audioListener!) + this.activeSounds.add(sound) + this.soundVolumes.set(sound, volume) + + const audioLoader = new THREE.AudioLoader() + const start = Date.now() + void audioLoader.loadAsync(path).then((buffer) => { + if (Date.now() - start > timeout) { + console.warn('Ignored playing sound', path, 'due to timeout:', timeout, 'ms <', Date.now() - start, 'ms') + return + } + // play + sound.setBuffer(buffer) + sound.setRefDistance(20) + sound.setVolume(volume * this.baseVolume) + sound.setPlaybackRate(pitch) // set the pitch + this.worldRenderer.scene.add(sound) + // set sound position + sound.position.set(position.x, position.y, position.z) + sound.onEnded = () => { + this.worldRenderer.scene.remove(sound) + if (sound.source) { + sound.disconnect() + } + this.activeSounds.delete(sound) + this.soundVolumes.delete(sound) + audioLoader.manager.itemEnd(path) + } + sound.play() + }) + } + + stopAll () { + for (const sound of this.activeSounds) { + if (!sound) continue + sound.stop() + if (sound.source) { + sound.disconnect() + } + this.worldRenderer.scene.remove(sound) + } + this.activeSounds.clear() + this.soundVolumes.clear() + } + + changeVolume (volume: number) { + this.baseVolume = volume + for (const [sound, individualVolume] of this.soundVolumes) { + sound.setVolume(individualVolume * this.baseVolume) + } + } + + destroy () { + this.stopAll() + // Remove and cleanup audio listener + if (this.audioListener) { + this.audioListener.removeFromParent() + this.audioListener = undefined + } + } + + playTestSound () { + this.playSound(this.worldRenderer.camera.position, '/sound.mp3') + } +} diff --git a/renderer/viewer/three/threeJsUtils.ts b/renderer/viewer/three/threeJsUtils.ts new file mode 100644 index 00000000..cbef9065 --- /dev/null +++ b/renderer/viewer/three/threeJsUtils.ts @@ -0,0 +1,73 @@ +import * as THREE from 'three' +import { getLoadedImage } from 'mc-assets/dist/utils' +import { createCanvas } from '../lib/utils' + +export const disposeObject = (obj: THREE.Object3D, cleanTextures = false) => { + // 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) { + // eslint-disable-next-line unicorn/no-array-for-each + obj.children.forEach(child => disposeObject(child, cleanTextures)) + } + if (cleanTextures) { + if (obj instanceof THREE.Mesh) { + obj.material?.map?.dispose?.() + } + } +} + +let textureCache: Record = {} +let imagesPromises: Record> = {} + +export const loadThreeJsTextureFromUrlSync = (imageUrl: string) => { + const texture = new THREE.Texture() + const promise = getLoadedImage(imageUrl).then(image => { + texture.image = image + texture.needsUpdate = true + return texture + }) + return { + texture, + promise + } +} + +export const loadThreeJsTextureFromUrl = async (imageUrl: string) => { + const loaded = new THREE.TextureLoader().loadAsync(imageUrl) + return loaded +} + +export const loadThreeJsTextureFromBitmap = (image: ImageBitmap) => { + const canvas = createCanvas(image.width, image.height) + const ctx = canvas.getContext('2d')! + ctx.drawImage(image, 0, 0) + const texture = new THREE.Texture(canvas) + texture.magFilter = THREE.NearestFilter + texture.minFilter = THREE.NearestFilter + return texture +} + +export async function loadTexture (texture: string, cb: (texture: THREE.Texture) => void, onLoad?: () => void): Promise { + const cached = textureCache[texture] + if (!cached) { + const { promise, resolve } = Promise.withResolvers() + const t = loadThreeJsTextureFromUrlSync(texture) + textureCache[texture] = t.texture + void t.promise.then(resolve) + imagesPromises[texture] = promise + } + + cb(textureCache[texture]) + void imagesPromises[texture].then(() => { + onLoad?.() + }) +} + +export const clearTextureCache = () => { + textureCache = {} + imagesPromises = {} +} + diff --git a/renderer/viewer/three/waypointSprite.ts b/renderer/viewer/three/waypointSprite.ts new file mode 100644 index 00000000..6a30e6db --- /dev/null +++ b/renderer/viewer/three/waypointSprite.ts @@ -0,0 +1,418 @@ +import * as THREE from 'three' + +// Centralized visual configuration (in screen pixels) +export const WAYPOINT_CONFIG = { + // Target size in screen pixels (this controls the final sprite size) + TARGET_SCREEN_PX: 150, + // Canvas size for internal rendering (keep power of 2 for textures) + CANVAS_SIZE: 256, + // Relative positions in canvas (0-1) + LAYOUT: { + DOT_Y: 0.3, + NAME_Y: 0.45, + DISTANCE_Y: 0.55, + }, + // Multiplier for canvas internal resolution to keep text crisp + CANVAS_SCALE: 2, + ARROW: { + enabledDefault: false, + pixelSize: 50, + paddingPx: 50, + }, +} + +export type WaypointSprite = { + group: THREE.Group + sprite: THREE.Sprite + // Offscreen arrow controls + enableOffscreenArrow: (enabled: boolean) => void + setArrowParent: (parent: THREE.Object3D | null) => void + // Convenience combined updater + updateForCamera: ( + cameraPosition: THREE.Vector3, + camera: THREE.PerspectiveCamera, + viewportWidthPx: number, + viewportHeightPx: number + ) => boolean + // Utilities + setColor: (color: number) => void + setLabel: (label?: string) => void + updateDistanceText: (label: string, distanceText: string) => void + setVisible: (visible: boolean) => void + setPosition: (x: number, y: number, z: number) => void + dispose: () => void +} + +export function createWaypointSprite (options: { + position: THREE.Vector3 | { x: number, y: number, z: number }, + color?: number, + label?: string, + depthTest?: boolean, + // Y offset in world units used by updateScaleWorld only (screen-pixel API ignores this) + labelYOffset?: number, + metadata?: any, +}): WaypointSprite { + const color = options.color ?? 0xFF_00_00 + const depthTest = options.depthTest ?? false + const labelYOffset = options.labelYOffset ?? 1.5 + + // Build combined sprite + const sprite = createCombinedSprite(color, options.label ?? '', '0m', depthTest) + sprite.renderOrder = 10 + let currentLabel = options.label ?? '' + + // Offscreen arrow (detached by default) + let arrowSprite: THREE.Sprite | undefined + let arrowParent: THREE.Object3D | null = null + let arrowEnabled = WAYPOINT_CONFIG.ARROW.enabledDefault + + // Group for easy add/remove + const group = new THREE.Group() + group.add(sprite) + + // Initial position + const { x, y, z } = options.position + group.position.set(x, y, z) + + function setColor (newColor: number) { + const canvas = drawCombinedCanvas(newColor, currentLabel, '0m') + const texture = new THREE.CanvasTexture(canvas) + const mat = sprite.material + mat.map?.dispose() + mat.map = texture + mat.needsUpdate = true + } + + function setLabel (newLabel?: string) { + currentLabel = newLabel ?? '' + const canvas = drawCombinedCanvas(color, currentLabel, '0m') + const texture = new THREE.CanvasTexture(canvas) + const mat = sprite.material + mat.map?.dispose() + mat.map = texture + mat.needsUpdate = true + } + + function updateDistanceText (label: string, distanceText: string) { + const canvas = drawCombinedCanvas(color, label, distanceText) + const texture = new THREE.CanvasTexture(canvas) + const mat = sprite.material + mat.map?.dispose() + mat.map = texture + mat.needsUpdate = true + } + + function setVisible (visible: boolean) { + sprite.visible = visible + } + + function setPosition (nx: number, ny: number, nz: number) { + group.position.set(nx, ny, nz) + } + + // Keep constant pixel size on screen using global config + function updateScaleScreenPixels ( + cameraPosition: THREE.Vector3, + cameraFov: number, + distance: number, + viewportHeightPx: number + ) { + const vFovRad = cameraFov * Math.PI / 180 + const worldUnitsPerScreenHeightAtDist = Math.tan(vFovRad / 2) * 2 * distance + // Use configured target screen size + const scale = worldUnitsPerScreenHeightAtDist * (WAYPOINT_CONFIG.TARGET_SCREEN_PX / viewportHeightPx) + sprite.scale.set(scale, scale, 1) + } + + function ensureArrow () { + if (arrowSprite) return + const size = 128 + const canvas = document.createElement('canvas') + canvas.width = size + canvas.height = size + const ctx = canvas.getContext('2d')! + ctx.clearRect(0, 0, size, size) + + // Draw arrow shape + ctx.beginPath() + ctx.moveTo(size * 0.15, size * 0.5) + ctx.lineTo(size * 0.85, size * 0.5) + ctx.lineTo(size * 0.5, size * 0.15) + ctx.closePath() + + // Use waypoint color for arrow + const colorHex = `#${color.toString(16).padStart(6, '0')}` + ctx.lineWidth = 6 + ctx.strokeStyle = 'black' + ctx.stroke() + ctx.fillStyle = colorHex + ctx.fill() + + const texture = new THREE.CanvasTexture(canvas) + const material = new THREE.SpriteMaterial({ map: texture, transparent: true, depthTest: false, depthWrite: false }) + arrowSprite = new THREE.Sprite(material) + arrowSprite.renderOrder = 12 + arrowSprite.visible = false + if (arrowParent) arrowParent.add(arrowSprite) + } + + function enableOffscreenArrow (enabled: boolean) { + arrowEnabled = enabled + if (!enabled && arrowSprite) arrowSprite.visible = false + } + + function setArrowParent (parent: THREE.Object3D | null) { + if (arrowSprite?.parent) arrowSprite.parent.remove(arrowSprite) + arrowParent = parent + if (arrowSprite && parent) parent.add(arrowSprite) + } + + function updateOffscreenArrow ( + camera: THREE.PerspectiveCamera, + viewportWidthPx: number, + viewportHeightPx: number + ): boolean { + if (!arrowEnabled) return true + ensureArrow() + if (!arrowSprite) return true + + // Check if onlyLeftRight is enabled in metadata + const onlyLeftRight = options.metadata?.onlyLeftRight === true + + // Build camera basis using camera.up to respect custom orientations + const forward = new THREE.Vector3() + camera.getWorldDirection(forward) // camera look direction + const upWorld = camera.up.clone().normalize() + const right = new THREE.Vector3().copy(forward).cross(upWorld).normalize() + const upCam = new THREE.Vector3().copy(right).cross(forward).normalize() + + // Vector from camera to waypoint + const camPos = new THREE.Vector3().setFromMatrixPosition(camera.matrixWorld) + const toWp = new THREE.Vector3(group.position.x, group.position.y, group.position.z).sub(camPos) + + // Components in camera basis + const z = toWp.dot(forward) + const x = toWp.dot(right) + const y = toWp.dot(upCam) + + const aspect = viewportWidthPx / viewportHeightPx + const vFovRad = camera.fov * Math.PI / 180 + const hFovRad = 2 * Math.atan(Math.tan(vFovRad / 2) * aspect) + + // Determine if waypoint is inside view frustum using angular checks + const thetaX = Math.atan2(x, z) + const thetaY = Math.atan2(y, z) + const visible = z > 0 && Math.abs(thetaX) <= hFovRad / 2 && Math.abs(thetaY) <= vFovRad / 2 + if (visible) { + arrowSprite.visible = false + return true + } + + // Direction on screen in normalized frustum units + let rx = thetaX / (hFovRad / 2) + let ry = thetaY / (vFovRad / 2) + + // If behind the camera, snap to dominant axis to avoid confusing directions + if (z <= 0) { + if (Math.abs(rx) > Math.abs(ry)) { + rx = Math.sign(rx) + ry = 0 + } else { + rx = 0 + ry = Math.sign(ry) + } + } + + // Apply onlyLeftRight logic - restrict arrows to left/right edges only + if (onlyLeftRight) { + // Force the arrow to appear only on left or right edges + if (Math.abs(rx) > Math.abs(ry)) { + // Horizontal direction is dominant, keep it + ry = 0 + } else { + // Vertical direction is dominant, but we want only left/right + // So choose left or right based on the sign of rx + rx = rx >= 0 ? 1 : -1 + ry = 0 + } + } + + // Place on the rectangle border [-1,1]x[-1,1] + const s = Math.max(Math.abs(rx), Math.abs(ry)) || 1 + let ndcX = rx / s + let ndcY = ry / s + + // Apply padding in pixel space by clamping + const padding = WAYPOINT_CONFIG.ARROW.paddingPx + const pxX = ((ndcX + 1) * 0.5) * viewportWidthPx + const pxY = ((1 - ndcY) * 0.5) * viewportHeightPx + const clampedPxX = Math.min(Math.max(pxX, padding), viewportWidthPx - padding) + const clampedPxY = Math.min(Math.max(pxY, padding), viewportHeightPx - padding) + ndcX = (clampedPxX / viewportWidthPx) * 2 - 1 + ndcY = -(clampedPxY / viewportHeightPx) * 2 + 1 + + // Compute world position at a fixed distance in front of the camera using camera basis + const placeDist = Math.max(2, camera.near * 4) + const halfPlaneHeight = Math.tan(vFovRad / 2) * placeDist + const halfPlaneWidth = halfPlaneHeight * aspect + const pos = camPos.clone() + .add(forward.clone().multiplyScalar(placeDist)) + .add(right.clone().multiplyScalar(ndcX * halfPlaneWidth)) + .add(upCam.clone().multiplyScalar(ndcY * halfPlaneHeight)) + + // Update arrow sprite + arrowSprite.visible = true + arrowSprite.position.copy(pos) + + // Angle for rotation relative to screen right/up (derived from camera up vector) + const angle = Math.atan2(ry, rx) + arrowSprite.material.rotation = angle - Math.PI / 2 + + // Constant pixel size for arrow (use fixed placement distance) + const worldUnitsPerScreenHeightAtDist = Math.tan(vFovRad / 2) * 2 * placeDist + const sPx = worldUnitsPerScreenHeightAtDist * (WAYPOINT_CONFIG.ARROW.pixelSize / viewportHeightPx) + arrowSprite.scale.set(sPx, sPx, 1) + return false + } + + function computeDistance (cameraPosition: THREE.Vector3): number { + return cameraPosition.distanceTo(group.position) + } + + function updateForCamera ( + cameraPosition: THREE.Vector3, + camera: THREE.PerspectiveCamera, + viewportWidthPx: number, + viewportHeightPx: number + ): boolean { + const distance = computeDistance(cameraPosition) + // Keep constant pixel size + updateScaleScreenPixels(cameraPosition, camera.fov, distance, viewportHeightPx) + // Update text + updateDistanceText(currentLabel, `${Math.round(distance)}m`) + // Update arrow and visibility + const onScreen = updateOffscreenArrow(camera, viewportWidthPx, viewportHeightPx) + setVisible(onScreen) + return onScreen + } + + function dispose () { + const mat = sprite.material + mat.map?.dispose() + mat.dispose() + if (arrowSprite) { + const am = arrowSprite.material + am.map?.dispose() + am.dispose() + } + } + + return { + group, + sprite, + enableOffscreenArrow, + setArrowParent, + updateForCamera, + setColor, + setLabel, + updateDistanceText, + setVisible, + setPosition, + dispose, + } +} + +// Internal helpers +function drawCombinedCanvas (color: number, id: string, distance: string): HTMLCanvasElement { + const scale = WAYPOINT_CONFIG.CANVAS_SCALE * (globalThis.devicePixelRatio || 1) + const size = WAYPOINT_CONFIG.CANVAS_SIZE * scale + const canvas = document.createElement('canvas') + canvas.width = size + canvas.height = size + const ctx = canvas.getContext('2d')! + + // Clear canvas + ctx.clearRect(0, 0, size, size) + + // Draw dot + const centerX = size / 2 + const dotY = Math.round(size * WAYPOINT_CONFIG.LAYOUT.DOT_Y) + const radius = Math.round(size * 0.05) // Dot takes up ~12% of canvas height + const borderWidth = Math.max(2, Math.round(4 * scale)) + + // Outer border (black) + ctx.beginPath() + ctx.arc(centerX, dotY, radius + borderWidth, 0, Math.PI * 2) + ctx.fillStyle = 'black' + ctx.fill() + + // Inner circle (colored) + ctx.beginPath() + ctx.arc(centerX, dotY, radius, 0, Math.PI * 2) + ctx.fillStyle = `#${color.toString(16).padStart(6, '0')}` + ctx.fill() + + // Text properties + ctx.textAlign = 'center' + ctx.textBaseline = 'middle' + + // Title + const nameFontPx = Math.round(size * 0.08) // ~8% of canvas height + const distanceFontPx = Math.round(size * 0.06) // ~6% of canvas height + ctx.font = `bold ${nameFontPx}px mojangles` + ctx.lineWidth = Math.max(2, Math.round(3 * scale)) + const nameY = Math.round(size * WAYPOINT_CONFIG.LAYOUT.NAME_Y) + + ctx.strokeStyle = 'black' + ctx.strokeText(id, centerX, nameY) + ctx.fillStyle = 'white' + ctx.fillText(id, centerX, nameY) + + // Distance + ctx.font = `bold ${distanceFontPx}px mojangles` + ctx.lineWidth = Math.max(2, Math.round(2 * scale)) + const distanceY = Math.round(size * WAYPOINT_CONFIG.LAYOUT.DISTANCE_Y) + + ctx.strokeStyle = 'black' + ctx.strokeText(distance, centerX, distanceY) + ctx.fillStyle = '#CCCCCC' + ctx.fillText(distance, centerX, distanceY) + + return canvas +} + +function createCombinedSprite (color: number, id: string, distance: string, depthTest: boolean): THREE.Sprite { + const canvas = drawCombinedCanvas(color, id, distance) + const texture = new THREE.CanvasTexture(canvas) + texture.anisotropy = 1 + texture.magFilter = THREE.LinearFilter + texture.minFilter = THREE.LinearFilter + const material = new THREE.SpriteMaterial({ + map: texture, + transparent: true, + opacity: 1, + depthTest, + depthWrite: false, + }) + const sprite = new THREE.Sprite(material) + sprite.position.set(0, 0, 0) + return sprite +} + +export const WaypointHelpers = { + // World-scale constant size helper + computeWorldScale (distance: number, fixedReference = 10) { + return Math.max(0.0001, distance / fixedReference) + }, + // Screen-pixel constant size helper + computeScreenPixelScale ( + camera: THREE.PerspectiveCamera, + distance: number, + pixelSize: number, + viewportHeightPx: number + ) { + const vFovRad = camera.fov * Math.PI / 180 + const worldUnitsPerScreenHeightAtDist = Math.tan(vFovRad / 2) * 2 * distance + return worldUnitsPerScreenHeightAtDist * (pixelSize / viewportHeightPx) + } +} diff --git a/renderer/viewer/three/waypoints.ts b/renderer/viewer/three/waypoints.ts new file mode 100644 index 00000000..256ca6df --- /dev/null +++ b/renderer/viewer/three/waypoints.ts @@ -0,0 +1,140 @@ +import * as THREE from 'three' +import { WorldRendererThree } from './worldrendererThree' +import { createWaypointSprite, type WaypointSprite } from './waypointSprite' + +interface Waypoint { + id: string + x: number + y: number + z: number + minDistance: number + color: number + label?: string + sprite: WaypointSprite +} + +interface WaypointOptions { + color?: number + label?: string + minDistance?: number + metadata?: any +} + +export class WaypointsRenderer { + private readonly waypoints = new Map() + private readonly waypointScene = new THREE.Scene() + + constructor ( + private readonly worldRenderer: WorldRendererThree + ) { + } + + private updateWaypoints () { + const playerPos = this.worldRenderer.cameraObject.position + const sizeVec = this.worldRenderer.renderer.getSize(new THREE.Vector2()) + + for (const waypoint of this.waypoints.values()) { + const waypointPos = new THREE.Vector3(waypoint.x, waypoint.y, waypoint.z) + const distance = playerPos.distanceTo(waypointPos) + const visible = !waypoint.minDistance || distance >= waypoint.minDistance + + waypoint.sprite.setVisible(visible) + + if (visible) { + // Update position + waypoint.sprite.setPosition(waypoint.x, waypoint.y, waypoint.z) + // Ensure camera-based update each frame + waypoint.sprite.updateForCamera(this.worldRenderer.getCameraPosition(), this.worldRenderer.camera, sizeVec.width, sizeVec.height) + } + } + } + + render () { + if (this.waypoints.size === 0) return + + // Update waypoint scaling + this.updateWaypoints() + + // Render waypoints scene with the world camera + this.worldRenderer.renderer.render(this.waypointScene, this.worldRenderer.camera) + } + + // Removed sprite/label texture creation. Use utils/waypointSprite.ts + + addWaypoint ( + id: string, + x: number, + y: number, + z: number, + options: WaypointOptions = {} + ) { + // Remove existing waypoint if it exists + this.removeWaypoint(id) + + const color = options.color ?? 0xFF_00_00 + const { label, metadata } = options + const minDistance = options.minDistance ?? 0 + + const sprite = createWaypointSprite({ + position: new THREE.Vector3(x, y, z), + color, + label: (label || id), + metadata, + }) + sprite.enableOffscreenArrow(true) + sprite.setArrowParent(this.waypointScene) + + this.waypointScene.add(sprite.group) + + this.waypoints.set(id, { + id, x: x + 0.5, y: y + 0.5, z: z + 0.5, minDistance, + color, label, + sprite, + }) + } + + removeWaypoint (id: string) { + const waypoint = this.waypoints.get(id) + if (waypoint) { + this.waypointScene.remove(waypoint.sprite.group) + waypoint.sprite.dispose() + this.waypoints.delete(id) + } + } + + clear () { + for (const id of this.waypoints.keys()) { + this.removeWaypoint(id) + } + } + + testWaypoint () { + this.addWaypoint('Test Point', 0, 70, 0, { color: 0x00_FF_00, label: 'Test Point' }) + this.addWaypoint('Spawn', 0, 64, 0, { color: 0xFF_FF_00, label: 'Spawn' }) + this.addWaypoint('Far Point', 100, 70, 100, { color: 0x00_00_FF, label: 'Far Point' }) + } + + getWaypoint (id: string): Waypoint | undefined { + return this.waypoints.get(id) + } + + getAllWaypoints (): Waypoint[] { + return [...this.waypoints.values()] + } + + setWaypointColor (id: string, color: number) { + const waypoint = this.waypoints.get(id) + if (waypoint) { + waypoint.sprite.setColor(color) + waypoint.color = color + } + } + + setWaypointLabel (id: string, label?: string) { + const waypoint = this.waypoints.get(id) + if (waypoint) { + waypoint.label = label + waypoint.sprite.setLabel(label) + } + } +} diff --git a/renderer/viewer/three/world/cursorBlock.ts b/renderer/viewer/three/world/cursorBlock.ts new file mode 100644 index 00000000..a03a6999 --- /dev/null +++ b/renderer/viewer/three/world/cursorBlock.ts @@ -0,0 +1,162 @@ +import * as THREE from 'three' +import { LineMaterial, LineSegmentsGeometry, Wireframe } from 'three-stdlib' +import { Vec3 } from 'vec3' +import { BlockShape, BlocksShapes } from 'renderer/viewer/lib/basePlayerState' +import { WorldRendererThree } from '../worldrendererThree' +import { loadThreeJsTextureFromUrl } from '../threeJsUtils' +import destroyStage0 from '../../../../assets/destroy_stage_0.png' +import destroyStage1 from '../../../../assets/destroy_stage_1.png' +import destroyStage2 from '../../../../assets/destroy_stage_2.png' +import destroyStage3 from '../../../../assets/destroy_stage_3.png' +import destroyStage4 from '../../../../assets/destroy_stage_4.png' +import destroyStage5 from '../../../../assets/destroy_stage_5.png' +import destroyStage6 from '../../../../assets/destroy_stage_6.png' +import destroyStage7 from '../../../../assets/destroy_stage_7.png' +import destroyStage8 from '../../../../assets/destroy_stage_8.png' +import destroyStage9 from '../../../../assets/destroy_stage_9.png' + +export class CursorBlock { + _cursorLinesHidden = false + get cursorLinesHidden () { + return this._cursorLinesHidden + } + set cursorLinesHidden (value: boolean) { + if (this.interactionLines) { + this.interactionLines.mesh.visible = !value + } + this._cursorLinesHidden = value + } + + cursorLineMaterial: LineMaterial + interactionLines: null | { blockPos: Vec3, mesh: THREE.Group, shapePositions: BlocksShapes | undefined } = null + prevColor: string | undefined + blockBreakMesh: THREE.Mesh + breakTextures: THREE.Texture[] = [] + + constructor (public readonly worldRenderer: WorldRendererThree) { + // Initialize break mesh and textures + const destroyStagesImages = [ + destroyStage0, destroyStage1, destroyStage2, destroyStage3, destroyStage4, + destroyStage5, destroyStage6, destroyStage7, destroyStage8, destroyStage9 + ] + + for (let i = 0; i < 10; i++) { + void loadThreeJsTextureFromUrl(destroyStagesImages[i]).then((texture) => { + texture.magFilter = THREE.NearestFilter + texture.minFilter = THREE.NearestFilter + this.breakTextures.push(texture) + }) + } + + const breakMaterial = new THREE.MeshBasicMaterial({ + transparent: true, + blending: THREE.MultiplyBlending, + alphaTest: 0.5, + }) + this.blockBreakMesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), breakMaterial) + this.blockBreakMesh.visible = false + this.blockBreakMesh.renderOrder = 999 + this.blockBreakMesh.name = 'blockBreakMesh' + this.worldRenderer.scene.add(this.blockBreakMesh) + + this.worldRenderer.onReactivePlayerStateUpdated('gameMode', () => { + this.updateLineMaterial() + }) + // todo figure out why otherwise fog from skybox breaks it + setTimeout(() => { + this.updateLineMaterial() + if (this.interactionLines) { + this.setHighlightCursorBlock(this.interactionLines.blockPos, this.interactionLines.shapePositions, true) + } + }) + } + + // Update functions + updateLineMaterial () { + const inCreative = this.worldRenderer.playerStateReactive.gameMode === 'creative' + const pixelRatio = this.worldRenderer.renderer.getPixelRatio() + + if (this.cursorLineMaterial) { + this.cursorLineMaterial.dispose() + } + this.cursorLineMaterial = new LineMaterial({ + color: (() => { + switch (this.worldRenderer.worldRendererConfig.highlightBlockColor) { + case 'blue': + return 0x40_80_ff + case 'classic': + return 0x00_00_00 + default: + return inCreative ? 0x40_80_ff : 0x00_00_00 + } + })(), + linewidth: Math.max(pixelRatio * 0.7, 1) * 2, + // dashed: true, + // dashSize: 5, + }) + this.prevColor = this.worldRenderer.worldRendererConfig.highlightBlockColor + } + + updateBreakAnimation (blockPosition: { x: number, y: number, z: number } | undefined, stage: number | null, mergedShape?: BlockShape) { + this.hideBreakAnimation() + if (stage === null || !blockPosition || !mergedShape) return + + const { position, width, height, depth } = mergedShape + this.blockBreakMesh.scale.set(width * 1.001, height * 1.001, depth * 1.001) + position.add(blockPosition) + this.blockBreakMesh.position.set(position.x, position.y, position.z) + this.blockBreakMesh.visible = true; + + (this.blockBreakMesh.material as THREE.MeshBasicMaterial).map = this.breakTextures[stage] ?? this.breakTextures.at(-1); + (this.blockBreakMesh.material as THREE.MeshBasicMaterial).needsUpdate = true + } + + hideBreakAnimation () { + if (this.blockBreakMesh) { + this.blockBreakMesh.visible = false + } + } + + updateDisplay () { + if (this.cursorLineMaterial) { + const { renderer } = this.worldRenderer + this.cursorLineMaterial.resolution.set(renderer.domElement.width, renderer.domElement.height) + this.cursorLineMaterial.dashOffset = performance.now() / 750 + } + } + + setHighlightCursorBlock (blockPos: Vec3 | null, shapePositions?: BlocksShapes, force = false): void { + if (blockPos && this.interactionLines && blockPos.equals(this.interactionLines.blockPos) && !force) { + return + } + if (this.interactionLines !== null) { + this.worldRenderer.scene.remove(this.interactionLines.mesh) + this.interactionLines = null + } + if (blockPos === null) { + return + } + + const group = new THREE.Group() + for (const { position, width, height, depth } of shapePositions ?? []) { + const scale = [1.0001 * width, 1.0001 * height, 1.0001 * depth] as const + const geometry = new THREE.BoxGeometry(...scale) + const lines = new LineSegmentsGeometry().fromEdgesGeometry(new THREE.EdgesGeometry(geometry)) + const wireframe = new Wireframe(lines, this.cursorLineMaterial) + const pos = blockPos.plus(position) + wireframe.position.set(pos.x, pos.y, pos.z) + wireframe.computeLineDistances() + group.add(wireframe) + } + this.worldRenderer.scene.add(group) + group.visible = !this.cursorLinesHidden + this.interactionLines = { blockPos, mesh: group, shapePositions } + } + + render () { + if (this.prevColor !== this.worldRenderer.worldRendererConfig.highlightBlockColor) { + this.updateLineMaterial() + } + this.updateDisplay() + } +} diff --git a/src/vr.js b/renderer/viewer/three/world/vr.ts similarity index 51% rename from src/vr.js rename to renderer/viewer/three/world/vr.ts index 45c25b3f..ecf1b299 100644 --- a/src/vr.js +++ b/renderer/viewer/three/world/vr.ts @@ -1,23 +1,109 @@ -const { VRButton } = require('three/examples/jsm/webxr/VRButton.js') -const { GLTFLoader } = require('three/examples/jsm/loaders/GLTFLoader.js') -const { XRControllerModelFactory } = require('three/examples/jsm/webxr/XRControllerModelFactory.js') -const { buttonMap: standardButtonsMap } = require('contro-max/build/gamepad') -const { activeModalStack, hideModal } = require('./globalState') +import { VRButton } from 'three/examples/jsm/webxr/VRButton.js' +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js' +import { XRControllerModelFactory } from 'three/examples/jsm/webxr/XRControllerModelFactory.js' +import { buttonMap as standardButtonsMap } from 'contro-max/build/gamepad' +import * as THREE from 'three' +import { WorldRendererThree } from '../worldrendererThree' +import { DocumentRenderer } from '../documentRenderer' -async function initVR () { - const { renderer } = viewer - if (!('xr' in navigator)) return - const isSupported = await navigator.xr.isSessionSupported('immersive-vr') && !!XRSession.prototype.updateRenderState // e.g. android webview doesn't support updateRenderState +export async function initVR (worldRenderer: WorldRendererThree, documentRenderer: DocumentRenderer) { + if (!('xr' in navigator) || !worldRenderer.worldRendererConfig.vrSupport) return + const { renderer } = worldRenderer + + const isSupported = await checkVRSupport() if (!isSupported) return - // VR - document.body.appendChild(VRButton.createButton(renderer)) - renderer.xr.enabled = true + enableVr() + + const vrButtonContainer = createVrButtonContainer(renderer) + const updateVrButtons = () => { + const newHidden = !worldRenderer.worldRendererConfig.vrSupport || !worldRenderer.worldRendererConfig.foreground + if (vrButtonContainer.hidden !== newHidden) { + vrButtonContainer.hidden = newHidden + } + } + + worldRenderer.onRender.push(updateVrButtons) + + function enableVr () { + renderer.xr.enabled = true + // renderer.xr.setReferenceSpaceType('local-floor') + worldRenderer.reactiveState.preventEscapeMenu = true + } + + function disableVr () { + renderer.xr.enabled = false + worldRenderer.cameraGroupVr = undefined + worldRenderer.reactiveState.preventEscapeMenu = false + worldRenderer.scene.remove(user) + vrButtonContainer.hidden = true + } + + function createVrButtonContainer (renderer) { + const container = document.createElement('div') + const vrButton = VRButton.createButton(renderer) + styleContainer(container) + + const closeButton = createCloseButton(container) + + container.appendChild(vrButton) + container.appendChild(closeButton) + document.body.appendChild(container) + + return container + } + + function styleContainer (container: HTMLElement) { + typedAssign(container.style, { + position: 'absolute', + bottom: '80px', + left: '0', + right: '0', + display: 'flex', + justifyContent: 'center', + zIndex: '8', + gap: '8px', + }) + } + + function createCloseButton (container: HTMLElement) { + const closeButton = document.createElement('button') + closeButton.textContent = 'X' + typedAssign(closeButton.style, { + padding: '0 12px', + color: 'white', + fontSize: '14px', + lineHeight: '20px', + cursor: 'pointer', + background: 'transparent', + border: '1px solid rgb(255, 255, 255)', + borderRadius: '4px', + opacity: '0.7', + }) + + closeButton.addEventListener('click', () => { + container.hidden = true + worldRenderer.worldRendererConfig.vrSupport = false + }) + + return closeButton + } + + + async function checkVRSupport () { + try { + const supported = await navigator.xr?.isSessionSupported('immersive-vr') + return supported && !!XRSession.prototype.updateRenderState + } catch (err) { + console.error('Error checking if VR is supported', err) + return false + } + } // hack for vr camera const user = new THREE.Group() - user.add(viewer.camera) - viewer.scene.add(user) + user.name = 'vr-camera-container' + worldRenderer.scene.add(user) const controllerModelFactory = new XRControllerModelFactory(new GLTFLoader()) const controller1 = renderer.xr.getControllerGrip(0) const controller2 = renderer.xr.getControllerGrip(1) @@ -25,22 +111,23 @@ async function initVR () { // todo the logic written here can be hard to understand as it was designed to work in gamepad api emulation mode, will be refactored once there is a contro-max rewrite is done const virtualGamepadIndex = 4 let connectedVirtualGamepad + //@ts-expect-error const manageXrInputSource = ({ gamepad, handedness = defaultHandedness }, defaultHandedness, removeAction = false) => { if (handedness === 'right') { - const event = new Event(removeAction ? 'gamepaddisconnected' : 'gamepadconnected') // todo need to expose and use external gamepads api in contro-max instead + const event: any = new Event(removeAction ? 'gamepaddisconnected' : 'gamepadconnected') // todo need to expose and use external gamepads api in contro-max instead event.gamepad = removeAction ? connectedVirtualGamepad : { ...gamepad, mapping: 'standard', index: virtualGamepadIndex } connectedVirtualGamepad = event.gamepad window.dispatchEvent(event) } } - let hand1 = controllerModelFactory.createControllerModel(controller1) + let hand1: any = controllerModelFactory.createControllerModel(controller1) controller1.addEventListener('connected', (event) => { hand1.xrInputSource = event.data manageXrInputSource(event.data, 'left') user.add(controller1) }) controller1.add(hand1) - let hand2 = controllerModelFactory.createControllerModel(controller2) + let hand2: any = controllerModelFactory.createControllerModel(controller2) controller2.addEventListener('connected', (event) => { hand2.xrInputSource = event.data manageXrInputSource(event.data, 'right') @@ -50,15 +137,17 @@ async function initVR () { controller1.addEventListener('disconnected', () => { // don't handle removal of gamepads for now as is don't affect contro-max - hand1.xrInputSource = undefined manageXrInputSource(hand1.xrInputSource, 'left', true) + hand1.xrInputSource = undefined }) controller2.addEventListener('disconnected', () => { - hand2.xrInputSource = undefined manageXrInputSource(hand1.xrInputSource, 'right', true) + hand2.xrInputSource = undefined }) const originalGetGamepads = navigator.getGamepads.bind(navigator) + // is it okay to patch this? + //@ts-expect-error navigator.getGamepads = () => { const originalGamepads = originalGetGamepads() if (!hand1.xrInputSource || !hand2.xrInputSource) return originalGamepads @@ -101,34 +190,28 @@ async function initVR () { rotSnapReset = true } - // viewer.setFirstPersonCamera(null, yawOffset, 0) - viewer.setFirstPersonCamera(null, bot.entity.yaw, bot.entity.pitch) + // appViewer.backend?.updateCamera(null, yawOffset, 0) + // worldRenderer.updateCamera(null, bot.entity.yaw, bot.entity.pitch) // todo restore this logic (need to preserve ability to move camera) - // const xrCamera = renderer.xr.getCamera(viewer.camera) - // const d = xrCamera.getWorldDirection() // todo target + // const xrCamera = renderer.xr.getCamera() + // const d = xrCamera.getWorldDirection(new THREE.Vector3()) // bot.entity.yaw = Math.atan2(-d.x, -d.z) // bot.entity.pitch = Math.asin(d.y) - // todo ? - // bot.physics.stepHeight = 1 - - viewer.update() - viewer.render() + documentRenderer.frameRender(false) }) renderer.xr.addEventListener('sessionstart', () => { - viewer.cameraObjectOverride = user - // close all modals to be in game - for (const _modal of activeModalStack) { - hideModal(undefined, {}, { force: true }) - } + user.add(worldRenderer.camera) + worldRenderer.cameraGroupVr = user }) renderer.xr.addEventListener('sessionend', () => { - viewer.cameraObjectOverride = undefined + worldRenderer.cameraGroupVr = undefined + user.remove(worldRenderer.camera) }) -} -module.exports.initVR = initVR + worldRenderer.abortController.signal.addEventListener('abort', disableVr) +} const xrStandardRightButtonsMap = [ [0 /* trigger */, 'Right Trigger'], @@ -146,9 +229,9 @@ const xrStandardLeftButtonsMap = [ [4 /* A */, 'X'], [5 /* B */, 'Y'], ] -const remapButtons = (rightButtons, leftButtons) => { +const remapButtons = (rightButtons: any[], leftButtons: any[]) => { // return remapped buttons - const remapped = [] + const remapped = [] as string[] const remapWithMap = (buttons, map) => { for (const [index, standardName] of map) { const standardMappingIndex = standardButtonsMap.findIndex((aliases) => aliases.find(alias => standardName === alias)) @@ -168,3 +251,7 @@ const remapAxes = (axesRight, axesLeft) => { axesRight[3] ] } + +function typedAssign> (target: T, source: Partial) { + Object.assign(target, source) +} diff --git a/renderer/viewer/three/worldrendererThree.ts b/renderer/viewer/three/worldrendererThree.ts new file mode 100644 index 00000000..1b4e6152 --- /dev/null +++ b/renderer/viewer/three/worldrendererThree.ts @@ -0,0 +1,1161 @@ +import * as THREE from 'three' +import { Vec3 } from 'vec3' +import nbt from 'prismarine-nbt' +import PrismarineChatLoader from 'prismarine-chat' +import * as tweenJs from '@tweenjs/tween.js' +import { Biome } from 'minecraft-data' +import { renderSign } from '../sign-renderer' +import { DisplayWorldOptions, GraphicsInitOptions } from '../../../src/appViewer' +import { chunkPos, sectionPos } from '../lib/simpleUtils' +import { WorldRendererCommon } from '../lib/worldrendererCommon' +import { addNewStat } from '../lib/ui/newStats' +import { MesherGeometryOutput } from '../lib/mesher/shared' +import { ItemSpecificContextProperties } from '../lib/basePlayerState' +import { setBlockPosition } from '../lib/mesher/standaloneRenderer' +import { getMyHand } from './hand' +import HoldingBlock from './holdingBlock' +import { getMesh } from './entity/EntityMesh' +import { armorModel } from './entity/armorModels' +import { disposeObject, loadThreeJsTextureFromBitmap } from './threeJsUtils' +import { CursorBlock } from './world/cursorBlock' +import { getItemUv } from './appShared' +import { Entities } from './entities' +import { ThreeJsSound } from './threeJsSound' +import { CameraShake } from './cameraShake' +import { ThreeJsMedia } from './threeJsMedia' +import { Fountain } from './threeJsParticles' +import { WaypointsRenderer } from './waypoints' +import { DEFAULT_TEMPERATURE, SkyboxRenderer } from './skyboxRenderer' + +type SectionKey = string + +export class WorldRendererThree extends WorldRendererCommon { + outputFormat = 'threeJs' as const + sectionObjects: Record = {} + chunkTextures = new Map() + signsCache = new Map() + starField: StarField + cameraSectionPos: Vec3 = new Vec3(0, 0, 0) + holdingBlock: HoldingBlock + holdingBlockLeft: HoldingBlock + scene = new THREE.Scene() + ambientLight = new THREE.AmbientLight(0xcc_cc_cc) + directionalLight = new THREE.DirectionalLight(0xff_ff_ff, 0.5) + entities = new Entities(this) + cameraGroupVr?: THREE.Object3D + material = new THREE.MeshLambertMaterial({ vertexColors: true, transparent: true, alphaTest: 0.1 }) + itemsTexture: THREE.Texture + cursorBlock: CursorBlock + onRender: Array<() => void> = [] + cameraShake: CameraShake + cameraContainer: THREE.Object3D + media: ThreeJsMedia + waitingChunksToDisplay = {} as { [chunkKey: string]: SectionKey[] } + waypoints: WaypointsRenderer + camera: THREE.PerspectiveCamera + renderTimeAvg = 0 + sectionsOffsetsAnimations = {} as { + [chunkKey: string]: { + time: number, + // also specifies direction + speedX: number, + speedY: number, + speedZ: number, + + currentOffsetX: number, + currentOffsetY: number, + currentOffsetZ: number, + + limitX?: number, + limitY?: number, + limitZ?: number, + } + } + fountains: Fountain[] = [] + DEBUG_RAYCAST = false + skyboxRenderer: SkyboxRenderer + + private currentPosTween?: tweenJs.Tween + private currentRotTween?: tweenJs.Tween<{ pitch: number, yaw: number }> + + get tilesRendered () { + return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj as any).tilesCount, 0) + } + + get blocksRendered () { + return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj as any).blocksCount, 0) + } + + constructor (public renderer: THREE.WebGLRenderer, public initOptions: GraphicsInitOptions, public displayOptions: DisplayWorldOptions) { + if (!initOptions.resourcesManager) throw new Error('resourcesManager is required') + super(initOptions.resourcesManager, displayOptions, initOptions) + + this.renderer = renderer + displayOptions.rendererState.renderer = WorldRendererThree.getRendererInfo(renderer) ?? '...' + this.starField = new StarField(this) + this.cursorBlock = new CursorBlock(this) + this.holdingBlock = new HoldingBlock(this) + this.holdingBlockLeft = new HoldingBlock(this, true) + + // Initialize skybox renderer + this.skyboxRenderer = new SkyboxRenderer(this.scene, this.worldRendererConfig.defaultSkybox, null) + void this.skyboxRenderer.init() + + this.addDebugOverlay() + this.resetScene() + void this.init() + + this.soundSystem = new ThreeJsSound(this) + this.cameraShake = new CameraShake(this, this.onRender) + this.media = new ThreeJsMedia(this) + this.waypoints = new WaypointsRenderer(this) + + // this.fountain = new Fountain(this.scene, this.scene, { + // position: new THREE.Vector3(0, 10, 0), + // }) + + this.renderUpdateEmitter.on('chunkFinished', (chunkKey: string) => { + this.finishChunk(chunkKey) + }) + this.worldSwitchActions() + } + + get cameraObject () { + return this.cameraGroupVr ?? this.cameraContainer + } + + worldSwitchActions () { + this.onWorldSwitched.push(() => { + // clear custom blocks + this.protocolCustomBlocks.clear() + // Reset section animations + this.sectionsOffsetsAnimations = {} + // Clear waypoints + this.waypoints.clear() + }) + } + + updateEntity (e, isPosUpdate = false) { + const overrides = { + rotation: { + head: { + x: e.headPitch ?? e.pitch, + y: e.headYaw, + z: 0 + } + } + } + if (isPosUpdate) { + this.entities.updateEntityPosition(e, false, overrides) + } else { + this.entities.update(e, overrides) + } + } + + updatePlayerEntity (e: any) { + this.entities.handlePlayerEntity(e) + } + + resetScene () { + this.scene.matrixAutoUpdate = false // for perf + this.scene.background = new THREE.Color(this.initOptions.config.sceneBackground) + this.scene.add(this.ambientLight) + this.directionalLight.position.set(1, 1, 0.5).normalize() + this.directionalLight.castShadow = true + this.scene.add(this.directionalLight) + + const size = this.renderer.getSize(new THREE.Vector2()) + this.camera = new THREE.PerspectiveCamera(75, size.x / size.y, 0.1, 1000) + this.cameraContainer = new THREE.Object3D() + this.cameraContainer.add(this.camera) + this.scene.add(this.cameraContainer) + } + + override watchReactivePlayerState () { + super.watchReactivePlayerState() + this.onReactivePlayerStateUpdated('inWater', (value) => { + this.skyboxRenderer.updateWaterState(value, this.playerStateReactive.waterBreathing) + }) + this.onReactivePlayerStateUpdated('waterBreathing', (value) => { + this.skyboxRenderer.updateWaterState(this.playerStateReactive.inWater, value) + }) + this.onReactivePlayerStateUpdated('ambientLight', (value) => { + if (!value) return + this.ambientLight.intensity = value + }) + this.onReactivePlayerStateUpdated('directionalLight', (value) => { + if (!value) return + this.directionalLight.intensity = value + }) + this.onReactivePlayerStateUpdated('lookingAtBlock', (value) => { + this.cursorBlock.setHighlightCursorBlock(value ? new Vec3(value.x, value.y, value.z) : null, value?.shapes) + }) + this.onReactivePlayerStateUpdated('diggingBlock', (value) => { + this.cursorBlock.updateBreakAnimation(value ? { x: value.x, y: value.y, z: value.z } : undefined, value?.stage ?? null, value?.mergedShape) + }) + this.onReactivePlayerStateUpdated('perspective', (value) => { + // Update camera perspective when it changes + const vecPos = new Vec3(this.cameraObject.position.x, this.cameraObject.position.y, this.cameraObject.position.z) + this.updateCamera(vecPos, this.cameraShake.getBaseRotation().yaw, this.cameraShake.getBaseRotation().pitch) + // todo also update camera when block within camera was changed + }) + } + + override watchReactiveConfig () { + super.watchReactiveConfig() + this.onReactiveConfigUpdated('showChunkBorders', (value) => { + this.updateShowChunksBorder(value) + }) + this.onReactiveConfigUpdated('defaultSkybox', (value) => { + this.skyboxRenderer.updateDefaultSkybox(value) + }) + } + + changeHandSwingingState (isAnimationPlaying: boolean, isLeft = false) { + const holdingBlock = isLeft ? this.holdingBlockLeft : this.holdingBlock + if (isAnimationPlaying) { + holdingBlock.startSwing() + } else { + holdingBlock.stopSwing() + } + } + + async updateAssetsData (): Promise { + const resources = this.resourcesManager.currentResources + + const oldTexture = this.material.map + const oldItemsTexture = this.itemsTexture + + const texture = loadThreeJsTextureFromBitmap(resources.blocksAtlasImage) + texture.needsUpdate = true + texture.flipY = false + this.material.map = texture + + const itemsTexture = loadThreeJsTextureFromBitmap(resources.itemsAtlasImage) + itemsTexture.needsUpdate = true + itemsTexture.flipY = false + this.itemsTexture = itemsTexture + + if (oldTexture) { + oldTexture.dispose() + } + if (oldItemsTexture) { + oldItemsTexture.dispose() + } + + await super.updateAssetsData() + this.onAllTexturesLoaded() + if (Object.keys(this.loadedChunks).length > 0) { + console.log('rerendering chunks because of texture update') + this.rerenderAllChunks() + } + } + + onAllTexturesLoaded () { + this.holdingBlock.ready = true + this.holdingBlock.updateItem() + this.holdingBlockLeft.ready = true + this.holdingBlockLeft.updateItem() + } + + changeBackgroundColor (color: [number, number, number]): void { + this.scene.background = new THREE.Color(color[0], color[1], color[2]) + } + + timeUpdated (newTime: number): void { + const nightTime = 13_500 + const morningStart = 23_000 + const displayStars = newTime > nightTime && newTime < morningStart + if (displayStars) { + this.starField.addToScene() + } else { + this.starField.remove() + } + + this.skyboxRenderer.updateTime(newTime) + } + + biomeUpdated (biome: Biome): void { + if (biome?.temperature !== undefined) { + this.skyboxRenderer.updateTemperature(biome.temperature) + } + } + + biomeReset (): void { + // Reset to default temperature when biome is unknown + this.skyboxRenderer.updateTemperature(DEFAULT_TEMPERATURE) + } + + getItemRenderData (item: Record, specificProps: ItemSpecificContextProperties) { + return getItemUv(item, specificProps, this.resourcesManager, this.playerStateReactive) + } + + async demoModel () { + //@ts-expect-error + const pos = cursorBlockRel(0, 1, 0).position + + const mesh = (await getMyHand())! + // mesh.rotation.y = THREE.MathUtils.degToRad(90) + setBlockPosition(mesh, pos) + const helper = new THREE.BoxHelper(mesh, 0xff_ff_00) + mesh.add(helper) + this.scene.add(mesh) + } + + demoItem () { + //@ts-expect-error + const pos = cursorBlockRel(0, 1, 0).position + const { mesh } = this.entities.getItemMesh({ + itemId: 541, + }, {})! + mesh.position.set(pos.x + 0.5, pos.y + 0.5, pos.z + 0.5) + // mesh.scale.set(0.5, 0.5, 0.5) + const helper = new THREE.BoxHelper(mesh, 0xff_ff_00) + mesh.add(helper) + this.scene.add(mesh) + } + + debugOverlayAdded = false + addDebugOverlay () { + if (this.debugOverlayAdded) return + this.debugOverlayAdded = true + const pane = addNewStat('debug-overlay') + setInterval(() => { + pane.setVisibility(this.displayAdvancedStats) + if (this.displayAdvancedStats) { + const formatBigNumber = (num: number) => { + return new Intl.NumberFormat('en-US', {}).format(num) + } + let text = '' + text += `C: ${formatBigNumber(this.renderer.info.render.calls)} ` + text += `TR: ${formatBigNumber(this.renderer.info.render.triangles)} ` + text += `TE: ${formatBigNumber(this.renderer.info.memory.textures)} ` + text += `F: ${formatBigNumber(this.tilesRendered)} ` + text += `B: ${formatBigNumber(this.blocksRendered)}` + pane.updateText(text) + this.backendInfoReport = text + } + }, 200) + } + + /** + * Optionally update data that are depedendent on the viewer position + */ + updatePosDataChunk (key: string) { + const [x, y, z] = key.split(',').map(x => Math.floor(+x / 16)) + // sum of distances: x + y + z + 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 + } + + override updateViewerPosition (pos: Vec3): void { + this.viewerChunkPosition = pos + } + + cameraSectionPositionUpdate () { + // eslint-disable-next-line guard-for-in + for (const key in this.sectionObjects) { + const value = this.sectionObjects[key] + if (!value) continue + this.updatePosDataChunk(key) + } + } + + getDir (current: number, origin: number) { + if (current === origin) return 0 + return current < origin ? 1 : -1 + } + + finishChunk (chunkKey: string) { + for (const sectionKey of this.waitingChunksToDisplay[chunkKey] ?? []) { + this.sectionObjects[sectionKey].visible = true + } + delete this.waitingChunksToDisplay[chunkKey] + } + + // debugRecomputedDeletedObjects = 0 + handleWorkerMessage (data: { geometry: MesherGeometryOutput, key, type }): void { + if (data.type !== 'geometry') return + let object: THREE.Object3D = this.sectionObjects[data.key] + if (object) { + this.scene.remove(object) + disposeObject(object) + delete this.sectionObjects[data.key] + } + + const chunkCoords = data.key.split(',') + if (!this.loadedChunks[chunkCoords[0] + ',' + chunkCoords[2]] || !data.geometry.positions.length || !this.active) return + + // if (object) { + // this.debugRecomputedDeletedObjects++ + // } + + const geometry = new THREE.BufferGeometry() + geometry.setAttribute('position', new THREE.BufferAttribute(data.geometry.positions, 3)) + geometry.setAttribute('normal', new THREE.BufferAttribute(data.geometry.normals, 3)) + geometry.setAttribute('color', new THREE.BufferAttribute(data.geometry.colors, 3)) + geometry.setAttribute('uv', new THREE.BufferAttribute(data.geometry.uvs, 2)) + geometry.index = new THREE.BufferAttribute(data.geometry.indices as Uint32Array | Uint16Array, 1) + + const mesh = new THREE.Mesh(geometry, this.material) + mesh.position.set(data.geometry.sx, data.geometry.sy, data.geometry.sz) + mesh.name = 'mesh' + object = new THREE.Group() + object.add(mesh) + // mesh with static dimensions: 16x16x16 + const staticChunkMesh = new THREE.Mesh(new THREE.BoxGeometry(16, 16, 16), new THREE.MeshBasicMaterial({ color: 0x00_00_00, transparent: true, opacity: 0 })) + staticChunkMesh.position.set(data.geometry.sx, data.geometry.sy, data.geometry.sz) + const boxHelper = new THREE.BoxHelper(staticChunkMesh, 0xff_ff_00) + boxHelper.name = 'helper' + object.add(boxHelper) + object.name = 'chunk'; + (object as any).tilesCount = data.geometry.positions.length / 3 / 4; + (object as any).blocksCount = data.geometry.blocksCount + if (!this.displayOptions.inWorldRenderingConfig.showChunkBorders) { + boxHelper.visible = false + } + // should not compute it once + if (Object.keys(data.geometry.signs).length) { + for (const [posKey, { isWall, isHanging, rotation }] of Object.entries(data.geometry.signs)) { + const signBlockEntity = this.blockEntities[posKey] + if (!signBlockEntity) continue + const [x, y, z] = posKey.split(',') + const sign = this.renderSign(new Vec3(+x, +y, +z), rotation, isWall, isHanging, nbt.simplify(signBlockEntity)) + if (!sign) continue + object.add(sign) + } + } + if (Object.keys(data.geometry.heads).length) { + for (const [posKey, { isWall, rotation }] of Object.entries(data.geometry.heads)) { + const headBlockEntity = this.blockEntities[posKey] + if (!headBlockEntity) continue + const [x, y, z] = posKey.split(',') + const head = this.renderHead(new Vec3(+x, +y, +z), rotation, isWall, nbt.simplify(headBlockEntity)) + if (!head) continue + object.add(head) + } + } + this.sectionObjects[data.key] = object + if (this.displayOptions.inWorldRenderingConfig._renderByChunks) { + object.visible = false + const chunkKey = `${chunkCoords[0]},${chunkCoords[2]}` + this.waitingChunksToDisplay[chunkKey] ??= [] + this.waitingChunksToDisplay[chunkKey].push(data.key) + if (this.finishedChunks[chunkKey]) { + // todo it might happen even when it was not an update + this.finishChunk(chunkKey) + } + } + + this.updatePosDataChunk(data.key) + object.matrixAutoUpdate = false + mesh.onAfterRender = (renderer, scene, camera, geometry, material, group) => { + // mesh.matrixAutoUpdate = false + } + + this.scene.add(object) + } + + getSignTexture (position: Vec3, blockEntity, isHanging, backSide = false) { + const chunk = chunkPos(position) + let textures = this.chunkTextures.get(`${chunk[0]},${chunk[1]}`) + if (!textures) { + textures = {} + this.chunkTextures.set(`${chunk[0]},${chunk[1]}`, textures) + } + const texturekey = `${position.x},${position.y},${position.z}` + // todo investigate bug and remove this so don't need to clean in section dirty + if (textures[texturekey]) return textures[texturekey] + + const PrismarineChat = PrismarineChatLoader(this.version) + const canvas = renderSign(blockEntity, isHanging, PrismarineChat) + if (!canvas) return + const tex = new THREE.Texture(canvas) + tex.magFilter = THREE.NearestFilter + tex.minFilter = THREE.NearestFilter + tex.needsUpdate = true + textures[texturekey] = tex + return tex + } + + getCameraPosition () { + const worldPos = new THREE.Vector3() + this.camera.getWorldPosition(worldPos) + return worldPos + } + + getSectionCameraPosition () { + const pos = this.getCameraPosition() + return new Vec3( + Math.floor(pos.x / 16), + Math.floor(pos.y / 16), + Math.floor(pos.z / 16) + ) + } + + updateCameraSectionPos () { + const newSectionPos = this.getSectionCameraPosition() + if (!this.cameraSectionPos.equals(newSectionPos)) { + this.cameraSectionPos = newSectionPos + this.cameraSectionPositionUpdate() + } + } + + setFirstPersonCamera (pos: Vec3 | null, yaw: number, pitch: number) { + const yOffset = this.playerStateReactive.eyeHeight + + this.updateCamera(pos?.offset(0, yOffset, 0) ?? null, yaw, pitch) + this.media.tryIntersectMedia() + this.updateCameraSectionPos() + } + + getThirdPersonCamera (pos: THREE.Vector3 | null, yaw: number, pitch: number) { + pos ??= this.cameraObject.position + + // Calculate camera offset based on perspective + const isBack = this.playerStateReactive.perspective === 'third_person_back' + const distance = 4 // Default third person distance + + // Calculate direction vector using proper world orientation + // We need to get the camera's current look direction and use that for positioning + + // Create a direction vector that represents where the camera is looking + // This matches the Three.js camera coordinate system + const direction = new THREE.Vector3(0, 0, -1) // Forward direction in camera space + + // Apply the same rotation that's applied to the camera container + const pitchQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), pitch) + const yawQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), yaw) + const finalQuat = new THREE.Quaternion().multiplyQuaternions(yawQuat, pitchQuat) + + // Transform the direction vector by the camera's rotation + direction.applyQuaternion(finalQuat) + + // For back view, we want the camera behind the player (opposite to view direction) + // For front view, we want the camera in front of the player (same as view direction) + if (isBack) { + direction.multiplyScalar(-1) + } + + // Create debug visualization if advanced stats are enabled + if (this.DEBUG_RAYCAST) { + this.debugRaycast(pos, direction, distance) + } + + // Perform raycast to avoid camera going through blocks + const raycaster = new THREE.Raycaster() + raycaster.set(pos, direction) + raycaster.far = distance // Limit raycast distance + + // Filter to only nearby chunks for performance + const nearbyChunks = Object.values(this.sectionObjects) + .filter(obj => obj.name === 'chunk' && obj.visible) + .filter(obj => { + // Get the mesh child which has the actual geometry + const mesh = obj.children.find(child => child.name === 'mesh') + if (!mesh) return false + + // Check distance from player position to chunk + const chunkWorldPos = new THREE.Vector3() + mesh.getWorldPosition(chunkWorldPos) + const distance = pos.distanceTo(chunkWorldPos) + return distance < 80 // Only check chunks within 80 blocks + }) + + // Get all mesh children for raycasting + const meshes: THREE.Object3D[] = [] + for (const chunk of nearbyChunks) { + const mesh = chunk.children.find(child => child.name === 'mesh') + if (mesh) meshes.push(mesh) + } + + const intersects = raycaster.intersectObjects(meshes, false) + + let finalDistance = distance + if (intersects.length > 0) { + // Use intersection distance minus a small offset to prevent clipping + finalDistance = Math.max(0.5, intersects[0].distance - 0.2) + } + + const finalPos = new Vec3( + pos.x + direction.x * finalDistance, + pos.y + direction.y * finalDistance, + pos.z + direction.z * finalDistance + ) + + return finalPos + } + + private debugRaycastHelper?: THREE.ArrowHelper + private debugHitPoint?: THREE.Mesh + + private debugRaycast (pos: THREE.Vector3, direction: THREE.Vector3, distance: number) { + // Remove existing debug objects + if (this.debugRaycastHelper) { + this.scene.remove(this.debugRaycastHelper) + this.debugRaycastHelper = undefined + } + if (this.debugHitPoint) { + this.scene.remove(this.debugHitPoint) + this.debugHitPoint = undefined + } + + // Create raycast arrow + this.debugRaycastHelper = new THREE.ArrowHelper( + direction.clone().normalize(), + pos, + distance, + 0xff_00_00, // Red color + distance * 0.1, + distance * 0.05 + ) + this.scene.add(this.debugRaycastHelper) + + // Create hit point indicator + const hitGeometry = new THREE.SphereGeometry(0.2, 8, 8) + const hitMaterial = new THREE.MeshBasicMaterial({ color: 0x00_ff_00 }) + this.debugHitPoint = new THREE.Mesh(hitGeometry, hitMaterial) + this.debugHitPoint.position.copy(pos).add(direction.clone().multiplyScalar(distance)) + this.scene.add(this.debugHitPoint) + } + + prevFramePerspective = null as string | null + + updateCamera (pos: Vec3 | null, yaw: number, pitch: number): void { + // if (this.freeFlyMode) { + // pos = this.freeFlyState.position + // pitch = this.freeFlyState.pitch + // yaw = this.freeFlyState.yaw + // } + + if (pos) { + if (this.renderer.xr.isPresenting) { + pos.y -= this.camera.position.y // Fix Y position of camera in world + } + + this.currentPosTween?.stop() + this.currentPosTween = new tweenJs.Tween(this.cameraObject.position).to({ x: pos.x, y: pos.y, z: pos.z }, this.playerStateUtils.isSpectatingEntity() ? 150 : 50).start() + // this.freeFlyState.position = pos + } + + if (this.playerStateUtils.isSpectatingEntity()) { + const rotation = this.cameraShake.getBaseRotation() + // wrap in the correct direction + let yawOffset = 0 + const halfPi = Math.PI / 2 + if (rotation.yaw < halfPi && yaw > Math.PI + halfPi) { + yawOffset = -Math.PI * 2 + } else if (yaw < halfPi && rotation.yaw > Math.PI + halfPi) { + yawOffset = Math.PI * 2 + } + this.currentRotTween?.stop() + this.currentRotTween = new tweenJs.Tween(rotation).to({ pitch, yaw: yaw + yawOffset }, 100) + .onUpdate(params => this.cameraShake.setBaseRotation(params.pitch, params.yaw - yawOffset)).start() + } else { + this.currentRotTween?.stop() + this.cameraShake.setBaseRotation(pitch, yaw) + + const { perspective } = this.playerStateReactive + if (perspective === 'third_person_back' || perspective === 'third_person_front') { + // Use getThirdPersonCamera for proper raycasting with max distance of 4 + const currentCameraPos = this.cameraObject.position + const thirdPersonPos = this.getThirdPersonCamera( + new THREE.Vector3(currentCameraPos.x, currentCameraPos.y, currentCameraPos.z), + yaw, + pitch + ) + + const distance = currentCameraPos.distanceTo(new THREE.Vector3(thirdPersonPos.x, thirdPersonPos.y, thirdPersonPos.z)) + // Apply Z offset based on perspective and calculated distance + const zOffset = perspective === 'third_person_back' ? distance : -distance + this.camera.position.set(0, 0, zOffset) + + if (perspective === 'third_person_front') { + // Flip camera view 180 degrees around Y axis for front view + this.camera.rotation.set(0, Math.PI, 0) + } else { + this.camera.rotation.set(0, 0, 0) + } + } else { + this.camera.position.set(0, 0, 0) + this.camera.rotation.set(0, 0, 0) + + // remove any debug raycasting + if (this.debugRaycastHelper) { + this.scene.remove(this.debugRaycastHelper) + this.debugRaycastHelper = undefined + } + if (this.debugHitPoint) { + this.scene.remove(this.debugHitPoint) + this.debugHitPoint = undefined + } + } + } + + this.updateCameraSectionPos() + } + + debugChunksVisibilityOverride () { + const { chunksRenderAboveOverride, chunksRenderBelowOverride, chunksRenderDistanceOverride, chunksRenderAboveEnabled, chunksRenderBelowEnabled, chunksRenderDistanceEnabled } = this.reactiveDebugParams + + const baseY = this.cameraSectionPos.y * 16 + + if ( + this.displayOptions.inWorldRenderingConfig.enableDebugOverlay && + chunksRenderAboveOverride !== undefined || + chunksRenderBelowOverride !== undefined || + chunksRenderDistanceOverride !== undefined + ) { + for (const [key, object] of Object.entries(this.sectionObjects)) { + const [x, y, z] = key.split(',').map(Number) + const isVisible = + // eslint-disable-next-line no-constant-binary-expression, sonarjs/no-redundant-boolean + (chunksRenderAboveEnabled && chunksRenderAboveOverride !== undefined) ? y <= (baseY + chunksRenderAboveOverride) : true && + // eslint-disable-next-line @stylistic/indent-binary-ops, no-constant-binary-expression, sonarjs/no-redundant-boolean + (chunksRenderBelowEnabled && chunksRenderBelowOverride !== undefined) ? y >= (baseY - chunksRenderBelowOverride) : true && + // eslint-disable-next-line @stylistic/indent-binary-ops + (chunksRenderDistanceEnabled && chunksRenderDistanceOverride !== undefined) ? Math.abs(y - baseY) <= chunksRenderDistanceOverride : true + + object.visible = isVisible + } + } else { + for (const object of Object.values(this.sectionObjects)) { + object.visible = true + } + } + } + + render (sizeChanged = false) { + if (this.reactiveDebugParams.stopRendering) return + this.debugChunksVisibilityOverride() + const start = performance.now() + this.lastRendered = performance.now() + this.cursorBlock.render() + this.updateSectionOffsets() + + // Update skybox position to follow camera + const cameraPos = this.getCameraPosition() + this.skyboxRenderer.update(cameraPos, this.viewDistance) + + const sizeOrFovChanged = sizeChanged || this.displayOptions.inWorldRenderingConfig.fov !== this.camera.fov + if (sizeOrFovChanged) { + const size = this.renderer.getSize(new THREE.Vector2()) + this.camera.aspect = size.width / size.height + this.camera.fov = this.displayOptions.inWorldRenderingConfig.fov + this.camera.updateProjectionMatrix() + } + + if (!this.reactiveDebugParams.disableEntities) { + this.entities.render() + } + + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style + const cam = this.cameraGroupVr instanceof THREE.Group ? this.cameraGroupVr.children.find(child => child instanceof THREE.PerspectiveCamera) as THREE.PerspectiveCamera : this.camera + this.renderer.render(this.scene, cam) + + if ( + this.displayOptions.inWorldRenderingConfig.showHand && + this.playerStateReactive.gameMode !== 'spectator' && + this.playerStateReactive.perspective === 'first_person' && + // !this.freeFlyMode && + !this.renderer.xr.isPresenting + ) { + this.holdingBlock.render(this.camera, this.renderer, this.ambientLight, this.directionalLight) + this.holdingBlockLeft.render(this.camera, this.renderer, this.ambientLight, this.directionalLight) + } + + for (const fountain of this.fountains) { + if (this.sectionObjects[fountain.sectionId] && !this.sectionObjects[fountain.sectionId].foutain) { + fountain.createParticles(this.sectionObjects[fountain.sectionId]) + this.sectionObjects[fountain.sectionId].foutain = true + } + fountain.render() + } + + this.waypoints.render() + + for (const onRender of this.onRender) { + onRender() + } + const end = performance.now() + const totalTime = end - start + this.renderTimeAvgCount++ + this.renderTimeAvg = ((this.renderTimeAvg * (this.renderTimeAvgCount - 1)) + totalTime) / this.renderTimeAvgCount + this.renderTimeMax = Math.max(this.renderTimeMax, totalTime) + this.currentRenderedFrames++ + } + + renderHead (position: Vec3, rotation: number, isWall: boolean, blockEntity) { + let textureData: string + if (blockEntity.SkullOwner) { + textureData = blockEntity.SkullOwner.Properties?.textures?.[0]?.Value + } else { + textureData = blockEntity.profile?.properties?.find(p => p.name === 'textures')?.value + } + if (!textureData) return + + try { + const decodedData = JSON.parse(Buffer.from(textureData, 'base64').toString()) + let skinUrl = decodedData.textures?.SKIN?.url + const { skinTexturesProxy } = this.worldRendererConfig + if (skinTexturesProxy) { + skinUrl = skinUrl?.replace('http://textures.minecraft.net/', skinTexturesProxy) + .replace('https://textures.minecraft.net/', skinTexturesProxy) + } + + const mesh = getMesh(this, skinUrl, armorModel.head) + const group = new THREE.Group() + if (isWall) { + mesh.position.set(0, 0.3125, 0.3125) + } + // move head model down as armor have a different offset than blocks + mesh.position.y -= 23 / 16 + group.add(mesh) + group.position.set(position.x + 0.5, position.y + 0.045, position.z + 0.5) + group.rotation.set( + 0, + -THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)), + 0 + ) + group.scale.set(0.8, 0.8, 0.8) + return group + } catch (err) { + console.error('Error decoding player texture:', err) + } + } + + renderSign (position: Vec3, rotation: number, isWall: boolean, isHanging: boolean, blockEntity) { + const tex = this.getSignTexture(position, blockEntity, isHanging) + + if (!tex) return + + // todo implement + // const key = JSON.stringify({ position, rotation, isWall }) + // if (this.signsCache.has(key)) { + // console.log('cached', key) + // } else { + // this.signsCache.set(key, tex) + // } + + const mesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), new THREE.MeshBasicMaterial({ map: tex, transparent: true })) + mesh.renderOrder = 999 + + 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 { + mesh.position.set(0, 0, thickness / 2 + 0.0001) + } + + const group = new THREE.Group() + group.rotation.set( + 0, + -THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)), + 0 + ) + group.add(mesh) + 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 + } + + lightUpdate (chunkX: number, chunkZ: number) { + // set all sections in the chunk dirty + for (let y = this.worldSizeParams.minY; y < this.worldSizeParams.worldHeight; y += 16) { + this.setSectionDirty(new Vec3(chunkX, y, chunkZ)) + } + } + + rerenderAllChunks () { // todo not clear what to do with loading chunks + for (const key of Object.keys(this.sectionObjects)) { + const [x, y, z] = key.split(',').map(Number) + this.setSectionDirty(new Vec3(x, y, z)) + } + } + + updateShowChunksBorder (value: boolean) { + for (const object of Object.values(this.sectionObjects)) { + for (const child of object.children) { + if (child.name === 'helper') { + child.visible = value + } + } + } + } + + resetWorld () { + super.resetWorld() + + for (const mesh of Object.values(this.sectionObjects)) { + this.scene.remove(mesh) + } + + // Clean up debug objects + if (this.debugRaycastHelper) { + this.scene.remove(this.debugRaycastHelper) + this.debugRaycastHelper = undefined + } + if (this.debugHitPoint) { + this.scene.remove(this.debugHitPoint) + this.debugHitPoint = undefined + } + } + + getLoadedChunksRelative (pos: Vec3, includeY = false) { + const [currentX, currentY, currentZ] = sectionPos(pos) + return Object.fromEntries(Object.entries(this.sectionObjects).map(([key, o]) => { + const [xRaw, yRaw, zRaw] = key.split(',').map(Number) + const [x, y, z] = sectionPos({ x: xRaw, y: yRaw, z: zRaw }) + const setKey = includeY ? `${x - currentX},${y - currentY},${z - currentZ}` : `${x - currentX},${z - currentZ}` + return [setKey, o] + })) + } + + cleanChunkTextures (x, z) { + const textures = this.chunkTextures.get(`${Math.floor(x / 16)},${Math.floor(z / 16)}`) ?? {} + for (const key of Object.keys(textures)) { + textures[key].dispose() + delete textures[key] + } + } + + 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) + + this.cleanChunkTextures(x, z) + for (let y = this.worldSizeParams.minY; y < this.worldSizeParams.worldHeight; y += 16) { + this.setSectionDirty(new Vec3(x, y, z), false) + const key = `${x},${y},${z}` + const mesh = this.sectionObjects[key] + if (mesh) { + this.scene.remove(mesh) + disposeObject(mesh) + } + delete this.sectionObjects[key] + } + } + + setSectionDirty (...args: Parameters) { + const [pos] = args + this.cleanChunkTextures(pos.x, pos.z) // todo don't do this! + super.setSectionDirty(...args) + } + + static getRendererInfo (renderer: THREE.WebGLRenderer) { + try { + const gl = renderer.getContext() + return `${gl.getParameter(gl.getExtension('WEBGL_debug_renderer_info')!.UNMASKED_RENDERER_WEBGL)}` + } catch (err) { + console.warn('Failed to get renderer info', err) + } + } + + worldStop () { + this.media.onWorldStop() + } + + destroy (): void { + super.destroy() + this.skyboxRenderer.dispose() + } + + shouldObjectVisible (object: THREE.Object3D) { + // Get chunk coordinates + const chunkX = Math.floor(object.position.x / 16) * 16 + const chunkZ = Math.floor(object.position.z / 16) * 16 + const sectionY = Math.floor(object.position.y / 16) * 16 + + const chunkKey = `${chunkX},${chunkZ}` + const sectionKey = `${chunkX},${sectionY},${chunkZ}` + + return !!this.finishedChunks[chunkKey] || !!this.sectionObjects[sectionKey] + } + + updateSectionOffsets () { + const currentTime = performance.now() + for (const [key, anim] of Object.entries(this.sectionsOffsetsAnimations)) { + const timeDelta = (currentTime - anim.time) / 1000 // Convert to seconds + anim.time = currentTime + + // Update offsets based on speed and time delta + anim.currentOffsetX += anim.speedX * timeDelta + anim.currentOffsetY += anim.speedY * timeDelta + anim.currentOffsetZ += anim.speedZ * timeDelta + + // Apply limits if they exist + if (anim.limitX !== undefined) { + if (anim.speedX > 0) { + anim.currentOffsetX = Math.min(anim.currentOffsetX, anim.limitX) + } else { + anim.currentOffsetX = Math.max(anim.currentOffsetX, anim.limitX) + } + } + if (anim.limitY !== undefined) { + if (anim.speedY > 0) { + anim.currentOffsetY = Math.min(anim.currentOffsetY, anim.limitY) + } else { + anim.currentOffsetY = Math.max(anim.currentOffsetY, anim.limitY) + } + } + if (anim.limitZ !== undefined) { + if (anim.speedZ > 0) { + anim.currentOffsetZ = Math.min(anim.currentOffsetZ, anim.limitZ) + } else { + anim.currentOffsetZ = Math.max(anim.currentOffsetZ, anim.limitZ) + } + } + + // Apply the offset to the section object + const section = this.sectionObjects[key] + if (section) { + section.position.set( + anim.currentOffsetX, + anim.currentOffsetY, + anim.currentOffsetZ + ) + section.updateMatrix() + } + } + } + + reloadWorld () { + this.entities.reloadEntities() + } +} + +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 readonly worldRenderer: WorldRendererThree + ) { + const clock = new THREE.Clock() + const speed = 0.2 + this.worldRenderer.onRender.push(() => { + if (!this.points) return + this.points.position.copy(this.worldRenderer.getCameraPosition()); + (this.points.material as StarfieldMaterial).uniforms.time.value = clock.getElapsedTime() * speed + }) + } + + addToScene () { + if (this.points || !this.enabled) return + + const radius = 80 + const depth = 50 + const count = 7000 + const factor = 7 + const saturation = 10 + + const geometry = new THREE.BufferGeometry() + + const genStar = r => new THREE.Vector3().setFromSpherical(new THREE.Spherical(r, Math.acos(1 - Math.random() * 2), Math.random() * 2 * Math.PI)) + + const positions = [] as number[] + const colors = [] as number[] + const sizes = Array.from({ length: count }, () => (0.5 + 0.5 * Math.random()) * factor) + const color = new THREE.Color() + let r = radius + depth + const increment = depth / count + for (let i = 0; i < count; i++) { + r -= increment * Math.random() + positions.push(...genStar(r).toArray()) + color.setHSL(i / count, saturation, 0.9) + colors.push(color.r, color.g, color.b) + } + + geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)) + geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)) + geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1)) + + // Create a material + const material = new StarfieldMaterial() + material.blending = THREE.AdditiveBlending + material.depthTest = false + material.transparent = true + + // Create points and add them to the scene + this.points = new THREE.Points(geometry, material) + this.worldRenderer.scene.add(this.points) + + this.points.renderOrder = -1 + } + + remove () { + if (this.points) { + this.points.geometry.dispose(); + (this.points.material as THREE.Material).dispose() + this.worldRenderer.scene.remove(this.points) + + this.points = undefined + } + } +} + +const version = parseInt(THREE.REVISION.replaceAll(/\D+/g, ''), 10) +class StarfieldMaterial extends THREE.ShaderMaterial { + constructor () { + super({ + uniforms: { time: { value: 0 }, fade: { value: 1 } }, + vertexShader: /* glsl */ ` + uniform float time; + attribute float size; + varying vec3 vColor; + attribute vec3 color; + void main() { + vColor = color; + vec4 mvPosition = modelViewMatrix * vec4(position, 0.5); + gl_PointSize = 0.7 * size * (30.0 / -mvPosition.z) * (3.0 + sin(time + 100.0)); + gl_Position = projectionMatrix * mvPosition; + }`, + fragmentShader: /* glsl */ ` + uniform sampler2D pointTexture; + uniform float fade; + varying vec3 vColor; + void main() { + float opacity = 1.0; + gl_FragColor = vec4(vColor, 1.0); + + #include + #include <${version >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}> + }`, + }) + } +} diff --git a/rsbuild.config.ts b/rsbuild.config.ts new file mode 100644 index 00000000..6cd6b2ed --- /dev/null +++ b/rsbuild.config.ts @@ -0,0 +1,298 @@ +/// +import { defineConfig, mergeRsbuildConfig, RsbuildPluginAPI } from '@rsbuild/core' +import { pluginReact } from '@rsbuild/plugin-react' +import { pluginTypedCSSModules } from '@rsbuild/plugin-typed-css-modules' +import { pluginNodePolyfill } from '@rsbuild/plugin-node-polyfill' +import { pluginTypeCheck } from '@rsbuild/plugin-type-check' +import path from 'path' +import childProcess from 'child_process' +import fs from 'fs' +import fsExtra from 'fs-extra' +import { promisify } from 'util' +import { generateSW } from 'workbox-build' +import { getSwAdditionalEntries } from './scripts/build' +import { appAndRendererSharedConfig } from './renderer/rsbuildSharedConfig' +import { genLargeDataAliases } from './scripts/genLargeDataAliases' +import sharp from 'sharp' +import supportedVersions from './src/supportedVersions.mjs' +import { startWsServer } from './scripts/wsServer' + +const SINGLE_FILE_BUILD = process.env.SINGLE_FILE_BUILD === 'true' + +if (SINGLE_FILE_BUILD) { + const patchCssFile = 'node_modules/pixelarticons/fonts/pixelart-icons-font.css' + const text = fs.readFileSync(patchCssFile, 'utf8') + fs.writeFileSync(patchCssFile, text.replaceAll("url('pixelart-icons-font.ttf?t=1711815892278') format('truetype'),", ""), 'utf8') +} + +//@ts-ignore +try { require('./localSettings.js') } catch { } + +const execAsync = promisify(childProcess.exec) + +const buildingVersion = new Date().toISOString().split(':')[0] + +const dev = process.env.NODE_ENV === 'development' +const disableServiceWorker = process.env.DISABLE_SERVICE_WORKER === 'true' + +let releaseTag +let releaseLink +let releaseChangelog +let githubRepositoryFallback + +if (fs.existsSync('./assets/release.json')) { + const releaseJson = JSON.parse(fs.readFileSync('./assets/release.json', 'utf8')) + releaseTag = releaseJson.latestTag + releaseLink = releaseJson.isCommit ? `/commit/${releaseJson.latestTag}` : `/releases/${releaseJson.latestTag}` + releaseChangelog = releaseJson.changelog?.replace(//, '') + githubRepositoryFallback = releaseJson.repository +} + +const configJson = JSON.parse(fs.readFileSync('./config.json', 'utf8')) +try { + Object.assign(configJson, JSON.parse(fs.readFileSync(process.env.LOCAL_CONFIG_FILE || './config.local.json', 'utf8'))) +} catch (err) {} +if (dev) { + configJson.defaultProxy = ':8080' +} + +const configSource = (SINGLE_FILE_BUILD ? 'BUNDLED' : (process.env.CONFIG_JSON_SOURCE || 'REMOTE')) as 'BUNDLED' | 'REMOTE' + +const faviconPath = 'favicon.png' + +const enableMetrics = process.env.ENABLE_METRICS === 'true' + +// base options are in ./renderer/rsbuildSharedConfig.ts +const appConfig = defineConfig({ + html: { + template: './index.html', + inject: 'body', + tags: [ + ...SINGLE_FILE_BUILD ? [] : [ + { + tag: 'link', + attrs: { + rel: 'manifest', + crossorigin: 'anonymous', + href: 'manifest.json' + }, + } + ], + // + // + // + { + tag: 'link', + attrs: { + rel: 'favicon', + href: faviconPath + } + }, + ...SINGLE_FILE_BUILD ? [] : [ + { + tag: 'link', + attrs: { + rel: 'icon', + type: 'image/png', + href: faviconPath + } + }, + { + tag: 'meta', + attrs: { + property: 'og:image', + content: faviconPath + } + } + ] + ] + }, + output: { + externals: [ + 'sharp' + ], + sourceMap: { + js: 'source-map', + css: true, + }, + minify: { + // js: false, + jsOptions: { + minimizerOptions: { + mangle: { + safari10: true, + keep_classnames: true, + keep_fnames: true, + keep_private_props: true, + }, + compress: { + unused: true, + }, + }, + }, + }, + distPath: SINGLE_FILE_BUILD ? { + html: './single', + } : undefined, + inlineScripts: SINGLE_FILE_BUILD, + inlineStyles: SINGLE_FILE_BUILD, + // 50kb limit for data uri + dataUriLimit: SINGLE_FILE_BUILD ? 1 * 1024 * 1024 * 1024 : 50 * 1024 + }, + performance: { + // prefetch: { + // include(filename) { + // return filename.includes('mc-data') || filename.includes('mc-assets') + // }, + // }, + }, + source: { + entry: { + index: './src/index.ts', + }, + // exclude: [ + // /.woff$/ + // ], + define: { + 'process.env.BUILD_VERSION': JSON.stringify(!dev ? buildingVersion : 'undefined'), + 'process.env.MAIN_MENU_LINKS': JSON.stringify(process.env.MAIN_MENU_LINKS), + 'process.env.SINGLE_FILE_BUILD': JSON.stringify(process.env.SINGLE_FILE_BUILD), + 'process.env.SINGLE_FILE_BUILD_MODE': JSON.stringify(process.env.SINGLE_FILE_BUILD), + 'process.platform': '"browser"', + 'process.env.GITHUB_URL': + JSON.stringify(`https://github.com/${process.env.GITHUB_REPOSITORY || `${process.env.VERCEL_GIT_REPO_OWNER}/${process.env.VERCEL_GIT_REPO_SLUG}` || githubRepositoryFallback}`), + 'process.env.ALWAYS_MINIMAL_SERVER_UI': JSON.stringify(process.env.ALWAYS_MINIMAL_SERVER_UI), + 'process.env.RELEASE_TAG': JSON.stringify(releaseTag), + 'process.env.RELEASE_LINK': JSON.stringify(releaseLink), + 'process.env.RELEASE_CHANGELOG': JSON.stringify(releaseChangelog), + 'process.env.DISABLE_SERVICE_WORKER': JSON.stringify(disableServiceWorker), + 'process.env.INLINED_APP_CONFIG': JSON.stringify(configSource === 'BUNDLED' ? configJson : null), + 'process.env.ENABLE_COOKIE_STORAGE': JSON.stringify(process.env.ENABLE_COOKIE_STORAGE || true), + 'process.env.COOKIE_STORAGE_PREFIX': JSON.stringify(process.env.COOKIE_STORAGE_PREFIX || ''), + 'process.env.WS_PORT': JSON.stringify(enableMetrics ? 8081 : false), + }, + }, + server: { + // strictPort: true, + // publicDir: { + // name: 'assets', + // }, + proxy: { + '/api': 'http://localhost:8080', + }, + }, + plugins: [ + pluginTypedCSSModules(), + { + name: 'test', + setup(build: RsbuildPluginAPI) { + const prep = async () => { + console.time('total-prep') + fs.mkdirSync('./generated', { recursive: true }) + if (!fs.existsSync('./generated/minecraft-data-optimized.json') || !fs.existsSync('./generated/mc-assets-compressed.js') || require('./generated/minecraft-data-optimized.json').versionKey !== require('minecraft-data/package.json').version) { + childProcess.execSync('tsx ./scripts/makeOptimizedMcData.mjs', { stdio: 'inherit' }) + } + childProcess.execSync('tsx ./scripts/genShims.ts', { stdio: 'inherit' }) + if (!fs.existsSync('./generated/latestBlockCollisionsShapes.json') || require('./generated/latestBlockCollisionsShapes.json').versionKey !== require('minecraft-data/package.json').version) { + childProcess.execSync('tsx ./scripts/optimizeBlockCollisions.ts', { stdio: 'inherit' }) + } + // childProcess.execSync(['tsx', './scripts/genLargeDataAliases.ts', ...(SINGLE_FILE_BUILD ? ['--compressed'] : [])].join(' '), { stdio: 'inherit' }) + genLargeDataAliases(SINGLE_FILE_BUILD || process.env.ALWAYS_COMPRESS_LARGE_DATA === 'true') + fsExtra.copySync('./node_modules/mc-assets/dist/other-textures/latest/entity', './dist/textures/entity') + fsExtra.copySync('./assets/background', './dist/background') + fs.copyFileSync('./assets/favicon.png', './dist/favicon.png') + fs.copyFileSync('./assets/playground.html', './dist/playground.html') + fs.copyFileSync('./assets/manifest.json', './dist/manifest.json') + fs.copyFileSync('./assets/config.html', './dist/config.html') + fs.copyFileSync('./assets/debug-inputs.html', './dist/debug-inputs.html') + fs.copyFileSync('./assets/loading-bg.jpg', './dist/loading-bg.jpg') + if (fs.existsSync('./assets/release.json')) { + fs.copyFileSync('./assets/release.json', './dist/release.json') + } + + if (configSource === 'REMOTE') { + fs.writeFileSync('./dist/config.json', JSON.stringify(configJson, undefined, 2), 'utf8') + } + if (fs.existsSync('./generated/sounds.js')) { + fs.copyFileSync('./generated/sounds.js', './dist/sounds.js') + } + // childProcess.execSync('./scripts/prepareSounds.mjs', { stdio: 'inherit' }) + // childProcess.execSync('tsx ./scripts/genMcDataTypes.ts', { stdio: 'inherit' }) + // childProcess.execSync('tsx ./scripts/genPixelartTypes.ts', { stdio: 'inherit' }) + if (fs.existsSync('./renderer/dist/mesher.js') && dev) { + // copy mesher + fs.copyFileSync('./renderer/dist/mesher.js', './dist/mesher.js') + fs.copyFileSync('./renderer/dist/mesher.js.map', './dist/mesher.js.map') + } else if (!dev) { + await execAsync('pnpm run build-mesher') + } + fs.writeFileSync('./dist/version.txt', buildingVersion, 'utf-8') + + // Start WebSocket server in development + if (dev && enableMetrics) { + await startWsServer(8081, false) + } + + console.timeEnd('total-prep') + } + if (!dev) { + build.onBeforeBuild(async () => { + prep() + }) + build.onAfterBuild(async () => { + if (fs.readdirSync('./assets/customTextures').length > 0) { + childProcess.execSync('tsx ./scripts/patchAssets.ts', { stdio: 'inherit' }) + } + + if (SINGLE_FILE_BUILD) { + // check that only index.html is in the dist/single folder + const singleBuildFiles = fs.readdirSync('./dist/single') + if (singleBuildFiles.length !== 1 || singleBuildFiles[0] !== 'index.html') { + throw new Error('Single file build must only have index.html in the dist/single folder. Ensure workers are imported & built correctly.') + } + + // process index.html + const singleBuildHtml = './dist/single/index.html' + let html = fs.readFileSync(singleBuildHtml, 'utf8') + const verToMajor = (ver: string) => ver.split('.').slice(0, 2).join('.') + const supportedMajorVersions = [...new Set(supportedVersions.map(a => verToMajor(a)))].join(', ') + html = `\n\n\n${html}` + + const resizedImage = (await (sharp('./assets/favicon.png') as any).resize(64).toBuffer()).toString('base64') + html = html.replace('favicon.png', `data:image/png;base64,${resizedImage}`) + html = html.replace('src="./loading-bg.jpg"', `src="data:image/png;base64,${fs.readFileSync('./assets/loading-bg.jpg', 'base64')}"`) + html += '' + fs.writeFileSync(singleBuildHtml, html, 'utf8') + // write output file size + console.log('single file size', (fs.statSync(singleBuildHtml).size / 1024 / 1024).toFixed(2), 'mb') + } else { + if (!disableServiceWorker) { + const { count, size, warnings } = await generateSW({ + // dontCacheBustURLsMatching: [new RegExp('...')], + globDirectory: 'dist', + skipWaiting: true, + clientsClaim: true, + additionalManifestEntries: getSwAdditionalEntries(), + globPatterns: [], + swDest: './dist/service-worker.js', + }) + } + } + }) + } + build.onBeforeStartDevServer(() => prep()) + }, + }, + ], + // performance: { + // bundleAnalyze: { + // analyzerMode: 'json', + // reportFilename: 'report.json', + // }, + // }, +}) + +export default mergeRsbuildConfig( + appAndRendererSharedConfig(), + appConfig +) diff --git a/scripts/build.js b/scripts/build.js index 9fcc6d2c..2d5e0a2e 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -5,18 +5,15 @@ const glob = require('glob') const fs = require('fs') const crypto = require('crypto') const path = require('path') -const McAssets = require('minecraft-assets') -const prismarineViewerBase = "./node_modules/prismarine-viewer" -const entityMcAssets = McAssets('1.16.4') +const prismarineViewerBase = "./node_modules/renderer" // these files could be copied at build time eg with copy plugin, but copy plugin slows down the config so we copy them there, alternative we could inline it in esbuild config const filesToCopy = [ - { from: `${prismarineViewerBase}/public/blocksStates/`, to: 'dist/blocksStates/' }, { from: `${prismarineViewerBase}/public/mesher.js`, to: 'dist/mesher.js' }, { from: './assets/', to: './dist/' }, { from: './config.json', to: 'dist/config.json' }, - { from: path.join(entityMcAssets.directory, 'entity'), to: 'dist/textures/1.16.4/entity' }, + // { from: path.join(entityMcAssets.directory, 'entity'), to: 'dist/textures/1.16.4/entity' }, ] exports.filesToCopy = filesToCopy exports.copyFiles = (dev = false) => { @@ -46,29 +43,24 @@ exports.copyFilesDev = () => { exports.getSwAdditionalEntries = () => { // need to be careful with this - const singlePlayerVersion = defaultLocalServerOptions.version const filesToCachePatterns = [ 'index.html', - 'index.js', - 'index.css', - 'favicon.ico', - `mc-data/${defaultLocalServerOptions.versionMajor}.js`, - `blocksStates/${singlePlayerVersion}.json`, - 'extra-textures/**', + 'background/**', // todo-low copy from assets '*.mp3', '*.ttf', '*.png', '*.woff', 'mesher.js', + 'manifest.json', 'worldSaveWorker.js', - // todo-low preload entity atlas? - `textures/${singlePlayerVersion}.png`, - `textures/1.16.4/entity/squid.png`, + `textures/entity/squid/squid.png`, + 'sounds.js', + // everything but not .map + 'static/**/!(*.map)', ] const filesNeedsCacheKey = [ - 'index.js', - 'index.css', + 'index.html', 'mesher.js', 'worldSaveWorker.js', ] @@ -89,6 +81,9 @@ exports.getSwAdditionalEntries = () => { output.push({ url, revision }) } } + if (output.length > 40) { + throw new Error(`SW: Ios has a limit of 40 urls to cache (now ${output.length})`) + } console.log(`Got ${output.length} additional sw entries to cache`) return output } @@ -98,6 +93,16 @@ exports.moveStorybookFiles = () => { fsExtra.copySync('dist/storybook', '.vercel/output/static/storybook') } +exports.getSwFilesSize = () => { + const files = exports.getSwAdditionalEntries() + let size = 0 + for (const { url } of files) { + const file = path.join(__dirname, '../dist', url) + size += fs.statSync(file).size + } + console.log('mb', size / 1024 / 1024) +} + const fn = require.main === module && exports[process.argv[2]] if (fn) { diff --git a/scripts/buildNpmReact.ts b/scripts/buildNpmReact.ts index 4516f1b7..f4f00e4d 100644 --- a/scripts/buildNpmReact.ts +++ b/scripts/buildNpmReact.ts @@ -11,7 +11,7 @@ fs.promises.readdir(path.resolve(__dirname, '../src/react')).then(async (files) const components = files .filter((file) => { if (file.startsWith('Concept')) return false - return file.endsWith('.stories.tsx'); + return file.endsWith('.stories.tsx') }) .map((file) => { return file.replace('.stories.tsx', '') @@ -39,7 +39,7 @@ fs.promises.readdir(path.resolve(__dirname, '../src/react')).then(async (files) version = version.replace(/^v/, '') packageJson.version = version - const externalize = ['minecraft-assets', 'prismarine-viewer'] + const externalize = ['renderer', 'mc-assets'] const { metafile } = await build({ entryPoints: [path.resolve(__dirname, '../src/react/npmReactComponents.ts')], bundle: true, @@ -53,6 +53,10 @@ fs.promises.readdir(path.resolve(__dirname, '../src/react')).then(async (files) write: false, // todo loader: { '.png': 'dataurl', + '.jpg': 'dataurl', + '.jpeg': 'dataurl', + '.webp': 'dataurl', + '.css': 'text', }, plugins: [ // on external module resolve @@ -144,6 +148,13 @@ fs.promises.readdir(path.resolve(__dirname, '../src/react')).then(async (files) 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') }) + execSync('npm publish', { + cwd: path.resolve(__dirname, '../dist-npm'), + env: { + ...process.env, + NPM_TOKEN: process.env.NPM_TOKEN, + NODE_AUTH_TOKEN: process.env.NPM_TOKEN + } + }) } }) diff --git a/scripts/dockerPrepare.mjs b/scripts/dockerPrepare.mjs new file mode 100644 index 00000000..62a4f5e4 --- /dev/null +++ b/scripts/dockerPrepare.mjs @@ -0,0 +1,35 @@ +//@ts-check +import fs from 'fs' +import path from 'path' +import { fileURLToPath } from 'url' +import { execSync } from 'child_process' + +// Get repository from git config +const getGitRepository = () => { + try { + const gitConfig = fs.readFileSync('.git/config', 'utf8') + const originUrlMatch = gitConfig.match(/\[remote "origin"\][\s\S]*?url = .*?github\.com[:/](.*?)(\.git)?\n/m) + if (originUrlMatch) { + return originUrlMatch[1] + } + } catch (err) { + console.warn('Failed to read git repository from config:', err) + } + return null +} + +// write release tag and repository info +const commitShort = execSync('git rev-parse --short HEAD').toString().trim() +const repository = getGitRepository() +fs.writeFileSync('./assets/release.json', JSON.stringify({ + latestTag: `${commitShort} (docker)`, + repository +}), 'utf8') + +const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8')) +delete packageJson.optionalDependencies +fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, 2), 'utf8') + +const packageJsonViewer = JSON.parse(fs.readFileSync('./renderer/package.json', 'utf8')) +delete packageJsonViewer.optionalDependencies +fs.writeFileSync('./renderer/package.json', JSON.stringify(packageJsonViewer, null, 2), 'utf8') diff --git a/scripts/downloadSoundsMap.mjs b/scripts/downloadSoundsMap.mjs index 066a3df7..f5791768 100644 --- a/scripts/downloadSoundsMap.mjs +++ b/scripts/downloadSoundsMap.mjs @@ -1,9 +1,12 @@ import fs from 'fs' -const url = 'https://github.com/zardoy/prismarine-web-client/raw/sounds-generated/sounds.js' -const savePath = 'dist/sounds.js' +const url = 'https://github.com/zardoy/minecraft-web-client/raw/sounds-generated/sounds-v2.js' fetch(url).then(res => res.text()).then(data => { - fs.writeFileSync(savePath, data, 'utf8') + if (fs.existsSync('./dist')) { + fs.writeFileSync('./dist/sounds.js', data, 'utf8') + } + fs.mkdirSync('./generated', { recursive: true }) + fs.writeFileSync('./generated/sounds.js', data, 'utf8') if (fs.existsSync('.vercel/output/static/')) { fs.writeFileSync('.vercel/output/static/sounds.js', data, 'utf8') } diff --git a/scripts/esbuildPlugins.mjs b/scripts/esbuildPlugins.mjs index fe4018f3..431c16a4 100644 --- a/scripts/esbuildPlugins.mjs +++ b/scripts/esbuildPlugins.mjs @@ -1,46 +1,16 @@ //@ts-check -import { polyfillNode } from 'esbuild-plugin-polyfill-node' -import { join, dirname, basename } from 'path' +import { join, dirname } from 'path' import * as fs from 'fs' -import { filesize } from 'filesize' -import MCProtocol from 'minecraft-protocol' -import MCData from 'minecraft-data' -import { throttle } from 'lodash-es' import { fileURLToPath } from 'url' const __dirname = dirname(fileURLToPath(new URL(import.meta.url))) -const { supportedVersions } = MCProtocol - -const prod = process.argv.includes('--prod') -let connectedClients = [] - -const writeToClients = (data) => { - connectedClients.forEach((res) => { - res.write(`data: ${JSON.stringify(data)}\n\n`) - res.flush() - }) -} - -export const startWatchingHmr = () => { - const eventsPerFile = { - 'mesher.js': 'mesher', - // 'dist/webglRendererWorker.js': 'webglRendererWorker', - } - for (const name of Object.keys(eventsPerFile)) { - const file = join('dist', name) - if (!fs.existsSync(file)) console.warn(`[missing worker] File ${name} does not exist`) - fs.watchFile(file, () => { - writeToClients({ replace: { type: eventsPerFile[name] } }) - }) - } -} /** @type {import('esbuild').Plugin[]} */ const mesherSharedPlugins = [ { name: 'minecraft-data', - setup(build) { + setup (build) { build.onLoad({ filter: /data[\/\\]pc[\/\\]common[\/\\]legacy.json$/, }, async (args) => { @@ -54,310 +24,4 @@ const mesherSharedPlugins = [ } ] -/** @type {import('esbuild').Plugin[]} */ -const plugins = [ - ...mesherSharedPlugins, - { - name: 'strict-aliases', - setup(build) { - build.onResolve({ - filter: /^minecraft-protocol$/, - }, async ({ kind, resolveDir }) => { - return { - path: (await build.resolve('minecraft-protocol/src/index.js', { kind, resolveDir })).path, - } - }) - build.onLoad({ - filter: /minecraft-data[\/\\]data.js$/, - }, (args) => { - const version = supportedVersions.at(-1) - if (!version) throw new Error('unreachable') - const data = MCData(version) - const defaultVersionsObj = { - // default protocol data, needed for auto-version - [version]: { - version: data.version, - // protocol: JSON.parse(fs.readFileSync(join(args.path, '..', 'minecraft-data/data/pc/1.20/protocol.json'), 'utf8')), - protocol: data.protocol, - } - } - return { - contents: `window.mcData ??= ${JSON.stringify(defaultVersionsObj)};module.exports = { pc: window.mcData }`, - loader: 'js', - } - }) - build.onResolve({ - filter: /^minecraft-assets$/, - }, () => { - throw new Error('hit banned package') - }) - build.onLoad({ - filter: /^prismarine-auth/, - }, () => { - return { - contents: 'module.exports = {}', - } - }) - - build.onResolve({ - filter: /^three$/, - }, async ({ kind, resolveDir }) => { - return { - path: (await build.resolve('three/src/Three.js', { kind, resolveDir })).path, - } - }) - } - }, - { - name: 'data-assets', - setup(build) { - build.onResolve({ - filter: /.*/, - }, async ({ path, ...rest }) => { - if (['.woff', '.woff2', '.ttf'].some(ext => path.endsWith(ext)) || path.startsWith('extra-textures/')) { - return { - path, - namespace: 'assets', - external: true, - } - } - }) - - const removeNodeModulesSourcemaps = (map) => { - const doNotRemove = ['prismarine', 'mineflayer', 'flying-squid', '@jspm/core', 'minecraft'] - map.sourcesContent.forEach((_, i) => { - if (map.sources[i].includes('node_modules') && !doNotRemove.some(x => map.sources[i].includes(x))) { - map.sourcesContent[i] = null - } - }) - } - - build.onEnd(async ({ metafile, outputFiles }) => { - // write outputFiles - //@ts-ignore - for (const file of outputFiles) { - let contents = file.text - if (file.path.endsWith('.map') && file.text && !process.env.PROD) { - const map = JSON.parse(file.text) - removeNodeModulesSourcemaps(map) - contents = JSON.stringify(map) - } - await fs.promises.writeFile(file.path, contents) - } - if (!prod) return - // const deps = Object.entries(metafile.inputs).sort(([, a], [, b]) => b.bytes - a.bytes).map(([x, { bytes }]) => [x, filesize(bytes)]).slice(0, 5) - //@ts-ignore - const sizeByExt = {} - //@ts-ignore - Object.entries(metafile.inputs).sort(([, a], [, b]) => b.bytes - a.bytes).forEach(([x, { bytes }]) => { - const ext = x.slice(x.lastIndexOf('.')) - sizeByExt[ext] ??= 0 - sizeByExt[ext] += bytes - }) - console.log('Input size by ext:') - console.log(Object.fromEntries(Object.entries(sizeByExt).map(x => [x[0], filesize(x[1])]))) - }) - }, - }, - { - name: 'prevent-incorrect-linking', - setup(build) { - build.onResolve({ - filter: /.+/, - }, async ({ resolveDir, path, importer, kind, pluginData }) => { - if (pluginData?.__internal) return - // not ideal as packages can have different version, on the other hand we should not have multiple versions of the same package of developing deps - const packageName = path.startsWith('@') ? path.split('/', 2).join('/') : path.split('/', 1)[0] - const localPackageToReuse = join('node_modules', packageName) - if (!resolveDir.startsWith(process.cwd()) && ['./', '../'].every(x => !path.startsWith(x)) && fs.existsSync(localPackageToReuse)) { - const redirected = await build.resolve(path, { kind: 'import-statement', resolveDir: process.cwd(), pluginData: { __internal: true }, }) - return redirected - } - // disallow imports from outside the root directory to ensure modules are resolved from node_modules of this workspace - // if ([resolveDir, path].some(x => x.includes('node_modules')) && !resolveDir.startsWith(process.cwd())) { - // // why? ensure workspace dependency versions are used (we have overrides and need to dedupe so it doesn't grow in size) - // throw new Error(`Restricted package import from outside the root directory: ${resolveDir}`) - // } - return undefined - }) - } - }, - { - name: 'watch-notify', - setup(build) { - let count = 0 - let time - let prevHash - - build.onStart(() => { - time = Date.now() - }) - build.onEnd(({ errors, outputFiles: _outputFiles, metafile, warnings }) => { - /** @type {import('esbuild').OutputFile[]} */ - // @ts-ignore - const outputFiles = _outputFiles - const elapsed = Date.now() - time - outputFiles.find(outputFile => outputFile.path) - - if (errors.length) { - writeToClients({ errors: errors.map(error => error.text) }) - return - } - - // write metafile to disk if needed to analyze - fs.writeFileSync('dist/meta.json', JSON.stringify(metafile, null, 2)) - - /** @type {import('esbuild').OutputFile} */ - //@ts-ignore - const outputFile = outputFiles.find(x => x.path.endsWith('.js')) - if (outputFile.hash === prevHash) { - // todo also check workers and css - console.log('Ignoring reload as contents the same') - return - } - prevHash = outputFile.hash - let outputText = outputFile.text - //@ts-ignore - if (['inline', 'both'].includes(build.initialOptions.sourcemap)) { - outputText = outputText.slice(0, outputText.indexOf('//# sourceMappingURL=data:application/json;base64,')) - } - console.log(`Done in ${elapsed}ms. Size: ${filesize(outputText.length)} (${build.initialOptions.minify ? 'minified' : 'without minify'})`) - - if (count++ === 0) { - return - } - - writeToClients({ update: { time: elapsed } }) - connectedClients.length = 0 - }) - } - }, - { - name: 'esbuild-readdir', - setup(build) { - build.onResolve({ - filter: /^esbuild-readdir:.+$/, - }, ({ resolveDir, path }) => { - return { - namespace: 'esbuild-readdir', - path, - pluginData: { - resolveDir: join(resolveDir, path.replace(/^esbuild-readdir:/, '')) - }, - } - }) - build.onLoad({ - filter: /.+/, - namespace: 'esbuild-readdir', - }, async ({ pluginData }) => { - const { resolveDir } = pluginData - const files = await fs.promises.readdir(resolveDir) - return { - contents: `module.exports = ${JSON.stringify(files)}`, - resolveDir, - loader: 'js', - } - }) - } - }, - { - name: 'esbuild-import-glob', - setup(build) { - build.onResolve({ - filter: /^esbuild-import-glob\(path:(.+),skipFiles:(.+)\)+$/, - }, ({ resolveDir, path }) => { - return { - namespace: 'esbuild-import-glob', - path, - pluginData: { - resolveDir - }, - } - }) - build.onLoad({ - filter: /.+/, - namespace: 'esbuild-import-glob', - }, async ({ pluginData, path }) => { - const { resolveDir } = pluginData - //@ts-ignore - const [, userPath, skipFiles] = /^esbuild-import-glob\(path:(.+),skipFiles:(.+)\)+$/g.exec(path) - const files = (await fs.promises.readdir(join(resolveDir, userPath))).filter(f => !skipFiles.includes(f)) - return { - contents: `module.exports = { ${files.map(f => `'${f}': require('./${join(userPath, f)}')`).join(',')} }`, - resolveDir, - loader: 'js', - } - }) - } - }, - { - name: 'fix-dynamic-require', - setup(build) { - build.onResolve({ - filter: /1\.14\/chunk/, - }, async ({ resolveDir, path }) => { - if (!resolveDir.includes('prismarine-provider-anvil')) return - return { - namespace: 'fix-dynamic-require', - path, - pluginData: { - resolvedPath: `${join(resolveDir, path)}.js`, - resolveDir - }, - } - }) - build.onLoad({ - filter: /.+/, - namespace: 'fix-dynamic-require', - }, async ({ pluginData: { resolvedPath, resolveDir } }) => { - const resolvedFile = await fs.promises.readFile(resolvedPath, 'utf8') - return { - contents: resolvedFile.replace("require(`prismarine-chunk/src/pc/common/BitArray${noSpan ? 'NoSpan' : ''}`)", "noSpan ? require(`prismarine-chunk/src/pc/common/BitArray`) : require(`prismarine-chunk/src/pc/common/BitArrayNoSpan`)"), - resolveDir, - loader: 'js', - } - }) - } - }, - { - name: 'react-displayname', - setup(build) { - build.onLoad({ - filter: /.tsx$/, - }, async ({ path }) => { - let file = await fs.promises.readFile(path, 'utf8') - const fileName = basename(path, '.tsx') - let replaced = false - const varName = `__${fileName}_COMPONENT` - file = file.replace(/export default /, () => { - replaced = true - return `const ${varName} = ` - }) - if (replaced) { - file += `;${varName}.displayName = '${fileName}';export default ${varName};` - } - - return { - contents: file, - loader: 'tsx', - } - }) - } - }, - polyfillNode({ - polyfills: { - fs: false, - dns: false, - crypto: false, - events: false, - http: false, - stream: false, - buffer: false, - perf_hooks: false, - net: false, - assert: false, - }, - }) -] - -export { plugins, connectedClients as clients, mesherSharedPlugins } +export { mesherSharedPlugins } diff --git a/scripts/gen-texturepack-files.mjs b/scripts/gen-texturepack-files.mjs deleted file mode 100644 index d996236e..00000000 --- a/scripts/gen-texturepack-files.mjs +++ /dev/null @@ -1,52 +0,0 @@ -//@ts-check -import fs from 'fs' -import minecraftAssets from 'minecraft-assets' - -// why store another data? -// 1. want to make it compatible (at least for now) -// 2. don't want to read generated blockStates as it might change in future, and the current way was faster to implement - -const blockNames = [] -const indexesPerVersion = {} -/** @type {Map} */ -const allBlocksMap = new Map() -const getBlockIndex = (block) => { - if (allBlocksMap.has(block)) { - return allBlocksMap.get(block) - } - - const index = blockNames.length - allBlocksMap.set(block, index) - blockNames.push(block) - return index -} - -// const blocksFull = [] -// const allBlocks = [] -// // we can even optimize it even futher by doing prev-step resolving -// const blocksDiff = {} - -for (const [i, version] of minecraftAssets.versions.reverse().entries()) { - const assets = minecraftAssets(version) - const blocksDir = assets.directory + '/blocks' - const blocks = fs.readdirSync(blocksDir) - indexesPerVersion[version] = blocks.map(block => { - if (!block.endsWith('.png')) return undefined - return getBlockIndex(block) - }).filter(i => i !== undefined) - - // if (!blocksFull.length) { - // // first iter - // blocksFull.push(...blocks) - // } else { - // const missing = blocksFull.map((b, i) => !blocks.includes(b) ? i : -1).filter(i => i !== -1) - // const added = blocks.filter(b => !blocksFull.includes(b)) - // blocksDiff[version] = { - // missing, - // added - // } - // } -} - -fs.mkdirSync('./generated', { recursive: true, }) -fs.writeFileSync('./generated/blocks.json', JSON.stringify({ blockNames: blockNames, indexes: indexesPerVersion })) diff --git a/scripts/genLargeDataAliases.ts b/scripts/genLargeDataAliases.ts new file mode 100644 index 00000000..2372dbfd --- /dev/null +++ b/scripts/genLargeDataAliases.ts @@ -0,0 +1,62 @@ +import * as fs from 'fs' + +export const genLargeDataAliases = async (isCompressed: boolean) => { + const modules = { + mcData: { + raw: '../generated/minecraft-data-optimized.json', + compressed: '../generated/mc-data-compressed.js', + }, + blockStatesModels: { + raw: 'mc-assets/dist/blockStatesModels.json', + compressed: '../generated/mc-assets-compressed.js', + } + } + + const OUT_FILE = './generated/large-data-aliases.ts' + + let str = `${decoderCode}\nexport const importLargeData = async (mod: ${Object.keys(modules).map(x => `'${x}'`).join(' | ')}) => {\n` + for (const [module, { compressed, raw }] of Object.entries(modules)) { + const chunkName = module === 'mcData' ? 'mc-data' : 'mc-assets'; + let importCode = `(await import(/* webpackChunkName: "${chunkName}" */ '${isCompressed ? compressed : raw}')).default`; + if (isCompressed) { + importCode = `JSON.parse(decompressFromBase64(${importCode}))` + } + str += ` if (mod === '${module}') return ${importCode}\n` + } + str += `}\n` + + fs.writeFileSync(OUT_FILE, str, 'utf8') +} + +const decoderCode = /* ts */ ` +import pako from 'pako'; + +globalThis.pako = { inflate: pako.inflate.bind(pako) } + +function decompressFromBase64(input) { + console.time('decompressFromBase64') + // Decode the Base64 string + const binaryString = atob(input); + const len = binaryString.length; + const bytes = new Uint8Array(len); + + // Convert the binary string to a byte array + for (let i = 0; i < len; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + + // Decompress the byte array + const decompressedData = pako.inflate(bytes, { to: 'string' }); + + console.timeEnd('decompressFromBase64') + return decompressedData; +} +` + +// execute if run directly +if (require.main === module) { + console.log('running...') + const isCompressed = process.argv.includes('--compressed') + genLargeDataAliases(isCompressed) + console.log('done generating large data aliases') +} diff --git a/scripts/genMcDataTypes.ts b/scripts/genMcDataTypes.ts index f5b15069..82b5b878 100644 --- a/scripts/genMcDataTypes.ts +++ b/scripts/genMcDataTypes.ts @@ -1,5 +1,6 @@ import minecraftData from 'minecraft-data' import fs from 'fs' +import supportedVersions from '../src/supportedVersions.mjs' const data = minecraftData('1.20.1') @@ -10,4 +11,41 @@ types += `\nexport type EntityNames = ${Object.keys(data.entitiesByName).map(blo types += `\nexport type BiomesNames = ${Object.keys(data.biomesByName).map(blockName => `'${blockName}'`).join(' | ')};` types += `\nexport type EnchantmentNames = ${Object.keys(data.enchantmentsByName).map(blockName => `'${blockName}'`).join(' | ')};` +type Version = string +const allVersionsEntitiesMetadata = {} as Record> +for (const version of supportedVersions) { + const data = minecraftData(version) + for (const { name, metadataKeys } of data.entitiesArray) { + allVersionsEntitiesMetadata[name] ??= {} + if (!metadataKeys) { + // console.warn('Entity has no metadata', name, version) + } + for (const [i, key] of (metadataKeys ?? []).entries()) { + allVersionsEntitiesMetadata[name][key] ??= { + version: version, + firstKey: i, + } + } + } +} + +types += '\n\nexport type EntityMetadataVersions = {\n' +for (const [name, versions] of Object.entries(allVersionsEntitiesMetadata)) { + types += `'${name}': {` + for (const [key, v] of Object.entries(versions)) { + types += `\n/** ${v.version}+ (${v.firstKey}) */\n` + types += `'${key}': string;` + } + types += '},' +} +types += '\n}' + +const minify = false +if (minify) { + types = types.replaceAll(/[\t]/g, '') +} + fs.writeFileSync('./src/mcDataTypes.ts', types, 'utf8') 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/scripts/genShims.ts b/scripts/genShims.ts new file mode 100644 index 00000000..2916044a --- /dev/null +++ b/scripts/genShims.ts @@ -0,0 +1,37 @@ +import fs from 'fs' +import { appReplacableResources } from '../src/resourcesSource' + +fs.mkdirSync('./generated', { recursive: true }) + +// app resources + +let headerImports = '' +let resourcesContent = 'export const appReplacableResources: { [key in Keys]: { content: any, resourcePackPath: string, cssVar?: string, cssVarRepeat?: number } } = {\n' +let resourcesContentOriginal = 'export const resourcesContentOriginal = {\n' +const keys = [] as string[] + +for (const resource of appReplacableResources) { + const { path, ...rest } = resource + const name = path.split('/').slice(-4).join('_').replace('.png', '').replaceAll('-', '_').replaceAll('.', '_') + keys.push(name) + headerImports += `import ${name} from '${path.replace('../node_modules/', '')}'\n` + + resourcesContent += ` + '${name}': { + content: ${name}, + resourcePackPath: 'minecraft/textures/${path.slice(path.indexOf('other-textures/') + 'other-textures/'.length).split('/').slice(1).join('/')}', + ...${JSON.stringify(rest)} + }, +` + resourcesContentOriginal += ` + '${name}': ${name}, +` +} + +resourcesContent += '}\n' +resourcesContent += `type Keys = ${keys.map(k => `'${k}'`).join(' | ')}\n` +resourcesContentOriginal += '}\n' +resourcesContent += resourcesContentOriginal + +fs.mkdirSync('./src/generated', { recursive: true }) +fs.writeFileSync('./src/generated/resources.ts', headerImports + '\n' + resourcesContent, 'utf8') diff --git a/scripts/generateMoreCollisionShapes.mjs b/scripts/generateMoreCollisionShapes.mjs deleted file mode 100644 index ee178478..00000000 --- a/scripts/generateMoreCollisionShapes.mjs +++ /dev/null @@ -1,209 +0,0 @@ -//@ts-check -import minecraftData from 'minecraft-data' -import minecraftAssets from 'minecraft-assets' -import fs from 'fs' - -const latestVersion = minecraftData.versions.pc[0] - -const latestData = minecraftData(latestVersion.minecraftVersion) - -// dont touch, these are the ones that are already full box -const fullBoxInteractionShapes = [ - 'dead_bush', - 'cave_vines_plant', - 'grass', - 'tall_seagrass', - 'spruce_sapling', - 'oak_sapling', - 'dark_oak_sapling', - 'birch_sapling', - 'seagrass', - 'nether_portal', - 'tall_grass', - 'lilac', - 'cobweb' -] - -const ignoreStates = [ - 'mangrove_propagule', - 'moving_piston' -] - -// const - -// to fix -const fullBoxInteractionShapesTemp = [ - 'moving_piston', - 'lime_wall_banner', - 'gray_wall_banner', - 'weeping_vines_plant', - 'pumpkin_stem', - 'red_wall_banner', - 'crimson_wall_sign', - 'magenta_wall_banner', - 'melon_stem', - 'gray_banner', - 'spruce_sign', - 'pink_wall_banner', - 'purple_banner', - 'bamboo_sapling', - 'mangrove_sign', - 'cyan_banner', - 'blue_banner', - 'green_wall_banner', - 'yellow_banner', - 'black_wall_banner', - 'green_banner', - 'oak_sign', - 'jungle_sign', - 'yellow_wall_banner', - 'lime_banner', - 'tube_coral', - 'red_banner', - 'magenta_banner', - 'brown_wall_banner', - 'white_wall_banner', -] - -const shapes = latestData.blockCollisionShapes -const fullShape = shapes.shapes[1] -const outputJson = {} - -let interestedBlocksNoStates = [] -let interestedBlocksStates = [] - -const stateIgnoreStates = ['waterlogged'] - -const isNonInteractive = block => block.name.includes('air') || block.name.includes('water') || block.name.includes('lava') || block.name.includes('void') -const interestedBlocks = latestData.blocksArray.filter(block => { - const shapeId = shapes.blocks[block.name] - // console.log('shapeId', shapeId, block.name) - if (!shapeId) return true - const shape = typeof shapeId === 'number' ? shapes.shapes[shapeId] : shapeId - if (shape.length === 0) return true - // console.log(shape) -}).filter(b => !isNonInteractive(b)).filter(b => { - if (fullBoxInteractionShapes.includes(b.name)) { - outputJson[b.name] = fullShape - return false - } - - if (!b.states?.length || ignoreStates.includes(b.name) || b.states.every(s => stateIgnoreStates.every(state => s.name === state))) { - interestedBlocksNoStates.push(b.name) - return false - } else { - interestedBlocksStates.push(b.name) - return false - } -}).map(d => d.name) - -const { blocksStates, blocksModels } = minecraftAssets(latestData.version.minecraftVersion) - -const getShapeFromModel = (block,) => { - const blockStates = JSON.parse(fs.readFileSync('./prismarine-viewer/public/blocksStates/1.19.1.json', 'utf8')) - const blockState = blockStates[block] - const perVariant = {} - for (const [key, variant] of Object.entries(blockState.variants)) { - // const shapes = (Array.isArray(variant) ? variant : [variant]).flatMap((v) => v.model?.elements).filter(Boolean).map(({ from, to }) => [...from, ...to]).reduce((acc, cur) => { - // return [ - // Math.min(acc[0], cur[0]), - // Math.min(acc[1], cur[1]), - // Math.min(acc[2], cur[2]), - // Math.max(acc[3], cur[3]), - // Math.max(acc[4], cur[4]), - // Math.max(acc[5], cur[5]) - // ] - // }) - console.log(variant) - const shapes = (Array.isArray(variant) ? variant : [variant]).flatMap((v) => v.model?.elements).filter(Boolean).map(({ from, to }) => [...from, ...to]) - perVariant[key] = shapes - break - } - return perVariant -} - -// console.log(getShapeFromModel('oak_button')) - -// const addShapeIf = { -// redstone: [ -// ['east', 'up', shape] -// ] -// } - -const needBlocksStated = {} - -const groupedBlocksRules = { - // button: block => block.includes('button'), - // pressure_plate: block => block.includes('pressure_plate'), - // sign: block => block.includes('_sign'), - // sapling: block => block.includes('_sapling'), -} -const groupedBlocksOutput = {} - -outer: for (const interestedBlock of [...interestedBlocksNoStates, ...interestedBlocksStates]) { - for (const [block, func] of Object.entries(groupedBlocksRules)) { - if (func(interestedBlock)) { - groupedBlocksOutput[block] ??= [] - groupedBlocksOutput[block].push(interestedBlock) - continue outer - } - } - - const hasStates = interestedBlocksStates.includes(interestedBlock) - if (hasStates) { - const states = blocksStates[interestedBlock] - if (!states) { - console.log('no states', interestedBlock) - continue - } - if (!states.variants) { - if (!states.multipart) { - console.log('no variants', interestedBlock) - continue - } - let outputStates = {} - for (const { when } of states.multipart) { - if (when) { - for (const [key, value] of Object.entries(when)) { - if (key === 'OR') { - for (const or of value) { - for (const [key, value] of Object.entries(or)) { - const str = `${key}=${value}` - outputStates[str] = true - } - } - continue - } - const str = `${key}=${value}` - outputStates[str] = true - } - } - } - needBlocksStated[interestedBlock] = outputStates - continue - } - if (Object.keys(states.variants).length === 1 && states.variants['']) { - needBlocksStated[interestedBlock] = false - } else { - needBlocksStated[interestedBlock] = Object.fromEntries(Object.entries(states.variants).map(([key, value]) => [key, true])) - } - } else { - needBlocksStated[interestedBlock] = false - } - // let vars = [] - // Object.keys(variants).forEach(variant => { - // if (variant !== '') vars.push(variant) - // }) - // needBlocksVariants.push({ - // block: interestedBlock, - // variants: vars - // }) -} - -fs.writeFileSync('scripts/needBlocks.json', JSON.stringify(needBlocksStated)) - -// console.log(interestedBlocks.includes('lever')) - -// read latest block states - -// read block model elements & combine diff --git a/scripts/getMissingRecipes.mjs b/scripts/getMissingRecipes.mjs new file mode 100644 index 00000000..59e78672 --- /dev/null +++ b/scripts/getMissingRecipes.mjs @@ -0,0 +1,41 @@ +//@ts-check +// tsx ./scripts/getMissingRecipes.mjs +import MinecraftData from 'minecraft-data' +import supportedVersions from '../src/supportedVersions.mjs' +import fs from 'fs' + +console.time('import-data') +const { descriptionGenerators } = await import('../src/itemsDescriptions') +console.timeEnd('import-data') + +const data = MinecraftData(supportedVersions.at(-1)) + +const hasDescription = name => { + for (const [key, value] of descriptionGenerators) { + if (Array.isArray(key) && key.includes(name)) { + return true + } + if (key instanceof RegExp && key.test(name)) { + return true + } + } + return false +} + +const result = [] +for (const item of data.itemsArray) { + const recipes = data.recipes[item.id] + if (!recipes) { + if (item.name.endsWith('_slab') || item.name.endsWith('_stairs') || item.name.endsWith('_wall')) { + console.warn('Must have recipe!', item.name) + continue + } + if (hasDescription(item.name)) { + continue + } + + result.push(item.name) + } +} + +fs.writeFileSync('./generated/noRecipies.json', JSON.stringify(result, null, 2)) diff --git a/scripts/githubActions.mjs b/scripts/githubActions.mjs index ab786ea9..3e8eb0f6 100644 --- a/scripts/githubActions.mjs +++ b/scripts/githubActions.mjs @@ -15,6 +15,17 @@ const fns = { // set github output setOutput('alias', alias[1]) } + }, + getReleasingAlias() { + const final = (ver) => `${ver}.mcraft.fun,${ver}.pcm.gg` + const releaseJson = JSON.parse(fs.readFileSync('./assets/release.json', 'utf8')) + const tag = releaseJson.latestTag + const [major, minor, patch] = tag.replace('v', '').split('.') + if (major === '0' && minor === '1') { + setOutput('alias', final(`v${patch}`)) + } else { + setOutput('alias', final(tag)) + } } } diff --git a/scripts/makeOptimizedMcData.mjs b/scripts/makeOptimizedMcData.mjs new file mode 100644 index 00000000..a572d067 --- /dev/null +++ b/scripts/makeOptimizedMcData.mjs @@ -0,0 +1,382 @@ +//@ts-check +import { build } from 'esbuild' +import { existsSync } from 'node:fs' +import Module from "node:module" +import { dirname } from 'node:path' +import supportedVersions from '../src/supportedVersions.mjs' +import { gzipSizeFromFileSync } from 'gzip-size' +import fs from 'fs' +import { default as _JsonOptimizer } from '../src/optimizeJson' +import { gzipSync } from 'zlib' +import MinecraftData from 'minecraft-data' +import MCProtocol from 'minecraft-protocol' + +/** @type {typeof _JsonOptimizer} */ +//@ts-ignore +const JsonOptimizer = _JsonOptimizer.default + +// console.log(a.diff_main(JSON.stringify({ a: 1 }), JSON.stringify({ a: 1, b: 2 }))) + +const require = Module.createRequire(import.meta.url) + +const dataPaths = require('minecraft-data/minecraft-data/data/dataPaths.json') + +function toMajor(version) { + const [a, b] = (version + '').split('.') + return `${a}.${b}` +} + +let versions = {} +const dataTypes = new Set() + +for (const [version, dataSet] of Object.entries(dataPaths.pc)) { + if (!supportedVersions.includes(version)) continue + for (const type of Object.keys(dataSet)) { + dataTypes.add(type) + } + versions[version] = dataSet +} + +const versionToNumber = (ver) => { + const [x, y = '0', z = '0'] = ver.split('.') + return +`${x.padStart(2, '0')}${y.padStart(2, '0')}${z.padStart(2, '0')}` +} + +// Version clipping support +const minVersion = process.env.MIN_MC_VERSION +const maxVersion = process.env.MAX_MC_VERSION + +// Filter versions based on MIN_VERSION and MAX_VERSION if provided +if (minVersion || maxVersion) { + const filteredVersions = {} + const minVersionNum = minVersion ? versionToNumber(minVersion) : 0 + const maxVersionNum = maxVersion ? versionToNumber(maxVersion) : Infinity + + for (const [version, dataSet] of Object.entries(versions)) { + const versionNum = versionToNumber(version) + if (versionNum >= minVersionNum && versionNum <= maxVersionNum) { + filteredVersions[version] = dataSet + } + } + + versions = filteredVersions + + console.log(`Version clipping applied: ${minVersion || 'none'} to ${maxVersion || 'none'}`) + console.log(`Processing ${Object.keys(versions).length} versions:`, Object.keys(versions).sort((a, b) => versionToNumber(a) - versionToNumber(b))) +} + +console.log('Bundling version range:', Object.keys(versions)[0], 'to', Object.keys(versions).at(-1)) + +// if not included here (even as {}) will not be bundled & accessible! +// const compressedOutput = !!process.env.SINGLE_FILE_BUILD +const compressedOutput = true +const dataTypeBundling2 = { + blocks: { + arrKey: 'name', + }, + items: { + arrKey: 'name', + }, + recipes: { + processData: processRecipes + } +} +const dataTypeBundling = { + language: process.env.SKIP_MC_DATA_LANGUAGE === 'true' ? { + raw: {} + } : { + ignoreRemoved: true, + ignoreChanges: true + }, + blocks: { + arrKey: 'name', + processData(current, prev, _, version) { + for (const block of current) { + const prevBlock = prev?.find(x => x.name === block.name) + if (block.transparent) { + const forceOpaque = block.name.includes('shulker_box') || block.name.match(/^double_.+_slab\d?$/) || ['melon_block', 'lit_pumpkin', 'lit_redstone_ore', 'lit_furnace'].includes(block.name) + + if (forceOpaque || (prevBlock && !prevBlock.transparent)) { + block.transparent = false + } + } + if (block.hardness === 0 && prevBlock && prevBlock.hardness > 0) { + block.hardness = prevBlock.hardness + } + } + } + // ignoreRemoved: true, + // genChanges (source, diff) { + // const diffs = {} + // const newItems = {} + // for (const [key, val] of Object.entries(diff)) { + // const src = source[key] + // if (!src) { + // newItems[key] = val + // continue + // } + // const { minStateId, defaultState, maxStateId } = val + // if (defaultState === undefined || minStateId === src.minStateId || maxStateId === src.maxStateId || defaultState === src.defaultState) continue + // diffs[key] = [minStateId, defaultState, maxStateId] + // } + // return { + // stateChanges: diffs + // } + // }, + // ignoreChanges: true + }, + items: { + arrKey: 'name' + }, + attributes: { + arrKey: 'name' + }, + particles: { + arrKey: 'name' + }, + effects: { + arrKey: 'name' + }, + enchantments: { + arrKey: 'name' + }, + instruments: { + arrKey: 'name' + }, + foods: { + arrKey: 'name' + }, + entities: { + arrKey: 'id+type' + }, + materials: {}, + windows: { + arrKey: 'name' + }, + version: { + raw: true + }, + tints: {}, + biomes: { + arrKey: 'name' + }, + entityLoot: { + arrKey: 'entity' + }, + blockLoot: { + arrKey: 'block' + }, + recipes: process.env.SKIP_MC_DATA_RECIPES === 'true' ? { + raw: {} + } : { + raw: true + // processData: processRecipes + }, + blockCollisionShapes: {}, + loginPacket: {}, + protocol: { + raw: true + }, + // sounds: { + // arrKey: 'name' + // } +} + +function processRecipes(current, prev, getData, version) { + // can require the same multiple times per different versions + if (current._proccessed) return + const items = getData('items') + const blocks = getData('blocks') + const itemsIdsMap = Object.fromEntries(items.map((b) => [b.id, b.name])) + const blocksIdsMap = Object.fromEntries(blocks.map((b) => [b.id, b.name])) + for (const key of Object.keys(current)) { + const mapId = (id) => { + if (typeof id !== 'string' && typeof id !== 'number') throw new Error('Incorrect type') + const mapped = itemsIdsMap[id] ?? blocksIdsMap[id] + if (!mapped) { + throw new Error(`No item/block name with id ${id}`) + } + return mapped + } + const processRecipe = (obj) => { + // if (!obj) return + // if (Array.isArray(obj)) { + // obj.forEach((id, i) => { + // obj[i] = mapId(obj[id]) + // }) + // } else if (obj && typeof obj === 'object') { + // if (!'count metadata id'.split(' ').every(x => x in obj)) { + // throw new Error(`process error: Unknown deep object pattern: ${JSON.stringify(obj)}`) + // } + // obj.id = mapId(obj.id) + // } else { + // throw new Error('unknown type') + // } + const parseRecipeItem = (item) => { + if (typeof item === 'number') return mapId(item) + if (Array.isArray(item)) return [mapId(item), ...item.slice(1)] + if (!item) { + return item + } + if ('id' in item) { + item.id = mapId(item.id) + return item + } + throw new Error('unhandled') + } + const maybeProccessShape = (shape) => { + if (!shape) return + for (const shapeRow of shape) { + for (const [i, item] of shapeRow.entries()) { + shapeRow[i] = parseRecipeItem(item) + } + } + } + if (obj.result) obj.result = parseRecipeItem(obj.result) + maybeProccessShape(obj.inShape) + maybeProccessShape(obj.outShape) + if (obj.ingredients) { + for (const [i, ingredient] of obj.ingredients.entries()) { + obj.ingredients[i] = parseRecipeItem(ingredient) + } + } + } + try { + const name = mapId(key) + for (const [i, recipe] of current[key].entries()) { + try { + processRecipe(recipe) + } catch (err) { + console.warn(`${version} [warn] Removing incorrect recipe: ${err}`) + delete current[i] + } + } + current[name] = current[key] + } catch (err) { + console.warn(`${version} [warn] Removing incorrect recipe: ${err}`) + } + delete current[key] + } + current._proccessed = true +} + +const notBundling = [...dataTypes.keys()].filter(x => !Object.keys(dataTypeBundling).includes(x)) +console.log("Not bundling minecraft-data data:", notBundling) + +let previousData = {} +// /** @type {Record} */ +const diffSources = {} +const versionsArr = Object.entries(versions) +const sizePerDataType = {} +const rawDataVersions = {} +// const versionsArr = Object.entries(versions).slice(-1) +for (const [i, [version, dataSet]] of versionsArr.reverse().entries()) { + for (const [dataType, dataPath] of Object.entries(dataSet)) { + const config = dataTypeBundling[dataType] + if (!config) continue + const ignoreCollisionShapes = dataType === 'blockCollisionShapes' && versionToNumber(version) >= versionToNumber('1.13') + + let injectCode = '' + const getRealData = (type) => { + const loc = `minecraft-data/data/${dataSet[type]}/` + const dataPathAbsolute = require.resolve(`minecraft-data/${loc}${type}`) + // const data = fs.readFileSync(dataPathAbsolute, 'utf8') + const dataRaw = require(dataPathAbsolute) + return dataRaw + } + const dataRaw = getRealData(dataType) + let rawData = dataRaw + if (config.raw) { + rawDataVersions[dataType] ??= {} + rawDataVersions[dataType][version] = rawData + if (config.raw === true) { + rawData = dataRaw + } else { + rawData = config.raw + } + + if (ignoreCollisionShapes && dataType === 'blockCollisionShapes') { + rawData = { + blocks: {}, + shapes: {} + } + } + } else { + if (!diffSources[dataType]) { + diffSources[dataType] = new JsonOptimizer(config.arrKey, config.ignoreChanges, config.ignoreRemoved) + } + try { + config.processData?.(dataRaw, previousData[dataType], getRealData, version) + diffSources[dataType].recordDiff(version, dataRaw) + injectCode = `restoreDiff(sources, ${JSON.stringify(dataType)}, ${JSON.stringify(version)})` + } catch (err) { + const error = new Error(`Failed to diff ${dataType} for ${version}: ${err.message}`) + error.stack = err.stack + throw error + } + } + sizePerDataType[dataType] ??= 0 + sizePerDataType[dataType] += Buffer.byteLength(JSON.stringify(injectCode || rawData), 'utf8') + if (config.genChanges && previousData[dataType]) { + const changes = config.genChanges(previousData[dataType], dataRaw) + // Object.assign(data, changes) + } + previousData[dataType] = dataRaw + } +} +const sources = Object.fromEntries(Object.entries(diffSources).map(x => { + const data = x[1].export() + // const data = {} + sizePerDataType[x[0]] += Buffer.byteLength(JSON.stringify(data), 'utf8') + return [x[0], data] +})) +Object.assign(sources, rawDataVersions) +sources.versionKey = require('minecraft-data/package.json').version + +const totalSize = Object.values(sizePerDataType).reduce((acc, val) => acc + val, 0) +console.log('total size (mb)', totalSize / 1024 / 1024) +console.log( + 'size per data type (mb, %)', + Object.fromEntries(Object.entries(sizePerDataType).map(([dataType, size]) => { + return [dataType, [size / 1024 / 1024, Math.round(size / totalSize * 100)]] + }).sort((a, b) => { + //@ts-ignore + return b[1][1] - a[1][1] + })) +) + +function compressToBase64(input) { + const buffer = gzipSync(input) + return buffer.toString('base64') +} + +const filePath = './generated/minecraft-data-optimized.json' +fs.writeFileSync(filePath, JSON.stringify(sources), 'utf8') +if (compressedOutput) { + const minizedCompressed = compressToBase64(fs.readFileSync(filePath)) + console.log('size of compressed', Buffer.byteLength(minizedCompressed, 'utf8') / 1000 / 1000) + const compressedFilePath = './generated/mc-data-compressed.js' + fs.writeFileSync(compressedFilePath, `export default ${JSON.stringify(minizedCompressed)}`, 'utf8') + + const mcAssets = JSON.stringify(require('mc-assets/dist/blockStatesModels.json')) + fs.writeFileSync('./generated/mc-assets-compressed.js', `export default ${JSON.stringify(compressToBase64(mcAssets))}`, 'utf8') + + // const modelsObj = fs.readFileSync('./prismarine-renderer/viewer/lib/entity/exportedModels.js') + // const models = +} + +console.log('size', fs.lstatSync(filePath).size / 1000 / 1000, gzipSizeFromFileSync(filePath) / 1000 / 1000) + +// always bundled + +const { defaultVersion } = MCProtocol +const data = MinecraftData(defaultVersion) +console.log('defaultVersion', defaultVersion, !!data) +const initialMcData = { + [defaultVersion]: { + version: data.version, + protocol: data.protocol, + } +} + +// fs.writeFileSync('./generated/minecraft-initial-data.json', JSON.stringify(initialMcData), 'utf8') diff --git a/scripts/optimizeBlockCollisions.ts b/scripts/optimizeBlockCollisions.ts index 8a87b358..251a564a 100644 --- a/scripts/optimizeBlockCollisions.ts +++ b/scripts/optimizeBlockCollisions.ts @@ -48,7 +48,9 @@ for (const version of [...supportedVersions].reverse()) { console.log('using blockCollisionShapes of version', version) const data = JSON.parse(fs.readFileSync(dataPath, 'utf8')) data.version = version + data.versionKey = require('minecraft-data/package.json').version processData(data) + fs.mkdirSync('./generated', { recursive: true }) fs.writeFileSync('./generated/latestBlockCollisionsShapes.json', JSON.stringify(data), 'utf8') break } diff --git a/scripts/patchAssets.ts b/scripts/patchAssets.ts new file mode 100644 index 00000000..99994f5f --- /dev/null +++ b/scripts/patchAssets.ts @@ -0,0 +1,137 @@ +import blocksAtlas from 'mc-assets/dist/blocksAtlases.json' +import itemsAtlas from 'mc-assets/dist/itemsAtlases.json' +import * as fs from 'fs' +import * as path from 'path' +import sharp from 'sharp' + +interface AtlasFile { + latest: { + suSv: number + tileSize: number + width: number + height: number + textures: { + [key: string]: { + u: number + v: number + su: number + sv: number + tileIndex: number + } + } + } +} + +async function patchTextureAtlas( + atlasType: 'blocks' | 'items', + atlasData: AtlasFile, + customTexturesDir: string, + distDir: string +) { + // Check if custom textures directory exists and has files + if (!fs.existsSync(customTexturesDir) || fs.readdirSync(customTexturesDir).length === 0) { + return + } + + // Find the latest atlas file + const atlasFiles = fs.readdirSync(distDir) + .filter(file => file.startsWith(`${atlasType}AtlasLatest`) && file.endsWith('.png')) + .sort() + + if (atlasFiles.length === 0) { + console.log(`No ${atlasType}AtlasLatest.png found in ${distDir}`) + return + } + + const latestAtlasFile = atlasFiles[atlasFiles.length - 1] + const atlasPath = path.join(distDir, latestAtlasFile) + console.log(`Patching ${atlasPath}`) + + // Get atlas dimensions + const atlasMetadata = await sharp(atlasPath).metadata() + if (!atlasMetadata.width || !atlasMetadata.height) { + throw new Error(`Failed to get atlas dimensions for ${atlasPath}`) + } + + // Process each custom texture + const customTextureFiles = fs.readdirSync(customTexturesDir) + .filter(file => file.endsWith('.png')) + + if (customTextureFiles.length === 0) return + + // Prepare composite operations + const composites: sharp.OverlayOptions[] = [] + + for (const textureFile of customTextureFiles) { + const textureName = path.basename(textureFile, '.png') + + if (atlasData.latest.textures[textureName]) { + const textureData = atlasData.latest.textures[textureName] + const customTexturePath = path.join(customTexturesDir, textureFile) + + try { + // Convert UV coordinates to pixel coordinates + const x = Math.round(textureData.u * atlasMetadata.width) + const y = Math.round(textureData.v * atlasMetadata.height) + const width = Math.round((textureData.su ?? atlasData.latest.suSv) * atlasMetadata.width) + const height = Math.round((textureData.sv ?? atlasData.latest.suSv) * atlasMetadata.height) + + // Resize custom texture to match atlas dimensions and add to composite operations + const resizedTextureBuffer = await sharp(customTexturePath) + .resize(width, height, { + fit: 'fill', + kernel: 'nearest' // Preserve pixel art quality + }) + .png() + .toBuffer() + + composites.push({ + input: resizedTextureBuffer, + left: x, + top: y, + blend: 'over' + }) + + console.log(`Prepared ${textureName} at (${x}, ${y}) with size (${width}, ${height})`) + } catch (error) { + console.error(`Failed to prepare ${textureName}:`, error) + } + } else { + console.warn(`Texture ${textureName} not found in ${atlasType} atlas`) + } + } + + if (composites.length > 0) { + // Apply all patches at once using Sharp's composite + await sharp(atlasPath) + .composite(composites) + .png() + .toFile(atlasPath + '.tmp') + + // Replace original with patched version + fs.renameSync(atlasPath + '.tmp', atlasPath) + console.log(`Saved patched ${atlasType} atlas to ${atlasPath}`) + } +} + +async function main() { + const customBlocksDir = './assets/customTextures/blocks' + const customItemsDir = './assets/customTextures/items' + const distDir = './dist/static/image' + + try { + // Patch blocks atlas + await patchTextureAtlas('blocks', blocksAtlas as unknown as AtlasFile, customBlocksDir, distDir) + + // Patch items atlas + await patchTextureAtlas('items', itemsAtlas as unknown as AtlasFile, customItemsDir, distDir) + + console.log('Texture atlas patching completed!') + } catch (error) { + console.error('Failed to patch texture atlases:', error) + process.exit(1) + } +} + +// Run the script +main() diff --git a/scripts/prepareData.mjs b/scripts/prepareData.mjs deleted file mode 100644 index ab92499e..00000000 --- a/scripts/prepareData.mjs +++ /dev/null @@ -1,72 +0,0 @@ -//@ts-check -import { build } from 'esbuild' -import { existsSync } from 'node:fs' -import Module from "node:module" -import { dirname } from 'node:path' -import supportedVersions from '../src/supportedVersions.mjs' - -if (existsSync('dist/mc-data') && !process.argv.includes('-f')) { - console.log('using cached prepared data') - process.exit(0) -} - -const require = Module.createRequire(import.meta.url) - -const dataPaths = require('minecraft-data/minecraft-data/data/dataPaths.json') - -function toMajor (version) { - const [a, b] = (version + '').split('.') - return `${a}.${b}` -} - -const grouped = {} - -for (const [version, data] of Object.entries(dataPaths.pc)) { - if (!supportedVersions.includes(version)) continue - const major = toMajor(version) - grouped[major] ??= {} - grouped[major][version] = data -} - -const versionToNumber = (ver) => { - const [x, y = '0', z = '0'] = ver.split('.') - return +`${x.padStart(2, '0')}${y.padStart(2, '0')}${z.padStart(2, '0')}` -} - -console.log('preparing data') -console.time('data prepared') -let builds = [] -for (const [major, versions] of Object.entries(grouped)) { - // if (major !== '1.19') continue - let contents = 'Object.assign(window.mcData, {\n' - for (const [version, dataSet] of Object.entries(versions)) { - contents += ` '${version}': {\n` - for (const [dataType, dataPath] of Object.entries(dataSet)) { - if (dataType === 'blockCollisionShapes' && versionToNumber(version) >= versionToNumber('1.13')) { - contents += ` get ${dataType} () { return window.globalGetCollisionShapes?.("${version}") },\n` - continue - } - const loc = `minecraft-data/data/${dataPath}/` - contents += ` get ${dataType} () { return require("./${loc}${dataType}.json") },\n` - } - contents += ' },\n' - } - contents += '})' - - const promise = build({ - bundle: true, - outfile: `dist/mc-data/${major}.js`, - stdin: { - contents, - - resolveDir: dirname(require.resolve('minecraft-data')), - sourcefile: `mcData${major}.js`, - loader: 'js', - }, - metafile: true, - }) - // require('fs').writeFileSync('dist/mc-data/metafile.json', JSON.stringify(promise.metafile), 'utf8') - builds.push(promise) -} -await Promise.all(builds) -console.timeEnd('data prepared') diff --git a/scripts/prepareSounds.mjs b/scripts/prepareSounds.mjs index 4ed119cb..02026a04 100644 --- a/scripts/prepareSounds.mjs +++ b/scripts/prepareSounds.mjs @@ -7,29 +7,40 @@ import { fileURLToPath } from 'url' import { exec } from 'child_process' import { promisify } from 'util' import { build } from 'esbuild' +import supportedVersions from '../src/supportedVersions.mjs' const __dirname = path.dirname(fileURLToPath(new URL(import.meta.url))) -const targetedVersions = ['1.20.1', '1.19.2', '1.18.2', '1.17.1', '1.16.5', '1.15.2', '1.14.4', '1.13.2', '1.12.2', '1.11.2', '1.10.2', '1.9.4', '1.8.9'] +export const versionToNumber = (ver) => { + const [x, y = '0', z = '0'] = ver.split('.') + return +`${x.padStart(2, '0')}${y.padStart(2, '0')}${z.padStart(2, '0')}` +} + +const targetedVersions = [...supportedVersions].sort((a, b) => versionToNumber(b) - versionToNumber(a)) /** @type {{name, size, hash}[]} */ let prevSounds = null const burgerDataUrl = (version) => `https://raw.githubusercontent.com/Pokechu22/Burger/gh-pages/${version}.json` const burgerDataPath = './generated/burger.json' +const EXISTING_CACHE_PATH = './generated/existing-sounds-cache.json' // const perVersionData: Record { +const downloadAllSoundsAndCreateMap = async () => { + let existingSoundsCache = {} + try { + existingSoundsCache = JSON.parse(await fs.promises.readFile(EXISTING_CACHE_PATH, 'utf8')) + } catch (err) {} const { versions } = await getVersionList() const lastVersion = versions.filter(version => !version.id.includes('w'))[0] // if (lastVersion.id !== targetedVersions[0]) throw new Error('last version is not the same as targetedVersions[0], update') - for (const targetedVersion of targetedVersions) { - const versionData = versions.find(x => x.id === targetedVersion) - if (!versionData) throw new Error('no version data for ' + targetedVersion) - console.log('Getting assets for version', targetedVersion) + for (const version of targetedVersions) { + const versionData = versions.find(x => x.id === version) + if (!versionData) throw new Error('no version data for ' + version) + console.log('Getting assets for version', version) const { assetIndex } = await fetch(versionData.url).then((r) => r.json()) /** @type {{objects: {[a: string]: { size, hash }}}} */ const index = await fetch(assetIndex.url).then((r) => r.json()) @@ -45,26 +56,30 @@ const downloadAllSounds = async () => { const changedSize = soundAssets.filter(x => prevSoundNames.has(x.name) && prevSounds.find(y => y.name === x.name).size !== x.size) console.log('changed size', changedSize.map(x => ({ name: x.name, prev: prevSounds.find(y => y.name === x.name).size, curr: x.size }))) if (addedSounds.length || changedSize.length) { - soundsPathVersionsRemap[targetedVersion] = [...addedSounds, ...changedSize].map(x => x.name.replace('minecraft/sounds/', '').replace('.ogg', '')) + soundsPathVersionsRemap[version] = [...addedSounds, ...changedSize].map(x => x.name.replace('minecraft/sounds/', '').replace('.ogg', '')) } if (addedSounds.length) { - console.log('downloading new sounds for version', targetedVersion) - downloadSounds(addedSounds, targetedVersion + '/') + console.log('downloading new sounds for version', version) + downloadSounds(version, addedSounds, version + '/') } if (changedSize.length) { - console.log('downloading changed sounds for version', targetedVersion) - downloadSounds(changedSize, targetedVersion + '/') + console.log('downloading changed sounds for version', version) + downloadSounds(version, changedSize, version + '/') } } else { - console.log('downloading sounds for version', targetedVersion) - downloadSounds(soundAssets) + console.log('downloading sounds for version', version) + downloadSounds(version, soundAssets) } prevSounds = soundAssets } - async function downloadSound ({ name, hash, size }, namePath, log) { + async function downloadSound({ name, hash, size }, namePath, log) { + const cached = + !!namePath.replace('.ogg', '.mp3').split('/').reduce((acc, cur) => acc?.[cur], existingSoundsCache.sounds) || + !!namePath.replace('.ogg', '.ogg').split('/').reduce((acc, cur) => acc?.[cur], existingSoundsCache.sounds) const savePath = path.resolve(`generated/sounds/${namePath}`) - if (fs.existsSync(savePath)) { + if (cached || fs.existsSync(savePath)) { // console.log('skipped', name) + existingSoundsCache.sounds[namePath] = true return } log() @@ -86,7 +101,12 @@ const downloadAllSounds = async () => { } writer.close() } - async function downloadSounds (assets, addPath = '') { + async function downloadSounds(version, assets, addPath = '') { + if (addPath && existingSoundsCache.sounds[version]) { + console.log('using existing sounds for version', version) + return + } + console.log(version, 'have to download', assets.length, 'sounds') 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) @@ -95,6 +115,7 @@ const downloadAllSounds = async () => { } fs.writeFileSync('./generated/soundsPathVersionsRemap.json', JSON.stringify(soundsPathVersionsRemap), 'utf8') + fs.writeFileSync(EXISTING_CACHE_PATH, JSON.stringify(existingSoundsCache), 'utf8') } const lightpackOverrideSounds = { @@ -106,7 +127,8 @@ const lightpackOverrideSounds = { // this is not done yet, will be used to select only sounds for bundle (most important ones) const isSoundWhitelisted = (name) => name.startsWith('random/') || name.startsWith('note/') || name.endsWith('/say1') || name.endsWith('/death') || (name.startsWith('mob/') && name.endsWith('/step1')) || name.endsWith('/swoop1') || /* name.endsWith('/break1') || */ name.endsWith('dig/stone1') -const ffmpeg = 'C:/Users/Vitaly/Documents/LosslessCut-win-x64/resources/ffmpeg.exe' // will be ffmpeg-static +// const ffmpeg = 'C:/Users/Vitaly/Documents/LosslessCut-win-x64/resources/ffmpeg.exe' // can be ffmpeg-static +const ffmpegExec = 'ffmpeg' const maintainBitrate = true const scanFilesDeep = async (root, onOggFile) => { @@ -127,15 +149,16 @@ const convertSounds = async () => { }) const convertSound = async (i) => { - const proc = promisify(exec)(`${ffmpeg} -i "${toConvert[i]}" -y -codec:a libmp3lame ${maintainBitrate ? '-qscale:a 2' : ''} "${toConvert[i].replace('.ogg', '.mp3')}"`) + const proc = promisify(exec)(`${ffmpegExec} -i "${toConvert[i]}" -y -codec:a libmp3lame ${maintainBitrate ? '-qscale:a 2' : ''} "${toConvert[i].replace('.ogg', '.mp3')}"`) // pipe stdout to the console + //@ts-ignore proc.child.stdout.pipe(process.stdout) await proc console.log('converted to mp3', i, '/', toConvert.length, toConvert[i]) } 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))) } } @@ -147,17 +170,44 @@ const getSoundsMap = (burgerData) => { } const writeSoundsMap = async () => { - // const burgerData = await fetch(burgerDataUrl(targetedVersions[0])).then((r) => r.json()) - // fs.writeFileSync(burgerDataPath, JSON.stringify(burgerData[0].sounds), 'utf8') + const burgerData = await fetch(burgerDataUrl(targetedVersions[0])).then((r) => r.json()) + fs.writeFileSync(burgerDataPath, JSON.stringify(burgerData[0].sounds), 'utf8') const allSoundsMapOutput = {} let prevMap // todo REMAP ONLY IDS. Do diffs, as mostly only ids are changed between versions // const localTargetedVersions = targetedVersions.slice(0, 2) + let lastMappingsJson const localTargetedVersions = targetedVersions - for (const targetedVersion of localTargetedVersions) { - const burgerData = await fetch(burgerDataUrl(targetedVersion)).then((r) => r.json()) + for (const targetedVersion of [...localTargetedVersions].reverse()) { + console.log('Processing version', targetedVersion) + + const burgerData = await fetch(burgerDataUrl(targetedVersion)).then((r) => r.json()).catch((err) => { + // console.error('error fetching burger data', targetedVersion, err) + return null + }) + /** @type {{sounds: string[]}} */ + const mappingJson = await fetch(`https://raw.githubusercontent.com/ViaVersion/Mappings/7a45c1f9dbc1f1fdadacfecdb205ba84e55766fc/mappings/mapping-${targetedVersion}.json`).then(async (r) => { + return r.json() + // lastMappingsJson = r.status === 404 ? lastMappingsJson : (await r.json()) + // if (r.status === 404) { + // console.warn('using prev mappings json for ' + targetedVersion) + // } + // return lastMappingsJson + }).catch((err) => { + // console.error('error fetching mapping json', targetedVersion, err) + return null + }) + // if (!mappingJson) throw new Error('no initial mapping json for ' + targetedVersion) + if (burgerData && !mappingJson) { + console.warn('has burger but no mapping json for ' + targetedVersion) + continue + } + if (!mappingJson || !burgerData) { + console.warn('no mapping json or burger data for ' + targetedVersion) + continue + } const allSoundsMap = getSoundsMap(burgerData) // console.log(Object.keys(sounds).length, 'ids') const outputIdMap = {} @@ -168,22 +218,33 @@ const writeSoundsMap = async () => { new: 0, same: 0 } - for (const { id, subtitle, sounds, name } of Object.values(allSoundsMap)) { + for (const { _id, subtitle, sounds, name } of Object.values(allSoundsMap)) { if (!sounds?.length /* && !subtitle */) continue const firstName = sounds[0].name // const includeSound = isSoundWhitelisted(firstName) // if (!includeSound) continue const mostUsedSound = sounds.sort((a, b) => b.weight - a.weight)[0] - const targetSound = sounds[0] // outputMap[id] = { subtitle, sounds: mostUsedSound } // outputMap[id] = { subtitle, sounds } - const soundFilePath = `generated/sounds/minecraft/sounds/${targetSound.name}.mp3` + // const soundFilePath = `generated/sounds/minecraft/sounds/${targetSound.name}.mp3` // if (!fs.existsSync(soundFilePath)) { // console.warn('no sound file', targetSound.name) // continue // } + let outputUseSoundLine = [] + const minWeight = sounds.reduce((acc, cur) => cur.weight ? Math.min(acc, cur.weight) : acc, sounds[0].weight ?? 1) + if (isNaN(minWeight)) debugger + for (const sound of sounds) { + if (sound.weight && isNaN(sound.weight)) debugger + outputUseSoundLine.push(`${sound.volume ?? 1};${sound.name};${sound.weight ?? minWeight}`) + } + const id = mappingJson.sounds.findIndex(x => x === name) + if (id === -1) { + console.warn('no id for sound', name, targetedVersion) + continue + } const key = `${id};${name}` - outputIdMap[key] = `${targetSound.volume ?? 1};${targetSound.name}` + outputIdMap[key] = outputUseSoundLine.join(',') if (prevMap && prevMap[key]) { keysStats.same++ } else { @@ -218,10 +279,11 @@ const writeSoundsMap = async () => { const makeSoundsBundle = async () => { const allSoundsMap = JSON.parse(fs.readFileSync('./generated/sounds.json', 'utf8')) const allSoundsVersionedMap = JSON.parse(fs.readFileSync('./generated/soundsPathVersionsRemap.json', 'utf8')) + if (!process.env.REPO_SLUG) throw new Error('REPO_SLUG is not set') const allSoundsMeta = { format: 'mp3', - baseUrl: 'https://raw.githubusercontent.com/zardoy/prismarine-web-client/sounds-generated/sounds/' + baseUrl: `https://raw.githubusercontent.com/${process.env.REPO_SLUG}/sounds/sounds/` } await build({ @@ -235,9 +297,25 @@ const makeSoundsBundle = async () => { }, metafile: true, }) + // copy also to generated/sounds.js + fs.copyFileSync('./dist/sounds.js', './generated/sounds.js') } -// downloadAllSounds() -// convertSounds() -// writeSoundsMap() -// makeSoundsBundle() +const action = process.argv[2] +if (action) { + const execFn = { + download: downloadAllSoundsAndCreateMap, + convert: convertSounds, + write: writeSoundsMap, + bundle: makeSoundsBundle, + }[action] + + if (execFn) { + execFn() + } +} else { + // downloadAllSoundsAndCreateMap() + // convertSounds() + writeSoundsMap() + // makeSoundsBundle() +} diff --git a/scripts/replaceFavicon.mjs b/scripts/replaceFavicon.mjs new file mode 100644 index 00000000..0c60d26d --- /dev/null +++ b/scripts/replaceFavicon.mjs @@ -0,0 +1,8 @@ +import fs from 'fs' + +const faviconUrl = process.argv[2] + +// save to assets/favicon.png +fetch(faviconUrl).then(res => res.arrayBuffer()).then(buffer => { + fs.writeFileSync('assets/favicon.png', Buffer.from(buffer)) +}) diff --git a/scripts/requestData.ts b/scripts/requestData.ts new file mode 100644 index 00000000..dc866a1b --- /dev/null +++ b/scripts/requestData.ts @@ -0,0 +1,42 @@ +import WebSocket from 'ws' + +function formatBytes(bytes: number) { + return `${(bytes).toFixed(2)} MB` +} + +function formatTime(ms: number) { + return `${(ms / 1000).toFixed(2)}s` +} + +const ws = new WebSocket('ws://localhost:8081') + +ws.on('open', () => { + console.log('Connected to metrics server, waiting for metrics...') +}) + +ws.on('message', (data) => { + try { + const metrics = JSON.parse(data.toString()) + console.log('\nPerformance Metrics:') + console.log('------------------') + console.log(`Load Time: ${formatTime(metrics.loadTime)}`) + console.log(`Memory Usage: ${formatBytes(metrics.memoryUsage)}`) + console.log(`Timestamp: ${new Date(metrics.timestamp).toLocaleString()}`) + if (!process.argv.includes('-f')) { // follow mode + process.exit(0) + } + } catch (error) { + console.error('Error parsing metrics:', error) + } +}) + +ws.on('error', (error) => { + console.error('WebSocket error:', error) + process.exit(1) +}) + +// Exit if no metrics received after 5 seconds +setTimeout(() => { + console.error('Timeout waiting for metrics') + process.exit(1) +}, 5000) diff --git a/scripts/test-texturepack-files.mjs b/scripts/test-texturepack-files.mjs deleted file mode 100644 index 0446a2fe..00000000 --- a/scripts/test-texturepack-files.mjs +++ /dev/null @@ -1,16 +0,0 @@ -import fs from 'fs' -import minecraftAssets from 'minecraft-assets' - -const gen = JSON.parse(fs.readFileSync('./blocks.json', 'utf8')) - -const version = '1.8.8' -const { blockNames, indexes } = gen - -const blocksActual = indexes[version].map((i) => blockNames[i]) - -const blocksExpected = fs.readdirSync(minecraftAssets(version).directory + '/blocks') -for (const [i, item] of blocksActual.entries()) { - if (item !== blocksExpected[i]) { - console.log('not equal at', i) - } -} diff --git a/scripts/testOptimizedMcdata.ts b/scripts/testOptimizedMcdata.ts new file mode 100644 index 00000000..7c94fac2 --- /dev/null +++ b/scripts/testOptimizedMcdata.ts @@ -0,0 +1,116 @@ +import assert from 'assert' +import JsonOptimizer, { restoreMinecraftData } from '../src/optimizeJson'; +import fs from 'fs' +import minecraftData from 'minecraft-data' + +const json = JSON.parse(fs.readFileSync('./generated/minecraft-data-optimized.json', 'utf8')) + +const dataPaths = require('minecraft-data/minecraft-data/data/dataPaths.json') + +const validateData = (ver, type) => { + const target = restoreMinecraftData(structuredClone(json), type, ver) + const arrKey = json[type].arrKey + const originalPath = dataPaths.pc[ver][type] + const original = require(`minecraft-data/minecraft-data/data/${originalPath}/${type}.json`) + if (arrKey) { + const originalKeys = original.map(a => JsonOptimizer.getByArrKey(a, arrKey)) as string[] + for (const [i, item] of originalKeys.entries()) { + if (originalKeys.indexOf(item) !== i) { + console.warn(`${type} ${ver} Incorrect source, duplicated arrKey (${arrKey}) ${item}. Ignoring!`) // todo should span instead + const index = originalKeys.indexOf(item); + original.splice(index, 1) + originalKeys.splice(index, 1) + } + } + // if (target.length !== originalKeys.length) { + // throw new Error(`wrong arr length: ${target.length} !== ${original.length}`) + // } + checkKeys(originalKeys, target.map(a => JsonOptimizer.getByArrKey(a, arrKey))) + for (const item of target as any[]) { + const keys = Object.entries(item).map(a => a[0]) + const origItem = original.find(a => JsonOptimizer.getByArrKey(a, arrKey) === JsonOptimizer.getByArrKey(item, arrKey)); + const keysSource = Object.entries(origItem).map(a => a[0]) + checkKeys(keysSource, keys, true, 'prop keys', true) + checkObj(origItem, item) + } + } else { + const keysOriginal = Object.keys(original) + const keysTarget = Object.keys(target) + checkKeys(keysOriginal, keysTarget) + for (const key of keysTarget) { + checkObj(original[key], target[key]) + } + } +} + +const sortObj = (obj) => { + const sorted = {} + for (const key of Object.keys(obj).sort()) { + sorted[key] = obj[key] + } + return sorted +} + +const checkObj = (source, diffing) => { + if (!Array.isArray(source)) { + source = sortObj(source) + } + if (!Array.isArray(diffing)) { + diffing = sortObj(diffing) + } + if (JSON.stringify(source) !== JSON.stringify(diffing)) { + throw new Error(`different value: ${JSON.stringify(source)} ${JSON.stringify(diffing)}`) + } + // checkKeys(Object.keys(source), Object.keys(diffing)) + // for (const [key, val] of Object.entries(source)) { + // if (JSON.stringify(val) !== JSON.stringify(diffing[key])) { + // throw new Error(`different value of ${key}: ${val} ${diffing[key]}`) + // } + // } +} + +const checkKeys = (source, diffing, isUniq = true, msg = '', redundantIsOk = false) => { + if (isUniq) { + for (const [i, item] of diffing.entries()) { + if (diffing.indexOf(item) !== i) { + throw new Error(`Duplicate: ${item}: ${i} ${diffing.indexOf(item)} ${msg}`) + } + } + } + for (const key of source) { + if (!diffing.includes(key)) { + throw new Error(`Diffing does not include "${key}" (${msg})`) + } + } + if (!redundantIsOk) { + for (const key of diffing) { + if (!source.includes(key)) { + throw new Error(`Source does not include "${key}" (${msg})`) + } + } + } +} + +// const data = minecraftData('1.20.4') +const oldId = JsonOptimizer.restoreData(json['blocks'], '1.20', undefined).find(x => x.name === 'brown_stained_glass').id; +const newId = JsonOptimizer.restoreData(json['blocks'], '1.20.4', undefined).find(x => x.name === 'brown_stained_glass').id; +assert(oldId !== newId) +// test all types + all versions + +for (const type of Object.keys(json)) { + if (!json[type].__IS_OPTIMIZED__) continue + if (type === 'language') continue // we have loose data for language for size reasons + console.log('validating', type) + const source = json[type] + let checkedVer = 0 + for (const ver of Object.keys(source.diffs)) { + try { + validateData(ver, type) + } catch (err) { + err.message = `Failed to validate ${type} for ${ver}: ${err.message}` + throw err; + } + checkedVer++ + } + console.log('Checked versions:', checkedVer) +} diff --git a/scripts/updateGitDeps.ts b/scripts/updateGitDeps.ts new file mode 100644 index 00000000..797aea8f --- /dev/null +++ b/scripts/updateGitDeps.ts @@ -0,0 +1,160 @@ +import fs from 'fs' +import path from 'path' +import yaml from 'yaml' +import { execSync } from 'child_process' +import { createInterface } from 'readline' + +interface LockfilePackage { + specifier: string + version: string +} + +interface Lockfile { + importers: { + '.': { + dependencies?: Record + devDependencies?: Record + } + } +} + +interface PackageJson { + pnpm?: { + updateConfig?: { + ignoreDependencies?: string[] + } + } +} + +async function prompt(question: string): Promise { + const rl = createInterface({ + input: process.stdin, + output: process.stdout + }) + + return new Promise(resolve => { + rl.question(question, answer => { + rl.close() + resolve(answer.toLowerCase().trim()) + }) + }) +} + +async function getLatestCommit(owner: string, repo: string): Promise { + const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/commits/HEAD`) + if (!response.ok) { + throw new Error(`Failed to fetch latest commit: ${response.statusText}`) + } + const data = await response.json() + return data.sha +} + +function extractGitInfo(specifier: string): { owner: string; repo: string; branch: string } | null { + const match = specifier.match(/github:([^/]+)\/([^#]+)(?:#(.+))?/) + if (!match) return null + return { + owner: match[1], + repo: match[2], + branch: match[3] || 'master' + } +} + +function extractCommitHash(version: string): string | null { + const match = version.match(/https:\/\/codeload\.github\.com\/[^/]+\/[^/]+\/tar\.gz\/([a-f0-9]+)/) + return match ? match[1] : null +} + +function getIgnoredDependencies(): string[] { + try { + const packageJsonPath = path.join(process.cwd(), 'package.json') + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as PackageJson + return packageJson.pnpm?.updateConfig?.ignoreDependencies || [] + } catch (error) { + console.warn('Failed to read package.json for ignored dependencies:', error) + return [] + } +} + +async function main() { + const lockfilePath = path.join(process.cwd(), 'pnpm-lock.yaml') + const lockfileContent = fs.readFileSync(lockfilePath, 'utf8') + const lockfile = yaml.parse(lockfileContent) as Lockfile + + const ignoredDependencies = new Set(getIgnoredDependencies()) + console.log('Ignoring dependencies:', Array.from(ignoredDependencies).join(', ') || 'none') + + const dependencies = { + ...lockfile.importers['.'].dependencies, + ...lockfile.importers['.'].devDependencies + } + + const updates: Array<{ + name: string + currentHash: string + latestHash: string + gitInfo: ReturnType + }> = [] + + console.log('\nChecking git dependencies...') + for (const [name, pkg] of Object.entries(dependencies)) { + if (ignoredDependencies.has(name)) { + console.log(`Skipping ignored dependency: ${name}`) + continue + } + + if (!pkg.specifier.startsWith('github:')) continue + + const gitInfo = extractGitInfo(pkg.specifier) + if (!gitInfo) continue + + const currentHash = extractCommitHash(pkg.version) + if (!currentHash) continue + + try { + process.stdout.write(`Checking ${name}... `) + const latestHash = await getLatestCommit(gitInfo.owner, gitInfo.repo) + if (currentHash !== latestHash) { + console.log('update available') + updates.push({ name, currentHash, latestHash, gitInfo }) + } else { + console.log('up to date') + } + } catch (error) { + console.log('failed') + console.error(`Error checking ${name}:`, error) + } + } + + if (updates.length === 0) { + console.log('\nAll git dependencies are up to date!') + return + } + + console.log('\nThe following git dependencies can be updated:') + for (const update of updates) { + console.log(`\n${update.name}:`) + console.log(` Current: ${update.currentHash}`) + console.log(` Latest: ${update.latestHash}`) + console.log(` Repo: ${update.gitInfo!.owner}/${update.gitInfo!.repo}`) + } + + const answer = await prompt('\nWould you like to update these dependencies? (y/N): ') + if (answer === 'y' || answer === 'yes') { + let newLockfileContent = lockfileContent + for (const update of updates) { + newLockfileContent = newLockfileContent.replace( + new RegExp(update.currentHash, 'g'), + update.latestHash + ) + } + fs.writeFileSync(lockfilePath, newLockfileContent) + console.log('\nUpdated pnpm-lock.yaml with new commit hashes') + // console.log('Running pnpm install to apply changes...') + // execSync('pnpm install', { stdio: 'inherit' }) + console.log('Done!') + } else { + console.log('\nNo changes were made.') + } +} + +main().catch(console.error) 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) diff --git a/scripts/uploadSoundFiles.ts b/scripts/uploadSoundFiles.ts new file mode 100644 index 00000000..e8677c87 --- /dev/null +++ b/scripts/uploadSoundFiles.ts @@ -0,0 +1,109 @@ +import fetch from 'node-fetch'; +import * as fs from 'fs'; +import * as path from 'path'; +import { glob } from 'glob'; + +// Git details +const REPO_SLUG = process.env.REPO_SLUG; +const owner = REPO_SLUG.split('/')[0]; +const repo = REPO_SLUG.split('/')[1]; +const branch = "sounds"; + +// GitHub token for authentication +const token = process.env.GITHUB_TOKEN; + +// GitHub API endpoint +const baseUrl = `https://api.github.com/repos/${owner}/${repo}/contents`; + +const headers = { + Authorization: `token ${token}`, + 'Content-Type': 'application/json' +}; + +async function getShaForExistingFile(repoFilePath: string): Promise { + const url = `${baseUrl}/${repoFilePath}?ref=${branch}`; + const response = await fetch(url, { headers }); + if (response.status === 404) { + return null; // File does not exist + } + if (!response.ok) { + throw new Error(`Failed to fetch ${url}: ${response.statusText}`); + } + const data = await response.json(); + return data.sha; +} + +async function uploadFiles() { + const commitMessage = "Upload multiple files via script"; + const committer = { + name: "GitHub", + email: "noreply@github.com" + }; + + const filesToUpload = glob.sync("generated/sounds/**/*.mp3").map(localPath => { + const repoPath = localPath.replace(/^generated\//, ''); + return { localPath, repoPath }; + }); + + const files = await Promise.all(filesToUpload.map(async file => { + const content = fs.readFileSync(file.localPath, 'base64'); + const sha = await getShaForExistingFile(file.repoPath); + return { + path: file.repoPath, + mode: "100644", + type: "blob", + sha: sha || undefined, + content: content + }; + })); + + const treeResponse = await fetch(`${baseUrl}/git/trees`, { + method: 'POST', + headers: headers, + body: JSON.stringify({ + base_tree: null, + tree: files + }) + }); + + if (!treeResponse.ok) { + throw new Error(`Failed to create tree: ${treeResponse.statusText}`); + } + + const treeData = await treeResponse.json(); + + const commitResponse = await fetch(`${baseUrl}/git/commits`, { + method: 'POST', + headers: headers, + body: JSON.stringify({ + message: commitMessage, + tree: treeData.sha, + parents: [branch], + committer: committer + }) + }); + + if (!commitResponse.ok) { + throw new Error(`Failed to create commit: ${commitResponse.statusText}`); + } + + const commitData = await commitResponse.json(); + + const updateRefResponse = await fetch(`${baseUrl}/git/refs/heads/${branch}`, { + method: 'PATCH', + headers: headers, + body: JSON.stringify({ + sha: commitData.sha + }) + }); + + if (!updateRefResponse.ok) { + throw new Error(`Failed to update ref: ${updateRefResponse.statusText}`); + } + + console.log("Files uploaded successfully"); +} + +uploadFiles().catch(error => { + console.error("Error uploading files:", error); +}); diff --git a/scripts/uploadSounds.ts b/scripts/uploadSounds.ts new file mode 100644 index 00000000..b0e9ecd7 --- /dev/null +++ b/scripts/uploadSounds.ts @@ -0,0 +1,67 @@ +import fs from 'fs' + +// GitHub details +const owner = "zardoy"; +const repo = "minecraft-web-client"; +const branch = "sounds-generated"; +const filePath = "dist/sounds.js"; // Local file path +const repoFilePath = "sounds-v2.js"; // Path in the repo + +// GitHub token for authentication +const token = process.env.GITHUB_TOKEN; + +// GitHub API endpoint +const baseUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${repoFilePath}`; + +const headers = { + Authorization: `token ${token}`, + 'Content-Type': 'application/json' +}; + +async function getShaForExistingFile(): Promise { + const url = `${baseUrl}?ref=${branch}`; + const response = await fetch(url, { headers }); + if (response.status === 404) { + return null; // File does not exist + } + if (!response.ok) { + throw new Error(`Failed to fetch ${url}: ${response.statusText}`); + } + const data = await response.json(); + return data.sha; +} + +async function uploadFile() { + const content = fs.readFileSync(filePath, 'utf8'); + const base64Content = Buffer.from(content).toString('base64'); + const sha = await getShaForExistingFile(); + console.log('got sha') + + const body = { + message: "Update sounds.js", + content: base64Content, + branch: branch, + committer: { + name: "GitHub", + email: "noreply@github.com" + }, + sha: sha || undefined + }; + + const response = await fetch(baseUrl, { + method: 'PUT', + headers: headers, + body: JSON.stringify(body) + }); + + if (!response.ok) { + throw new Error(`Failed to upload file: ${response.statusText}`); + } + + const responseData = await response.json(); + console.log("File uploaded successfully:", responseData); +} + +uploadFile().catch(error => { + console.error("Error uploading file:", error); +}); diff --git a/scripts/wsServer.ts b/scripts/wsServer.ts new file mode 100644 index 00000000..43035f52 --- /dev/null +++ b/scripts/wsServer.ts @@ -0,0 +1,45 @@ +import {WebSocketServer} from 'ws' + +export function startWsServer(port: number = 8081, tryOtherPort: boolean = true): Promise { + return new Promise((resolve, reject) => { + const tryPort = (currentPort: number) => { + const wss = new WebSocketServer({ port: currentPort }) + .on('listening', () => { + console.log(`WebSocket server started on port ${currentPort}`) + resolve(currentPort) + }) + .on('error', (err: any) => { + if (err.code === 'EADDRINUSE' && tryOtherPort) { + console.log(`Port ${currentPort} in use, trying ${currentPort + 1}`) + wss.close() + tryPort(currentPort + 1) + } else { + reject(err) + } + }) + + wss.on('connection', (ws) => { + console.log('Client connected') + + ws.on('message', (message) => { + try { + // Simply relay the message to all connected clients except sender + wss.clients.forEach(client => { + if (client !== ws && client.readyState === WebSocket.OPEN) { + client.send(message.toString()) + } + }) + } catch (error) { + console.error('Error processing message:', error) + } + }) + + ws.on('close', () => { + console.log('Client disconnected') + }) + }) + } + + tryPort(port) + }) +} diff --git a/server.js b/server.js index d757024b..49699cdb 100644 --- a/server.js +++ b/server.js @@ -15,19 +15,32 @@ try { // Create our app const app = express() -const isProd = process.argv.includes('--prod') +const isProd = process.argv.includes('--prod') || process.env.NODE_ENV === 'production' +const timeoutIndex = process.argv.indexOf('--timeout') +let timeout = timeoutIndex > -1 && timeoutIndex + 1 < process.argv.length + ? parseInt(process.argv[timeoutIndex + 1]) + : process.env.TIMEOUT + ? parseInt(process.env.TIMEOUT) + : 10000 +if (isNaN(timeout) || timeout < 0) { + console.warn('Invalid timeout value provided, using default of 10000ms') + timeout = 10000 +} app.use(compression()) -app.use(netApi({ allowOrigin: '*' })) +app.use(cors()) +app.use(netApi({ + allowOrigin: '*', + log: process.argv.includes('--log') || process.env.LOG === 'true', + timeout +})) if (!isProd) { - app.use('/blocksStates', express.static(path.join(__dirname, './prismarine-viewer/public/blocksStates'))) - app.use('/textures', express.static(path.join(__dirname, './prismarine-viewer/public/textures'))) - app.use('/sounds', express.static(path.join(__dirname, './generated/sounds/'))) } // patch config app.get('/config.json', (req, res, next) => { // read original file config let config = {} + let publicConfig = {} try { config = require('./config.json') } catch { @@ -35,28 +48,38 @@ app.get('/config.json', (req, res, next) => { config = require('./dist/config.json') } catch { } } + try { + publicConfig = require('./public/config.json') + } catch { } res.json({ ...config, 'defaultProxy': '', // use current url (this server) + ...publicConfig, }) }) -// add headers to enable shared array buffer -app.use((req, res, next) => { - res.setHeader('Cross-Origin-Opener-Policy', 'same-origin') - res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') - next() -}) -app.use(express.static(path.join(__dirname, './dist'))) +if (isProd) { + // add headers to enable shared array buffer + app.use((req, res, next) => { + res.setHeader('Cross-Origin-Opener-Policy', 'same-origin') + res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') + next() + }) -const portArg = process.argv.indexOf('--port') -const port = (require.main === module ? process.argv[2] : portArg !== -1 ? process.argv[portArg + 1] : undefined) || 8080 + // First serve from the override directory (volume mount) + app.use(express.static(path.join(__dirname, './public'))) + + // Then fallback to the original dist directory + app.use(express.static(path.join(__dirname, './dist'))) +} + +const numArg = process.argv.find(x => x.match(/^\d+$/)) +const port = (require.main === module ? numArg : undefined) || 8080 // Start the server -const server = isProd ? - undefined : +const server = app.listen(port, async function () { - console.log('Server listening on port ' + server.address().port) - if (siModule) { + console.log('Proxy server listening on port ' + server.address().port) + if (siModule && isProd) { const _interfaces = await siModule.networkInterfaces() const interfaces = Array.isArray(_interfaces) ? _interfaces : [_interfaces] let netInterface = interfaces.find(int => int.default) diff --git a/src/api/mcStatusApi.ts b/src/api/mcStatusApi.ts new file mode 100644 index 00000000..8ac429dd --- /dev/null +++ b/src/api/mcStatusApi.ts @@ -0,0 +1,64 @@ +globalThis.resolveDnsFallback = async (hostname: string) => { + const response = await fetchServerStatus(hostname) + return response?.raw.srv_record ?? undefined +} + +export const isServerValid = (ip: string) => { + const isInLocalNetwork = ip.startsWith('192.168.') || + ip.startsWith('10.') || + ip.startsWith('172.') || + ip.startsWith('127.') || + ip.startsWith('localhost') || + ip.startsWith(':') + const VALID_IP_OR_DOMAIN = ip.includes('.') + + return !isInLocalNetwork && VALID_IP_OR_DOMAIN +} + +export async function fetchServerStatus (ip: string, signal?: AbortSignal, versionOverride?: string) { + if (!isServerValid(ip)) return + + const response = await fetch(`https://api.mcstatus.io/v2/status/java/${ip}`, { signal }) + const data: ServerResponse = await response.json() + const versionClean = data.version?.name_raw.replace(/^[^\d.]+/, '') + + return { + formattedText: data.motd?.raw ?? '', + textNameRight: data.online ? + `${versionOverride ?? versionClean} ${data.players?.online ?? '??'}/${data.players?.max ?? '??'}` : + '', + icon: data.icon, + offline: !data.online, + raw: data + } +} + +export type ServerResponse = { + online: boolean + 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: string, version: string }> + // todo display via hammer icon + software?: string + plugins?: Array<{ name, version }> + // port?: number + srv_record?: { + host: string + port: number + } +} diff --git a/src/appConfig.ts b/src/appConfig.ts new file mode 100644 index 00000000..c29d74e8 --- /dev/null +++ b/src/appConfig.ts @@ -0,0 +1,109 @@ +import { defaultsDeep } from 'lodash' +import { disabledSettings, options, qsOptions } from './optionsStorage' +import { miscUiState } from './globalState' +import { setLoadingScreenStatus } from './appStatus' +import { setStorageDataOnAppConfigLoad } from './react/appStorageProvider' +import { customKeymaps, updateBinds } from './controls' + +export type CustomAction = { + readonly type: string + readonly input: readonly any[] +} + +export type ActionType = string | CustomAction + +export type ActionHoldConfig = { + readonly command: ActionType + readonly longPressAction?: ActionType + readonly duration?: number + readonly threshold?: number +} + +export type MobileButtonConfig = { + readonly label?: string + readonly icon?: string + readonly action?: ActionType + readonly actionHold?: ActionType | ActionHoldConfig + readonly iconStyle?: React.CSSProperties +} + +export type AppConfig = { + // defaultHost?: string + // defaultHostSave?: string + defaultProxy?: string + // defaultProxySave?: string + // defaultVersion?: string + peerJsServer?: string + peerJsServerFallback?: string + promoteServers?: Array<{ ip, description, name?, version?, }> + mapsProvider?: string + + appParams?: Record // query string params + rightSideText?: string + + defaultSettings?: Record + forceSettings?: Record + // hideSettings?: Record + allowAutoConnect?: boolean + splashText?: string + splashTextFallback?: string + pauseLinks?: Array>> + mobileButtons?: MobileButtonConfig[] + keybindings?: Record + defaultLanguage?: string + displayLanguageSelector?: boolean + supportedLanguages?: string[] + showModsButton?: boolean + defaultUsername?: string + skinTexturesProxy?: string + alwaysReconnectButton?: boolean + reportBugButtonWithReconnect?: boolean + disabledCommands?: string[] // Array of command IDs to disable (e.g. ['general.jump', 'general.chat']) +} + +export const loadAppConfig = (appConfig: AppConfig) => { + + if (miscUiState.appConfig) { + Object.assign(miscUiState.appConfig, appConfig) + } else { + miscUiState.appConfig = appConfig + } + + if (appConfig.forceSettings) { + for (const [key, value] of Object.entries(appConfig.forceSettings)) { + if (value) { + disabledSettings.value.add(key) + // since the setting is forced, we need to set it to that value + if (appConfig.defaultSettings && key in appConfig.defaultSettings && !qsOptions[key]) { + options[key] = appConfig.defaultSettings[key] + } + } else { + disabledSettings.value.delete(key) + } + } + } + // todo apply defaultSettings to defaults even if not forced in case of remote config + + if (appConfig.keybindings) { + Object.assign(customKeymaps, defaultsDeep(appConfig.keybindings, customKeymaps)) + updateBinds(customKeymaps) + } + + appViewer?.appConfigUdpate() + + setStorageDataOnAppConfigLoad(appConfig) +} + +export const isBundledConfigUsed = !!process.env.INLINED_APP_CONFIG + +if (isBundledConfigUsed) { + loadAppConfig(process.env.INLINED_APP_CONFIG as AppConfig ?? {}) +} else { + void window.fetch('config.json').then(async res => res.json()).then(c => c, (error) => { + // console.warn('Failed to load optional app config.json', error) + // return {} + setLoadingScreenStatus('Failed to load app config.json', true) + }).then((config: AppConfig) => { + loadAppConfig(config) + }) +} diff --git a/src/appParams.ts b/src/appParams.ts new file mode 100644 index 00000000..4c8ca186 --- /dev/null +++ b/src/appParams.ts @@ -0,0 +1,121 @@ +import type { AppConfig } from './appConfig' +import { miscUiState } from './globalState' + +const qsParams = new URLSearchParams(window.location?.search ?? '') + +export type AppQsParams = { + // AddServerOrConnect.tsx params + ip?: string + name?: string + version?: string + proxy?: string + username?: string + lockConnect?: string + autoConnect?: string + alwaysReconnect?: string + // googledrive.ts params + state?: string + // ServersListProvider.tsx params + serversList?: string + // Map and texture params + texturepack?: string + map?: string + mapDirBaseUrl?: string + mapDirGuess?: string + // Singleplayer params + singleplayer?: string + sp?: string + loadSave?: string + // Server params + reconnect?: string + server?: string + // Peer connection params + connectPeer?: string + peerVersion?: string + // UI params + modal?: string + viewerConnect?: string + // Map version param + mapVersion?: string + // Command params + command?: string + // Misc params + suggest_save?: string + noPacketsValidation?: string + testCrashApp?: string + onlyConnect?: string + connectText?: string + freezeSettings?: string + testIosCrash?: string + addPing?: string + + // Replay params + replayFilter?: string + replaySpeed?: string + replayFileUrl?: string + replayValidateClient?: string + replayStopOnError?: string + replaySkipMissingOnTimeout?: string + replayPacketsSenderDelay?: string + + // Benchmark params + openBenchmark?: string + renderDistance?: string + downloadBenchmark?: string + benchmarkMapZipUrl?: string + benchmarkPosition?: string +} + +export type AppQsParamsArray = { + mapDir?: string[] + setting?: string[] + serverSetting?: string[] + command?: string[] +} + +type AppQsParamsArrayTransformed = { + [k in keyof AppQsParamsArray]: string[] +} + +globalThis.process ??= {} as any +const initialAppConfig = process?.env?.INLINED_APP_CONFIG as AppConfig ?? {} + +export const appQueryParams = new Proxy({} as AppQsParams, { + get (target, property) { + if (typeof property !== 'string') { + return undefined + } + const qsParam = qsParams.get(property) + if (qsParam) return qsParam + return miscUiState.appConfig?.appParams?.[property] + }, +}) + +export const appQueryParamsArray = new Proxy({} as AppQsParamsArrayTransformed, { + get (target, property) { + if (typeof property !== 'string') { + return null + } + const qsParam = qsParams.getAll(property) + if (qsParam.length) return qsParam + return miscUiState.appConfig?.appParams?.[property] ?? [] + }, +}) + +export function updateQsParam (name: keyof AppQsParams, value: string | undefined) { + const url = new URL(window.location.href) + if (value) { + url.searchParams.set(name, value) + } else { + url.searchParams.delete(name) + } + window.history.replaceState({}, '', url.toString()) +} + +// Helper function to check if a specific query parameter exists +export const hasQueryParam = (param: keyof AppQsParams) => qsParams.has(param) + +// Helper function to get all query parameters as a URLSearchParams object +export const getRawQueryParams = () => qsParams; + +(globalThis as any).debugQueryParams = Object.fromEntries(qsParams.entries()) diff --git a/src/appStatus.ts b/src/appStatus.ts new file mode 100644 index 00000000..101714f5 --- /dev/null +++ b/src/appStatus.ts @@ -0,0 +1,41 @@ +import { resetStateAfterDisconnect } from './browserfs' +import { hideModal, activeModalStack, showModal, miscUiState } from './globalState' +import { appStatusState, resetAppStatusState } from './react/AppStatusProvider' + +let ourLastStatus: string | undefined = '' +export const setLoadingScreenStatus = function (status: string | undefined | null, isError = false, hideDots = false, fromFlyingSquid = false, minecraftJsonMessage?: Record) { + if (typeof status === 'string') status = window.translateText?.(status) ?? status + // null can come from flying squid, should restore our last status + if (status === null) { + status = ourLastStatus + } else if (!fromFlyingSquid) { + ourLastStatus = status + } + fromFlyingSquid = false + + if (status === undefined) { + appStatusState.status = '' + + hideModal({ reactType: 'app-status' }, {}, { force: true }) + return + } + + if (!activeModalStack.some(x => x.reactType === 'app-status')) { + // just showing app status + resetAppStatusState() + } + showModal({ reactType: 'app-status' }) + if (appStatusState.isError) { + return + } + appStatusState.hideDots = hideDots + appStatusState.isError = isError + appStatusState.lastStatus = isError ? appStatusState.status : '' + appStatusState.status = status + appStatusState.minecraftJsonMessage = minecraftJsonMessage ?? null + + if (isError && miscUiState.gameLoaded) { + resetStateAfterDisconnect() + } +} +globalThis.setLoadingScreenStatus = setLoadingScreenStatus diff --git a/src/appViewer.ts b/src/appViewer.ts new file mode 100644 index 00000000..628d11b4 --- /dev/null +++ b/src/appViewer.ts @@ -0,0 +1,354 @@ +import { WorldDataEmitter, WorldDataEmitterWorker } from 'renderer/viewer/lib/worldDataEmitter' +import { getInitialPlayerState, PlayerStateRenderer, PlayerStateReactive } from 'renderer/viewer/lib/basePlayerState' +import { subscribeKey } from 'valtio/utils' +import { defaultWorldRendererConfig, WorldRendererConfig } from 'renderer/viewer/lib/worldrendererCommon' +import { Vec3 } from 'vec3' +import { SoundSystem } from 'renderer/viewer/three/threeJsSound' +import { proxy, subscribe } from 'valtio' +import { getDefaultRendererState } from 'renderer/viewer/baseGraphicsBackend' +import { getSyncWorld } from 'renderer/playground/shared' +import { MaybePromise } from 'contro-max/build/types/store' +import { PANORAMA_VERSION } from 'renderer/viewer/three/panoramaShared' +import { playerState } from './mineflayer/playerState' +import { createNotificationProgressReporter, ProgressReporter } from './core/progressReporter' +import { setLoadingScreenStatus } from './appStatus' +import { activeModalStack, miscUiState } from './globalState' +import { options } from './optionsStorage' +import { ResourcesManager, ResourcesManagerTransferred } from './resourcesManager' +import { watchOptionsAfterWorldViewInit } from './watchOptions' +import { loadMinecraftData } from './connect' +import { reloadChunks } from './utils' +import { displayClientChat } from './botUtils' + +export interface RendererReactiveState { + world: { + chunksLoaded: Set + // chunksTotalNumber: number + heightmaps: Map + allChunksLoaded: boolean + mesherWork: boolean + intersectMedia: { id: string, x: number, y: number } | null + } + renderer: string + preventEscapeMenu: boolean +} +export interface NonReactiveState { + world: { + chunksLoaded: Set + chunksTotalNumber: number + } +} + +export interface GraphicsBackendConfig { + fpsLimit?: number + powerPreference?: 'high-performance' | 'low-power' + statsVisible?: number + sceneBackground: string + timeoutRendering?: boolean +} + +const defaultGraphicsBackendConfig: GraphicsBackendConfig = { + fpsLimit: undefined, + powerPreference: undefined, + sceneBackground: 'lightblue', + timeoutRendering: false +} + +export interface GraphicsInitOptions { + resourcesManager: ResourcesManagerTransferred + config: GraphicsBackendConfig + rendererSpecificSettings: S + + callbacks: { + displayCriticalError: (error: Error) => void + setRendererSpecificSettings: (key: string, value: any) => void + + fireCustomEvent: (eventName: string, ...args: any[]) => void + } +} + +export interface DisplayWorldOptions { + version: string + worldView: WorldDataEmitterWorker + inWorldRenderingConfig: WorldRendererConfig + playerStateReactive: PlayerStateReactive + rendererState: RendererReactiveState + nonReactiveState: NonReactiveState +} + +export type GraphicsBackendLoader = ((options: GraphicsInitOptions) => MaybePromise) & { + id: string +} + +// no sync methods +export interface GraphicsBackend { + id: string + displayName?: string + startPanorama: () => void + // prepareResources: (version: string, progressReporter: ProgressReporter) => Promise + startWorld: (options: DisplayWorldOptions) => Promise | void + disconnect: () => void + setRendering: (rendering: boolean) => void + getDebugOverlay?: () => Record + updateCamera: (pos: Vec3 | null, yaw: number, pitch: number) => void + setRoll?: (roll: number) => void + soundSystem: SoundSystem | undefined + + backendMethods: Record | undefined +} + +export class AppViewer { + waitBackendLoadPromises = [] as Array> + + resourcesManager = new ResourcesManager() + worldView: WorldDataEmitter | undefined + readonly config: GraphicsBackendConfig = { + ...defaultGraphicsBackendConfig, + powerPreference: options.gpuPreference === 'default' ? undefined : options.gpuPreference + } + backend?: GraphicsBackend + backendLoader?: GraphicsBackendLoader + private currentState?: { + method: string + args: any[] + } + currentDisplay = null as 'menu' | 'world' | null + inWorldRenderingConfig: WorldRendererConfig = proxy(defaultWorldRendererConfig) + lastCamUpdate = 0 + playerState = playerState + rendererState = getDefaultRendererState().reactive + nonReactiveState: NonReactiveState = getDefaultRendererState().nonReactive + worldReady: Promise + private resolveWorldReady: () => void + + constructor () { + this.disconnectBackend() + } + + async loadBackend (loader: GraphicsBackendLoader) { + if (this.backend) { + this.disconnectBackend() + } + + await Promise.all(this.waitBackendLoadPromises) + this.waitBackendLoadPromises = [] + + this.backendLoader = loader + const rendererSpecificSettings = {} as Record + const rendererSettingsKey = `renderer.${this.backendLoader?.id}` + for (const key in options) { + if (key.startsWith(rendererSettingsKey)) { + rendererSpecificSettings[key.slice(rendererSettingsKey.length + 1)] = options[key] + } + } + const loaderOptions: GraphicsInitOptions = { // todo! + resourcesManager: this.resourcesManager as ResourcesManagerTransferred, + config: this.config, + callbacks: { + displayCriticalError (error) { + console.error(error) + setLoadingScreenStatus(error.message, true) + }, + setRendererSpecificSettings (key: string, value: any) { + options[`${rendererSettingsKey}.${key}`] = value + }, + fireCustomEvent (eventName, ...args) { + // this.callbacks.fireCustomEvent(eventName, ...args) + } + }, + rendererSpecificSettings, + } + this.backend = await loader(loaderOptions) + + // if (this.resourcesManager.currentResources) { + // void this.prepareResources(this.resourcesManager.currentResources.version, createNotificationProgressReporter()) + // } + + // Execute queued action if exists + if (this.currentState) { + if (this.currentState.method === 'startPanorama') { + this.startPanorama() + } else { + const { method, args } = this.currentState + this.backend[method](...args) + if (method === 'startWorld') { + void this.worldView!.init(bot.entity.position) + // void this.worldView!.init(args[0].playerState.getPosition()) + } + } + } + + // todo + modalStackUpdateChecks() + } + + async startWithBot () { + const renderDistance = miscUiState.singleplayer ? options.renderDistance : options.multiplayerRenderDistance + await this.startWorld(bot.world, renderDistance) + this.worldView!.listenToBot(bot) + } + + appConfigUdpate () { + if (miscUiState.appConfig) { + this.inWorldRenderingConfig.skinTexturesProxy = miscUiState.appConfig.skinTexturesProxy + } + } + + async startWorld (world, renderDistance: number, playerStateSend: PlayerStateRenderer = this.playerState.reactive) { + if (this.currentDisplay === 'world') throw new Error('World already started') + this.currentDisplay = 'world' + const startPosition = bot.entity?.position ?? new Vec3(0, 64, 0) + this.worldView = new WorldDataEmitter(world, renderDistance, startPosition) + this.worldView.panicChunksReload = () => { + if (!options.experimentalClientSelfReload) return + if (process.env.NODE_ENV === 'development') { + displayClientChat(`[client] client panicked due to too long loading time. Soft reloading chunks...`) + } + void reloadChunks() + } + window.worldView = this.worldView + watchOptionsAfterWorldViewInit(this.worldView) + this.appConfigUdpate() + + const displayWorldOptions: DisplayWorldOptions = { + version: this.resourcesManager.currentConfig!.version, + worldView: this.worldView, + inWorldRenderingConfig: this.inWorldRenderingConfig, + playerStateReactive: playerStateSend, + rendererState: this.rendererState, + nonReactiveState: this.nonReactiveState + } + let promise: undefined | Promise + if (this.backend) { + promise = this.backend.startWorld(displayWorldOptions) ?? undefined + // void this.worldView.init(startPosition) + } + this.currentState = { method: 'startWorld', args: [displayWorldOptions] } + + await promise + // Resolve the promise after world is started + this.resolveWorldReady() + return !!promise + } + + resetBackend (cleanState = false) { + this.disconnectBackend(cleanState) + if (this.backendLoader) { + void this.loadBackend(this.backendLoader) + } + } + + startPanorama () { + if (this.currentDisplay === 'menu') return + if (options.disableAssets) return + if (this.backend && !hasAppStatus()) { + this.currentDisplay = 'menu' + if (process.env.SINGLE_FILE_BUILD_MODE) { + void loadMinecraftData(PANORAMA_VERSION).then(() => { + this.backend?.startPanorama() + }) + } else { + this.backend.startPanorama() + } + } + this.currentState = { method: 'startPanorama', args: [] } + } + + // async prepareResources (version: string, progressReporter: ProgressReporter) { + // if (this.backend) { + // await this.backend.prepareResources(version, progressReporter) + // } + // } + + destroyAll () { + this.disconnectBackend() + this.resourcesManager.destroy() + } + + disconnectBackend (cleanState = false) { + if (cleanState) { + this.currentState = undefined + this.currentDisplay = null + this.worldView = undefined + } + if (this.backend) { + this.backend.disconnect() + this.backend = undefined + } + this.currentDisplay = null + const { promise, resolve } = Promise.withResolvers() + this.worldReady = promise + this.resolveWorldReady = resolve + this.rendererState = proxy(getDefaultRendererState().reactive) + this.nonReactiveState = getDefaultRendererState().nonReactive + // this.queuedDisplay = undefined + } + + get utils () { + return { + async waitingForChunks () { + if (this.backend?.worldState.allChunksLoaded) return + return new Promise((resolve) => { + const interval = setInterval(() => { + if (this.backend?.worldState.allChunksLoaded) { + clearInterval(interval) + resolve(true) + } + }, 100) + }) + } + } + } +} + +// do not import this. Use global appViewer instead (without window prefix). +export const appViewer = new AppViewer() +window.appViewer = appViewer + +const initialMenuStart = async () => { + if (appViewer.currentDisplay === 'world') { + appViewer.resetBackend(true) + } + const demo = new URLSearchParams(window.location.search).get('demo') + if (!demo) { + appViewer.startPanorama() + return + } + + // const version = '1.18.2' + const version = '1.21.4' + const { loadMinecraftData } = await import('./connect') + const { getSyncWorld } = await import('../renderer/playground/shared') + await loadMinecraftData(version) + const world = getSyncWorld(version) + world.setBlockStateId(new Vec3(0, 64, 0), loadedData.blocksByName.water.defaultState) + world.setBlockStateId(new Vec3(1, 64, 0), loadedData.blocksByName.water.defaultState) + world.setBlockStateId(new Vec3(1, 64, 1), loadedData.blocksByName.water.defaultState) + world.setBlockStateId(new Vec3(0, 64, 1), loadedData.blocksByName.water.defaultState) + world.setBlockStateId(new Vec3(-1, 64, -1), loadedData.blocksByName.water.defaultState) + world.setBlockStateId(new Vec3(-1, 64, 0), loadedData.blocksByName.water.defaultState) + world.setBlockStateId(new Vec3(0, 64, -1), loadedData.blocksByName.water.defaultState) + appViewer.resourcesManager.currentConfig = { version } + appViewer.playerState.reactive = getInitialPlayerState() + await appViewer.resourcesManager.updateAssetsData({}) + await appViewer.startWorld(world, 3) + appViewer.backend!.updateCamera(new Vec3(0, 65.7, 0), 0, -Math.PI / 2) // Y+1 and pitch = PI/2 to look down + void appViewer.worldView!.init(new Vec3(0, 64, 0)) +} +window.initialMenuStart = initialMenuStart + +const hasAppStatus = () => activeModalStack.some(m => m.reactType === 'app-status') + +const modalStackUpdateChecks = () => { + // maybe start panorama + if (!miscUiState.gameLoaded && !hasAppStatus()) { + void initialMenuStart() + } + + if (appViewer.backend) { + appViewer.backend.setRendering(!hasAppStatus()) + } + + appViewer.inWorldRenderingConfig.foreground = activeModalStack.length === 0 +} +subscribe(activeModalStack, modalStackUpdateChecks) diff --git a/src/appViewerLoad.ts b/src/appViewerLoad.ts new file mode 100644 index 00000000..53260662 --- /dev/null +++ b/src/appViewerLoad.ts @@ -0,0 +1,51 @@ +import { subscribeKey } from 'valtio/utils' +import createGraphicsBackend from 'renderer/viewer/three/graphicsBackend' +import { options } from './optionsStorage' +import { appViewer } from './appViewer' +import { miscUiState } from './globalState' +import { watchOptionsAfterViewerInit } from './watchOptions' +import { showNotification } from './react/NotificationProvider' + +const backends = [ + createGraphicsBackend, +] +const loadBackend = async () => { + let backend = backends.find(backend => backend.id === options.activeRenderer) + if (!backend) { + showNotification(`No backend found for renderer ${options.activeRenderer}`, `Falling back to ${backends[0].id}`, true) + backend = backends[0] + } + await appViewer.loadBackend(backend) +} +window.loadBackend = loadBackend +if (process.env.SINGLE_FILE_BUILD_MODE) { + const unsub = subscribeKey(miscUiState, 'fsReady', () => { + if (miscUiState.fsReady) { + // don't do it earlier to load fs and display menu faster + void loadBackend() + unsub() + } + }) +} else { + setTimeout(() => { + void loadBackend() + }) +} + +const animLoop = () => { + for (const fn of beforeRenderFrame) fn() + requestAnimationFrame(animLoop) +} +requestAnimationFrame(animLoop) + +watchOptionsAfterViewerInit() + +// reset backend when renderer changes + +subscribeKey(options, 'activeRenderer', async () => { + if (appViewer.currentDisplay === 'world' && bot) { + appViewer.resetBackend(true) + await loadBackend() + void appViewer.startWithBot() + } +}) diff --git a/src/basicSounds.ts b/src/basicSounds.ts index 53c86652..54af0d35 100644 --- a/src/basicSounds.ts +++ b/src/basicSounds.ts @@ -1,3 +1,4 @@ +import { subscribeKey } from 'valtio/utils' import { options } from './optionsStorage' import { isCypress } from './standaloneUtils' import { reportWarningOnce } from './utils' @@ -5,38 +6,61 @@ import { reportWarningOnce } from './utils' let audioContext: AudioContext const sounds: Record = {} +// Track currently playing sounds and their gain nodes +const activeSounds: Array<{ + source: AudioBufferSourceNode; + gainNode: GainNode; + volumeMultiplier: number; + isMusic: boolean; +}> = [] +window.activeSounds = activeSounds + // load as many resources on page load as possible instead on demand as user can disable internet connection after he thinks the page is loaded const loadingSounds = [] as string[] const convertedSounds = [] as string[] -export async function loadSound (path: string) { + +export async function loadSound (path: string, contents = path) { if (loadingSounds.includes(path)) return true loadingSounds.push(path) - const res = await window.fetch(path) - if (!res.ok) { - const error = `Failed to load sound ${path}` - if (isCypress()) throw new Error(error) - else console.warn(error) - return - } - const data = await res.arrayBuffer() - sounds[path] = data - loadingSounds.splice(loadingSounds.indexOf(path), 1) + try { + audioContext ??= new window.AudioContext() + + const res = await window.fetch(contents) + if (!res.ok) { + const error = `Failed to load sound ${path}` + if (isCypress()) throw new Error(error) + else console.warn(error) + return + } + const arrayBuffer = await res.arrayBuffer() + + // Decode the audio data immediately + const audioBuffer = await audioContext.decodeAudioData(arrayBuffer) + sounds[path] = audioBuffer + convertedSounds.push(path) // Mark as converted immediately + + loadingSounds.splice(loadingSounds.indexOf(path), 1) + } catch (err) { + console.warn(`Failed to load sound ${path}:`, err) + loadingSounds.splice(loadingSounds.indexOf(path), 1) + if (isCypress()) throw err + } } -export const loadOrPlaySound = async (url, soundVolume = 1) => { +export const loadOrPlaySound = async (url, soundVolume = 1, loadTimeout = options.remoteSoundsLoadTimeout, loop = false, isMusic = false) => { const soundBuffer = sounds[url] if (!soundBuffer) { const start = Date.now() const cancelled = await loadSound(url) - if (cancelled || Date.now() - start > 500) return + if (cancelled || Date.now() - start > loadTimeout) return } - await playSound(url) + return playSound(url, soundVolume, loop, isMusic) } -export async function playSound (url, soundVolume = 1) { - const volume = soundVolume * (options.volume / 100) +export async function playSound (url, soundVolume = 1, loop = false, isMusic = false) { + const volume = soundVolume * (options.volume / 100) * (isMusic ? options.musicVolume / 100 : 1) if (!volume) return @@ -47,12 +71,6 @@ export async function playSound (url, soundVolume = 1) { return } - for (const [soundName, sound] of Object.entries(sounds)) { - if (convertedSounds.includes(soundName)) continue - sounds[soundName] = await audioContext.decodeAudioData(sound) - convertedSounds.push(soundName) - } - const soundBuffer = sounds[url] if (!soundBuffer) { console.warn(`Sound ${url} not loaded yet`) @@ -62,8 +80,84 @@ export async function playSound (url, soundVolume = 1) { const gainNode = audioContext.createGain() const source = audioContext.createBufferSource() source.buffer = soundBuffer + source.loop = loop source.connect(gainNode) gainNode.connect(audioContext.destination) gainNode.gain.value = volume source.start(0) + + // Add to active sounds + activeSounds.push({ source, gainNode, volumeMultiplier: soundVolume, isMusic }) + + const callbacks = [] as Array<() => void> + source.onended = () => { + // Remove from active sounds when finished + const index = activeSounds.findIndex(s => s.source === source) + if (index !== -1) activeSounds.splice(index, 1) + + for (const callback of callbacks) { + callback() + } + callbacks.length = 0 + } + + return { + onEnded (callback: () => void) { + callbacks.push(callback) + }, + stop () { + try { + source.stop() + // Remove from active sounds + const index = activeSounds.findIndex(s => s.source === source) + if (index !== -1) activeSounds.splice(index, 1) + } catch (err) { + console.warn('Failed to stop sound:', err) + } + }, + gainNode, + } } + +export function stopAllSounds () { + for (const { source } of activeSounds) { + try { + source.stop() + } catch (err) { + console.warn('Failed to stop sound:', err) + } + } + activeSounds.length = 0 +} + +export function stopSound (url: string) { + const soundIndex = activeSounds.findIndex(s => s.source.buffer === sounds[url]) + if (soundIndex !== -1) { + const { source } = activeSounds[soundIndex] + try { + source.stop() + } catch (err) { + console.warn('Failed to stop sound:', err) + } + activeSounds.splice(soundIndex, 1) + } +} + +export function changeVolumeOfCurrentlyPlayingSounds (newVolume: number, newMusicVolume: number) { + const normalizedVolume = newVolume / 100 + for (const { gainNode, volumeMultiplier, isMusic } of activeSounds) { + try { + gainNode.gain.value = normalizedVolume * volumeMultiplier * (isMusic ? newMusicVolume / 100 : 1) + } catch (err) { + console.warn('Failed to change sound volume:', err) + } + } +} + +subscribeKey(options, 'volume', () => { + changeVolumeOfCurrentlyPlayingSounds(options.volume, options.musicVolume) +}) + +subscribeKey(options, 'musicVolume', () => { + changeVolumeOfCurrentlyPlayingSounds(options.volume, options.musicVolume) +}) diff --git a/src/benchmark.ts b/src/benchmark.ts new file mode 100644 index 00000000..42603a10 --- /dev/null +++ b/src/benchmark.ts @@ -0,0 +1,311 @@ +import { Vec3 } from 'vec3' +import { WorldRendererCommon } from 'renderer/viewer/lib/worldrendererCommon' +import prettyBytes from 'pretty-bytes' +import { subscribe } from 'valtio' +import { downloadAndOpenMapFromUrl } from './downloadAndOpenFile' +import { activeModalStack, miscUiState } from './globalState' +import { disabledSettings, options } from './optionsStorage' +import { BenchmarkAdapterInfo, getAllInfoLines } from './benchmarkAdapter' +import { appQueryParams } from './appParams' +import { getScreenRefreshRate } from './utils' +import { setLoadingScreenStatus } from './appStatus' + +const DEFAULT_RENDER_DISTANCE = 5 + +interface BenchmarkFixture { + urlZip?: string + urlDir?: string[] + replayFileUrl?: string + spawn?: [number, number, number] +} + +const fixtures: Record = { + default: { + urlZip: 'https://bucket.mcraft.fun/Future CITY 4.4-slim.zip', + spawn: [-133, 87, 309] as [number, number, number], + }, + dir: { + urlDir: ['https://bucket.mcraft.fun/Greenfield%20v0.5.1/map-index.json', 'https://mcraft-proxy.vercel.app/0/bucket.mcraft.fun/Greenfield%20v0.5.1/map-index.json'], + }, + replay: { + replayFileUrl: 'https://raw.githubusercontent.com/zardoy/mcraft-fun-replays/refs/heads/main/hypepixel-tnt-lobby.worldstate.txt', + }, +} + +Error.stackTraceLimit = Error.stackTraceLimit < 30 ? 30 : Error.stackTraceLimit + +const SESSION_STORAGE_BACKUP_KEY = 'benchmark-backup' +export const openBenchmark = async (renderDistance = DEFAULT_RENDER_DISTANCE) => { + let fixtureNameOpen = appQueryParams.openBenchmark + if (!fixtureNameOpen || fixtureNameOpen === '1' || fixtureNameOpen === 'true' || fixtureNameOpen === 'zip') { + fixtureNameOpen = 'default' + } + + + if (sessionStorage.getItem(SESSION_STORAGE_BACKUP_KEY)) { + const backup = JSON.stringify(JSON.parse(sessionStorage.getItem(SESSION_STORAGE_BACKUP_KEY)!), null, 2) + setLoadingScreenStatus('Either other tab with benchmark is open or page crashed. Last data backup is downloaded. Reload page to retry.') + // download file + const a = document.createElement('a') + a.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(backup) + a.download = `benchmark-${appViewer.backend?.id}.txt` + a.click() + sessionStorage.removeItem(SESSION_STORAGE_BACKUP_KEY) + return + } + + const fixture: BenchmarkFixture = appQueryParams.benchmarkMapZipUrl ? { + urlZip: appQueryParams.benchmarkMapZipUrl, + spawn: appQueryParams.benchmarkPosition ? appQueryParams.benchmarkPosition.split(',').map(Number) as [number, number, number] : fixtures.default.spawn, + } : fixtures[fixtureNameOpen] + + if (!fixture) { + setLoadingScreenStatus(`Benchmark fixture ${fixtureNameOpen} not found`) + return + } + + let memoryUsageAverage = 0 + let memoryUsageSamples = 0 + let memoryUsageWorst = 0 + setInterval(() => { + const memoryUsage = (window.performance as any)?.memory?.usedJSHeapSize + if (memoryUsage) { + memoryUsageAverage = (memoryUsageAverage * memoryUsageSamples + memoryUsage) / (memoryUsageSamples + 1) + memoryUsageSamples++ + if (memoryUsage > memoryUsageWorst) { + memoryUsageWorst = memoryUsage + } + } + }, 200) + + let mainThreadFpsAverage = 0 + let mainThreadFpsWorst = undefined as number | undefined + let mainThreadFpsSamples = 0 + let currentPassedFrames = 0 + const mainLoop = () => { + currentPassedFrames++ + requestAnimationFrame(mainLoop) + } + requestAnimationFrame(mainLoop) + setInterval(() => { + mainThreadFpsAverage = (mainThreadFpsAverage * mainThreadFpsSamples + currentPassedFrames) / (mainThreadFpsSamples + 1) + mainThreadFpsSamples++ + if (mainThreadFpsWorst === undefined) { + mainThreadFpsWorst = currentPassedFrames + } else { + mainThreadFpsWorst = Math.min(mainThreadFpsWorst, currentPassedFrames) + } + currentPassedFrames = 0 + }, 1000) + + // todo urlDir fix + let fixtureName = `${fixture.urlZip ?? fixture.urlDir?.join('|') ?? fixture.replayFileUrl ?? 'unknown'}` + if (fixture.spawn) { + fixtureName += ` - ${fixture.spawn.join(' ')}` + } + + fixtureName += ` - ${renderDistance}` + if (process.env.NODE_ENV !== 'development') { // do not delay + setLoadingScreenStatus('Benchmark requested... Getting screen refresh rate') + await new Promise(resolve => { + setTimeout(resolve, 1000) + }) + } + let start = 0 + // interval to backup data in sessionStorage in case of page crash + const saveBackupInterval = setInterval(() => { + if (!window.world) return + const backup = JSON.parse(JSON.stringify(window.benchmarkAdapter)) + backup.timePassed = ((Date.now() - start) / 1000).toFixed(2) + sessionStorage.setItem(SESSION_STORAGE_BACKUP_KEY, JSON.stringify(backup)) + }, 500) + + const screenRefreshRate = await getScreenRefreshRate() + const benchmarkAdapter: BenchmarkAdapterInfo = { + get fixture () { + return fixtureName + }, + get worldLoadTimeSeconds () { + return window.worldLoadTime + }, + get mesherWorkersCount () { + return (window.world as WorldRendererCommon).worldRendererConfig.mesherWorkers + }, + get mesherProcessAvgMs () { + return (window.world as WorldRendererCommon).workersProcessAverageTime + }, + get mesherProcessTotalMs () { + return (window.world as WorldRendererCommon).workersProcessAverageTime * (window.world as WorldRendererCommon).workersProcessAverageTimeCount + }, + get mesherProcessWorstMs () { + return (window.world as WorldRendererCommon).maxWorkersProcessTime + }, + get chunksFullInfo () { + return (window.world as WorldRendererCommon).chunksFullInfo + }, + get averageRenderTimeMs () { + return (window.world as WorldRendererCommon).renderTimeAvg + }, + get worstRenderTimeMs () { + return (window.world as WorldRendererCommon).renderTimeMax + }, + get fpsAveragePrediction () { + const avgRenderTime = (window.world as WorldRendererCommon).renderTimeAvg + return 1000 / avgRenderTime + }, + get fpsWorstPrediction () { + const maxRenderTime = (window.world as WorldRendererCommon).renderTimeMax + return 1000 / maxRenderTime + }, + get fpsAverageReal () { + return `${(window.world as WorldRendererCommon).fpsAverage.toFixed(0)} / ${screenRefreshRate}` + }, + get fpsWorstReal () { + return (window.world as WorldRendererCommon).fpsWorst ?? -1 + }, + get backendInfoReport () { + return (window.world as WorldRendererCommon).backendInfoReport + }, + get fpsAverageMainThread () { + return mainThreadFpsAverage + }, + get fpsWorstMainThread () { + return mainThreadFpsWorst ?? -1 + }, + get memoryUsageAverage () { + return prettyBytes(memoryUsageAverage) + }, + get memoryUsageWorst () { + return prettyBytes(memoryUsageWorst) + }, + get gpuInfo () { + return appViewer.rendererState.renderer + }, + get hardwareConcurrency () { + return navigator.hardwareConcurrency + }, + get userAgent () { + return navigator.userAgent + }, + clientVersion: `${process.env.RELEASE_TAG} ${process.env.BUILD_VERSION} ${process.env.RELEASE_LINK ?? ''}`, + } + window.benchmarkAdapter = benchmarkAdapter + + disabledSettings.value.add('renderDistance') + options.renderDistance = renderDistance + disabledSettings.value.add('renderDebug') + options.renderDebug = 'advanced' + disabledSettings.value.add('waitForChunksRender') + options.waitForChunksRender = false + + void downloadAndOpenMapFromUrl(fixture.urlZip, undefined, fixture.urlDir, fixture.replayFileUrl, { + connectEvents: { + serverCreated () { + if (fixture.spawn) { + localServer!.spawnPoint = new Vec3(...fixture.spawn) + localServer!.on('newPlayer', (player) => { + player.on('dataLoaded', () => { + player.position = new Vec3(...fixture.spawn!) + start = Date.now() + }) + }) + } + }, + } + }) + + document.addEventListener('cypress-world-ready', () => { + clearInterval(saveBackupInterval) + sessionStorage.removeItem(SESSION_STORAGE_BACKUP_KEY) + let stats = getAllInfoLines(window.benchmarkAdapter) + const downloadFile = () => { + // const changedSettings = + + const a = document.createElement('a') + a.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(stats.join('\n')) + a.download = `benchmark-${appViewer.backend?.id}.txt` + a.click() + } + if (appQueryParams.downloadBenchmark) { + downloadFile() + } + + const panel = document.createElement('div') + panel.style.position = 'fixed' + panel.style.top = '20px' + panel.style.right = '10px' + panel.style.backgroundColor = 'rgba(0,0,0,0.8)' + panel.style.color = 'white' + panel.style.padding = '10px' + panel.style.zIndex = '1000' + panel.style.fontFamily = 'monospace' + panel.style.maxWidth = '80%' + panel.style.maxHeight = '90vh' + panel.style.overflow = 'auto' + panel.id = 'benchmark-panel' + + // Add download button + const downloadButton = document.createElement('button') + downloadButton.textContent = 'Download Results' + downloadButton.style.marginBottom = '10px' + downloadButton.style.padding = '5px 10px' + downloadButton.style.backgroundColor = '#4CAF50' + downloadButton.style.color = 'white' + downloadButton.style.border = 'none' + downloadButton.style.borderRadius = '4px' + downloadButton.style.cursor = 'pointer' + downloadButton.onclick = downloadFile + panel.appendChild(downloadButton) + + const pre = document.createElement('pre') + pre.style.whiteSpace = 'pre-wrap' + pre.style.wordBreak = 'break-word' + panel.appendChild(pre) + + pre.textContent = stats.join('\n') + const updateStats = () => { + stats = getAllInfoLines(window.benchmarkAdapter) + pre.textContent = stats.join('\n') + } + + document.body.appendChild(panel) + // setInterval(updateStats, 100) + }) +} + +// add before unload +window.addEventListener('beforeunload', () => { + // remove sessionStorage backup + sessionStorage.removeItem(SESSION_STORAGE_BACKUP_KEY) +}) + +document.addEventListener('pointerlockchange', (e) => { + const panel = document.querySelector('#benchmark-panel') + if (panel) { + panel.hidden = !!document.pointerLockElement + } +}) + +subscribe(activeModalStack, () => { + const panel = document.querySelector('#benchmark-panel') + if (panel && activeModalStack.length > 1) { + panel.hidden = true + } +}) + +export const registerOpenBenchmarkListener = () => { + if (appQueryParams.openBenchmark) { + void openBenchmark(appQueryParams.renderDistance ? +appQueryParams.renderDistance : undefined) + } + + window.addEventListener('keydown', (e) => { + if (e.code === 'KeyB' && e.shiftKey && !miscUiState.gameLoaded && activeModalStack.length === 0) { + e.preventDefault() + // add ?openBenchmark=true to url without reload + const url = new URL(window.location.href) + url.searchParams.set('openBenchmark', 'true') + window.history.replaceState({}, '', url.toString()) + void openBenchmark() + } + }) +} diff --git a/src/benchmarkAdapter.ts b/src/benchmarkAdapter.ts new file mode 100644 index 00000000..e3da6669 --- /dev/null +++ b/src/benchmarkAdapter.ts @@ -0,0 +1,66 @@ +import { noCase } from 'change-case' + +export interface BenchmarkAdapterInfo { + fixture: string + // general load info + worldLoadTimeSeconds: number + + // mesher + mesherWorkersCount: number + mesherProcessAvgMs: number + mesherProcessWorstMs: number + mesherProcessTotalMs: number + chunksFullInfo: string + + // rendering backend + averageRenderTimeMs: number + worstRenderTimeMs: number + fpsAveragePrediction: number + fpsWorstPrediction: number + fpsAverageReal: string + fpsWorstReal: number + backendInfoReport: string + + // main thread + fpsAverageMainThread: number + fpsWorstMainThread: number + + // memory total + memoryUsageAverage: string + memoryUsageWorst: string + + // context info + gpuInfo: string + hardwareConcurrency: number + userAgent: string + clientVersion: string +} + +export const getAllInfo = (adapter: BenchmarkAdapterInfo) => { + return Object.fromEntries( + Object.entries(adapter).map(([key, value]) => { + if (typeof value === 'function') { + value = (value as () => any)() + } + if (typeof value === 'number') { + value = value.toFixed(2) + } + return [noCase(key), value] + }) + ) +} + +export const getAllInfoLines = (adapter: BenchmarkAdapterInfo, delayed = false) => { + const info = getAllInfo(adapter) + if (delayed) { + for (const key in info) { + if (key !== 'fpsAveragePrediction' && key !== 'fpsAverageReal') { + delete info[key] + } + } + } + + return Object.entries(info).map(([key, value]) => { + return `${key}${delayed ? ' (delayed)' : ''}: ${value}` + }) +} diff --git a/src/botUtils.ts b/src/botUtils.ts index 30e13834..10609322 100644 --- a/src/botUtils.ts +++ b/src/botUtils.ts @@ -1,122 +1,49 @@ -// this should actually be moved to mineflayer / prismarine-viewer +import { versionToNumber } from 'renderer/viewer/common/utils' +import * as nbt from 'prismarine-nbt' -import { fromFormattedString, TextComponent } from '@xmcl/text-component' -import type { IndexedData } from 'minecraft-data' - -export type MessageFormatPart = Pick & { - text: string - color?: string - bold?: boolean - italic?: boolean - underlined?: boolean - strikethrough?: boolean - obfuscated?: boolean +export const displayClientChat = (text: string) => { + const message = { + text + } + if (versionToNumber(bot.version) >= versionToNumber('1.19')) { + bot._client.emit('systemChat', { + formattedMessage: JSON.stringify(message), + position: 0, + sender: 'minecraft:chat' + }) + return + } + bot._client.emit('chat', { + message: JSON.stringify(message), + position: 0, + sender: 'minecraft:chat' + }) } -type MessageInput = { - text?: string - translate?: string - with?: Array - color?: string - bold?: boolean - italic?: boolean - underlined?: boolean - strikethrough?: boolean - obfuscated?: boolean - extra?: MessageInput[] - json?: any -} - -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) => { - const styles = { - color: msg.color, - bold: !!msg.bold, - italic: !!msg.italic, - underlined: !!msg.underlined, - strikethrough: !!msg.strikethrough, - obfuscated: !!msg.obfuscated - } - - if (msg.text) { - msglist.push({ - ...msg, - text: msg.text, - ...styles - }) - } else if (msg.translate) { - const tText = mcData?.language[msg.translate] ?? msg.translate - - if (msg.with) { - const splitted = tText.split(/%s|%\d+\$s/g) - - let i = 0 - for (const [j, part] of splitted.entries()) { - msglist.push({ text: part, ...styles }) - - if (j + 1 < splitted.length) { - if (msg.with[i]) { - const msgWith = msg.with[i] - if (typeof msgWith === 'string') { - readMsg({ - ...styles, - text: msgWith - }) - } else { - readMsg({ - ...styles, - ...msgWith - }) - } - } - i++ - } - } - } else { - msglist.push({ - ...msg, - text: tText, - ...styles - }) +export const parseFormattedMessagePacket = (arg) => { + if (typeof arg === 'string') { + try { + arg = JSON.parse(arg) + return { + formatted: arg, + plain: '' } - } - - if (msg.extra) { - for (const ex of msg.extra) { - readMsg({ ...styles, ...ex }) + } catch {} + } + if (typeof arg === 'object') { + try { + return { + formatted: nbt.simplify(arg), + plain: '' + } + } catch (err) { + console.warn('Failed to parse formatted message', arg, err) + return { + plain: JSON.stringify(arg) } } } - - readMsg(message) - - const flat = (msg) => { - return [msg, msg.extra?.flatMap(flat) ?? []] + return { + plain: String(arg) } - - msglist = msglist.map(msg => { - // normalize § - if (!msg.text.includes('§')) return msg - const newMsg = fromFormattedString(msg.text) - return flat(newMsg) - }).flat(Infinity) - - return msglist -} - -const blockToItemRemaps = { - water: 'water_bucket', - lava: 'lava_bucket', - redstone_wire: 'redstone', - tripwire: 'tripwire_hook' -} - -export const getItemFromBlock = (block: import('prismarine-block').Block) => { - const item = global.loadedData.itemsByName[blockToItemRemaps[block.name] ?? block.name] - return item } diff --git a/src/browserfs.ts b/src/browserfs.ts index ebe8acfd..006b6db8 100644 --- a/src/browserfs.ts +++ b/src/browserfs.ts @@ -7,24 +7,50 @@ import * as browserfs from 'browserfs' import { options, resetOptions } from './optionsStorage' import { fsState, loadSave } from './loadSave' -import { installTexturePack, installTexturePackFromHandle, updateTexturePackInstalledState } from './texturePack' +import { installResourcepackPack, installTexturePackFromHandle, updateTexturePackInstalledState } from './resourcePack' import { miscUiState } from './globalState' -import { setLoadingScreenStatus } from './utils' -const { GoogleDriveFileSystem } = require('google-drive-browserfs/src/backends/GoogleDrive') // disable type checking +import { setLoadingScreenStatus } from './appStatus' +import { VALID_REPLAY_EXTENSIONS, openFile } from './packetsReplay/replayPackets' +import { getFixedFilesize } from './downloadAndOpenFile' +import { packetsReplayState } from './react/state/packetsReplayState' +import { createFullScreenProgressReporter } from './core/progressReporter' +import { showNotification } from './react/NotificationProvider' +import { resetAppStorage } from './react/appStorageProvider' +import { ConnectOptions } from './connect' +const { GoogleDriveFileSystem } = require('google-drive-browserfs/src/backends/GoogleDrive') browserfs.install(window) const defaultMountablePoints = { - '/world': { fs: 'LocalStorage' }, // will be removed in future '/data': { fs: 'IndexedDB' }, + '/resourcepack': { fs: 'InMemory' }, // temporary storage for currently loaded resource pack + '/temp': { fs: 'InMemory' } +} +const fallbackMountablePoints = { + '/resourcepack': { fs: 'InMemory' }, // temporary storage for downloaded server resource pack + '/temp': { fs: 'InMemory' } } browserfs.configure({ fs: 'MountableFileSystem', options: defaultMountablePoints, }, async (e) => { - // todo disable singleplayer button - if (e) throw e + if (e) { + browserfs.configure({ + fs: 'MountableFileSystem', + options: fallbackMountablePoints, + }, async (e2) => { + if (e2) { + showNotification('Unknown FS error, cannot continue', e2.message, true) + throw e2 + } + showNotification('Failed to access device storage', `Check you have free space. ${e.message}`, true) + miscUiState.fsReady = true + miscUiState.singleplayerAvailable = false + }) + return + } await updateTexturePackInstalledState() - miscUiState.appLoaded = true + miscUiState.fsReady = true + miscUiState.singleplayerAvailable = true }) export const forceCachedDataPaths = {} @@ -233,10 +259,11 @@ export const mountGoogleDriveFolder = async (readonly: boolean, rootId: string) fsState.isReadonly = readonly fsState.syncFs = false fsState.inMemorySave = false + fsState.remoteBackend = true return true } -export async function removeFileRecursiveAsync (path) { +export async function removeFileRecursiveAsync (path, removeDirectoryItself = true) { const errors = [] as Array<[string, Error]> try { const files = await fs.promises.readdir(path) @@ -255,7 +282,9 @@ export async function removeFileRecursiveAsync (path) { })) // After removing all files/directories, remove the current directory - await fs.promises.rmdir(path) + if (removeDirectoryItself) { + await fs.promises.rmdir(path) + } } catch (error) { errors.push([path, error]) } @@ -313,6 +342,7 @@ export const openWorldDirectory = async (dragndropHandle?: FileSystemDirectoryHa fsState.isReadonly = !writeAccess fsState.syncFs = false fsState.inMemorySave = false + fsState.remoteBackend = false await loadSave() } @@ -352,7 +382,33 @@ export const possiblyCleanHandle = (callback = () => { }) => { } } -export const copyFilesAsyncWithProgress = async (pathSrc: string, pathDest: string, throwRootNotExist = true) => { +const readdirSafe = async (path: string) => { + try { + return await fs.promises.readdir(path) + } catch (err) { + return null + } +} + +export const collectFilesToCopy = async (basePath: string, safe = false): Promise => { + const result: string[] = [] + const countFiles = async (relPath: string) => { + const resolvedPath = join(basePath, relPath) + const files = relPath === '.' && !safe ? await fs.promises.readdir(resolvedPath) : await readdirSafe(resolvedPath) + if (!files) return null + await Promise.all(files.map(async file => { + const res = await countFiles(join(relPath, file)) + if (res === null) { + // is file + result.push(join(relPath, file)) + } + })) + } + await countFiles('.') + return result +} + +export const copyFilesAsyncWithProgress = async (pathSrc: string, pathDest: string, throwRootNotExist = true, addMsg = '') => { const stat = await existsViaStats(pathSrc) if (!stat) { if (throwRootNotExist) throw new Error(`Cannot copy. Source directory ${pathSrc} does not exist`) @@ -360,7 +416,7 @@ export const copyFilesAsyncWithProgress = async (pathSrc: string, pathDest: stri return } if (!stat.isDirectory()) { - await fs.promises.writeFile(pathDest, await fs.promises.readFile(pathSrc)) + await fs.promises.writeFile(pathDest, await fs.promises.readFile(pathSrc) as any) console.debug('copied single file', pathSrc, pathDest) return } @@ -387,7 +443,7 @@ export const copyFilesAsyncWithProgress = async (pathSrc: string, pathDest: stri let copied = 0 await copyFilesAsync(pathSrc, pathDest, (name) => { copied++ - setLoadingScreenStatus(`Copying files (${copied}/${filesCount}): ${name}`) + setLoadingScreenStatus(`Copying files${addMsg} (${copied}/${filesCount}): ${name}`) }) } finally { setLoadingScreenStatus(undefined) @@ -402,6 +458,19 @@ export const existsViaStats = async (path: string) => { } } +export const fileExistsAsyncOptimized = async (path: string) => { + try { + await fs.promises.readdir(path) + } catch (err) { + if (err.code === 'ENOTDIR') return true + // eslint-disable-next-line sonarjs/prefer-single-boolean-return + if (err.code === 'ENOENT') return false + // throw err + return false + } + return true +} + export const copyFilesAsync = async (pathSrc: string, pathDest: string, fileCopied?: (name) => void) => { // query: can't use fs.copy! use fs.promises.writeFile and readFile const files = await fs.promises.readdir(pathSrc) @@ -422,7 +491,7 @@ export const copyFilesAsync = async (pathSrc: string, pathDest: string, fileCopi } else { // Copy file try { - await fs.promises.writeFile(curPathDest, await fs.promises.readFile(curPathSrc)) + await fs.promises.writeFile(curPathDest, await fs.promises.readFile(curPathSrc) as any) console.debug('copied file', curPathSrc, curPathDest) } catch (err) { console.error('Error copying file', curPathSrc, curPathDest, err) @@ -433,8 +502,66 @@ export const copyFilesAsync = async (pathSrc: string, pathDest: string, fileCopi })) } +export const openWorldFromHttpDir = async (fileDescriptorUrls: string[]/* | undefined */, baseUrlParam) => { + // todo try go guess mode + let index + let baseUrl + for (const url of fileDescriptorUrls) { + let file + try { + setLoadingScreenStatus(`Trying to get world descriptor from ${new URL(url).host}`) + const controller = new AbortController() + setTimeout(() => { + controller.abort() + }, 3000) + // eslint-disable-next-line no-await-in-loop + const response = await fetch(url, { signal: controller.signal }) + // eslint-disable-next-line no-await-in-loop + file = await response.json() + } catch (err) { + console.error('Error fetching file descriptor', url, err) + } + if (!file) continue + if (file.baseUrl) { + baseUrl = new URL(file.baseUrl, baseUrl).toString() + index = file.index + } else { + index = file + baseUrl = baseUrlParam ?? url.split('/').slice(0, -1).join('/') + } + break + } + if (!index) throw new Error(`The provided mapDir file is not valid descriptor file! ${fileDescriptorUrls.join(', ')}`) + await new Promise(async resolve => { + browserfs.configure({ + fs: 'MountableFileSystem', + options: { + ...defaultMountablePoints, + '/world': { + fs: 'HTTPRequest', + options: { + index, + baseUrl + } + } + }, + }, (e) => { + if (e) throw e + resolve() + }) + }) + + fsState.saveLoaded = false + fsState.isReadonly = true + fsState.syncFs = false + fsState.inMemorySave = false + fsState.remoteBackend = true + + await loadSave() +} + // todo rename method -const openWorldZipInner = async (file: File | ArrayBuffer, name = file['name']) => { +const openWorldZipInner = async (file: File | ArrayBuffer, name = file['name'], connectOptions?: Partial) => { await new Promise(async resolve => { browserfs.configure({ // todo @@ -459,6 +586,7 @@ const openWorldZipInner = async (file: File | ArrayBuffer, name = file['name']) fsState.isReadonly = true fsState.syncFs = true fsState.inMemorySave = false + fsState.remoteBackend = false if (fs.existsSync('/world/level.dat')) { await loadSave() @@ -478,7 +606,7 @@ const openWorldZipInner = async (file: File | ArrayBuffer, name = file['name']) } if (availableWorlds.length === 1) { - await loadSave(`/world/${availableWorlds[0]}`) + await loadSave(`/world/${availableWorlds[0]}`, connectOptions) return } @@ -496,44 +624,46 @@ export const openWorldZip = async (...args: Parameters } } -export const resetLocalStorageWorld = () => { - for (const key of Object.keys(localStorage)) { - if (/^[\da-fA-F]{8}(?:\b-[\da-fA-F]{4}){3}\b-[\da-fA-F]{12}$/g.test(key) || key === '/') { - localStorage.removeItem(key) - } - } -} - -export const resetLocalStorageWithoutWorld = () => { - for (const key of Object.keys(localStorage)) { - if (!/^[\da-fA-F]{8}(?:\b-[\da-fA-F]{4}){3}\b-[\da-fA-F]{12}$/g.test(key) && key !== '/') { - localStorage.removeItem(key) - } - } +export const resetLocalStorage = () => { resetOptions() + resetAppStorage() } -window.resetLocalStorageWorld = resetLocalStorageWorld +window.resetLocalStorage = resetLocalStorage + export const openFilePicker = (specificCase?: 'resourcepack') => { // create and show input picker let picker: HTMLInputElement = document.body.querySelector('input#file-zip-picker')! if (!picker) { picker = document.createElement('input') picker.type = 'file' - picker.accept = '.zip' + picker.accept = specificCase ? '.zip' : [...VALID_REPLAY_EXTENSIONS, '.zip'].join(',') picker.addEventListener('change', () => { const file = picker.files?.[0] picker.value = '' if (!file) return - if (!file.name.endsWith('.zip')) { - const doContinue = confirm(`Are you sure ${file.name.slice(-20)} is .zip file? Only .zip files are supported. Continue?`) - if (!doContinue) return - } if (specificCase === 'resourcepack') { - void installTexturePack(file) + if (!file.name.endsWith('.zip')) { + const doContinue = confirm(`Are you sure ${file.name.slice(-20)} is .zip file? ONLY .zip files are supported. Continue?`) + if (!doContinue) return + } + void installResourcepackPack(file, createFullScreenProgressReporter()).catch((err) => { + setLoadingScreenStatus(err.message, true) + }) } else { - void openWorldZip(file) + // eslint-disable-next-line no-lonely-if + if (VALID_REPLAY_EXTENSIONS.some(ext => file.name.endsWith(ext)) || file.name.startsWith('packets-replay')) { + void file.text().then(contents => { + openFile({ + contents, + filename: file.name, + filesize: file.size + }) + }) + } else { + void openWorldZip(file) + } } }) picker.hidden = true diff --git a/src/builtinCommands.ts b/src/builtinCommands.ts index e68daa03..a292c5cd 100644 --- a/src/builtinCommands.ts +++ b/src/builtinCommands.ts @@ -1,11 +1,14 @@ import fs from 'fs' import { join } from 'path' import JSZip from 'jszip' -import { readLevelDat } from './loadSave' +import { getThreeJsRendererMethods } from 'renderer/viewer/three/threeJsMethods' +import { fsState, readLevelDat } from './loadSave' import { closeWan, openToWanAndCopyJoinLink } from './localServerMultiplayer' import { copyFilesAsync, uniqueFileNameFromWorldName } from './browserfs' import { saveServer } from './flyingSquidUtils' -import { setLoadingScreenStatus } from './utils' +import { setLoadingScreenStatus } from './appStatus' +import { displayClientChat } from './botUtils' +import { miscUiState } from './globalState' const notImplemented = () => { return 'Not implemented yet' @@ -67,7 +70,7 @@ export const exportWorld = async (path: string, type: 'zip' | 'folder', zipName // todo include in help const exportLoadedWorld = async () => { await saveServer() - let { worldFolder } = localServer!.options + let worldFolder = fsState.inMemorySavePath if (!worldFolder.startsWith('/')) worldFolder = `/${worldFolder}` await exportWorld(worldFolder, 'zip') } @@ -75,14 +78,13 @@ const exportLoadedWorld = async () => { window.exportWorld = exportLoadedWorld const writeText = (text) => { - bot._client.emit('chat', { - message: JSON.stringify({ text }) - }) + displayClientChat(text) } -const commands: Array<{ +export const commands: Array<{ command: string[], - invoke (): Promise | void + alwaysAvailable?: boolean, + invoke (args: string[]): Promise | void //@ts-format-ignore-region }> = [ { @@ -107,19 +109,47 @@ const commands: Array<{ command: ['/save'], async invoke () { await saveServer(false) + writeText('Saved to browser memory') + } + }, + { + command: ['/pos'], + alwaysAvailable: true, + async invoke ([type]) { + let pos: { x: number, y: number, z: number } | undefined + if (type === 'block') { + const blockPos = window.cursorBlockRel()?.position + if (blockPos) { + pos = { x: blockPos.x, y: blockPos.y, z: blockPos.z } + } + } else { + const playerPos = bot.entity.position + pos = { x: playerPos.x, y: playerPos.y, z: playerPos.z } + } + if (!pos) return + const formatted = `${pos.x.toFixed(2)} ${pos.y.toFixed(2)} ${pos.z.toFixed(2)}` + await navigator.clipboard.writeText(formatted) + writeText(`Copied position to clipboard: ${formatted}`) + } + }, + { + command: ['/mesherlog'], + alwaysAvailable: true, + invoke () { + getThreeJsRendererMethods()?.downloadMesherLog() } } ] //@ts-format-ignore-endregion -export const getBuiltinCommandsList = () => commands.flatMap(command => command.command) +export const getBuiltinCommandsList = () => commands.filter(command => command.alwaysAvailable || miscUiState.singleplayer).flatMap(command => command.command) -export const tryHandleBuiltinCommand = (message) => { - if (!localServer) return +export const tryHandleBuiltinCommand = (message: string) => { + const [userCommand, ...args] = message.split(' ') - for (const command of commands) { - if (command.command.includes(message)) { - void command.invoke() // ignoring for now + for (const command of commands.filter(command => command.alwaysAvailable || miscUiState.singleplayer)) { + if (command.command.includes(userCommand)) { + void command.invoke(args) // ignoring for now return true } } diff --git a/src/cameraRotationControls.ts b/src/cameraRotationControls.ts new file mode 100644 index 00000000..679a3a44 --- /dev/null +++ b/src/cameraRotationControls.ts @@ -0,0 +1,83 @@ +import { contro } from './controls' +import { activeModalStack, isGameActive, miscUiState, showModal } from './globalState' +import { options } from './optionsStorage' +import { hideNotification, notificationProxy } from './react/NotificationProvider' +import { pointerLock } from './utils' +import { updateMotion, initMotionTracking } from './react/uiMotion' + +let lastMouseMove: number + +export type CameraMoveEvent = { + movementX: number + movementY: number + type: string + stopPropagation?: () => void +} + +export function onCameraMove (e: MouseEvent | CameraMoveEvent) { + if (!isGameActive(true)) return + if (e.type === 'mousemove' && !document.pointerLockElement) return + e.stopPropagation?.() + if (appViewer.playerState.utils.isSpectatingEntity()) return + const now = performance.now() + // todo: limit camera movement for now to avoid unexpected jumps + if (now - lastMouseMove < 4 && !options.preciseMouseInput) return + lastMouseMove = now + let { mouseSensX, mouseSensY } = options + if (mouseSensY === -1) mouseSensY = mouseSensX + moveCameraRawHandler({ + x: e.movementX * mouseSensX * 0.0001, + y: e.movementY * mouseSensY * 0.0001 + }) + bot.mouse.update() + updateMotion() +} + +export const moveCameraRawHandler = ({ x, y }: { x: number; y: number }) => { + const maxPitch = 0.5 * Math.PI + const minPitch = -0.5 * Math.PI + + appViewer.lastCamUpdate = Date.now() + + // if (viewer.world.freeFlyMode) { + // // Update freeFlyState directly + // viewer.world.freeFlyState.yaw = (viewer.world.freeFlyState.yaw - x) % (2 * Math.PI) + // viewer.world.freeFlyState.pitch = Math.max(minPitch, Math.min(maxPitch, viewer.world.freeFlyState.pitch - y)) + // return + // } + + if (!bot?.entity) return + const pitch = bot.entity.pitch - y + void bot.look(bot.entity.yaw - x, Math.max(minPitch, Math.min(maxPitch, pitch)), true) + appViewer.backend?.updateCamera(null, bot.entity.yaw, pitch) +} + +window.addEventListener('mousemove', (e: MouseEvent) => { + onCameraMove(e) +}, { capture: true }) + +export const onControInit = () => { + contro.on('stickMovement', ({ stick, vector }) => { + if (!isGameActive(true)) return + if (stick !== 'right') return + let { x, z } = vector + if (Math.abs(x) < 0.18) x = 0 + if (Math.abs(z) < 0.18) z = 0 + onCameraMove({ + movementX: x * 10, + movementY: z * 10, + type: 'stickMovement', + stopPropagation () {} + } as CameraMoveEvent) + miscUiState.usingGamepadInput = true + }) +} + +function pointerLockChangeCallback () { + if (appViewer.rendererState.preventEscapeMenu) return + if (!pointerLock.hasPointerLock && activeModalStack.length === 0 && miscUiState.gameLoaded) { + showModal({ reactType: 'pause-screen' }) + } +} + +document.addEventListener('pointerlockchange', pointerLockChangeCallback, false) diff --git a/src/botUtils.test.ts b/src/chatUtils.test.ts similarity index 66% rename from src/botUtils.test.ts rename to src/chatUtils.test.ts index 99aa07b4..6d683919 100644 --- a/src/botUtils.test.ts +++ b/src/chatUtils.test.ts @@ -1,6 +1,6 @@ import { test, expect } from 'vitest' import mcData from 'minecraft-data' -import { formatMessage } from './botUtils' +import { formatMessage, isAllowedChatCharacter, isStringAllowed } from './chatUtils' //@ts-expect-error globalThis.loadedData ??= mcData('1.20.1') @@ -64,3 +64,21 @@ test('formatMessage', () => { ] `) }) + +test('isAllowedChatCharacter', () => { + expect(isAllowedChatCharacter('a')).toBe(true) + expect(isAllowedChatCharacter('a')).toBe(true) + expect(isAllowedChatCharacter('§')).toBe(false) + expect(isAllowedChatCharacter(' ')).toBe(true) + expect(isStringAllowed('a§b')).toMatchObject({ + valid: false, + clean: 'ab', + invalid: ['§'] + }) + expect(isStringAllowed('aツ')).toMatchObject({ + valid: true, + }) + expect(isStringAllowed('a🟢')).toMatchObject({ + valid: true, + }) +}) diff --git a/src/chatUtils.ts b/src/chatUtils.ts new file mode 100644 index 00000000..849d5847 --- /dev/null +++ b/src/chatUtils.ts @@ -0,0 +1,173 @@ +// this should actually be moved to mineflayer / renderer + +import { fromFormattedString, TextComponent } from '@xmcl/text-component' +import type { IndexedData } from 'minecraft-data' +import { versionToNumber } from 'renderer/viewer/common/utils' + +export interface MessageFormatOptions { + doShadow?: boolean +} + +export type MessageFormatPart = Pick & { + text: string + color?: string + bold?: boolean + italic?: boolean + underlined?: boolean + strikethrough?: boolean + obfuscated?: boolean +} + +type MessageInput = { + text?: string + translate?: string + with?: Array + color?: string + bold?: boolean + italic?: boolean + underlined?: boolean + strikethrough?: boolean + obfuscated?: boolean + extra?: MessageInput[] + json?: any +} + +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) => { + const styles = { + color: msg.color, + bold: !!msg.bold, + italic: !!msg.italic, + underlined: !!msg.underlined, + strikethrough: !!msg.strikethrough, + obfuscated: !!msg.obfuscated + } + + if (!msg.text && typeof msg.json?.[''] === 'string') msg.text = msg.json[''] + if (msg.text) { + msglist.push({ + ...msg, + text: msg.text, + ...styles + }) + } else if (msg.translate) { + const tText = mcData?.language[msg.translate] ?? msg.translate + + if (msg.with) { + const splitted = tText.split(/%s|%\d+\$s/g) + + let i = 0 + for (const [j, part] of splitted.entries()) { + msglist.push({ text: part, ...styles }) + + if (j + 1 < splitted.length) { + if (msg.with[i]) { + const msgWith = msg.with[i] + if (typeof msgWith === 'string') { + readMsg({ + ...styles, + text: msgWith + }) + } else { + readMsg({ + ...styles, + ...msgWith + }) + } + } + i++ + } + } + } else { + msglist.push({ + ...msg, + text: tText, + ...styles + }) + } + } + + if (msg.extra) { + for (let ex of msg.extra) { + if (typeof ex === 'string') { + ex = { text: ex } + } + readMsg({ ...styles, ...ex }) + } + } + } + + readMsg(message) + + const flat = (msg) => { + return [msg, msg.extra?.flatMap(flat) ?? []] + } + + msglist = msglist.map(msg => { + // normalize § + if (!msg.text.includes?.('§')) return msg + const newMsg = fromFormattedString(msg.text) + return flat(newMsg) + }).flat(Infinity) + + return msglist +} + +export const messageToString = (message: MessageInput | string) => { + if (typeof message === 'string') { + return message + } + const msglist = formatMessage(message) + return msglist.map(msg => msg.text).join('') +} + +const blockToItemRemaps = { + water: 'water_bucket', + lava: 'lava_bucket', + redstone_wire: 'redstone', + tripwire: 'tripwire_hook' +} + +export const getItemFromBlock = (block: import('prismarine-block').Block) => { + const item = global.loadedData.itemsByName[blockToItemRemaps[block.name] ?? block.name] + return item +} + +export function isAllowedChatCharacter (char: string): boolean { + // if (char.length !== 1) { + // throw new Error('Input must be a single character') + // } + + const charCode = char.codePointAt(0)! + return charCode !== 167 && charCode >= 32 && charCode !== 127 +} + +export const isStringAllowed = (str: string) => { + const invalidChars = new Set() + for (const [i, char] of [...str].entries()) { + const isSurrogatePair = str.codePointAt(i) !== str['charCodeAt'](i) + if (isSurrogatePair) continue + + if (!isAllowedChatCharacter(char)) { + invalidChars.add(char) + } + } + + const valid = invalidChars.size === 0 + if (valid) { + return { + valid: true + } + } + + return { + valid, + clean: [...str].filter(c => !invalidChars.has(c)).join(''), + invalid: [...invalidChars] + } +} diff --git a/src/clientMods.ts b/src/clientMods.ts new file mode 100644 index 00000000..204a5861 --- /dev/null +++ b/src/clientMods.ts @@ -0,0 +1,637 @@ +/* eslint-disable no-await-in-loop */ +import { openDB } from 'idb' +import * as React from 'react' +import * as valtio from 'valtio' +import * as valtioUtils from 'valtio/utils' +import { gt } from 'semver' +import { proxy } from 'valtio' +import { options } from './optionsStorage' +import { appStorage } from './react/appStorageProvider' +import { showInputsModal, showOptionsModal } from './react/SelectOption' +import { ProgressReporter } from './core/progressReporter' +import { showNotification } from './react/NotificationProvider' + +let sillyProtection = false +const protectRuntime = () => { + if (sillyProtection) return + sillyProtection = true + const sensetiveKeys = new Set(['authenticatedAccounts', 'serversList', 'username']) + const proxy = new Proxy(window.localStorage, { + get (target, prop) { + if (typeof prop === 'string') { + if (sensetiveKeys.has(prop)) { + console.warn(`Access to sensitive key "${prop}" was blocked`) + return null + } + if (prop === 'getItem') { + return (key: string) => { + if (sensetiveKeys.has(key)) { + console.warn(`Access to sensitive key "${key}" via getItem was blocked`) + return null + } + return target.getItem(key) + } + } + if (prop === 'setItem') { + return (key: string, value: string) => { + if (sensetiveKeys.has(key)) { + console.warn(`Attempt to set sensitive key "${key}" via setItem was blocked`) + return + } + target.setItem(key, value) + } + } + if (prop === 'removeItem') { + return (key: string) => { + if (sensetiveKeys.has(key)) { + console.warn(`Attempt to delete sensitive key "${key}" via removeItem was blocked`) + return + } + target.removeItem(key) + } + } + if (prop === 'clear') { + console.warn('Attempt to clear localStorage was blocked') + return () => {} + } + } + return Reflect.get(target, prop) + }, + set (target, prop, value) { + if (typeof prop === 'string' && sensetiveKeys.has(prop)) { + console.warn(`Attempt to set sensitive key "${prop}" was blocked`) + return false + } + return Reflect.set(target, prop, value) + }, + deleteProperty (target, prop) { + if (typeof prop === 'string' && sensetiveKeys.has(prop)) { + console.warn(`Attempt to delete sensitive key "${prop}" was blocked`) + return false + } + return Reflect.deleteProperty(target, prop) + } + }) + Object.defineProperty(window, 'localStorage', { + value: proxy, + writable: false, + configurable: false, + }) +} + +// #region Database +const dbPromise = openDB('mods-db', 1, { + upgrade (db) { + db.createObjectStore('mods', { + keyPath: 'name', + }) + db.createObjectStore('repositories', { + keyPath: 'url', + }) + }, +}) + +export interface ModSetting { + label?: string + type: 'toggle' | 'choice' | 'input' | 'slider' + hidden?: boolean + values?: string[] + inputType?: string + hint?: string + default?: any +} + +export interface ModSettingsDict { + [settingId: string]: ModSetting +} + +export interface ModAction { + method?: string + label?: string + /** @default false */ + gameGlobal?: boolean + /** @default false */ + onlyForeground?: boolean +} + +// mcraft-repo.json +export interface McraftRepoFile { + packages: ClientModDefinition[] + /** @default true */ + prefix?: string | boolean + name?: string // display name + description?: string + mirrorUrls?: string[] + autoUpdateOverride?: boolean + lastUpdated?: number +} +export interface Repository extends McraftRepoFile { + url: string +} + +export interface ClientMod { + name: string; // unique identifier like owner.name + version: string + enabled?: boolean + + scriptMainUnstable?: string; + serverPlugin?: string + // serverPlugins?: string[] + // mesherThread?: string + stylesGlobal?: string + threeJsBackend?: string // three.js + // stylesLocal?: string + + requiresNetwork?: boolean + fullyOffline?: boolean + description?: string + author?: string + section?: string + autoUpdateOverride?: boolean + lastUpdated?: number + wasModifiedLocally?: boolean + // todo depends, hashsum + + settings?: ModSettingsDict + actionsMain?: Record +} + +const cleanupFetchedModData = (mod: ClientModDefinition | Record) => { + delete mod['enabled'] + delete mod['repo'] + delete mod['autoUpdateOverride'] + delete mod['lastUpdated'] + delete mod['wasModifiedLocally'] + return mod +} + +export type ClientModDefinition = Omit & { + scriptMainUnstable?: boolean + stylesGlobal?: boolean + serverPlugin?: boolean + threeJsBackend?: boolean +} + +export async function saveClientModData (data: ClientMod) { + const db = await dbPromise + data.lastUpdated = Date.now() + await db.put('mods', data) + modsReactiveUpdater.counter++ +} + +async function getPlugin (name: string) { + const db = await dbPromise + return db.get('mods', name) as Promise +} + +export async function getAllMods () { + const db = await dbPromise + return db.getAll('mods') as Promise +} + +async function deletePlugin (name) { + const db = await dbPromise + await db.delete('mods', name) + modsReactiveUpdater.counter++ +} + +async function removeAllMods () { + const db = await dbPromise + await db.clear('mods') + modsReactiveUpdater.counter++ +} + +// --- + +async function saveRepository (data: Repository) { + const db = await dbPromise + data.lastUpdated = Date.now() + await db.put('repositories', data) +} + +async function getRepository (url: string) { + const db = await dbPromise + return db.get('repositories', url) as Promise +} + +async function getAllRepositories () { + const db = await dbPromise + return db.getAll('repositories') as Promise +} +window.getAllRepositories = getAllRepositories + +async function deleteRepository (url) { + const db = await dbPromise + await db.delete('repositories', url) +} + +// --- + +// #endregion + +window.mcraft = { + version: process.env.RELEASE_TAG, + build: process.env.BUILD_VERSION, + ui: {}, + React, + valtio: { + ...valtio, + ...valtioUtils, + }, + // openDB +} + +const activateMod = async (mod: ClientMod, reason: string) => { + if (mod.enabled === false) return false + protectRuntime() + console.debug(`Activating mod ${mod.name} (${reason})...`) + window.loadedMods ??= {} + if (window.loadedMods[mod.name]) { + console.warn(`Mod is ${mod.name} already loaded, skipping activation...`) + return false + } + if (mod.stylesGlobal) { + const style = document.createElement('style') + style.textContent = mod.stylesGlobal + style.id = `mod-${mod.name}` + document.head.appendChild(style) + } + if (mod.scriptMainUnstable) { + const blob = new Blob([mod.scriptMainUnstable], { type: 'text/javascript' }) + const url = URL.createObjectURL(blob) + // eslint-disable-next-line no-useless-catch + try { + const module = await import(/* webpackIgnore: true */ url) + module.default?.(structuredClone(mod), { settings: getModSettingsProxy(mod) }) + window.loadedMods[mod.name] ??= {} + window.loadedMods[mod.name].mainUnstableModule = module + } catch (e) { + throw e + } + URL.revokeObjectURL(url) + } + if (mod.threeJsBackend) { + const blob = new Blob([mod.threeJsBackend], { type: 'text/javascript' }) + const url = URL.createObjectURL(blob) + // eslint-disable-next-line no-useless-catch + try { + const module = await import(/* webpackIgnore: true */ url) + // todo + window.loadedMods[mod.name] ??= {} + // for accessing global world var + window.loadedMods[mod.name].threeJsBackendModule = module + } catch (e) { + throw e + } + URL.revokeObjectURL(url) + } + mod.enabled = true + return true +} + +export const appStartup = async () => { + void checkModsUpdates() + + const mods = await getAllMods() + for (const mod of mods) { + await activateMod(mod, 'autostart').catch(e => { + modsErrors[mod.name] ??= [] + modsErrors[mod.name].push(`startup: ${String(e)}`) + console.error(`Error activating mod on startup ${mod.name}:`, e) + }) + } +} + +export const modsUpdateStatus = proxy({} as Record) +export const modsWaitingReloadStatus = proxy({} as Record) +export const modsErrors = proxy({} as Record) + +const normalizeRepoUrl = (url: string) => { + if (url.startsWith('https://')) return url + if (url.startsWith('http://')) return url + if (url.startsWith('//')) return `https:${url}` + return `https://raw.githubusercontent.com/${url}/master` +} + +const installOrUpdateMod = async (repo: Repository, mod: ClientModDefinition, activate = true, progress?: ProgressReporter) => { + // eslint-disable-next-line no-useless-catch + try { + const fetchData = async (urls: string[]) => { + const errored = [] as string[] + // eslint-disable-next-line no-unreachable-loop + for (const urlTemplate of urls) { + const modNameOnly = mod.name.split('.').pop() + const modFolder = repo.prefix === false ? modNameOnly : typeof repo.prefix === 'string' ? `${repo.prefix}/${modNameOnly}` : mod.name + const url = new URL(`${modFolder}/${urlTemplate}`, normalizeRepoUrl(repo.url).replace(/\/$/, '') + '/').href + // eslint-disable-next-line no-useless-catch + try { + const response = await fetch(url) + if (!response.ok) throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`) + return await response.text() + } catch (e) { + // errored.push(String(e)) + throw e + } + } + console.warn(`[${mod.name}] Error installing component of ${urls[0]}: ${errored.join(', ')}`) + return undefined + } + if (mod.stylesGlobal) { + await progress?.executeWithMessage( + `Downloading ${mod.name} styles`, + async () => { + mod.stylesGlobal = await fetchData(['global.css']) as any + } + ) + } + if (mod.scriptMainUnstable) { + await progress?.executeWithMessage( + `Downloading ${mod.name} script`, + async () => { + mod.scriptMainUnstable = await fetchData(['mainUnstable.js']) as any + } + ) + } + if (mod.threeJsBackend) { + await progress?.executeWithMessage( + `Downloading ${mod.name} three.js backend`, + async () => { + mod.threeJsBackend = await fetchData(['three.js']) as any + } + ) + } + if (mod.serverPlugin) { + if (mod.name.endsWith('.disabled')) throw new Error(`Mod name ${mod.name} can't end with .disabled`) + await progress?.executeWithMessage( + `Downloading ${mod.name} server plugin`, + async () => { + mod.serverPlugin = await fetchData(['serverPlugin.js']) as any + } + ) + } + if (activate) { + // todo try to de-activate mod if it's already loaded + if (window.loadedMods?.[mod.name]) { + modsWaitingReloadStatus[mod.name] = true + } else { + await activateMod(mod as ClientMod, 'install') + } + } + await saveClientModData(mod as ClientMod) + delete modsUpdateStatus[mod.name] + } catch (e) { + // console.error(`Error installing mod ${mod.name}:`, e) + throw e + } +} + +const checkRepositoryUpdates = async (repo: Repository) => { + for (const mod of repo.packages) { + + const modExisting = await getPlugin(mod.name) + if (modExisting?.version && gt(mod.version, modExisting.version)) { + modsUpdateStatus[mod.name] = [modExisting.version, mod.version] + if (options.modsAutoUpdate === 'always' && (!repo.autoUpdateOverride && !modExisting.autoUpdateOverride)) { + void installOrUpdateMod(repo, mod).catch(e => { + console.error(`Error updating mod ${mod.name}:`, e) + }) + } + } + } + +} + +export const fetchRepository = async (urlOriginal: string, url: string, hasMirrors = false) => { + const fetchUrl = normalizeRepoUrl(url).replace(/\/$/, '') + '/mcraft-repo.json' + try { + const response = await fetch(fetchUrl).then(async res => res.json()) + if (!response.packages) throw new Error(`No packages field in the response json of the repository: ${fetchUrl}`) + response.autoUpdateOverride = (await getRepository(urlOriginal))?.autoUpdateOverride + response.url = urlOriginal + void saveRepository(response) + modsReactiveUpdater.counter++ + return true + } catch (e) { + console.warn(`Error fetching repository (trying other mirrors) ${url}:`, e) + return false + } +} + +export const fetchAllRepositories = async () => { + const repositories = await getAllRepositories() + await Promise.all(repositories.map(async (repo) => { + const allUrls = [repo.url, ...(repo.mirrorUrls || [])] + for (const [i, url] of allUrls.entries()) { + const isLast = i === allUrls.length - 1 + + if (await fetchRepository(repo.url, url, !isLast)) break + } + })) + appStorage.modsAutoUpdateLastCheck = Date.now() +} + +const checkModsUpdates = async () => { + await autoRefreshModRepositories() + for (const repo of await getAllRepositories()) { + + await checkRepositoryUpdates(repo) + } +} + +const autoRefreshModRepositories = async () => { + if (options.modsAutoUpdate === 'never') return + const lastCheck = appStorage.modsAutoUpdateLastCheck + if (lastCheck && Date.now() - lastCheck < 1000 * 60 * 60 * options.modsUpdatePeriodCheck) return + await fetchAllRepositories() + // todo think of not updating check timestamp on offline access +} + +export const installModByName = async (repoUrl: string, name: string, progress?: ProgressReporter) => { + progress?.beginStage('main', `Installing ${name}`) + const repo = await getRepository(repoUrl) + if (!repo) throw new Error(`Repository ${repoUrl} not found`) + const mod = repo.packages.find(m => m.name === name) + if (!mod) throw new Error(`Mod ${name} not found in repository ${repoUrl}`) + await installOrUpdateMod(repo, mod, undefined, progress) + progress?.endStage('main') +} + +export const uninstallModAction = async (name: string) => { + const choice = await showOptionsModal(`Uninstall mod ${name}?`, ['Yes']) + if (!choice) return + await deletePlugin(name) + window.loadedMods ??= {} + if (window.loadedMods[name]) { + // window.loadedMods[name].default?.(null) + delete window.loadedMods[name] + modsWaitingReloadStatus[name] = true + } + // Clear any errors associated with the mod + delete modsErrors[name] +} + +export const setEnabledModAction = async (name: string, newEnabled: boolean) => { + const mod = await getPlugin(name) + if (!mod) throw new Error(`Mod ${name} not found`) + if (newEnabled) { + mod.enabled = true + if (!window.loadedMods?.[mod.name]) { + await activateMod(mod, 'manual') + } + } else { + // todo deactivate mod + mod.enabled = false + if (window.loadedMods?.[mod.name]) { + if (window.loadedMods[mod.name]?.threeJsBackendModule) { + window.loadedMods[mod.name].threeJsBackendModule.deactivate() + delete window.loadedMods[mod.name].threeJsBackendModule + } + if (window.loadedMods[mod.name]?.mainUnstableModule) { + window.loadedMods[mod.name].mainUnstableModule.deactivate() + delete window.loadedMods[mod.name].mainUnstableModule + } + + if (Object.keys(window.loadedMods[mod.name]).length === 0) { + delete window.loadedMods[mod.name] + } + } + } + await saveClientModData(mod) +} + +export const modsReactiveUpdater = proxy({ + counter: 0 +}) + +export const getAllModsDisplayList = async () => { + const repos = await getAllRepositories() + const installedMods = await getAllMods() + const modsWithoutRepos = installedMods.filter(mod => !repos.some(repo => repo.packages.some(m => m.name === mod.name))) + const mapMods = (mapMods: ClientMod[]) => mapMods.map(mod => ({ + ...mod, + installed: installedMods.find(m => m.name === mod.name), + activated: !!window.loadedMods?.[mod.name], + installedVersion: installedMods.find(m => m.name === mod.name)?.version, + canBeActivated: mod.scriptMainUnstable || mod.stylesGlobal, + })) + return { + repos: repos.map(repo => ({ + ...repo, + packages: mapMods(repo.packages as ClientMod[]), + })), + modsWithoutRepos: mapMods(modsWithoutRepos), + } +} + +export const removeRepositoryAction = async (url: string) => { + // todo remove mods + const choice = await showOptionsModal('Remove repository? Installed mods wont be automatically removed.', ['Yes']) + if (!choice) return + await deleteRepository(url) + modsReactiveUpdater.counter++ +} + +export const selectAndRemoveRepository = async () => { + const repos = await getAllRepositories() + const choice = await showOptionsModal('Select repository to remove', repos.map(repo => repo.url)) + if (!choice) return + await removeRepositoryAction(choice) +} + +export const addRepositoryAction = async () => { + const { url } = await showInputsModal('Add repository', { + url: { + type: 'text', + label: 'Repository URL or slug', + placeholder: 'github-owner/repo-name', + }, + }) + if (!url) return + await fetchRepository(url, url) +} + +export const getServerPlugin = async (plugin: string) => { + const mod = await getPlugin(plugin) + if (!mod) return null + if (mod.serverPlugin) { + return { + content: mod.serverPlugin, + version: mod.version + } + } + return null +} + +export const getAvailableServerPlugins = async () => { + const mods = await getAllMods() + return mods.filter(mod => mod.serverPlugin) +} + +window.inspectInstalledMods = getAllMods + +type ModifiableField = { + field: string + label: string + language: string + getContent?: () => string +} + +// --- + +export const getAllModsModifiableFields = () => { + const fields: ModifiableField[] = [ + { + field: 'scriptMainUnstable', + label: 'Main Thread Script (unstable)', + language: 'js' + }, + { + field: 'stylesGlobal', + label: 'Global CSS Styles', + language: 'css' + }, + { + field: 'threeJsBackend', + label: 'Three.js Renderer Backend Thread', + language: 'js' + }, + { + field: 'serverPlugin', + label: 'Built-in server plugin', + language: 'js' + } + ] + return fields +} + +export const getModModifiableFields = (mod: ClientMod): ModifiableField[] => { + return getAllModsModifiableFields().filter(field => mod[field.field]) +} + +export const getModSettingsProxy = (mod: ClientMod) => { + if (!mod.settings) return valtio.proxy({}) + + const proxy = valtio.proxy({}) + for (const [key, setting] of Object.entries(mod.settings)) { + proxy[key] = options[`mod-${mod.name}-${key}`] ?? setting.default + } + + valtio.subscribe(proxy, (ops) => { + for (const op of ops) { + const [type, path, value] = op + const key = path[0] as string + options[`mod-${mod.name}-${key}`] = value + } + }) + + return proxy +} + +export const callMethodAction = async (modName: string, type: 'main', method: string) => { + try { + const mod = window.loadedMods?.[modName] + await mod[method]() + } catch (err) { + showNotification(`Failed to execute ${method}`, `Problem in ${type} js script of ${modName}`, true) + } +} diff --git a/src/connect.ts b/src/connect.ts index 5e4df859..cb6b8f65 100644 --- a/src/connect.ts +++ b/src/connect.ts @@ -1,15 +1,96 @@ +// import { versionsByMinecraftVersion } from 'minecraft-data' +// import minecraftInitialDataJson from '../generated/minecraft-initial-data.json' +import MinecraftData from 'minecraft-data' +import PrismarineBlock from 'prismarine-block' +import PrismarineItem from 'prismarine-item' +import { miscUiState } from './globalState' +import supportedVersions from './supportedVersions.mjs' +import { options } from './optionsStorage' +import { downloadSoundsIfNeeded } from './sounds/botSoundSystem' +import { AuthenticatedAccount } from './react/serversStorage' + export type ConnectOptions = { - server?: string; - singleplayer?: any; - username: string; - password?: any; - proxy?: any; - botVersion?: any; - serverOverrides?; - serverOverridesFlat?; - peerId?: string; - ignoreQs?: boolean; + server?: string + singleplayer?: any + username: string + proxy?: string + botVersion?: string + serverOverrides? + serverOverridesFlat? + peerId?: string + ignoreQs?: boolean onSuccessfulPlay?: () => void - autoLoginPassword?: string serverIndex?: string + authenticatedAccount?: AuthenticatedAccount | true + peerOptions?: any + viewerWsConnect?: string + saveServerToHistory?: boolean + + /** Will enable local replay server */ + worldStateFileContents?: string + + connectEvents?: { + serverCreated?: () => void + // connect: () => void; + // disconnect: () => void; + // error: (err: any) => void; + // ready: () => void; + // end: () => void; + } +} + +export const getVersionAutoSelect = (autoVersionSelect = options.serversAutoVersionSelect) => { + if (autoVersionSelect === 'auto') { + return '1.19.4' + } + if (autoVersionSelect === 'latest') { + return supportedVersions.at(-1)! + } + return autoVersionSelect +} + +export const loadMinecraftData = async (version: string) => { + await window._LOAD_MC_DATA() + // setLoadingScreenStatus(`Loading data for ${version}`) + // // todo expose cache + // // const initialDataVersion = Object.keys(minecraftInitialDataJson)[0]! + // // if (version === initialDataVersion) { + // // // ignore cache hit + // // versionsByMinecraftVersion.pc[initialDataVersion]!.dataVersion!++ + // // } + + const mcData = MinecraftData(version) + window.PrismarineBlock = PrismarineBlock(mcData.version.minecraftVersion!) + window.PrismarineItem = PrismarineItem(mcData.version.minecraftVersion!) + window.loadedData = mcData + window.mcData = mcData + miscUiState.loadedDataVersion = version +} + +export type AssetDownloadReporter = (asset: string, isDone: boolean) => void + +export const downloadAllMinecraftData = async (reporter?: AssetDownloadReporter) => { + reporter?.('mc-data', false) + await window._LOAD_MC_DATA() + reporter?.('mc-data', true) +} + +const loadFonts = async () => { + const FONT_FAMILY = 'mojangles' + if (!document.fonts.check(`1em ${FONT_FAMILY}`)) { + // todo instead re-render signs on load + await document.fonts.load(`1em ${FONT_FAMILY}`).catch(() => { + console.error('Failed to load font, signs wont be rendered correctly') + }) + } +} + +export const downloadOtherGameData = async (reporter?: AssetDownloadReporter) => { + reporter?.('fonts', false) + reporter?.('sounds', false) + + await Promise.all([ + loadFonts().then(() => reporter?.('fonts', true)), + downloadSoundsIfNeeded().then(() => reporter?.('sounds', true)) + ]) } diff --git a/src/controls.ts b/src/controls.ts index f940d59d..db6a6fc6 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -6,25 +6,34 @@ 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 { UserOverrideCommand, UserOverridesConfig } from 'contro-max/build/types/store' -import { isGameActive, showModal, gameAdditionalState, activeModalStack, hideCurrentModal, miscUiState } from './globalState' -import { goFullscreen, pointerLock, reloadChunks } from './utils' +import { GameMode } from 'mineflayer' +import { getThreeJsRendererMethods } from 'renderer/viewer/three/threeJsMethods' +import { isGameActive, showModal, gameAdditionalState, activeModalStack, hideCurrentModal, miscUiState, hideModal, hideAllModals } from './globalState' +import { goFullscreen, isInRealGameSession, pointerLock, reloadChunks } from './utils' import { options } from './optionsStorage' import { openPlayerInventory } from './inventoryWindows' import { chatInputValueGlobal } from './react/Chat' import { fsState } from './loadSave' import { customCommandsConfig } from './customCommands' -import { CustomCommand } from './react/KeybindingsCustom' +import type { CustomCommand } from './react/KeybindingsCustom' import { showOptionsModal } from './react/SelectOption' import widgets from './react/widgets' -import { getItemFromBlock } from './botUtils' +import { getItemFromBlock } from './chatUtils' import { gamepadUiCursorState, moveGamepadCursorByPx } from './react/GamepadUiCursor' -import { updateBinds } from './react/KeybindingsScreenProvider' +import { completeResourcepackPackInstall, copyServerResourcePackToRegular, resourcePackState } from './resourcePack' +import { showNotification } from './react/NotificationProvider' +import { lastConnectOptions } from './react/AppStatusProvider' +import { onCameraMove, onControInit } from './cameraRotationControls' +import { createNotificationProgressReporter } from './core/progressReporter' +import { appStorage } from './react/appStorageProvider' +import { switchGameMode } from './packetsReplay/replayPackets' +import { tabListState } from './react/PlayerListOverlayProvider' +import { type ActionType, type ActionHoldConfig, type CustomAction } from './appConfig' +import { playerState } from './mineflayer/playerState' - -export const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}')) as UserOverridesConfig +export const customKeymaps = proxy(appStorage.keybindings) subscribe(customKeymaps, () => { - localStorage.keymap = JSON.stringify(customKeymaps) + appStorage.keybindings = customKeymaps }) const controlOptions = { @@ -34,28 +43,48 @@ const controlOptions = { export const contro = new ControMax({ commands: { general: { + // movement jump: ['Space', 'A'], inventory: ['KeyE', 'X'], drop: ['KeyQ', 'B'], + dropStack: [null], sneak: ['ShiftLeft'], toggleSneakOrDown: [null, 'Right Stick'], sprint: ['ControlLeft', 'Left Stick'], + // game interactions nextHotbarSlot: [null, 'Right Bumper'], prevHotbarSlot: [null, 'Left Bumper'], attackDestroy: [null, 'Right Trigger'], interactPlace: [null, 'Left Trigger'], + swapHands: ['KeyF'], + selectItem: ['KeyH'], + rotateCameraLeft: [null], + rotateCameraRight: [null], + rotateCameraUp: [null], + rotateCameraDown: [null], + // ui? chat: [['KeyT', 'Enter']], command: ['Slash'], - swapHands: ['KeyF'], - selectItem: ['KeyH'] // default will be removed + playersList: ['Tab'], + debugOverlay: ['F3'], + debugOverlayHelpMenu: [null], + // client side + zoom: ['KeyC'], + viewerConsole: ['Backquote'], + togglePerspective: ['F5'], }, ui: { + toggleFullscreen: ['F11'], back: [null/* 'Escape' */, 'B'], + toggleMap: ['KeyJ'], leftClick: [null, 'A'], rightClick: [null, 'Y'], speedupCursor: [null, 'Left Stick'], pauseMenu: [null, 'Start'] }, + communication: { + toggleMicrophone: ['KeyM'], + }, advanced: { lockUrl: ['KeyY'], }, @@ -87,6 +116,12 @@ export const contro = new ControMax({ window.controMax = contro export type Command = CommandEventArgument['command'] +export const isCommandDisabled = (command: Command) => { + return miscUiState.appConfig?.disabledCommands?.includes(command) +} + +onControInit() + updateBinds(customKeymaps) const updateDoPreventDefault = () => { @@ -102,7 +137,14 @@ const setSprinting = (state: boolean) => { gameAdditionalState.isSprinting = state } +const isSpectatingEntity = () => { + return appViewer.playerState.utils.isSpectatingEntity() +} + contro.on('movementUpdate', ({ vector, soleVector, gamepadIndex }) => { + // Don't allow movement while spectating an entity + if (isSpectatingEntity()) return + if (gamepadIndex !== undefined && gamepadUiCursorState.display) { const deadzone = 0.1 // TODO make deadzone configurable if (Math.abs(soleVector.x) < deadzone && Math.abs(soleVector.z) < deadzone) { @@ -114,6 +156,23 @@ contro.on('movementUpdate', ({ vector, soleVector, gamepadIndex }) => { } miscUiState.usingGamepadInput = gamepadIndex !== undefined if (!bot || !isGameActive(false)) return + + // if (viewer.world.freeFlyMode) { + // // Create movement vector from input + // const direction = new THREE.Vector3(0, 0, 0) + // if (vector.z !== undefined) direction.z = vector.z + // if (vector.x !== undefined) direction.x = vector.x + + // // Apply camera rotation to movement direction + // direction.applyQuaternion(viewer.camera.quaternion) + + // // Update freeFlyState position with normalized direction + // const moveSpeed = 1 + // direction.multiplyScalar(moveSpeed) + // viewer.world.freeFlyState.position.add(new Vec3(direction.x, direction.y, direction.z)) + // return + // } + // gamepadIndex will be used for splitscreen in future const coordToAction = [ ['z', -1, 'forward'], @@ -143,6 +202,7 @@ contro.on('movementUpdate', ({ vector, soleVector, gamepadIndex }) => { if (action) { void contro.emit('trigger', { command: 'general.forward' } as any) } else { + void contro.emit('release', { command: 'general.forward' } as any) setSprinting(false) } } @@ -154,6 +214,7 @@ let lastCommandTrigger = null as { command: string, time: number } | null const secondActionActivationTimeout = 300 const secondActionCommands = { 'general.jump' () { + // if (bot.game.gameMode === 'spectator') return toggleFly() }, 'general.forward' () { @@ -192,6 +253,10 @@ const inModalCommand = (command: Command, pressed: boolean) => { if (command === 'ui.back') { hideCurrentModal() } + if (command === 'ui.pauseMenu') { + // hide all modals + hideAllModals() + } if (command === 'ui.leftClick' || command === 'ui.rightClick') { // in percent const { x, y } = gamepadUiCursorState @@ -239,9 +304,80 @@ const inModalCommand = (command: Command, pressed: boolean) => { } } +// Camera rotation controls +const cameraRotationControls = { + activeDirections: new Set<'left' | 'right' | 'up' | 'down'>(), + interval: null as ReturnType | null, + config: { + speed: 1, // movement per interval + interval: 5 // ms between movements + }, + movements: { + left: { movementX: -0.5, movementY: 0 }, + right: { movementX: 0.5, movementY: 0 }, + up: { movementX: 0, movementY: -0.5 }, + down: { movementX: 0, movementY: 0.5 } + }, + updateMovement () { + if (cameraRotationControls.activeDirections.size === 0) { + if (cameraRotationControls.interval) { + clearInterval(cameraRotationControls.interval) + cameraRotationControls.interval = null + } + return + } + + if (!cameraRotationControls.interval) { + cameraRotationControls.interval = setInterval(() => { + // Combine all active movements + const movement = { movementX: 0, movementY: 0 } + for (const direction of cameraRotationControls.activeDirections) { + movement.movementX += cameraRotationControls.movements[direction].movementX + movement.movementY += cameraRotationControls.movements[direction].movementY + } + + onCameraMove({ + ...movement, + type: 'keyboardRotation', + stopPropagation () {} + }) + }, cameraRotationControls.config.interval) + } + }, + start (direction: 'left' | 'right' | 'up' | 'down') { + cameraRotationControls.activeDirections.add(direction) + cameraRotationControls.updateMovement() + }, + stop (direction: 'left' | 'right' | 'up' | 'down') { + cameraRotationControls.activeDirections.delete(direction) + cameraRotationControls.updateMovement() + }, + handleCommand (command: string, pressed: boolean) { + // Don't allow movement while spectating an entity + if (isSpectatingEntity()) return + + const directionMap = { + 'general.rotateCameraLeft': 'left', + 'general.rotateCameraRight': 'right', + 'general.rotateCameraUp': 'up', + 'general.rotateCameraDown': 'down' + } as const + + const direction = directionMap[command] + if (direction) { + if (pressed) cameraRotationControls.start(direction) + else cameraRotationControls.stop(direction) + return true + } + return false + } +} +window.cameraRotationControls = cameraRotationControls + const setSneaking = (state: boolean) => { gameAdditionalState.isSneaking = state bot.setControlState('sneak', state) + } const onTriggerOrReleased = (command: Command, pressed: boolean) => { @@ -252,10 +388,21 @@ const onTriggerOrReleased = (command: Command, pressed: boolean) => { // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check switch (command) { case 'general.jump': + if (isSpectatingEntity()) break + // if (viewer.world.freeFlyMode) { + // const moveSpeed = 0.5 + // viewer.world.freeFlyState.position.add(new Vec3(0, pressed ? moveSpeed : 0, 0)) + // } else { bot.setControlState('jump', pressed) + // } break case 'general.sneak': + // if (viewer.world.freeFlyMode) { + // const moveSpeed = 0.5 + // viewer.world.freeFlyState.position.add(new Vec3(0, pressed ? -moveSpeed : 0, 0)) + // } else { setSneaking(pressed) + // } break case 'general.sprint': // todo add setting to change behavior @@ -269,7 +416,6 @@ const onTriggerOrReleased = (command: Command, pressed: boolean) => { } else if (pressed) { setSneaking(!gameAdditionalState.isSneaking) } - break case 'general.attackDestroy': document.dispatchEvent(new MouseEvent(pressed ? 'mousedown' : 'mouseup', { button: 0 })) @@ -277,6 +423,70 @@ const onTriggerOrReleased = (command: Command, pressed: boolean) => { case 'general.interactPlace': document.dispatchEvent(new MouseEvent(pressed ? 'mousedown' : 'mouseup', { button: 2 })) break + case 'general.zoom': + gameAdditionalState.isZooming = pressed + break + case 'general.debugOverlay': + if (pressed) { + miscUiState.showDebugHud = !miscUiState.showDebugHud + } + break + case 'general.debugOverlayHelpMenu': + if (pressed) { + void onF3LongPress() + } + break + case 'general.rotateCameraLeft': + case 'general.rotateCameraRight': + case 'general.rotateCameraUp': + case 'general.rotateCameraDown': + cameraRotationControls.handleCommand(command, pressed) + break + case 'general.playersList': + tabListState.isOpen = pressed + break + case 'general.viewerConsole': + if (lastConnectOptions.value?.viewerWsConnect) { + showModal({ reactType: 'console' }) + } + break + case 'general.togglePerspective': + if (pressed) { + const currentPerspective = playerState.reactive.perspective + // eslint-disable-next-line sonarjs/no-nested-switch + switch (currentPerspective) { + case 'first_person': + playerState.reactive.perspective = 'third_person_back' + break + case 'third_person_back': + playerState.reactive.perspective = 'third_person_front' + break + case 'third_person_front': + playerState.reactive.perspective = 'first_person' + break + } + } + break + } + } else if (stringStartsWith(command, 'ui')) { + switch (command) { + case 'ui.pauseMenu': + if (pressed) { + if (activeModalStack.length) { + hideCurrentModal() + } else { + showModal({ reactType: 'pause-screen' }) + } + } + break + case 'ui.back': + case 'ui.toggleFullscreen': + case 'ui.toggleMap': + case 'ui.leftClick': + case 'ui.rightClick': + case 'ui.speedupCursor': + // These are handled elsewhere + break } } } @@ -290,6 +500,35 @@ const alwaysPressedHandledCommand = (command: Command) => { hideCurrentModal() } } + if (command === 'advanced.lockUrl') { + lockUrl() + } + if (command === 'communication.toggleMicrophone') { + toggleMicrophoneMuted?.() + } +} + +export function lockUrl () { + let newQs = '' + if (fsState.saveLoaded && fsState.inMemorySave) { + const worldFolder = fsState.inMemorySavePath + const save = worldFolder.split('/').at(-1) + newQs = `loadSave=${save}` + } else if (process.env.NODE_ENV === 'development') { + newQs = `reconnect=1` + } else if (lastConnectOptions.value?.server) { + const qs = new URLSearchParams() + const { server, botVersion, proxy, username } = lastConnectOptions.value + qs.set('ip', server) + if (botVersion) qs.set('version', botVersion) + if (proxy) qs.set('proxy', proxy) + if (username) qs.set('username', username) + newQs = String(qs.toString()) + } + + if (newQs) { + window.history.replaceState({}, '', `${window.location.pathname}?${newQs}`) + } } function cycleHotbarSlot (dir: 1 | -1) { @@ -303,14 +542,14 @@ const customCommandsHandler = ({ command }) => { if (!isGameActive(true) || section !== 'custom') return if (contro.userConfig?.custom) { - customCommandsConfig[(contro.userConfig.custom[name] as CustomCommand).type].handler( - (contro.userConfig.custom[name] as CustomCommand).inputs - ) + customCommandsConfig[(contro.userConfig.custom[name] as CustomCommand).type].handler((contro.userConfig.custom[name] as CustomCommand).inputs) } } contro.on('trigger', customCommandsHandler) contro.on('trigger', ({ command }) => { + if (isCommandDisabled(command)) return + const willContinue = !isGameActive(true) alwaysPressedHandledCommand(command) if (willContinue) return @@ -338,11 +577,26 @@ contro.on('trigger', ({ command }) => { case 'general.toggleSneakOrDown': case 'general.sprint': case 'general.attackDestroy': + case 'general.rotateCameraLeft': + case 'general.rotateCameraRight': + case 'general.rotateCameraUp': + case 'general.rotateCameraDown': + case 'general.debugOverlay': + case 'general.debugOverlayHelpMenu': + case 'general.playersList': + case 'general.togglePerspective': + // no-op + break case 'general.swapHands': { - bot._client.write('entity_action', { - entityId: bot.entity.id, - actionId: 6, - jumpBoost: 0 + if (isSpectatingEntity()) break + bot._client.write('block_dig', { + 'status': 6, + 'location': { + 'x': 0, + 'z': 0, + 'y': 0 + }, + 'face': 0, }) break } @@ -350,11 +604,13 @@ contro.on('trigger', ({ command }) => { // handled in onTriggerOrReleased break case 'general.inventory': + if (isSpectatingEntity()) break document.exitPointerLock?.() openPlayerInventory() break - case 'general.drop': - // if (bot.heldItem/* && ctrl */) bot.tossStack(bot.heldItem) + case 'general.drop': { + if (isSpectatingEntity()) break + // protocol 1.9+ bot._client.write('block_dig', { 'status': 4, 'location': { @@ -365,7 +621,20 @@ 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.dropStack': { + if (bot.heldItem) { + void bot.tossStack(bot.heldItem) + } + break + } case 'general.chat': showModal({ reactType: 'chat' }) break @@ -374,48 +643,60 @@ contro.on('trigger', ({ command }) => { showModal({ reactType: 'chat' }) break case 'general.selectItem': + if (isSpectatingEntity()) break void selectItem() break case 'general.nextHotbarSlot': + if (isSpectatingEntity()) break cycleHotbarSlot(1) break case 'general.prevHotbarSlot': + if (isSpectatingEntity()) break cycleHotbarSlot(-1) break + case 'general.zoom': + break + case 'general.viewerConsole': + if (lastConnectOptions.value?.viewerWsConnect) { + showModal({ reactType: 'console' }) + } + break } } - if (command === 'advanced.lockUrl') { - let newQs = '' - if (fsState.saveLoaded) { - const save = localServer!.options.worldFolder.split('/').at(-1) - newQs = `loadSave=${save}` - } else if (process.env.NODE_ENV === 'development') { - newQs = `reconnect=1` - } else { - const qs = new URLSearchParams() - const { server, version } = localStorage - qs.set('server', server) - if (version) qs.set('version', version) - newQs = String(qs.toString()) - } - window.history.replaceState({}, '', `${window.location.pathname}?${newQs}`) - // return + if (command === 'ui.toggleFullscreen') { + void goFullscreen(true) } +}) - if (command === 'ui.pauseMenu') { - showModal({ reactType: 'pause-screen' }) +// show-hide Fullmap +contro.on('trigger', ({ command }) => { + if (command !== 'ui.toggleMap') return + const isActive = isGameActive(true) + if (activeModalStack.at(-1)?.reactType === 'full-map') { + miscUiState.displayFullmap = false + hideModal({ reactType: 'full-map' }) + } else if (isActive && !activeModalStack.length) { + miscUiState.displayFullmap = true + showModal({ reactType: 'full-map' }) } }) contro.on('release', ({ command }) => { + if (isCommandDisabled(command)) return + inModalCommand(command, false) onTriggerOrReleased(command, false) }) // hard-coded keybindings -export const f3Keybinds = [ +export const f3Keybinds: Array<{ + key?: string, + action: () => void | Promise, + mobileTitle: string + enabled?: () => boolean +}> = [ { key: 'KeyA', action () { @@ -424,17 +705,20 @@ export const f3Keybinds = [ for (const [x, z] of loadedChunks) { worldView!.unloadChunk({ x, z }) } - for (const child of viewer.scene.children) { - if (child.name === 'chunk') { // should not happen - viewer.scene.remove(child) - console.warn('forcefully removed chunk from scene') - } - } + // for (const child of viewer.scene.children) { + // if (child.name === 'chunk') { // should not happen + // viewer.scene.remove(child) + // console.warn('forcefully removed chunk from scene') + // } + // } if (localServer) { //@ts-expect-error not sure why it is private... maybe revisit api? localServer.players[0].world.columns = {} } void reloadChunks() + if (appViewer.backend?.backendMethods && typeof appViewer.backend.backendMethods.reloadWorld === 'function') { + appViewer.backend.backendMethods.reloadWorld() + } }, mobileTitle: 'Reload chunks', }, @@ -442,12 +726,24 @@ export const f3Keybinds = [ key: 'KeyG', action () { options.showChunkBorders = !options.showChunkBorders - viewer.world.updateShowChunksBorder(options.showChunkBorders) }, mobileTitle: 'Toggle chunk borders', }, { - key: 'KeyT', + key: 'KeyH', + action () { + showModal({ reactType: 'chunks-debug' }) + }, + mobileTitle: 'Show Chunks Debug', + }, + { + action () { + showModal({ reactType: 'renderer-debug' }) + }, + mobileTitle: 'Renderer Debug Menu', + }, + { + key: 'KeyY', async action () { // waypoints const widgetNames = widgets.map(widget => widget.name) @@ -456,99 +752,91 @@ export const f3Keybinds = [ showModal({ reactType: `widget-${widget}` }) }, mobileTitle: 'Open Widget' + }, + { + key: 'KeyT', + async action () { + // TODO! + if (resourcePackState.resourcePackInstalled || gameAdditionalState.usingServerResourcePack) { + showNotification('Reloading textures...') + await completeResourcepackPackInstall('default', 'default', gameAdditionalState.usingServerResourcePack, createNotificationProgressReporter()) + } + }, + mobileTitle: 'Reload Textures' + }, + { + key: 'F4', + async action () { + let nextGameMode: GameMode + switch (bot.game.gameMode) { + case 'creative': { + nextGameMode = 'survival' + + break + } + case 'survival': { + nextGameMode = 'adventure' + + break + } + case 'adventure': { + nextGameMode = 'spectator' + + break + } + case 'spectator': { + nextGameMode = 'creative' + + break + } + // No default + } + if (lastConnectOptions.value?.worldStateFileContents) { + switchGameMode(nextGameMode) + } else { + bot.chat(`/gamemode ${nextGameMode}`) + } + }, + mobileTitle: 'Cycle Game Mode' + }, + { + key: 'KeyP', + async action () { + const { uuid, ping: playerPing, username } = bot.player + const proxyPing = await bot['pingProxy']() + void showOptionsModal(`${username}: last known total latency (ping): ${playerPing}. Connected to ${lastConnectOptions.value?.proxy} with current ping ${proxyPing}. Player UUID: ${uuid}`, []) + }, + mobileTitle: 'Show Player & Ping Details', + enabled: () => !lastConnectOptions.value?.singleplayer && !!bot.player + }, + { + action () { + void copyServerResourcePackToRegular() + }, + mobileTitle: 'Copy Server Resource Pack', + enabled: () => !!gameAdditionalState.usingServerResourcePack } ] -const hardcodedPressedKeys = new Set() +export const reloadChunksAction = () => { + const action = f3Keybinds.find(f3Keybind => f3Keybind.key === 'KeyA') + void action!.action() +} + document.addEventListener('keydown', (e) => { if (!isGameActive(false)) return - if (hardcodedPressedKeys.has('F3')) { + if (contro.pressedKeys.has('F3')) { const keybind = f3Keybinds.find((v) => v.key === e.code) - if (keybind) { - keybind.action() + if (keybind && (keybind.enabled?.() ?? true)) { + void keybind.action() e.stopPropagation() } - return } - - hardcodedPressedKeys.add(e.code) }, { capture: true, }) -document.addEventListener('keyup', (e) => { - hardcodedPressedKeys.delete(e.code) -}) -document.addEventListener('visibilitychange', (e) => { - if (document.visibilityState === 'hidden') { - hardcodedPressedKeys.clear() - } -}) -// #region creative fly -// these controls are more like for gamemode 3 - -const makeInterval = (fn, interval) => { - const intervalId = setInterval(fn, interval) - - const cleanup = () => { - clearInterval(intervalId) - cleanup.active = false - } - cleanup.active = true - return cleanup -} - -const isFlying = () => bot.physics.gravity === 0 -let endFlyLoop: ReturnType | undefined - -const currentFlyVector = new Vec3(0, 0, 0) -window.currentFlyVector = currentFlyVector - -// todo cleanup -const flyingPressedKeys = { - down: false, - up: false -} - -const startFlyLoop = () => { - if (!isFlying()) return - endFlyLoop?.() - - endFlyLoop = makeInterval(() => { - if (!bot) { - endFlyLoop?.() - return - } - - bot.entity.position.add(currentFlyVector.clone().multiply(new Vec3(0, 0.5, 0))) - }, 50) -} - -// todo we will get rid of patching it when refactor controls -let originalSetControlState -const patchedSetControlState = (action, state) => { - if (!isFlying()) { - return originalSetControlState(action, state) - } - - const actionPerFlyVector = { - jump: new Vec3(0, 1, 0), - sneak: new Vec3(0, -1, 0), - } - - const changeVec = actionPerFlyVector[action] - if (!changeVec) { - return originalSetControlState(action, state) - } - if (flyingPressedKeys[state === 'jump' ? 'up' : 'down'] === state) return - const toAddVec = changeVec.scaled(state ? 1 : -1) - for (const coord of ['x', 'y', 'z']) { - if (toAddVec[coord] === 0) continue - if (currentFlyVector[coord] === toAddVec[coord]) return - } - currentFlyVector.add(toAddVec) - flyingPressedKeys[state === 'jump' ? 'up' : 'down'] = state -} +const isFlying = () => (bot.entity as any).flying const startFlying = (sendAbilities = true) => { if (sendAbilities) { @@ -556,51 +844,24 @@ const startFlying = (sendAbilities = true) => { flags: 2, }) } - // window.flyingSpeed will be removed - bot.physics['airborneAcceleration'] = window.flyingSpeed ?? 0.1 // todo use abilities - bot.entity.velocity = new Vec3(0, 0, 0) - bot.creative.startFlying() - startFlyLoop() + (bot.entity as any).flying = true } const endFlying = (sendAbilities = true) => { - if (bot.physics.gravity !== 0) return + if (!isFlying()) return if (sendAbilities) { bot._client.write('abilities', { flags: 0, }) } - Object.assign(flyingPressedKeys, { - up: false, - down: false - }) - currentFlyVector.set(0, 0, 0) - bot.physics['airborneAcceleration'] = standardAirborneAcceleration - bot.creative.stopFlying() - endFlyLoop?.() + (bot.entity as any).flying = false } -let allowFlying = false - export const onBotCreate = () => { - bot._client.on('abilities', ({ flags }) => { - if (flags & 2) { // flying - toggleFly(true, false) - } else { - toggleFly(false, false) - } - allowFlying = !!(flags & 4) - }) } -const standardAirborneAcceleration = 0.02 const toggleFly = (newState = !isFlying(), sendAbilities?: boolean) => { - // if (bot.game.gameMode !== 'creative' && bot.game.gameMode !== 'spectator') return - if (!allowFlying) return - if (bot.setControlState !== patchedSetControlState) { - originalSetControlState = bot.setControlState - bot.setControlState = patchedSetControlState - } + if (!bot.entity.canFly) return if (newState) { startFlying(sendAbilities) @@ -609,7 +870,6 @@ const toggleFly = (newState = !isFlying(), sendAbilities?: boolean) => { } gameAdditionalState.isFlying = isFlying() } -// #endregion const selectItem = async () => { const block = bot.blockAtCursor(5) @@ -623,9 +883,16 @@ const selectItem = async () => { } addEventListener('mousedown', async (e) => { + // always prevent default for side buttons (back / forward navigation) + if (e.button === 3 || e.button === 4) { + e.preventDefault() + } + if ((e.target as HTMLElement).matches?.('#VRButton')) return + if (!isInRealGameSession() && !(e.target as HTMLElement).id.includes('ui-root')) return void pointerLock.requestPointerLock() if (!bot) return + getThreeJsRendererMethods()?.onPageInteraction() // wheel click // todo support ctrl+wheel (+nbt) if (e.button === 1) { @@ -635,12 +902,21 @@ addEventListener('mousedown', async (e) => { window.addEventListener('keydown', (e) => { if (e.code !== 'Escape') return + if (!activeModalStack.length) { + getThreeJsRendererMethods()?.onPageInteraction() + } + if (activeModalStack.length) { - hideCurrentModal(undefined, () => { - if (!activeModalStack.length) { - pointerLock.justHitEscape = true - } - }) + const hideAll = e.ctrlKey || e.metaKey + if (hideAll) { + hideAllModals() + } else { + hideCurrentModal() + } + if (activeModalStack.length === 0) { + getThreeJsRendererMethods()?.onPageInteraction() + pointerLock.justHitEscape = true + } } else if (pointerLock.hasPointerLock) { document.exitPointerLock?.() if (options.autoExitFullscreen) { @@ -651,14 +927,125 @@ 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') { - e.preventDefault() - void goFullscreen(true) - } - if (e.code === 'KeyL' && e.altKey) { + if (e.code === 'KeyL' && e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey) { console.clear() } + if (e.code === 'KeyK' && e.altKey && e.shiftKey && !e.ctrlKey && !e.metaKey) { + if (sessionStorage.delayLoadUntilFocus) { + sessionStorage.removeItem('delayLoadUntilFocus') + } else { + sessionStorage.setItem('delayLoadUntilFocus', 'true') + } + } + if (e.code === 'KeyK' && e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey) { + // eslint-disable-next-line no-debugger + debugger + } }) // #endregion + +export function updateBinds (commands: any) { + contro.inputSchema.commands.custom = Object.fromEntries(Object.entries(commands?.custom ?? {}).map(([key, value]) => { + return [key, { + keys: [], + gamepad: [], + type: '', + inputs: [] + }] + })) + + for (const [group, actions] of Object.entries(commands)) { + contro.userConfig![group] = Object.fromEntries(Object.entries(actions).map(([key, value]) => { + const newValue = { + keys: value?.keys ?? undefined, + gamepad: value?.gamepad ?? undefined, + } + + if (group === 'custom') { + newValue['type'] = (value).type + newValue['inputs'] = (value).inputs + } + + return [key, newValue] + })) + } +} + +export const onF3LongPress = async () => { + const actions = f3Keybinds.filter(f3Keybind => { + return f3Keybind.mobileTitle && (f3Keybind.enabled?.() ?? true) + }) + const actionNames = actions.map(f3Keybind => { + return `${f3Keybind.mobileTitle}${f3Keybind.key ? ` (F3+${f3Keybind.key})` : ''}` + }) + const select = await showOptionsModal('', actionNames) + if (!select) return + const actionIndex = actionNames.indexOf(select) + const f3Keybind = actions[actionIndex]! + void f3Keybind.action() +} + +export const handleMobileButtonCustomAction = (action: CustomAction) => { + const handler = customCommandsConfig[action.type]?.handler + if (handler) { + handler([...action.input]) + } +} + +export const triggerCommand = (command: Command, isDown: boolean) => { + handleMobileButtonActionCommand(command, isDown) +} + +export const handleMobileButtonActionCommand = (command: ActionType | ActionHoldConfig, isDown: boolean) => { + const commandValue = typeof command === 'string' ? command : 'command' in command ? command.command : command + + // Check if command is disabled before proceeding + if (typeof commandValue === 'string' && isCommandDisabled(commandValue as Command)) return + + if (typeof commandValue === 'string' && !stringStartsWith(commandValue, 'custom')) { + const event: CommandEventArgument = { + command: commandValue as Command, + schema: { + keys: [], + gamepad: [] + } + } + if (isDown) { + contro.emit('trigger', event) + } else { + contro.emit('release', event) + } + } else if (typeof commandValue === 'object') { + if (isDown) { + handleMobileButtonCustomAction(commandValue) + } + } +} + +export const handleMobileButtonLongPress = (actionHold: ActionHoldConfig) => { + if (typeof actionHold.longPressAction === 'string' && actionHold.longPressAction === 'general.debugOverlayHelpMenu') { + void onF3LongPress() + } else if (actionHold.longPressAction) { + handleMobileButtonActionCommand(actionHold.longPressAction, true) + } +} diff --git a/src/core/ideChannels.ts b/src/core/ideChannels.ts new file mode 100644 index 00000000..a9c517f7 --- /dev/null +++ b/src/core/ideChannels.ts @@ -0,0 +1,106 @@ +import { proxy } from 'valtio' + +export const ideState = proxy({ + id: '', + contents: '', + line: 0, + column: 0, + language: 'typescript', + title: '', +}) +globalThis.ideState = ideState + +export const registerIdeChannels = () => { + registerIdeOpenChannel() + registerIdeSaveChannel() +} + +const registerIdeOpenChannel = () => { + const CHANNEL_NAME = 'minecraft-web-client:ide-open' + + const packetStructure = [ + 'container', + [ + { + name: 'id', + type: ['pstring', { countType: 'i16' }] + }, + { + name: 'language', + type: ['pstring', { countType: 'i16' }] + }, + { + name: 'contents', + type: ['pstring', { countType: 'i16' }] + }, + { + name: 'line', + type: 'i32' + }, + { + name: 'column', + type: 'i32' + }, + { + name: 'title', + type: ['pstring', { countType: 'i16' }] + } + ] + ] + + bot._client.registerChannel(CHANNEL_NAME, packetStructure, true) + + bot._client.on(CHANNEL_NAME as any, (data) => { + const { id, language, contents, line, column, title } = data + + ideState.contents = contents + ideState.line = line + ideState.column = column + ideState.id = id + ideState.language = language || 'typescript' + ideState.title = title + }) + + console.debug(`registered custom channel ${CHANNEL_NAME} channel`) +} +const IDE_SAVE_CHANNEL_NAME = 'minecraft-web-client:ide-save' +const registerIdeSaveChannel = () => { + + const packetStructure = [ + 'container', + [ + { + name: 'id', + type: ['pstring', { countType: 'i16' }] + }, + { + name: 'contents', + type: ['pstring', { countType: 'i16' }] + }, + { + name: 'language', + type: ['pstring', { countType: 'i16' }] + }, + { + name: 'line', + type: 'i32' + }, + { + name: 'column', + type: 'i32' + }, + ] + ] + bot._client.registerChannel(IDE_SAVE_CHANNEL_NAME, packetStructure, true) +} + +export const saveIde = () => { + bot._client.writeChannel(IDE_SAVE_CHANNEL_NAME, { + id: ideState.id, + contents: ideState.contents, + language: ideState.language, + // todo: reflect updated + line: ideState.line, + column: ideState.column, + }) +} diff --git a/src/core/importExport.ts b/src/core/importExport.ts new file mode 100644 index 00000000..b3e26347 --- /dev/null +++ b/src/core/importExport.ts @@ -0,0 +1,219 @@ +import { appStorage } from '../react/appStorageProvider' +import { getChangedSettings, options } from '../optionsStorage' +import { customKeymaps } from '../controls' +import { showInputsModal } from '../react/SelectOption' + +interface ExportedFile { + _about: string + options?: Record + keybindings?: Record + servers?: any[] + username?: string + proxy?: string + proxies?: string[] + accountTokens?: any[] +} + +export const importData = async () => { + try { + const input = document.createElement('input') + input.type = 'file' + input.accept = '.json' + input.click() + + const file = await new Promise((resolve) => { + input.onchange = () => { + if (!input.files?.[0]) return + resolve(input.files[0]) + } + }) + + const text = await file.text() + const data = JSON.parse(text) + + if (!data._about?.includes('Minecraft Web Client')) { + const doContinue = confirm('This file does not appear to be a Minecraft Web Client profile. Continue anyway?') + if (!doContinue) return + } + + // Build available data types for selection + const availableData: Record, { present: boolean, description: string }> = { + options: { present: !!data.options, description: 'Game settings and preferences' }, + keybindings: { present: !!data.keybindings, description: 'Custom key mappings' }, + servers: { present: !!data.servers, description: 'Saved server list' }, + username: { present: !!data.username, description: 'Username' }, + proxy: { present: !!data.proxy, description: 'Selected proxy server' }, + proxies: { present: !!data.proxies, description: 'Global proxies list' }, + accountTokens: { present: !!data.accountTokens, description: 'Account authentication tokens' }, + } + + // Filter to only present data types + const presentTypes = Object.fromEntries(Object.entries(availableData) + .filter(([_, info]) => info.present) + .map(([key, info]) => [key, info])) + + if (Object.keys(presentTypes).length === 0) { + alert('No compatible data found in the imported file.') + return + } + + const importChoices = await showInputsModal('Select Data to Import', { + mergeData: { + type: 'checkbox', + label: 'Merge with existing data (uncheck to remove old data)', + defaultValue: true, + }, + ...Object.fromEntries(Object.entries(presentTypes).map(([key, info]) => [key, { + type: 'checkbox', + label: info.description, + defaultValue: true, + }])) + }) as { mergeData: boolean } & Record + + if (!importChoices) return + + const importedTypes: string[] = [] + const shouldMerge = importChoices.mergeData + + if (importChoices.options && data.options) { + if (shouldMerge) { + Object.assign(options, data.options) + } else { + for (const key of Object.keys(options)) { + if (key in data.options) { + options[key as any] = data.options[key] + } + } + } + importedTypes.push('settings') + } + + if (importChoices.keybindings && data.keybindings) { + if (shouldMerge) { + Object.assign(customKeymaps, data.keybindings) + } else { + for (const key of Object.keys(customKeymaps)) delete customKeymaps[key] + Object.assign(customKeymaps, data.keybindings) + } + importedTypes.push('keybindings') + } + + if (importChoices.servers && data.servers) { + if (shouldMerge && appStorage.serversList) { + // Merge by IP, update existing entries and add new ones + const existingIps = new Set(appStorage.serversList.map(s => s.ip)) + const newServers = data.servers.filter(s => !existingIps.has(s.ip)) + appStorage.serversList = [...appStorage.serversList, ...newServers] + } else { + appStorage.serversList = data.servers + } + importedTypes.push('servers') + } + + if (importChoices.username && data.username) { + appStorage.username = data.username + importedTypes.push('username') + } + + if ((importChoices.proxy && data.proxy) || (importChoices.proxies && data.proxies)) { + if (!appStorage.proxiesData) { + appStorage.proxiesData = { proxies: [], selected: '' } + } + + if (importChoices.proxies && data.proxies) { + if (shouldMerge) { + // Merge unique proxies + const uniqueProxies = new Set([...appStorage.proxiesData.proxies, ...data.proxies]) + appStorage.proxiesData.proxies = [...uniqueProxies] + } else { + appStorage.proxiesData.proxies = data.proxies + } + importedTypes.push('proxies list') + } + + if (importChoices.proxy && data.proxy) { + appStorage.proxiesData.selected = data.proxy + importedTypes.push('selected proxy') + } + } + + if (importChoices.accountTokens && data.accountTokens) { + if (shouldMerge && appStorage.authenticatedAccounts) { + // Merge by unique identifier (assuming accounts have some unique ID or username) + const existingAccounts = new Set(appStorage.authenticatedAccounts.map(a => a.username)) + const newAccounts = data.accountTokens.filter(a => !existingAccounts.has(a.username)) + appStorage.authenticatedAccounts = [...appStorage.authenticatedAccounts, ...newAccounts] + } else { + appStorage.authenticatedAccounts = data.accountTokens + } + importedTypes.push('account tokens') + } + + alert(`Profile imported successfully! Imported data: ${importedTypes.join(', ')}.\nYou may need to reload the page for some changes to take effect.`) + } catch (err) { + console.error('Failed to import profile:', err) + alert('Failed to import profile: ' + (err.message || err)) + } +} + +export const exportData = async () => { + const data = await showInputsModal('Export Profile', { + profileName: { + type: 'text', + }, + exportSettings: { + type: 'checkbox', + defaultValue: true, + }, + exportKeybindings: { + type: 'checkbox', + defaultValue: true, + }, + exportServers: { + type: 'checkbox', + defaultValue: true, + }, + saveUsernameAndProxy: { + type: 'checkbox', + defaultValue: true, + }, + exportGlobalProxiesList: { + type: 'checkbox', + defaultValue: false, + }, + exportAccountTokens: { + type: 'checkbox', + defaultValue: false, + }, + }) + const fileName = `${data.profileName ? `${data.profileName}-` : ''}web-client-profile.json` + const json: ExportedFile = { + _about: 'Minecraft Web Client (mcraft.fun) Profile', + ...data.exportSettings ? { + options: getChangedSettings(), + } : {}, + ...data.exportKeybindings ? { + keybindings: customKeymaps, + } : {}, + ...data.exportServers ? { + servers: appStorage.serversList, + } : {}, + ...data.saveUsernameAndProxy ? { + username: appStorage.username, + proxy: appStorage.proxiesData?.selected, + } : {}, + ...data.exportGlobalProxiesList ? { + proxies: appStorage.proxiesData?.proxies, + } : {}, + ...data.exportAccountTokens ? { + accountTokens: appStorage.authenticatedAccounts, + } : {}, + } + const blob = new Blob([JSON.stringify(json, null, 2)], { type: 'application/json' }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = fileName + a.click() + URL.revokeObjectURL(url) +} diff --git a/src/core/progressReporter.ts b/src/core/progressReporter.ts new file mode 100644 index 00000000..75878fd2 --- /dev/null +++ b/src/core/progressReporter.ts @@ -0,0 +1,234 @@ +import { setLoadingScreenStatus } from '../appStatus' +import { appStatusState } from '../react/AppStatusProvider' +import { hideNotification, showNotification } from '../react/NotificationProvider' +import { pixelartIcons } from '../react/PixelartIcon' + +export interface ProgressReporter { + currentMessage: string | undefined + beginStage (stage: string, title: string): void + endStage (stage: string): void + setSubStage (stage: string, subStageTitle: string): void + reportProgress (stage: string, progress: number): void + executeWithMessage(message: string, fn: () => Promise): Promise + executeWithMessage(message: string, stage: string, fn: () => Promise): Promise + + setMessage (message: string): void + + end(): void + error(message: string): void +} + +interface ReporterDisplayImplementation { + setMessage (message: string): void + end (): void + error(message: string): void +} + +interface StageInfo { + title: string + subStage?: string + progress?: number +} + +const NO_STAGES_ACTION_END = false + +const createProgressReporter = (implementation: ReporterDisplayImplementation): ProgressReporter => { + const stages = new Map() + let currentMessage: string | undefined + let ended = false + + const end = () => { + if (ended) return + ended = true + stages.clear() + implementation.end() + } + + const updateStatus = () => { + if (ended) return + const activeStages = [...stages.entries()] + if (activeStages.length === 0) { + if (NO_STAGES_ACTION_END) { + end() + } else { + implementation.setMessage('Waiting for tasks') + } + return + } + + const [currentStage, info] = activeStages.at(-1)! + let message = info.title + if (info.subStage) { + message += ` - ${info.subStage}` + } + if (info.progress !== undefined) { + const num = Math.round(info.progress * 100) + if (isFinite(num)) { + message += `: ${num}%` + } + } + + currentMessage = message + implementation.setMessage(message) + } + + const reporter = { + beginStage (stage: string, title: string) { + if (stages.has(stage)) { + throw new Error(`Stage ${stage} already is running`) + } + stages.set(stage, { title }) + updateStatus() + }, + + endStage (stage: string) { + stages.delete(stage) + updateStatus() + }, + + setSubStage (stage: string, subStageTitle: string) { + const info = stages.get(stage) + if (info) { + info.subStage = subStageTitle + updateStatus() + } + }, + + reportProgress (stage: string, progress: number) { + const info = stages.get(stage) + if (info) { + info.progress = progress + updateStatus() + } + }, + + async executeWithMessage(...args: any[]): Promise { + const message = args[0] + const stage = typeof args[1] === 'string' ? args[1] : undefined + const fn = typeof args[1] === 'string' ? args[2] : args[1] + + const tempStage = stage ?? 'temp-' + Math.random().toString(36).slice(2) + reporter.beginStage(tempStage, message) + try { + const result = await fn() + return result + } finally { + reporter.endStage(tempStage) + } + }, + + end (): void { + end() + }, + + setMessage (message: string): void { + if (ended) return + implementation.setMessage(message) + }, + + get currentMessage () { + return currentMessage + }, + + error (message: string): void { + if (ended) return + implementation.error(message) + } + } + + return reporter +} + +const fullScreenReporters = [] as ProgressReporter[] +export const createFullScreenProgressReporter = (): ProgressReporter => { + const reporter = createProgressReporter({ + setMessage (message: string) { + if (appStatusState.isError) return + setLoadingScreenStatus(message) + }, + end () { + if (appStatusState.isError) return + fullScreenReporters.splice(fullScreenReporters.indexOf(reporter), 1) + if (fullScreenReporters.length === 0) { + setLoadingScreenStatus(undefined) + } else { + setLoadingScreenStatus(fullScreenReporters.at(-1)!.currentMessage) + } + }, + + error (message: string): void { + if (appStatusState.isError) return + setLoadingScreenStatus(message, true) + } + }) + fullScreenReporters.push(reporter) + return reporter +} + +export const createNotificationProgressReporter = (endMessage?: string): ProgressReporter => { + const id = `progress-reporter-${Math.random().toString(36).slice(2)}` + return createProgressReporter({ + setMessage (message: string) { + showNotification(`${message}...`, '', false, '', undefined, true, id) + }, + end () { + if (endMessage) { + showNotification(endMessage, '', false, pixelartIcons.check, undefined, true) + } else { + hideNotification(id) + } + }, + + error (message: string): void { + showNotification(message, '', true, '', undefined, true) + } + }) +} + +export const createConsoleLogProgressReporter = (group?: string): ProgressReporter => { + return createProgressReporter({ + setMessage (message: string) { + console.log(group ? `[${group}] ${message}` : message) + }, + end () { + console.log(group ? `[${group}] done` : 'done') + }, + + error (message: string): void { + console.error(message) + } + }) +} + +export const createWrappedProgressReporter = (reporter: ProgressReporter, message?: string) => { + const stage = `wrapped-${message}` + if (message) { + reporter.beginStage(stage, message) + } + + return createProgressReporter({ + setMessage (message: string) { + reporter.setMessage(message) + }, + end () { + if (message) { + reporter.endStage(stage) + } + }, + + error (message: string): void { + reporter.error(message) + } + }) +} + +export const createNullProgressReporter = (): ProgressReporter => { + return createProgressReporter({ + setMessage (message: string) { + }, + end () { + }, + error (message: string) { + } + }) +} diff --git a/src/core/timers.ts b/src/core/timers.ts new file mode 100644 index 00000000..570f46c0 --- /dev/null +++ b/src/core/timers.ts @@ -0,0 +1,139 @@ +import { options } from '../optionsStorage' + +interface Timer { + id: number + callback: () => void + targetTime: number + isInterval: boolean + interval?: number + cleanup?: () => void +} + +let nextTimerId = 1 +const timers: Timer[] = [] + +// TODO implementation breaks tps (something is wrong with intervals) +const fixBrowserTimers = () => { + const originalSetTimeout = window.setTimeout + //@ts-expect-error + window.setTimeout = (callback: () => void, delay: number) => { + if (!delay) { + return originalSetTimeout(callback) + } + const id = nextTimerId++ + const targetTime = performance.now() + delay + timers.push({ id, callback, targetTime, isInterval: false }) + originalSetTimeout(() => { + checkTimers() + }, delay) + return id + } + + const originalSetInterval = window.setInterval + //@ts-expect-error + window.setInterval = (callback: () => void, interval: number) => { + if (!interval) { + return originalSetInterval(callback, interval) + } + const id = nextTimerId++ + const targetTime = performance.now() + interval + const originalInterval = originalSetInterval(() => { + checkTimers() + }, interval) + timers.push({ + id, + callback, + targetTime, + isInterval: true, + interval, + cleanup () { + originalClearInterval(originalInterval) + }, + }) + return id + } + + const originalClearTimeout = window.clearTimeout + //@ts-expect-error + window.clearTimeout = (id: number) => { + const index = timers.findIndex(t => t.id === id) + if (index !== -1) { + timers.splice(index, 1) + } + return originalClearTimeout(id) + } + + const originalClearInterval = window.clearInterval + //@ts-expect-error + window.clearInterval = (id: number) => { + const index = timers.findIndex(t => t.id === id) + if (index !== -1) { + const timer = timers[index] + if (timer.cleanup) { + timer.cleanup() + } + timers.splice(index, 1) + } + return originalClearInterval(id) + } +} + +export const checkTimers = () => { + const now = performance.now() + + let triggered = false + for (let i = timers.length - 1; i >= 0; i--) { + const timer = timers[i] + + if (now >= timer.targetTime) { + triggered = true + timer.callback() + + if (timer.isInterval && timer.interval) { + // Reschedule interval + timer.targetTime = now + timer.interval + } else { + // Remove one-time timer + timers.splice(i, 1) + } + } + } + + if (!triggered) { + console.log('No timers triggered!') + } +} + +// workaround for browser timers throttling after 5 minutes of tab inactivity +export const preventThrottlingWithSound = () => { + try { + const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)() + const oscillator = audioContext.createOscillator() + const gainNode = audioContext.createGain() + + // Unfortunatelly cant use 0 + gainNode.gain.value = 0.001 + + // Connect nodes + oscillator.connect(gainNode) + gainNode.connect(audioContext.destination) + + // Use a very low frequency + oscillator.frequency.value = 1 + + // Start playing + oscillator.start() + + return async () => { + try { + oscillator.stop() + await audioContext.close() + } catch (err) { + console.warn('Error stopping silent audio:', err) + } + } + } catch (err) { + console.error('Error creating silent audio:', err) + return () => {} + } +} 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/cross_playstation_console_controller_gamepad_icon.svg b/src/cross_playstation_console_controller_gamepad_icon.svg deleted file mode 100644 index d7d176e2..00000000 --- a/src/cross_playstation_console_controller_gamepad_icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/crypto.js b/src/crypto.js deleted file mode 100644 index 9034a397..00000000 --- a/src/crypto.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from 'crypto-browserify' -export function createPublicKey () { } diff --git a/src/customChannels.ts b/src/customChannels.ts new file mode 100644 index 00000000..506ea776 --- /dev/null +++ b/src/customChannels.ts @@ -0,0 +1,504 @@ +import PItem from 'prismarine-item' +import { getThreeJsRendererMethods } from 'renderer/viewer/three/threeJsMethods' +import { options } from './optionsStorage' +import { jeiCustomCategories } from './inventoryWindows' +import { registerIdeChannels } from './core/ideChannels' + +export default () => { + customEvents.on('mineflayerBotCreated', async () => { + if (!options.customChannels) return + bot.once('login', () => { + registerBlockModelsChannel() + registerMediaChannels() + registerSectionAnimationChannels() + registeredJeiChannel() + registerBlockInteractionsCustomizationChannel() + registerWaypointChannels() + registerIdeChannels() + }) + }) +} + +const registerChannel = (channelName: string, packetStructure: any[], handler: (data: any) => void, waitForWorld = true) => { + bot._client.registerChannel(channelName, packetStructure, true) + bot._client.on(channelName as any, async (data) => { + if (waitForWorld) { + await appViewer.worldReady + handler(data) + } else { + handler(data) + } + }) + + console.debug(`registered custom channel ${channelName} channel`) +} + +const registerBlockInteractionsCustomizationChannel = () => { + const CHANNEL_NAME = 'minecraft-web-client:block-interactions-customization' + const packetStructure = [ + 'container', + [ + { + name: 'newConfiguration', + type: ['pstring', { countType: 'i16' }] + }, + ] + ] + + registerChannel(CHANNEL_NAME, packetStructure, (data) => { + const config = JSON.parse(data.newConfiguration) + bot.mouse.setConfigFromPacket(config) + }, true) +} + +const registerWaypointChannels = () => { + const packetStructure = [ + 'container', + [ + { + name: 'id', + type: ['pstring', { countType: 'i16' }] + }, + { + name: 'x', + type: 'f32' + }, + { + name: 'y', + type: 'f32' + }, + { + name: 'z', + type: 'f32' + }, + { + name: 'minDistance', + type: 'i32' + }, + { + name: 'label', + type: ['pstring', { countType: 'i16' }] + }, + { + name: 'color', + type: 'i32' + }, + { + name: 'metadataJson', + type: ['pstring', { countType: 'i16' }] + } + ] + ] + + registerChannel('minecraft-web-client:waypoint-add', packetStructure, (data) => { + // Parse metadata if provided + let metadata: any = {} + if (data.metadataJson && data.metadataJson.trim() !== '') { + try { + metadata = JSON.parse(data.metadataJson) + } catch (error) { + console.warn('Failed to parse waypoint metadataJson:', error) + } + } + + getThreeJsRendererMethods()?.addWaypoint(data.id, data.x, data.y, data.z, { + minDistance: data.minDistance, + label: data.label || undefined, + color: data.color || undefined, + metadata + }) + }) + + registerChannel('minecraft-web-client:waypoint-delete', [ + 'container', + [ + { + name: 'id', + type: ['pstring', { countType: 'i16' }] + } + ] + ], (data) => { + getThreeJsRendererMethods()?.removeWaypoint(data.id) + }) +} + +const registerBlockModelsChannel = () => { + const CHANNEL_NAME = 'minecraft-web-client:blockmodels' + + const packetStructure = [ + 'container', + [ + { + name: 'worldName', // currently not used + type: ['pstring', { countType: 'i16' }] + }, + { + name: 'x', + type: 'i32' + }, + { + name: 'y', + type: 'i32' + }, + { + name: 'z', + type: 'i32' + }, + { + name: 'model', + type: ['pstring', { countType: 'i16' }] + } + ] + ] + + registerChannel(CHANNEL_NAME, packetStructure, (data) => { + const { worldName, x, y, z, model } = data + + const chunkX = Math.floor(x / 16) * 16 + const chunkZ = Math.floor(z / 16) * 16 + const chunkKey = `${chunkX},${chunkZ}` + const blockPosKey = `${x},${y},${z}` + + getThreeJsRendererMethods()?.updateCustomBlock(chunkKey, blockPosKey, model) + }, true) +} + +const registerSectionAnimationChannels = () => { + const ADD_CHANNEL = 'minecraft-web-client:section-animation-add' + const REMOVE_CHANNEL = 'minecraft-web-client:section-animation-remove' + + /** + * Add a section animation + * @param id - Section position for animation like `16,32,16` + * @param offset - Initial offset in blocks + * @param speedX - Movement speed in blocks per second on X axis + * @param speedY - Movement speed in blocks per second on Y axis + * @param speedZ - Movement speed in blocks per second on Z axis + * @param limitX - Maximum offset in blocks on X axis (0 means no limit) + * @param limitY - Maximum offset in blocks on Y axis (0 means no limit) + * @param limitZ - Maximum offset in blocks on Z axis (0 means no limit) + */ + const addPacketStructure = [ + 'container', + [ + { name: 'id', type: ['pstring', { countType: 'i16' }] }, + { name: 'offset', type: 'f32' }, + { name: 'speedX', type: 'f32' }, + { name: 'speedY', type: 'f32' }, + { name: 'speedZ', type: 'f32' }, + { name: 'limitX', type: 'f32' }, + { name: 'limitY', type: 'f32' }, + { name: 'limitZ', type: 'f32' } + ] + ] + + /** + * Remove a section animation + * @param id - Identifier of the animation to remove + */ + const removePacketStructure = [ + 'container', + [ + { name: 'id', type: ['pstring', { countType: 'i16' }] } + ] + ] + + registerChannel(ADD_CHANNEL, addPacketStructure, (data) => { + const { id, offset, speedX, speedY, speedZ, limitX, limitY, limitZ } = data + getThreeJsRendererMethods()?.addSectionAnimation(id, { + time: performance.now(), + speedX, + speedY, + speedZ, + currentOffsetX: offset, + currentOffsetY: offset, + currentOffsetZ: offset, + limitX: limitX === 0 ? undefined : limitX, + limitY: limitY === 0 ? undefined : limitY, + limitZ: limitZ === 0 ? undefined : limitZ + }) + }, true) + + registerChannel(REMOVE_CHANNEL, removePacketStructure, (data) => { + const { id } = data + getThreeJsRendererMethods()?.removeSectionAnimation(id) + }, true) + + console.debug('Registered section animation channels') +} + +window.testSectionAnimation = (speedY = 1) => { + const pos = bot.entity.position + const id = `${Math.floor(pos.x / 16) * 16},${Math.floor(pos.y / 16) * 16},${Math.floor(pos.z / 16) * 16}` + getThreeJsRendererMethods()?.addSectionAnimation(id, { + time: performance.now(), + speedX: 0, + speedY, + speedZ: 0, + currentOffsetX: 0, + currentOffsetY: 0, + currentOffsetZ: 0, + // limitX: 10, + // limitY: 10, + }) +} + +const registeredJeiChannel = () => { + const CHANNEL_NAME = 'minecraft-web-client:jei' + // id - string, categoryTitle - string, items - string (json array) + const packetStructure = [ + 'container', + [ + { + name: 'id', + type: ['pstring', { countType: 'i16' }] + }, + { + name: '_categoryTitle', + type: ['pstring', { countType: 'i16' }] + }, + { + name: 'items', + type: ['pstring', { countType: 'i16' }] + }, + ] + ] + + bot._client.registerChannel(CHANNEL_NAME, packetStructure, true) + + bot._client.on(CHANNEL_NAME as any, (data) => { + const { id, categoryTitle, items } = data + if (items === '') { + // remove category + jeiCustomCategories.value = jeiCustomCategories.value.filter(x => x.id !== id) + return + } + const PrismarineItem = PItem(bot.version) + jeiCustomCategories.value.push({ + id, + categoryTitle, + items: JSON.parse(items).map(x => { + const itemString = x.itemName || x.item_name || x.item || x.itemId + const itemId = loadedData.itemsByName[itemString.replace('minecraft:', '')] + if (!itemId) { + console.warn(`Could not add item ${itemString} to JEI category ${categoryTitle} because it was not found`) + return null + } + // const item = new PrismarineItem(itemId.id, x.itemCount || x.item_count || x.count || 1, x.itemDamage || x.item_damage || x.damage || 0, x.itemNbt || x.item_nbt || x.nbt || null) + return PrismarineItem.fromNotch({ + ...x, + itemId: itemId.id, + }) + }) + }) + }) + + console.debug(`registered custom channel ${CHANNEL_NAME} channel`) +} + +const registerMediaChannels = () => { + // Media Add Channel + const ADD_CHANNEL = 'minecraft-web-client:media-add' + const addPacketStructure = [ + 'container', + [ + { name: 'id', type: ['pstring', { countType: 'i16' }] }, + { name: 'x', type: 'f32' }, + { name: 'y', type: 'f32' }, + { name: 'z', type: 'f32' }, + { name: 'width', type: 'f32' }, + { name: 'height', type: 'f32' }, + { name: 'rotation', type: 'i16' }, // 0: 0° - towards positive z, 1: 90° - positive x, 2: 180° - negative z, 3: 270° - negative x (3-6 is same but double side) + { name: 'source', type: ['pstring', { countType: 'i16' }] }, + { name: 'loop', type: 'bool' }, + { name: 'volume', type: 'f32' }, // 0 + { name: '_aspectRatioMode', type: 'i16' }, // 0 + { name: '_background', type: 'i16' }, // 0 + { name: '_opacity', type: 'i16' }, // 1 + { name: '_cropXStart', type: 'f32' }, // 0 + { name: '_cropYStart', type: 'f32' }, // 0 + { name: '_cropXEnd', type: 'f32' }, // 0 + { name: '_cropYEnd', type: 'f32' }, // 0 + ] + ] + + // Media Control Channels + const PLAY_CHANNEL = 'minecraft-web-client:media-play' + const PAUSE_CHANNEL = 'minecraft-web-client:media-pause' + const SEEK_CHANNEL = 'minecraft-web-client:media-seek' + const VOLUME_CHANNEL = 'minecraft-web-client:media-volume' + const SPEED_CHANNEL = 'minecraft-web-client:media-speed' + const DESTROY_CHANNEL = 'minecraft-web-client:media-destroy' + + const noDataPacketStructure = [ + 'container', + [ + { name: 'id', type: ['pstring', { countType: 'i16' }] } + ] + ] + + const setNumberPacketStructure = [ + 'container', + [ + { name: 'id', type: ['pstring', { countType: 'i16' }] }, + { name: 'seconds', type: 'f32' } + ] + ] + + // Register channels + registerChannel(PLAY_CHANNEL, noDataPacketStructure, (data) => { + const { id } = data + getThreeJsRendererMethods()?.setVideoPlaying(id, true) + }, true) + registerChannel(PAUSE_CHANNEL, noDataPacketStructure, (data) => { + const { id } = data + getThreeJsRendererMethods()?.setVideoPlaying(id, false) + }, true) + registerChannel(SEEK_CHANNEL, setNumberPacketStructure, (data) => { + const { id, seconds } = data + getThreeJsRendererMethods()?.setVideoSeeking(id, seconds) + }, true) + registerChannel(VOLUME_CHANNEL, setNumberPacketStructure, (data) => { + const { id, volume } = data + getThreeJsRendererMethods()?.setVideoVolume(id, volume) + }, true) + registerChannel(SPEED_CHANNEL, setNumberPacketStructure, (data) => { + const { id, speed } = data + getThreeJsRendererMethods()?.setVideoSpeed(id, speed) + }, true) + registerChannel(DESTROY_CHANNEL, noDataPacketStructure, (data) => { + const { id } = data + getThreeJsRendererMethods()?.destroyMedia(id) + }, true) + + // Handle media add + registerChannel(ADD_CHANNEL, addPacketStructure, (data) => { + const { id, x, y, z, width, height, rotation, source, loop, volume, background, opacity } = data + + // Add new video + getThreeJsRendererMethods()?.addMedia(id, { + position: { x, y, z }, + size: { width, height }, + // side: 'towards', + src: source, + rotation: rotation as 0 | 1 | 2 | 3, + doubleSide: false, + background, + opacity: opacity / 100, + allowOrigins: options.remoteContentNotSameOrigin === false ? [getCurrentTopDomain()] : options.remoteContentNotSameOrigin, + loop, + volume + }) + }) + + // --- + + // Video interaction channel + const interactionPacketStructure = [ + 'container', + [ + { name: 'id', type: ['pstring', { countType: 'i16' }] }, + { name: 'x', type: 'f32' }, + { name: 'y', type: 'f32' }, + { name: 'isRightClick', type: 'bool' } + ] + ] + + bot._client.registerChannel(MEDIA_INTERACTION_CHANNEL, interactionPacketStructure, true) + + // Media play channel + bot._client.registerChannel(MEDIA_PLAY_CHANNEL_CLIENTBOUND, noDataPacketStructure, true) + const mediaStopPacketStructure = [ + 'container', + [ + { name: 'id', type: ['pstring', { countType: 'i16' }] }, + // ended - emitted even when loop is true (will continue playing) + // error: ... + // stalled - connection drops, server stops sending data + // waiting - connection is slow, server is sending data, but not fast enough (buffering) + // control + { name: 'reason', type: ['pstring', { countType: 'i16' }] }, + { name: 'time', type: 'f32' } + ] + ] + bot._client.registerChannel(MEDIA_STOP_CHANNEL_CLIENTBOUND, mediaStopPacketStructure, true) + + console.debug('Registered media channels') +} + +const MEDIA_INTERACTION_CHANNEL = 'minecraft-web-client:media-interaction' +const MEDIA_PLAY_CHANNEL_CLIENTBOUND = 'minecraft-web-client:media-play' +const MEDIA_STOP_CHANNEL_CLIENTBOUND = 'minecraft-web-client:media-stop' + +export const sendVideoInteraction = (id: string, x: number, y: number, isRightClick: boolean) => { + bot._client.writeChannel(MEDIA_INTERACTION_CHANNEL, { id, x, y, isRightClick }) +} + +export const sendVideoPlay = (id: string) => { + bot._client.writeChannel(MEDIA_PLAY_CHANNEL_CLIENTBOUND, { id }) +} + +export const sendVideoStop = (id: string, reason: string, time: number) => { + bot._client.writeChannel(MEDIA_STOP_CHANNEL_CLIENTBOUND, { id, reason, time }) +} + +export const videoCursorInteraction = () => { + const { intersectMedia } = appViewer.rendererState.world + if (!intersectMedia) return null + return intersectMedia +} +window.videoCursorInteraction = videoCursorInteraction + +const addTestVideo = (rotation = 0 as 0 | 1 | 2 | 3, scale = 1, isImage = false) => { + const block = window.cursorBlockRel() + if (!block) return + const { position: startPosition } = block + + // Add video with proper positioning + getThreeJsRendererMethods()?.addMedia('test-video', { + position: { + x: startPosition.x, + y: startPosition.y + 1, + z: startPosition.z + }, + size: { + width: scale, + height: scale + }, + src: isImage ? 'https://bucket.mcraft.fun/test_image.png' : 'https://bucket.mcraft.fun/test_video.mp4', + rotation, + // doubleSide: true, + background: 0x00_00_00, // Black color + // TODO broken + // uvMapping: { + // startU: 0, + // endU: 1, + // startV: 0, + // endV: 1 + // }, + opacity: 1, + allowOrigins: true, + }) +} +window.addTestVideo = addTestVideo + +function getCurrentTopDomain (): string { + const { hostname } = location + // Split hostname into parts + const parts = hostname.split('.') + + // Handle special cases like co.uk, com.br, etc. + if (parts.length > 2) { + // Check for common country codes with additional segments + if (parts.at(-2) === 'co' || + parts.at(-2) === 'com' || + parts.at(-2) === 'org' || + parts.at(-2) === 'gov') { + // Return last 3 parts (e.g., example.co.uk) + return parts.slice(-3).join('.') + } + } + + // Return last 2 parts (e.g., example.com) + return parts.slice(-2).join('.') +} diff --git a/src/customClient.js b/src/customClient.js index e349a837..b1a99904 100644 --- a/src/customClient.js +++ b/src/customClient.js @@ -1,18 +1,19 @@ +//@ts-check +import * as nbt from 'prismarine-nbt' import { options } from './optionsStorage' -//@ts-check const { EventEmitter } = require('events') const debug = require('debug')('minecraft-protocol') const states = require('minecraft-protocol/src/states') window.serverDataChannel ??= {} export const customCommunication = { - sendData (data) { + sendData(data) { setTimeout(() => { window.serverDataChannel[this.isServer ? 'emitClient' : 'emitServer'](data) }) }, - receiverSetup (processData) { + receiverSetup(processData) { window.serverDataChannel[this.isServer ? 'emitServer' : 'emitClient'] = (data) => { processData(data) } @@ -20,18 +21,18 @@ export const customCommunication = { } class CustomChannelClient extends EventEmitter { - constructor (isServer, version) { + constructor(isServer, version) { super() this.version = version this.isServer = !!isServer this.state = states.HANDSHAKING } - get state () { + get state() { return this.protocolState } - setSerializer (state) { + setSerializer(state) { customCommunication.receiverSetup.call(this, (/** @type {{name, params, state?}} */parsed) => { if (!options.excludeCommunicationDebugEvents.includes(parsed.name)) { debug(`receive in ${this.isServer ? 'server' : 'client'}: ${parsed.name}`) @@ -42,7 +43,7 @@ class CustomChannelClient extends EventEmitter { } // eslint-disable-next-line @typescript-eslint/adjacent-overload-signatures, grouped-accessor-pairs - set state (newProperty) { + set state(newProperty) { const oldProperty = this.protocolState this.protocolState = newProperty @@ -51,13 +52,25 @@ class CustomChannelClient extends EventEmitter { this.emit('state', newProperty, oldProperty) } - end (reason) { - this._endReason = reason + end(endReason, fullReason) { + // eslint-disable-next-line unicorn/no-this-assignment + const client = this + if (client.state === states.PLAY) { + fullReason ||= loadedData.supportFeature('chatPacketsUseNbtComponents') + ? nbt.comp({ text: nbt.string(endReason) }) + : JSON.stringify({ text: endReason }) + client.write('kick_disconnect', { reason: fullReason }) + } else if (client.state === states.LOGIN) { + fullReason ||= JSON.stringify({ text: endReason }) + client.write('disconnect', { reason: fullReason }) + } + + this._endReason = endReason this.emit('end', this._endReason) // still emits on server side only, doesn't send anything to our client } - write (name, params) { - if(!options.excludeCommunicationDebugEvents.includes(name)) { + write(name, params) { + if (!options.excludeCommunicationDebugEvents.includes(name)) { debug(`[${this.state}] from ${this.isServer ? 'server' : 'client'}: ` + name) debug(params) } @@ -66,11 +79,11 @@ class CustomChannelClient extends EventEmitter { customCommunication.sendData.call(this, { name, params, state: this.state }) } - writeBundle (packets) { + writeBundle(packets) { // no-op } - writeRaw (buffer) { + writeRaw(buffer) { // no-op } } diff --git a/src/customCommands.ts b/src/customCommands.ts index eddfc89e..75c13f68 100644 --- a/src/customCommands.ts +++ b/src/customCommands.ts @@ -59,7 +59,7 @@ export const customCommandsConfig = { } ], handler ([setting, action, value]) { - if (action === 'toggle') { + if (action === 'toggle' || action === undefined) { const value = options[setting] const config = tryFindOptionConfig(setting) if (config && 'values' in config && config.values) { diff --git a/src/dayCycle.ts b/src/dayCycle.ts deleted file mode 100644 index f092c465..00000000 --- a/src/dayCycle.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { options } from './optionsStorage' -import { assertDefined } from './utils' -import { updateBackground } from './water' - -export default () => { - const timeUpdated = () => { - assertDefined(viewer) - // 0 morning - const dayTotal = 24_000 - const evening = 11_500 - const night = 13_500 - const morningStart = 23_000 - const morningEnd = 23_961 - const timeProgress = options.dayCycleAndLighting ? bot.time.timeOfDay : 0 - - // todo check actual colors - const dayColorRainy = { r: 111 / 255, g: 156 / 255, b: 236 / 255 } - // todo yes, we should make animations (and rain) - // eslint-disable-next-line unicorn/numeric-separators-style - const dayColor = bot.isRaining ? dayColorRainy : { r: 0.6784313725490196, g: 0.8470588235294118, b: 0.9019607843137255 } // lightblue - // let newColor = dayColor - let int = 1 - if (timeProgress < evening) { - // stay dayily - } else if (timeProgress < night) { - const progressNorm = timeProgress - evening - const progressMax = night - evening - int = 1 - progressNorm / progressMax - } else if (timeProgress < morningStart) { - int = 0 - } else if (timeProgress < morningEnd) { - const progressNorm = timeProgress - morningStart - const progressMax = night - morningEnd - int = progressNorm / progressMax - } - // todo need to think wisely how to set these values & also move directional light around! - const colorInt = Math.max(int, 0.1) - updateBackground({ r: dayColor.r * colorInt, g: dayColor.g * colorInt, b: dayColor.b * colorInt }) - if (!options.newVersionsLighting && bot.supportFeature('blockStateId')) { - viewer.ambientLight.intensity = Math.max(int, 0.25) - viewer.directionalLight.intensity = Math.min(int, 0.5) - } - } - - bot.on('time', timeUpdated) - timeUpdated() -} diff --git a/src/defaultLocalServerOptions.js b/src/defaultLocalServerOptions.js index 8e294616..3b93910d 100644 --- a/src/defaultLocalServerOptions.js +++ b/src/defaultLocalServerOptions.js @@ -8,6 +8,7 @@ module.exports = { 'gameMode': 0, 'difficulty': 0, 'worldFolder': 'world', + 'pluginsFolder': true, // todo set sid, disable entities auto-spawn 'generation': { // grass_field @@ -28,11 +29,11 @@ module.exports = { 'view-distance': 2, 'player-list-text': { 'header': 'Flying squid', - 'footer': 'Test server' + 'footer': 'Integrated server' }, keepAlive: false, 'everybody-op': true, 'max-entities': 100, - 'version': '1.14.4', - versionMajor: '1.14' + 'version': '1.18', + versionMajor: '1.18' } diff --git a/src/defaultOptions.ts b/src/defaultOptions.ts new file mode 100644 index 00000000..48c1cfad --- /dev/null +++ b/src/defaultOptions.ts @@ -0,0 +1,159 @@ +export const defaultOptions = { + renderDistance: 3, + keepChunksDistance: 1, + multiplayerRenderDistance: 3, + closeConfirmation: true, + autoFullScreen: false, + mouseRawInput: true, + autoExitFullscreen: false, + localUsername: 'wanderer', + mouseSensX: 50, + mouseSensY: -1, + chatWidth: 320, + chatHeight: 180, + chatScale: 100, + chatOpacity: 100, + chatOpacityOpened: 100, + messagesLimit: 200, + volume: 50, + enableMusic: true, + musicVolume: 50, + // fov: 70, + fov: 75, + defaultPerspective: 'first_person' as 'first_person' | 'third_person_back' | 'third_person_front', + guiScale: 3, + autoRequestCompletions: true, + touchButtonsSize: 40, + touchButtonsOpacity: 80, + touchButtonsPosition: 12, + touchControlsPositions: getDefaultTouchControlsPositions(), + touchControlsSize: getTouchControlsSize(), + touchMovementType: 'modern' as 'modern' | 'classic', + touchInteractionType: 'classic' as 'classic' | 'buttons', + gpuPreference: 'default' as 'default' | 'high-performance' | 'low-power', + backgroundRendering: '20fps' as 'full' | '20fps' | '5fps', + /** @unstable */ + disableAssets: false, + /** @unstable */ + debugLogNotFrequentPackets: false, + unimplementedContainers: false, + dayCycleAndLighting: true, + loadPlayerSkins: true, + renderEars: true, + lowMemoryMode: false, + starfieldRendering: true, + defaultSkybox: true, + enabledResourcepack: null as string | null, + useVersionsTextures: 'latest', + serverResourcePacks: 'prompt' as 'prompt' | 'always' | 'never', + showHand: true, + viewBobbing: true, + displayRecordButton: true, + packetsLoggerPreset: 'all' as 'all' | 'no-buffers', + serversAutoVersionSelect: 'auto' as 'auto' | 'latest' | '1.20.4' | string, + customChannels: false, + remoteContentNotSameOrigin: false as boolean | string[], + packetsRecordingAutoStart: false, + language: 'auto', + preciseMouseInput: false, + // todo ui setting, maybe enable by default? + waitForChunksRender: false as 'sp-only' | boolean, + jeiEnabled: true as boolean | Array<'creative' | 'survival' | 'adventure' | 'spectator'>, + modsSupport: false, + modsAutoUpdate: 'check' as 'check' | 'never' | 'always', + modsUpdatePeriodCheck: 24, // hours + preventBackgroundTimeoutKick: false, + preventSleep: false, + debugContro: false, + debugChatScroll: false, + chatVanillaRestrictions: true, + debugResponseTimeIndicator: false, + chatPingExtension: true, + // antiAliasing: false, + topRightTimeDisplay: 'only-fullscreen' as 'only-fullscreen' | 'always' | 'never', + + clipWorldBelowY: undefined as undefined | number, // will be removed + disableSignsMapsSupport: false, + singleplayerAutoSave: false, + showChunkBorders: false, // todo rename option + frameLimit: false as number | false, + alwaysBackupWorldBeforeLoading: undefined as boolean | undefined | null, + alwaysShowMobileControls: false, + excludeCommunicationDebugEvents: [] as string[], + preventDevReloadWhilePlaying: false, + numWorkers: 4, + localServerOptions: { + gameMode: 1 + } as any, + saveLoginPassword: 'prompt' as 'prompt' | 'never' | 'always', + preferLoadReadonly: false, + experimentalClientSelfReload: false, + remoteSoundsSupport: false, + remoteSoundsLoadTimeout: 500, + disableLoadPrompts: false, + guestUsername: 'guest', + askGuestName: true, + errorReporting: true, + /** Actually might be useful */ + showCursorBlockInSpectator: false, + renderEntities: true, + smoothLighting: true, + newVersionsLighting: false, + chatSelect: true, + autoJump: 'auto' as 'auto' | 'always' | 'never', + autoParkour: false, + vrSupport: true, // doesn't directly affect the VR mode, should only disable the button which is annoying to android users + vrPageGameRendering: false, + renderDebug: 'basic' as 'none' | 'advanced' | 'basic', + rendererPerfDebugOverlay: false, + + // advanced bot options + autoRespawn: false, + mutedSounds: [] as string[], + plugins: [] as Array<{ enabled: boolean, name: string, description: string, script: string }>, + /** Wether to popup sign editor on server action */ + autoSignEditor: true, + wysiwygSignEditor: 'auto' as 'auto' | 'always' | 'never', + showMinimap: 'never' as 'always' | 'singleplayer' | 'never', + minimapOptimizations: true, + displayBossBars: true, + disabledUiParts: [] as string[], + neighborChunkUpdates: true, + highlightBlockColor: 'auto' as 'auto' | 'blue' | 'classic', + activeRenderer: 'threejs', + rendererSharedOptions: { + _experimentalSmoothChunkLoading: true, + _renderByChunks: false + } +} + +function getDefaultTouchControlsPositions () { + return { + action: [ + 70, + 76 + ], + sneak: [ + 84, + 76 + ], + break: [ + 70, + 57 + ], + jump: [ + 84, + 57 + ], + } as Record +} + +function getTouchControlsSize () { + return { + joystick: 55, + action: 36, + break: 36, + jump: 36, + sneak: 36, + } +} diff --git a/src/devReload.ts b/src/devReload.ts index 19e50263..e778d8d4 100644 --- a/src/devReload.ts +++ b/src/devReload.ts @@ -1,45 +1,11 @@ -import { isMobile } from 'prismarine-viewer/viewer/lib/simpleUtils' -import { WorldRendererThree } from 'prismarine-viewer/viewer/lib/worldrendererThree' +import { isMobile } from 'renderer/viewer/lib/simpleUtils' if (process.env.NODE_ENV === 'development') { - if (sessionStorage.lastReload) { - const [rebuild, reloadStart] = sessionStorage.lastReload.split(',') - const now = Date.now() - console.log(`rebuild + reload:`, `${+rebuild} + ${now - reloadStart} = ${((+rebuild + (now - reloadStart)) / 1000).toFixed(1)}s`) - sessionStorage.lastReload = '' - } - - const autoRefresh = () => { - window.noAutoReload ??= false - new EventSource('/esbuild').onmessage = async ({ data: _data }) => { - if (!_data) return - const data = JSON.parse(_data) - if (data.update) { - console.log('[esbuild] Page is outdated') - document.title = `[O] ${document.title}` - if (window.noAutoReload || localStorage.noAutoReload) return - if (localStorage.autoReloadVisible && document.visibilityState !== 'visible') return - sessionStorage.lastReload = `${data.update.time},${Date.now()}` - location.reload() - } - if (data.replace) { - console.log('[esbuild hmr] Reloading', data.replace.type, data.replace.path) - switch (data.replace.type) { - case 'mesher': { - if (!worldView || !viewer.world.version || !(viewer.world instanceof WorldRendererThree)) return - void viewer.world.doHmr() - } - } - } - } - } - autoRefresh() - // mobile devtools if (isMobile()) { // can be changed to require('eruda') //@ts-expect-error void import('https://cdn.skypack.dev/eruda').then(({ default: eruda }) => eruda.init()) - console.log('JS Loaded in', Date.now() - window.startLoad) } } +console.log('JS Loaded in', Date.now() - window.startLoad) diff --git a/src/devtools.ts b/src/devtools.ts index 4dbeb51d..1f8ef8e8 100644 --- a/src/devtools.ts +++ b/src/devtools.ts @@ -1,18 +1,30 @@ // global variables useful for debugging -import { WorldRendererThree } from 'prismarine-viewer/viewer/lib/worldrendererThree' -import { getEntityCursor } from './worldInteractions' +import fs from 'fs' +import { WorldRendererThree } from 'renderer/viewer/three/worldrendererThree' +import { enable, disable, enabled } from 'debug' +import { Vec3 } from 'vec3' -// Object.defineProperty(window, 'cursorBlock', ) +customEvents.on('mineflayerBotCreated', () => { + window.debugServerPacketNames = Object.fromEntries(Object.keys(loadedData.protocol.play.toClient.types).map(name => { + name = name.replace('packet_', '') + return [name, name] + })) + window.debugClientPacketNames = Object.fromEntries(Object.keys(loadedData.protocol.play.toServer.types).map(name => { + name = name.replace('packet_', '') + return [name, name] + })) +}) +window.Vec3 = Vec3 window.cursorBlockRel = (x = 0, y = 0, z = 0) => { const newPos = bot.blockAtCursor(5)?.position.offset(x, y, z) if (!newPos) return return bot.world.getBlock(newPos) } -window.cursorEntity = () => { - return getEntityCursor() +window.entityCursor = () => { + return bot.mouse.getCursorState().entity } // wanderer @@ -20,26 +32,293 @@ window.inspectPlayer = () => require('fs').promises.readFile('/world/playerdata/ Object.defineProperty(window, 'debugSceneChunks', { get () { - return (viewer.world as WorldRendererThree).getLoadedChunksRelative?.(bot.entity.position, true) + if (!(window.world instanceof WorldRendererThree)) return undefined + return (window.world)?.getLoadedChunksRelative?.(bot.entity.position, true) }, }) +window.chunkKey = (xRel = 0, zRel = 0) => { + const pos = bot.entity.position + return `${(Math.floor(pos.x / 16) + xRel) * 16},${(Math.floor(pos.z / 16) + zRel) * 16}` +} + +window.sectionKey = (xRel = 0, yRel = 0, zRel = 0) => { + const pos = bot.entity.position + return `${(Math.floor(pos.x / 16) + xRel) * 16},${(Math.floor(pos.y / 16) + yRel) * 16},${(Math.floor(pos.z / 16) + zRel) * 16}` +} + +window.keys = (obj) => Object.keys(obj) +window.values = (obj) => Object.values(obj) + window.len = (obj) => Object.keys(obj).length -window.inspectPacket = (packetName, full = false) => { - const listener = (...args) => console.log('packet', packetName, full ? args : args[0]) +customEvents.on('gameLoaded', () => { + bot._client.on('packet', (data, { name }) => { + if (sessionStorage.ignorePackets?.includes(name)) { + console.log('ignoring packet', name) + const oldEmit = bot._client.emit + let i = 0 + // ignore next 3 emits + //@ts-expect-error + bot._client.emit = (...args) => { + if (i++ === 3) { + oldEmit.apply(bot._client, args) + bot._client.emit = oldEmit + } + } + } + }) +}) + +window.inspectPacket = (packetName, isFromClient = false, fullOrListener: boolean | ((...args) => void) = false) => { + if (typeof isFromClient === 'function') { + fullOrListener = isFromClient + isFromClient = false + } + const listener = typeof fullOrListener === 'function' + ? (name, ...args) => fullOrListener(...args, name) + : (name, ...args) => { + const displayName = name === packetName ? name : `${name} (${packetName})` + console.log('packet', displayName, fullOrListener ? args : args[0]) + } + + // Pre-compile regex if using wildcards + const pattern = typeof packetName === 'string' && packetName.includes('*') + ? new RegExp('^' + packetName.replaceAll('*', '.*') + '$') + : null + + const packetNameListener = (name, data) => { + if (pattern) { + if (pattern.test(name)) { + listener(name, data) + } + } else if (name === packetName) { + listener(name, data) + } + } + const packetListener = (data, { name }) => { + packetNameListener(name, data) + } + const attach = () => { - bot?.on(packetName, listener) + if (isFromClient) { + bot?._client.prependListener('writePacket', packetNameListener) + } else { + bot?._client.prependListener('packet_name', packetNameListener) + bot?._client.prependListener('packet', packetListener) + } + } + const detach = () => { + if (isFromClient) { + bot?._client.removeListener('writePacket', packetNameListener) + } else { + bot?._client.removeListener('packet_name', packetNameListener) + bot?._client.removeListener('packet', packetListener) + } } attach() customEvents.on('mineflayerBotCreated', attach) + const returnobj = {} Object.defineProperty(returnobj, 'detach', { get () { - bot?.removeListener(packetName, listener) + detach() customEvents.removeListener('mineflayerBotCreated', attach) return true }, }) return returnobj } + +window.downloadFile = async (path: string) => { + if (!path.startsWith('/') && localServer) path = `${localServer.options.worldFolder}/${path}` + const data = await fs.promises.readFile(path) + const blob = new Blob([data], { type: 'application/octet-stream' }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = path.split('/').at(-1)! + a.click() + URL.revokeObjectURL(url) +} + +Object.defineProperty(window, 'debugToggle', { + get () { + localStorage.debug = localStorage.debug === '*' ? '' : '*' + if (enabled('*')) { + disable() + return 'disabled debug' + } else { + enable('*') + return 'enabled debug' + } + }, + set (v) { + enable(v) + localStorage.debug = v + console.log('Enabled debug for', v) + } +}) + +customEvents.on('gameLoaded', () => { + window.holdingBlock = (window.world as WorldRendererThree | undefined)?.holdingBlock +}) + +window.clearStorage = (...keysToKeep: string[]) => { + for (let i = 0; i < localStorage.length; i++) { + const key = localStorage.key(i) + if (key && !keysToKeep.includes(key)) { + localStorage.removeItem(key) + } + } + return `Cleared ${localStorage.length - keysToKeep.length} items from localStorage. Kept: ${keysToKeep.join(', ')}` +} + + +// PERF DEBUG + +// for advanced debugging, use with watch expression + +window.statsPerSecAvg = {} +let currentStatsPerSec = {} as Record +const waitingStatsPerSec = {} +window.markStart = (label) => { + waitingStatsPerSec[label] ??= [] + waitingStatsPerSec[label][0] = performance.now() +} +window.markEnd = (label) => { + if (!waitingStatsPerSec[label]?.[0]) return + currentStatsPerSec[label] ??= [] + currentStatsPerSec[label].push(performance.now() - waitingStatsPerSec[label][0]) + delete waitingStatsPerSec[label] +} +const updateStatsPerSecAvg = () => { + window.statsPerSecAvg = Object.fromEntries(Object.entries(currentStatsPerSec).map(([key, value]) => { + return [key, { + avg: value.reduce((a, b) => a + b, 0) / value.length, + count: value.length + }] + })) + currentStatsPerSec = {} +} + + +window.statsPerSec = {} +let statsPerSecCurrent = {} +let lastReset = performance.now() +window.addStatPerSec = (name) => { + statsPerSecCurrent[name] ??= 0 + statsPerSecCurrent[name]++ +} +window.statsPerSecCurrent = statsPerSecCurrent +setInterval(() => { + window.statsPerSec = { duration: Math.floor(performance.now() - lastReset), ...statsPerSecCurrent, } + statsPerSecCurrent = {} + window.statsPerSecCurrent = statsPerSecCurrent + updateStatsPerSecAvg() + lastReset = performance.now() +}, 1000) + +// --- + +// Add type declaration for performance.memory +declare global { + interface Performance { + memory?: { + usedJSHeapSize: number + totalJSHeapSize: number + jsHeapSizeLimit: number + } + } +} + +// Performance metrics WebSocket client +let ws: WebSocket | null = null +let wsReconnectTimeout: NodeJS.Timeout | null = null +let metricsInterval: NodeJS.Timeout | null = null + +// Start collecting metrics immediately +const startTime = performance.now() + +function collectAndSendMetrics () { + if (!ws || ws.readyState !== WebSocket.OPEN) return + + const metrics = { + loadTime: performance.now() - startTime, + memoryUsage: (performance.memory?.usedJSHeapSize ?? 0) / 1024 / 1024, + timestamp: Date.now() + } + + ws.send(JSON.stringify(metrics)) +} + +function getWebSocketUrl () { + const wsPort = process.env.WS_PORT + if (!wsPort) return null + + const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:' + const { hostname } = window.location + return `${protocol}//${hostname}:${wsPort}` +} + +function connectWebSocket () { + if (ws) return + + const wsUrl = getWebSocketUrl() + if (!wsUrl) { + return + } + + ws = new WebSocket(wsUrl) + + ws.onopen = () => { + console.log('Connected to metrics server') + if (wsReconnectTimeout) { + clearTimeout(wsReconnectTimeout) + wsReconnectTimeout = null + } + + // Start sending metrics immediately after connection + collectAndSendMetrics() + + // Clear existing interval if any + if (metricsInterval) { + clearInterval(metricsInterval) + } + + // Set new interval + metricsInterval = setInterval(collectAndSendMetrics, 500) + } + + ws.onclose = () => { + console.log('Disconnected from metrics server') + ws = null + + // Clear metrics interval + if (metricsInterval) { + clearInterval(metricsInterval) + metricsInterval = null + } + + // Try to reconnect after 3 seconds + wsReconnectTimeout = setTimeout(connectWebSocket, 3000) + } + + ws.onerror = (error) => { + console.error('WebSocket error:', error) + } +} + +// Connect immediately +connectWebSocket() + +// Add command to request current metrics +window.requestMetrics = () => { + const metrics = { + loadTime: performance.now() - startTime, + memoryUsage: (performance.memory?.usedJSHeapSize ?? 0) / 1024 / 1024, + timestamp: Date.now() + } + console.log('Current metrics:', metrics) + return metrics +} diff --git a/src/downloadAndOpenFile.ts b/src/downloadAndOpenFile.ts index 7ac154fc..1ff318ff 100644 --- a/src/downloadAndOpenFile.ts +++ b/src/downloadAndOpenFile.ts @@ -1,42 +1,38 @@ import prettyBytes from 'pretty-bytes' -import { openWorldZip } from './browserfs' -import { getResourcePackName, installTexturePack, resourcePackState, updateTexturePackInstalledState } from './texturePack' -import { setLoadingScreenStatus } from './utils' +import { openWorldFromHttpDir, openWorldZip } from './browserfs' +import { getResourcePackNames, installResourcepackPack, resourcePackState, updateTexturePackInstalledState } from './resourcePack' +import { setLoadingScreenStatus } from './appStatus' +import { appQueryParams, appQueryParamsArray } from './appParams' +import { VALID_REPLAY_EXTENSIONS, openFile } from './packetsReplay/replayPackets' +import { createFullScreenProgressReporter } from './core/progressReporter' +import { ConnectOptions } from './connect' export const getFixedFilesize = (bytes: number) => { return prettyBytes(bytes, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) } +export const isInterestedInDownload = () => { + const { map, texturepack, replayFileUrl } = appQueryParams + const { mapDir } = appQueryParamsArray + return !!map || !!texturepack || !!replayFileUrl || !!mapDir +} + const inner = async () => { - const qs = new URLSearchParams(window.location.search) - let mapUrl = qs.get('map') - const texturepack = qs.get('texturepack') - // fixme - if (texturepack) mapUrl = texturepack - if (!mapUrl) return false + const { map, texturepack, replayFileUrl } = appQueryParams + const { mapDir } = appQueryParamsArray + return downloadAndOpenMapFromUrl(map, texturepack, mapDir, replayFileUrl) +} - if (texturepack) { - await updateTexturePackInstalledState() - if (resourcePackState.resourcePackInstalled) { - if (!confirm(`You are going to install a new resource pack, which will REPLACE the current one: ${await getResourcePackName()} Continue?`)) return - } - } - const name = mapUrl.slice(mapUrl.lastIndexOf('/') + 1).slice(-25) - const downloadThing = texturepack ? 'texturepack' : 'world' - setLoadingScreenStatus(`Downloading ${downloadThing} ${name}...`) +export const downloadAndOpenMapFromUrl = async (mapUrl: string | undefined, texturepackUrl: string | undefined, mapUrlDir: string[] | undefined, replayFileUrl: string | undefined, connectOptions?: Partial) => { + if (replayFileUrl) { + setLoadingScreenStatus('Downloading replay file') + const response = await fetch(replayFileUrl) + const contentLength = response.headers?.get('Content-Length') + const size = contentLength ? +contentLength : undefined + const filename = replayFileUrl.split('/').pop() - const response = await fetch(mapUrl) - const contentType = response.headers.get('Content-Type') - if (!contentType || !contentType.startsWith('application/zip')) { - alert('Invalid map file') - } - const contentLengthStr = response.headers?.get('Content-Length') - const contentLength = contentLengthStr && +contentLengthStr - setLoadingScreenStatus(`Downloading ${downloadThing} ${name}: have to download ${contentLength && getFixedFilesize(contentLength)}...`) - - let downloadedBytes = 0 - const buffer = await new Response( - new ReadableStream({ + let downloadedBytes = 0 + const buffer = await new Response(new ReadableStream({ async start (controller) { if (!response.body) throw new Error('Server returned no response!') const reader = response.body.getReader() @@ -53,29 +49,102 @@ const inner = async () => { downloadedBytes += value.byteLength // Calculate download progress as a percentage - const progress = contentLength ? (downloadedBytes / contentLength) * 100 : undefined - setLoadingScreenStatus(`Download ${downloadThing} progress: ${progress === undefined ? '?' : Math.floor(progress)}% (${getFixedFilesize(downloadedBytes)} / ${contentLength && getFixedFilesize(contentLength)})`, false, true) - + const progress = size ? (downloadedBytes / size) * 100 : undefined + setLoadingScreenStatus(`Download replay file progress: ${progress === undefined ? '?' : Math.floor(progress)}% (${getFixedFilesize(downloadedBytes)} / ${size && getFixedFilesize(size)})`, false, true) // Pass the received data to the controller controller.enqueue(value) } }, + })).arrayBuffer() + + // Convert buffer to text, handling any compression automatically + const decoder = new TextDecoder() + const contents = decoder.decode(buffer) + + openFile({ + contents, + filename, + filesize: size }) - ).arrayBuffer() - if (texturepack) { - const name = mapUrl.slice(mapUrl.lastIndexOf('/') + 1).slice(-30) - await installTexturePack(buffer, name) - } else { - await openWorldZip(buffer) + return true } + + const mapUrlDirGuess = appQueryParams.mapDirGuess + const mapUrlDirBaseUrl = appQueryParams.mapDirBaseUrl + if (mapUrlDir?.length) { + await openWorldFromHttpDir(mapUrlDir, mapUrlDirBaseUrl ?? undefined) + return true + } + + if (mapUrlDirGuess) { + // await openWorldFromHttpDir(undefined, mapUrlDirGuess) + return true + } + + // fixme + if (texturepackUrl) mapUrl = texturepackUrl + if (!mapUrl) return false + + if (texturepackUrl) { + await updateTexturePackInstalledState() + if (resourcePackState.resourcePackInstalled) { + if (!confirm(`You are going to install a new resource pack, which will REPLACE the current one: ${await getResourcePackNames()[0]} Continue?`)) return + } + } + const name = mapUrl.slice(mapUrl.lastIndexOf('/') + 1).slice(-25) + const downloadThing = texturepackUrl ? 'texturepack' : 'world' + setLoadingScreenStatus(`Downloading ${downloadThing} ${name}...`) + + const response = await fetch(mapUrl) + const contentType = response.headers.get('Content-Type') + if (!contentType || !contentType.startsWith('application/zip')) { + alert('Invalid map file') + } + const contentLengthStr = response.headers?.get('Content-Length') + const contentLength = contentLengthStr && +contentLengthStr + setLoadingScreenStatus(`Downloading ${downloadThing} ${name}: have to download ${contentLength && getFixedFilesize(contentLength)}...`) + + let downloadedBytes = 0 + const buffer = await new Response(new ReadableStream({ + async start (controller) { + if (!response.body) throw new Error('Server returned no response!') + const reader = response.body.getReader() + + // eslint-disable-next-line no-constant-condition + while (true) { + const { done, value } = await reader.read() + + if (done) { + controller.close() + break + } + + downloadedBytes += value.byteLength + + // Calculate download progress as a percentage + const progress = contentLength ? (downloadedBytes / contentLength) * 100 : undefined + setLoadingScreenStatus(`Download ${downloadThing} progress: ${progress === undefined ? '?' : Math.floor(progress)}% (${getFixedFilesize(downloadedBytes)} / ${contentLength && getFixedFilesize(contentLength)})`, false, true) + + // Pass the received data to the controller + controller.enqueue(value) + } + }, + })).arrayBuffer() + if (texturepackUrl) { + const name = mapUrl.slice(mapUrl.lastIndexOf('/') + 1).slice(-30) + await installResourcepackPack(buffer, createFullScreenProgressReporter(), name) + } else { + await openWorldZip(buffer, undefined, connectOptions) + } + return true } export default async () => { try { return await inner() } catch (err) { - setLoadingScreenStatus(`Failed to download. Either refresh page or remove map param from URL. Reason: ${err.message}`) + setLoadingScreenStatus(`Failed to download/open. Either refresh page or remove map param from URL. Reason: ${err.message}`) return true } } diff --git a/src/dragndrop.ts b/src/dragndrop.ts index 034b7b9b..5a16bc05 100644 --- a/src/dragndrop.ts +++ b/src/dragndrop.ts @@ -3,14 +3,19 @@ import fs from 'fs' import * as nbt from 'prismarine-nbt' import RegionFile from 'prismarine-provider-anvil/src/region' import { versions } from 'minecraft-data' +import { getThreeJsRendererMethods } from 'renderer/viewer/three/threeJsMethods' import { openWorldDirectory, openWorldZip } from './browserfs' import { isGameActive } from './globalState' import { showNotification } from './react/NotificationProvider' +import { openFile, VALID_REPLAY_EXTENSIONS } from './packetsReplay/replayPackets' const parseNbt = promisify(nbt.parse) const simplifyNbt = nbt.simplify window.nbt = nbt +// Supported image types for skybox +const VALID_IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.webp'] + // todo display drop zone for (const event of ['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop']) { window.addEventListener(event, (e: any) => { @@ -44,6 +49,34 @@ window.addEventListener('drop', async e => { }) async function handleDroppedFile (file: File) { + // Check for image files first when game is active + if (isGameActive(false) && VALID_IMAGE_EXTENSIONS.some(ext => file.name.toLowerCase().endsWith(ext))) { + try { + // Convert image to base64 + const reader = new FileReader() + const base64Promise = new Promise((resolve, reject) => { + reader.onload = () => resolve(reader.result as string) + reader.onerror = reject + }) + reader.readAsDataURL(file) + const base64Image = await base64Promise + + // Get ThreeJS backend methods and update skybox + const setSkyboxImage = getThreeJsRendererMethods()?.setSkyboxImage + if (setSkyboxImage) { + await setSkyboxImage(base64Image) + showNotification('Skybox updated successfully') + } else { + showNotification('Cannot update skybox - renderer does not support it') + } + return + } catch (err) { + console.error('Failed to update skybox:', err) + showNotification('Failed to update skybox', 'error') + return + } + } + if (file.name.endsWith('.zip')) { void openWorldZip(file) return @@ -53,10 +86,19 @@ async function handleDroppedFile (file: File) { alert('Rar files are not supported yet!') return } + if (VALID_REPLAY_EXTENSIONS.some(ext => file.name.endsWith(ext)) || file.name.startsWith('packets-replay')) { + const contents = await file.text() + openFile({ + contents, + filename: file.name, + filesize: file.size + }) + return + } if (file.name.endsWith('.mca')) { - const tempPath = '/data/temp.mca' + const tempPath = '/temp/temp.mca' try { - await fs.promises.writeFile(tempPath, Buffer.from(await file.arrayBuffer())) + await fs.promises.writeFile(tempPath, Buffer.from(await file.arrayBuffer()) as any) const region = new RegionFile(tempPath) await region.initialize() const chunks: Record = {} @@ -65,6 +107,8 @@ async function handleDroppedFile (file: File) { let versionDetected = false for (const [i, _] of Array.from({ length: 32 }).entries()) { for (const [k, _] of Array.from({ length: 32 }).entries()) { + // todo, may use faster reading, but features is not commonly used + // eslint-disable-next-line no-await-in-loop const nbt = await region.read(i, k) chunks[`${i},${k}`] = nbt if (nbt && !versionDetected) { diff --git a/src/entities.ts b/src/entities.ts index b238d4ea..674f91ef 100644 --- a/src/entities.ts +++ b/src/entities.ts @@ -1,16 +1,20 @@ import { Entity } from 'prismarine-entity' +import { versionToNumber } from 'renderer/viewer/common/utils' import tracker from '@nxg-org/mineflayer-tracker' import { loader as autoJumpPlugin } from '@nxg-org/mineflayer-auto-jump' import { subscribeKey } from 'valtio/utils' +import { getThreeJsRendererMethods } from 'renderer/viewer/three/threeJsMethods' +import { Team } from 'mineflayer' import { options, watchValue } from './optionsStorage' -import { miscUiState } from './globalState' +import { gameAdditionalState, miscUiState } from './globalState' +import { EntityStatus } from './mineflayer/entityStatus' const updateAutoJump = () => { if (!bot?.autoJumper) return const autoJump = options.autoParkour || (options.autoJump === 'auto' ? miscUiState.currentTouch && !miscUiState.usingGamepadInput : options.autoJump === 'always') bot.autoJumper.setOpts({ - jumpIntoWater: options.autoParkour, + // jumpIntoWater: options.autoParkour, jumpOnAllEdges: options.autoParkour, // strictBlockCollision: true, }) @@ -39,23 +43,20 @@ customEvents.on('gameLoaded', () => { bot.loadPlugin(autoJumpPlugin) updateAutoJump() - // todo cleanup (move to viewer, also shouldnt be used at all) const playerPerAnimation = {} as Record - const entityData = (e: Entity) => { + const checkEntityData = (e: Entity) => { if (!e.username) return window.debugEntityMetadata ??= {} window.debugEntityMetadata[e.username] = e - // todo entity spawn timing issue, check perf - if (viewer.entities.entities[e.id]?.playerObject) { - // todo throttle! + if (e.type === 'player') { bot.tracker.trackEntity(e) - const { playerObject } = viewer.entities.entities[e.id] - playerObject.backEquipment = e.equipment.some((item) => item?.name === 'elytra') ? 'elytra' : 'cape' - if (playerObject.cape.map === null) { - playerObject.cape.visible = false - } - // todo (easy, important) elytra flying animation - // todo cleanup states + } + } + + const trackBotEntity = () => { + // Always track the bot entity for animations + if (bot.entity) { + bot.tracker.trackEntity(bot.entity) } } @@ -68,74 +69,300 @@ customEvents.on('gameLoaded', () => { if (!tracking) continue const e = bot.entities[id] if (!e) continue - const speed = info.avgSpeed + const speed = info.avgVel const WALKING_SPEED = 0.03 const SPRINTING_SPEED = 0.18 + const isCrouched = e === bot.entity ? gameAdditionalState.isSneaking : e['crouching'] const isWalking = Math.abs(speed.x) > WALKING_SPEED || Math.abs(speed.z) > WALKING_SPEED const isSprinting = Math.abs(speed.x) > SPRINTING_SPEED || Math.abs(speed.z) > SPRINTING_SPEED - const newAnimation = isWalking ? (isSprinting ? 'running' : 'walking') : 'idle' - const username = e.username! - if (newAnimation !== playerPerAnimation[username]) { - viewer.entities.playAnimation(e.id, newAnimation) - playerPerAnimation[username] = newAnimation + + const newAnimation = + isCrouched ? (isWalking ? 'crouchWalking' : 'crouch') + : isWalking ? (isSprinting ? 'running' : 'walking') + : 'idle' + if (newAnimation !== playerPerAnimation[id]) { + // Handle bot entity animation specially (for player entity in third person) + if (e === bot.entity) { + getThreeJsRendererMethods()?.playEntityAnimation('player_entity', newAnimation) + } else { + getThreeJsRendererMethods()?.playEntityAnimation(e.id, newAnimation) + } + playerPerAnimation[id] = newAnimation } } }) bot.on('entitySwingArm', (e) => { - if (viewer.entities.entities[e.id]?.playerObject) { - viewer.entities.playAnimation(e.id, 'oneSwing') + getThreeJsRendererMethods()?.playEntityAnimation(e.id, 'oneSwing') + }) + + bot.on('botArmSwingStart', (hand) => { + if (hand === 'right') { + getThreeJsRendererMethods()?.playEntityAnimation('player_entity', 'oneSwing') } }) - const loadedSkinEntityIds = new Set() - - const playerRenderSkin = (e: Entity) => { - const mesh = viewer.entities.entities[e.id] - if (!mesh) return - if (!mesh.playerObject || !options.loadPlayerSkins) return - const MAX_DISTANCE_SKIN_LOAD = 128 - const distance = e.position.distanceTo(bot.entity.position) - if (distance < MAX_DISTANCE_SKIN_LOAD && distance < (bot.settings.viewDistance as number) * 16) { - if (viewer.entities.entities[e.id]) { - if (loadedSkinEntityIds.has(e.id)) return - loadedSkinEntityIds.add(e.id) - viewer.entities.updatePlayerSkin(e.id, e.username, true, true) - } + bot.inventory.on('updateSlot', (slot) => { + if (slot === 5 || slot === 6 || slot === 7 || slot === 8) { + const item = bot.inventory.slots[slot]! + bot.entity.equipment[slot - 3] = item + appViewer.worldView?.emit('playerEntity', bot.entity) } + }) + bot.on('heldItemChanged', () => { + const item = bot.inventory.slots[bot.quickBarSlot + 36]! + bot.entity.equipment[0] = item + appViewer.worldView?.emit('playerEntity', bot.entity) + }) + + bot._client.on('damage_event', (data) => { + const { entityId, sourceTypeId: damage } = data + getThreeJsRendererMethods()?.damageEntity(entityId, damage) + }) + + bot._client.on('entity_status', (data) => { + if (versionToNumber(bot.version) >= versionToNumber('1.19.4')) return + const { entityId, entityStatus } = data + if (entityStatus === EntityStatus.HURT) { + getThreeJsRendererMethods()?.damageEntity(entityId, entityStatus) + } + + if (entityStatus === EntityStatus.BURNED) { + updateEntityStates(entityId, true, true) + } + }) + + // on fire events + bot._client.on('entity_metadata', (data) => { + if (data.entityId !== bot.entity.id) return + handleEntityMetadata(data) + }) + + bot.on('end', () => { + if (onFireTimeout) { + clearTimeout(onFireTimeout) + } + }) + + bot.on('respawn', () => { + if (onFireTimeout) { + clearTimeout(onFireTimeout) + } + }) + + const updateCamera = (entity: Entity) => { + if (bot.game.gameMode !== 'spectator') return + bot.entity.position = entity.position.clone() + void bot.look(entity.yaw, entity.pitch, true) + bot.entity.yaw = entity.yaw + bot.entity.pitch = entity.pitch } - viewer.entities.addListener('remove', (e) => { - loadedSkinEntityIds.delete(e.id) - playerPerAnimation[e.username] = '' - bot.tracker.stopTrackingEntity(e, true) + + bot.on('entityGone', (entity) => { + bot.tracker.stopTrackingEntity(entity, true) }) bot.on('entityMoved', (e) => { - playerRenderSkin(e) - entityData(e) + checkEntityData(e) + if (appViewer.playerState.reactive.cameraSpectatingEntity === e.id) { + updateCamera(e) + } }) bot._client.on('entity_velocity', (packet) => { const e = bot.entities[packet.entityId] if (!e) return - entityData(e) - }) - - viewer.entities.addListener('add', (e) => { - if (!viewer.entities.entities[e.id]) throw new Error('mesh still not loaded') - playerRenderSkin(e) + checkEntityData(e) }) for (const entity of Object.values(bot.entities)) { if (entity !== bot.entity) { - entityData(entity) + checkEntityData(entity) } } - bot.on('entitySpawn', entityData) - bot.on('entityUpdate', entityData) - bot.on('entityEquip', entityData) + // Track bot entity initially + trackBotEntity() - watchValue(options, o => { - viewer.entities.setDebugMode(o.showChunkBorders ? 'basic' : 'none') + bot.on('entitySpawn', (e) => { + checkEntityData(e) + if (appViewer.playerState.reactive.cameraSpectatingEntity === e.id) { + updateCamera(e) + } }) + bot.on('entityUpdate', checkEntityData) + bot.on('entityEquip', checkEntityData) + + // Re-track bot entity after login + bot.on('login', () => { + setTimeout(() => { + trackBotEntity() + }) // Small delay to ensure bot.entity is properly set + }) + + bot._client.on('camera', (packet) => { + if (bot.player.entity.id === packet.cameraId) { + if (appViewer.playerState.utils.isSpectatingEntity() && appViewer.playerState.reactive.cameraSpectatingEntity) { + const entity = bot.entities[appViewer.playerState.reactive.cameraSpectatingEntity] + appViewer.playerState.reactive.cameraSpectatingEntity = undefined + if (entity) { + // do a force entity update + bot.emit('entityUpdate', entity) + } + } + } else if (appViewer.playerState.reactive.gameMode === 'spectator') { + const entity = bot.entities[packet.cameraId] + appViewer.playerState.reactive.cameraSpectatingEntity = packet.cameraId + if (entity) { + updateCamera(entity) + // do a force entity update + bot.emit('entityUpdate', entity) + } + } + }) + + const applySkinTexturesProxy = (url: string | undefined) => { + const { appConfig } = miscUiState + if (appConfig?.skinTexturesProxy) { + return url?.replace('http://textures.minecraft.net/', appConfig.skinTexturesProxy) + .replace('https://textures.minecraft.net/', appConfig.skinTexturesProxy) + } + return url + } + + // Texture override from packet properties + const updateSkin = (player: import('mineflayer').Player) => { + if (!player.uuid || !player.username || !player.skinData) return + + try { + const skinUrl = applySkinTexturesProxy(player.skinData.url) + const capeUrl = applySkinTexturesProxy((player.skinData as any).capeUrl) + + // Find entity with matching UUID and update skin + let entityId = '' + for (const [entId, entity] of Object.entries(bot.entities)) { + if (entity.uuid === player.uuid) { + entityId = entId + break + } + } + // even if not found, still record to cache + void getThreeJsRendererMethods()!.updatePlayerSkin(entityId, player.username, player.uuid, skinUrl ?? true, capeUrl) + } catch (err) { + reportError(new Error('Error applying skin texture:', { cause: err })) + } + } + + bot.on('playerJoined', updateSkin) + bot.on('playerUpdated', updateSkin) + for (const entity of Object.values(bot.players)) { + updateSkin(entity) + } + + const teamUpdated = (team: Team) => { + for (const entity of Object.values(bot.entities)) { + if (entity.type === 'player' && entity.username && team.members.includes(entity.username) || entity.uuid && team.members.includes(entity.uuid)) { + bot.emit('entityUpdate', entity) + } + } + } + bot.on('teamUpdated', teamUpdated) + for (const team of Object.values(bot.teams)) { + teamUpdated(team) + } + + const updateEntityNameTags = (team: Team) => { + for (const entity of Object.values(bot.entities)) { + const entityTeam = entity.type === 'player' && entity.username ? bot.teamMap[entity.username] : entity.uuid ? bot.teamMap[entity.uuid] : undefined + if ((entityTeam?.nameTagVisibility === 'hideForOwnTeam' && entityTeam.name === team.name) + || (entityTeam?.nameTagVisibility === 'hideForOtherTeams' && entityTeam.name !== team.name)) { + bot.emit('entityUpdate', entity) + } + } + } + + const doEntitiesNeedUpdating = (team: Team) => { + return team.nameTagVisibility === 'never' + || (team.nameTagVisibility === 'hideForOtherTeams' && appViewer.playerState.reactive.team?.team !== team.team) + || (team.nameTagVisibility === 'hideForOwnTeam' && appViewer.playerState.reactive.team?.team === team.team) + } + + bot.on('teamMemberAdded', (team: Team, members: string[]) => { + if (members.includes(bot.username) && appViewer.playerState.reactive.team?.team !== team.team) { + appViewer.playerState.reactive.team = team + // Player was added to a team, need to check if any entities need updating + updateEntityNameTags(team) + } else if (doEntitiesNeedUpdating(team)) { + // Need to update all entities that were added + for (const entity of Object.values(bot.entities)) { + if (entity.type === 'player' && entity.username && members.includes(entity.username) || entity.uuid && members.includes(entity.uuid)) { + bot.emit('entityUpdate', entity) + } + } + } + }) + + bot.on('teamMemberRemoved', (team: Team, members: string[]) => { + if (members.includes(bot.username) && appViewer.playerState.reactive.team?.team === team.team) { + appViewer.playerState.reactive.team = undefined + // Player was removed from a team, need to check if any entities need updating + updateEntityNameTags(team) + } else if (doEntitiesNeedUpdating(team)) { + // Need to update all entities that were removed + for (const entity of Object.values(bot.entities)) { + if (entity.type === 'player' && entity.username && members.includes(entity.username) || entity.uuid && members.includes(entity.uuid)) { + bot.emit('entityUpdate', entity) + } + } + } + }) + + bot.on('teamRemoved', (team: Team) => { + if (appViewer.playerState.reactive.team?.team === team?.team) { + appViewer.playerState.reactive.team = undefined + // Player's team was removed, need to update all entities that are in a team + updateEntityNameTags(team) + } + }) + }) + +// Constants +const SHARED_FLAGS_KEY = 0 +const ENTITY_FLAGS = { + ON_FIRE: 0x01, // Bit 0 + SNEAKING: 0x02, // Bit 1 + SPRINTING: 0x08, // Bit 3 + SWIMMING: 0x10, // Bit 4 + INVISIBLE: 0x20, // Bit 5 + GLOWING: 0x40, // Bit 6 + FALL_FLYING: 0x80 // Bit 7 (elytra flying) +} + +let onFireTimeout: NodeJS.Timeout | undefined +const updateEntityStates = (entityId: number, onFire: boolean, timeout?: boolean) => { + if (entityId !== bot.entity.id) return + appViewer.playerState.reactive.onFire = onFire + if (onFireTimeout) { + clearTimeout(onFireTimeout) + } + if (timeout) { + onFireTimeout = setTimeout(() => { + updateEntityStates(entityId, false, false) + }, 5000) + } +} + +// Process entity metadata packet +function handleEntityMetadata (packet: { entityId: number, metadata: Array<{ key: number, type: string, value: number }> }) { + const { entityId, metadata } = packet + + // Find shared flags in metadata + const flagsData = metadata.find(meta => meta.key === SHARED_FLAGS_KEY && + meta.type === 'byte') + + // Update fire state if flags were found + if (flagsData) { + const wasOnFire = appViewer.playerState.reactive.onFire + appViewer.playerState.reactive.onFire = (flagsData.value & ENTITY_FLAGS.ON_FIRE) !== 0 + } +} diff --git a/src/env.d.ts b/src/env.d.ts new file mode 100644 index 00000000..e565fcec --- /dev/null +++ b/src/env.d.ts @@ -0,0 +1,37 @@ +declare namespace NodeJS { + interface ProcessEnv { + // Build configuration + NODE_ENV: 'development' | 'production' + MIN_MC_VERSION?: string + MAX_MC_VERSION?: string + ALWAYS_COMPRESS_LARGE_DATA?: 'true' | 'false' + SINGLE_FILE_BUILD?: 'true' | 'false' + WS_PORT?: string + DISABLE_SERVICE_WORKER?: 'true' | 'false' + CONFIG_JSON_SOURCE?: 'BUNDLED' | 'REMOTE' + LOCAL_CONFIG_FILE?: string + BUILD_VERSION?: string + + // Build internals + GITHUB_REPOSITORY?: string + VERCEL_GIT_REPO_OWNER?: string + VERCEL_GIT_REPO_SLUG?: string + + // UI + MAIN_MENU_LINKS?: string + ALWAYS_MINIMAL_SERVER_UI?: 'true' | 'false' + + // App features + ENABLE_COOKIE_STORAGE?: string + COOKIE_STORAGE_PREFIX?: string + + // Build info. Release information + RELEASE_TAG?: string + RELEASE_LINK?: string + RELEASE_CHANGELOG?: string + + // Build info + INLINED_APP_CONFIG?: string + GITHUB_URL?: string + } +} diff --git a/src/errorLoadingScreenHelpers.ts b/src/errorLoadingScreenHelpers.ts new file mode 100644 index 00000000..2f882f89 --- /dev/null +++ b/src/errorLoadingScreenHelpers.ts @@ -0,0 +1,12 @@ +export const guessProblem = (errorMessage: string) => { + if (errorMessage.endsWith('Socket error: ECONNREFUSED')) { + return 'Most probably the server is not running.' + } +} + +export const loadingTexts = [ + 'Like the project? Give us a star on GitHub or rate us on AlternativeTo!', + 'To stay updated with the latest changes, go to the GitHub page, click on "Watch", choose "Custom", and then opt for "Releases"!', + 'Upvote features on GitHub issues to help us prioritize them!', + 'Want to contribute to the project? Check out Contributing.md on GitHub!', +] diff --git a/src/external/index.ts b/src/external/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/flyingSquidEvents.ts b/src/flyingSquidEvents.ts index fb5b00e3..7231dd27 100644 --- a/src/flyingSquidEvents.ts +++ b/src/flyingSquidEvents.ts @@ -1,4 +1,7 @@ +import { saveServer } from './flyingSquidUtils' +import { watchUnloadForCleanup } from './gameUnload' import { showModal } from './globalState' +import { options } from './optionsStorage' import { chatInputValueGlobal } from './react/Chat' import { showNotification } from './react/NotificationProvider' @@ -10,4 +13,15 @@ export default () => { showModal({ reactType: 'chat' }) }) }) + + if (options.singleplayerAutoSave) { + const autoSaveInterval = setInterval(() => { + if (options.singleplayerAutoSave) { + void saveServer(true) + } + }, 2000) + watchUnloadForCleanup(() => { + clearInterval(autoSaveInterval) + }) + } } diff --git a/src/flyingSquidUtils.ts b/src/flyingSquidUtils.ts index 1f070022..2ae0be7c 100644 --- a/src/flyingSquidUtils.ts +++ b/src/flyingSquidUtils.ts @@ -18,17 +18,20 @@ export function nameToMcOfflineUUID (name) { } export async function savePlayers (autoSave: boolean) { + if (!localServer?.players[0]) return if (autoSave && new URL(location.href).searchParams.get('noSave') === 'true') return //@ts-expect-error TODO - await localServer!.savePlayersSingleplayer() + await localServer.savePlayersSingleplayer() } // todo flying squid should expose save function instead export const saveServer = async (autoSave = true) => { if (!localServer || fsState.isReadonly) return // todo + console.time('save server') const worlds = [(localServer as any).overworld] as Array - await Promise.all([savePlayers(autoSave), ...worlds.map(async world => world.saveNow())]) + await Promise.all([localServer.writeLevelDat(), savePlayers(autoSave), ...worlds.map(async world => world.saveNow())]) + console.timeEnd('save server') } export const disconnect = async () => { if (localServer) { diff --git a/src/generatedServerPackets.ts b/src/generatedServerPackets.ts index 1c7ffa9e..3b3ce018 100644 --- a/src/generatedServerPackets.ts +++ b/src/generatedServerPackets.ts @@ -6,14 +6,7 @@ export interface ClientOnMap { } | /** 1.12.2 */ { keepAliveId: bigint; }; - login: /** 1.7 */ { - entityId: number; - gameMode: number; - dimension: number; - difficulty: number; - maxPlayers: number; - levelType: string; - } | /** 1.8 */ { + login:/** 1.8 */ { entityId: number; gameMode: number; dimension: number; @@ -148,9 +141,7 @@ export interface ClientOnMap { entityId: number; equipments: any; }; - spawn_position: /** 1.7 */ { - location: any; - } | /** 1.8 */ { + spawn_position:/** 1.8 */ { location: { x: number, y: number, z: number }; } | /** 1.17 */ { location: { x: number, y: number, z: number }; @@ -215,14 +206,7 @@ export interface ClientOnMap { death: any; portalCooldown: number; }; - position: /** 1.7 */ { - x: number; - y: number; - z: number; - yaw: number; - pitch: number; - onGround: boolean; - } | /** 1.8 */ { + position: /** 1.8 */ { x: number; y: number; z: number; @@ -905,11 +889,7 @@ export interface ClientOnMap { statistics: /** 1.7 */ { entries: any; }; - player_info: /** 1.7 */ { - playerName: string; - online: boolean; - ping: number; - } | /** 1.8 */ { + player_info: /** 1.8 */ { action: number; data: any; }; @@ -926,22 +906,13 @@ export interface ClientOnMap { length: number; matches: any; }; - scoreboard_objective: /** 1.7 */ { - name: string; - displayText: string; - action: number; - } | /** 1.8 */ { + scoreboard_objective:/** 1.8 */ { name: string; action: number; displayText: any; type: any; }; - scoreboard_score: /** 1.7 */ { - itemName: string; - action: number; - scoreName: any; - value: any; - } | /** 1.8 */ { + scoreboard_score:/** 1.8 */ { itemName: string; action: number; scoreName: string; diff --git a/src/getCollisionInteractionShapes.ts b/src/getCollisionInteractionShapes.ts new file mode 100644 index 00000000..9dead22b --- /dev/null +++ b/src/getCollisionInteractionShapes.ts @@ -0,0 +1,17 @@ +import { getRenamedData } from 'flying-squid/dist/blockRenames' +import outputInteractionShapesJson from './interactionShapesGenerated.json' +import './getCollisionShapes' + +export default () => { + customEvents.on('gameLoaded', () => { + // todo also remap block states (e.g. redstone)! + 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])) + } + interactionShapes[''] = interactionShapes['air'] + // todo make earlier + window.interactionShapes = interactionShapes + }) +} diff --git a/src/getCollisionShapes.ts b/src/getCollisionShapes.ts index 0faf5b6a..383adc0e 100644 --- a/src/getCollisionShapes.ts +++ b/src/getCollisionShapes.ts @@ -1,29 +1,14 @@ -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' // defining globally to be used in loaded data, not sure of better workaround 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])) } return collisionShapes } - -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 interactionShapes = { - ...outputInteractionShapesJson, - ...Object.fromEntries(Object.entries(outputInteractionShapesJson).map(([block, shape], i) => [renamedBlocksInteraction[i], shape])) - } - interactionShapes[''] = interactionShapes['air'] - // todo make earlier - window.interactionShapes = interactionShapes - }) -} diff --git a/src/globalDomListeners.ts b/src/globalDomListeners.ts index 866c9784..bfce0d42 100644 --- a/src/globalDomListeners.ts +++ b/src/globalDomListeners.ts @@ -1,6 +1,7 @@ import { saveServer } from './flyingSquidUtils' import { isGameActive, activeModalStack } from './globalState' import { options } from './optionsStorage' +import { isInRealGameSession } from './utils' window.addEventListener('unload', (e) => { if (!window.justReloaded) { @@ -25,6 +26,7 @@ window.addEventListener('beforeunload', (event) => { if (!isGameActive(true) && activeModalStack.at(-1)?.elem?.id !== 'chat') return if (sessionStorage.lastReload && !options.preventDevReloadWhilePlaying) return if (!options.closeConfirmation) return + if (!isInRealGameSession()) return // For major browsers doning only this is enough event.preventDefault() @@ -33,3 +35,12 @@ window.addEventListener('beforeunload', (event) => { event.returnValue = '' // Required for some browsers return 'The game is running. Are you sure you want to close this page?' }) + +window.addEventListener('contextmenu', (e) => { + const ALLOW_TAGS = ['INPUT', 'TEXTAREA', 'A'] + // allow if target is in ALLOW_TAGS or has selection text + if (ALLOW_TAGS.includes((e.target as HTMLElement)?.tagName) || window.getSelection()?.toString()) { + return + } + e.preventDefault() +}) diff --git a/src/globalState.ts b/src/globalState.ts index 4b62f8d6..b8982de7 100644 --- a/src/globalState.ts +++ b/src/globalState.ts @@ -1,12 +1,18 @@ //@ts-check import { proxy, ref, subscribe } from 'valtio' -import { pointerLock } from './utils' +import type { WorldWarp } from 'flying-squid/dist/lib/modules/warps' import type { OptionsGroupType } from './optionsGuiScheme' +import { options, disabledSettings } from './optionsStorage' +import { AppConfig } from './appConfig' // todo: refactor structure with support of hideNext=false -const notHideableModalsWithoutForce = new Set(['app-status']) +export const notHideableModalsWithoutForce = new Set([ + 'app-status', + 'divkit:nonclosable', + 'only-connect-server', +]) type Modal = ({ elem?: HTMLElement & Record } & { reactType: string }) @@ -25,45 +31,23 @@ export const activeModalStacks: Record = {} window.activeModalStack = activeModalStack -subscribe(activeModalStack, () => { - if (activeModalStack.length === 0) { - if (isGameActive(false)) { - void pointerLock.requestPointerLock() - } - } else { - document.exitPointerLock?.() - } -}) - -export const customDisplayManageKeyword = 'custom' - -const defaultModalActions = { - show (modal: Modal) { - if (modal.elem) modal.elem.style.display = 'block' - }, - hide (modal: Modal) { - if (modal.elem) modal.elem.style.display = 'none' - } -} - /** * @returns true if operation was successful */ const showModalInner = (modal: Modal) => { const cancel = modal.elem?.show?.() - if (cancel && cancel !== customDisplayManageKeyword) return false - if (cancel !== 'custom') defaultModalActions.show(modal) return true } -export const showModal = (elem: /* (HTMLElement & Record) | */{ reactType: string }) => { - const resolved = elem +export const showModal = (elem: /* (HTMLElement & Record) | */{ reactType: string } | string) => { + const resolved = typeof elem === 'string' ? { reactType: elem } : elem const curModal = activeModalStack.at(-1) - if (/* elem === curModal?.elem || */(elem.reactType && elem.reactType === curModal?.reactType) || !showModalInner(resolved)) return - if (curModal) defaultModalActions.hide(curModal) + if ((resolved.reactType && resolved.reactType === curModal?.reactType) || !showModalInner(resolved)) return activeModalStack.push(resolved) } +window.showModal = showModal + /** * * @returns true if previous modal was restored @@ -71,21 +55,21 @@ export const showModal = (elem: /* (HTMLElement & Record) | */{ re export const hideModal = (modal = activeModalStack.at(-1), data: any = undefined, options: { force?: boolean; restorePrevious?: boolean } = {}) => { const { force = false, restorePrevious = true } = options if (!modal) return - let cancel - if (modal.elem) { - cancel = modal.elem.hide?.(data) - } else if (modal.reactType) { - cancel = notHideableModalsWithoutForce.has(modal.reactType) ? !force : undefined - } - if (force && cancel !== customDisplayManageKeyword) { + let cancel = [...notHideableModalsWithoutForce].some(m => modal.reactType.startsWith(m)) ? !force : undefined + if (force) { cancel = undefined } - if (!cancel || cancel === customDisplayManageKeyword) { - if (cancel !== customDisplayManageKeyword) defaultModalActions.hide(modal) - activeModalStack.pop() + if (!cancel) { + const lastModal = activeModalStack.at(-1) + for (let i = activeModalStack.length - 1; i >= 0; i--) { + if (activeModalStack[i].reactType === modal.reactType) { + activeModalStack.splice(i, 1) + break + } + } const newModal = activeModalStack.at(-1) - if (newModal && restorePrevious) { + if (newModal && lastModal !== newModal && restorePrevious) { // would be great to ignore cancel I guess? showModalInner(newModal) } @@ -99,10 +83,21 @@ export const hideCurrentModal = (_data?, onHide?: () => void) => { } } +export const hideAllModals = () => { + while (activeModalStack.length > 0) { + if (!hideModal()) break + } + return activeModalStack.length === 0 +} + export const openOptionsMenu = (group: OptionsGroupType) => { showModal({ reactType: `options-${group}` }) } +subscribe(activeModalStack, () => { + document.body.style.setProperty('--has-modals-z', activeModalStack.length ? '-1' : null) +}) + // --- export const currentContextMenu = proxy({ items: [] as ContextMenuItem[] | null, x: 0, y: 0 }) @@ -117,34 +112,27 @@ export const showContextmenu = (items: ContextMenuItem[], { clientX, clientY }) // --- -export type AppConfig = { - // defaultHost?: string - // defaultHostSave?: string - defaultProxy?: string - // defaultProxySave?: string - // defaultVersion?: string - promoteServers?: Array<{ ip, description, version?}> - mapsProvider?: string -} - 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, + wanOpening: false, /** wether game hud is shown (in playing state) */ gameLoaded: false, + showUI: true, + showDebugHud: false, loadedServerIndex: '', /** currently trying to load or loaded mc version, after all data is loaded */ loadedDataVersion: null as string | null, - appLoaded: false, + fsReady: false, + singleplayerAvailable: false, usingGamepadInput: false, appConfig: null as AppConfig | null, displaySearchInput: false, + displayFullmap: false }) export const isGameActive = (foregroundCheck: boolean) => { @@ -159,8 +147,13 @@ export const gameAdditionalState = proxy({ isFlying: false, isSprinting: false, isSneaking: false, + isZooming: false, + warps: [] as WorldWarp[], + noConnection: false, + poorConnection: false, + viewerConnection: false, + + usingServerResourcePack: false, }) window.gameAdditionalState = gameAdditionalState - -// todo restore auto-save on interval for player data! (or implement it in flying squid since there is already auto-save for world) diff --git a/src/globals.d.ts b/src/globals.d.ts index 6a38a21d..7a2c6f1f 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -1,33 +1,56 @@ /// -declare const THREE: typeof import('three') // todo make optional declare const bot: Omit & { - world: import('prismarine-world').world.WorldSync - _client: Omit & { - write: typeof import('./generatedClientPackets').clientWrite - on: typeof import('./generatedServerPackets').clientOn - } + world: Omit & { + getBlock: (pos: import('vec3').Vec3) => import('prismarine-block').Block | null + } + _client: Omit & { + write: typeof import('./generatedClientPackets').clientWrite + on: typeof import('./generatedServerPackets').clientOn + } } declare const __type_bot: typeof bot -declare const viewer: import('prismarine-viewer/viewer/lib/viewer').Viewer -declare const worldView: import('prismarine-viewer/viewer/lib/worldDataEmitter').WorldDataEmitter | undefined +declare const appViewer: import('./appViewer').AppViewer +declare const worldView: import('renderer/viewer/lib/worldDataEmitter').WorldDataEmitter | undefined +declare const addStatPerSec: (name: string) => void 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 - digStart () - gameLoaded (): void - mineflayerBotCreated (): void - search (q: string): void + /** Singleplayer load requested */ + singleplayer (): void + digStart (): void + gameLoaded (): void + mineflayerBotCreated (): void + search (q: string): void + activateItem (item: Item, slot: number, offhand: boolean): void + hurtAnimation (yaw?: number): void + customChannelRegister (channel: string, parser: any): void }> declare const beforeRenderFrame: Array<() => void> +declare const translate: (key: T) => T + +// API LAYER +declare const toggleMicrophoneMuted: undefined | (() => void) +declare const translateText: undefined | ((text: string) => string) declare interface Document { - exitPointerLock?(): void + exitPointerLock?(): void +} + +declare module '*.frag' { + const png: string + export default png +} +declare module '*.vert' { + const png: string + export default png +} +declare module '*.wgsl' { + const png: string + export default png } declare interface Window extends Record { } diff --git a/src/globals.js b/src/globals.js index f9a1053c..11351555 100644 --- a/src/globals.js +++ b/src/globals.js @@ -1,9 +1,16 @@ import EventEmitter from 'events' +window.reportError = window.reportError ?? console.error window.bot = undefined window.THREE = undefined window.localServer = undefined window.worldView = undefined -window.viewer = undefined +window.viewer = undefined // legacy +window.appViewer = undefined window.loadedData = undefined window.customEvents = new EventEmitter() +window.customEvents.setMaxListeners(10_000) +window.translate = (key) => { + if (typeof key !== 'string') return key + return window.translateText?.(key) ?? key +} diff --git a/src/googledrive.ts b/src/googledrive.ts index 3846add3..5e5e9ae9 100644 --- a/src/googledrive.ts +++ b/src/googledrive.ts @@ -1,11 +1,11 @@ import { GoogleOAuthProvider, useGoogleLogin } from '@react-oauth/google' import { proxy, ref, subscribe } from 'valtio' import React from 'react' -import { loadScript } from 'prismarine-viewer/viewer/lib/utils' +import { loadScript } from 'renderer/viewer/lib/utils' import { loadGoogleDriveApi, loadInMemorySave } from './react/SingleplayerProvider' -import { setLoadingScreenStatus } from './utils' -import { mountGoogleDriveFolder } from './browserfs' +import { setLoadingScreenStatus } from './appStatus' import { showOptionsModal } from './react/SelectOption' +import { appQueryParams } from './appParams' const CLIENT_ID = '137156026346-igv2gkjsj2hlid92rs3q7cjjnc77s132.apps.googleusercontent.com' // const CLIENT_ID = process.env.GOOGLE_CLIENT_ID @@ -45,7 +45,7 @@ export const useGoogleLogIn = () => { } export const possiblyHandleStateVariable = async () => { - const stateParam = new URLSearchParams(window.location.search).get('state') + const stateParam = appQueryParams.state if (!stateParam) return setLoadingScreenStatus('Opening world in read only mode, waiting for login...') await loadGoogleDriveApi() @@ -66,7 +66,7 @@ export const possiblyHandleStateVariable = async () => { } setLoadingScreenStatus('Opening world in read only mode...') googleProviderState.accessToken = response.access_token - await mountGoogleDriveFolder(true, parsed.ids[0]) + // await mountGoogleDriveFolder(true, parsed.ids[0]) await loadInMemorySave('/google') } }) diff --git a/src/guessProblem.ts b/src/guessProblem.ts deleted file mode 100644 index ecc7dbf1..00000000 --- a/src/guessProblem.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const guessProblem = (errorMessage: string) => { - if (errorMessage.endsWith('Socket error: ECONNREFUSED')) { - return 'Most probably the server is not running.' - } -} diff --git a/src/importsWorkaround.js b/src/importsWorkaround.js index 21bc4585..231654ca 100644 --- a/src/importsWorkaround.js +++ b/src/importsWorkaround.js @@ -1,4 +1,6 @@ // workaround for mineflayer +globalThis.window ??= globalThis +globalThis.localStorage ??= {} process.versions.node = '18.0.0' if (!navigator.getGamepads) { diff --git a/src/index.ts b/src/index.ts index 89baaa10..7764188f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,222 +1,140 @@ /* eslint-disable import/order */ import './importsWorkaround' import './styles.css' +import './testCrasher' import './globals' -import 'iconify-icon' import './devtools' import './entities' +import customChannels from './customChannels' import './globalDomListeners' -import initCollisionShapes from './getCollisionShapes' -import { itemsAtlases, onGameLoad } from './inventoryWindows' -import { supportedVersions } from 'minecraft-protocol' - -import 'core-js/features/array/at' -import 'core-js/features/promise/with-resolvers' +import './mineflayer/maps' +import './mineflayer/cameraShake' +import './shims/patchShims' +import './mineflayer/java-tester/index' +import './external' +import './appConfig' +import './mineflayer/timers' +import './mineflayer/plugins' +import { getServerInfo } from './mineflayer/mc-protocol' +import { onGameLoad } from './inventoryWindows' +import initCollisionShapes from './getCollisionInteractionShapes' +import protocolMicrosoftAuth from 'minecraft-protocol/src/client/microsoftAuth' +import microsoftAuthflow from './microsoftAuthflow' +import { Duplex } from 'stream' import './scaleInterface' -import itemsPng from 'prismarine-viewer/public/textures/items.png' -import { initWithRenderer } from './topRightStats' -import PrismarineBlock from 'prismarine-block' -import { options, watchValue } from './optionsStorage' -import './reactUi.jsx' -import { contro, onBotCreate } from './controls' +import { options } from './optionsStorage' +import './reactUi' +import { lockUrl, onBotCreate } from './controls' import './dragndrop' -import { possiblyCleanHandle, resetStateAfterDisconnect } from './browserfs' -import { watchOptionsAfterViewerInit } from './watchOptions' -import downloadAndOpenFile from './downloadAndOpenFile' +import { possiblyCleanHandle } from './browserfs' +import downloadAndOpenFile, { isInterestedInDownload } from './downloadAndOpenFile' import fs from 'fs' -import net from 'net' +import net, { Socket } from 'net' import mineflayer from 'mineflayer' -import { WorldDataEmitter, Viewer } from 'prismarine-viewer/viewer' -import pathfinder from 'mineflayer-pathfinder' -import { Vec3 } from 'vec3' -import worldInteractions from './worldInteractions' - -import * as THREE from 'three' -import MinecraftData, { versionsByMinecraftVersion } from 'minecraft-data' import debug from 'debug' import { defaultsDeep } from 'lodash-es' +import initializePacketsReplay from './packetsReplay/packetsReplayLegacy' -import { initVR } from './vr' import { - AppConfig, activeModalStack, activeModalStacks, hideModal, insertActiveModalStack, isGameActive, miscUiState, - showModal + showModal, + gameAdditionalState, } from './globalState' - -import { - pointerLock, - toMajorVersion, - setLoadingScreenStatus -} from './utils' +import { parseServerAddress } from './parseServerAddress' +import { setLoadingScreenStatus } from './appStatus' import { isCypress } from './standaloneUtils' -import { - removePanorama -} from './panorama' - import { startLocalServer, unsupportedLocalServerFeatures } from './createLocalServer' import defaultServerOptions from './defaultLocalServerOptions' -import dayCycle from './dayCycle' -import { genTexturePackTextures, watchTexturepackInViewer } from './texturePack' -import { connectToPeer } from './localServerMultiplayer' +import { onAppLoad, resourcepackReload, resourcePackState } from './resourcePack' +import { ConnectPeerOptions, connectToPeer } from './localServerMultiplayer' import CustomChannelClient from './customClient' -import { loadScript } from 'prismarine-viewer/viewer/lib/utils' import { registerServiceWorker } from './serviceWorker' -import { appStatusState, lastConnectOptions } from './react/AppStatusProvider' +import { appStatusState, lastConnectOptions, quickDevReconnect } from './react/AppStatusProvider' import { fsState } from './loadSave' import { watchFov } from './rendererUtils' import { loadInMemorySave } from './react/SingleplayerProvider' -import { downloadSoundsIfNeeded, earlyCheck as earlySoundsMapCheck } from './soundSystem' -import { ua } from './react/utils' -import { handleMovementStickDelta, joystickPointer } from './react/TouchAreasControls' import { possiblyHandleStateVariable } from './googledrive' import flyingSquidEvents from './flyingSquidEvents' -import { hideNotification, notificationProxy, showNotification } from './react/NotificationProvider' +import { showNotification } from './react/NotificationProvider' import { saveToBrowserMemory } from './react/PauseScreen' -import { ViewerWrapper } from 'prismarine-viewer/viewer/lib/viewerWrapper' import './devReload' import './water' -import { ConnectOptions } from './connect' -import { subscribe } from 'valtio' +import { ConnectOptions, getVersionAutoSelect, downloadOtherGameData, downloadAllMinecraftData, loadMinecraftData } from './connect' +import { ref, subscribe } from 'valtio' +import { signInMessageState } from './react/SignInMessageProvider' +import { findServerPassword, updateAuthenticatedAccountData, updateLoadedServerData, updateServerConnectionHistory } from './react/serversStorage' +import { mainMenuState } from './react/MainMenuRenderApp' +import './mobileShim' +import { parseFormattedMessagePacket } from './botUtils' +import { appStartup } from './clientMods' +import { getViewerVersionData, getWsProtocolStream, onBotCreatedViewerHandler } from './viewerConnector' +import { getWebsocketStream } from './mineflayer/websocket-core' +import { appQueryParams, appQueryParamsArray } from './appParams' +import { playerState } from './mineflayer/playerState' +import { states } from 'minecraft-protocol' +import { initMotionTracking } from './react/uiMotion' +import { UserError } from './mineflayer/userError' +import { startLocalReplayServer } from './packetsReplay/replayPackets' +import { createFullScreenProgressReporter, createWrappedProgressReporter, ProgressReporter } from './core/progressReporter' +import { appViewer } from './appViewer' +import './appViewerLoad' +import { registerOpenBenchmarkListener } from './benchmark' +import { tryHandleBuiltinCommand } from './builtinCommands' +import { loadingTimerState } from './react/LoadingTimer' +import { loadPluginsIntoWorld } from './react/CreateWorldProvider' +import { getCurrentProxy, getCurrentUsername } from './react/ServersList' window.debug = debug -window.THREE = THREE -window.worldInteractions = worldInteractions window.beforeRenderFrame = [] // ACTUAL CODE -void registerServiceWorker() +void registerServiceWorker().then(() => { + mainMenuState.serviceWorkerLoaded = true +}) watchFov() initCollisionShapes() +initializePacketsReplay() +onAppLoad() +customChannels() -// Create three.js context, add to page -let renderer: THREE.WebGLRenderer -try { - renderer = new THREE.WebGLRenderer({ - powerPreference: options.gpuPreference, - }) -} catch (err) { - console.error(err) - throw new Error(`Failed to create WebGL context, not possible to render (restart browser): ${err.message}`) -} - -// renderer.localClippingEnabled = true -initWithRenderer(renderer.domElement) -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' -if (isFirefox) { - // set custom property - document.body.style.setProperty('--thin-if-firefox', 'thin') -} - -const isIphone = ua.getDevice().model === 'iPhone' // todo ipad? - -if (isIphone) { - document.documentElement.style.setProperty('--hud-bottom-max', '21px') // env-safe-aria-inset-bottom -} - -// Create viewer -const viewer: import('prismarine-viewer/viewer/lib/viewer').Viewer = new Viewer(renderer) -window.viewer = viewer -new THREE.TextureLoader().load(itemsPng, (texture) => { - viewer.entities.itemsTexture = texture - // todo unify - viewer.entities.getItemUv = (id) => { - try { - const name = loadedData.items[id]?.name - const uv = itemsAtlases.latest.textures[name] - if (!uv) { - const variant = viewer.world.downloadedBlockStatesData[name]?.variants?.[''] - if (!variant) return - const faces = (Array.isArray(variant) ? variant[0] : variant).model?.elements?.[0]?.faces - const uvBlock = faces?.north?.texture ?? faces?.up?.texture ?? faces?.down?.texture ?? faces?.west?.texture ?? faces?.east?.texture ?? faces?.south?.texture - if (!uvBlock) return - return { - ...uvBlock, - size: Math.abs(uvBlock.su), - texture: viewer.world.material.map - } - } - return { - ...uv, - size: itemsAtlases.latest.size, - texture: viewer.entities.itemsTexture - } - } catch (err) { - reportError?.(err) - return { - u: 0, - v: 0, - size: 16 / viewer.world.material.map!.image.width, - texture: viewer.world.material.map - } - } - } -}) -viewer.entities.entitiesOptions = { - fontFamily: 'mojangles' -} -watchOptionsAfterViewerInit() -watchTexturepackInViewer(viewer) - -let mouseMovePostHandle = (e) => { } -let lastMouseMove: number -const updateCursor = () => { - worldInteractions.update() -} -function onCameraMove (e) { - if (e.type !== 'touchmove' && !pointerLock.hasPointerLock) return - e.stopPropagation?.() - const now = performance.now() - // todo: limit camera movement for now to avoid unexpected jumps - if (now - lastMouseMove < 4) return - lastMouseMove = now - let { mouseSensX, mouseSensY } = options - if (mouseSensY === -1) mouseSensY = mouseSensX - mouseMovePostHandle({ - x: e.movementX * mouseSensX * 0.0001, - y: e.movementY * mouseSensY * 0.0001 - }) - updateCursor() -} -window.addEventListener('mousemove', onCameraMove, { capture: true }) -contro.on('stickMovement', ({ stick, vector }) => { - if (!isGameActive(true)) return - if (stick !== 'right') return - let { x, z } = vector - if (Math.abs(x) < 0.18) x = 0 - if (Math.abs(z) < 0.18) z = 0 - onCameraMove({ movementX: x * 10, movementY: z * 10, type: 'touchmove' }) - miscUiState.usingGamepadInput = true -}) +if (appQueryParams.testCrashApp === '2') throw new Error('test') function hideCurrentScreens () { activeModalStacks['main-menu'] = [...activeModalStack] insertActiveModalStack('', []) } -const loadSingleplayer = (serverOverrides = {}, flattenedServerOverrides = {}) => { - void connect({ singleplayer: true, username: options.localUsername, password: '', serverOverrides, serverOverridesFlat: flattenedServerOverrides }) +const loadSingleplayer = (serverOverrides = {}, flattenedServerOverrides = {}, connectOptions?: Partial) => { + const serverSettingsQsRaw = appQueryParamsArray.serverSetting ?? [] + const serverSettingsQs = serverSettingsQsRaw.map(x => x.split(':')).reduce>((acc, [key, value]) => { + acc[key] = JSON.parse(value) + return acc + }, {}) + void connect({ + singleplayer: true, + username: options.localUsername, + serverOverrides, + serverOverridesFlat: { + ...flattenedServerOverrides, + ...serverSettingsQs + }, + ...connectOptions + }) } function listenGlobalEvents () { window.addEventListener('connect', e => { @@ -224,84 +142,109 @@ function listenGlobalEvents () { void connect(options) }) window.addEventListener('singleplayer', (e) => { - loadSingleplayer((e as CustomEvent).detail) + const { detail } = (e as CustomEvent) + const { connectOptions, ...rest } = detail + loadSingleplayer(rest, {}, connectOptions) }) } -let listeners = [] as Array<{ target, event, callback }> -let cleanupFunctions = [] as Array<() => void> -// only for dom listeners (no removeAllListeners) -// todo refactor them out of connect fn instead -const registerListener: import('./utilsTs').RegisterListener = (target, event, callback) => { - target.addEventListener(event, callback) - listeners.push({ target, event, callback }) -} -const removeAllListeners = () => { - for (const { target, event, callback } of listeners) { - target.removeEventListener(event, callback) - } - for (const cleanupFunction of cleanupFunctions) { - cleanupFunction() - } - cleanupFunctions = [] - listeners = [] -} - -const cleanConnectIp = (host: string | undefined, defaultPort: string | undefined) => { - const hostPort = host && /:\d+$/.exec(host) - if (hostPort) { - return { - host: host.slice(0, -hostPort[0].length), - port: hostPort[0].slice(1) - } - } else { - return { host, port: defaultPort } - } -} - -async function connect (connectOptions: ConnectOptions) { +export async function connect (connectOptions: ConnectOptions) { if (miscUiState.gameLoaded) return + + if (sessionStorage.delayLoadUntilFocus) { + await new Promise(resolve => { + if (document.hasFocus()) { + resolve(undefined) + } else { + window.addEventListener('focus', resolve) + } + }) + } + if (sessionStorage.delayLoadUntilClick) { + await new Promise(resolve => { + window.addEventListener('click', resolve) + }) + } + + appStatusState.showReconnect = false + loadingTimerState.loading = true + loadingTimerState.start = Date.now() miscUiState.hasErrors = false lastConnectOptions.value = connectOptions - removePanorama() const { singleplayer } = connectOptions const p2pMultiplayer = !!connectOptions.peerId miscUiState.singleplayer = singleplayer miscUiState.flyingSquid = singleplayer || p2pMultiplayer - const { renderDistance: renderDistanceSingleplayer, multiplayerRenderDistance } = options - const server = cleanConnectIp(connectOptions.server, '25565') - const proxy = cleanConnectIp(connectOptions.proxy, undefined) - const { username, password } = connectOptions - console.log(`connecting to ${server.host}:${server.port} with ${username}`) + // Track server connection in history + if (!singleplayer && !p2pMultiplayer && connectOptions.server && connectOptions.saveServerToHistory !== false) { + const parsedServer = parseServerAddress(connectOptions.server) + updateServerConnectionHistory(parsedServer.host, connectOptions.botVersion) + } + + const { renderDistance: renderDistanceSingleplayer, multiplayerRenderDistance } = options + + const parsedServer = parseServerAddress(connectOptions.server) + const server = { host: parsedServer.host, port: parsedServer.port } + if (connectOptions.proxy?.startsWith(':')) { + connectOptions.proxy = `${location.protocol}//${location.hostname}${connectOptions.proxy}` + } + if (connectOptions.proxy && location.port !== '80' && location.port !== '443' && !/:\d+$/.test(connectOptions.proxy)) { + const https = connectOptions.proxy.startsWith('https://') || location.protocol === 'https:' + connectOptions.proxy = `${connectOptions.proxy}:${https ? 443 : 80}` + } + const parsedProxy = parseServerAddress(connectOptions.proxy, false) + const proxy = { host: parsedProxy.host, port: parsedProxy.port } + let { username } = connectOptions + + if (connectOptions.server) { + console.log(`connecting to ${server.host}:${server.port ?? 25_565}`) + } + console.log('using player username', username) hideCurrentScreens() - setLoadingScreenStatus('Logging in') + const progress = createFullScreenProgressReporter() + const loggingInMsg = connectOptions.server ? 'Connecting to server' : 'Logging in' + progress.beginStage('connect', loggingInMsg) let ended = false let bot!: typeof __type_bot - const destroyAll = () => { + let hadConnected = false + const destroyAll = (wasKicked = false) => { if (ended) return + loadingTimerState.loading = false + const { alwaysReconnect } = appQueryParams + if ((!wasKicked && miscUiState.appConfig?.allowAutoConnect && appQueryParams.autoConnect && hadConnected) || (alwaysReconnect)) { + if (alwaysReconnect === 'quick' || alwaysReconnect === 'fast') { + quickDevReconnect() + } else { + location.reload() + } + } + errorAbortController.abort() ended = true - viewer.resetAll() + progress.end() + // dont reset viewer so we can still do debugging localServer = window.localServer = window.server = undefined + gameAdditionalState.viewerConnection = false - renderWrapper.postRender = () => { } if (bot) { bot.end() // ensure mineflayer plugins receive this event for cleanup bot.emit('end', '') bot.removeAllListeners() bot._client.removeAllListeners() - //@ts-expect-error TODO? - bot._client = undefined + bot._client = { + //@ts-expect-error + write (packetName) { + console.warn('Tried to write packet', packetName, 'after bot was destroyed') + } + } //@ts-expect-error window.bot = bot = undefined } - resetStateAfterDisconnect() cleanFs() - removeAllListeners() } const cleanFs = () => { if (singleplayer && !fsState.inMemorySave) { @@ -312,23 +255,30 @@ async function connect (connectOptions: ConnectOptions) { } let lastPacket = undefined as string | undefined const onPossibleErrorDisconnect = () => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison - if (lastPacket && bot?._client && bot._client.state !== 'play') { + if (lastPacket && bot?._client && bot._client.state !== states.PLAY) { appStatusState.descriptionHint = `Last Server Packet: ${lastPacket}` } } const handleError = (err) => { console.error(err) - errorAbortController.abort() + if (err === 'ResizeObserver loop completed with undelivered notifications.') { + return + } if (isCypress()) throw err miscUiState.hasErrors = true if (miscUiState.gameLoaded) return + // close all modals + for (const modal of activeModalStack) { + hideModal(modal) + } setLoadingScreenStatus(`Error encountered. ${err}`, true) + appStatusState.showReconnect = true onPossibleErrorDisconnect() destroyAll() } + // todo(hard): remove it! const errorAbortController = new AbortController() window.addEventListener('unhandledrejection', (e) => { if (e.reason.name === 'ServerPluginLoadFailure') { @@ -336,6 +286,10 @@ async function connect (connectOptions: ConnectOptions) { return } } + if (e.reason?.stack?.includes('chrome-extension://')) { + // ignore issues caused by chrome extension + return + } handleError(e.reason) }, { signal: errorAbortController.signal @@ -346,47 +300,89 @@ async function connect (connectOptions: ConnectOptions) { signal: errorAbortController.signal }) - if (proxy) { - console.log(`using proxy ${proxy.host}:${proxy.port || location.port}`) + let clientDataStream: Duplex | undefined - net['setProxy']({ hostname: proxy.host, port: proxy.port }) + if (connectOptions.server && !connectOptions.viewerWsConnect && !parsedServer.isWebSocket) { + console.log(`using proxy ${proxy.host}:${proxy.port || location.port}`) + net['setProxy']({ hostname: proxy.host, port: proxy.port, headers: { Authorization: `Bearer ${new URLSearchParams(location.search).get('token') ?? ''}` }, artificialDelay: appQueryParams.addPing ? Number(appQueryParams.addPing) : undefined }) } const renderDistance = singleplayer ? renderDistanceSingleplayer : multiplayerRenderDistance + let updateDataAfterJoin = () => { } let localServer + let localReplaySession: ReturnType | undefined + let lastKnownKickReason = undefined as string | undefined try { const serverOptions = defaultsDeep({}, connectOptions.serverOverrides ?? {}, options.localServerOptions, defaultServerOptions) Object.assign(serverOptions, connectOptions.serverOverridesFlat ?? {}) - const downloadMcData = async (version: string) => { - // todo expose cache - const lastVersion = supportedVersions.at(-1) - if (version === lastVersion) { - // ignore cache hit - versionsByMinecraftVersion.pc[lastVersion]!['dataVersion']!++ - } - if (!document.fonts.check('1em mojangles')) { - // todo instead re-render signs on load - await document.fonts.load('1em mojangles').catch(() => { }) - } - setLoadingScreenStatus(`Downloading data for ${version}`) - await downloadSoundsIfNeeded() - await loadScript(`./mc-data/${toMajorVersion(version)}.js`) - miscUiState.loadedDataVersion = version - try { - await genTexturePackTextures(version) - } catch (err) { - console.error(err) - const doContinue = confirm('Failed to apply texture pack. See errors in the console. Continue?') - if (!doContinue) { - throw err + + await progress.executeWithMessage('Downloading Minecraft data', 'download-mcdata', async () => { + loadingTimerState.networkOnlyStart = Date.now() + + let downloadingAssets = [] as string[] + const reportAssetDownload = (asset: string, isDone: boolean) => { + if (isDone) { + downloadingAssets = downloadingAssets.filter(a => a !== asset) + } else { + downloadingAssets.push(asset) } + progress.setSubStage('download-mcdata', `(${downloadingAssets.join(', ')})`) } - viewer.setVersion(version) + + await Promise.all([ + downloadAllMinecraftData(reportAssetDownload), + downloadOtherGameData(reportAssetDownload) + ]) + loadingTimerState.networkOnlyStart = 0 + }) + + let dataDownloaded = false + const downloadMcData = async (version: string) => { + if (dataDownloaded) return + dataDownloaded = true + appViewer.resourcesManager.currentConfig = { version, texturesVersion: options.useVersionsTextures || undefined } + + await progress.executeWithMessage( + 'Processing downloaded Minecraft data', + async () => { + await loadMinecraftData(version) + await appViewer.resourcesManager.loadSourceData(version) + } + ) + + await progress.executeWithMessage( + 'Applying user-installed resource pack', + async () => { + try { + await resourcepackReload(true) + } catch (err) { + console.error(err) + const doContinue = confirm('Failed to apply texture pack. See errors in the console. Continue?') + if (!doContinue) { + throw err + } + } + } + ) + + await progress.executeWithMessage( + 'Preparing textures', + async () => { + await appViewer.resourcesManager.updateAssetsData({}) + } + ) } - const downloadVersion = connectOptions.botVersion || (singleplayer ? serverOptions.version : undefined) - if (downloadVersion) { - await downloadMcData(downloadVersion) + let finalVersion = connectOptions.botVersion || (singleplayer ? serverOptions.version : undefined) + + if (connectOptions.worldStateFileContents) { + try { + localReplaySession = startLocalReplayServer(connectOptions.worldStateFileContents) + } catch (err) { + console.error(err) + throw new UserError(`Failed to start local replay server: ${err}`) + } + finalVersion = localReplaySession.version } if (singleplayer) { @@ -401,43 +397,127 @@ async function connect (connectOptions: ConnectOptions) { // Client (class) of flying-squid (in server/login.js of mc-protocol): onLogin handler: skip most logic & go to loginClient() which assigns uuid and sends 'success' back to client (onLogin handler) and emits 'login' on the server (login.js in flying-squid handler) // flying-squid: 'login' -> player.login -> now sends 'login' event to the client (handled in many plugins in mineflayer) -> then 'update_health' is sent which emits 'spawn' in mineflayer - setLoadingScreenStatus('Starting local server') + const serverPlugins = new URLSearchParams(location.search).getAll('serverPlugin') + if (serverPlugins.length > 0 && !serverOptions.worldFolder) { + console.log('Placing server plugins', serverPlugins) + + serverOptions.worldFolder ??= '/temp' + await loadPluginsIntoWorld('/temp', serverPlugins) + + console.log('Server plugins placed') + } + localServer = window.localServer = window.server = startLocalServer(serverOptions) + connectOptions?.connectEvents?.serverCreated?.() // todo need just to call quit if started // loadingScreen.maybeRecoverable = false // init world, todo: do it for any async plugins if (!localServer.pluginsReady) { - await new Promise(resolve => { - localServer.once('pluginsReady', resolve) - }) + await progress.executeWithMessage( + 'Starting local server', + async () => { + await new Promise(resolve => { + localServer.once('pluginsReady', resolve) + }) + } + ) } localServer.on('newPlayer', (player) => { - // it's you! player.on('loadingStatus', (newStatus) => { - setLoadingScreenStatus(newStatus, false, false, true) + progress.setMessage(newStatus) }) }) flyingSquidEvents() } + if (connectOptions.authenticatedAccount) username = 'you' let initialLoadingText: string if (singleplayer) { initialLoadingText = 'Local server is still starting' } else if (p2pMultiplayer) { initialLoadingText = 'Connecting to peer' + } else if (connectOptions.server) { + if (!finalVersion) { + const versionAutoSelect = getVersionAutoSelect() + const wrapped = createWrappedProgressReporter(progress, `Fetching server version. Preffered: ${versionAutoSelect}`) + loadingTimerState.networkOnlyStart = Date.now() + const autoVersionSelect = await getServerInfo(server.host, server.port ? Number(server.port) : undefined, versionAutoSelect) + wrapped.end() + finalVersion = autoVersionSelect.version + } + initialLoadingText = `Connecting to server ${server.host}:${server.port ?? 25_565} with version ${finalVersion}` + } else if (connectOptions.viewerWsConnect) { + initialLoadingText = `Connecting to Mineflayer WebSocket server ${connectOptions.viewerWsConnect}` + } else if (connectOptions.worldStateFileContents) { + initialLoadingText = `Loading local replay server` } else { - initialLoadingText = 'Connecting to server' + initialLoadingText = 'We have no idea what to do' } - setLoadingScreenStatus(initialLoadingText) + progress.setMessage(initialLoadingText) + + if (parsedServer.isWebSocket) { + loadingTimerState.networkOnlyStart = Date.now() + clientDataStream = (await getWebsocketStream(server.host)).mineflayerStream + } + + let newTokensCacheResult = null as any + const cachedTokens = typeof connectOptions.authenticatedAccount === 'object' ? connectOptions.authenticatedAccount.cachedTokens : {} + let authData: Awaited> | undefined + if (connectOptions.authenticatedAccount) { + authData = await microsoftAuthflow({ + tokenCaches: cachedTokens, + proxyBaseUrl: connectOptions.proxy, + setProgressText (text) { + progress.setMessage(text) + }, + setCacheResult (result) { + newTokensCacheResult = result + }, + connectingServer: server.host + }) + } + + if (p2pMultiplayer) { + clientDataStream = await connectToPeer(connectOptions.peerId!, connectOptions.peerOptions) + } + if (connectOptions.viewerWsConnect) { + const { version, time, requiresPass } = await getViewerVersionData(connectOptions.viewerWsConnect) + let password + if (requiresPass) { + password = prompt('Enter password') + if (!password) { + throw new UserError('Password is required') + } + } + console.log('Latency:', Date.now() - time, 'ms') + // const version = '1.21.1' + finalVersion = version + await downloadMcData(version) + setLoadingScreenStatus(`Connecting to WebSocket server ${connectOptions.viewerWsConnect}`) + clientDataStream = (await getWsProtocolStream(connectOptions.viewerWsConnect)).clientDuplex + if (password) { + clientDataStream.write(password) + } + gameAdditionalState.viewerConnection = true + } + + if (finalVersion) { + // ensure data is downloaded + loadingTimerState.networkOnlyStart ??= Date.now() + await downloadMcData(finalVersion) + } + + const brand = clientDataStream ? 'minecraft-web-client' : undefined bot = mineflayer.createBot({ host: server.host, port: server.port ? +server.port : undefined, - version: connectOptions.botVersion || false, - ...p2pMultiplayer ? { - stream: await connectToPeer(connectOptions.peerId!), + brand, + version: finalVersion || false, + ...clientDataStream ? { + stream: clientDataStream as any, } : {}, - ...singleplayer || p2pMultiplayer ? { + ...singleplayer || p2pMultiplayer || localReplaySession ? { keepAlive: false, } : {}, ...singleplayer ? { @@ -445,43 +525,114 @@ async function connect (connectOptions: ConnectOptions) { connect () { }, Client: CustomChannelClient as any, } : {}, + ...localReplaySession ? { + connect () { }, + Client: CustomChannelClient as any, + } : {}, + onMsaCode (data) { + signInMessageState.code = data.user_code + signInMessageState.link = data.verification_uri + signInMessageState.expiresOn = Date.now() + data.expires_in * 1000 + }, + sessionServer: authData?.sessionEndpoint?.toString(), + auth: connectOptions.authenticatedAccount ? async (client, options) => { + authData!.setOnMsaCodeCallback(options.onMsaCode) + authData?.setConnectingVersion(client.version) + //@ts-expect-error + client.authflow = authData!.authFlow + try { + signInMessageState.abortController = ref(new AbortController()) + await Promise.race([ + protocolMicrosoftAuth.authenticate(client, options), + new Promise((_r, reject) => { + signInMessageState.abortController.signal.addEventListener('abort', () => { + reject(new UserError('Aborted by user')) + }) + }) + ]) + if (signInMessageState.shouldSaveToken) { + updateAuthenticatedAccountData(accounts => { + const existingAccount = accounts.find(a => a.username === client.username) + if (existingAccount) { + existingAccount.cachedTokens = { ...existingAccount.cachedTokens, ...newTokensCacheResult } + } else { + accounts.push({ + username: client.username, + cachedTokens: { ...cachedTokens, ...newTokensCacheResult } + }) + } + return accounts + }) + updateDataAfterJoin = () => { + updateLoadedServerData(s => ({ ...s, authenticatedAccountOverride: client.username }), connectOptions.serverIndex) + } + } else { + updateDataAfterJoin = () => { + updateLoadedServerData(s => ({ ...s, authenticatedAccountOverride: undefined }), connectOptions.serverIndex) + } + } + setLoadingScreenStatus('Authentication successful. Logging in to server') + } finally { + signInMessageState.code = '' + } + } : undefined, username, - password, viewDistance: renderDistance, checkTimeoutInterval: 240 * 1000, - noPongTimeout: 240 * 1000, + // noPongTimeout: 240 * 1000, closeTimeout: 240 * 1000, respawn: options.autoRespawn, maxCatchupTicks: 0, - async versionSelectedHook (client) { - await downloadMcData(client.version) - setLoadingScreenStatus(initialLoadingText) - }, 'mapDownloader-saveToFile': false, // "mapDownloader-saveInternal": false, // do not save into memory, todo must be implemeneted as we do really care of ram }) as unknown as typeof __type_bot window.bot = bot - earlySoundsMapCheck() + + if (connectOptions.viewerWsConnect) { + void onBotCreatedViewerHandler() + } customEvents.emit('mineflayerBotCreated') - if (singleplayer || p2pMultiplayer) { - // in case of p2pMultiplayer there is still flying-squid on the host side - const _supportFeature = bot.supportFeature - bot.supportFeature = ((feature) => { - if (unsupportedLocalServerFeatures.includes(feature)) { - return false - } - return _supportFeature(feature) - }) as typeof bot.supportFeature + if (singleplayer || p2pMultiplayer || localReplaySession) { + if (singleplayer || p2pMultiplayer) { + // in case of p2pMultiplayer there is still flying-squid on the host side + const _supportFeature = bot.supportFeature + bot.supportFeature = ((feature) => { + if (unsupportedLocalServerFeatures.includes(feature)) { + return false + } + return _supportFeature(feature) + }) as typeof bot.supportFeature + } bot.emit('inject_allowed') bot._client.emit('connect') + } else if (clientDataStream) { + // bot.emit('inject_allowed') + bot._client.emit('connect') } else { const setupConnectHandlers = () => { + Socket.prototype['handleStringMessage'] = function (message: string) { + if (message.startsWith('proxy-message') || message.startsWith('proxy-command:')) { // for future + return false + } + if (message.startsWith('proxy-shutdown:')) { + lastKnownKickReason = message.slice('proxy-shutdown:'.length) + return false + } + return true + } bot._client.socket.on('connect', () => { - console.log('WebSocket connection established') + console.log('Proxy WebSocket connection established') //@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') @@ -496,6 +647,7 @@ async function connect (connectOptions: ConnectOptions) { } else { const originalSetSocket = bot._client.setSocket.bind(bot._client) bot._client.setSocket = (socket) => { + if (!bot) return originalSetSocket(socket) setupConnectHandlers() } @@ -507,7 +659,7 @@ async function connect (connectOptions: ConnectOptions) { } if (!bot) return - const p2pConnectTimeout = p2pMultiplayer ? setTimeout(() => { throw new Error('Spawn timeout. There might be error on the other side, check console.') }, 20_000) : undefined + const p2pConnectTimeout = p2pMultiplayer ? setTimeout(() => { throw new UserError('Spawn timeout. There might be error on the other side, check console.') }, 20_000) : undefined // bot.on('inject_allowed', () => { // loadingScreen.maybeRecoverable = false @@ -516,9 +668,15 @@ async function connect (connectOptions: ConnectOptions) { bot.on('error', handleError) bot.on('kicked', (kickReason) => { - console.log('User was kicked!', kickReason) - setLoadingScreenStatus(`The Minecraft server kicked you. Kick reason: ${typeof kickReason === 'object' ? JSON.stringify(kickReason) : kickReason}`, true) - destroyAll() + console.log('You were kicked!', kickReason) + const { formatted: kickReasonFormatted, plain: kickReasonString } = parseFormattedMessagePacket(kickReason) + // close all modals + for (const modal of activeModalStack) { + hideModal(modal) + } + setLoadingScreenStatus(`The Minecraft server kicked you. Kick reason: ${kickReasonString}`, true, undefined, undefined, kickReasonFormatted) + appStatusState.showReconnect = true + destroyAll(true) }) const packetBeforePlay = (_, __, ___, fullBuffer) => { @@ -535,7 +693,15 @@ async function connect (connectOptions: ConnectOptions) { bot.on('end', (endReason) => { if (ended) return console.log('disconnected for', endReason) - setLoadingScreenStatus(`You have been disconnected from the server. End reason: ${endReason}`, true) + if (endReason === 'socketClosed') { + endReason = lastKnownKickReason ?? 'Connection with proxy server lost' + } + // close all modals + for (const modal of activeModalStack) { + hideModal(modal) + } + setLoadingScreenStatus(`You have been disconnected from the server. End reason:\n${endReason}`, true) + appStatusState.showReconnect = true onPossibleErrorDisconnect() destroyAll() if (isCypress()) throw new Error(`disconnected: ${endReason}`) @@ -544,288 +710,190 @@ async function connect (connectOptions: ConnectOptions) { onBotCreate() bot.once('login', () => { - worldInteractions.initBot() - - setLoadingScreenStatus('Loading world') + errorAbortController.abort() + loadingTimerState.networkOnlyStart = 0 + progress.setMessage('Loading world') }) + let worldWasReady = false + const waitForChunksToLoad = async (progress?: ProgressReporter) => { + await new Promise(resolve => { + if (worldWasReady) { + resolve() + return + } + const unsub = subscribe(appViewer.rendererState, () => { + if (appViewer.rendererState.world.allChunksLoaded && appViewer.nonReactiveState.world.chunksTotalNumber) { + worldWasReady = true + resolve() + unsub() + } else { + const perc = Math.round(appViewer.rendererState.world.chunksLoaded.size / appViewer.nonReactiveState.world.chunksTotalNumber * 100) + progress?.reportProgress('chunks', perc / 100) + } + }) + }) + } + const spawnEarlier = !singleplayer && !p2pMultiplayer - // don't use spawn event, player can be dead - bot.once(spawnEarlier ? 'forcedMove' : 'health', () => { - errorAbortController.abort() - const mcData = MinecraftData(bot.version) - window.PrismarineBlock = PrismarineBlock(mcData.version.minecraftVersion!) - window.loadedData = mcData - 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') - 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') - - const center = bot.entity.position - - const worldView = window.worldView = new WorldDataEmitter(bot.world, renderDistance, center) - - bot.on('physicsTick', () => updateCursor()) - - - void initVR() - - renderWrapper.postRender = () => { - viewer.setFirstPersonCamera(null, bot.entity.yaw, bot.entity.pitch) - } - - - // Link WorldDataEmitter and Viewer - viewer.listen(worldView) - worldView.listenToBot(bot) - void worldView.init(bot.entity.position) - - dayCycle() - - // Bot position callback - 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) - void worldView.updatePosition(bot.entity.position) - } - bot.on('move', botPosition) - botPosition() - - setLoadingScreenStatus('Setting callbacks') - - const maxPitch = 0.5 * Math.PI - const minPitch = -0.5 * Math.PI - mouseMovePostHandle = ({ x, y }) => { - viewer.world.lastCamUpdate = Date.now() - bot.entity.pitch -= y - bot.entity.pitch = Math.max(minPitch, Math.min(maxPitch, bot.entity.pitch)) - bot.entity.yaw -= x - } - - function changeCallback () { - if (notificationProxy.id === 'pointerlockchange') { - hideNotification() - } - if (renderer.xr.isPresenting) return // todo - if (!pointerLock.hasPointerLock && activeModalStack.length === 0) { - showModal({ reactType: 'pause-screen' }) - } - } - - registerListener(document, 'pointerlockchange', changeCallback, false) - - const cameraControlEl = document.querySelector('#ui-root') - - /** after what time of holding the finger start breaking the block */ - const touchStartBreakingBlockMs = 500 - let virtualClickActive = false - let virtualClickTimeout - let screenTouches = 0 - let capturedPointer: { id; x; y; sourceX; sourceY; activateCameraMove; time } | undefined - registerListener(document, 'pointerdown', (e) => { - const usingJoystick = options.touchControlsType === 'joystick-buttons' - const clickedEl = e.composedPath()[0] - if (!isGameActive(true) || !miscUiState.currentTouch || clickedEl !== cameraControlEl || e.pointerId === undefined) { - return - } - screenTouches++ - if (screenTouches === 3) { - // todo needs fixing! - // window.dispatchEvent(new MouseEvent('mousedown', { button: 1 })) - } - if (usingJoystick) { - if (!joystickPointer.pointer && e.clientX < window.innerWidth / 2) { - joystickPointer.pointer = { - pointerId: e.pointerId, - x: e.clientX, - y: e.clientY + const displayWorld = async () => { + if (resourcePackState.isServerInstalling) { + await new Promise(resolve => { + subscribe(resourcePackState, () => { + if (!resourcePackState.isServerInstalling) { + resolve() } - return - } - } - if (capturedPointer) { - return - } - cameraControlEl.setPointerCapture(e.pointerId) - capturedPointer = { - id: e.pointerId, - x: e.clientX, - y: e.clientY, - sourceX: e.clientX, - sourceY: e.clientY, - activateCameraMove: false, - time: Date.now() - } - if (options.touchControlsType !== 'joystick-buttons') { - virtualClickTimeout ??= setTimeout(() => { - virtualClickActive = true - document.dispatchEvent(new MouseEvent('mousedown', { button: 0 })) - }, touchStartBreakingBlockMs) - } - }) - registerListener(document, 'pointermove', (e) => { - if (e.pointerId === undefined) return - const supportsPressure = (e as any).pressure !== undefined && (e as any).pressure !== 0 && (e as any).pressure !== 0.5 && (e as any).pressure !== 1 && (e.pointerType === 'touch' || e.pointerType === 'pen') - if (e.pointerId === joystickPointer.pointer?.pointerId) { - handleMovementStickDelta(e) - if (supportsPressure && (e as any).pressure > 0.5) { - bot.setControlState('sprint', true) - // todo - } - return - } - if (e.pointerId !== capturedPointer?.id) return - window.scrollTo(0, 0) - e.preventDefault() - e.stopPropagation() - - const allowedJitter = 1.1 - if (supportsPressure) { - bot.setControlState('jump', (e as any).pressure > 0.5) - } - const xDiff = Math.abs(e.pageX - capturedPointer.sourceX) > allowedJitter - const yDiff = Math.abs(e.pageY - capturedPointer.sourceY) > allowedJitter - if (!capturedPointer.activateCameraMove && (xDiff || yDiff)) capturedPointer.activateCameraMove = true - if (capturedPointer.activateCameraMove) { - clearTimeout(virtualClickTimeout) - } - onCameraMove({ movementX: e.pageX - capturedPointer.x, movementY: e.pageY - capturedPointer.y, type: 'touchmove' }) - capturedPointer.x = e.pageX - capturedPointer.y = e.pageY - }, { passive: false }) - - const pointerUpHandler = (e: PointerEvent) => { - if (e.pointerId === undefined) return - if (e.pointerId === joystickPointer.pointer?.pointerId) { - handleMovementStickDelta() - joystickPointer.pointer = null - return - } - if (e.pointerId !== capturedPointer?.id) return - clearTimeout(virtualClickTimeout) - virtualClickTimeout = undefined - - if (options.touchControlsType !== 'joystick-buttons') { - if (virtualClickActive) { - // button 0 is left click - document.dispatchEvent(new MouseEvent('mouseup', { button: 0 })) - virtualClickActive = false - } else if (!capturedPointer.activateCameraMove && (Date.now() - capturedPointer.time < touchStartBreakingBlockMs)) { - document.dispatchEvent(new MouseEvent('mousedown', { button: 2 })) - worldInteractions.update() - document.dispatchEvent(new MouseEvent('mouseup', { button: 2 })) - } - } - capturedPointer = undefined - screenTouches-- + }) + }) + await appViewer.resourcesManager.promiseAssetsReady } - registerListener(document, 'pointerup', pointerUpHandler) - registerListener(document, 'pointercancel', pointerUpHandler) - registerListener(document, 'lostpointercapture', pointerUpHandler) - - registerListener(document, 'contextmenu', (e) => e.preventDefault(), false) - - registerListener(document, 'blur', (e) => { - bot.clearControlStates() - }, false) - - console.log('Done!') - - // todo - onGameLoad(async () => { - if (!viewer.world.downloadedBlockStatesData && !viewer.world.customBlockStatesData) { - await new Promise(resolve => { - viewer.world.renderUpdateEmitter.once('blockStatesDownloaded', () => resolve()) - }) - } - miscUiState.serverIp = server.host as string | null - miscUiState.username = username - }) - if (appStatusState.isError) return - setTimeout(() => { - // todo - const qs = new URLSearchParams(window.location.search) - if (qs.get('suggest_save')) { - showNotification('Suggestion', 'Save the world to keep your progress!', false, undefined, async () => { - const savePath = await saveToBrowserMemory() - if (!savePath) return - const saveName = savePath.split('/').pop() - bot.end() - // todo hot reload - location.search = `loadSave=${saveName}` - }) - } - }, 600) - setLoadingScreenStatus(undefined) - const start = Date.now() - let done = false - void viewer.world.renderUpdateEmitter.on('update', () => { - // todo might not emit as servers simply don't send chunk if it's empty - if (!viewer.world.allChunksFinished || done) return - done = true - console.log('All done and ready! In', (Date.now() - start) / 1000, 's') - viewer.render() // ensure the last state is rendered + if (!appViewer.resourcesManager.currentResources?.itemsRenderer) { + await appViewer.resourcesManager.updateAssetsData({}) + } + + const loadWorldStart = Date.now() + console.log('try to focus window') + window.focus?.() + void waitForChunksToLoad().then(() => { + window.worldLoadTime = (Date.now() - loadWorldStart) / 1000 + console.log('All chunks done and ready! Time from renderer connect to ready', (Date.now() - loadWorldStart) / 1000, 's') document.dispatchEvent(new Event('cypress-world-ready')) }) - }) - if (!connectOptions.ignoreQs) { + try { + if (p2pConnectTimeout) clearTimeout(p2pConnectTimeout) + playerState.reactive.onlineMode = !!connectOptions.authenticatedAccount + + progress.setMessage('Placing blocks (starting viewer)') + if (!connectOptions.worldStateFileContents || connectOptions.worldStateFileContents.length < 3 * 1024 * 1024) { + localStorage.lastConnectOptions = JSON.stringify(connectOptions) + if (process.env.NODE_ENV === 'development' && !localStorage.lockUrl && !location.search.slice(1).length) { + lockUrl() + } + } else { + localStorage.removeItem('lastConnectOptions') + } + connectOptions.onSuccessfulPlay?.() + updateDataAfterJoin() + const password = findServerPassword() + if (password) { + setTimeout(() => { + bot.chat(`/login ${password}`) + }, 500) + } + + + console.log('bot spawned - starting viewer') + await appViewer.startWorld(bot.world, renderDistance) + appViewer.worldView!.listenToBot(bot) + if (appViewer.backend) { + void appViewer.worldView!.init(bot.entity.position) + } + + initMotionTracking() + + // Bot position callback + const botPosition = () => { + appViewer.lastCamUpdate = Date.now() + // this might cause lag, but not sure + appViewer.backend?.updateCamera(bot.entity.position, bot.entity.yaw, bot.entity.pitch) + void appViewer.worldView?.updatePosition(bot.entity.position) + } + bot.on('move', botPosition) + botPosition() + + progress.setMessage('Setting callbacks') + + onGameLoad() + + if (appStatusState.isError) return + + const waitForChunks = async () => { + if (appQueryParams.sp === '1') return //todo + const waitForChunks = options.waitForChunksRender === 'sp-only' ? !!singleplayer : options.waitForChunksRender + if (!appViewer.backend || appViewer.rendererState.world.allChunksLoaded || !waitForChunks) { + return + } + + await progress.executeWithMessage( + 'Loading chunks', + 'chunks', + async () => { + await waitForChunksToLoad(progress) + } + ) + } + + await waitForChunks() + + setTimeout(() => { + if (appQueryParams.suggest_save) { + showNotification('Suggestion', 'Save the world to keep your progress!', false, undefined, async () => { + const savePath = await saveToBrowserMemory() + if (!savePath) return + const saveName = savePath.split('/').pop() + bot.end() + // todo hot reload + location.search = `loadSave=${saveName}` + }) + } + }, 600) + + miscUiState.gameLoaded = true + miscUiState.loadedServerIndex = connectOptions.serverIndex ?? '' + customEvents.emit('gameLoaded') + + // Test iOS Safari crash by creating memory pressure + if (appQueryParams.testIosCrash) { + setTimeout(() => { + console.log('Starting iOS crash test with memory pressure...') + // eslint-disable-next-line sonarjs/no-unused-collection + const arrays: number[][] = [] + try { + // Create large arrays until we run out of memory + // eslint-disable-next-line no-constant-condition + while (true) { + const arr = Array.from({ length: 1024 * 1024 }).fill(0).map((_, i) => i) + arrays.push(arr) + } + } catch (e) { + console.error('Memory allocation failed:', e) + } + }, 1000) + } + + progress.end() + setLoadingScreenStatus(undefined) + } catch (err) { + handleError(err) + } + hadConnected = true + } + // don't use spawn event, player can be dead + bot.once(spawnEarlier ? 'forcedMove' : 'health', displayWorld) + + if (singleplayer && connectOptions.serverOverrides.worldFolder) { + fsState.saveLoaded = true + } + + if (!connectOptions.ignoreQs || process.env.NODE_ENV === 'development') { // todo cleanup customEvents.on('gameLoaded', () => { - const qs = new URLSearchParams(window.location.search) - for (let command of qs.getAll('command')) { + const commands = appQueryParamsArray.command ?? [] + for (let command of commands) { if (!command.startsWith('/')) command = `/${command}` - bot.chat(command) + const builtinHandled = tryHandleBuiltinCommand(command) + if (!builtinHandled) { + bot.chat(command) + } } }) } } listenGlobalEvents() -watchValue(miscUiState, async s => { - if (s.appLoaded) { // fs ready - const qs = new URLSearchParams(window.location.search) - if (qs.get('singleplayer') === '1') { - loadSingleplayer({}, { - worldFolder: undefined - }) - } - if (qs.get('loadSave')) { - const savePath = `/data/worlds/${qs.get('loadSave')}` - try { - await fs.promises.stat(savePath) - } catch (err) { - alert(`Save ${savePath} not found`) - return - } - await loadInMemorySave(savePath) - } - } -}) // #region fire click event on touch as we disable default behaviors let activeTouch: { touch: Touch, elem: HTMLElement, start: number } | undefined @@ -840,8 +908,8 @@ document.body.addEventListener('touchend', (e) => { activeTouch = undefined }) document.body.addEventListener('touchstart', (e) => { - const ignoreElem = (e.target as HTMLElement).matches('vercel-live-feedback') || (e.target as HTMLElement).closest('.hotbar') - if (!isGameActive(true) || ignoreElem) return + const targetElement = (e.target as HTMLElement).closest('#ui-root') + if (!isGameActive(true) || !targetElement) 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 @@ -861,70 +929,149 @@ document.body.addEventListener('touchstart', (e) => { }, { passive: false }) // #endregion -void window.fetch('config.json').then(async res => res.json()).then(c => c, (error) => { - console.warn('Failed to load optional app config.json', error) - return {} -}).then((config: AppConfig | {}) => { - miscUiState.appConfig = config -}) +// immediate game enter actions: reconnect or URL QS +const maybeEnterGame = () => { + const waitForConfigFsLoad = (fn: () => void) => { + let unsubscribe: () => void | undefined + const checkDone = () => { + if (miscUiState.fsReady && miscUiState.appConfig) { + fn() + unsubscribe?.() + return true + } + return false + } -// 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') + if (!checkDone()) { + const text = miscUiState.appConfig ? 'Loading' : 'Loading config' + setLoadingScreenStatus(text) + unsubscribe = subscribe(miscUiState, checkDone) + } + } + + const reconnectOptions = sessionStorage.getItem('reconnectOptions') ? JSON.parse(sessionStorage.getItem('reconnectOptions')!) : undefined + + if (reconnectOptions) { + sessionStorage.removeItem('reconnectOptions') + if (Date.now() - reconnectOptions.timestamp < 1000 * 60 * 2) { + return waitForConfigFsLoad(async () => { + void connect(reconnectOptions.value) + }) + } + } + + if (appQueryParams.reconnect && localStorage.lastConnectOptions && process.env.NODE_ENV === 'development') { const lastConnect = JSON.parse(localStorage.lastConnectOptions ?? {}) + return waitForConfigFsLoad(async () => { + void connect({ + botVersion: appQueryParams.version ?? undefined, + ...lastConnect, + ip: appQueryParams.ip || undefined + }) + }) + } + + if (appQueryParams.singleplayer === '1' || appQueryParams.sp === '1') { + return waitForConfigFsLoad(async () => { + loadSingleplayer({}, { + worldFolder: undefined, + ...appQueryParams.version ? { version: appQueryParams.version } : {} + }) + }) + } + if (appQueryParams.loadSave) { + const enterSave = async () => { + const savePath = `/data/worlds/${appQueryParams.loadSave}` + try { + await fs.promises.stat(savePath) + await loadInMemorySave(savePath) + } catch (err) { + alert(`Save ${savePath} not found`) + } + } + return waitForConfigFsLoad(enterSave) + } + + if (appQueryParams.ip || appQueryParams.proxy) { + const openServerAction = () => { + if (appQueryParams.autoConnect && miscUiState.appConfig?.allowAutoConnect) { + void connect({ + server: appQueryParams.ip, + proxy: getCurrentProxy(), + botVersion: appQueryParams.version ?? undefined, + username: getCurrentUsername()!, + }) + return + } + + setLoadingScreenStatus(undefined) + if (appQueryParams.onlyConnect || process.env.ALWAYS_MINIMAL_SERVER_UI === 'true') { + showModal({ reactType: 'only-connect-server' }) + } else { + showModal({ reactType: 'editServer' }) + } + } + + // showModal({ reactType: 'empty' }) + return waitForConfigFsLoad(openServerAction) + } + + if (appQueryParams.connectPeer) { + // try to connect to peer + const peerId = appQueryParams.connectPeer + const peerOptions = {} as ConnectPeerOptions + if (appQueryParams.server) { + peerOptions.server = appQueryParams.server + } + const version = appQueryParams.peerVersion + let username: string | null = options.guestUsername + if (options.askGuestName) username = prompt('Enter your username to connect to peer', username) + if (!username) return + options.guestUsername = username void connect({ - ...lastConnect, // todo mixing is not good idea - ip: ip || undefined + username, + botVersion: version || undefined, + peerId, + peerOptions + }) + return + + } + + if (appQueryParams.viewerConnect) { + void connect({ + username: `viewer-${Math.random().toString(36).slice(2, 10)}`, + viewerWsConnect: appQueryParams.viewerConnect, }) return } - if (qs.get('ip') || qs.get('proxy')) { - const waitAppConfigLoad = !qs.get('proxy') - const openServerEditor = () => { - hideModal() - // show server editor for connect or save - showModal({ reactType: 'editServer' }) - } - showModal({ reactType: 'empty' }) - if (waitAppConfigLoad) { - const unsubscribe = subscribe(miscUiState, checkCanDisplay) - checkCanDisplay() - // eslint-disable-next-line no-inner-declarations - function checkCanDisplay () { - if (miscUiState.appConfig) { - unsubscribe() - openServerEditor() - return true - } - } - } else { - openServerEditor() + + if (appQueryParams.modal) { + const modals = appQueryParams.modal.split(',') + for (const modal of modals) { + showModal({ reactType: modal }) } + return } - void Promise.resolve().then(() => { - // try to connect to peer - const peerId = qs.get('connectPeer') - const version = qs.get('peerVersion') - if (peerId) { - let username: string | null = options.guestUsername - if (options.askGuestName) username = prompt('Enter your username', username) - if (!username) return - options.guestUsername = username - void connect({ - username, - botVersion: version || undefined, - peerId - }) - } - }) -}, (err) => { + if (appQueryParams.serversList && !miscUiState.appConfig?.appParams?.serversList) { + // open UI only if it's in URL + showModal({ reactType: 'serversList' }) + } + + if (isInterestedInDownload()) { + void downloadAndOpenFile() + } + + void possiblyHandleStateVariable() +} + +try { + maybeEnterGame() +} catch (err) { console.error(err) - alert(`Failed to download file: ${err}`) -}) + alert(`Something went wrong: ${err}`) +} // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion const initialLoader = document.querySelector('.initial-loader') as HTMLElement | null @@ -934,4 +1081,5 @@ if (initialLoader) { } window.pageLoaded = true -void possiblyHandleStateVariable() +appViewer.waitBackendLoadPromises.push(appStartup()) +registerOpenBenchmarkListener() diff --git a/src/interactionShapesGenerated.json b/src/interactionShapesGenerated.json index 425cfb0d..804952e0 100644 --- a/src/interactionShapesGenerated.json +++ b/src/interactionShapesGenerated.json @@ -457,7 +457,14 @@ 13, 14 ], - "powder_snow": "PowderSnowBlock", + "powder_snow": [ + 0, + 0, + 0, + 16, + 16, + 16 + ], "spore_blossom": [ 2, 13, @@ -1311,55 +1318,47 @@ 13 ], "lever": { - "face=ceiling,facing=east": [ - 4, - 0, - 5, - 12, - 6, - 11 - ], - "face=ceiling,facing=north": [ - 5, - 0, - 4, - 11, - 6, - 12 - ], - "face=ceiling,facing=south": [ - 5, - 0, - 4, - 11, - 6, - 12 - ], - "face=ceiling,facing=west": [ - 4, - 0, - 5, - 12, - 6, - 11 - ], "face=floor,facing=east": [ 4, - 10, + 0, 5, 12, - 16, + 6, 11 ], "face=floor,facing=north": [ 5, - 10, + 0, 4, 11, - 16, + 6, 12 ], "face=floor,facing=south": [ + 5, + 0, + 4, + 11, + 6, + 12 + ], + "face=floor,facing=west": [ + 4, + 0, + 5, + 12, + 6, + 11 + ], + "face=ceiling,facing=east": [ + 4, + 10, + 5, + 12, + 16, + 11 + ], + "face=ceiling,facing=north": [ 5, 10, 4, @@ -1367,7 +1366,15 @@ 16, 12 ], - "face=floor,facing=west": [ + "face=ceiling,facing=south": [ + 5, + 10, + 4, + 11, + 16, + 12 + ], + "face=ceiling,facing=west": [ 4, 10, 5, @@ -1632,20 +1639,20 @@ }, "stone_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -1664,34 +1671,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -1760,20 +1767,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -1792,34 +1799,34 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] @@ -2374,20 +2381,20 @@ }, "oak_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -2406,34 +2413,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -2502,20 +2509,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -2534,54 +2541,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "spruce_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -2600,34 +2607,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -2696,20 +2703,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -2728,54 +2735,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "birch_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -2794,34 +2801,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -2890,20 +2897,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -2922,54 +2929,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "jungle_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -2988,34 +2995,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -3084,20 +3091,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -3116,54 +3123,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "acacia_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -3182,34 +3189,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -3278,20 +3285,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -3310,54 +3317,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "cherry_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -3376,34 +3383,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -3472,20 +3479,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -3504,54 +3511,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "dark_oak_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -3570,34 +3577,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -3666,20 +3673,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -3698,54 +3705,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "mangrove_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -3764,34 +3771,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -3860,20 +3867,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -3892,54 +3899,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "bamboo_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -3958,34 +3965,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -4054,20 +4061,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -4086,34 +4093,34 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] @@ -5813,20 +5820,20 @@ }, "crimson_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -5845,34 +5852,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -5941,20 +5948,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -5973,54 +5980,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "warped_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -6039,34 +6046,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -6135,20 +6142,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -6167,34 +6174,34 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] @@ -6303,20 +6310,20 @@ }, "polished_blackstone_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -6335,34 +6342,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -6431,20 +6438,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -6463,34 +6470,34 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] @@ -6547,7 +6554,6 @@ 16, 15 ], - "pink_petals": "PinkPetalsBlock", "big_dripleaf_stem": { "facing=north": [ 5, diff --git a/src/inventoryWindows.ts b/src/inventoryWindows.ts index d87d4008..d40260df 100644 --- a/src/inventoryWindows.ts +++ b/src/inventoryWindows.ts @@ -1,107 +1,123 @@ -import { subscribe } from 'valtio' +import { proxy, subscribe } from 'valtio' import { showInventory } from 'minecraft-inventory-gui/web/ext.mjs' -import InventoryGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/inventory.png' -import ChestLikeGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/shulker_box.png' -import LargeChestLikeGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/generic_54.png' -import FurnaceGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/furnace.png' -import CraftingTableGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/crafting_table.png' -import DispenserGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/dispenser.png' -import HopperGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/hopper.png' -import HorseGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/horse.png' -import VillagerGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/villager2.png' -import EnchantingGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/enchanting_table.png' -import AnvilGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/anvil.png' -import BeaconGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/beacon.png' -import WidgetsGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/widgets.png' -import Dirt from 'minecraft-assets/minecraft-assets/data/1.17.1/blocks/dirt.png' -import { subscribeKey } from 'valtio/utils' -import MinecraftData, { RecipeItem } from 'minecraft-data' -import { getVersion } from 'prismarine-viewer/viewer/lib/version' -import { versionToNumber } from 'prismarine-viewer/viewer/prepare/utils' -import itemsPng from 'prismarine-viewer/public/textures/items.png' -import itemsLegacyPng from 'prismarine-viewer/public/textures/items-legacy.png' -import _itemsAtlases from 'prismarine-viewer/public/textures/items.json' -import type { ItemsAtlasesOutputJson } from 'prismarine-viewer/viewer/prepare/genItemsAtlas' -import PrismarineBlockLoader from 'prismarine-block' -import { flat } from '@xmcl/text-component' -import mojangson from 'mojangson' -import nbt from 'prismarine-nbt' +// import Dirt from 'mc-assets/dist/other-textures/latest/blocks/dirt.png' +import { RecipeItem } from 'minecraft-data' +import { flat, fromFormattedString } from '@xmcl/text-component' import { splitEvery, equals } from 'rambda' import PItem, { Item } from 'prismarine-item' +import { versionToNumber } from 'renderer/viewer/common/utils' +import { getRenamedData } from 'flying-squid/dist/blockRenames' +import PrismarineChatLoader from 'prismarine-chat' +import * as nbt from 'prismarine-nbt' +import { BlockModel } from 'mc-assets' +import { renderSlot } from 'renderer/viewer/three/renderSlot' +import { loadSkinFromUsername } from 'renderer/viewer/lib/utils/skins' import Generic95 from '../assets/generic_95.png' -import { activeModalStack, hideCurrentModal, miscUiState, showModal } from './globalState' -import invspriteJson from './invsprite.json' +import { appReplacableResources } from './generated/resources' +import { activeModalStack, hideCurrentModal, hideModal, miscUiState, showModal } from './globalState' import { options } from './optionsStorage' import { assertDefined, inGameError } from './utils' -import { MessageFormatPart } from './botUtils' +import { displayClientChat } from './botUtils' import { currentScaling } from './scaleInterface' +import { getItemDescription } from './itemsDescriptions' +import { MessageFormatPart } from './chatUtils' +import { GeneralInputItem, getItemMetadata, getItemModelName, getItemNameRaw, RenderItem } from './mineflayer/items' +import { playerState } from './mineflayer/playerState' +import { modelViewerState } from './react/OverlayModelViewer' -export const itemsAtlases: ItemsAtlasesOutputJson = _itemsAtlases -const loadedImagesCache = new Map() +const loadedImagesCache = new Map() const cleanLoadedImagesCache = () => { loadedImagesCache.delete('blocks') + loadedImagesCache.delete('items') } -export type BlockStates = Record -}> let lastWindow: ReturnType +let lastWindowType: string | null | undefined // null is inventory /** bot version */ let version: string -let PrismarineBlock: typeof PrismarineBlockLoader.Block let PrismarineItem: typeof Item -export const onGameLoad = (onLoad) => { - let loaded = 0 - const onImageLoaded = () => { - loaded++ - if (loaded === 3) onLoad?.() +export const jeiCustomCategories = proxy({ + value: [] as Array<{ id: string, categoryTitle: string, items: any[] }> +}) + +let remotePlayerSkin: string | undefined | Promise + +export const showInventoryPlayer = () => { + modelViewerState.model = { + positioning: { + windowWidth: 176, + windowHeight: 166, + x: 25, + y: 8, + width: 50, + height: 70, + scaled: true, + onlyInitialScale: true, + followCursor: true, + }, + // models: ['https://bucket.mcraft.fun/sitarbuckss.glb'], + // debug: true, + steveModelSkin: appViewer.playerState.reactive.playerSkin ?? (typeof remotePlayerSkin === 'string' ? remotePlayerSkin : ''), } + if (remotePlayerSkin === undefined && !appViewer.playerState.reactive.playerSkin) { + remotePlayerSkin = loadSkinFromUsername(bot.username, 'skin').then(a => { + setTimeout(() => { showInventoryPlayer() }, 0) // todo patch instead and make reactive + remotePlayerSkin = a ?? '' + return remotePlayerSkin + }) + } +} + +export const onGameLoad = () => { version = bot.version - getImage({ path: 'invsprite' }, onImageLoaded) - getImage({ path: 'items' }, onImageLoaded) - getImage({ path: 'items-legacy' }, onImageLoaded) - PrismarineBlock = PrismarineBlockLoader(version) + PrismarineItem = PItem(version) + const mapWindowType = (type: string, inventoryStart: number) => { + if (type === 'minecraft:container') { + if (inventoryStart === 45 - 9 * 4) return 'minecraft:generic_9x1' + if (inventoryStart === 45 - 9 * 3) return 'minecraft:generic_9x2' + if (inventoryStart === 45 - 9 * 2) return 'minecraft:generic_9x3' + if (inventoryStart === 45 - 9) return 'minecraft:generic_9x4' + if (inventoryStart === 45) return 'minecraft:generic_9x5' + if (inventoryStart === 45 + 9) return 'minecraft:generic_9x6' + } + return type + } + + const maybeParseNbtJson = (data: any) => { + if (typeof data === 'string') { + try { + data = JSON.parse(data) + } catch (err) { + // ignore + } + } + return nbt.simplify(data) ?? data + } + bot.on('windowOpen', (win) => { - if (implementedContainersGuiMap[win.type]) { - // todo also render title! - openWindow(implementedContainersGuiMap[win.type]) + const implementedWindow = implementedContainersGuiMap[mapWindowType(win.type as string, win.inventoryStart)] + if (implementedWindow) { + openWindow(implementedWindow, maybeParseNbtJson(win.title)) } else if (options.unimplementedContainers) { - openWindow('ChestWin') + openWindow('ChestWin', maybeParseNbtJson(win.title)) } else { // todo format - bot._client.emit('chat', { - message: JSON.stringify({ - text: `[client error] cannot open unimplemented window ${win.id} (${win.type}). Slots: ${win.slots.map(item => getItemName(item)).filter(Boolean).join(', ')}` - }) - }) + displayClientChat(`[client error] cannot open unimplemented window ${win.id} (${win.type}). Slots: ${win.slots.map(item => getItemName(item)).filter(Boolean).join(', ')}`) bot.currentWindow?.['close']() } }) + // workaround: singleplayer player inventory crafting + let skipUpdate = false bot.inventory.on('updateSlot', ((_oldSlot, oldItem, newItem) => { - const oldSlot = _oldSlot as number - if (!miscUiState.singleplayer) return + const currentSlot = _oldSlot as number + if (!miscUiState.singleplayer || oldItem === newItem || skipUpdate) return const { craftingResultSlot } = bot.inventory - if (oldSlot === craftingResultSlot && oldItem && !newItem) { + if (currentSlot === craftingResultSlot && oldItem && !newItem) { for (let i = 1; i < 5; i++) { const count = bot.inventory.slots[i]?.count if (count && count > 1) { @@ -114,14 +130,25 @@ export const onGameLoad = (onLoad) => { } return } + if (currentSlot > 4) return const craftingSlots = bot.inventory.slots.slice(1, 5) - const resultingItem = getResultingRecipe(craftingSlots, 2) - void bot.creative.setInventorySlot(craftingResultSlot, resultingItem ?? null) + try { + const resultingItem = getResultingRecipe(craftingSlots, 2) + skipUpdate = true + void bot.creative.setInventorySlot(craftingResultSlot, resultingItem ?? null).then(() => { + skipUpdate = false + }) + } catch (err) { + console.error(err) + // todo resolve the error! and why would we ever get here on every update? + } }) as any) bot.on('windowClose', () => { // todo hide up to the window itself! - hideCurrentModal() + if (lastWindow) { + hideCurrentModal() + } }) bot.on('respawn', () => { // todo validate logic against native client (maybe login) if (lastWindow) { @@ -133,91 +160,62 @@ export const onGameLoad = (onLoad) => { if (!lastWindow) return upJei(q) }) -} -const findTextureInBlockStates = (name) => { - assertDefined(viewer) - const blockStates: BlockStates = viewer.world.customBlockStatesData || viewer.world.downloadedBlockStatesData - const vars = blockStates[name]?.variants - if (!vars) return - let firstVar = Object.values(vars)[0] - if (Array.isArray(firstVar)) firstVar = firstVar[0] - if (!firstVar) return - const elements = firstVar.model?.elements - if (elements?.length !== 1) return - return elements[0].faces -} - -const svSuToCoordinates = (path: string, u, v, su, sv = su) => { - const img = getImage({ path })! - if (!img.width) throw new Error(`Image ${path} is not loaded`) - return [u * img.width, v * img.height, su * img.width, sv * img.height] -} - -const getBlockData = (name) => { - const data = findTextureInBlockStates(name) - if (!data) return - - const getSpriteBlockSide = (side) => { - const d = data[side]?.texture - if (!d) return - const spriteSide = svSuToCoordinates('blocks', d.u, d.v, d.su, d.sv) - const blockSideData = { - slice: spriteSide, - path: 'blocks' + if (!appViewer.resourcesManager['_inventoryChangeTracked']) { + appViewer.resourcesManager['_inventoryChangeTracked'] = true + const texturesChanged = () => { + cleanLoadedImagesCache() + if (!lastWindow) return + upWindowItemsLocal() + upJei(lastJeiSearch) } - return blockSideData - } - - return { - // todo look at grass bug - top: getSpriteBlockSide('up') || getSpriteBlockSide('top'), - left: getSpriteBlockSide('east') || getSpriteBlockSide('side'), - right: getSpriteBlockSide('north') || getSpriteBlockSide('side'), + appViewer.resourcesManager.on('assetsInventoryReady', () => texturesChanged()) + appViewer.resourcesManager.on('assetsTexturesUpdated', () => texturesChanged()) } } -const getInvspriteSlice = (name) => { - const invspriteImg = loadedImagesCache.get('invsprite') - if (!invspriteImg?.width) return - - const { x, y } = invspriteJson[name] ?? /* unknown item */ { x: 0, y: 0 } - const sprite = [x, y, 32, 32] - return sprite -} - -const getImageSrc = (path): string | HTMLImageElement => { - assertDefined(viewer) +const getImageSrc = (path): string | HTMLImageElement | ImageBitmap => { switch (path) { - case 'gui/container/inventory': return InventoryGui - case 'blocks': return viewer.world.customTexturesDataUrl || viewer.world.downloadedTextureImage - case 'invsprite': return `invsprite.png` - case 'items': return itemsPng - case 'items-legacy': return itemsLegacyPng - case 'gui/container/dispenser': return DispenserGui - case 'gui/container/furnace': return FurnaceGui - case 'gui/container/crafting_table': return CraftingTableGui - case 'gui/container/shulker_box': return ChestLikeGui - case 'gui/container/generic_54': return LargeChestLikeGui + case 'gui/container/inventory': return appReplacableResources.latest_gui_container_inventory.content + case 'blocks': return appViewer.resourcesManager.blocksAtlasParser.latestImage + case 'items': return appViewer.resourcesManager.itemsAtlasParser.latestImage + case 'gui': return appViewer.resourcesManager.currentResources!.guiAtlas!.image + case 'gui/container/dispenser': return appReplacableResources.latest_gui_container_dispenser.content + case 'gui/container/furnace': return appReplacableResources.latest_gui_container_furnace.content + case 'gui/container/crafting_table': return appReplacableResources.latest_gui_container_crafting_table.content + case 'gui/container/shulker_box': return appReplacableResources.latest_gui_container_shulker_box.content + case 'gui/container/generic_54': return appReplacableResources.latest_gui_container_generic_54.content case 'gui/container/generic_95': return Generic95 - case 'gui/container/hopper': return HopperGui - case 'gui/container/horse': return HorseGui - case 'gui/container/villager2': return VillagerGui - case 'gui/container/enchanting_table': return EnchantingGui - case 'gui/container/anvil': return AnvilGui - case 'gui/container/beacon': return BeaconGui - case 'gui/widgets': return WidgetsGui + case 'gui/container/hopper': return appReplacableResources.latest_gui_container_hopper.content + case 'gui/container/horse': return appReplacableResources.latest_gui_container_horse.content + case 'gui/container/villager2': return appReplacableResources.latest_gui_container_villager2.content + case 'gui/container/enchanting_table': return appReplacableResources.latest_gui_container_enchanting_table.content + case 'gui/container/anvil': return appReplacableResources.latest_gui_container_anvil.content + case 'gui/container/beacon': return appReplacableResources.latest_gui_container_beacon.content + case 'gui/widgets': return appReplacableResources.other_textures_latest_gui_widgets.content } - return Dirt + // empty texture + return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=' } -const getImage = ({ path = undefined as string | undefined, texture = undefined as string | undefined, blockData = undefined as any }, onLoad = () => { }) => { - if (!path && !texture) throw new Error('Either pass path or texture') +const getImage = ({ path = undefined as string | undefined, texture = undefined as string | undefined, blockData = undefined as any, image = undefined as HTMLImageElement | undefined }, onLoad = () => { }) => { + if (image) { + return image + } + if (!path && !texture) { + throw new Error('Either pass path or texture') + } const loadPath = (blockData ? 'blocks' : path ?? texture)! if (loadedImagesCache.has(loadPath)) { onLoad() } else { const imageSrc = getImageSrc(loadPath) + if (imageSrc instanceof ImageBitmap) { + onLoad() + loadedImagesCache.set(loadPath, imageSrc) + return imageSrc + } + let image: HTMLImageElement if (imageSrc instanceof Image) { image = imageSrc @@ -231,125 +229,70 @@ const getImage = ({ path = undefined as string | undefined, texture = undefined return loadedImagesCache.get(loadPath) } -const getItemVerToRender = (version: string, item: string, itemsMapSortedEntries: any[]) => { - const verNumber = versionToNumber(version) - for (const [itemsVer, items] of itemsMapSortedEntries) { - // 1.18 < 1.18.1 - // 1.13 < 1.13.2 - if (items.includes(item) && verNumber <= versionToNumber(itemsVer)) { - return itemsVer as string - } - } -} - -const isFullBlock = (block: string) => { - const blockData = loadedData.blocksByName[block] - if (!blockData) return false - const pBlock = new PrismarineBlock(blockData.id, 0, 0) - if (pBlock.shapes?.length !== 1) return false - const shape = pBlock.shapes[0]! - return shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1 -} - -type RenderSlot = Pick -const renderSlot = (slot: RenderSlot, skipBlock = false): { texture: string, blockData?, scale?: number, slice?: number[] } | undefined => { - const itemName = slot.name - const isItem = loadedData.itemsByName[itemName] - const fullBlock = isFullBlock(itemName) - - if (isItem) { - const legacyItemVersion = getItemVerToRender(version, itemName, itemsAtlases.legacyMap) - const vuToSlice = ({ u, v }, size) => [...svSuToCoordinates('items', u, v, size).slice(0, 2), 16, 16] // item size is fixed - if (legacyItemVersion) { - const textureData = itemsAtlases.legacy.textures[`${legacyItemVersion}-${itemName}`]! - return { - texture: 'items-legacy', - slice: vuToSlice(textureData, itemsAtlases.legacy.size) - } - } - const textureData = itemsAtlases.latest.textures[itemName] - if (textureData) { - return { - texture: 'items', - slice: vuToSlice(textureData, itemsAtlases.latest.size) - } - } - } - if (fullBlock && !skipBlock) { - const blockData = getBlockData(itemName) - if (blockData) { - return { - texture: 'blocks', - blockData - } - } - } - const invspriteSlice = getInvspriteSlice(itemName) - if (invspriteSlice) { - return { - texture: 'invsprite', - scale: 0.5, - slice: invspriteSlice - } - } - console.warn(`No render data for ${itemName}`) - if (isItem) { - return { - texture: 'blocks', - slice: [0, 0, 16, 16] - } - } -} - -type JsonString = string -type PossibleItemProps = { - Damage?: number - display?: { Name?: JsonString } // {"text":"Knife","color":"white","italic":"true"} -} -export const getItemNameRaw = (item: Pick | null) => { - if (!item?.nbt) return - const itemNbt: PossibleItemProps = nbt.simplify(item.nbt) - const customName = itemNbt.display?.Name - if (!customName) return - const parsed = mojangson.simplify(mojangson.parse(customName)) - if (parsed.extra) { - return parsed as Record - } else { - return parsed as MessageFormatPart - } -} - -const getItemName = (slot: Item | null) => { - const parsed = getItemNameRaw(slot) +const getItemName = (slot: Item | RenderItem | null) => { + const parsed = getItemNameRaw(slot, appViewer.resourcesManager) if (!parsed) return // todo display full text renderer from sign renderer - const text = flat(parsed as MessageFormatPart).map(x => x.text) + const text = flat(parsed as MessageFormatPart).map(x => (typeof x === 'string' ? x : x.text)) return text.join('') } -export const renderSlotExternal = (slot) => { - const data = renderSlot(slot, true) - if (!data) return - return { - imageDataUrl: data.texture === 'invsprite' ? undefined : getImage({ path: data.texture })?.src, - sprite: data.slice && data.texture !== 'invsprite' ? data.slice.map(x => x * 2) : data.slice, - displayName: getItemName(slot) ?? slot.displayName, +let lastMappedSlots = [] as any[] +const itemToVisualKey = (slot: RenderItem | Item | null) => { + if (!slot) return '' + const keys = [ + slot.name, + slot.durabilityUsed, + slot.maxDurability, + slot['count'], + slot['metadata'], + slot.nbt ? JSON.stringify(slot.nbt) : '', + slot['components'] ? JSON.stringify(slot['components']) : '', + appViewer.resourcesManager.currentResources!.guiAtlasVersion, + ].join('|') + return keys +} +const validateSlot = (slot: any, index: number) => { + if (!slot.texture) { + throw new Error(`Slot has no texture: ${index} ${slot.name}`) } } +const mapSlots = (slots: Array, isJei = false) => { + const newSlots = slots.map((slot, i) => { + if (!slot) return null -const mapSlots = (slots: Array) => { - return slots.map(slot => { - // todo stateid - if (!slot) return + if (!isJei) { + const oldKey = lastMappedSlots[i]?.cacheKey + const newKey = itemToVisualKey(slot) + slot['cacheKey'] = i + '|' + newKey + if (oldKey && oldKey === newKey) { + validateSlot(lastMappedSlots[i], i) + return lastMappedSlots[i] + } + } try { - const slotCustomProps = renderSlot(slot) - Object.assign(slot, { ...slotCustomProps, displayName: ('nbt' in slot ? getItemName(slot) : undefined) ?? slot.displayName }) + if (slot.durabilityUsed && slot.maxDurability) slot.durabilityUsed = Math.min(slot.durabilityUsed, slot.maxDurability) + const debugIsQuickbar = !isJei && i === bot.inventory.hotbarStart + bot.quickBarSlot + const modelName = getItemModelName(slot, { 'minecraft:display_context': 'gui', }, appViewer.resourcesManager, appViewer.playerState.reactive) + const slotCustomProps = renderSlot({ modelName, originalItemName: slot.name }, appViewer.resourcesManager, debugIsQuickbar) + const itemCustomName = getItemName(slot) + Object.assign(slot, { ...slotCustomProps, displayName: itemCustomName ?? slot.displayName }) + //@ts-expect-error + slot.toJSON = () => { + // Allow to serialize slot to JSON as minecraft-inventory-gui creates icon property as cache (recursively) + //@ts-expect-error + const { icon, ...rest } = slot + return rest + } + validateSlot(slot, i) } catch (err) { inGameError(err) } return slot }) + lastMappedSlots = JSON.parse(JSON.stringify(newSlots)) + return newSlots } export const upInventoryItems = (isInventory: boolean, invWindow = lastWindow) => { @@ -357,6 +300,7 @@ export const upInventoryItems = (isInventory: boolean, invWindow = lastWindow) = // inv.pwindow.inv.slots[2].blockData = getBlockData('dirt') const customSlots = mapSlots((isInventory ? bot.inventory : bot.currentWindow)!.slots) invWindow.pwindow.setSlots(customSlots) + return customSlots } export const onModalClose = (callback: () => any) => { @@ -383,7 +327,10 @@ const implementedContainersGuiMap = { 'minecraft:generic_3x3': 'DropDispenseWin', 'minecraft:furnace': 'FurnaceWin', 'minecraft:smoker': 'FurnaceWin', + 'minecraft:shulker_box': 'ChestWin', + 'minecraft:blast_furnace': 'FurnaceWin', 'minecraft:crafting': 'CraftingWin', + 'minecraft:crafting3x3': 'CraftingWin', // todo different result slot 'minecraft:anvil': 'AnvilWin', // enchant 'minecraft:enchanting_table': 'EnchantingWin', @@ -393,24 +340,64 @@ const implementedContainersGuiMap = { 'minecraft:villager': 'VillagerWin', } +let lastJeiSearch = '' const upJei = (search: string) => { + lastJeiSearch = search search = search.toLowerCase() // todo fix pre flat - const matchedSlots = loadedData.itemsArray.map(x => { + const itemsArray = [ + ...jeiCustomCategories.value.flatMap(x => x.items).filter(x => x !== null), + ...loadedData.itemsArray.filter(x => x.displayName.toLowerCase().includes(search)).map(item => new PrismarineItem(item.id, 1)).filter(x => x !== null) + ] + const matchedSlots = itemsArray.map(x => { + x.displayName = getItemName(x) ?? x.displayName if (!x.displayName.toLowerCase().includes(search)) return null - return new PrismarineItem(x.id, 1) + return x }).filter(a => a !== null) lastWindow.pwindow.win.jeiSlotsPage = 0 - lastWindow.pwindow.win.jeiSlots = mapSlots(matchedSlots) + lastWindow.pwindow.win.jeiSlots = mapSlots(matchedSlots, true) } export const openItemsCanvas = (type, _bot = bot as typeof bot | null) => { - const inv = showInventory(type, getImage, {}, _bot) + const inv = showInventory(type, getImage, {}, _bot); + (inv.canvasManager.children[0].callbacks as any).getItemRecipes = (item) => { + const allRecipes = getAllItemRecipes(item.name) + inv.canvasManager.children[0].messageDisplay = '' + const itemDescription = getItemDescription(item) + if (!allRecipes?.length && !itemDescription) { + inv.canvasManager.children[0].messageDisplay = `No recipes found for ${item.displayName}` + } + return [...allRecipes ?? [], ...itemDescription ? [ + [ + 'GenericDescription', + mapSlots([item], true)[0], + [], + itemDescription + ] + ] : []] + } + (inv.canvasManager.children[0].callbacks as any).getItemUsages = (item) => { + const allItemUsages = getAllItemUsages(item.name) + inv.canvasManager.children[0].messageDisplay = '' + if (!allItemUsages?.length) { + inv.canvasManager.children[0].messageDisplay = `No usages found for ${item.displayName}` + } + return allItemUsages + } return inv } +const upWindowItemsLocal = () => { + if (!lastWindow && bot.currentWindow) { + // edge case: might happen due to high ping, inventory should be closed soon! + // openWindow(implementedContainersGuiMap[bot.currentWindow.type]) + return + } + void Promise.resolve().then(() => upInventoryItems(lastWindowType === null)) +} + let skipClosePacketSending = false -const openWindow = (type: string | undefined) => { +const openWindow = (type: string | undefined, title: string | any = 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) { @@ -421,6 +408,7 @@ const openWindow = (type: string | undefined) => { return } } + lastWindowType = type ?? null showModal({ reactType: `player_win:${type}`, }) @@ -429,64 +417,126 @@ const openWindow = (type: string | undefined) => { if (type !== undefined && bot.currentWindow && !skipClosePacketSending) bot.currentWindow['close']() lastWindow.destroy() lastWindow = null as any + lastWindowType = null + window.inventory = null miscUiState.displaySearchInput = false destroyFn() skipClosePacketSending = false + + modelViewerState.model = undefined }) + if (type === undefined) { + showInventoryPlayer() + } cleanLoadedImagesCache() const inv = openItemsCanvas(type) + inv.canvasManager.children[0].mobileHelpers = miscUiState.currentTouch + window.inventory = inv + const PrismarineChat = PrismarineChatLoader(bot.version) + try { + inv.canvasManager.children[0].customTitleText = title ? + typeof title === 'string' ? + fromFormattedString(title).text : + new PrismarineChat(title).toString() : + undefined + } catch (err) { + reportError?.(err) + inv.canvasManager.children[0].customTitleText = undefined + } // todo inv.canvasManager.setScale(currentScaling.scale === 1 ? 1.5 : currentScaling.scale) inv.canvas.style.zIndex = '10' inv.canvas.style.position = 'fixed' inv.canvas.style.inset = '0' - inv.canvasManager.onClose = () => { - hideCurrentModal() + inv.canvasManager.onClose = async () => { + await new Promise(resolve => { + setTimeout(resolve, 0) + }) + if (activeModalStack.at(-1)?.reactType?.includes('player_win:')) { + hideModal(undefined, undefined, { force: true }) + } inv.canvasManager.destroy() } lastWindow = inv - const upWindowItems = () => { - void Promise.resolve().then(() => upInventoryItems(type === undefined)) - } - upWindowItems() - lastWindow.pwindow.touch = miscUiState.currentTouch + upWindowItemsLocal() + + lastWindow.pwindow.touch = miscUiState.currentTouch ?? false + const oldOnInventoryEvent = lastWindow.pwindow.onInventoryEvent.bind(lastWindow.pwindow) + lastWindow.pwindow.onInventoryEvent = (type, containing, windowIndex, inventoryIndex, item) => { + if (inv.canvasManager.children[0].currentGuide) { + const isRightClick = type === 'rightclick' + const isLeftClick = type === 'leftclick' + if (isLeftClick || isRightClick) { + modelViewerState.model = undefined + inv.canvasManager.children[0].showRecipesOrUsages(isLeftClick, item) + } + } else { + oldOnInventoryEvent(type, containing, windowIndex, inventoryIndex, item) + } + } lastWindow.pwindow.onJeiClick = (slotItem, _index, isRightclick) => { + if (versionToNumber(bot.version) < versionToNumber('1.13')) { + alert('Item give is broken on 1.12.2 and below, we are working on it!') + return + } // slotItem is the slot from mapSlots const itemId = loadedData.itemsByName[slotItem.name]?.id if (!itemId) { inGameError(`Item for block ${slotItem.name} not found`) return } - const item = new PrismarineItem(itemId, isRightclick ? 64 : 1, slotItem.metadata) - const freeSlot = bot.inventory.firstEmptyInventorySlot() - if (freeSlot === null) return - void bot.creative.setInventorySlot(freeSlot, item) + const item = PrismarineItem.fromNotch({ + ...slotItem, + itemId, + itemCount: isRightclick ? 64 : 1, + components: slotItem.components ?? [], + removeComponents: slotItem.removedComponents ?? [], + itemDamage: slotItem.metadata ?? 0, + nbt: slotItem.nbt, + }) + if (bot.game.gameMode === 'creative') { + const freeSlot = bot.inventory.firstEmptyInventorySlot() + if (freeSlot === null) return + void bot.creative.setInventorySlot(freeSlot, item) + } else { + modelViewerState.model = undefined + inv.canvasManager.children[0].showRecipesOrUsages(!isRightclick, mapSlots([item], true)[0]) + } } - if (bot.game.gameMode === 'creative') { + const isJeiEnabled = () => { + if (typeof options.jeiEnabled === 'boolean') return options.jeiEnabled + if (Array.isArray(options.jeiEnabled)) { + return options.jeiEnabled.includes(bot.game?.gameMode as any) + } + return false + } + + if (isJeiEnabled()) { lastWindow.pwindow.win.jeiSlotsPage = 0 - // todo workaround so inventory opens immediately (but still lags) + // todo workaround so inventory opens immediately (though it still lags) setTimeout(() => { upJei('') }) miscUiState.displaySearchInput = true } else { lastWindow.pwindow.win.jeiSlots = [] + miscUiState.displaySearchInput = false } if (type === undefined) { // player inventory - bot.inventory.on('updateSlot', upWindowItems) + bot.inventory.on('updateSlot', upWindowItemsLocal) destroyFn = () => { - bot.inventory.off('updateSlot', upWindowItems) + bot.inventory.off('updateSlot', upWindowItemsLocal) } } else { //@ts-expect-error bot.currentWindow.on('updateSlot', () => { - upWindowItems() + upWindowItemsLocal() }) } } @@ -521,7 +571,7 @@ const getResultingRecipe = (slots: Array, gridRows: number) => { type Result = RecipeItem | undefined let shapelessResult: Result let shapeResult: Result - outer: for (const [id, recipeVariants] of Object.entries(loadedData.recipes)) { + outer: for (const [id, recipeVariants] of Object.entries(loadedData.recipes ?? {})) { for (const recipeVariant of recipeVariants) { if ('inShape' in recipeVariant && equals(currentShape, recipeVariant.inShape as number[][])) { shapeResult = recipeVariant.result! @@ -542,3 +592,75 @@ const getResultingRecipe = (slots: Array, gridRows: number) => { const item = new PrismarineItem(id, count, metadata) return item } + +const ingredientToItem = (recipeItem) => (recipeItem === null ? null : new PrismarineItem(recipeItem, 1)) + +const getAllItemRecipes = (itemName: string) => { + const item = loadedData.itemsByName[itemName] + if (!item) return + const itemId = item.id + const recipes = loadedData.recipes?.[itemId] + if (!recipes) return + const results = [] as Array<{ + result: Item, + ingredients: Array, + description?: string + }> + + // get recipes here + for (const recipe of recipes) { + const { result } = recipe + if (!result) continue + const resultId = typeof result === 'number' ? result : Array.isArray(result) ? result[0]! : result.id + const resultCount = (typeof result === 'number' ? undefined : Array.isArray(result) ? result[1] : result.count) ?? 1 + const resultMetadata = typeof result === 'object' && !Array.isArray(result) ? result.metadata : undefined + const resultItem = new PrismarineItem(resultId!, resultCount, resultMetadata) + if ('inShape' in recipe) { + const ingredients = recipe.inShape + if (!ingredients) continue + + const ingredientsItems = ingredients.flatMap(items => items.map(item => ingredientToItem(item))) + results.push({ result: resultItem, ingredients: ingredientsItems }) + } + if ('ingredients' in recipe) { + const { ingredients } = recipe + if (!ingredients) continue + const ingredientsItems = ingredients.map(item => ingredientToItem(item)) + results.push({ result: resultItem, ingredients: ingredientsItems, description: 'Shapeless' }) + } + } + return results.map(({ result, ingredients, description }) => { + return [ + 'CraftingTableGuide', + mapSlots([result], true)[0], + mapSlots(ingredients, true), + description + ] + }) +} + +const getAllItemUsages = (itemName: string) => { + const item = loadedData.itemsByName[itemName] + if (!item) return + const foundRecipeIds = [] as string[] + + for (const [id, recipes] of Object.entries(loadedData.recipes ?? {})) { + for (const recipe of recipes) { + if ('inShape' in recipe) { + if (recipe.inShape.some(row => row.includes(item.id))) { + foundRecipeIds.push(id) + } + } + if ('ingredients' in recipe) { + if (recipe.ingredients.includes(item.id)) { + foundRecipeIds.push(id) + } + } + } + } + + return foundRecipeIds.flatMap(id => { + // todo should use exact match, not include all recipes! + return getAllItemRecipes(loadedData.items[id].name) + }) +} diff --git a/src/invsprite.json b/src/invsprite.json deleted file mode 100644 index 58cd192d..00000000 --- a/src/invsprite.json +++ /dev/null @@ -1,4812 +0,0 @@ -{ - "air": { - "name": "Air", - "x": 832, - "y": 2336 - }, - "stone": { - "name": "Stone", - "x": 224, - "y": 992 - }, - "granite": { - "name": "Granite", - "x": 96, - "y": 3360 - }, - "polished_granite": { - "name": "Polished Granite", - "x": 384, - "y": 896 - }, - "diorite": { - "name": "Diorite", - "x": 64, - "y": 3360 - }, - "polished_diorite": { - "name": "Polished Diorite", - "x": 352, - "y": 896 - }, - "andesite": { - "name": "Andesite", - "x": 832, - "y": 3328 - }, - "polished_andesite": { - "name": "Polished Andesite", - "x": 320, - "y": 896 - }, - "grass_block": { - "name": "Grass Block", - "x": 640, - "y": 960 - }, - "dirt": { - "name": "Dirt", - "x": 576, - "y": 960 - }, - "coarse_dirt": { - "name": "Coarse Dirt", - "x": 416, - "y": 960 - }, - "podzol": { - "name": "Podzol", - "x": 352, - "y": 3360 - }, - "crimson_nylium": { - "name": "Crimson Nylium", - "x": 640, - "y": 128 - }, - "warped_nylium": { - "name": "Warped Nylium", - "x": 768, - "y": 128 - }, - "cobblestone": { - "name": "Cobblestone", - "x": 960, - "y": 3328 - }, - "oak_planks": { - "name": "Oak Planks", - "x": 192, - "y": 896 - }, - "spruce_planks": { - "name": "Spruce Planks", - "x": 0, - "y": 928 - }, - "birch_planks": { - "name": "Birch Planks", - "x": 832, - "y": 832 - }, - "jungle_planks": { - "name": "Jungle Planks", - "x": 992, - "y": 864 - }, - "acacia_planks": { - "name": "Acacia Planks", - "x": 672, - "y": 832 - }, - "dark_oak_planks": { - "name": "Dark Oak Planks", - "x": 512, - "y": 864 - }, - "crimson_planks": { - "name": "Crimson Planks", - "x": 544, - "y": 128 - }, - "warped_planks": { - "name": "Warped Planks", - "x": 576, - "y": 128 - }, - "oak_sapling": { - "name": "Oak Sapling", - "x": 192, - "y": 3424 - }, - "spruce_sapling": { - "name": "Spruce Sapling", - "x": 608, - "y": 3424 - }, - "birch_sapling": { - "name": "Birch Sapling", - "x": 416, - "y": 3392 - }, - "jungle_sapling": { - "name": "Jungle Sapling", - "x": 960, - "y": 3392 - }, - "acacia_sapling": { - "name": "Acacia Sapling", - "x": 224, - "y": 3392 - }, - "dark_oak_sapling": { - "name": "Dark Oak Sapling", - "x": 768, - "y": 3392 - }, - "bedrock": { - "name": "Bedrock", - "x": 320, - "y": 960 - }, - "sand": { - "name": "Sand", - "x": 480, - "y": 3360 - }, - "red_sand": { - "name": "Red Sand", - "x": 416, - "y": 3360 - }, - "gravel": { - "name": "Gravel", - "x": 128, - "y": 3360 - }, - "gold_ore": { - "name": "Gold Ore", - "x": 32, - "y": 3392 - }, - "iron_ore": { - "name": "Iron Ore", - "x": 64, - "y": 3392 - }, - "coal_ore": { - "name": "Coal Ore", - "x": 960, - "y": 3360 - }, - "nether_gold_ore": { - "name": "Nether Gold Ore", - "x": 288, - "y": 192 - }, - "oak_log": { - "name": "Oak Log", - "x": 160, - "y": 3424 - }, - "spruce_log": { - "name": "Spruce Log", - "x": 576, - "y": 3424 - }, - "birch_log": { - "name": "Birch Log", - "x": 384, - "y": 3392 - }, - "jungle_log": { - "name": "Jungle Log", - "x": 928, - "y": 3392 - }, - "acacia_log": { - "name": "Acacia Log", - "x": 192, - "y": 3392 - }, - "dark_oak_log": { - "name": "Dark Oak Log", - "x": 736, - "y": 3392 - }, - "crimson_stem": { - "name": "Crimson Stem", - "x": 672, - "y": 128 - }, - "warped_stem": { - "name": "Warped Stem", - "x": 800, - "y": 128 - }, - "stripped_oak_log": { - "name": "Stripped Oak Log", - "x": 288, - "y": 1664 - }, - "stripped_spruce_log": { - "name": "Stripped Spruce Log", - "x": 320, - "y": 1664 - }, - "stripped_birch_log": { - "name": "Stripped Birch Log", - "x": 192, - "y": 1664 - }, - "stripped_jungle_log": { - "name": "Stripped Jungle Log", - "x": 256, - "y": 1664 - }, - "stripped_acacia_log": { - "name": "Stripped Acacia Log", - "x": 160, - "y": 1664 - }, - "stripped_dark_oak_log": { - "name": "Stripped Dark Oak Log", - "x": 224, - "y": 1664 - }, - "stripped_crimson_stem": { - "name": "Stripped Crimson Stem", - "x": 448, - "y": 160 - }, - "stripped_warped_stem": { - "name": "Stripped Warped Stem", - "x": 480, - "y": 160 - }, - "stripped_oak_wood": { - "name": "Stripped Oak Wood", - "x": 576, - "y": 2080 - }, - "stripped_spruce_wood": { - "name": "Stripped Spruce Wood", - "x": 608, - "y": 2080 - }, - "stripped_birch_wood": { - "name": "Stripped Birch Wood", - "x": 640, - "y": 2080 - }, - "stripped_jungle_wood": { - "name": "Stripped Jungle Wood", - "x": 672, - "y": 2080 - }, - "stripped_acacia_wood": { - "name": "Stripped Acacia Wood", - "x": 704, - "y": 2080 - }, - "stripped_dark_oak_wood": { - "name": "Stripped Dark Oak Wood", - "x": 736, - "y": 2080 - }, - "stripped_crimson_hyphae": { - "name": "Stripped Crimson Hyphae", - "x": 224, - "y": 192 - }, - "stripped_warped_hyphae": { - "name": "Stripped Warped Hyphae", - "x": 256, - "y": 192 - }, - "oak_wood": { - "name": "Oak Wood", - "x": 704, - "y": 3264 - }, - "spruce_wood": { - "name": "Spruce Wood", - "x": 736, - "y": 3296 - }, - "birch_wood": { - "name": "Birch Wood", - "x": 0, - "y": 3232 - }, - "jungle_wood": { - "name": "Jungle Wood", - "x": 192, - "y": 3264 - }, - "acacia_wood": { - "name": "Acacia Wood", - "x": 768, - "y": 3200 - }, - "dark_oak_wood": { - "name": "Dark Oak Wood", - "x": 704, - "y": 3232 - }, - "crimson_hyphae": { - "name": "Crimson Hyphae", - "x": 160, - "y": 192 - }, - "warped_hyphae": { - "name": "Warped Hyphae", - "x": 192, - "y": 192 - }, - "oak_leaves": { - "name": "Oak Leaves", - "x": 128, - "y": 3424 - }, - "spruce_leaves": { - "name": "Spruce Leaves", - "x": 544, - "y": 3424 - }, - "birch_leaves": { - "name": "Birch Leaves", - "x": 352, - "y": 3392 - }, - "jungle_leaves": { - "name": "Jungle Leaves", - "x": 896, - "y": 3392 - }, - "acacia_leaves": { - "name": "Acacia Leaves", - "x": 160, - "y": 3392 - }, - "dark_oak_leaves": { - "name": "Dark Oak Leaves", - "x": 704, - "y": 3392 - }, - "sponge": { - "name": "Sponge", - "x": 896, - "y": 3584 - }, - "wet_sponge": { - "name": "Wet Sponge", - "x": 0, - "y": 3616 - }, - "glass": { - "name": "Glass", - "x": 960, - "y": 3232 - }, - "lapis_ore": { - "name": "Lapis Lazuli Ore", - "x": 96, - "y": 3392 - }, - "lapis_block": { - "name": "Lapis Lazuli Block", - "x": 256, - "y": 3264 - }, - "dispenser": { - "name": "Dispenser", - "x": 576, - "y": 3584 - }, - "sandstone": { - "name": "Sandstone", - "x": 512, - "y": 3360 - }, - "chiseled_sandstone": { - "name": "Chiseled Sandstone", - "x": 384, - "y": 3232 - }, - "cut_sandstone": { - "name": "Cut Sandstone", - "x": 544, - "y": 3232 - }, - "note_block": { - "name": "Note Block", - "x": 832, - "y": 3584 - }, - "powered_rail": { - "name": "Powered Rail", - "x": 448, - "y": 3328 - }, - "detector_rail": { - "name": "Detector Rail", - "x": 160, - "y": 3328 - }, - "sticky_piston": { - "name": "Sticky Piston", - "x": 704, - "y": 3328 - }, - "cobweb": { - "name": "Cobweb", - "x": 992, - "y": 3328 - }, - "grass": { - "name": "Grass", - "x": 864, - "y": 3392 - }, - "fern": { - "name": "Fern", - "x": 832, - "y": 3392 - }, - "dead_bush": { - "name": "Dead Bush", - "x": 800, - "y": 3392 - }, - "seagrass": { - "name": "Seagrass", - "x": 384, - "y": 2016 - }, - "sea_pickle": { - "name": "Sea Pickle", - "x": 224, - "y": 1728 - }, - "piston": { - "name": "Piston", - "x": 416, - "y": 3328 - }, - "white_wool": { - "name": "White Wool", - "x": 0, - "y": 1536 - }, - "orange_wool": { - "name": "Orange Wool", - "x": 896, - "y": 1504 - }, - "magenta_wool": { - "name": "Magenta Wool", - "x": 864, - "y": 1504 - }, - "light_blue_wool": { - "name": "Light Blue Wool", - "x": 768, - "y": 1504 - }, - "yellow_wool": { - "name": "Yellow Wool", - "x": 32, - "y": 1536 - }, - "lime_wool": { - "name": "Lime Wool", - "x": 832, - "y": 1504 - }, - "pink_wool": { - "name": "Pink Wool", - "x": 928, - "y": 1504 - }, - "gray_wool": { - "name": "Gray Wool", - "x": 704, - "y": 1504 - }, - "light_gray_wool": { - "name": "Light Gray Wool", - "x": 800, - "y": 1504 - }, - "cyan_wool": { - "name": "Cyan Wool", - "x": 672, - "y": 1504 - }, - "purple_wool": { - "name": "Purple Wool", - "x": 960, - "y": 1504 - }, - "blue_wool": { - "name": "Blue Wool", - "x": 608, - "y": 1504 - }, - "brown_wool": { - "name": "Brown Wool", - "x": 640, - "y": 1504 - }, - "green_wool": { - "name": "Green Wool", - "x": 736, - "y": 1504 - }, - "red_wool": { - "name": "Red Wool", - "x": 992, - "y": 1504 - }, - "black_wool": { - "name": "Black Wool", - "x": 576, - "y": 1504 - }, - "dandelion": { - "name": "Dandelion", - "x": 672, - "y": 3392 - }, - "poppy": { - "name": "Poppy", - "x": 352, - "y": 3424 - }, - "blue_orchid": { - "name": "Blue Orchid", - "x": 448, - "y": 3392 - }, - "allium": { - "name": "Allium", - "x": 256, - "y": 3392 - }, - "azure_bluet": { - "name": "Azure Bluet", - "x": 288, - "y": 3392 - }, - "red_tulip": { - "name": "Red Tulip", - "x": 480, - "y": 3424 - }, - "orange_tulip": { - "name": "Orange Tulip", - "x": 224, - "y": 3424 - }, - "white_tulip": { - "name": "White Tulip", - "x": 768, - "y": 3424 - }, - "pink_tulip": { - "name": "Pink Tulip", - "x": 320, - "y": 3424 - }, - "oxeye_daisy": { - "name": "Oxeye Daisy", - "x": 256, - "y": 3424 - }, - "cornflower": { - "name": "Cornflower", - "x": 640, - "y": 2368 - }, - "lily_of_the_valley": { - "name": "Lily of the Valley", - "x": 672, - "y": 2368 - }, - "wither_rose": { - "name": "Wither Rose", - "x": 608, - "y": 2368 - }, - "brown_mushroom": { - "name": "Brown Mushroom", - "x": 512, - "y": 3392 - }, - "red_mushroom": { - "name": "Red Mushroom", - "x": 448, - "y": 3424 - }, - "crimson_fungus": { - "name": "Crimson Fungus", - "x": 928, - "y": 128 - }, - "warped_fungus": { - "name": "Warped Fungus", - "x": 960, - "y": 128 - }, - "crimson_roots": { - "name": "Crimson Roots", - "x": 928, - "y": 160 - }, - "warped_roots": { - "name": "Warped Roots", - "x": 992, - "y": 160 - }, - "nether_sprouts": { - "name": "Nether Sprouts", - "x": 928, - "y": 64 - }, - "weeping_vines": { - "name": "Weeping Vines", - "x": 992, - "y": 128 - }, - "twisting_vines": { - "name": "Twisting Vines", - "x": 320, - "y": 192 - }, - "sugar_cane": { - "name": "Sugar Cane", - "x": 640, - "y": 3424 - }, - "kelp": { - "name": "Kelp", - "x": 576, - "y": 1664 - }, - "bamboo": { - "name": "Bamboo", - "x": 128, - "y": 2368 - }, - "gold_block": { - "name": "Block of Gold", - "x": 128, - "y": 3232 - }, - "iron_block": { - "name": "Block of Iron", - "x": 160, - "y": 3232 - }, - "oak_slab": { - "name": "Oak Slab", - "x": 640, - "y": 3264 - }, - "spruce_slab": { - "name": "Spruce Slab", - "x": 672, - "y": 3296 - }, - "birch_slab": { - "name": "Birch Slab", - "x": 960, - "y": 3200 - }, - "jungle_slab": { - "name": "Jungle Slab", - "x": 128, - "y": 3264 - }, - "acacia_slab": { - "name": "Acacia Slab", - "x": 704, - "y": 3200 - }, - "dark_oak_slab": { - "name": "Dark Oak Slab", - "x": 640, - "y": 3232 - }, - "crimson_slab": { - "name": "Crimson Slab", - "x": 32, - "y": 160 - }, - "warped_slab": { - "name": "Warped Slab", - "x": 128, - "y": 160 - }, - "stone_slab": { - "name": "Stone Slab", - "x": 864, - "y": 3296 - }, - "smooth_stone_slab": { - "name": "Smooth Stone Slab", - "x": 544, - "y": 3296 - }, - "sandstone_slab": { - "name": "Sandstone Slab", - "x": 192, - "y": 3296 - }, - "cut_sandstone_slab": { - "name": "Cut Sandstone Slab", - "x": 64, - "y": 2464 - }, - "petrified_oak_slab": { - "name": "Petrified Oak Slab", - "x": 224, - "y": 896 - }, - "cobblestone_slab": { - "name": "Cobblestone Slab", - "x": 416, - "y": 3232 - }, - "brick_slab": { - "name": "Brick Slab", - "x": 256, - "y": 3232 - }, - "stone_brick_slab": { - "name": "Stone Brick Slab", - "x": 128, - "y": 928 - }, - "nether_brick_slab": { - "name": "Nether Brick Slab", - "x": 480, - "y": 3264 - }, - "quartz_slab": { - "name": "Quartz Slab", - "x": 960, - "y": 3264 - }, - "red_sandstone_slab": { - "name": "Red Sandstone Slab", - "x": 96, - "y": 3296 - }, - "cut_red_sandstone_slab": { - "name": "Cut Red Sandstone Slab", - "x": 32, - "y": 2464 - }, - "purpur_slab": { - "name": "Purpur Slab", - "x": 896, - "y": 3264 - }, - "prismarine_slab": { - "name": "Dark Prismarine Slab", - "x": 736, - "y": 3232 - }, - "prismarine_brick_slab": { - "name": "Prismarine Brick Slab", - "x": 864, - "y": 3264 - }, - "dark_prismarine_slab": { - "name": "Dark Prismarine Slab", - "x": 736, - "y": 3232 - }, - "smooth_quartz": { - "name": "Smooth Quartz Block", - "x": 64, - "y": 864 - }, - "smooth_red_sandstone": { - "name": "Smooth Red Sandstone", - "x": 416, - "y": 3296 - }, - "smooth_sandstone": { - "name": "Smooth Sandstone", - "x": 512, - "y": 3296 - }, - "smooth_stone": { - "name": "Smooth Stone", - "x": 832, - "y": 896 - }, - "bricks": { - "name": "Bricks", - "x": 416, - "y": 96 - }, - "tnt": { - "name": "TNT", - "x": 960, - "y": 3584 - }, - "bookshelf": { - "name": "Bookshelf", - "x": 224, - "y": 3232 - }, - "mossy_cobblestone": { - "name": "Mossy Cobblestone", - "x": 192, - "y": 3360 - }, - "obsidian": { - "name": "Obsidian", - "x": 288, - "y": 3360 - }, - "torch": { - "name": "Torch", - "x": 928, - "y": 3360 - }, - "end_rod": { - "name": "End Rod", - "x": 672, - "y": 3168 - }, - "chorus_plant": { - "name": "Chorus Plant", - "x": 640, - "y": 3392 - }, - "chorus_flower": { - "name": "Chorus Flower", - "x": 608, - "y": 3392 - }, - "purpur_block": { - "name": "Purpur Block", - "x": 416, - "y": 896 - }, - "purpur_pillar": { - "name": "Purpur Pillar", - "x": 448, - "y": 896 - }, - "purpur_stairs": { - "name": "Purpur Stairs", - "x": 928, - "y": 3264 - }, - "spawner": { - "name": "Spawner", - "x": 576, - "y": 3360 - }, - "oak_stairs": { - "name": "Oak Stairs", - "x": 672, - "y": 3264 - }, - "chest": { - "name": "Chest", - "x": 704, - "y": 1216 - }, - "diamond_ore": { - "name": "Diamond Ore", - "x": 992, - "y": 3360 - }, - "diamond_block": { - "name": "Block of Diamond", - "x": 64, - "y": 3232 - }, - "crafting_table": { - "name": "Crafting Table", - "x": 512, - "y": 3584 - }, - "farmland": { - "name": "Farmland", - "x": 672, - "y": 864 - }, - "furnace": { - "name": "Furnace", - "x": 704, - "y": 3584 - }, - "ladder": { - "name": "Ladder", - "x": 224, - "y": 3264 - }, - "rail": { - "name": "Rail", - "x": 480, - "y": 3328 - }, - "cobblestone_stairs": { - "name": "Cobblestone Stairs", - "x": 448, - "y": 3232 - }, - "lever": { - "name": "Lever", - "x": 288, - "y": 3328 - }, - "stone_pressure_plate": { - "name": "Stone Pressure Plate", - "x": 768, - "y": 3328 - }, - "oak_pressure_plate": { - "name": "Oak Pressure Plate", - "x": 384, - "y": 3328 - }, - "spruce_pressure_plate": { - "name": "Spruce Pressure Plate", - "x": 672, - "y": 3328 - }, - "birch_pressure_plate": { - "name": "Birch Pressure Plate", - "x": 32, - "y": 3328 - }, - "jungle_pressure_plate": { - "name": "Jungle Pressure Plate", - "x": 256, - "y": 3328 - }, - "acacia_pressure_plate": { - "name": "Acacia Pressure Plate", - "x": 960, - "y": 3296 - }, - "dark_oak_pressure_plate": { - "name": "Dark Oak Pressure Plate", - "x": 128, - "y": 3328 - }, - "crimson_pressure_plate": { - "name": "Crimson Pressure Plate", - "x": 256, - "y": 160 - }, - "warped_pressure_plate": { - "name": "Warped Pressure Plate", - "x": 384, - "y": 160 - }, - "polished_blackstone_pressure_plate": { - "name": "Polished Blackstone Pressure Plate", - "x": 928, - "y": 256 - }, - "redstone_ore": { - "name": "Redstone Ore", - "x": 128, - "y": 3392 - }, - "redstone_torch": { - "name": "Redstone Torch", - "x": 608, - "y": 3328 - }, - "snow": { - "name": "Snow", - "x": 544, - "y": 3360 - }, - "ice": { - "name": "Ice", - "x": 160, - "y": 3360 - }, - "snow_block": { - "name": "Snow Block", - "x": 576, - "y": 3296 - }, - "cactus": { - "name": "Cactus", - "x": 544, - "y": 3392 - }, - "clay": { - "name": "Clay", - "x": 928, - "y": 3328 - }, - "jukebox": { - "name": "Jukebox", - "x": 768, - "y": 3584 - }, - "oak_fence": { - "name": "Oak Fence", - "x": 608, - "y": 3264 - }, - "spruce_fence": { - "name": "Spruce Fence", - "x": 640, - "y": 3296 - }, - "birch_fence": { - "name": "Birch Fence", - "x": 928, - "y": 3200 - }, - "jungle_fence": { - "name": "Jungle Fence", - "x": 96, - "y": 3264 - }, - "acacia_fence": { - "name": "Acacia Fence", - "x": 672, - "y": 3200 - }, - "dark_oak_fence": { - "name": "Dark Oak Fence", - "x": 608, - "y": 3232 - }, - "crimson_fence": { - "name": "Crimson Fence", - "x": 0, - "y": 160 - }, - "warped_fence": { - "name": "Warped Fence", - "x": 96, - "y": 160 - }, - "pumpkin": { - "name": "Pumpkin", - "x": 384, - "y": 3424 - }, - "carved_pumpkin": { - "name": "Carved Pumpkin", - "x": 576, - "y": 3392 - }, - "netherrack": { - "name": "Netherrack", - "x": 832, - "y": 3360 - }, - "soul_sand": { - "name": "Soul Sand", - "x": 864, - "y": 3360 - }, - "soul_soil": { - "name": "Soul Soil", - "x": 736, - "y": 128 - }, - "basalt": { - "name": "Basalt", - "x": 608, - "y": 128 - }, - "polished_basalt": { - "name": "Polished Basalt", - "x": 416, - "y": 192 - }, - "soul_torch": { - "name": "Soul Torch", - "x": 864, - "y": 128 - }, - "glowstone": { - "name": "Glowstone", - "x": 672, - "y": 3360 - }, - "jack_o_lantern": { - "name": "Jack o'Lantern", - "x": 32, - "y": 3264 - }, - "oak_trapdoor": { - "name": "Oak Trapdoor", - "x": 928, - "y": 928 - }, - "spruce_trapdoor": { - "name": "Spruce Trapdoor", - "x": 448, - "y": 1632 - }, - "birch_trapdoor": { - "name": "Birch Trapdoor", - "x": 480, - "y": 1632 - }, - "jungle_trapdoor": { - "name": "Jungle Trapdoor", - "x": 512, - "y": 1632 - }, - "acacia_trapdoor": { - "name": "Acacia Trapdoor", - "x": 544, - "y": 1632 - }, - "dark_oak_trapdoor": { - "name": "Dark Oak Trapdoor", - "x": 576, - "y": 1632 - }, - "crimson_trapdoor": { - "name": "Crimson Trapdoor", - "x": 288, - "y": 160 - }, - "warped_trapdoor": { - "name": "Warped Trapdoor", - "x": 416, - "y": 160 - }, - "infested_stone": { - "name": "Infested Stone", - "x": 224, - "y": 992 - }, - "infested_cobblestone": { - "name": "Infested Cobblestone", - "x": 960, - "y": 3328 - }, - "infested_stone_bricks": { - "name": "Infested Stone Bricks", - "x": 608, - "y": 3360 - }, - "infested_mossy_stone_bricks": { - "name": "Infested Mossy Stone Bricks", - "x": 224, - "y": 3360 - }, - "infested_cracked_stone_bricks": { - "name": "Infested Cracked Stone Bricks", - "x": 0, - "y": 3360 - }, - "infested_chiseled_stone_bricks": { - "name": "Infested Chiseled Stone Bricks", - "x": 896, - "y": 3328 - }, - "stone_bricks": { - "name": "Stone Bricks", - "x": 608, - "y": 3360 - }, - "mossy_stone_bricks": { - "name": "Mossy Stone Bricks", - "x": 224, - "y": 3360 - }, - "cracked_stone_bricks": { - "name": "Cracked Stone Bricks", - "x": 0, - "y": 3360 - }, - "chiseled_stone_bricks": { - "name": "Chiseled Stone Bricks", - "x": 896, - "y": 3328 - }, - "brown_mushroom_block": { - "name": "Brown Mushroom Block", - "x": 480, - "y": 3392 - }, - "red_mushroom_block": { - "name": "Red Mushroom Block", - "x": 416, - "y": 3424 - }, - "mushroom_stem": { - "name": "Mushroom Stem", - "x": 96, - "y": 3424 - }, - "iron_bars": { - "name": "Iron Bars", - "x": 0, - "y": 3264 - }, - "chain": { - "name": "Chain", - "x": 32, - "y": 288 - }, - "glass_pane": { - "name": "Glass Pane", - "x": 928, - "y": 3232 - }, - "melon": { - "name": "Melon", - "x": 64, - "y": 3424 - }, - "vine": { - "name": "Vines", - "x": 736, - "y": 3424 - }, - "oak_fence_gate": { - "name": "Oak Fence Gate", - "x": 576, - "y": 3264 - }, - "spruce_fence_gate": { - "name": "Spruce Fence Gate", - "x": 608, - "y": 3296 - }, - "birch_fence_gate": { - "name": "Birch Fence Gate", - "x": 896, - "y": 3200 - }, - "jungle_fence_gate": { - "name": "Jungle Fence Gate", - "x": 64, - "y": 3264 - }, - "acacia_fence_gate": { - "name": "Acacia Fence Gate", - "x": 640, - "y": 3200 - }, - "dark_oak_fence_gate": { - "name": "Dark Oak Fence Gate", - "x": 576, - "y": 3232 - }, - "crimson_fence_gate": { - "name": "Crimson Fence Gate", - "x": 576, - "y": 160 - }, - "warped_fence_gate": { - "name": "Warped Fence Gate", - "x": 608, - "y": 160 - }, - "brick_stairs": { - "name": "Brick Stairs", - "x": 288, - "y": 3232 - }, - "stone_brick_stairs": { - "name": "Stone Brick Stairs", - "x": 800, - "y": 3296 - }, - "mycelium": { - "name": "Mycelium", - "x": 256, - "y": 3360 - }, - "lily_pad": { - "name": "Lily Pad", - "x": 32, - "y": 3424 - }, - "nether_bricks": { - "name": "Nether Bricks", - "x": 768, - "y": 3360 - }, - "cracked_nether_bricks": { - "name": "Cracked Nether Bricks", - "x": 448, - "y": 256 - }, - "chiseled_nether_bricks": { - "name": "Chiseled Nether Bricks", - "x": 384, - "y": 256 - }, - "nether_brick_fence": { - "name": "Nether Brick Fence", - "x": 704, - "y": 3360 - }, - "nether_brick_stairs": { - "name": "Nether Brick Stairs", - "x": 736, - "y": 3360 - }, - "enchanting_table": { - "name": "Enchanting Table", - "x": 640, - "y": 3584 - }, - "end_portal_frame": { - "name": "End Portal Frame", - "x": 640, - "y": 3168 - }, - "end_stone": { - "name": "End Stone", - "x": 704, - "y": 3168 - }, - "end_stone_bricks": { - "name": "End Stone Bricks", - "x": 896, - "y": 3232 - }, - "dragon_egg": { - "name": "Dragon Egg", - "x": 576, - "y": 3168 - }, - "redstone_lamp": { - "name": "Redstone Lamp", - "x": 544, - "y": 3328 - }, - "sandstone_stairs": { - "name": "Sandstone Stairs", - "x": 224, - "y": 3296 - }, - "emerald_ore": { - "name": "Emerald Ore", - "x": 0, - "y": 3392 - }, - "ender_chest": { - "name": "Ender Chest", - "x": 672, - "y": 3584 - }, - "tripwire_hook": { - "name": "Tripwire Hook", - "x": 800, - "y": 3328 - }, - "emerald_block": { - "name": "Block of Emerald", - "x": 96, - "y": 3232 - }, - "spruce_stairs": { - "name": "Spruce Stairs", - "x": 704, - "y": 3296 - }, - "birch_stairs": { - "name": "Birch Stairs", - "x": 992, - "y": 3200 - }, - "jungle_stairs": { - "name": "Jungle Stairs", - "x": 160, - "y": 3264 - }, - "crimson_stairs": { - "name": "Crimson Stairs", - "x": 64, - "y": 160 - }, - "warped_stairs": { - "name": "Warped Stairs", - "x": 160, - "y": 160 - }, - "command_block": { - "name": "Impulse Command Block Revision 1", - "x": 736, - "y": 1216 - }, - "beacon": { - "name": "Beacon", - "x": 352, - "y": 3584 - }, - "cobblestone_wall": { - "name": "Cobblestone Wall", - "x": 480, - "y": 3232 - }, - "mossy_cobblestone_wall": { - "name": "Mossy Cobblestone Wall", - "x": 352, - "y": 3264 - }, - "brick_wall": { - "name": "Brick Wall", - "x": 320, - "y": 3232 - }, - "prismarine_wall": { - "name": "Prismarine Wall", - "x": 0, - "y": 96 - }, - "red_sandstone_wall": { - "name": "Red Sandstone Wall", - "x": 160, - "y": 3296 - }, - "mossy_stone_brick_wall": { - "name": "Mossy Stone Brick Wall", - "x": 448, - "y": 3264 - }, - "granite_wall": { - "name": "Granite Wall", - "x": 32, - "y": 2400 - }, - "stone_brick_wall": { - "name": "Stone Brick Wall", - "x": 832, - "y": 3296 - }, - "nether_brick_wall": { - "name": "Nether Brick Wall", - "x": 512, - "y": 3264 - }, - "andesite_wall": { - "name": "Andesite Wall", - "x": 864, - "y": 3200 - }, - "red_nether_brick_wall": { - "name": "Red Nether Brick Wall", - "x": 64, - "y": 3296 - }, - "sandstone_wall": { - "name": "Sandstone Wall", - "x": 256, - "y": 3296 - }, - "end_stone_brick_wall": { - "name": "End Stone Brick Wall", - "x": 0, - "y": 2400 - }, - "diorite_wall": { - "name": "Diorite Wall", - "x": 864, - "y": 3232 - }, - "blackstone_wall": { - "name": "Blackstone Wall", - "x": 672, - "y": 256 - }, - "polished_blackstone_wall": { - "name": "Polished Blackstone Wall", - "x": 864, - "y": 256 - }, - "polished_blackstone_brick_wall": { - "name": "Polished Blackstone Brick Wall", - "x": 768, - "y": 256 - }, - "stone_button": { - "name": "Stone Button", - "x": 736, - "y": 3328 - }, - "oak_button": { - "name": "Oak Button", - "x": 352, - "y": 3328 - }, - "spruce_button": { - "name": "Spruce Button", - "x": 640, - "y": 3328 - }, - "birch_button": { - "name": "Birch Button", - "x": 0, - "y": 3328 - }, - "jungle_button": { - "name": "Jungle Button", - "x": 224, - "y": 3328 - }, - "acacia_button": { - "name": "Acacia Button", - "x": 928, - "y": 3296 - }, - "dark_oak_button": { - "name": "Dark Oak Button", - "x": 96, - "y": 3328 - }, - "crimson_button": { - "name": "Crimson Button", - "x": 192, - "y": 160 - }, - "warped_button": { - "name": "Warped Button", - "x": 320, - "y": 160 - }, - "polished_blackstone_button": { - "name": "Polished Blackstone Button", - "x": 896, - "y": 256 - }, - "anvil": { - "name": "Anvil", - "x": 288, - "y": 3584 - }, - "chipped_anvil": { - "name": "Chipped Anvil", - "x": 480, - "y": 3584 - }, - "damaged_anvil": { - "name": "Damaged Anvil", - "x": 544, - "y": 3584 - }, - "trapped_chest": { - "name": "Trapped Chest", - "x": 992, - "y": 3584 - }, - "light_weighted_pressure_plate": { - "name": "Light Weighted Pressure Plate", - "x": 320, - "y": 3328 - }, - "heavy_weighted_pressure_plate": { - "name": "Heavy Weighted Pressure Plate", - "x": 192, - "y": 3328 - }, - "daylight_detector": { - "name": "Daylight Detector", - "x": 800, - "y": 1216 - }, - "redstone_block": { - "name": "Block of Redstone", - "x": 64, - "y": 3328 - }, - "nether_quartz_ore": { - "name": "Nether Quartz Ore", - "x": 800, - "y": 3360 - }, - "hopper": { - "name": "Hopper", - "x": 736, - "y": 3584 - }, - "chiseled_quartz_block": { - "name": "Chiseled Quartz Block", - "x": 224, - "y": 864 - }, - "quartz_block": { - "name": "Block of Quartz", - "x": 192, - "y": 3232 - }, - "quartz_bricks": { - "name": "Quartz Bricks", - "x": 992, - "y": 256 - }, - "quartz_pillar": { - "name": "Quartz Pillar", - "x": 288, - "y": 896 - }, - "quartz_stairs": { - "name": "Quartz Stairs", - "x": 992, - "y": 3264 - }, - "activator_rail": { - "name": "Activator Rail", - "x": 992, - "y": 3296 - }, - "dropper": { - "name": "Dropper", - "x": 608, - "y": 3584 - }, - "white_terracotta": { - "name": "White Terracotta", - "x": 672, - "y": 768 - }, - "orange_terracotta": { - "name": "Orange Terracotta", - "x": 928, - "y": 736 - }, - "magenta_terracotta": { - "name": "Magenta Terracotta", - "x": 736, - "y": 736 - }, - "light_blue_terracotta": { - "name": "Light Blue Terracotta", - "x": 160, - "y": 736 - }, - "yellow_terracotta": { - "name": "Yellow Terracotta", - "x": 864, - "y": 768 - }, - "lime_terracotta": { - "name": "Lime Terracotta", - "x": 544, - "y": 736 - }, - "pink_terracotta": { - "name": "Pink Terracotta", - "x": 96, - "y": 768 - }, - "gray_terracotta": { - "name": "Gray Terracotta", - "x": 800, - "y": 704 - }, - "light_gray_terracotta": { - "name": "Light Gray Terracotta", - "x": 352, - "y": 736 - }, - "cyan_terracotta": { - "name": "Cyan Terracotta", - "x": 608, - "y": 704 - }, - "purple_terracotta": { - "name": "Purple Terracotta", - "x": 288, - "y": 768 - }, - "blue_terracotta": { - "name": "Blue Terracotta", - "x": 224, - "y": 704 - }, - "brown_terracotta": { - "name": "Brown Terracotta", - "x": 416, - "y": 704 - }, - "green_terracotta": { - "name": "Green Terracotta", - "x": 992, - "y": 704 - }, - "red_terracotta": { - "name": "Red Terracotta", - "x": 480, - "y": 768 - }, - "black_terracotta": { - "name": "Black Terracotta", - "x": 32, - "y": 704 - }, - "barrier": { - "name": "Barrier", - "x": 320, - "y": 3584 - }, - "iron_trapdoor": { - "name": "Iron Trapdoor", - "x": 416, - "y": 928 - }, - "hay_block": { - "name": "Hay Bale", - "x": 992, - "y": 3232 - }, - "white_carpet": { - "name": "White Carpet", - "x": 64, - "y": 1632 - }, - "orange_carpet": { - "name": "Orange Carpet", - "x": 960, - "y": 1600 - }, - "magenta_carpet": { - "name": "Magenta Carpet", - "x": 928, - "y": 1600 - }, - "light_blue_carpet": { - "name": "Light Blue Carpet", - "x": 832, - "y": 1600 - }, - "yellow_carpet": { - "name": "Yellow Carpet", - "x": 96, - "y": 1632 - }, - "lime_carpet": { - "name": "Lime Carpet", - "x": 896, - "y": 1600 - }, - "pink_carpet": { - "name": "Pink Carpet", - "x": 992, - "y": 1600 - }, - "gray_carpet": { - "name": "Gray Carpet", - "x": 768, - "y": 1600 - }, - "light_gray_carpet": { - "name": "Light Gray Carpet", - "x": 864, - "y": 1600 - }, - "cyan_carpet": { - "name": "Cyan Carpet", - "x": 736, - "y": 1600 - }, - "purple_carpet": { - "name": "Purple Carpet", - "x": 0, - "y": 1632 - }, - "blue_carpet": { - "name": "Blue Carpet", - "x": 672, - "y": 1600 - }, - "brown_carpet": { - "name": "Brown Carpet", - "x": 704, - "y": 1600 - }, - "green_carpet": { - "name": "Green Carpet", - "x": 800, - "y": 1600 - }, - "red_carpet": { - "name": "Red Carpet", - "x": 32, - "y": 1632 - }, - "black_carpet": { - "name": "Black Carpet", - "x": 640, - "y": 1600 - }, - "terracotta": { - "name": "Terracotta", - "x": 640, - "y": 3360 - }, - "coal_block": { - "name": "Block of Coal", - "x": 32, - "y": 3232 - }, - "packed_ice": { - "name": "Packed Ice", - "x": 320, - "y": 3360 - }, - "acacia_stairs": { - "name": "Acacia Stairs", - "x": 736, - "y": 3200 - }, - "dark_oak_stairs": { - "name": "Dark Oak Stairs", - "x": 672, - "y": 3232 - }, - "slime_block": { - "name": "Slime Block", - "x": 736, - "y": 896 - }, - "grass_path": { - "name": "Grass Path", - "x": 96, - "y": 1344 - }, - "sunflower": { - "name": "Sunflower", - "x": 672, - "y": 3424 - }, - "lilac": { - "name": "Lilac", - "x": 0, - "y": 3424 - }, - "rose_bush": { - "name": "Rose Bush", - "x": 512, - "y": 3424 - }, - "peony": { - "name": "Peony", - "x": 288, - "y": 3424 - }, - "tall_grass": { - "name": "Tall Grass", - "x": 704, - "y": 3424 - }, - "large_fern": { - "name": "Large Fern", - "x": 992, - "y": 3392 - }, - "white_stained_glass": { - "name": "White Stained Glass", - "x": 704, - "y": 768 - }, - "orange_stained_glass": { - "name": "Orange Stained Glass", - "x": 960, - "y": 736 - }, - "magenta_stained_glass": { - "name": "Magenta Stained Glass", - "x": 768, - "y": 736 - }, - "light_blue_stained_glass": { - "name": "Light Blue Stained Glass", - "x": 192, - "y": 736 - }, - "yellow_stained_glass": { - "name": "Yellow Stained Glass", - "x": 896, - "y": 768 - }, - "lime_stained_glass": { - "name": "Lime Stained Glass", - "x": 576, - "y": 736 - }, - "pink_stained_glass": { - "name": "Pink Stained Glass", - "x": 128, - "y": 768 - }, - "gray_stained_glass": { - "name": "Gray Stained Glass", - "x": 832, - "y": 704 - }, - "light_gray_stained_glass": { - "name": "Light Gray Stained Glass", - "x": 384, - "y": 736 - }, - "cyan_stained_glass": { - "name": "Cyan Stained Glass", - "x": 640, - "y": 704 - }, - "purple_stained_glass": { - "name": "Purple Stained Glass", - "x": 320, - "y": 768 - }, - "blue_stained_glass": { - "name": "Blue Stained Glass", - "x": 256, - "y": 704 - }, - "brown_stained_glass": { - "name": "Brown Stained Glass", - "x": 448, - "y": 704 - }, - "green_stained_glass": { - "name": "Green Stained Glass", - "x": 0, - "y": 736 - }, - "red_stained_glass": { - "name": "Red Stained Glass", - "x": 512, - "y": 768 - }, - "black_stained_glass": { - "name": "Black Stained Glass", - "x": 64, - "y": 704 - }, - "white_stained_glass_pane": { - "name": "White Stained Glass Pane", - "x": 736, - "y": 768 - }, - "orange_stained_glass_pane": { - "name": "Orange Stained Glass Pane", - "x": 992, - "y": 736 - }, - "magenta_stained_glass_pane": { - "name": "Magenta Stained Glass Pane", - "x": 800, - "y": 736 - }, - "light_blue_stained_glass_pane": { - "name": "Light Blue Stained Glass Pane", - "x": 224, - "y": 736 - }, - "yellow_stained_glass_pane": { - "name": "Yellow Stained Glass Pane", - "x": 928, - "y": 768 - }, - "lime_stained_glass_pane": { - "name": "Lime Stained Glass Pane", - "x": 608, - "y": 736 - }, - "pink_stained_glass_pane": { - "name": "Pink Stained Glass Pane", - "x": 160, - "y": 768 - }, - "gray_stained_glass_pane": { - "name": "Gray Stained Glass Pane", - "x": 864, - "y": 704 - }, - "light_gray_stained_glass_pane": { - "name": "Light Gray Stained Glass Pane", - "x": 416, - "y": 736 - }, - "cyan_stained_glass_pane": { - "name": "Cyan Stained Glass Pane", - "x": 672, - "y": 704 - }, - "purple_stained_glass_pane": { - "name": "Purple Stained Glass Pane", - "x": 352, - "y": 768 - }, - "blue_stained_glass_pane": { - "name": "Blue Stained Glass Pane", - "x": 288, - "y": 704 - }, - "brown_stained_glass_pane": { - "name": "Brown Stained Glass Pane", - "x": 480, - "y": 704 - }, - "green_stained_glass_pane": { - "name": "Green Stained Glass Pane", - "x": 32, - "y": 736 - }, - "red_stained_glass_pane": { - "name": "Red Stained Glass Pane", - "x": 544, - "y": 768 - }, - "black_stained_glass_pane": { - "name": "Black Stained Glass Pane", - "x": 96, - "y": 704 - }, - "prismarine": { - "name": "Prismarine Wall", - "x": 0, - "y": 96 - }, - "prismarine_bricks": { - "name": "Prismarine Bricks", - "x": 384, - "y": 3360 - }, - "dark_prismarine": { - "name": "Dark Prismarine", - "x": 32, - "y": 3360 - }, - "prismarine_stairs": { - "name": "Dark Prismarine Stairs", - "x": 768, - "y": 3232 - }, - "prismarine_brick_stairs": { - "name": "Prismarine Brick Stairs", - "x": 448, - "y": 96 - }, - "dark_prismarine_stairs": { - "name": "Dark Prismarine Stairs", - "x": 768, - "y": 3232 - }, - "sea_lantern": { - "name": "Sea Lantern BE", - "x": 512, - "y": 192 - }, - "red_sandstone": { - "name": "Red Sandstone", - "x": 448, - "y": 3360 - }, - "chiseled_red_sandstone": { - "name": "Chiseled Red Sandstone", - "x": 352, - "y": 3232 - }, - "cut_red_sandstone": { - "name": "Cut Red Sandstone", - "x": 512, - "y": 3232 - }, - "red_sandstone_stairs": { - "name": "Red Sandstone Stairs", - "x": 128, - "y": 3296 - }, - "magma_block": { - "name": "Magma Block BE", - "x": 928, - "y": 480 - }, - "nether_wart_block": { - "name": "Nether Wart Block", - "x": 544, - "y": 3264 - }, - "warped_wart_block": { - "name": "Warped Wart Block", - "x": 832, - "y": 128 - }, - "red_nether_bricks": { - "name": "Red Nether Bricks", - "x": 704, - "y": 1344 - }, - "bone_block": { - "name": "Bone Block", - "x": 864, - "y": 3328 - }, - "structure_void": { - "name": "Structure Void", - "x": 928, - "y": 3584 - }, - "observer": { - "name": "Observer", - "x": 864, - "y": 3584 - }, - "shulker_box": { - "name": "Shulker Box", - "x": 448, - "y": 1600 - }, - "white_shulker_box": { - "name": "White Shulker Box", - "x": 512, - "y": 1600 - }, - "orange_shulker_box": { - "name": "Orange Shulker Box", - "x": 384, - "y": 1600 - }, - "magenta_shulker_box": { - "name": "Magenta Shulker Box", - "x": 352, - "y": 1600 - }, - "light_blue_shulker_box": { - "name": "Light Blue Shulker Box", - "x": 256, - "y": 1600 - }, - "yellow_shulker_box": { - "name": "Yellow Shulker Box", - "x": 544, - "y": 1600 - }, - "lime_shulker_box": { - "name": "Lime Shulker Box", - "x": 320, - "y": 1600 - }, - "pink_shulker_box": { - "name": "Pink Shulker Box", - "x": 416, - "y": 1600 - }, - "gray_shulker_box": { - "name": "Gray Shulker Box", - "x": 192, - "y": 1600 - }, - "light_gray_shulker_box": { - "name": "Light Gray Shulker Box", - "x": 288, - "y": 1600 - }, - "cyan_shulker_box": { - "name": "Cyan Shulker Box", - "x": 160, - "y": 1600 - }, - "purple_shulker_box": { - "name": "Purple Shulker Box", - "x": 608, - "y": 1408 - }, - "blue_shulker_box": { - "name": "Blue Shulker Box", - "x": 96, - "y": 1600 - }, - "brown_shulker_box": { - "name": "Brown Shulker Box", - "x": 128, - "y": 1600 - }, - "green_shulker_box": { - "name": "Green Shulker Box", - "x": 224, - "y": 1600 - }, - "red_shulker_box": { - "name": "Red Shulker Box", - "x": 480, - "y": 1600 - }, - "black_shulker_box": { - "name": "Black Shulker Box", - "x": 64, - "y": 1600 - }, - "white_glazed_terracotta": { - "name": "White Glazed Terracotta", - "x": 192, - "y": 1536 - }, - "orange_glazed_terracotta": { - "name": "Orange Glazed Terracotta", - "x": 160, - "y": 1536 - }, - "magenta_glazed_terracotta": { - "name": "Magenta Glazed Terracotta", - "x": 128, - "y": 1536 - }, - "light_blue_glazed_terracotta": { - "name": "Light Blue Glazed Terracotta", - "x": 704, - "y": 1472 - }, - "yellow_glazed_terracotta": { - "name": "Yellow Glazed Terracotta", - "x": 544, - "y": 1504 - }, - "lime_glazed_terracotta": { - "name": "Lime Glazed Terracotta", - "x": 896, - "y": 1472 - }, - "pink_glazed_terracotta": { - "name": "Pink Glazed Terracotta", - "x": 160, - "y": 1504 - }, - "gray_glazed_terracotta": { - "name": "Gray Glazed Terracotta", - "x": 512, - "y": 1472 - }, - "light_gray_glazed_terracotta": { - "name": "Light Gray Glazed Terracotta", - "x": 800, - "y": 1472 - }, - "cyan_glazed_terracotta": { - "name": "Cyan Glazed Terracotta", - "x": 96, - "y": 1536 - }, - "purple_glazed_terracotta": { - "name": "Purple Glazed Terracotta", - "x": 256, - "y": 1504 - }, - "blue_glazed_terracotta": { - "name": "Blue Glazed Terracotta", - "x": 224, - "y": 1472 - }, - "brown_glazed_terracotta": { - "name": "Brown Glazed Terracotta", - "x": 320, - "y": 1472 - }, - "green_glazed_terracotta": { - "name": "Green Glazed Terracotta", - "x": 608, - "y": 1472 - }, - "red_glazed_terracotta": { - "name": "Red Glazed Terracotta", - "x": 352, - "y": 1504 - }, - "black_glazed_terracotta": { - "name": "Black Glazed Terracotta", - "x": 128, - "y": 1472 - }, - "white_concrete": { - "name": "White Concrete", - "x": 384, - "y": 1504 - }, - "orange_concrete": { - "name": "Orange Concrete", - "x": 0, - "y": 1504 - }, - "magenta_concrete": { - "name": "Magenta Concrete", - "x": 928, - "y": 1472 - }, - "light_blue_concrete": { - "name": "Light Blue Concrete", - "x": 640, - "y": 1472 - }, - "yellow_concrete": { - "name": "Yellow Concrete", - "x": 480, - "y": 1504 - }, - "lime_concrete": { - "name": "Lime Concrete", - "x": 832, - "y": 1472 - }, - "pink_concrete": { - "name": "Pink Concrete", - "x": 96, - "y": 1504 - }, - "gray_concrete": { - "name": "Gray Concrete", - "x": 448, - "y": 1472 - }, - "light_gray_concrete": { - "name": "Light Gray Concrete", - "x": 736, - "y": 1472 - }, - "cyan_concrete": { - "name": "Cyan Concrete", - "x": 352, - "y": 1472 - }, - "purple_concrete": { - "name": "Purple Concrete", - "x": 192, - "y": 1504 - }, - "blue_concrete": { - "name": "Blue Concrete", - "x": 160, - "y": 1472 - }, - "brown_concrete": { - "name": "Brown Concrete", - "x": 256, - "y": 1472 - }, - "green_concrete": { - "name": "Green Concrete", - "x": 544, - "y": 1472 - }, - "red_concrete": { - "name": "Red Concrete", - "x": 288, - "y": 1504 - }, - "black_concrete": { - "name": "Black Concrete", - "x": 64, - "y": 1472 - }, - "white_concrete_powder": { - "name": "White Concrete Powder", - "x": 416, - "y": 1504 - }, - "orange_concrete_powder": { - "name": "Orange Concrete Powder", - "x": 32, - "y": 1504 - }, - "magenta_concrete_powder": { - "name": "Magenta Concrete Powder", - "x": 960, - "y": 1472 - }, - "light_blue_concrete_powder": { - "name": "Light Blue Concrete Powder", - "x": 672, - "y": 1472 - }, - "yellow_concrete_powder": { - "name": "Yellow Concrete Powder", - "x": 512, - "y": 1504 - }, - "lime_concrete_powder": { - "name": "Lime Concrete Powder", - "x": 864, - "y": 1472 - }, - "pink_concrete_powder": { - "name": "Pink Concrete Powder", - "x": 128, - "y": 1504 - }, - "gray_concrete_powder": { - "name": "Gray Concrete Powder", - "x": 480, - "y": 1472 - }, - "light_gray_concrete_powder": { - "name": "Light Gray Concrete Powder", - "x": 768, - "y": 1472 - }, - "cyan_concrete_powder": { - "name": "Cyan Concrete Powder", - "x": 384, - "y": 1472 - }, - "purple_concrete_powder": { - "name": "Purple Concrete Powder", - "x": 224, - "y": 1504 - }, - "blue_concrete_powder": { - "name": "Blue Concrete Powder", - "x": 192, - "y": 1472 - }, - "brown_concrete_powder": { - "name": "Brown Concrete Powder", - "x": 288, - "y": 1472 - }, - "green_concrete_powder": { - "name": "Green Concrete Powder", - "x": 576, - "y": 1472 - }, - "red_concrete_powder": { - "name": "Red Concrete Powder", - "x": 320, - "y": 1504 - }, - "black_concrete_powder": { - "name": "Black Concrete Powder", - "x": 96, - "y": 1472 - }, - "turtle_egg": { - "name": "Turtle Egg", - "x": 608, - "y": 1952 - }, - "dead_tube_coral_block": { - "name": "Dead Tube Coral Block", - "x": 640, - "y": 1696 - }, - "dead_brain_coral_block": { - "name": "Dead Brain Coral Block", - "x": 672, - "y": 1696 - }, - "dead_bubble_coral_block": { - "name": "Dead Bubble Coral Block", - "x": 704, - "y": 1696 - }, - "dead_fire_coral_block": { - "name": "Dead Fire Coral Block", - "x": 736, - "y": 1696 - }, - "dead_horn_coral_block": { - "name": "Dead Horn Coral Block", - "x": 768, - "y": 1696 - }, - "tube_coral_block": { - "name": "Tube Coral Block", - "x": 288, - "y": 1696 - }, - "brain_coral_block": { - "name": "Brain Coral Block", - "x": 320, - "y": 1696 - }, - "bubble_coral_block": { - "name": "Bubble Coral Block", - "x": 352, - "y": 1696 - }, - "fire_coral_block": { - "name": "Fire Coral Block", - "x": 384, - "y": 1696 - }, - "horn_coral_block": { - "name": "Horn Coral Block", - "x": 416, - "y": 1696 - }, - "tube_coral": { - "name": "Tube Coral", - "x": 448, - "y": 1696 - }, - "brain_coral": { - "name": "Brain Coral", - "x": 480, - "y": 1696 - }, - "bubble_coral": { - "name": "Bubble Coral", - "x": 512, - "y": 1696 - }, - "fire_coral": { - "name": "Fire Coral", - "x": 544, - "y": 1696 - }, - "horn_coral": { - "name": "Horn Coral", - "x": 576, - "y": 1696 - }, - "dead_brain_coral": { - "name": "Dead Brain Coral", - "x": 992, - "y": 2336 - }, - "dead_bubble_coral": { - "name": "Dead Bubble Coral", - "x": 0, - "y": 2368 - }, - "dead_fire_coral": { - "name": "Dead Fire Coral", - "x": 32, - "y": 2368 - }, - "dead_horn_coral": { - "name": "Dead Horn Coral", - "x": 64, - "y": 2368 - }, - "dead_tube_coral": { - "name": "Dead Tube Coral", - "x": 960, - "y": 2336 - }, - "tube_coral_fan": { - "name": "Tube Coral Fan", - "x": 704, - "y": 2112 - }, - "brain_coral_fan": { - "name": "Brain Coral Fan", - "x": 608, - "y": 2112 - }, - "bubble_coral_fan": { - "name": "Bubble Coral Fan", - "x": 640, - "y": 2112 - }, - "fire_coral_fan": { - "name": "Fire Coral Fan", - "x": 896, - "y": 1696 - }, - "horn_coral_fan": { - "name": "Horn Coral Fan", - "x": 672, - "y": 2112 - }, - "dead_tube_coral_fan": { - "name": "Dead Tube Coral Fan", - "x": 160, - "y": 2144 - }, - "dead_brain_coral_fan": { - "name": "Dead Brain Coral Fan", - "x": 32, - "y": 2144 - }, - "dead_bubble_coral_fan": { - "name": "Dead Bubble Coral Fan", - "x": 64, - "y": 2144 - }, - "dead_fire_coral_fan": { - "name": "Dead Fire Coral Fan", - "x": 96, - "y": 2144 - }, - "dead_horn_coral_fan": { - "name": "Dead Horn Coral Fan", - "x": 128, - "y": 2144 - }, - "blue_ice": { - "name": "Blue Ice", - "x": 192, - "y": 1728 - }, - "conduit": { - "name": "Conduit", - "x": 512, - "y": 2016 - }, - "polished_granite_stairs": { - "name": "Polished Granite Stairs", - "x": 960, - "y": 2400 - }, - "smooth_red_sandstone_stairs": { - "name": "Smooth Red Sandstone Stairs", - "x": 384, - "y": 3296 - }, - "mossy_stone_brick_stairs": { - "name": "Mossy Stone Brick Stairs", - "x": 416, - "y": 3264 - }, - "polished_diorite_stairs": { - "name": "Polished Diorite Stairs", - "x": 832, - "y": 3264 - }, - "mossy_cobblestone_stairs": { - "name": "Mossy Cobblestone Stairs", - "x": 320, - "y": 3264 - }, - "end_stone_brick_stairs": { - "name": "End Stone Brick Stairs", - "x": 576, - "y": 2400 - }, - "stone_stairs": { - "name": "Stone Stairs", - "x": 896, - "y": 3296 - }, - "smooth_sandstone_stairs": { - "name": "Smooth Sandstone Stairs", - "x": 480, - "y": 3296 - }, - "smooth_quartz_stairs": { - "name": "Smooth Quartz Stairs", - "x": 320, - "y": 3296 - }, - "granite_stairs": { - "name": "Granite Stairs", - "x": 640, - "y": 2400 - }, - "andesite_stairs": { - "name": "Andesite Stairs", - "x": 832, - "y": 3200 - }, - "red_nether_brick_stairs": { - "name": "Red Nether Brick Stairs", - "x": 32, - "y": 3296 - }, - "polished_andesite_stairs": { - "name": "Polished Andesite Stairs", - "x": 768, - "y": 3264 - }, - "diorite_stairs": { - "name": "Diorite Stairs", - "x": 832, - "y": 3232 - }, - "polished_granite_slab": { - "name": "Polished Granite Slab", - "x": 928, - "y": 2400 - }, - "smooth_red_sandstone_slab": { - "name": "Smooth Red Sandstone Slab", - "x": 352, - "y": 3296 - }, - "mossy_stone_brick_slab": { - "name": "Mossy Stone Brick Slab", - "x": 384, - "y": 3264 - }, - "polished_diorite_slab": { - "name": "Polished Diorite Slab", - "x": 800, - "y": 3264 - }, - "mossy_cobblestone_slab": { - "name": "Mossy Cobblestone Slab", - "x": 288, - "y": 3264 - }, - "end_stone_brick_slab": { - "name": "End Stone Brick Slab", - "x": 544, - "y": 2400 - }, - "smooth_sandstone_slab": { - "name": "Smooth Sandstone Slab", - "x": 448, - "y": 3296 - }, - "smooth_quartz_slab": { - "name": "Smooth Quartz Slab", - "x": 288, - "y": 3296 - }, - "granite_slab": { - "name": "Granite Slab", - "x": 608, - "y": 2400 - }, - "andesite_slab": { - "name": "Andesite Slab", - "x": 800, - "y": 3200 - }, - "red_nether_brick_slab": { - "name": "Red Nether Brick Slab", - "x": 0, - "y": 3296 - }, - "polished_andesite_slab": { - "name": "Polished Andesite Slab", - "x": 736, - "y": 3264 - }, - "diorite_slab": { - "name": "Diorite Slab", - "x": 800, - "y": 3232 - }, - "scaffolding": { - "name": "Scaffolding", - "x": 416, - "y": 2400 - }, - "iron_door": { - "name": "Iron Door", - "x": 384, - "y": 928 - }, - "oak_door": { - "name": "Oak Door", - "x": 512, - "y": 928 - }, - "spruce_door": { - "name": "Spruce Door", - "x": 800, - "y": 928 - }, - "birch_door": { - "name": "Birch Door", - "x": 256, - "y": 928 - }, - "jungle_door": { - "name": "Jungle Door", - "x": 448, - "y": 928 - }, - "acacia_door": { - "name": "Acacia Door", - "x": 192, - "y": 928 - }, - "dark_oak_door": { - "name": "Dark Oak Door", - "x": 320, - "y": 928 - }, - "crimson_door": { - "name": "Crimson Door", - "x": 224, - "y": 160 - }, - "warped_door": { - "name": "Warped Door", - "x": 352, - "y": 160 - }, - "repeater": { - "name": "Redstone Repeater", - "x": 576, - "y": 3328 - }, - "comparator": { - "name": "Redstone Comparator", - "x": 512, - "y": 3328 - }, - "structure_block": { - "name": "Structure Block", - "x": 96, - "y": 1376 - }, - "jigsaw": { - "name": "Jigsaw Block", - "x": 64, - "y": 288 - }, - "turtle_helmet": { - "name": "Turtle Shell", - "x": 512, - "y": 1664 - }, - "scute": { - "name": "Scute", - "x": 608, - "y": 1664 - }, - "flint_and_steel": { - "name": "Flint and Steel", - "x": 480, - "y": 3552 - }, - "apple": { - "name": "Apple", - "x": 768, - "y": 3168 - }, - "bow": { - "name": "Bow", - "x": 992, - "y": 1248 - }, - "arrow": { - "name": "Arrow", - "x": 576, - "y": 1248 - }, - "coal": { - "name": "Coal", - "x": 576, - "y": 3488 - }, - "charcoal": { - "name": "Charcoal", - "x": 512, - "y": 3488 - }, - "diamond": { - "name": "Diamond", - "x": 608, - "y": 3488 - }, - "iron_ingot": { - "name": "Iron Ingot", - "x": 896, - "y": 3488 - }, - "gold_ingot": { - "name": "Gold Ingot", - "x": 800, - "y": 3488 - }, - "netherite_ingot": { - "name": "Netherite Ingot", - "x": 192, - "y": 128 - }, - "netherite_scrap": { - "name": "Netherite Scrap", - "x": 224, - "y": 128 - }, - "wooden_sword": { - "name": "Wooden Sword", - "x": 800, - "y": 3616 - }, - "wooden_shovel": { - "name": "Wooden Shovel", - "x": 192, - "y": 3584 - }, - "wooden_pickaxe": { - "name": "Wooden Pickaxe", - "x": 160, - "y": 3584 - }, - "wooden_axe": { - "name": "Wooden Axe", - "x": 96, - "y": 3584 - }, - "wooden_hoe": { - "name": "Wooden Hoe", - "x": 128, - "y": 3584 - }, - "stone_sword": { - "name": "Stone Sword", - "x": 736, - "y": 3616 - }, - "stone_shovel": { - "name": "Stone Shovel", - "x": 64, - "y": 3584 - }, - "stone_pickaxe": { - "name": "Stone Pickaxe", - "x": 32, - "y": 3584 - }, - "stone_axe": { - "name": "Stone Axe", - "x": 992, - "y": 3552 - }, - "stone_hoe": { - "name": "Stone Hoe", - "x": 0, - "y": 3584 - }, - "golden_sword": { - "name": "Golden Sword", - "x": 608, - "y": 3616 - }, - "golden_shovel": { - "name": "Golden Shovel", - "x": 640, - "y": 3552 - }, - "golden_pickaxe": { - "name": "Golden Pickaxe", - "x": 608, - "y": 3552 - }, - "golden_axe": { - "name": "Golden Axe", - "x": 544, - "y": 3552 - }, - "golden_hoe": { - "name": "Golden Hoe", - "x": 576, - "y": 3552 - }, - "iron_sword": { - "name": "Iron Sword", - "x": 640, - "y": 3616 - }, - "iron_shovel": { - "name": "Iron Shovel", - "x": 768, - "y": 3552 - }, - "iron_pickaxe": { - "name": "Iron Pickaxe", - "x": 736, - "y": 3552 - }, - "iron_axe": { - "name": "Iron Axe", - "x": 672, - "y": 3552 - }, - "iron_hoe": { - "name": "Iron Hoe", - "x": 704, - "y": 3552 - }, - "diamond_sword": { - "name": "Diamond Sword", - "x": 576, - "y": 3616 - }, - "diamond_shovel": { - "name": "Diamond Shovel", - "x": 288, - "y": 3552 - }, - "diamond_pickaxe": { - "name": "Diamond Pickaxe", - "x": 256, - "y": 3552 - }, - "diamond_axe": { - "name": "Diamond Axe", - "x": 192, - "y": 3552 - }, - "diamond_hoe": { - "name": "Diamond Hoe", - "x": 224, - "y": 3552 - }, - "netherite_sword": { - "name": "Netherite Sword", - "x": 384, - "y": 128 - }, - "netherite_shovel": { - "name": "Netherite Shovel", - "x": 352, - "y": 128 - }, - "netherite_pickaxe": { - "name": "Netherite Pickaxe", - "x": 320, - "y": 128 - }, - "netherite_axe": { - "name": "Netherite Axe", - "x": 256, - "y": 128 - }, - "netherite_hoe": { - "name": "Netherite Hoe", - "x": 288, - "y": 128 - }, - "stick": { - "name": "Stick", - "x": 608, - "y": 1120 - }, - "bowl": { - "name": "Bowl", - "x": 384, - "y": 3520 - }, - "mushroom_stew": { - "name": "Mushroom Stew", - "x": 224, - "y": 3200 - }, - "string": { - "name": "String", - "x": 320, - "y": 3520 - }, - "feather": { - "name": "Feather", - "x": 704, - "y": 3488 - }, - "gunpowder": { - "name": "Gunpowder", - "x": 864, - "y": 3488 - }, - "wheat_seeds": { - "name": "Wheat Seeds", - "x": 320, - "y": 1056 - }, - "wheat": { - "name": "Wheat", - "x": 608, - "y": 3200 - }, - "bread": { - "name": "Bread", - "x": 896, - "y": 3168 - }, - "leather_helmet": { - "name": "Leather Cap", - "x": 608, - "y": 2496 - }, - "leather_chestplate": { - "name": "Leather Tunic", - "x": 672, - "y": 2496 - }, - "leather_leggings": { - "name": "Leather Pants", - "x": 640, - "y": 2496 - }, - "leather_boots": { - "name": "Leather Boots", - "x": 576, - "y": 2496 - }, - "chainmail_helmet": { - "name": "Chainmail Helmet", - "x": 320, - "y": 2464 - }, - "chainmail_chestplate": { - "name": "Chainmail Chestplate", - "x": 288, - "y": 2464 - }, - "chainmail_leggings": { - "name": "Chainmail Leggings", - "x": 352, - "y": 2464 - }, - "chainmail_boots": { - "name": "Chainmail Boots", - "x": 256, - "y": 2464 - }, - "iron_helmet": { - "name": "Iron Helmet", - "x": 512, - "y": 2496 - }, - "iron_chestplate": { - "name": "Iron Chestplate", - "x": 480, - "y": 2496 - }, - "iron_leggings": { - "name": "Iron Leggings", - "x": 544, - "y": 2496 - }, - "iron_boots": { - "name": "Iron Boots", - "x": 448, - "y": 2496 - }, - "diamond_helmet": { - "name": "Diamond Helmet", - "x": 160, - "y": 2496 - }, - "diamond_chestplate": { - "name": "Diamond Chestplate", - "x": 128, - "y": 2496 - }, - "diamond_leggings": { - "name": "Diamond Leggings", - "x": 192, - "y": 2496 - }, - "diamond_boots": { - "name": "Diamond Boots", - "x": 96, - "y": 2496 - }, - "golden_helmet": { - "name": "Golden Helmet", - "x": 320, - "y": 2496 - }, - "golden_chestplate": { - "name": "Golden Chestplate", - "x": 288, - "y": 2496 - }, - "golden_leggings": { - "name": "Golden Leggings", - "x": 352, - "y": 2496 - }, - "golden_boots": { - "name": "Golden Boots", - "x": 256, - "y": 2496 - }, - "netherite_helmet": { - "name": "Netherite Helmet", - "x": 480, - "y": 128 - }, - "netherite_chestplate": { - "name": "Netherite Chestplate", - "x": 448, - "y": 128 - }, - "netherite_leggings": { - "name": "Netherite Leggings", - "x": 512, - "y": 128 - }, - "netherite_boots": { - "name": "Netherite Boots", - "x": 416, - "y": 128 - }, - "flint": { - "name": "Flint", - "x": 736, - "y": 3488 - }, - "porkchop": { - "name": "Raw Porkchop", - "x": 480, - "y": 3200 - }, - "cooked_porkchop": { - "name": "Cooked Porkchop", - "x": 32, - "y": 3200 - }, - "painting": { - "name": "Painting", - "x": 544, - "y": 3136 - }, - "golden_apple": { - "name": "Golden Apple", - "x": 160, - "y": 3200 - }, - "enchanted_golden_apple": { - "name": "Enchanted Golden Apple", - "x": 128, - "y": 256 - }, - "oak_sign": { - "name": "Oak Sign", - "x": 896, - "y": 3360 - }, - "spruce_sign": { - "name": "Spruce Sign", - "x": 800, - "y": 2368 - }, - "birch_sign": { - "name": "Birch Sign", - "x": 768, - "y": 2368 - }, - "jungle_sign": { - "name": "Jungle Sign", - "x": 832, - "y": 2368 - }, - "acacia_sign": { - "name": "Acacia Sign", - "x": 864, - "y": 2368 - }, - "dark_oak_sign": { - "name": "Dark Oak Sign", - "x": 896, - "y": 2368 - }, - "crimson_sign": { - "name": "Crimson Sign", - "x": 512, - "y": 160 - }, - "warped_sign": { - "name": "Warped Sign", - "x": 544, - "y": 160 - }, - "bucket": { - "name": "Bucket", - "x": 288, - "y": 3136 - }, - "water_bucket": { - "name": "Water Bucket", - "x": 384, - "y": 3136 - }, - "lava_bucket": { - "name": "Lava Bucket", - "x": 320, - "y": 3136 - }, - "minecart": { - "name": "Minecart", - "x": 160, - "y": 3616 - }, - "saddle": { - "name": "Saddle", - "x": 928, - "y": 3552 - }, - "redstone": { - "name": "Redstone Dust", - "x": 224, - "y": 3520 - }, - "snowball": { - "name": "Snowball", - "x": 672, - "y": 3616 - }, - "oak_boat": { - "name": "Oak Boat", - "x": 352, - "y": 3616 - }, - "leather": { - "name": "Leather", - "x": 960, - "y": 3488 - }, - "milk_bucket": { - "name": "Milk Bucket", - "x": 352, - "y": 3136 - }, - "pufferfish_bucket": { - "name": "Bucket of Pufferfish", - "x": 704, - "y": 1664 - }, - "salmon_bucket": { - "name": "Bucket of Salmon", - "x": 736, - "y": 1664 - }, - "cod_bucket": { - "name": "Bucket of Cod", - "x": 672, - "y": 1664 - }, - "tropical_fish_bucket": { - "name": "Bucket of Tropical Fish", - "x": 352, - "y": 2016 - }, - "brick": { - "name": "Brick", - "x": 480, - "y": 3488 - }, - "clay_ball": { - "name": "Clay Ball", - "x": 544, - "y": 3488 - }, - "dried_kelp_block": { - "name": "Dried Kelp Block", - "x": 128, - "y": 1664 - }, - "paper": { - "name": "Paper", - "x": 64, - "y": 3520 - }, - "book": { - "name": "Book", - "x": 448, - "y": 3488 - }, - "slime_ball": { - "name": "Slimeball", - "x": 288, - "y": 3520 - }, - "chest_minecart": { - "name": "Minecart with Chest", - "x": 192, - "y": 3616 - }, - "furnace_minecart": { - "name": "Minecart with Furnace", - "x": 256, - "y": 3616 - }, - "egg": { - "name": "Egg", - "x": 128, - "y": 3200 - }, - "compass": { - "name": "Compass", - "x": 992, - "y": 480 - }, - "fishing_rod": { - "name": "Fishing Rod", - "x": 448, - "y": 3552 - }, - "clock": { - "name": "Clock", - "x": 960, - "y": 480 - }, - "glowstone_dust": { - "name": "Glowstone Dust", - "x": 768, - "y": 3488 - }, - "cod": { - "name": "Raw Cod", - "x": 896, - "y": 1664 - }, - "salmon": { - "name": "Raw Salmon", - "x": 928, - "y": 1664 - }, - "tropical_fish": { - "name": "Tropical Fish", - "x": 768, - "y": 1664 - }, - "pufferfish": { - "name": "Pufferfish", - "x": 864, - "y": 1664 - }, - "cooked_cod": { - "name": "Cooked Cod", - "x": 800, - "y": 1664 - }, - "cooked_salmon": { - "name": "Cooked Salmon", - "x": 832, - "y": 1664 - }, - "ink_sac": { - "name": "Ink Sac", - "x": 736, - "y": 3136 - }, - "cocoa_beans": { - "name": "Cocoa Beans", - "x": 608, - "y": 3136 - }, - "lapis_lazuli": { - "name": "Lapis Lazuli", - "x": 768, - "y": 3136 - }, - "white_dye": { - "name": "White Dye", - "x": 288, - "y": 2368 - }, - "orange_dye": { - "name": "Orange Dye", - "x": 928, - "y": 3136 - }, - "magenta_dye": { - "name": "Magenta Dye", - "x": 896, - "y": 3136 - }, - "light_blue_dye": { - "name": "Light Blue Dye", - "x": 800, - "y": 3136 - }, - "yellow_dye": { - "name": "Yellow Dye", - "x": 32, - "y": 3168 - }, - "lime_dye": { - "name": "Lime Dye", - "x": 864, - "y": 3136 - }, - "pink_dye": { - "name": "Pink Dye", - "x": 960, - "y": 3136 - }, - "gray_dye": { - "name": "Gray Dye", - "x": 672, - "y": 3136 - }, - "light_gray_dye": { - "name": "Light Gray Dye", - "x": 832, - "y": 3136 - }, - "cyan_dye": { - "name": "Cyan Dye", - "x": 640, - "y": 3136 - }, - "purple_dye": { - "name": "Purple Dye", - "x": 992, - "y": 3136 - }, - "blue_dye": { - "name": "Blue Dye", - "x": 224, - "y": 2368 - }, - "brown_dye": { - "name": "Brown Dye", - "x": 256, - "y": 2368 - }, - "green_dye": { - "name": "Green Dye", - "x": 704, - "y": 3136 - }, - "red_dye": { - "name": "Red Dye", - "x": 0, - "y": 3168 - }, - "black_dye": { - "name": "Black Dye", - "x": 192, - "y": 2368 - }, - "bone_meal": { - "name": "Bone Meal", - "x": 576, - "y": 3136 - }, - "bone": { - "name": "Bone", - "x": 416, - "y": 3488 - }, - "sugar": { - "name": "Sugar", - "x": 576, - "y": 3200 - }, - "cake": { - "name": "Cake", - "x": 416, - "y": 3584 - }, - "white_bed": { - "name": "White Bed", - "x": 512, - "y": 3168 - }, - "orange_bed": { - "name": "Orange Bed", - "x": 384, - "y": 3168 - }, - "magenta_bed": { - "name": "Magenta Bed", - "x": 352, - "y": 3168 - }, - "light_blue_bed": { - "name": "Light Blue Bed", - "x": 256, - "y": 3168 - }, - "yellow_bed": { - "name": "Yellow Bed", - "x": 544, - "y": 3168 - }, - "lime_bed": { - "name": "Lime Bed", - "x": 320, - "y": 3168 - }, - "pink_bed": { - "name": "Pink Bed", - "x": 416, - "y": 3168 - }, - "gray_bed": { - "name": "Gray Bed", - "x": 192, - "y": 3168 - }, - "light_gray_bed": { - "name": "Light Gray Bed", - "x": 288, - "y": 3168 - }, - "cyan_bed": { - "name": "Cyan Bed", - "x": 160, - "y": 3168 - }, - "purple_bed": { - "name": "Purple Bed", - "x": 448, - "y": 3168 - }, - "blue_bed": { - "name": "Blue Bed", - "x": 96, - "y": 3168 - }, - "brown_bed": { - "name": "Brown Bed", - "x": 128, - "y": 3168 - }, - "green_bed": { - "name": "Green Bed", - "x": 224, - "y": 3168 - }, - "red_bed": { - "name": "Red Bed", - "x": 480, - "y": 3168 - }, - "black_bed": { - "name": "Black Bed", - "x": 64, - "y": 3168 - }, - "cookie": { - "name": "Cookie", - "x": 96, - "y": 3200 - }, - "filled_map": { - "name": "Map", - "x": 832, - "y": 3552 - }, - "shears": { - "name": "Shears", - "x": 960, - "y": 3552 - }, - "melon_slice": { - "name": "Melon Slice", - "x": 192, - "y": 3200 - }, - "dried_kelp": { - "name": "Dried Kelp", - "x": 544, - "y": 1664 - }, - "pumpkin_seeds": { - "name": "Pumpkin Seeds", - "x": 128, - "y": 1056 - }, - "melon_seeds": { - "name": "Melon Seeds", - "x": 800, - "y": 1024 - }, - "beef": { - "name": "Raw Beef", - "x": 384, - "y": 3200 - }, - "cooked_beef": { - "name": "Steak", - "x": 480, - "y": 832 - }, - "chicken": { - "name": "Raw Chicken", - "x": 416, - "y": 3200 - }, - "cooked_chicken": { - "name": "Cooked Chicken", - "x": 992, - "y": 3168 - }, - "rotten_flesh": { - "name": "Rotten Flesh", - "x": 544, - "y": 3200 - }, - "ender_pearl": { - "name": "Ender Pearl", - "x": 672, - "y": 3488 - }, - "blaze_rod": { - "name": "Blaze Rod", - "x": 448, - "y": 640 - }, - "ghast_tear": { - "name": "Ghast Tear", - "x": 96, - "y": 3136 - }, - "gold_nugget": { - "name": "Gold Nugget", - "x": 832, - "y": 3488 - }, - "nether_wart": { - "name": "Nether Wart", - "x": 704, - "y": 640 - }, - "potion": { - "name": "Potion of Luck", - "x": 960, - "y": 3424 - }, - "glass_bottle": { - "name": "Glass Bottle", - "x": 512, - "y": 3552 - }, - "spider_eye": { - "name": "Spider Eye", - "x": 256, - "y": 3136 - }, - "fermented_spider_eye": { - "name": "Fermented Spider Eye", - "x": 64, - "y": 3136 - }, - "blaze_powder": { - "name": "Blaze Powder", - "x": 416, - "y": 640 - }, - "magma_cream": { - "name": "Magma Cream", - "x": 192, - "y": 3136 - }, - "brewing_stand": { - "name": "Brewing Stand", - "x": 384, - "y": 3584 - }, - "cauldron": { - "name": "Cauldron", - "x": 448, - "y": 3584 - }, - "ender_eye": { - "name": "Eye of Ender", - "x": 384, - "y": 3552 - }, - "glistering_melon_slice": { - "name": "Glistering Melon Slice", - "x": 128, - "y": 3136 - }, - "bat_spawn_egg": { - "name": "Bat Spawn Egg", - "x": 672, - "y": 1120 - }, - "bee_spawn_egg": { - "name": "Bee Spawn Egg", - "x": 224, - "y": 96 - }, - "blaze_spawn_egg": { - "name": "Blaze Spawn Egg", - "x": 704, - "y": 1120 - }, - "cat_spawn_egg": { - "name": "Cat Spawn Egg", - "x": 288, - "y": 2400 - }, - "cave_spider_spawn_egg": { - "name": "Cave Spider Spawn Egg", - "x": 736, - "y": 1120 - }, - "chicken_spawn_egg": { - "name": "Chicken Spawn Egg", - "x": 768, - "y": 1120 - }, - "cod_spawn_egg": { - "name": "Cod Spawn Egg", - "x": 0, - "y": 1696 - }, - "cow_spawn_egg": { - "name": "Cow Spawn Egg", - "x": 800, - "y": 1120 - }, - "creeper_spawn_egg": { - "name": "Creeper Spawn Egg", - "x": 832, - "y": 1120 - }, - "dolphin_spawn_egg": { - "name": "Dolphin Spawn Egg", - "x": 448, - "y": 1952 - }, - "donkey_spawn_egg": { - "name": "Donkey Spawn Egg", - "x": 832, - "y": 1344 - }, - "drowned_spawn_egg": { - "name": "Drowned Spawn Egg", - "x": 960, - "y": 1696 - }, - "elder_guardian_spawn_egg": { - "name": "Elder Guardian Spawn Egg", - "x": 864, - "y": 1344 - }, - "enderman_spawn_egg": { - "name": "Enderman Spawn Egg", - "x": 864, - "y": 1120 - }, - "endermite_spawn_egg": { - "name": "Endermite Spawn Egg", - "x": 896, - "y": 1120 - }, - "evoker_spawn_egg": { - "name": "Evoker Spawn Egg", - "x": 64, - "y": 1408 - }, - "fox_spawn_egg": { - "name": "Fox Spawn Egg", - "x": 992, - "y": 2432 - }, - "ghast_spawn_egg": { - "name": "Ghast Spawn Egg", - "x": 928, - "y": 1120 - }, - "guardian_spawn_egg": { - "name": "Guardian Spawn Egg", - "x": 960, - "y": 1120 - }, - "hoglin_spawn_egg": { - "name": "Hoglin Spawn Egg", - "x": 32, - "y": 192 - }, - "horse_spawn_egg": { - "name": "Horse Spawn Egg", - "x": 992, - "y": 1120 - }, - "husk_spawn_egg": { - "name": "Husk Spawn Egg", - "x": 896, - "y": 1344 - }, - "llama_spawn_egg": { - "name": "Llama Spawn Egg", - "x": 96, - "y": 1408 - }, - "magma_cube_spawn_egg": { - "name": "Magma Cube Spawn Egg", - "x": 0, - "y": 1152 - }, - "mooshroom_spawn_egg": { - "name": "Mooshroom Spawn Egg", - "x": 32, - "y": 1152 - }, - "mule_spawn_egg": { - "name": "Mule Spawn Egg", - "x": 928, - "y": 1344 - }, - "ocelot_spawn_egg": { - "name": "Ocelot Spawn Egg", - "x": 64, - "y": 1152 - }, - "panda_spawn_egg": { - "name": "Panda Spawn Egg", - "x": 352, - "y": 2400 - }, - "parrot_spawn_egg": { - "name": "Parrot Spawn Egg", - "x": 224, - "y": 1536 - }, - "phantom_spawn_egg": { - "name": "Phantom Spawn Egg", - "x": 672, - "y": 1952 - }, - "pig_spawn_egg": { - "name": "Pig Spawn Egg", - "x": 96, - "y": 1152 - }, - "piglin_spawn_egg": { - "name": "Piglin Spawn Egg", - "x": 0, - "y": 192 - }, - "piglin_brute_spawn_egg": { - "name": "Piglin Brute Spawn Egg", - "x": 160, - "y": 256 - }, - "pillager_spawn_egg": { - "name": "Pillager Spawn Egg", - "x": 384, - "y": 2400 - }, - "polar_bear_spawn_egg": { - "name": "Polar Bear Spawn Egg", - "x": 960, - "y": 1344 - }, - "pufferfish_spawn_egg": { - "name": "Pufferfish Spawn Egg", - "x": 32, - "y": 1696 - }, - "rabbit_spawn_egg": { - "name": "Rabbit Spawn Egg", - "x": 128, - "y": 1152 - }, - "ravager_spawn_egg": { - "name": "Ravager Spawn Egg", - "x": 320, - "y": 2400 - }, - "salmon_spawn_egg": { - "name": "Salmon Spawn Egg", - "x": 64, - "y": 1696 - }, - "sheep_spawn_egg": { - "name": "Sheep Spawn Egg", - "x": 160, - "y": 1152 - }, - "shulker_spawn_egg": { - "name": "Shulker Spawn Egg", - "x": 192, - "y": 1152 - }, - "silverfish_spawn_egg": { - "name": "Silverfish Spawn Egg", - "x": 224, - "y": 1152 - }, - "skeleton_spawn_egg": { - "name": "Skeleton Spawn Egg", - "x": 256, - "y": 1152 - }, - "skeleton_horse_spawn_egg": { - "name": "Skeleton Horse Spawn Egg", - "x": 992, - "y": 1344 - }, - "slime_spawn_egg": { - "name": "Slime Spawn Egg", - "x": 288, - "y": 1152 - }, - "spider_spawn_egg": { - "name": "Spider Spawn Egg", - "x": 320, - "y": 1152 - }, - "squid_spawn_egg": { - "name": "Squid Spawn Egg", - "x": 352, - "y": 1152 - }, - "stray_spawn_egg": { - "name": "Stray Spawn Egg", - "x": 0, - "y": 1376 - }, - "strider_spawn_egg": { - "name": "Strider Spawn Egg", - "x": 960, - "y": 192 - }, - "trader_llama_spawn_egg": { - "name": "Trader Llama Spawn Egg", - "x": 928, - "y": 2432 - }, - "tropical_fish_spawn_egg": { - "name": "Tropical Fish Spawn Egg", - "x": 800, - "y": 1696 - }, - "turtle_spawn_egg": { - "name": "Turtle Spawn Egg", - "x": 0, - "y": 1728 - }, - "vex_spawn_egg": { - "name": "Vex Spawn Egg", - "x": 128, - "y": 1408 - }, - "villager_spawn_egg": { - "name": "Villager Spawn Egg", - "x": 384, - "y": 1152 - }, - "vindicator_spawn_egg": { - "name": "Vindicator Spawn Egg", - "x": 160, - "y": 1408 - }, - "wandering_trader_spawn_egg": { - "name": "Wandering Trader Spawn Egg", - "x": 960, - "y": 2432 - }, - "witch_spawn_egg": { - "name": "Witch Spawn Egg", - "x": 416, - "y": 1152 - }, - "wither_skeleton_spawn_egg": { - "name": "Wither Skeleton Spawn Egg", - "x": 32, - "y": 1376 - }, - "wolf_spawn_egg": { - "name": "Wolf Spawn Egg", - "x": 448, - "y": 1152 - }, - "zoglin_spawn_egg": { - "name": "Zoglin Spawn Egg", - "x": 352, - "y": 256 - }, - "zombie_spawn_egg": { - "name": "Zombie Spawn Egg", - "x": 480, - "y": 1152 - }, - "zombie_horse_spawn_egg": { - "name": "Zombie Horse Spawn Egg", - "x": 64, - "y": 1376 - }, - "zombie_villager_spawn_egg": { - "name": "Zombie Villager Spawn Egg", - "x": 128, - "y": 1344 - }, - "zombified_piglin_spawn_egg": { - "name": "Zombified Piglin Spawn Egg", - "x": 512, - "y": 1152 - }, - "experience_bottle": { - "name": "Bottle o' Enchanting", - "x": 288, - "y": 3456 - }, - "fire_charge": { - "name": "Fire Charge", - "x": 416, - "y": 3552 - }, - "writable_book": { - "name": "Book and Quill", - "x": 352, - "y": 3520 - }, - "written_book": { - "name": "Written Book", - "x": 256, - "y": 3584 - }, - "emerald": { - "name": "Emerald", - "x": 640, - "y": 3488 - }, - "item_frame": { - "name": "Item Frame", - "x": 480, - "y": 3136 - }, - "flower_pot": { - "name": "Flower Pot", - "x": 448, - "y": 3136 - }, - "carrot": { - "name": "Carrot", - "x": 928, - "y": 3168 - }, - "potato": { - "name": "Potato", - "x": 288, - "y": 3200 - }, - "baked_potato": { - "name": "Baked Potato", - "x": 800, - "y": 3168 - }, - "poisonous_potato": { - "name": "Poisonous Potato", - "x": 256, - "y": 3200 - }, - "map": { - "name": "Empty Map", - "x": 320, - "y": 3552 - }, - "golden_carrot": { - "name": "Golden Carrot", - "x": 160, - "y": 3136 - }, - "skeleton_skull": { - "name": "Skeleton Skull", - "x": 192, - "y": 960 - }, - "wither_skeleton_skull": { - "name": "Wither Skeleton Skull", - "x": 224, - "y": 960 - }, - "player_head": { - "name": "Player Head", - "x": 160, - "y": 960 - }, - "zombie_head": { - "name": "Zombie Head", - "x": 256, - "y": 960 - }, - "creeper_head": { - "name": "Creeper Head", - "x": 96, - "y": 960 - }, - "dragon_head": { - "name": "Dragon Head", - "x": 128, - "y": 960 - }, - "carrot_on_a_stick": { - "name": "Carrot on a Stick", - "x": 416, - "y": 3520 - }, - "warped_fungus_on_a_stick": { - "name": "Warped Fungus on a Stick", - "x": 992, - "y": 192 - }, - "nether_star": { - "name": "Nether Star", - "x": 64, - "y": 352 - }, - "pumpkin_pie": { - "name": "Pumpkin Pie", - "x": 320, - "y": 3200 - }, - "firework_rocket": { - "name": "Firework Rocket", - "x": 736, - "y": 3168 - }, - "firework_star": { - "name": "Firework Star", - "x": 256, - "y": 800 - }, - "enchanted_book": { - "name": "Enchanted Book", - "x": 352, - "y": 3552 - }, - "nether_brick": { - "name": "Nether Brick", - "x": 992, - "y": 3488 - }, - "quartz": { - "name": "Nether Quartz", - "x": 0, - "y": 3520 - }, - "tnt_minecart": { - "name": "Minecart with TNT", - "x": 320, - "y": 3616 - }, - "hopper_minecart": { - "name": "Minecart with Hopper", - "x": 288, - "y": 3616 - }, - "prismarine_shard": { - "name": "Prismarine Shard", - "x": 160, - "y": 3520 - }, - "prismarine_crystals": { - "name": "Prismarine Crystals", - "x": 128, - "y": 3520 - }, - "rabbit": { - "name": "Raw Rabbit", - "x": 512, - "y": 3200 - }, - "cooked_rabbit": { - "name": "Cooked Rabbit", - "x": 64, - "y": 3200 - }, - "rabbit_stew": { - "name": "Rabbit Stew", - "x": 352, - "y": 3200 - }, - "rabbit_foot": { - "name": "Rabbit's Foot", - "x": 224, - "y": 3136 - }, - "rabbit_hide": { - "name": "Rabbit Hide", - "x": 192, - "y": 3520 - }, - "armor_stand": { - "name": "Armor Stand", - "x": 416, - "y": 3136 - }, - "iron_horse_armor": { - "name": "Iron Horse Armor", - "x": 192, - "y": 32 - }, - "golden_horse_armor": { - "name": "Golden Horse Armor", - "x": 32, - "y": 32 - }, - "diamond_horse_armor": { - "name": "Diamond Horse Armor", - "x": 896, - "y": 0 - }, - "leather_horse_armor": { - "name": "Leather Horse Armor", - "x": 160, - "y": 1376 - }, - "lead": { - "name": "Lead", - "x": 800, - "y": 3552 - }, - "name_tag": { - "name": "Name Tag", - "x": 864, - "y": 3552 - }, - "command_block_minecart": { - "name": "Minecart with Command Block", - "x": 224, - "y": 3616 - }, - "mutton": { - "name": "Raw Mutton", - "x": 448, - "y": 3200 - }, - "cooked_mutton": { - "name": "Cooked Mutton", - "x": 0, - "y": 3200 - }, - "white_banner": { - "name": "White Banner", - "x": 608, - "y": 768 - }, - "orange_banner": { - "name": "Orange Banner", - "x": 864, - "y": 736 - }, - "magenta_banner": { - "name": "Magenta Banner", - "x": 672, - "y": 736 - }, - "light_blue_banner": { - "name": "Light Blue Banner", - "x": 96, - "y": 736 - }, - "yellow_banner": { - "name": "Yellow Banner", - "x": 800, - "y": 768 - }, - "lime_banner": { - "name": "Lime Banner", - "x": 480, - "y": 736 - }, - "pink_banner": { - "name": "Pink Banner", - "x": 32, - "y": 768 - }, - "gray_banner": { - "name": "Gray Banner", - "x": 736, - "y": 704 - }, - "light_gray_banner": { - "name": "Light Gray Banner", - "x": 288, - "y": 736 - }, - "cyan_banner": { - "name": "Cyan Banner", - "x": 544, - "y": 704 - }, - "purple_banner": { - "name": "Purple Banner", - "x": 224, - "y": 768 - }, - "blue_banner": { - "name": "Blue Banner", - "x": 160, - "y": 704 - }, - "brown_banner": { - "name": "Brown Banner", - "x": 352, - "y": 704 - }, - "green_banner": { - "name": "Green Banner", - "x": 928, - "y": 704 - }, - "red_banner": { - "name": "Red Banner", - "x": 416, - "y": 768 - }, - "black_banner": { - "name": "Black Banner", - "x": 992, - "y": 672 - }, - "end_crystal": { - "name": "End Crystal", - "x": 608, - "y": 3168 - }, - "chorus_fruit": { - "name": "Chorus Fruit", - "x": 960, - "y": 3168 - }, - "popped_chorus_fruit": { - "name": "Popped Chorus Fruit", - "x": 96, - "y": 3520 - }, - "beetroot": { - "name": "Beetroot", - "x": 864, - "y": 3168 - }, - "beetroot_seeds": { - "name": "Beetroot Seeds", - "x": 320, - "y": 3392 - }, - "beetroot_soup": { - "name": "Beetroot Soup", - "x": 832, - "y": 3168 - }, - "dragon_breath": { - "name": "Dragon's Breath", - "x": 32, - "y": 3136 - }, - "splash_potion": { - "name": "Splash Potion of Luck", - "x": 512, - "y": 3456 - }, - "spectral_arrow": { - "name": "Spectral Arrow", - "x": 704, - "y": 3616 - }, - "tipped_arrow": { - "name": "Tipped Arrow", - "x": 544, - "y": 1248 - }, - "lingering_potion": { - "name": "Lingering Potion of Luck", - "x": 0, - "y": 3488 - }, - "shield": { - "name": "Shield", - "x": 960, - "y": 2496 - }, - "elytra": { - "name": "Elytra", - "x": 224, - "y": 2496 - }, - "spruce_boat": { - "name": "Spruce Boat", - "x": 384, - "y": 3616 - }, - "birch_boat": { - "name": "Birch Boat", - "x": 64, - "y": 3616 - }, - "jungle_boat": { - "name": "Jungle Boat", - "x": 128, - "y": 3616 - }, - "acacia_boat": { - "name": "Acacia Boat", - "x": 32, - "y": 3616 - }, - "dark_oak_boat": { - "name": "Dark Oak Boat", - "x": 96, - "y": 3616 - }, - "totem_of_undying": { - "name": "Totem of Undying", - "x": 768, - "y": 3616 - }, - "shulker_shell": { - "name": "Shulker Shell", - "x": 256, - "y": 3520 - }, - "iron_nugget": { - "name": "Iron Nugget", - "x": 928, - "y": 3488 - }, - "knowledge_book": { - "name": "Knowledge Book", - "x": 800, - "y": 3584 - }, - "debug_stick": { - "name": "Debug Stick", - "x": 608, - "y": 1120 - }, - "music_disc_pigstep": { - "name": "Music Disc 13", - "x": 0, - "y": 672 - }, - "trident": { - "name": "Trident", - "x": 608, - "y": 1696 - }, - "phantom_membrane": { - "name": "Phantom Membrane", - "x": 32, - "y": 1728 - }, - "nautilus_shell": { - "name": "Nautilus Shell", - "x": 448, - "y": 1728 - }, - "heart_of_the_sea": { - "name": "Heart of the Sea", - "x": 416, - "y": 1728 - }, - "crossbow": { - "name": "Crossbow", - "x": 416, - "y": 2368 - }, - "suspicious_stew": { - "name": "Suspicious Stew", - "x": 928, - "y": 2368 - }, - "loom": { - "name": "Loom", - "x": 416, - "y": 2432 - }, - "flower_banner_pattern": { - "name": "Banner Pattern", - "x": 704, - "y": 2368 - }, - "creeper_banner_pattern": { - "name": "Banner Pattern", - "x": 704, - "y": 2368 - }, - "skull_banner_pattern": { - "name": "Banner Pattern", - "x": 704, - "y": 2368 - }, - "mojang_banner_pattern": { - "name": "Banner Pattern", - "x": 704, - "y": 2368 - }, - "globe_banner_pattern": { - "name": "Banner Pattern", - "x": 704, - "y": 2368 - }, - "piglin_banner_pattern": { - "name": "Banner Pattern", - "x": 704, - "y": 2368 - }, - "composter": { - "name": "Composter", - "x": 864, - "y": 2432 - }, - "barrel": { - "name": "Barrel", - "x": 64, - "y": 2432 - }, - "smoker": { - "name": "Smoker", - "x": 480, - "y": 2432 - }, - "blast_furnace": { - "name": "Blast Furnace", - "x": 288, - "y": 2432 - }, - "cartography_table": { - "name": "Cartography Table", - "x": 608, - "y": 2432 - }, - "fletching_table": { - "name": "Fletching Table", - "x": 640, - "y": 2432 - }, - "grindstone": { - "name": "Grindstone", - "x": 896, - "y": 2432 - }, - "lectern": { - "name": "Lectern", - "x": 576, - "y": 0 - }, - "smithing_table": { - "name": "Smithing Table", - "x": 672, - "y": 2432 - }, - "stonecutter": { - "name": "Stonecutter BE", - "x": 800, - "y": 1056 - }, - "bell": { - "name": "Bell", - "x": 256, - "y": 2400 - }, - "lantern": { - "name": "Lantern", - "x": 576, - "y": 2432 - }, - "soul_lantern": { - "name": "Soul Lantern", - "x": 896, - "y": 128 - }, - "sweet_berries": { - "name": "Sweet Berries", - "x": 768, - "y": 2432 - }, - "campfire": { - "name": "Campfire", - "x": 832, - "y": 2432 - }, - "soul_campfire": { - "name": "Soul Campfire", - "x": 960, - "y": 256 - }, - "shroomlight": { - "name": "Shroomlight", - "x": 704, - "y": 128 - }, - "honeycomb": { - "name": "Honeycomb", - "x": 928, - "y": 32 - }, - "bee_nest": { - "name": "Bee Nest", - "x": 992, - "y": 32 - }, - "beehive": { - "name": "Beehive", - "x": 960, - "y": 32 - }, - "honey_bottle": { - "name": "Honey Bottle", - "x": 896, - "y": 32 - }, - "honey_block": { - "name": "Honey Block", - "x": 320, - "y": 96 - }, - "honeycomb_block": { - "name": "Honeycomb Block", - "x": 64, - "y": 96 - }, - "lodestone": { - "name": "Lodestone", - "x": 928, - "y": 192 - }, - "netherite_block": { - "name": "Block of Netherite", - "x": 96, - "y": 128 - }, - "ancient_debris": { - "name": "Ancient Debris", - "x": 160, - "y": 128 - }, - "target": { - "name": "Target", - "x": 96, - "y": 192 - }, - "crying_obsidian": { - "name": "Crying Obsidian", - "x": 128, - "y": 192 - }, - "blackstone": { - "name": "Blackstone", - "x": 96, - "y": 256 - }, - "blackstone_slab": { - "name": "Blackstone Slab", - "x": 608, - "y": 256 - }, - "blackstone_stairs": { - "name": "Blackstone Stairs", - "x": 640, - "y": 256 - }, - "gilded_blackstone": { - "name": "Gilded Blackstone", - "x": 512, - "y": 256 - }, - "polished_blackstone": { - "name": "Polished Blackstone", - "x": 544, - "y": 256 - }, - "polished_blackstone_slab": { - "name": "Polished Blackstone Slab", - "x": 800, - "y": 256 - }, - "polished_blackstone_stairs": { - "name": "Polished Blackstone Stairs", - "x": 832, - "y": 256 - }, - "chiseled_polished_blackstone": { - "name": "Chiseled Polished Blackstone", - "x": 416, - "y": 256 - }, - "polished_blackstone_bricks": { - "name": "Polished Blackstone Bricks", - "x": 576, - "y": 256 - }, - "polished_blackstone_brick_slab": { - "name": "Polished Blackstone Brick Slab", - "x": 704, - "y": 256 - }, - "polished_blackstone_brick_stairs": { - "name": "Polished Blackstone Brick Stairs", - "x": 736, - "y": 256 - }, - "cracked_polished_blackstone_bricks": { - "name": "Cracked Polished Blackstone Bricks", - "x": 480, - "y": 256 - }, - "respawn_anchor": { - "name": "Respawn Anchor", - "x": 448, - "y": 192 - } -} \ No newline at end of file diff --git a/src/itemsDescriptions.ts b/src/itemsDescriptions.ts new file mode 100644 index 00000000..662d7331 --- /dev/null +++ b/src/itemsDescriptions.ts @@ -0,0 +1,1290 @@ + +export const descriptionGenerators = new Map string)>() +descriptionGenerators.set(/_slab$/, name => 'Craft it by placing 3 blocks of the material in a row in a crafting table.') +descriptionGenerators.set(/_stairs$/, name => 'Craft it by placing 6 blocks of the material in a stair shape in a crafting table.') +descriptionGenerators.set(/_log$/, name => 'You can get it by chopping down a tree. To chop down a tree, hold down the left mouse button until the tree breaks.') +descriptionGenerators.set(/_leaves$/, name => 'You can get it by breaking the leaves of a tree with a tool that has the Silk Touch enchantment or by using shears.') +descriptionGenerators.set(['mangrove_roots'], name => 'You can get it by breaking the roots of a mangrove tree.') +descriptionGenerators.set(['mud'], 'Mud is a block found abundantly in mangrove swamps or created by using a water bottle on a dirt block. It can be used for crafting or converted into clay using pointed dripstone.') +descriptionGenerators.set(['clay'], 'Clay is a block found underwater or created by using a water bottle on a mud block. It can be used for crafting or converted into terracotta using a furnace.') +descriptionGenerators.set(['terracotta'], 'Terracotta is a block created by smelting clay in a furnace. It can be used for crafting or decoration.') +descriptionGenerators.set(['stone'], 'Stone is a block found underground.') +descriptionGenerators.set(['dirt'], 'Dirt is a block found on the surface.') +descriptionGenerators.set(['sand'], 'Sand is a block found on the surface near water.') +descriptionGenerators.set(['gravel'], 'Gravel is a block found on the surface and sometimes underground.') +descriptionGenerators.set(['sandstone'], 'Sandstone is a block found in deserts.') +descriptionGenerators.set(['red_sandstone'], 'Red sandstone is a block found in mesas.') +descriptionGenerators.set(['granite', 'diorite', 'andesite'], name => `${name.charAt(0).toUpperCase() + name.slice(1)} is a block found underground.`) +descriptionGenerators.set(['netherrack', 'soul_sand', 'soul_soil', 'glowstone'], name => `${name.charAt(0).toUpperCase() + name.slice(1)} is a block found in the Nether.`) +descriptionGenerators.set(['end_stone'], 'End stone is a block found in the End.') +descriptionGenerators.set(['obsidian'], 'Obsidian is a block created by pouring water on lava.') +descriptionGenerators.set(['glass'], 'Glass is a block created by smelting sand in a furnace.') +descriptionGenerators.set(['bedrock'], 'Bedrock is an indestructible block found at the bottom of the world in the Overworld and at the top of the world in the Nether.') +descriptionGenerators.set(['water', 'lava'], name => `${name.charAt(0).toUpperCase() + name.slice(1)} is a fluid found in the Overworld.`) +descriptionGenerators.set(/_sapling$/, name => `${name} drops from the leaves of a tree when it decays or is broken. It can be planted on dirt to grow a new tree.`) +descriptionGenerators.set(/^stripped_/, name => `${name} is created by using an axe on the block.`) +descriptionGenerators.set(['sponge'], 'Sponge is a block found in ocean monuments.') +descriptionGenerators.set(/^music_disc_/, name => `Music discs are rare items that can be found in dungeons or by trading with villagers. Also dropped by creepers when killed by a skeleton.`) +descriptionGenerators.set(/^enchanted_book$/, 'Enchanted books are rare items that can be found in dungeons or by trading with villagers.') +descriptionGenerators.set(/_spawn_egg$/, name => `${name} is an item that can be used to spawn a mob in Creative mode. Cannot be obtained in Survival mode.`) +descriptionGenerators.set(/_pottery_sherd$/, name => `${name} can be obtained only by brushing suspicious blocks, with the variants of sherd obtainable being dependent on the structure.`) +descriptionGenerators.set(['cracked_deepslate_bricks'], `Deepslate Bricks and Cracked Deepslate Bricks generate naturally in ancient cities.`) + +const moreGeneratedBlocks = { + 'natural_blocks': { + 'air': { + 'obtained_from': 'Naturally occurs in the world.' + }, + 'deepslate': { + 'obtained_from': 'Mined with a pickaxe in layers -64 to 16.', + 'rarity': 'Common' + }, + 'cobbled_deepslate': { + 'obtained_from': 'Mined from deepslate with any pickaxe.' + }, + 'calcite': { + 'obtained_from': 'Mined with a pickaxe, found in geodes.' + }, + 'tuff': { + 'obtained_from': 'Mined with a pickaxe in layers -64 to 16.', + 'rarity': 'Common' + }, + 'chiseled_tuff': { + 'obtained_from': 'Crafted from tuff.' + }, + 'polished_tuff': { + 'obtained_from': 'Crafted from tuff.' + }, + 'tuff_bricks': { + 'obtained_from': 'Crafted from tuff.' + }, + 'chiseled_tuff_bricks': { + 'obtained_from': 'Crafted from tuff bricks.' + }, + 'grass_block': { + 'obtained_from': 'Mined with a tool enchanted with Silk Touch.' + }, + 'podzol': { + 'obtained_from': 'Mined with a tool enchanted with Silk Touch, found in giant tree taiga biomes.' + }, + 'rooted_dirt': { + 'obtained_from': 'Mined with a shovel, found under azalea trees.' + }, + 'crimson_nylium': { + 'obtained_from': 'Mined with a pickaxe, found in the Nether.' + }, + 'warped_nylium': { + 'obtained_from': 'Mined with a pickaxe, found in the Nether.' + }, + 'cobblestone': { + 'obtained_from': 'Mined from stone, or from breaking stone structures.' + }, + 'mangrove_propagule': { + 'obtained_from': 'Harvested from mangrove trees.' + }, + 'suspicious_sand': { + 'obtained_from': 'Found in deserts and beaches.' + }, + 'suspicious_gravel': { + 'obtained_from': 'Found underwater.' + }, + 'red_sand': { + 'obtained_from': 'Mined from red sand in badlands biomes.' + }, + 'coal_ore': { + 'obtained_from': 'Mined with a pickaxe in layers 0 to 128.', + 'rarity': 'Common' + }, + 'deepslate_coal_ore': { + 'obtained_from': 'Mined with a pickaxe in layers -64 to 0.', + 'rarity': 'Rare' + }, + 'iron_ore': { + 'obtained_from': 'Mined with a pickaxe in layers 0 to 63.', + 'rarity': 'Common' + }, + 'deepslate_iron_ore': { + 'obtained_from': 'Mined with a pickaxe in layers -64 to 0.', + 'rarity': 'Uncommon' + }, + 'copper_ore': { + 'obtained_from': 'Mined with a pickaxe in layers 0 to 96.', + 'rarity': 'Common' + }, + 'deepslate_copper_ore': { + 'obtained_from': 'Mined with a pickaxe in layers -16 to 64.', + 'rarity': 'Uncommon' + }, + 'gold_ore': { + 'obtained_from': 'Mined with a pickaxe in layers -64 to 32.', + 'rarity': 'Uncommon' + }, + 'deepslate_gold_ore': { + 'obtained_from': 'Mined with a pickaxe in layers -64 to 0.', + 'rarity': 'Rare' + }, + 'redstone_ore': { + 'obtained_from': 'Mined with an iron pickaxe or higher in layers -64 to 16.', + 'rarity': 'Uncommon' + }, + 'deepslate_redstone_ore': { + 'obtained_from': 'Mined with an iron pickaxe or higher in layers -64 to 0.', + 'rarity': 'Uncommon' + }, + 'emerald_ore': { + 'obtained_from': 'Mined with an iron pickaxe or higher in mountain biomes, layers -16 to 256.', + 'rarity': 'Rare' + }, + 'deepslate_emerald_ore': { + 'obtained_from': 'Mined with an iron pickaxe or higher in mountain biomes, layers -64 to 0.', + 'rarity': 'Very Rare' + }, + 'lapis_ore': { + 'obtained_from': 'Mined with a stone pickaxe or higher in layers -64 to 32.', + 'rarity': 'Uncommon' + }, + 'deepslate_lapis_ore': { + 'obtained_from': 'Mined with a stone pickaxe or higher in layers -64 to 0.', + 'rarity': 'Rare' + }, + 'diamond_ore': { + 'obtained_from': 'Mined with an iron pickaxe or higher in layers -64 to 16.', + 'rarity': 'Rare' + }, + 'deepslate_diamond_ore': { + 'obtained_from': 'Mined with an iron pickaxe or higher in layers -64 to 0.', + 'rarity': 'Very Rare' + }, + 'nether_gold_ore': { + 'obtained_from': 'Mined with any pickaxe in the Nether.' + }, + 'nether_quartz_ore': { + 'obtained_from': 'Mined with any pickaxe in the Nether.' + }, + 'ancient_debris': { + 'obtained_from': 'Mined with a diamond or netherite pickaxe in the Nether, layers 8 to 22.', + 'rarity': 'Very Rare' + }, + 'budding_amethyst': { + 'obtained_from': 'Found in amethyst geodes, cannot be obtained as an item.' + }, + 'exposed_copper': { + 'obtained_from': 'Exposed copper block obtained through mining.' + }, + 'weathered_copper': { + 'obtained_from': 'Weathered copper block obtained through mining.' + }, + 'oxidized_copper': { + 'obtained_from': 'Oxidized copper block obtained through mining.' + }, + 'chiseled_copper': { + 'obtained_from': 'Crafted from copper blocks.' + }, + 'exposed_chiseled_copper': { + 'obtained_from': 'Exposed chiseled copper block obtained through mining.' + }, + 'weathered_chiseled_copper': { + 'obtained_from': 'Weathered chiseled copper block obtained through mining.' + }, + 'oxidized_chiseled_copper': { + 'obtained_from': 'Oxidized chiseled copper block obtained through mining.' + }, + 'waxed_chiseled_copper': { + 'obtained_from': 'Crafted from copper blocks, waxed to prevent oxidation.' + }, + 'waxed_exposed_chiseled_copper': { + 'obtained_from': 'Waxed exposed chiseled copper block obtained through mining.' + }, + 'waxed_weathered_chiseled_copper': { + 'obtained_from': 'Waxed weathered chiseled copper block obtained through mining.' + }, + 'waxed_oxidized_chiseled_copper': { + 'obtained_from': 'Waxed oxidized chiseled copper block obtained through mining.' + }, + 'crimson_stem': { + 'obtained_from': 'Mined from crimson trees in the Nether.' + }, + 'warped_stem': { + 'obtained_from': 'Mined from warped trees in the Nether.' + }, + 'stripped_crimson_stem': { + 'obtained_from': 'Stripped from crimson stem with an axe.' + }, + 'stripped_warped_stem': { + 'obtained_from': 'Stripped from warped stem with an axe.' + }, + 'stripped_bamboo_block': { + 'obtained_from': 'Crafted from bamboo.' + }, + 'sponge': { + 'obtained_from': 'Found in ocean monuments.' + }, + 'wet_sponge': { + 'obtained_from': 'Absorbs water, can be dried in a furnace.' + }, + 'cobweb': { + 'obtained_from': 'Mined with a sword or shears, found in mineshafts.' + }, + 'short_grass': { + 'obtained_from': 'Sheared from grass.' + }, + 'fern': { + 'obtained_from': 'Sheared from ferns in forest biomes.' + }, + 'azalea': { + 'obtained_from': 'Found in lush caves.' + }, + 'flowering_azalea': { + 'obtained_from': 'Found in lush caves.' + }, + 'dead_bush': { + 'obtained_from': 'Mined with shears in desert biomes.' + }, + 'seagrass': { + 'obtained_from': 'Sheared from underwater grass.' + }, + 'sea_pickle': { + 'obtained_from': 'Mined with shears from coral reefs.' + }, + 'dandelion': { + 'type': 'natural', + 'description': 'Dandelions are common flowers that spawn in plains, forests, and meadows.', + 'spawn_range': 'Surface' + }, + 'poppy': { + 'type': 'natural', + 'description': 'Poppies are common flowers that generate in plains, forests, and meadows.', + 'spawn_range': 'Surface' + }, + 'blue_orchid': { + 'type': 'natural', + 'description': 'Blue orchids spawn naturally in swamp biomes.', + 'spawn_range': 'Surface' + }, + 'allium': { + 'type': 'natural', + 'description': 'Alliums are flowers that generate in flower forest biomes.', + 'spawn_range': 'Surface' + }, + 'azure_bluet': { + 'type': 'natural', + 'description': 'Azure bluets are common flowers that spawn in plains and flower forest biomes.', + 'spawn_range': 'Surface' + }, + 'red_tulip': { + 'type': 'natural', + 'description': 'Red tulips are flowers found in flower forests and plains.', + 'spawn_range': 'Surface' + }, + 'orange_tulip': { + 'type': 'natural', + 'description': 'Orange tulips are flowers found in flower forests and plains.', + 'spawn_range': 'Surface' + }, + 'white_tulip': { + 'type': 'natural', + 'description': 'White tulips are flowers found in flower forests and plains.', + 'spawn_range': 'Surface' + }, + 'pink_tulip': { + 'type': 'natural', + 'description': 'Pink tulips are flowers found in flower forests and plains.', + 'spawn_range': 'Surface' + }, + 'oxeye_daisy': { + 'type': 'natural', + 'description': 'Oxeye daisies are common flowers that generate in plains and flower forest biomes.', + 'spawn_range': 'Surface' + }, + 'cornflower': { + 'type': 'natural', + 'description': 'Cornflowers spawn in plains, flower forests, and meadows.', + 'spawn_range': 'Surface' + }, + 'lily_of_the_valley': { + 'type': 'natural', + 'description': 'Lily of the valleys generate in flower forest biomes.', + 'spawn_range': 'Surface' + }, + 'wither_rose': { + 'type': 'dropped', + 'description': 'Wither roses are dropped when a mob is killed by the Wither boss.', + 'spawn_range': 'N/A' + }, + 'torchflower': { + 'type': 'crafted', + 'description': 'Torchflowers can be grown using torchflower seeds, which are found in archeology loot or by trading.', + 'spawn_range': 'N/A' + }, + 'pitcher_plant': { + 'type': 'crafted', + 'description': 'Pitcher plants can be grown using pitcher pods, which are found in archeology loot or by trading.', + 'spawn_range': 'N/A' + }, + 'spore_blossom': { + 'type': 'natural', + 'description': 'Spore blossoms generate naturally on the ceilings of lush caves.', + 'spawn_range': 'Underground' + }, + 'brown_mushroom': { + 'type': 'natural', + 'description': 'Brown mushrooms are found in dark areas, swamps, mushroom fields, and forests.', + 'spawn_range': 'Surface' + }, + 'red_mushroom': { + 'type': 'natural', + 'description': 'Red mushrooms are found in dark areas, swamps, mushroom fields, and forests.', + 'spawn_range': 'Surface' + }, + 'crimson_fungus': { + 'type': 'natural', + 'description': 'Crimson fungi generate naturally in crimson forests in the Nether.', + 'spawn_range': 'Nether' + }, + 'warped_fungus': { + 'type': 'natural', + 'description': 'Warped fungi generate naturally in warped forests in the Nether.', + 'spawn_range': 'Nether' + }, + 'crimson_roots': { + 'type': 'natural', + 'description': 'Crimson roots generate naturally in crimson forests in the Nether.', + 'spawn_range': 'Nether' + }, + 'warped_roots': { + 'type': 'natural', + 'description': 'Warped roots generate naturally in warped forests in the Nether.', + 'spawn_range': 'Nether' + }, + 'nether_sprouts': { + 'type': 'natural', + 'description': 'Nether sprouts generate naturally in warped forests in the Nether.', + 'spawn_range': 'Nether' + }, + 'weeping_vines': { + 'type': 'natural', + 'description': 'Weeping vines generate naturally in crimson forests in the Nether and grow downward from netherrack.', + 'spawn_range': 'Nether' + }, + 'twisting_vines': { + 'type': 'natural', + 'description': 'Twisting vines generate naturally in warped forests in the Nether and grow upward from the ground.', + 'spawn_range': 'Nether' + }, + 'sugar_cane': { + 'type': 'natural', + 'description': 'Sugar cane is found near water in most biomes.', + 'spawn_range': 'Surface' + }, + 'kelp': { + 'type': 'natural', + 'description': 'Kelp generates underwater in most ocean biomes.', + 'spawn_range': 'Water' + }, + 'pink_petals': { + 'type': 'natural', + 'description': 'Pink petals generate naturally in cherry grove biomes.', + 'spawn_range': 'Surface' + }, + 'moss_block': { + 'type': 'natural', + 'description': 'Moss blocks generate in lush caves and can also be obtained through trading or by using bone meal on moss carpets.', + 'spawn_range': 'Underground' + }, + 'hanging_roots': { + 'type': 'natural', + 'description': 'Hanging roots generate naturally in lush caves.', + 'spawn_range': 'Underground' + }, + 'big_dripleaf': { + 'type': 'natural', + 'description': 'Big dripleaf plants generate in lush caves and can also be obtained through trading.', + 'spawn_range': 'Underground' + }, + 'small_dripleaf': { + 'type': 'natural', + 'description': 'Small dripleaf plants generate in lush caves and can also be obtained through trading.', + 'spawn_range': 'Underground' + }, + 'bamboo': { + 'type': 'natural', + 'description': 'Bamboo generates in jungle biomes, especially bamboo jungles.', + 'spawn_range': 'Surface' + }, + 'smooth_quartz': { + 'type': 'crafted', + 'description': 'Smooth quartz is obtained by smelting blocks of quartz.', + 'spawn_range': 'N/A' + }, + 'smooth_red_sandstone': { + 'type': 'crafted', + 'description': 'Smooth red sandstone is obtained by smelting red sandstone.', + 'spawn_range': 'N/A' + }, + 'smooth_sandstone': { + 'type': 'crafted', + 'description': 'Smooth sandstone is obtained by smelting sandstone.', + 'spawn_range': 'N/A' + }, + 'smooth_stone': { + 'type': 'crafted', + 'description': 'Smooth stone is obtained by smelting regular stone.', + 'spawn_range': 'N/A' + }, + 'chorus_plant': { + 'type': 'natural', + 'description': 'Chorus plants generate naturally in the End and can be grown from chorus flowers.', + 'spawn_range': 'End' + }, + 'chorus_flower': { + 'type': 'natural', + 'description': 'Chorus flowers generate naturally in the End on top of chorus plants.', + 'spawn_range': 'End' + }, + 'spawner': { + 'type': 'natural', + 'description': 'Spawners generate in dungeons, mineshafts, and other structures.', + 'spawn_range': 'Underground' + }, + 'farmland': { + 'type': 'crafted', + 'description': 'Farmland is created by using a hoe on dirt or grass blocks.', + 'spawn_range': 'N/A' + }, + 'ice': { + 'type': 'natural', + 'description': 'Ice generates in snowy and icy biomes and can also be obtained by breaking ice blocks with a Silk Touch tool.', + 'spawn_range': 'Surface' + }, + 'cactus': { + 'type': 'natural', + 'description': 'Cacti generate naturally in desert biomes.', + 'spawn_range': 'Surface' + }, + 'pumpkin': { + 'type': 'natural', + 'description': 'Pumpkins generate naturally in most grassy biomes and can also be grown from pumpkin seeds.', + 'spawn_range': 'Surface' + }, + 'carved_pumpkin': { + 'type': 'crafted', + 'description': 'Carved pumpkins are obtained by using shears on a pumpkin.', + 'spawn_range': 'N/A' + }, + 'basalt': { + 'type': 'natural', + 'description': 'Basalt generates in the Nether in basalt deltas and can also be created by lava flowing over soul soil next to blue ice.', + 'spawn_range': 'Nether' + }, + 'smooth_basalt': { + 'type': 'natural', + 'description': 'Smooth basalt is found around amethyst geodes or can be obtained by smelting basalt.', + 'spawn_range': 'Underground' + }, + 'infested_stone': { + 'type': 'natural', + 'description': 'Infested stone blocks contain silverfish and generate in strongholds, underground.', + 'spawn_range': 'Underground' + }, + 'infested_cobblestone': { + 'type': 'natural', + 'description': 'Infested cobblestone blocks contain silverfish and generate in strongholds, underground.', + 'spawn_range': 'Underground' + }, + 'infested_stone_bricks': { + 'type': 'natural', + 'description': 'Infested stone bricks contain silverfish and generate in strongholds, underground.', + 'spawn_range': 'Underground' + }, + 'infested_mossy_stone_bricks': { + 'type': 'natural', + 'description': 'Infested mossy stone bricks contain silverfish and generate in strongholds, underground.', + 'spawn_range': 'Underground' + }, + 'infested_cracked_stone_bricks': { + 'type': 'natural', + 'description': 'Infested cracked stone bricks contain silverfish and generate in strongholds, underground.', + 'spawn_range': 'Underground' + }, + 'infested_chiseled_stone_bricks': { + 'type': 'natural', + 'description': 'Infested chiseled stone bricks contain silverfish and generate in strongholds, underground.', + 'spawn_range': 'Underground' + }, + 'infested_deepslate': { + 'type': 'natural', + 'description': 'Infested deepslate contains silverfish and generates in the deepslate layer underground.', + 'spawn_range': 'Underground' + }, + 'cracked_stone_bricks': { + 'type': 'crafted', + 'description': 'Cracked stone bricks are obtained by smelting stone bricks.', + 'spawn_range': 'N/A' + }, + 'cracked_deepslate_bricks': { + 'type': 'crafted', + 'description': 'Cracked deepslate bricks are obtained by smelting deepslate bricks.', + 'spawn_range': 'N/A' + }, + 'cracked_deepslate_tiles': { + 'type': 'crafted', + 'description': 'Cracked deepslate tiles are obtained by smelting deepslate tiles.', + 'spawn_range': 'N/A' + }, + 'reinforced_deepslate': { + 'type': 'crafted', + 'description': 'Reinforced deepslate is a strong block that cannot be obtained in survival mode.', + 'spawn_range': 'N/A' + }, + 'brown_mushroom_block': { + 'type': 'natural', + 'description': 'Brown mushroom blocks generate as part of huge mushrooms in dark forest biomes and mushroom fields.', + 'spawn_range': 'Surface' + }, + 'red_mushroom_block': { + 'type': 'natural', + 'description': 'Red mushroom blocks generate as part of huge mushrooms in dark forest biomes and mushroom fields.', + 'spawn_range': 'Surface' + }, + 'mushroom_stem': { + 'type': 'natural', + 'description': 'Mushroom stems generate as part of huge mushrooms in dark forest biomes and mushroom fields.', + 'spawn_range': 'Surface' + }, + 'vine': { + 'type': 'natural', + 'description': 'Vines generate naturally on trees and walls in jungle biomes, swamps, and lush caves.', + 'spawn_range': 'Surface' + }, + 'glow_lichen': { + 'type': 'natural', + 'description': 'Glow lichen generates naturally in caves and can spread to other blocks using bone meal.', + 'spawn_range': 'Underground' + }, + 'mycelium': { + 'type': 'natural', + 'description': 'Mycelium generates naturally in mushroom field biomes and spreads to dirt blocks.', + 'spawn_range': 'Surface' + }, + 'lily_pad': { + 'type': 'natural', + 'description': 'Lily pads generate naturally on the surface of water in swamps.', + 'spawn_range': 'Water' + }, + 'cracked_nether_bricks': { + 'type': 'crafted', + 'description': 'Cracked nether bricks are obtained by smelting nether bricks.', + 'spawn_range': 'N/A' + }, + 'sculk': { + 'type': 'natural', + 'description': 'Sculk generates naturally in the deep dark biome and spreads using a sculk catalyst.', + 'spawn_range': 'Underground' + }, + 'sculk_vein': { + 'type': 'natural', + 'description': 'Sculk veins generate naturally in the deep dark biome and spread using a sculk catalyst.', + 'spawn_range': 'Underground' + }, + 'sculk_catalyst': { + 'type': 'natural', + 'description': 'Sculk catalysts generate naturally in the deep dark biome and spread sculk blocks when mobs die nearby.', + 'spawn_range': 'Underground' + }, + 'sculk_shrieker': { + 'type': 'natural', + 'description': 'Sculk shriekers generate naturally in the deep dark biome and emit a loud shriek when activated.', + 'spawn_range': 'Underground' + }, + 'end_portal_frame': { + 'type': 'natural', + 'description': 'End portal frames generate naturally in strongholds, forming the structure of end portals.', + 'spawn_range': 'Underground' + }, + 'dragon_egg': { + 'type': 'dropped', + 'description': 'The dragon egg is dropped when the Ender Dragon is defeated for the first time.', + 'spawn_range': 'End' + }, + 'command_block': { + 'type': 'crafted', + 'description': 'Command blocks are powerful blocks used in commands and redstone, obtainable only via commands.', + 'spawn_range': 'N/A' + }, + 'chipped_anvil': { + 'type': 'crafted', + 'description': 'Chipped anvils are damaged versions of anvils and are used for repairing and enchanting.', + 'spawn_range': 'N/A' + }, + 'damaged_anvil': { + 'type': 'crafted', + 'description': 'Damaged anvils are further damaged versions of anvils and are used for repairing and enchanting.', + 'spawn_range': 'N/A' + }, + 'barrier': { + 'type': 'crafted', + 'description': 'Barriers are invisible blocks used in map-making and obtainable only via commands.', + 'spawn_range': 'N/A' + }, + 'light': { + 'type': 'crafted', + 'description': 'Light blocks are invisible blocks that emit light, obtainable only via commands.', + 'spawn_range': 'N/A' + }, + 'dirt_path': { + 'type': 'crafted', + 'description': 'Dirt paths are created by using a shovel on grass blocks and are commonly found in villages.', + 'spawn_range': 'Surface' + }, + 'sunflower': { + 'type': 'natural', + 'description': 'Sunflowers generate naturally in sunflower plains biomes.', + 'spawn_range': 'Surface' + }, + 'lilac': { + 'type': 'natural', + 'description': 'Lilacs generate naturally in forest biomes.', + 'spawn_range': 'Surface' + }, + 'rose_bush': { + 'type': 'natural', + 'description': 'Rose bushes generate naturally in forest biomes.', + 'spawn_range': 'Surface' + }, + 'peony': { + 'type': 'natural', + 'description': 'Peonies generate naturally in forest biomes.', + 'spawn_range': 'Surface' + }, + 'tall_grass': { + 'type': 'natural', + 'description': 'Tall grass generates naturally in various biomes and can be grown using bone meal.', + 'spawn_range': 'Surface' + }, + 'large_fern': { + 'type': 'natural', + 'description': 'Large ferns generate naturally in taiga biomes.', + 'spawn_range': 'Surface' + }, + 'repeating_command_block': { + 'type': 'crafted', + 'description': 'Repeating command blocks execute commands every tick and are obtainable only via commands.', + 'spawn_range': 'N/A' + }, + 'chain_command_block': { + 'type': 'crafted', + 'description': 'Chain command blocks execute commands when triggered and are obtainable only via commands.', + 'spawn_range': 'N/A' + }, + 'warped_wart_block': { + 'type': 'natural', + 'description': 'Warped wart blocks generate naturally in warped forests in the Nether.', + 'spawn_range': 'Nether' + }, + 'structure_void': { + 'type': 'crafted', + 'description': 'Structure voids are used in structure blocks to exclude certain blocks from being saved and are obtainable only via commands.', + 'spawn_range': 'N/A' + }, + 'white_shulker_box': { + 'type': 'crafted', + 'description': 'White shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'orange_shulker_box': { + 'type': 'crafted', + 'description': 'Orange shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'magenta_shulker_box': { + 'type': 'crafted', + 'description': 'Magenta shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'light_blue_shulker_box': { + 'type': 'crafted', + 'description': 'Light blue shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'yellow_shulker_box': { + 'type': 'crafted', + 'description': 'Yellow shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'lime_shulker_box': { + 'type': 'crafted', + 'description': 'Lime shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'pink_shulker_box': { + 'type': 'crafted', + 'description': 'Pink shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'gray_shulker_box': { + 'type': 'crafted', + 'description': 'Gray shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'light_gray_shulker_box': { + 'type': 'crafted', + 'description': 'Light gray shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'cyan_shulker_box': { + 'type': 'crafted', + 'description': 'Cyan shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'purple_shulker_box': { + 'type': 'crafted', + 'description': 'Purple shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'blue_shulker_box': { + 'type': 'crafted', + 'description': 'Blue shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'brown_shulker_box': { + 'type': 'crafted', + 'description': 'Brown shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'green_shulker_box': { + 'type': 'crafted', + 'description': 'Green shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'red_shulker_box': { + 'type': 'crafted', + 'description': 'Red shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'black_shulker_box': { + 'type': 'crafted', + 'description': 'Black shulker boxes are crafted from shulker shells and dye, and they function as portable storage.', + 'spawn_range': 'N/A' + }, + 'white_glazed_terracotta': { + 'type': 'crafted', + 'description': 'White glazed terracotta is obtained by smelting white terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'orange_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Orange glazed terracotta is obtained by smelting orange terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'magenta_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Magenta glazed terracotta is obtained by smelting magenta terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'light_blue_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Light blue glazed terracotta is obtained by smelting light blue terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'yellow_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Yellow glazed terracotta is obtained by smelting yellow terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'lime_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Lime glazed terracotta is obtained by smelting lime terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'pink_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Pink glazed terracotta is obtained by smelting pink terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'gray_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Gray glazed terracotta is obtained by smelting gray terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'light_gray_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Light gray glazed terracotta is obtained by smelting light gray terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'cyan_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Cyan glazed terracotta is obtained by smelting cyan terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'purple_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Purple glazed terracotta is obtained by smelting purple terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'blue_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Blue glazed terracotta is obtained by smelting blue terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'brown_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Brown glazed terracotta is obtained by smelting brown terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'green_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Green glazed terracotta is obtained by smelting green terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'red_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Red glazed terracotta is obtained by smelting red terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'black_glazed_terracotta': { + 'type': 'crafted', + 'description': 'Black glazed terracotta is obtained by smelting black terracotta and features decorative patterns.', + 'spawn_range': 'N/A' + }, + 'white_concrete': { + 'type': 'crafted', + 'description': 'White concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'orange_concrete': { + 'type': 'crafted', + 'description': 'Orange concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'magenta_concrete': { + 'type': 'crafted', + 'description': 'Magenta concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'light_blue_concrete': { + 'type': 'crafted', + 'description': 'Light blue concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'yellow_concrete': { + 'type': 'crafted', + 'description': 'Yellow concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'lime_concrete': { + 'type': 'crafted', + 'description': 'Lime concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'pink_concrete': { + 'type': 'crafted', + 'description': 'Pink concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'gray_concrete': { + 'type': 'crafted', + 'description': 'Gray concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'light_gray_concrete': { + 'type': 'crafted', + 'description': 'Light gray concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'cyan_concrete': { + 'type': 'crafted', + 'description': 'Cyan concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'purple_concrete': { + 'type': 'crafted', + 'description': 'Purple concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'blue_concrete': { + 'type': 'crafted', + 'description': 'Blue concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'brown_concrete': { + 'type': 'crafted', + 'description': 'Brown concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'green_concrete': { + 'type': 'crafted', + 'description': 'Green concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'red_concrete': { + 'type': 'crafted', + 'description': 'Red concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'black_concrete': { + 'type': 'crafted', + 'description': 'Black concrete is crafted from concrete powder and hardens when in contact with water.', + 'spawn_range': 'N/A' + }, + 'white_concrete_powder': { + 'type': 'crafted', + 'description': 'White concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'orange_concrete_powder': { + 'type': 'crafted', + 'description': 'Orange concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'magenta_concrete_powder': { + 'type': 'crafted', + 'description': 'Magenta concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'light_blue_concrete_powder': { + 'type': 'crafted', + 'description': 'Light blue concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'yellow_concrete_powder': { + 'type': 'crafted', + 'description': 'Yellow concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'lime_concrete_powder': { + 'type': 'crafted', + 'description': 'Lime concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'pink_concrete_powder': { + 'type': 'crafted', + 'description': 'Pink concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'gray_concrete_powder': { + 'type': 'crafted', + 'description': 'Gray concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'light_gray_concrete_powder': { + 'type': 'crafted', + 'description': 'Light gray concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'cyan_concrete_powder': { + 'type': 'crafted', + 'description': 'Cyan concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'purple_concrete_powder': { + 'type': 'crafted', + 'description': 'Purple concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'blue_concrete_powder': { + 'type': 'crafted', + 'description': 'Blue concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'brown_concrete_powder': { + 'type': 'crafted', + 'description': 'Brown concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'green_concrete_powder': { + 'type': 'crafted', + 'description': 'Green concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'red_concrete_powder': { + 'type': 'crafted', + 'description': 'Red concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'black_concrete_powder': { + 'type': 'crafted', + 'description': 'Black concrete powder is crafted from sand, gravel, and dye, and hardens into concrete when in contact with water.', + 'spawn_range': 'N/A' + }, + 'cyan_candle': { + 'type': 'crafted', + 'description': 'Cyan candles are crafted from string and dye and can be placed on blocks to emit light.', + 'spawn_range': 'N/A' + }, + 'pink_candle': { + 'type': 'crafted', + 'description': 'Pink candles are crafted from string and dye and can be placed on blocks to emit light.', + 'spawn_range': 'N/A' + }, + 'purple_candle': { + 'type': 'crafted', + 'description': 'Purple candles are crafted from string and dye and can be placed on blocks to emit light.', + 'spawn_range': 'N/A' + }, + 'blue_candle': { + 'type': 'crafted', + 'description': 'Blue candles are crafted from string and dye and can be placed on blocks to emit light.', + 'spawn_range': 'N/A' + }, + 'brown_candle': { + 'type': 'crafted', + 'description': 'Brown candles are crafted from string and dye and can be placed on blocks to emit light.', + 'spawn_range': 'N/A' + }, + 'green_candle': { + 'type': 'crafted', + 'description': 'Green candles are crafted from string and dye and can be placed on blocks to emit light.', + 'spawn_range': 'N/A' + }, + 'red_candle': { + 'type': 'crafted', + 'description': 'Red candles are crafted from string and dye and can be placed on blocks to emit light.', + 'spawn_range': 'N/A' + }, + 'black_candle': { + 'type': 'crafted', + 'description': 'Black candles are crafted from string and dye and can be placed on blocks to emit light.', + 'spawn_range': 'N/A' + }, + 'turtle_egg': 'can be obtained via turtle breeding on beaches, where turtles lay eggs that can be collected.', + 'sniffer_egg': 'can be found in buried treasure or ancient ruins, used to hatch sniffers.', + 'dead_tube_coral_block': 'can be obtained by mining tube coral blocks with a pickaxe without Silk Touch or when exposed to air.', + 'dead_brain_coral_block': 'can be obtained by mining brain coral blocks with a pickaxe without Silk Touch or when exposed to air.', + 'dead_bubble_coral_block': 'can be obtained by mining bubble coral blocks with a pickaxe without Silk Touch or when exposed to air.', + 'dead_fire_coral_block': 'can be obtained by mining fire coral blocks with a pickaxe without Silk Touch or when exposed to air.', + 'dead_horn_coral_block': 'can be obtained by mining horn coral blocks with a pickaxe without Silk Touch or when exposed to air.', + 'tube_coral_block': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'brain_coral_block': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'bubble_coral_block': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'fire_coral_block': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'horn_coral_block': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'tube_coral': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'brain_coral': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'bubble_coral': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'fire_coral': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'horn_coral': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'dead_brain_coral': 'can be obtained by mining brain coral without Silk Touch or when exposed to air.', + 'dead_bubble_coral': 'can be obtained by mining bubble coral without Silk Touch or when exposed to air.', + 'dead_fire_coral': 'can be obtained by mining fire coral without Silk Touch or when exposed to air.', + 'dead_horn_coral': 'can be obtained by mining horn coral without Silk Touch or when exposed to air.', + 'dead_tube_coral': 'can be obtained by mining tube coral without Silk Touch or when exposed to air.', + 'tube_coral_fan': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'brain_coral_fan': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'bubble_coral_fan': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'fire_coral_fan': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'horn_coral_fan': 'can be obtained by mining with a pickaxe enchanted with Silk Touch, found in warm ocean biomes.', + 'dead_tube_coral_fan': 'can be obtained by mining tube coral fans without Silk Touch or when exposed to air.', + 'dead_brain_coral_fan': 'can be obtained by mining brain coral fans without Silk Touch or when exposed to air.', + 'dead_bubble_coral_fan': 'can be obtained by mining bubble coral fans without Silk Touch or when exposed to air.', + 'dead_fire_coral_fan': 'can be obtained by mining fire coral fans without Silk Touch or when exposed to air.', + 'dead_horn_coral_fan': 'can be obtained by mining horn coral fans without Silk Touch or when exposed to air.', + 'sculk_sensor': 'can be obtained via Silk Touch enchantment on a pickaxe or found in ancient cities in the deep dark biome.', + 'copper_door': 'can be crafted using copper ingots.', + 'exposed_copper_door': 'can be obtained by allowing copper doors to oxidize or can be crafted directly.', + 'weathered_copper_door': 'can be obtained by allowing exposed copper doors to further oxidize or can be crafted directly.', + 'oxidized_copper_door': 'can be obtained by allowing weathered copper doors to fully oxidize or can be crafted directly.', + 'waxed_copper_door': 'can be crafted using copper ingots and honeycomb.', + 'waxed_exposed_copper_door': 'can be crafted using exposed copper doors and honeycomb.', + 'waxed_weathered_copper_door': 'can be crafted using weathered copper doors and honeycomb.', + 'waxed_oxidized_copper_door': 'can be crafted using oxidized copper doors and honeycomb.', + 'copper_trapdoor': 'can be crafted using copper ingots.', + 'exposed_copper_trapdoor': 'can be obtained by allowing copper trapdoors to oxidize or can be crafted directly.', + 'weathered_copper_trapdoor': 'can be obtained by allowing exposed copper trapdoors to further oxidize or can be crafted directly.', + 'oxidized_copper_trapdoor': 'can be obtained by allowing weathered copper trapdoors to fully oxidize or can be crafted directly.', + 'waxed_copper_trapdoor': 'can be crafted using copper ingots and honeycomb.', + 'waxed_exposed_copper_trapdoor': 'can be crafted using exposed copper trapdoors and honeycomb.', + 'waxed_weathered_copper_trapdoor': 'can be crafted using weathered copper trapdoors and honeycomb.', + 'waxed_oxidized_copper_trapdoor': 'can be crafted using oxidized copper trapdoors and honeycomb.', + 'saddle': 'can be obtained from fishing, dungeon chests, or trading with leatherworkers.', + 'elytra': 'can be found in end ships within end cities.', + 'structure_block': 'can be obtained using commands or in creative mode, used to save and load structures.', + 'jigsaw': 'can be obtained using commands or in creative mode, used to generate structures.', + 'scute': 'can be obtained when baby turtles grow into adults.', + 'apple': 'can be obtained by breaking oak and dark oak leaves or found in chests.', + 'charcoal': 'can be obtained by smelting logs or wood in a furnace.', + 'quartz': 'can be obtained by mining nether quartz ore in the Nether.', + 'amethyst_shard': 'can be obtained by mining amethyst clusters found in geodes with a pickaxe.', + 'netherite_scrap': 'can be obtained by smelting ancient debris found in the Nether.', + 'netherite_sword': 'can be crafted using a diamond sword and netherite ingot.', + 'netherite_shovel': 'can be crafted using a diamond shovel and netherite ingot.', + 'netherite_pickaxe': 'can be crafted using a diamond pickaxe and netherite ingot.', + 'netherite_axe': 'can be crafted using a diamond axe and netherite ingot.', + 'netherite_hoe': 'can be crafted using a diamond hoe and netherite ingot.', + 'string': 'can be obtained from killing spiders or breaking cobwebs.', + 'feather': 'can be obtained from killing chickens.', + 'gunpowder': 'can be obtained from killing creepers, ghasts, and witches.', + 'wheat_seeds': 'can be obtained by breaking tall grass or harvesting wheat crops.', + 'chainmail_helmet': 'can be obtained from chest loot, trading with villagers, or killing mobs wearing it.', + 'chainmail_chestplate': 'can be obtained from chest loot, trading with villagers, or killing mobs wearing it.', + 'chainmail_leggings': 'can be obtained from chest loot, trading with villagers, or killing mobs wearing it.', + 'chainmail_boots': 'can be obtained from chest loot, trading with villagers, or killing mobs wearing it.', + 'netherite_helmet': 'can be crafted using a diamond helmet and netherite ingot.', + 'netherite_chestplate': 'can be crafted using a diamond chestplate and netherite ingot.', + 'netherite_leggings': 'can be crafted using diamond leggings and netherite ingot.', + 'netherite_boots': 'can be crafted using diamond boots and netherite ingot.', + 'flint': 'can be obtained by breaking gravel blocks.', + 'porkchop': 'can be obtained by killing pigs.', + 'cooked_porkchop': 'can be obtained by cooking porkchop in a furnace, smoker, or campfire.', + 'enchanted_golden_apple': 'can be found in dungeon, bastion remnant, and mineshaft chests.', + 'water_bucket': 'can be obtained by using a bucket on a water source block.', + 'lava_bucket': 'can be obtained by using a bucket on a lava source block.', + 'powder_snow_bucket': 'can be obtained by using a bucket on powder snow.', + 'snowball': 'can be obtained by breaking snow blocks or using a shovel on snow.', + 'milk_bucket': 'can be obtained by using a bucket on a cow or mooshroom.', + 'pufferfish_bucket': 'can be obtained by using a bucket on a pufferfish in water.', + 'salmon_bucket': 'can be obtained by using a bucket on a salmon in water.', + 'cod_bucket': 'can be obtained by using a bucket on a cod in water.', + 'tropical_fish_bucket': 'can be obtained by using a bucket on a tropical fish in water.', + 'axolotl_bucket': 'can be obtained by using a bucket on an axolotl in water.', + 'tadpole_bucket': 'can be obtained by using a bucket on a tadpole in water.', + 'brick': 'can be obtained by smelting clay in a furnace.', + 'clay_ball': 'can be obtained by breaking clay blocks or from chest loot.', + 'egg': 'can be obtained from chickens periodically.', + 'bundle': 'can be crafted using rabbit hide and string.', + 'glowstone_dust': 'can be obtained by breaking glowstone blocks or killing witches.', + 'cod': 'can be obtained by fishing or killing cod in water.', + 'salmon': 'can be obtained by fishing or killing salmon in water.', + 'tropical_fish': 'can be obtained by fishing or killing tropical fish in water.', + 'pufferfish': 'can be obtained by fishing or killing pufferfish in water.', + 'cooked_cod': 'can be obtained by cooking cod in a furnace, smoker, or campfire.', + 'cooked_salmon': 'can be obtained by cooking salmon in a furnace, smoker, or campfire.', + 'ink_sac': 'can be obtained by killing squid or as loot from wandering traders.', + 'glow_ink_sac': 'can be obtained by killing glow squid.', + 'cocoa_beans': 'can be obtained from cocoa pods found on jungle trees.', + 'green_dye': 'can be obtained by smelting cactus in a furnace.', + 'bone': 'can be obtained by killing skeletons or from chest loot.', + 'crafter': 'can be obtained via crafting using specific materials (details vary by mod or version).', + 'filled_map': 'can be obtained by using an empty map item.', + 'melon_slice': 'can be obtained by breaking melon blocks.', + 'beef': 'can be obtained by killing cows.', + 'cooked_beef': 'can be obtained by cooking beef in a furnace, smoker, or campfire.', + 'chicken': 'can be obtained by killing chickens.', + 'cooked_chicken': 'can be obtained by cooking chicken in a furnace, smoker, or campfire.', + 'rotten_flesh': 'can be obtained by killing zombies or drowned.', + 'ender_pearl': 'can be obtained by killing endermen.', + 'blaze_rod': 'can be obtained by killing blazes in the Nether.', + 'ghast_tear': 'can be obtained by killing ghasts in the Nether.', + 'nether_wart': 'can be found in Nether fortresses and bastion remnants.', + 'potion': 'can be brewed using a brewing stand with various ingredients.', + 'spider_eye': 'can be obtained by killing spiders or witches.', + 'experience_bottle': 'can be obtained from trading with villagers or found in chest loot.', + 'written_book': 'can be crafted using a book and quill after writing in it.', + 'carrot': 'can be obtained by harvesting carrot crops or found in village farms.', + 'potato': 'can be obtained by harvesting potato crops or found in village farms.', + 'baked_potato': 'can be obtained by cooking potatoes in a furnace, smoker, or campfire.', + 'poisonous_potato': 'can be obtained by harvesting potato crops (rare chance).', + 'skeleton_skull': 'can be obtained by killing skeletons with a charged creeper explosion.', + 'wither_skeleton_skull': 'can be obtained by killing wither skeletons (rare drop).', + 'player_head': 'can be obtained via commands or by killing players in certain conditions (e.g., with a charged creeper).', + 'zombie_head': 'can be obtained by killing zombies with a charged creeper explosion.', + 'creeper_head': 'can be obtained by killing creepers with a charged creeper explosion.', + 'dragon_head': 'can be found at the end of end ships in end cities.', + 'piglin_head': 'can be obtained by killing piglins with a charged creeper explosion.', + 'nether_star': 'can be obtained by defeating the Wither boss.', + 'firework_star': 'can be crafted using gunpowder and dye.', + 'nether_brick': 'can be obtained by smelting netherrack in a furnace or found in Nether fortresses.', + 'prismarine_shard': 'can be obtained by killing guardians and elder guardians.', + 'prismarine_crystals': 'can be obtained by killing guardians and elder guardians or breaking sea lanterns.', + 'rabbit': 'can be obtained by killing rabbits.', + 'cooked_rabbit': 'can be obtained by cooking rabbit in a furnace, smoker, or campfire.', + 'rabbit_foot': 'can be obtained by killing rabbits (rare drop).', + 'rabbit_hide': 'can be obtained by killing rabbits.', + 'iron_horse_armor': 'can be found in dungeon, temple, and stronghold chests.', + 'golden_horse_armor': 'can be found in dungeon, temple, and stronghold chests.', + 'diamond_horse_armor': 'can be found in dungeon, temple, and stronghold chests.', + 'name_tag': 'can be obtained by fishing, dungeon chests, or trading with librarians.', + 'command_block_minecart': 'can be obtained using commands in creative mode.', + 'mutton': 'can be obtained by killing sheep.', + 'cooked_mutton': 'can be obtained by cooking mutton in a furnace, smoker, or campfire.', + 'chorus_fruit': 'can be obtained by breaking chorus plants found in the End.', + 'popped_chorus_fruit': 'can be obtained by smelting chorus fruit in a furnace.', + 'torchflower_seeds': 'can be obtained from torchflower plants, used for breeding and decoration.', + 'pitcher_pod': 'can be obtained from pitcher plants, used for breeding and decoration.', + 'beetroot': 'can be obtained by harvesting beetroot crops or found in village farms.', + 'beetroot_seeds': 'can be obtained by harvesting beetroot crops or from chests.', + 'dragon_breath': 'can be obtained by using an empty bottle on the ender dragon\'s breath attack.', + 'splash_potion': 'can be brewed using a brewing stand and gunpowder with various potions.', + 'tipped_arrow': 'can be crafted using arrows and lingering potions.', + 'lingering_potion': 'can be brewed using a brewing stand and dragon\'s breath with various potions.', + 'totem_of_undying': 'can be obtained by killing evokers in woodland mansions and during raids.', + 'shulker_shell': 'can be obtained by killing shulkers in end cities.', + 'knowledge_book': 'can be obtained using commands or given in custom advancements.', + 'debug_stick': 'can be obtained using commands in creative mode.', + 'disc_fragment_5': 'can be found in ancient city chests, used to craft music disc 5.', + 'trident': 'can be obtained by killing drowned (rare drop).', + 'phantom_membrane': 'can be obtained by killing phantoms.', + 'nautilus_shell': 'can be obtained from fishing, drowned, or wandering traders.', + 'heart_of_the_sea': 'can be found in buried treasure chests.', + 'suspicious_stew': 'can be crafted using mushrooms and various flowers or found in chests.', + 'globe_banner_pattern': 'can be obtained from trading with cartographer villagers.', + 'piglin_banner_pattern': 'can be obtained from bastion remnant chests.', + 'goat_horn': 'can be obtained when a goat rams a solid block.', + 'bell': 'can be obtained from village structures or crafted using iron ingots and wood.', + 'sweet_berries': 'can be obtained from sweet berry bushes found in taiga biomes.', + 'glow_berries': 'can be found in lush cave biomes or by trading with wandering traders.', + 'shroomlight': 'can be obtained by breaking shroomlights found in Nether forests.', + 'honeycomb': 'can be obtained by using shears on beehives or bee nests.', + 'bee_nest': 'can be found in forest biomes with birch or oak trees, especially in flower forests.', + 'crying_obsidian': 'can be found in ruined portals, bastion remnants, or bartered from piglins.', + 'blackstone': 'can be found in basalt deltas, bastion remnants, or crafted from polished blackstone.', + 'gilded_blackstone': 'can be found in bastion remnants.', + 'cracked_polished_blackstone_bricks': 'can be obtained by smelting polished blackstone bricks.', + 'small_amethyst_bud': 'can be found growing in amethyst geodes.', + 'medium_amethyst_bud': 'can be found growing in amethyst geodes.', + 'large_amethyst_bud': 'can be found growing in amethyst geodes.', + 'amethyst_cluster': 'can be found growing in amethyst geodes.', + 'pointed_dripstone': 'can be found in dripstone caves or created by placing a dripstone block under a water source block.', + 'ochre_froglight': 'can be obtained by leading a frog to eat a magma cube, dropping this item.', + 'verdant_froglight': 'can be obtained by leading a frog to eat a magma cube, dropping this item.', + 'pearlescent_froglight': 'can be obtained by leading a frog to eat a magma cube, dropping this item.', + 'frogspawn': 'Frogspawn is an item that can be found in the game Minecraft and is primarily used to breed frogs.', + 'echo_shard': 'Echo Shard is an item in Minecraft Dungeons, primarily used as a currency for trading with Piglin vendors.', + 'copper_grate': 'Copper Grate is a block in Minecraft that can be crafted from copper ingots, primarily used as a decorative block.', + 'exposed_copper_grate': 'Exposed Copper Grate is a variant of Copper Grate in Minecraft that has weathered to the exposed state over time.', + 'weathered_copper_grate': 'Weathered Copper Grate is a variant of Copper Grate in Minecraft that has weathered to the weathered state over time.', + 'oxidized_copper_grate': 'Oxidized Copper Grate is a variant of Copper Grate in Minecraft that has weathered to the oxidized state over time.', + 'waxed_copper_grate': 'Waxed Copper Grate is a variant of Copper Grate in Minecraft that has been waxed to prevent further weathering.', + 'waxed_exposed_copper_grate': 'Waxed Exposed Copper Grate is a variant of Exposed Copper Grate in Minecraft that has been waxed to prevent further weathering.', + 'waxed_weathered_copper_grate': 'Waxed Weathered Copper Grate is a variant of Weathered Copper Grate in Minecraft that has been waxed to prevent further weathering.', + 'waxed_oxidized_copper_grate': 'Waxed Oxidized Copper Grate is a variant of Oxidized Copper Grate in Minecraft that has been waxed to prevent further weathering.', + 'copper_bulb': 'Copper Bulb is a block in Minecraft that can be crafted from copper ingots, primarily used as a decorative block.', + 'exposed_copper_bulb': 'Exposed Copper Bulb is a variant of Copper Bulb in Minecraft that has weathered to the exposed state over time.', + 'weathered_copper_bulb': 'Weathered Copper Bulb is a variant of Copper Bulb in Minecraft that has weathered to the weathered state over time.', + 'oxidized_copper_bulb': 'Oxidized Copper Bulb is a variant of Copper Bulb in Minecraft that has weathered to the oxidized state over time.', + 'waxed_copper_bulb': 'Waxed Copper Bulb is a variant of Copper Bulb in Minecraft that has been waxed to prevent further weathering.', + 'waxed_exposed_copper_bulb': 'Waxed Exposed Copper Bulb is a variant of Exposed Copper Bulb in Minecraft that has been waxed to prevent further weathering.', + 'waxed_weathered_copper_bulb': 'Waxed Weathered Copper Bulb is a variant of Weathered Copper Bulb in Minecraft that has been waxed to prevent further weathering.', + 'waxed_oxidized_copper_bulb': 'Waxed Oxidized Copper Bulb is a variant of Oxidized Copper Bulb in Minecraft that has been waxed to prevent further weathering.', + 'trial_spawner': 'Trial Spawner is an item in Minecraft Dungeons, used in the Ancient Hunt game mode to summon trials for unique rewards.', + 'trial_key': 'Trial Key is an item in Minecraft Dungeons, obtained from defeating Ancient mobs in the Ancient Hunt game mode, used to unlock trials.' + } +} + +const lowerCaseFirstLetter = (string) => string.charAt(0).toLowerCase() + string.slice(1) +for (const [name, data] of Object.entries(moreGeneratedBlocks.natural_blocks)) { + let description = '' as string | ((name: string) => string) + if (typeof data === 'object') { + const obtainedFrom = 'obtained_from' in data ? data.obtained_from : 'description' in data ? data.description : '' + description = obtainedFrom + ('rarity' in data ? ` Rarity: ${data.rarity}` : '') + ('spawn_range' in data ? ` Spawn range: ${data.spawn_range}` : '') + } else { + description = (name) => `${lowerCaseFirstLetter(name)}: ${data}` + } + descriptionGenerators.set([name], description) +} + +export const getItemDescription = (item: import('prismarine-item').Item) => { + const { name } = item + let result: string | ((name: string) => string) = '' + for (const [names, description] of descriptionGenerators) { + if (Array.isArray(names) && names.includes(name)) { + result = description + } + if (typeof names === 'string' && names === name) { + result = description + } + if (names instanceof RegExp && names.test(name)) { + result = description + } + } + return typeof result === 'function' ? result(item.displayName) : result +} diff --git a/src/loadSave.ts b/src/loadSave.ts index af9d078c..f1676cff 100644 --- a/src/loadSave.ts +++ b/src/loadSave.ts @@ -1,15 +1,18 @@ 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 'renderer/viewer/common/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' +import { ConnectOptions } from './connect' +import { appQueryParams } from './appParams' // todo include name of opened handle (zip)! // additional fs metadata @@ -20,6 +23,8 @@ export const fsState = proxy({ saveLoaded: false, openReadOperations: 0, openWriteOperations: 0, + remoteBackend: false, + inMemorySavePath: '' }) const PROPOSE_BACKUP = true @@ -45,7 +50,7 @@ export const readLevelDat = async (path) => { return { levelDat, dataRaw: parsed.value.Data!.value as Record } } -export const loadSave = async (root = '/world') => { +export const loadSave = async (root = '/world', connectOptions?: Partial) => { // todo test if (miscUiState.gameLoaded) { await disconnect() @@ -59,12 +64,12 @@ export const loadSave = async (root = '/world') => { // todo do it in singleplayer as well // eslint-disable-next-line guard-for-in for (const key in forceCachedDataPaths) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete forceCachedDataPaths[key] } // eslint-disable-next-line guard-for-in for (const key in forceRedirectPaths) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete forceRedirectPaths[key] } // todo check jsHeapSizeLimit @@ -80,10 +85,8 @@ export const loadSave = async (root = '/world') => { } let version: string | undefined | null - let isFlat = false if (levelDat) { - const qs = new URLSearchParams(window.location.search) - version = qs.get('mapVersion') ?? levelDat.Version?.Name + version = appQueryParams.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 @@ -91,30 +94,14 @@ 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) { - for (const [key, value] of Object.entries(levelDat.WorldGenSettings.dimensions)) { - if (key.slice(10) === 'overworld') { - if (value.generator.type === 'flat') isFlat = true - break - } - } - } - - if (levelDat.generatorName) { - isFlat = levelDat.generatorName === 'flat' - } - if (!isFlat && levelDat.generatorName !== 'default' && levelDat.generatorName !== 'customized') { - // warnings.push(`Generator ${levelDat.generatorName} may not be supported yet, be careful of new chunks writes`) - } const playerUuid = nameToMcOfflineUUID(options.localUsername) const playerDatPath = `${root}/playerdata/${playerUuid}.dat` @@ -159,6 +146,7 @@ export const loadSave = async (root = '/world') => { // improve compatibility with community saves const rootRemapFiles = ['Warp files'] for (const rootRemapFile of rootRemapFiles) { + // eslint-disable-next-line no-await-in-loop if (await existsViaStats(path.join(root, '..', rootRemapFile))) { forceRedirectPaths[path.join(root, rootRemapFile)] = path.join(root, '..', rootRemapFile) } @@ -177,19 +165,17 @@ export const loadSave = async (root = '/world') => { // hideModal(undefined, undefined, { force: true }) // } + // todo should not be set here fsState.saveLoaded = true + fsState.inMemorySavePath = root window.dispatchEvent(new CustomEvent('singleplayer', { // todo check gamemode level.dat data etc detail: { version, - ...isFlat ? { - generation: { - name: 'superflat' - } - } : {}, ...root === '/world' ? {} : { 'worldFolder': root - } + }, + connectOptions }, })) } diff --git a/src/localServerMultiplayer.ts b/src/localServerMultiplayer.ts index c7c2cd28..7eaa2427 100644 --- a/src/localServerMultiplayer.ts +++ b/src/localServerMultiplayer.ts @@ -1,7 +1,8 @@ import { Duplex } from 'stream' -import Peer, { DataConnection } from 'peerjs' +import { Peer, DataConnection } from 'peerjs' import Client from 'minecraft-protocol/src/client' -import { resolveTimeout, setLoadingScreenStatus } from './utils' +import { resolveTimeout } from './utils' +import { setLoadingScreenStatus } from './appStatus' import { miscUiState } from './globalState' class CustomDuplex extends Duplex { @@ -19,6 +20,8 @@ class CustomDuplex extends Duplex { let peerInstance: Peer | undefined +let overridePeerJsServer = null as string | null + export const getJoinLink = () => { if (!peerInstance) return const url = new URL(window.location.href) @@ -27,6 +30,11 @@ export const getJoinLink = () => { } url.searchParams.set('connectPeer', peerInstance.id) url.searchParams.set('peerVersion', localServer!.options.version) + const host = (overridePeerJsServer ?? miscUiState.appConfig?.peerJsServer) ?? undefined + if (host) { + // TODO! use miscUiState.appConfig.peerJsServer + url.searchParams.set('server', host) + } return url.toString() } @@ -46,13 +54,18 @@ export const openToWanAndCopyJoinLink = async (writeText: (text) => void, doCopy if (doCopy) await copyJoinLink() return 'Already opened to wan. Join link copied' } + miscUiState.wanOpening = true + const host = (overridePeerJsServer ?? miscUiState.appConfig?.peerJsServer) || undefined + const params = host ? parseUrl(host) : undefined const peer = new Peer({ debug: 3, + secure: true, + ...params }) peerInstance = peer peer.on('connection', (connection) => { console.log('connection') - const serverDuplex = new CustomDuplex({}, (data) => connection.send(data)) + const serverDuplex = new CustomDuplex({}, async (data) => connection.send(data)) const client = new Client(true, localServer.options.version, undefined) client.setSocket(serverDuplex) localServer._server.emit('connection', client) @@ -83,34 +96,98 @@ export const openToWanAndCopyJoinLink = async (writeText: (text) => void, doCopy connection.on('close', disconnected) connection.on('error', disconnected) }) + const fallbackServer = miscUiState.appConfig?.peerJsServerFallback + const hasFallback = fallbackServer && peer.options.host !== fallbackServer + let hadErrorReported = false peer.on('error', (error) => { - console.error(error) - writeText(error.message) + console.error('peerJS error', error) + if (error.type === 'server-error' && hasFallback) { + return + } + hadErrorReported = true + writeText(error.message || JSON.stringify(error)) }) - return new Promise(resolve => { + let timeout + const destroy = () => { + clearTimeout(timeout) + timeout = undefined + peer.destroy() + peerInstance = undefined + } + + const result = await new Promise(resolve => { peer.on('open', async () => { await copyJoinLink() resolve('Copied join link to clipboard') }) - setTimeout(() => { - resolve('Failed to open to wan (timeout)') - }, 5000) + timeout = setTimeout(async () => { + if (!hadErrorReported && timeout !== undefined) { + if (hasFallback && overridePeerJsServer === null) { + destroy() + overridePeerJsServer = fallbackServer + console.log('Trying fallback server due to timeout', fallbackServer) + resolve((await openToWanAndCopyJoinLink(writeText, doCopy))!) + } else { + writeText('timeout') + resolve('Failed to open to wan (timeout)') + } + } + }, 6000) + + // fallback + peer.on('error', async (error) => { + if (!peer.open) { + if (hasFallback) { + destroy() + + overridePeerJsServer = fallbackServer + console.log('Trying fallback server', fallbackServer) + resolve((await openToWanAndCopyJoinLink(writeText, doCopy))!) + } + } + }) }) + if (peerInstance && !peerInstance.open) { + destroy() + } + miscUiState.wanOpening = false + return result +} + +const parseUrl = (url: string) => { + // peerJS does this internally for some reason: const url = new URL(`${protocol}://${host}:${port}${path}${key}/${method}`) + if (!url.startsWith('http')) url = `${location.protocol}//${url}` + const urlObj = new URL(url) + const key = urlObj.searchParams.get('key') + return { + host: urlObj.hostname, + path: urlObj.pathname, + protocol: urlObj.protocol.slice(0, -1), + ...urlObj.port ? { port: +urlObj.port } : {}, + ...key ? { key } : {}, + } } export const closeWan = () => { - if (!peerInstance) return - peerInstance.destroy() + peerInstance?.destroy() peerInstance = undefined miscUiState.wanOpened = false - return 'Closed to wan' + return 'Closed WAN' } -export const connectToPeer = async (peerId: string) => { +export type ConnectPeerOptions = { + server?: string +} + +export const connectToPeer = async (peerId: string, options: ConnectPeerOptions = {}) => { setLoadingScreenStatus('Connecting to peer server') // todo destroy connection on error + // TODO! use miscUiState.appConfig.peerJsServer + const host = options.server + const params = host ? parseUrl(host) : undefined const peer = new Peer({ debug: 3, + ...params }) await resolveTimeout(new Promise(resolve => { peer.once('open', resolve) @@ -129,9 +206,9 @@ export const connectToPeer = async (peerId: string) => { })) const clientDuplex = new CustomDuplex({}, (data) => { - // todo rm debug - console.debug('sending', data.toString()) - connection.send(data) + // todo debug until play state + // console.debug('sending', data.toString()) + void connection.send(data) }) connection.on('data', (data: any) => { console.debug('received', Buffer.from(data).toString()) diff --git a/src/markdownToFormattedText.ts b/src/markdownToFormattedText.ts index 5a09917d..5fff20f8 100644 --- a/src/markdownToFormattedText.ts +++ b/src/markdownToFormattedText.ts @@ -2,7 +2,7 @@ import { remark } from 'remark' export default (markdown: string) => { const arr = markdown.split('\n\n') - const lines = ['', '', '', ''] + const lines = ['', '', '', ''] as any[] for (const [i, ast] of arr.map(md => remark().parse(md)).entries()) { lines[i] = transformToMinecraftJSON(ast as Element) } @@ -38,21 +38,21 @@ function transformToMinecraftJSON (element: Element): any { } interface Position { - start: { - line: number; - column: number; - offset: number; - }; - end: { - line: number; - column: number; - offset: number; - }; - } + start: { + line: number; + column: number; + offset: number; + }; + end: { + line: number; + column: number; + offset: number; + }; +} - interface Element { - type: string; - children?: Element[]; - value?: string; - position: Position; - } +interface Element { + type: string; + children?: Element[]; + value?: string; + position: Position; +} diff --git a/src/mcDataTypes.ts b/src/mcDataTypes.ts index 8f4f05e3..3375cf28 100644 --- a/src/mcDataTypes.ts +++ b/src/mcDataTypes.ts @@ -3,4 +3,4316 @@ export type BlockNames = 'air' | 'stone' | 'granite' | 'polished_granite' | 'dio export type ItemNames = 'air' | 'stone' | 'granite' | 'polished_granite' | 'diorite' | 'polished_diorite' | 'andesite' | 'polished_andesite' | 'deepslate' | 'cobbled_deepslate' | 'polished_deepslate' | 'calcite' | 'tuff' | 'dripstone_block' | 'grass_block' | 'dirt' | 'coarse_dirt' | 'podzol' | 'rooted_dirt' | 'mud' | 'crimson_nylium' | 'warped_nylium' | 'cobblestone' | 'oak_planks' | 'spruce_planks' | 'birch_planks' | 'jungle_planks' | 'acacia_planks' | 'cherry_planks' | 'dark_oak_planks' | 'mangrove_planks' | 'bamboo_planks' | 'crimson_planks' | 'warped_planks' | 'bamboo_mosaic' | 'oak_sapling' | 'spruce_sapling' | 'birch_sapling' | 'jungle_sapling' | 'acacia_sapling' | 'cherry_sapling' | 'dark_oak_sapling' | 'mangrove_propagule' | 'bedrock' | 'sand' | 'suspicious_sand' | 'suspicious_gravel' | 'red_sand' | 'gravel' | 'coal_ore' | 'deepslate_coal_ore' | 'iron_ore' | 'deepslate_iron_ore' | 'copper_ore' | 'deepslate_copper_ore' | 'gold_ore' | 'deepslate_gold_ore' | 'redstone_ore' | 'deepslate_redstone_ore' | 'emerald_ore' | 'deepslate_emerald_ore' | 'lapis_ore' | 'deepslate_lapis_ore' | 'diamond_ore' | 'deepslate_diamond_ore' | 'nether_gold_ore' | 'nether_quartz_ore' | 'ancient_debris' | 'coal_block' | 'raw_iron_block' | 'raw_copper_block' | 'raw_gold_block' | 'amethyst_block' | 'budding_amethyst' | 'iron_block' | 'copper_block' | 'gold_block' | 'diamond_block' | 'netherite_block' | 'exposed_copper' | 'weathered_copper' | 'oxidized_copper' | 'cut_copper' | 'exposed_cut_copper' | 'weathered_cut_copper' | 'oxidized_cut_copper' | 'cut_copper_stairs' | 'exposed_cut_copper_stairs' | 'weathered_cut_copper_stairs' | 'oxidized_cut_copper_stairs' | 'cut_copper_slab' | 'exposed_cut_copper_slab' | 'weathered_cut_copper_slab' | 'oxidized_cut_copper_slab' | 'waxed_copper_block' | 'waxed_exposed_copper' | 'waxed_weathered_copper' | 'waxed_oxidized_copper' | 'waxed_cut_copper' | 'waxed_exposed_cut_copper' | 'waxed_weathered_cut_copper' | 'waxed_oxidized_cut_copper' | 'waxed_cut_copper_stairs' | 'waxed_exposed_cut_copper_stairs' | 'waxed_weathered_cut_copper_stairs' | 'waxed_oxidized_cut_copper_stairs' | 'waxed_cut_copper_slab' | 'waxed_exposed_cut_copper_slab' | 'waxed_weathered_cut_copper_slab' | 'waxed_oxidized_cut_copper_slab' | 'oak_log' | 'spruce_log' | 'birch_log' | 'jungle_log' | 'acacia_log' | 'cherry_log' | 'dark_oak_log' | 'mangrove_log' | 'mangrove_roots' | 'muddy_mangrove_roots' | 'crimson_stem' | 'warped_stem' | 'bamboo_block' | 'stripped_oak_log' | 'stripped_spruce_log' | 'stripped_birch_log' | 'stripped_jungle_log' | 'stripped_acacia_log' | 'stripped_cherry_log' | 'stripped_dark_oak_log' | 'stripped_mangrove_log' | 'stripped_crimson_stem' | 'stripped_warped_stem' | 'stripped_oak_wood' | 'stripped_spruce_wood' | 'stripped_birch_wood' | 'stripped_jungle_wood' | 'stripped_acacia_wood' | 'stripped_cherry_wood' | 'stripped_dark_oak_wood' | 'stripped_mangrove_wood' | 'stripped_crimson_hyphae' | 'stripped_warped_hyphae' | 'stripped_bamboo_block' | 'oak_wood' | 'spruce_wood' | 'birch_wood' | 'jungle_wood' | 'acacia_wood' | 'cherry_wood' | 'dark_oak_wood' | 'mangrove_wood' | 'crimson_hyphae' | 'warped_hyphae' | 'oak_leaves' | 'spruce_leaves' | 'birch_leaves' | 'jungle_leaves' | 'acacia_leaves' | 'cherry_leaves' | 'dark_oak_leaves' | 'mangrove_leaves' | 'azalea_leaves' | 'flowering_azalea_leaves' | 'sponge' | 'wet_sponge' | 'glass' | 'tinted_glass' | 'lapis_block' | 'sandstone' | 'chiseled_sandstone' | 'cut_sandstone' | 'cobweb' | 'grass' | 'fern' | 'azalea' | 'flowering_azalea' | 'dead_bush' | 'seagrass' | 'sea_pickle' | 'white_wool' | 'orange_wool' | 'magenta_wool' | 'light_blue_wool' | 'yellow_wool' | 'lime_wool' | 'pink_wool' | 'gray_wool' | 'light_gray_wool' | 'cyan_wool' | 'purple_wool' | 'blue_wool' | 'brown_wool' | 'green_wool' | 'red_wool' | 'black_wool' | 'dandelion' | 'poppy' | 'blue_orchid' | 'allium' | 'azure_bluet' | 'red_tulip' | 'orange_tulip' | 'white_tulip' | 'pink_tulip' | 'oxeye_daisy' | 'cornflower' | 'lily_of_the_valley' | 'wither_rose' | 'torchflower' | 'pitcher_plant' | 'spore_blossom' | 'brown_mushroom' | 'red_mushroom' | 'crimson_fungus' | 'warped_fungus' | 'crimson_roots' | 'warped_roots' | 'nether_sprouts' | 'weeping_vines' | 'twisting_vines' | 'sugar_cane' | 'kelp' | 'moss_carpet' | 'pink_petals' | 'moss_block' | 'hanging_roots' | 'big_dripleaf' | 'small_dripleaf' | 'bamboo' | 'oak_slab' | 'spruce_slab' | 'birch_slab' | 'jungle_slab' | 'acacia_slab' | 'cherry_slab' | 'dark_oak_slab' | 'mangrove_slab' | 'bamboo_slab' | 'bamboo_mosaic_slab' | 'crimson_slab' | 'warped_slab' | 'stone_slab' | 'smooth_stone_slab' | 'sandstone_slab' | 'cut_sandstone_slab' | 'petrified_oak_slab' | 'cobblestone_slab' | 'brick_slab' | 'stone_brick_slab' | 'mud_brick_slab' | 'nether_brick_slab' | 'quartz_slab' | 'red_sandstone_slab' | 'cut_red_sandstone_slab' | 'purpur_slab' | 'prismarine_slab' | 'prismarine_brick_slab' | 'dark_prismarine_slab' | 'smooth_quartz' | 'smooth_red_sandstone' | 'smooth_sandstone' | 'smooth_stone' | 'bricks' | 'bookshelf' | 'chiseled_bookshelf' | 'decorated_pot' | 'mossy_cobblestone' | 'obsidian' | 'torch' | 'end_rod' | 'chorus_plant' | 'chorus_flower' | 'purpur_block' | 'purpur_pillar' | 'purpur_stairs' | 'spawner' | 'chest' | 'crafting_table' | 'farmland' | 'furnace' | 'ladder' | 'cobblestone_stairs' | 'snow' | 'ice' | 'snow_block' | 'cactus' | 'clay' | 'jukebox' | 'oak_fence' | 'spruce_fence' | 'birch_fence' | 'jungle_fence' | 'acacia_fence' | 'cherry_fence' | 'dark_oak_fence' | 'mangrove_fence' | 'bamboo_fence' | 'crimson_fence' | 'warped_fence' | 'pumpkin' | 'carved_pumpkin' | 'jack_o_lantern' | 'netherrack' | 'soul_sand' | 'soul_soil' | 'basalt' | 'polished_basalt' | 'smooth_basalt' | 'soul_torch' | 'glowstone' | 'infested_stone' | 'infested_cobblestone' | 'infested_stone_bricks' | 'infested_mossy_stone_bricks' | 'infested_cracked_stone_bricks' | 'infested_chiseled_stone_bricks' | 'infested_deepslate' | 'stone_bricks' | 'mossy_stone_bricks' | 'cracked_stone_bricks' | 'chiseled_stone_bricks' | 'packed_mud' | 'mud_bricks' | 'deepslate_bricks' | 'cracked_deepslate_bricks' | 'deepslate_tiles' | 'cracked_deepslate_tiles' | 'chiseled_deepslate' | 'reinforced_deepslate' | 'brown_mushroom_block' | 'red_mushroom_block' | 'mushroom_stem' | 'iron_bars' | 'chain' | 'glass_pane' | 'melon' | 'vine' | 'glow_lichen' | 'brick_stairs' | 'stone_brick_stairs' | 'mud_brick_stairs' | 'mycelium' | 'lily_pad' | 'nether_bricks' | 'cracked_nether_bricks' | 'chiseled_nether_bricks' | 'nether_brick_fence' | 'nether_brick_stairs' | 'sculk' | 'sculk_vein' | 'sculk_catalyst' | 'sculk_shrieker' | 'enchanting_table' | 'end_portal_frame' | 'end_stone' | 'end_stone_bricks' | 'dragon_egg' | 'sandstone_stairs' | 'ender_chest' | 'emerald_block' | 'oak_stairs' | 'spruce_stairs' | 'birch_stairs' | 'jungle_stairs' | 'acacia_stairs' | 'cherry_stairs' | 'dark_oak_stairs' | 'mangrove_stairs' | 'bamboo_stairs' | 'bamboo_mosaic_stairs' | 'crimson_stairs' | 'warped_stairs' | 'command_block' | 'beacon' | 'cobblestone_wall' | 'mossy_cobblestone_wall' | 'brick_wall' | 'prismarine_wall' | 'red_sandstone_wall' | 'mossy_stone_brick_wall' | 'granite_wall' | 'stone_brick_wall' | 'mud_brick_wall' | 'nether_brick_wall' | 'andesite_wall' | 'red_nether_brick_wall' | 'sandstone_wall' | 'end_stone_brick_wall' | 'diorite_wall' | 'blackstone_wall' | 'polished_blackstone_wall' | 'polished_blackstone_brick_wall' | 'cobbled_deepslate_wall' | 'polished_deepslate_wall' | 'deepslate_brick_wall' | 'deepslate_tile_wall' | 'anvil' | 'chipped_anvil' | 'damaged_anvil' | 'chiseled_quartz_block' | 'quartz_block' | 'quartz_bricks' | 'quartz_pillar' | 'quartz_stairs' | 'white_terracotta' | 'orange_terracotta' | 'magenta_terracotta' | 'light_blue_terracotta' | 'yellow_terracotta' | 'lime_terracotta' | 'pink_terracotta' | 'gray_terracotta' | 'light_gray_terracotta' | 'cyan_terracotta' | 'purple_terracotta' | 'blue_terracotta' | 'brown_terracotta' | 'green_terracotta' | 'red_terracotta' | 'black_terracotta' | 'barrier' | 'light' | 'hay_block' | 'white_carpet' | 'orange_carpet' | 'magenta_carpet' | 'light_blue_carpet' | 'yellow_carpet' | 'lime_carpet' | 'pink_carpet' | 'gray_carpet' | 'light_gray_carpet' | 'cyan_carpet' | 'purple_carpet' | 'blue_carpet' | 'brown_carpet' | 'green_carpet' | 'red_carpet' | 'black_carpet' | 'terracotta' | 'packed_ice' | 'dirt_path' | 'sunflower' | 'lilac' | 'rose_bush' | 'peony' | 'tall_grass' | 'large_fern' | 'white_stained_glass' | 'orange_stained_glass' | 'magenta_stained_glass' | 'light_blue_stained_glass' | 'yellow_stained_glass' | 'lime_stained_glass' | 'pink_stained_glass' | 'gray_stained_glass' | 'light_gray_stained_glass' | 'cyan_stained_glass' | 'purple_stained_glass' | 'blue_stained_glass' | 'brown_stained_glass' | 'green_stained_glass' | 'red_stained_glass' | 'black_stained_glass' | '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' | 'prismarine' | 'prismarine_bricks' | 'dark_prismarine' | 'prismarine_stairs' | 'prismarine_brick_stairs' | 'dark_prismarine_stairs' | 'sea_lantern' | 'red_sandstone' | 'chiseled_red_sandstone' | 'cut_red_sandstone' | 'red_sandstone_stairs' | 'repeating_command_block' | 'chain_command_block' | 'magma_block' | 'nether_wart_block' | 'warped_wart_block' | 'red_nether_bricks' | 'bone_block' | 'structure_void' | 'shulker_box' | 'white_shulker_box' | 'orange_shulker_box' | 'magenta_shulker_box' | 'light_blue_shulker_box' | 'yellow_shulker_box' | 'lime_shulker_box' | 'pink_shulker_box' | 'gray_shulker_box' | 'light_gray_shulker_box' | 'cyan_shulker_box' | 'purple_shulker_box' | 'blue_shulker_box' | 'brown_shulker_box' | 'green_shulker_box' | 'red_shulker_box' | 'black_shulker_box' | 'white_glazed_terracotta' | 'orange_glazed_terracotta' | 'magenta_glazed_terracotta' | 'light_blue_glazed_terracotta' | 'yellow_glazed_terracotta' | 'lime_glazed_terracotta' | 'pink_glazed_terracotta' | 'gray_glazed_terracotta' | 'light_gray_glazed_terracotta' | 'cyan_glazed_terracotta' | 'purple_glazed_terracotta' | 'blue_glazed_terracotta' | 'brown_glazed_terracotta' | 'green_glazed_terracotta' | 'red_glazed_terracotta' | 'black_glazed_terracotta' | 'white_concrete' | 'orange_concrete' | 'magenta_concrete' | 'light_blue_concrete' | 'yellow_concrete' | 'lime_concrete' | 'pink_concrete' | 'gray_concrete' | 'light_gray_concrete' | 'cyan_concrete' | 'purple_concrete' | 'blue_concrete' | 'brown_concrete' | 'green_concrete' | 'red_concrete' | 'black_concrete' | 'white_concrete_powder' | 'orange_concrete_powder' | 'magenta_concrete_powder' | 'light_blue_concrete_powder' | 'yellow_concrete_powder' | 'lime_concrete_powder' | 'pink_concrete_powder' | 'gray_concrete_powder' | 'light_gray_concrete_powder' | 'cyan_concrete_powder' | 'purple_concrete_powder' | 'blue_concrete_powder' | 'brown_concrete_powder' | 'green_concrete_powder' | 'red_concrete_powder' | 'black_concrete_powder' | 'turtle_egg' | 'sniffer_egg' | 'dead_tube_coral_block' | 'dead_brain_coral_block' | 'dead_bubble_coral_block' | 'dead_fire_coral_block' | 'dead_horn_coral_block' | 'tube_coral_block' | 'brain_coral_block' | 'bubble_coral_block' | 'fire_coral_block' | 'horn_coral_block' | 'tube_coral' | 'brain_coral' | 'bubble_coral' | 'fire_coral' | 'horn_coral' | 'dead_brain_coral' | 'dead_bubble_coral' | 'dead_fire_coral' | 'dead_horn_coral' | 'dead_tube_coral' | 'tube_coral_fan' | 'brain_coral_fan' | 'bubble_coral_fan' | 'fire_coral_fan' | 'horn_coral_fan' | 'dead_tube_coral_fan' | 'dead_brain_coral_fan' | 'dead_bubble_coral_fan' | 'dead_fire_coral_fan' | 'dead_horn_coral_fan' | 'blue_ice' | 'conduit' | 'polished_granite_stairs' | 'smooth_red_sandstone_stairs' | 'mossy_stone_brick_stairs' | 'polished_diorite_stairs' | 'mossy_cobblestone_stairs' | 'end_stone_brick_stairs' | 'stone_stairs' | 'smooth_sandstone_stairs' | 'smooth_quartz_stairs' | 'granite_stairs' | 'andesite_stairs' | 'red_nether_brick_stairs' | 'polished_andesite_stairs' | 'diorite_stairs' | 'cobbled_deepslate_stairs' | 'polished_deepslate_stairs' | 'deepslate_brick_stairs' | 'deepslate_tile_stairs' | 'polished_granite_slab' | 'smooth_red_sandstone_slab' | 'mossy_stone_brick_slab' | 'polished_diorite_slab' | 'mossy_cobblestone_slab' | 'end_stone_brick_slab' | 'smooth_sandstone_slab' | 'smooth_quartz_slab' | 'granite_slab' | 'andesite_slab' | 'red_nether_brick_slab' | 'polished_andesite_slab' | 'diorite_slab' | 'cobbled_deepslate_slab' | 'polished_deepslate_slab' | 'deepslate_brick_slab' | 'deepslate_tile_slab' | 'scaffolding' | 'redstone' | 'redstone_torch' | 'redstone_block' | 'repeater' | 'comparator' | 'piston' | 'sticky_piston' | 'slime_block' | 'honey_block' | 'observer' | 'hopper' | 'dispenser' | 'dropper' | 'lectern' | 'target' | 'lever' | 'lightning_rod' | 'daylight_detector' | 'sculk_sensor' | 'calibrated_sculk_sensor' | 'tripwire_hook' | 'trapped_chest' | 'tnt' | 'redstone_lamp' | 'note_block' | 'stone_button' | 'polished_blackstone_button' | 'oak_button' | 'spruce_button' | 'birch_button' | 'jungle_button' | 'acacia_button' | 'cherry_button' | 'dark_oak_button' | 'mangrove_button' | 'bamboo_button' | 'crimson_button' | 'warped_button' | 'stone_pressure_plate' | 'polished_blackstone_pressure_plate' | 'light_weighted_pressure_plate' | 'heavy_weighted_pressure_plate' | 'oak_pressure_plate' | 'spruce_pressure_plate' | 'birch_pressure_plate' | 'jungle_pressure_plate' | 'acacia_pressure_plate' | 'cherry_pressure_plate' | 'dark_oak_pressure_plate' | 'mangrove_pressure_plate' | 'bamboo_pressure_plate' | 'crimson_pressure_plate' | 'warped_pressure_plate' | 'iron_door' | 'oak_door' | 'spruce_door' | 'birch_door' | 'jungle_door' | 'acacia_door' | 'cherry_door' | 'dark_oak_door' | 'mangrove_door' | 'bamboo_door' | 'crimson_door' | 'warped_door' | 'iron_trapdoor' | 'oak_trapdoor' | 'spruce_trapdoor' | 'birch_trapdoor' | 'jungle_trapdoor' | 'acacia_trapdoor' | 'cherry_trapdoor' | 'dark_oak_trapdoor' | 'mangrove_trapdoor' | 'bamboo_trapdoor' | 'crimson_trapdoor' | 'warped_trapdoor' | 'oak_fence_gate' | 'spruce_fence_gate' | 'birch_fence_gate' | 'jungle_fence_gate' | 'acacia_fence_gate' | 'cherry_fence_gate' | 'dark_oak_fence_gate' | 'mangrove_fence_gate' | 'bamboo_fence_gate' | 'crimson_fence_gate' | 'warped_fence_gate' | 'powered_rail' | 'detector_rail' | 'rail' | 'activator_rail' | 'saddle' | 'minecart' | 'chest_minecart' | 'furnace_minecart' | 'tnt_minecart' | 'hopper_minecart' | 'carrot_on_a_stick' | 'warped_fungus_on_a_stick' | 'elytra' | 'oak_boat' | 'oak_chest_boat' | 'spruce_boat' | 'spruce_chest_boat' | 'birch_boat' | 'birch_chest_boat' | 'jungle_boat' | 'jungle_chest_boat' | 'acacia_boat' | 'acacia_chest_boat' | 'cherry_boat' | 'cherry_chest_boat' | 'dark_oak_boat' | 'dark_oak_chest_boat' | 'mangrove_boat' | 'mangrove_chest_boat' | 'bamboo_raft' | 'bamboo_chest_raft' | 'structure_block' | 'jigsaw' | 'turtle_helmet' | 'scute' | 'flint_and_steel' | 'apple' | 'bow' | 'arrow' | 'coal' | 'charcoal' | 'diamond' | 'emerald' | 'lapis_lazuli' | 'quartz' | 'amethyst_shard' | 'raw_iron' | 'iron_ingot' | 'raw_copper' | 'copper_ingot' | 'raw_gold' | 'gold_ingot' | 'netherite_ingot' | 'netherite_scrap' | 'wooden_sword' | 'wooden_shovel' | 'wooden_pickaxe' | 'wooden_axe' | 'wooden_hoe' | 'stone_sword' | 'stone_shovel' | 'stone_pickaxe' | 'stone_axe' | 'stone_hoe' | 'golden_sword' | 'golden_shovel' | 'golden_pickaxe' | 'golden_axe' | 'golden_hoe' | 'iron_sword' | 'iron_shovel' | 'iron_pickaxe' | 'iron_axe' | 'iron_hoe' | 'diamond_sword' | 'diamond_shovel' | 'diamond_pickaxe' | 'diamond_axe' | 'diamond_hoe' | 'netherite_sword' | 'netherite_shovel' | 'netherite_pickaxe' | 'netherite_axe' | 'netherite_hoe' | 'stick' | 'bowl' | 'mushroom_stew' | 'string' | 'feather' | 'gunpowder' | 'wheat_seeds' | 'wheat' | 'bread' | 'leather_helmet' | 'leather_chestplate' | 'leather_leggings' | 'leather_boots' | 'chainmail_helmet' | 'chainmail_chestplate' | 'chainmail_leggings' | 'chainmail_boots' | 'iron_helmet' | 'iron_chestplate' | 'iron_leggings' | 'iron_boots' | 'diamond_helmet' | 'diamond_chestplate' | 'diamond_leggings' | 'diamond_boots' | 'golden_helmet' | 'golden_chestplate' | 'golden_leggings' | 'golden_boots' | 'netherite_helmet' | 'netherite_chestplate' | 'netherite_leggings' | 'netherite_boots' | 'flint' | 'porkchop' | 'cooked_porkchop' | 'painting' | 'golden_apple' | 'enchanted_golden_apple' | 'oak_sign' | 'spruce_sign' | 'birch_sign' | 'jungle_sign' | 'acacia_sign' | 'cherry_sign' | 'dark_oak_sign' | 'mangrove_sign' | 'bamboo_sign' | 'crimson_sign' | 'warped_sign' | 'oak_hanging_sign' | 'spruce_hanging_sign' | 'birch_hanging_sign' | 'jungle_hanging_sign' | 'acacia_hanging_sign' | 'cherry_hanging_sign' | 'dark_oak_hanging_sign' | 'mangrove_hanging_sign' | 'bamboo_hanging_sign' | 'crimson_hanging_sign' | 'warped_hanging_sign' | 'bucket' | 'water_bucket' | 'lava_bucket' | 'powder_snow_bucket' | 'snowball' | 'leather' | 'milk_bucket' | 'pufferfish_bucket' | 'salmon_bucket' | 'cod_bucket' | 'tropical_fish_bucket' | 'axolotl_bucket' | 'tadpole_bucket' | 'brick' | 'clay_ball' | 'dried_kelp_block' | 'paper' | 'book' | 'slime_ball' | 'egg' | 'compass' | 'recovery_compass' | 'bundle' | 'fishing_rod' | 'clock' | 'spyglass' | 'glowstone_dust' | 'cod' | 'salmon' | 'tropical_fish' | 'pufferfish' | 'cooked_cod' | 'cooked_salmon' | 'ink_sac' | 'glow_ink_sac' | 'cocoa_beans' | 'white_dye' | 'orange_dye' | 'magenta_dye' | 'light_blue_dye' | 'yellow_dye' | 'lime_dye' | 'pink_dye' | 'gray_dye' | 'light_gray_dye' | 'cyan_dye' | 'purple_dye' | 'blue_dye' | 'brown_dye' | 'green_dye' | 'red_dye' | 'black_dye' | 'bone_meal' | 'bone' | 'sugar' | 'cake' | 'white_bed' | 'orange_bed' | 'magenta_bed' | 'light_blue_bed' | 'yellow_bed' | 'lime_bed' | 'pink_bed' | 'gray_bed' | 'light_gray_bed' | 'cyan_bed' | 'purple_bed' | 'blue_bed' | 'brown_bed' | 'green_bed' | 'red_bed' | 'black_bed' | 'cookie' | 'filled_map' | 'shears' | 'melon_slice' | 'dried_kelp' | 'pumpkin_seeds' | 'melon_seeds' | 'beef' | 'cooked_beef' | 'chicken' | 'cooked_chicken' | 'rotten_flesh' | 'ender_pearl' | 'blaze_rod' | 'ghast_tear' | 'gold_nugget' | 'nether_wart' | 'potion' | 'glass_bottle' | 'spider_eye' | 'fermented_spider_eye' | 'blaze_powder' | 'magma_cream' | 'brewing_stand' | 'cauldron' | 'ender_eye' | 'glistering_melon_slice' | 'allay_spawn_egg' | 'axolotl_spawn_egg' | 'bat_spawn_egg' | 'bee_spawn_egg' | 'blaze_spawn_egg' | 'cat_spawn_egg' | 'camel_spawn_egg' | 'cave_spider_spawn_egg' | 'chicken_spawn_egg' | 'cod_spawn_egg' | 'cow_spawn_egg' | 'creeper_spawn_egg' | 'dolphin_spawn_egg' | 'donkey_spawn_egg' | 'drowned_spawn_egg' | 'elder_guardian_spawn_egg' | 'ender_dragon_spawn_egg' | 'enderman_spawn_egg' | 'endermite_spawn_egg' | 'evoker_spawn_egg' | 'fox_spawn_egg' | 'frog_spawn_egg' | 'ghast_spawn_egg' | 'glow_squid_spawn_egg' | 'goat_spawn_egg' | 'guardian_spawn_egg' | 'hoglin_spawn_egg' | 'horse_spawn_egg' | 'husk_spawn_egg' | 'iron_golem_spawn_egg' | 'llama_spawn_egg' | 'magma_cube_spawn_egg' | 'mooshroom_spawn_egg' | 'mule_spawn_egg' | 'ocelot_spawn_egg' | 'panda_spawn_egg' | 'parrot_spawn_egg' | 'phantom_spawn_egg' | 'pig_spawn_egg' | 'piglin_spawn_egg' | 'piglin_brute_spawn_egg' | 'pillager_spawn_egg' | 'polar_bear_spawn_egg' | 'pufferfish_spawn_egg' | 'rabbit_spawn_egg' | 'ravager_spawn_egg' | 'salmon_spawn_egg' | 'sheep_spawn_egg' | 'shulker_spawn_egg' | 'silverfish_spawn_egg' | 'skeleton_spawn_egg' | 'skeleton_horse_spawn_egg' | 'slime_spawn_egg' | 'sniffer_spawn_egg' | 'snow_golem_spawn_egg' | 'spider_spawn_egg' | 'squid_spawn_egg' | 'stray_spawn_egg' | 'strider_spawn_egg' | 'tadpole_spawn_egg' | 'trader_llama_spawn_egg' | 'tropical_fish_spawn_egg' | 'turtle_spawn_egg' | 'vex_spawn_egg' | 'villager_spawn_egg' | 'vindicator_spawn_egg' | 'wandering_trader_spawn_egg' | 'warden_spawn_egg' | 'witch_spawn_egg' | 'wither_spawn_egg' | 'wither_skeleton_spawn_egg' | 'wolf_spawn_egg' | 'zoglin_spawn_egg' | 'zombie_spawn_egg' | 'zombie_horse_spawn_egg' | 'zombie_villager_spawn_egg' | 'zombified_piglin_spawn_egg' | 'experience_bottle' | 'fire_charge' | 'writable_book' | 'written_book' | 'item_frame' | 'glow_item_frame' | 'flower_pot' | 'carrot' | 'potato' | 'baked_potato' | 'poisonous_potato' | 'map' | 'golden_carrot' | 'skeleton_skull' | 'wither_skeleton_skull' | 'player_head' | 'zombie_head' | 'creeper_head' | 'dragon_head' | 'piglin_head' | 'nether_star' | 'pumpkin_pie' | 'firework_rocket' | 'firework_star' | 'enchanted_book' | 'nether_brick' | 'prismarine_shard' | 'prismarine_crystals' | 'rabbit' | 'cooked_rabbit' | 'rabbit_stew' | 'rabbit_foot' | 'rabbit_hide' | 'armor_stand' | 'iron_horse_armor' | 'golden_horse_armor' | 'diamond_horse_armor' | 'leather_horse_armor' | 'lead' | 'name_tag' | 'command_block_minecart' | 'mutton' | 'cooked_mutton' | 'white_banner' | 'orange_banner' | 'magenta_banner' | 'light_blue_banner' | 'yellow_banner' | 'lime_banner' | 'pink_banner' | 'gray_banner' | 'light_gray_banner' | 'cyan_banner' | 'purple_banner' | 'blue_banner' | 'brown_banner' | 'green_banner' | 'red_banner' | 'black_banner' | 'end_crystal' | 'chorus_fruit' | 'popped_chorus_fruit' | 'torchflower_seeds' | 'pitcher_pod' | 'beetroot' | 'beetroot_seeds' | 'beetroot_soup' | 'dragon_breath' | 'splash_potion' | 'spectral_arrow' | 'tipped_arrow' | 'lingering_potion' | 'shield' | 'totem_of_undying' | 'shulker_shell' | 'iron_nugget' | 'knowledge_book' | 'debug_stick' | 'music_disc_13' | 'music_disc_cat' | 'music_disc_blocks' | 'music_disc_chirp' | 'music_disc_far' | 'music_disc_mall' | 'music_disc_mellohi' | 'music_disc_stal' | 'music_disc_strad' | 'music_disc_ward' | 'music_disc_11' | 'music_disc_wait' | 'music_disc_otherside' | 'music_disc_relic' | 'music_disc_5' | 'music_disc_pigstep' | 'disc_fragment_5' | 'trident' | 'phantom_membrane' | 'nautilus_shell' | 'heart_of_the_sea' | 'crossbow' | 'suspicious_stew' | 'loom' | 'flower_banner_pattern' | 'creeper_banner_pattern' | 'skull_banner_pattern' | 'mojang_banner_pattern' | 'globe_banner_pattern' | 'piglin_banner_pattern' | 'goat_horn' | 'composter' | 'barrel' | 'smoker' | 'blast_furnace' | 'cartography_table' | 'fletching_table' | 'grindstone' | 'smithing_table' | 'stonecutter' | 'bell' | 'lantern' | 'soul_lantern' | 'sweet_berries' | 'glow_berries' | 'campfire' | 'soul_campfire' | 'shroomlight' | 'honeycomb' | 'bee_nest' | 'beehive' | 'honey_bottle' | 'honeycomb_block' | 'lodestone' | 'crying_obsidian' | 'blackstone' | 'blackstone_slab' | 'blackstone_stairs' | 'gilded_blackstone' | 'polished_blackstone' | 'polished_blackstone_slab' | 'polished_blackstone_stairs' | 'chiseled_polished_blackstone' | 'polished_blackstone_bricks' | 'polished_blackstone_brick_slab' | 'polished_blackstone_brick_stairs' | 'cracked_polished_blackstone_bricks' | 'respawn_anchor' | 'candle' | 'white_candle' | 'orange_candle' | 'magenta_candle' | 'light_blue_candle' | 'yellow_candle' | 'lime_candle' | 'pink_candle' | 'gray_candle' | 'light_gray_candle' | 'cyan_candle' | 'purple_candle' | 'blue_candle' | 'brown_candle' | 'green_candle' | 'red_candle' | 'black_candle' | 'small_amethyst_bud' | 'medium_amethyst_bud' | 'large_amethyst_bud' | 'amethyst_cluster' | 'pointed_dripstone' | 'ochre_froglight' | 'verdant_froglight' | 'pearlescent_froglight' | 'frogspawn' | 'echo_shard' | 'brush' | 'netherite_upgrade_smithing_template' | 'sentry_armor_trim_smithing_template' | 'dune_armor_trim_smithing_template' | 'coast_armor_trim_smithing_template' | 'wild_armor_trim_smithing_template' | 'ward_armor_trim_smithing_template' | 'eye_armor_trim_smithing_template' | 'vex_armor_trim_smithing_template' | 'tide_armor_trim_smithing_template' | 'snout_armor_trim_smithing_template' | 'rib_armor_trim_smithing_template' | 'spire_armor_trim_smithing_template' | 'wayfinder_armor_trim_smithing_template' | 'shaper_armor_trim_smithing_template' | 'silence_armor_trim_smithing_template' | 'raiser_armor_trim_smithing_template' | 'host_armor_trim_smithing_template' | 'angler_pottery_sherd' | 'archer_pottery_sherd' | 'arms_up_pottery_sherd' | 'blade_pottery_sherd' | 'brewer_pottery_sherd' | 'burn_pottery_sherd' | 'danger_pottery_sherd' | 'explorer_pottery_sherd' | 'friend_pottery_sherd' | 'heart_pottery_sherd' | 'heartbreak_pottery_sherd' | 'howl_pottery_sherd' | 'miner_pottery_sherd' | 'mourner_pottery_sherd' | 'plenty_pottery_sherd' | 'prize_pottery_sherd' | 'sheaf_pottery_sherd' | 'shelter_pottery_sherd' | 'skull_pottery_sherd' | 'snort_pottery_sherd'; export type EntityNames = 'allay' | 'area_effect_cloud' | 'armor_stand' | 'arrow' | 'axolotl' | 'bat' | 'bee' | 'blaze' | 'block_display' | 'boat' | 'camel' | 'cat' | 'cave_spider' | 'chest_boat' | 'chest_minecart' | 'chicken' | 'cod' | 'command_block_minecart' | 'cow' | 'creeper' | 'dolphin' | 'donkey' | 'dragon_fireball' | 'drowned' | 'egg' | 'elder_guardian' | 'end_crystal' | 'ender_dragon' | 'ender_pearl' | 'enderman' | 'endermite' | 'evoker' | 'evoker_fangs' | 'experience_bottle' | 'experience_orb' | 'eye_of_ender' | 'falling_block' | 'firework_rocket' | 'fox' | 'frog' | 'furnace_minecart' | 'ghast' | 'giant' | 'glow_item_frame' | 'glow_squid' | 'goat' | 'guardian' | 'hoglin' | 'hopper_minecart' | 'horse' | 'husk' | 'illusioner' | 'interaction' | 'iron_golem' | 'item' | 'item_display' | 'item_frame' | 'fireball' | 'leash_knot' | 'lightning_bolt' | 'llama' | 'llama_spit' | 'magma_cube' | 'marker' | 'minecart' | 'mooshroom' | 'mule' | 'ocelot' | 'painting' | 'panda' | 'parrot' | 'phantom' | 'pig' | 'piglin' | 'piglin_brute' | 'pillager' | 'polar_bear' | 'potion' | 'pufferfish' | 'rabbit' | 'ravager' | 'salmon' | 'sheep' | 'shulker' | 'shulker_bullet' | 'silverfish' | 'skeleton' | 'skeleton_horse' | 'slime' | 'small_fireball' | 'sniffer' | 'snow_golem' | 'snowball' | 'spawner_minecart' | 'spectral_arrow' | 'spider' | 'squid' | 'stray' | 'strider' | 'tadpole' | 'text_display' | 'tnt' | 'tnt_minecart' | 'trader_llama' | 'trident' | 'tropical_fish' | 'turtle' | 'vex' | 'villager' | 'vindicator' | 'wandering_trader' | 'warden' | 'witch' | 'wither' | 'wither_skeleton' | 'wither_skull' | 'wolf' | 'zoglin' | 'zombie' | 'zombie_horse' | 'zombie_villager' | 'zombified_piglin' | 'player' | 'fishing_bobber'; export type BiomesNames = 'badlands' | 'bamboo_jungle' | 'basalt_deltas' | 'beach' | 'birch_forest' | 'cherry_grove' | 'cold_ocean' | 'crimson_forest' | 'dark_forest' | 'deep_cold_ocean' | 'deep_dark' | 'deep_frozen_ocean' | 'deep_lukewarm_ocean' | 'deep_ocean' | 'desert' | 'dripstone_caves' | 'end_barrens' | 'end_highlands' | 'end_midlands' | 'eroded_badlands' | 'flower_forest' | 'forest' | 'frozen_ocean' | 'frozen_peaks' | 'frozen_river' | 'grove' | 'ice_spikes' | 'jagged_peaks' | 'jungle' | 'lukewarm_ocean' | 'lush_caves' | 'mangrove_swamp' | 'meadow' | 'mushroom_fields' | 'nether_wastes' | 'ocean' | 'old_growth_birch_forest' | 'old_growth_pine_taiga' | 'old_growth_spruce_taiga' | 'plains' | 'river' | 'savanna' | 'savanna_plateau' | 'small_end_islands' | 'snowy_beach' | 'snowy_plains' | 'snowy_slopes' | 'snowy_taiga' | 'soul_sand_valley' | 'sparse_jungle' | 'stony_peaks' | 'stony_shore' | 'sunflower_plains' | 'swamp' | 'taiga' | 'the_end' | 'the_void' | 'warm_ocean' | 'warped_forest' | 'windswept_forest' | 'windswept_gravelly_hills' | 'windswept_hills' | 'windswept_savanna' | 'wooded_badlands'; -export type EnchantmentNames = 'protection' | 'fire_protection' | 'feather_falling' | 'blast_protection' | 'projectile_protection' | 'respiration' | 'aqua_affinity' | 'thorns' | 'depth_strider' | 'frost_walker' | 'binding_curse' | 'soul_speed' | 'swift_sneak' | 'sharpness' | 'smite' | 'bane_of_arthropods' | 'knockback' | 'fire_aspect' | 'looting' | 'sweeping' | 'efficiency' | 'silk_touch' | 'unbreaking' | 'fortune' | 'power' | 'punch' | 'flame' | 'infinity' | 'luck_of_the_sea' | 'lure' | 'loyalty' | 'impaling' | 'riptide' | 'channeling' | 'multishot' | 'quick_charge' | 'piercing' | 'mending' | 'vanishing_curse'; \ No newline at end of file +export type EnchantmentNames = 'protection' | 'fire_protection' | 'feather_falling' | 'blast_protection' | 'projectile_protection' | 'respiration' | 'aqua_affinity' | 'thorns' | 'depth_strider' | 'frost_walker' | 'binding_curse' | 'soul_speed' | 'swift_sneak' | 'sharpness' | 'smite' | 'bane_of_arthropods' | 'knockback' | 'fire_aspect' | 'looting' | 'sweeping' | 'efficiency' | 'silk_touch' | 'unbreaking' | 'fortune' | 'power' | 'punch' | 'flame' | 'infinity' | 'luck_of_the_sea' | 'lure' | 'loyalty' | 'impaling' | 'riptide' | 'channeling' | 'multishot' | 'quick_charge' | 'piercing' | 'mending' | 'vanishing_curse'; + +export type EntityMetadataVersions = { +'Mob': {},'Monster': {},'Creeper': {},'Skeleton': {},'Spider': {},'Giant': {},'Zombie': {},'Slime': {},'Ghast': {},'PigZombie': {},'Enderman': {},'CaveSpider': {},'Silverfish': {},'Blaze': {},'LavaSlime': {},'EnderDragon': {},'WitherBoss': {},'Bat': {},'Witch': {},'Endermite': {},'Guardian': {},'Pig': {},'Sheep': {},'Cow': {},'Chicken': {},'Squid': {},'Wolf': {},'MushroomCow': {},'SnowMan': {},'Ozelot': {},'VillagerGolem': {},'EntityHorse': {},'Rabbit': {},'Villager': {},'Boat': {},'Item': {},'MinecartRideable': {},'PrimedTnt': {},'EnderCrystal': {},'Arrow': {},'Snowball': {},'ThrownEgg': {},'Fireball': {},'SmallFireball': {},'ThrownEnderpearl': {},'WitherSkull': {},'FallingSand': {},'ItemFrame': {},'EyeOfEnderSignal': {},'ThrownPotion': {},'ThrownExpBottle': {},'FireworksRocketEntity': {},'LeashKnot': {},'ArmorStand': {},'Fishing Float': {},'Shulker': {},'XPOrb': {},'Dragon Fireball': {},'item': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'item': string;},'xp_orb': {},'area_effect_cloud': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'radius': string; +/** 1.19.4+ (9) */ +'color': string; +/** 1.19.4+ (10) */ +'waiting': string; +/** 1.19.4+ (11) */ +'particle': string;},'elder_guardian': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'moving': string; +/** 1.19.4+ (17) */ +'attack_target': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'wither_skeleton': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'stray': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'egg': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'item_stack': string;},'leash_knot': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string;},'painting': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'painting_variant': string;},'arrow': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'flags': string; +/** 1.19.4+ (9) */ +'pierce_level': string; +/** 1.19.4+ (10) */ +'effect_color': string;},'snowball': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'item_stack': string;},'fireball': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'item_stack': string;},'small_fireball': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'item_stack': string;},'ender_pearl': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'item_stack': string;},'eye_of_ender_signal': {},'potion': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'item_stack': string;},'xp_bottle': {},'item_frame': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'item': string; +/** 1.19.4+ (9) */ +'rotation': string;},'wither_skull': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'dangerous': string;},'tnt': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'fuse': string; +/** 1.20.3+ (9) */ +'block_state': string;},'falling_block': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'start_pos': string;},'fireworks_rocket': {},'husk': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'special_type': string; +/** 1.19.4+ (18) */ +'drowned_conversion': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'spectral_arrow': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'flags': string; +/** 1.19.4+ (9) */ +'pierce_level': string;},'shulker_bullet': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string;},'dragon_fireball': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string;},'zombie_villager': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'special_type': string; +/** 1.19.4+ (18) */ +'drowned_conversion': string; +/** 1.19.4+ (19) */ +'converting': string; +/** 1.19.4+ (20) */ +'villager_data': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'skeleton_horse': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'zombie_horse': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'armor_stand': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'client_flags': string; +/** 1.19.4+ (16) */ +'head_pose': string; +/** 1.19.4+ (17) */ +'body_pose': string; +/** 1.19.4+ (18) */ +'left_arm_pose': string; +/** 1.19.4+ (19) */ +'right_arm_pose': string; +/** 1.19.4+ (20) */ +'left_leg_pose': string; +/** 1.19.4+ (21) */ +'right_leg_pose': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'donkey': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'flags': string; +/** 1.19.4+ (18) */ +'chest': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'mule': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'flags': string; +/** 1.19.4+ (18) */ +'chest': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'evocation_fangs': {},'evocation_illager': {},'vex': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'vindication_illager': {},'commandblock_minecart': {},'boat': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'hurt': string; +/** 1.19.4+ (9) */ +'hurtdir': string; +/** 1.19.4+ (10) */ +'damage': string; +/** 1.19.4+ (11) */ +'type': string; +/** 1.19.4+ (12) */ +'paddle_left': string; +/** 1.19.4+ (13) */ +'paddle_right': string; +/** 1.19.4+ (14) */ +'bubble_time': string;},'minecart': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'hurt': string; +/** 1.19.4+ (9) */ +'hurtdir': string; +/** 1.19.4+ (10) */ +'damage': string; +/** 1.19.4+ (11) */ +'display_block': string; +/** 1.19.4+ (12) */ +'display_offset': string; +/** 1.19.4+ (13) */ +'custom_display': string;},'chest_minecart': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'hurt': string; +/** 1.19.4+ (9) */ +'hurtdir': string; +/** 1.19.4+ (10) */ +'damage': string; +/** 1.19.4+ (11) */ +'display_block': string; +/** 1.19.4+ (12) */ +'display_offset': string; +/** 1.19.4+ (13) */ +'custom_display': string;},'furnace_minecart': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'hurt': string; +/** 1.19.4+ (9) */ +'hurtdir': string; +/** 1.19.4+ (10) */ +'damage': string; +/** 1.19.4+ (11) */ +'display_block': string; +/** 1.19.4+ (12) */ +'display_offset': string; +/** 1.19.4+ (13) */ +'custom_display': string; +/** 1.19.4+ (14) */ +'fuel': string;},'tnt_minecart': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'hurt': string; +/** 1.19.4+ (9) */ +'hurtdir': string; +/** 1.19.4+ (10) */ +'damage': string; +/** 1.19.4+ (11) */ +'display_block': string; +/** 1.19.4+ (12) */ +'display_offset': string; +/** 1.19.4+ (13) */ +'custom_display': string;},'hopper_minecart': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'hurt': string; +/** 1.19.4+ (9) */ +'hurtdir': string; +/** 1.19.4+ (10) */ +'damage': string; +/** 1.19.4+ (11) */ +'display_block': string; +/** 1.19.4+ (12) */ +'display_offset': string; +/** 1.19.4+ (13) */ +'custom_display': string;},'spawner_minecart': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'hurt': string; +/** 1.19.4+ (9) */ +'hurtdir': string; +/** 1.19.4+ (10) */ +'damage': string; +/** 1.19.4+ (11) */ +'display_block': string; +/** 1.19.4+ (12) */ +'display_offset': string; +/** 1.19.4+ (13) */ +'custom_display': string;},'creeper': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'swell_dir': string; +/** 1.19.4+ (17) */ +'is_powered': string; +/** 1.19.4+ (18) */ +'is_ignited': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'skeleton': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'stray_conversion': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'spider': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'giant': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'zombie': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'special_type': string; +/** 1.19.4+ (18) */ +'drowned_conversion': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'slime': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'size': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'ghast': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'is_charging': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'zombie_pigman': {},'enderman': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'carry_state': string; +/** 1.19.4+ (17) */ +'creepy': string; +/** 1.19.4+ (18) */ +'stared_at': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'cave_spider': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'silverfish': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'blaze': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'magma_cube': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'size': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'ender_dragon': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'phase': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'wither': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'target_a': string; +/** 1.19.4+ (17) */ +'target_b': string; +/** 1.19.4+ (18) */ +'target_c': string; +/** 1.19.4+ (19) */ +'inv': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'bat': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'witch': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'is_celebrating': string; +/** 1.19.4+ (17) */ +'using_item': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'endermite': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'guardian': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'moving': string; +/** 1.19.4+ (17) */ +'attack_target': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'shulker': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'attach_face': string; +/** 1.19.4+ (17) */ +'peek': string; +/** 1.19.4+ (18) */ +'color': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'pig': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'saddle': string; +/** 1.19.4+ (18) */ +'boost_time': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'sheep': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'wool': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'cow': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'chicken': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'squid': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'wolf': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'flags': string; +/** 1.19.4+ (18) */ +'owneruuid': string; +/** 1.19.4+ (19) */ +'interested': string; +/** 1.19.4+ (20) */ +'collar_color': string; +/** 1.19.4+ (21) */ +'remaining_anger_time': string; +/** 1.20.5+ (10) */ +'effect_particles': string; +/** 1.20.5+ (22) */ +'variant': string;},'mooshroom': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'type': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'snowman': {},'ocelot': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'trusting': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'villager_golem': {},'horse': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'flags': string; +/** 1.19.4+ (18) */ +'type_variant': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'rabbit': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'type': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'polar_bear': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'standing': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'llama': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'flags': string; +/** 1.19.4+ (18) */ +'chest': string; +/** 1.19.4+ (19) */ +'strength': string; +/** 1.19.4+ (20) */ +'swag': string; +/** 1.19.4+ (21) */ +'variant': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'llama_spit': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string;},'villager': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'unhappy_counter': string; +/** 1.19.4+ (18) */ +'villager_data': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'ender_crystal': {},'Fishing Hook': {},'illusion_illager': {},'parrot': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'flags': string; +/** 1.19.4+ (18) */ +'owneruuid': string; +/** 1.19.4+ (19) */ +'variant': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'cod': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'from_bucket': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'dolphin': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'treasure_pos': string; +/** 1.19.4+ (17) */ +'got_fish': string; +/** 1.19.4+ (18) */ +'moistness_level': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'drowned': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'special_type': string; +/** 1.19.4+ (18) */ +'drowned_conversion': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'end_crystal': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'beam_target': string; +/** 1.19.4+ (9) */ +'show_bottom': string;},'evoker_fangs': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string;},'evoker': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'is_celebrating': string; +/** 1.19.4+ (17) */ +'spell_casting': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'experience_orb': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string;},'eye_of_ender': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'item_stack': string;},'illusioner': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'is_celebrating': string; +/** 1.19.4+ (17) */ +'spell_casting': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'pufferfish': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'from_bucket': string; +/** 1.19.4+ (17) */ +'puff_state': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'salmon': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'from_bucket': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'snow_golem': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'pumpkin': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'tropical_fish': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'from_bucket': string; +/** 1.19.4+ (17) */ +'type_variant': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'turtle': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'home_pos': string; +/** 1.19.4+ (18) */ +'has_egg': string; +/** 1.19.4+ (19) */ +'laying_egg': string; +/** 1.19.4+ (20) */ +'travel_pos': string; +/** 1.19.4+ (21) */ +'going_home': string; +/** 1.19.4+ (22) */ +'travelling': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'experience_bottle': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'item_stack': string;},'iron_golem}': {},'vindicator': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'is_celebrating': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'phantom': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'size': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'lightning_bolt': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string;},'player': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'player_absorption': string; +/** 1.19.4+ (16) */ +'score': string; +/** 1.19.4+ (17) */ +'player_mode_customisation': string; +/** 1.19.4+ (18) */ +'player_main_hand': string; +/** 1.19.4+ (19) */ +'shoulder_left': string; +/** 1.19.4+ (20) */ +'shoulder_right': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'fishing_bobber': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'hooked_entity': string; +/** 1.19.4+ (9) */ +'biting': string;},'trident': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'flags': string; +/** 1.19.4+ (9) */ +'pierce_level': string; +/** 1.19.4+ (10) */ +'loyalty': string; +/** 1.19.4+ (11) */ +'foil': string;},'item_stack': {},'area_effect cloud': {},'activated_tnt': {},'endercrystal': {},'tipped_arrow': {},'firecharge': {},'thrown_enderpearl': {},'falling_objects': {},'item_frames': {},'eye_of ender': {},'thrown_potion': {},'thrown_exp bottle': {},'firework_rocket': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'fireworks_item': string; +/** 1.19.4+ (9) */ +'attached_to_target': string; +/** 1.19.4+ (10) */ +'shot_at_angle': string;},'armorstand': {},'fishing_hook': {},'cat': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'flags': string; +/** 1.19.4+ (18) */ +'owneruuid': string; +/** 1.19.4+ (19) */ +'variant': string; +/** 1.19.4+ (20) */ +'is_lying': string; +/** 1.19.4+ (21) */ +'relax_state_one': string; +/** 1.19.4+ (22) */ +'collar_color': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'fox': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'type': string; +/** 1.19.4+ (18) */ +'flags': string; +/** 1.19.4+ (19) */ +'trusted_0': string; +/** 1.19.4+ (20) */ +'trusted_1': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'command_block_minecart': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'hurt': string; +/** 1.19.4+ (9) */ +'hurtdir': string; +/** 1.19.4+ (10) */ +'damage': string; +/** 1.19.4+ (11) */ +'display_block': string; +/** 1.19.4+ (12) */ +'display_offset': string; +/** 1.19.4+ (13) */ +'custom_display': string; +/** 1.19.4+ (14) */ +'command_name': string; +/** 1.19.4+ (15) */ +'last_output': string;},'panda': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'unhappy_counter': string; +/** 1.19.4+ (18) */ +'sneeze_counter': string; +/** 1.19.4+ (19) */ +'eat_counter': string; +/** 1.19.4+ (20) */ +'main_gene': string; +/** 1.19.4+ (21) */ +'hidden_gene': string; +/** 1.19.4+ (22) */ +'flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'trader_llama': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'flags': string; +/** 1.19.4+ (18) */ +'chest': string; +/** 1.19.4+ (19) */ +'strength': string; +/** 1.19.4+ (20) */ +'swag': string; +/** 1.19.4+ (21) */ +'variant': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'iron_golem': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'pillager': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'is_celebrating': string; +/** 1.19.4+ (17) */ +'is_charging_crossbow': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'wandering_trader': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'unhappy_counter': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'ravager': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'is_celebrating': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'bee': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'flags': string; +/** 1.19.4+ (18) */ +'remaining_anger_time': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'hoglin': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'immune_to_zombification': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'piglin': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'immune_to_zombification': string; +/** 1.19.4+ (17) */ +'baby': string; +/** 1.19.4+ (18) */ +'is_charging_crossbow': string; +/** 1.19.4+ (19) */ +'is_dancing': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'strider': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'boost_time': string; +/** 1.19.4+ (18) */ +'suffocating': string; +/** 1.19.4+ (19) */ +'saddle': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'zoglin': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'zombified_piglin': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'special_type': string; +/** 1.19.4+ (18) */ +'drowned_conversion': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'piglin_brute': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'immune_to_zombification': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'axolotl': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'variant': string; +/** 1.19.4+ (18) */ +'playing_dead': string; +/** 1.19.4+ (19) */ +'from_bucket': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'glow_item_frame': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'item': string; +/** 1.19.4+ (9) */ +'rotation': string;},'glow_squid': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'dark_ticks_remaining': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'goat': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'is_screaming_goat': string; +/** 1.19.4+ (18) */ +'has_left_horn': string; +/** 1.19.4+ (19) */ +'has_right_horn': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'marker': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string;},'allay': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'dancing': string; +/** 1.19.4+ (17) */ +'can_duplicate': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'chest_boat': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'hurt': string; +/** 1.19.4+ (9) */ +'hurtdir': string; +/** 1.19.4+ (10) */ +'damage': string; +/** 1.19.4+ (11) */ +'type': string; +/** 1.19.4+ (12) */ +'paddle_left': string; +/** 1.19.4+ (13) */ +'paddle_right': string; +/** 1.19.4+ (14) */ +'bubble_time': string;},'frog': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'variant': string; +/** 1.19.4+ (18) */ +'tongue_target': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'tadpole': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'from_bucket': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'warden': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'client_anger_level': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'camel': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'flags': string; +/** 1.19.4+ (18) */ +'dash': string; +/** 1.19.4+ (19) */ +'last_pose_change_tick': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'block_display': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'interpolation_start_delta_ticks': string; +/** 1.19.4+ (9) */ +'interpolation_duration': string; +/** 1.19.4+ (10) */ +'translation': string; +/** 1.19.4+ (11) */ +'scale': string; +/** 1.19.4+ (12) */ +'left_rotation': string; +/** 1.19.4+ (13) */ +'right_rotation': string; +/** 1.19.4+ (14) */ +'billboard_render_constraints': string; +/** 1.19.4+ (15) */ +'brightness_override': string; +/** 1.19.4+ (16) */ +'view_range': string; +/** 1.19.4+ (17) */ +'shadow_radius': string; +/** 1.19.4+ (18) */ +'shadow_strength': string; +/** 1.19.4+ (19) */ +'width': string; +/** 1.19.4+ (20) */ +'height': string; +/** 1.19.4+ (21) */ +'glow_color_override': string; +/** 1.19.4+ (22) */ +'block_state': string; +/** 1.20.2+ (8) */ +'transformation_interpolation_start_delta_ticks': string; +/** 1.20.2+ (9) */ +'transformation_interpolation_duration': string; +/** 1.20.2+ (10) */ +'pos_rot_interpolation_duration': string;},'interaction': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'width': string; +/** 1.19.4+ (9) */ +'height': string; +/** 1.19.4+ (10) */ +'response': string;},'item_display': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'interpolation_start_delta_ticks': string; +/** 1.19.4+ (9) */ +'interpolation_duration': string; +/** 1.19.4+ (10) */ +'translation': string; +/** 1.19.4+ (11) */ +'scale': string; +/** 1.19.4+ (12) */ +'left_rotation': string; +/** 1.19.4+ (13) */ +'right_rotation': string; +/** 1.19.4+ (14) */ +'billboard_render_constraints': string; +/** 1.19.4+ (15) */ +'brightness_override': string; +/** 1.19.4+ (16) */ +'view_range': string; +/** 1.19.4+ (17) */ +'shadow_radius': string; +/** 1.19.4+ (18) */ +'shadow_strength': string; +/** 1.19.4+ (19) */ +'width': string; +/** 1.19.4+ (20) */ +'height': string; +/** 1.19.4+ (21) */ +'glow_color_override': string; +/** 1.19.4+ (22) */ +'item_stack': string; +/** 1.19.4+ (23) */ +'item_display': string; +/** 1.20.2+ (8) */ +'transformation_interpolation_start_delta_ticks': string; +/** 1.20.2+ (9) */ +'transformation_interpolation_duration': string; +/** 1.20.2+ (10) */ +'pos_rot_interpolation_duration': string;},'sniffer': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'living_entity_flags': string; +/** 1.19.4+ (9) */ +'health': string; +/** 1.19.4+ (10) */ +'effect_color': string; +/** 1.19.4+ (11) */ +'effect_ambience': string; +/** 1.19.4+ (12) */ +'arrow_count': string; +/** 1.19.4+ (13) */ +'stinger_count': string; +/** 1.19.4+ (14) */ +'sleeping_pos': string; +/** 1.19.4+ (15) */ +'mob_flags': string; +/** 1.19.4+ (16) */ +'baby': string; +/** 1.19.4+ (17) */ +'state': string; +/** 1.19.4+ (18) */ +'drop_seed_at_tick': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'text_display': { +/** 1.19.4+ (0) */ +'shared_flags': string; +/** 1.19.4+ (1) */ +'air_supply': string; +/** 1.19.4+ (2) */ +'custom_name': string; +/** 1.19.4+ (3) */ +'custom_name_visible': string; +/** 1.19.4+ (4) */ +'silent': string; +/** 1.19.4+ (5) */ +'no_gravity': string; +/** 1.19.4+ (6) */ +'pose': string; +/** 1.19.4+ (7) */ +'ticks_frozen': string; +/** 1.19.4+ (8) */ +'interpolation_start_delta_ticks': string; +/** 1.19.4+ (9) */ +'interpolation_duration': string; +/** 1.19.4+ (10) */ +'translation': string; +/** 1.19.4+ (11) */ +'scale': string; +/** 1.19.4+ (12) */ +'left_rotation': string; +/** 1.19.4+ (13) */ +'right_rotation': string; +/** 1.19.4+ (14) */ +'billboard_render_constraints': string; +/** 1.19.4+ (15) */ +'brightness_override': string; +/** 1.19.4+ (16) */ +'view_range': string; +/** 1.19.4+ (17) */ +'shadow_radius': string; +/** 1.19.4+ (18) */ +'shadow_strength': string; +/** 1.19.4+ (19) */ +'width': string; +/** 1.19.4+ (20) */ +'height': string; +/** 1.19.4+ (21) */ +'glow_color_override': string; +/** 1.19.4+ (22) */ +'text': string; +/** 1.19.4+ (23) */ +'line_width': string; +/** 1.19.4+ (24) */ +'background_color': string; +/** 1.19.4+ (25) */ +'text_opacity': string; +/** 1.19.4+ (26) */ +'style_flags': string; +/** 1.20.2+ (8) */ +'transformation_interpolation_start_delta_ticks': string; +/** 1.20.2+ (9) */ +'transformation_interpolation_duration': string; +/** 1.20.2+ (10) */ +'pos_rot_interpolation_duration': string;},'breeze': { +/** 1.20.3+ (0) */ +'shared_flags': string; +/** 1.20.3+ (1) */ +'air_supply': string; +/** 1.20.3+ (2) */ +'custom_name': string; +/** 1.20.3+ (3) */ +'custom_name_visible': string; +/** 1.20.3+ (4) */ +'silent': string; +/** 1.20.3+ (5) */ +'no_gravity': string; +/** 1.20.3+ (6) */ +'pose': string; +/** 1.20.3+ (7) */ +'ticks_frozen': string; +/** 1.20.3+ (8) */ +'living_entity_flags': string; +/** 1.20.3+ (9) */ +'health': string; +/** 1.20.3+ (10) */ +'effect_color': string; +/** 1.20.3+ (11) */ +'effect_ambience': string; +/** 1.20.3+ (12) */ +'arrow_count': string; +/** 1.20.3+ (13) */ +'stinger_count': string; +/** 1.20.3+ (14) */ +'sleeping_pos': string; +/** 1.20.3+ (15) */ +'mob_flags': string; +/** 1.20.5+ (10) */ +'effect_particles': string;},'wind_charge': { +/** 1.20.3+ (0) */ +'shared_flags': string; +/** 1.20.3+ (1) */ +'air_supply': string; +/** 1.20.3+ (2) */ +'custom_name': string; +/** 1.20.3+ (3) */ +'custom_name_visible': string; +/** 1.20.3+ (4) */ +'silent': string; +/** 1.20.3+ (5) */ +'no_gravity': string; +/** 1.20.3+ (6) */ +'pose': string; +/** 1.20.3+ (7) */ +'ticks_frozen': string;},'armadillo': { +/** 1.20.5+ (0) */ +'shared_flags': string; +/** 1.20.5+ (1) */ +'air_supply': string; +/** 1.20.5+ (2) */ +'custom_name': string; +/** 1.20.5+ (3) */ +'custom_name_visible': string; +/** 1.20.5+ (4) */ +'silent': string; +/** 1.20.5+ (5) */ +'no_gravity': string; +/** 1.20.5+ (6) */ +'pose': string; +/** 1.20.5+ (7) */ +'ticks_frozen': string; +/** 1.20.5+ (8) */ +'living_entity_flags': string; +/** 1.20.5+ (9) */ +'health': string; +/** 1.20.5+ (10) */ +'effect_particles': string; +/** 1.20.5+ (11) */ +'effect_ambience': string; +/** 1.20.5+ (12) */ +'arrow_count': string; +/** 1.20.5+ (13) */ +'stinger_count': string; +/** 1.20.5+ (14) */ +'sleeping_pos': string; +/** 1.20.5+ (15) */ +'mob_flags': string; +/** 1.20.5+ (16) */ +'baby': string; +/** 1.20.5+ (17) */ +'armadillo_state': string;},'bogged': { +/** 1.20.5+ (0) */ +'shared_flags': string; +/** 1.20.5+ (1) */ +'air_supply': string; +/** 1.20.5+ (2) */ +'custom_name': string; +/** 1.20.5+ (3) */ +'custom_name_visible': string; +/** 1.20.5+ (4) */ +'silent': string; +/** 1.20.5+ (5) */ +'no_gravity': string; +/** 1.20.5+ (6) */ +'pose': string; +/** 1.20.5+ (7) */ +'ticks_frozen': string; +/** 1.20.5+ (8) */ +'living_entity_flags': string; +/** 1.20.5+ (9) */ +'health': string; +/** 1.20.5+ (10) */ +'effect_particles': string; +/** 1.20.5+ (11) */ +'effect_ambience': string; +/** 1.20.5+ (12) */ +'arrow_count': string; +/** 1.20.5+ (13) */ +'stinger_count': string; +/** 1.20.5+ (14) */ +'sleeping_pos': string; +/** 1.20.5+ (15) */ +'mob_flags': string; +/** 1.20.5+ (16) */ +'sheared': string;},'breeze_wind_charge': { +/** 1.20.5+ (0) */ +'shared_flags': string; +/** 1.20.5+ (1) */ +'air_supply': string; +/** 1.20.5+ (2) */ +'custom_name': string; +/** 1.20.5+ (3) */ +'custom_name_visible': string; +/** 1.20.5+ (4) */ +'silent': string; +/** 1.20.5+ (5) */ +'no_gravity': string; +/** 1.20.5+ (6) */ +'pose': string; +/** 1.20.5+ (7) */ +'ticks_frozen': string;},'ominous_item_spawner': { +/** 1.20.5+ (0) */ +'shared_flags': string; +/** 1.20.5+ (1) */ +'air_supply': string; +/** 1.20.5+ (2) */ +'custom_name': string; +/** 1.20.5+ (3) */ +'custom_name_visible': string; +/** 1.20.5+ (4) */ +'silent': string; +/** 1.20.5+ (5) */ +'no_gravity': string; +/** 1.20.5+ (6) */ +'pose': string; +/** 1.20.5+ (7) */ +'ticks_frozen': string; +/** 1.20.5+ (8) */ +'item': string;}, +} \ No newline at end of file diff --git a/src/mcTypes.ts b/src/mcTypes.ts index ee87b9c9..ebb4f560 100644 --- a/src/mcTypes.ts +++ b/src/mcTypes.ts @@ -1,108 +1,108 @@ -/* eslint-disable no-multi-spaces */ + // todo move from here //@ts-format-ignore-region // 1.8.8 export interface LevelDat { WorldGenSettings?: WorldGenSettings; - RandomSeed: number[]; - generatorName?: string; - BorderCenterX: number; - BorderCenterZ: number; - Difficulty: number; - DifficultyLocked: number; - BorderSizeLerpTime: number[]; + RandomSeed: number[]; + generatorName?: string; + BorderCenterX: number; + BorderCenterZ: number; + Difficulty: number; + DifficultyLocked: number; + BorderSizeLerpTime: number[]; Version?: { Name: string // id, snapshot } /** 0,1 */ - raining: number; - Time: number[]; - GameType: number; - MapFeatures: number; + raining: number; + Time: number[]; + GameType: number; + MapFeatures: number; BorderDamagePerBlock: number; - BorderWarningBlocks: number; + BorderWarningBlocks: number; BorderSizeLerpTarget: number; - DayTime: number[]; - initialized: number; - allowCommands: number; - SizeOnDisk: number[]; - GameRules: GameRules; - Player: Player; - SpawnY: number; - rainTime: number; - thunderTime: number; - SpawnZ: number; - hardcore: number; - SpawnX: number; - clearWeatherTime: number; - thundering: number; - generatorVersion?: number; - version: number; - BorderSafeZone: number; - generatorOptions?: string; - LastPlayed: number[]; - BorderWarningTime: number; - LevelName: string; - BorderSize: number; + DayTime: number[]; + initialized: number; + allowCommands: number; + SizeOnDisk: number[]; + GameRules: GameRules; + Player: Player; + SpawnY: number; + rainTime: number; + thunderTime: number; + SpawnZ: number; + hardcore: number; + SpawnX: number; + clearWeatherTime: number; + thundering: number; + generatorVersion?: number; + version: number; + BorderSafeZone: number; + generatorOptions?: string; + LastPlayed: number[]; + BorderWarningTime: number; + LevelName: string; + BorderSize: number; } export interface GameRules { - doTileDrops: string; - doFireTick: string; - reducedDebugInfo: string; + doTileDrops: string; + doFireTick: string; + reducedDebugInfo: string; naturalRegeneration: string; - doMobLoot: string; - keepInventory: string; - doEntityDrops: string; - mobGriefing: string; - randomTickSpeed: string; - commandBlockOutput: string; - doMobSpawning: string; - logAdminCommands: string; + doMobLoot: string; + keepInventory: string; + doEntityDrops: string; + mobGriefing: string; + randomTickSpeed: string; + commandBlockOutput: string; + doMobSpawning: string; + logAdminCommands: string; sendCommandFeedback: string; - doDaylightCycle: string; - showDeathMessages: string; + doDaylightCycle: string; + showDeathMessages: string; } export interface Player { - HurtByTimestamp: number; - SleepTimer: number; - Attributes: Attribute[]; - Invulnerable: number; - PortalCooldown: number; - AbsorptionAmount: number; - abilities: Abilities; - FallDistance: number; - DeathTime: number; - XpSeed: number; - HealF: number; - XpTotal: number; - playerGameType: number; - SelectedItem: SelectedItem; - Motion: number[]; - UUIDLeast: number[]; - Health: number; + HurtByTimestamp: number; + SleepTimer: number; + Attributes: Attribute[]; + Invulnerable: number; + PortalCooldown: number; + AbsorptionAmount: number; + abilities: Abilities; + FallDistance: number; + DeathTime: number; + XpSeed: number; + HealF: number; + XpTotal: number; + playerGameType: number; + SelectedItem: SelectedItem; + Motion: number[]; + UUIDLeast: number[]; + Health: number; foodSaturationLevel: number; - Air: number; - OnGround: number; - Dimension: number; - Rotation: number[]; - XpLevel: number; - Score: number; - UUIDMost: number[]; - Sleeping: number; - Pos: number[]; - Fire: number; - XpP: number; - EnderItems: any[]; - foodLevel: number; + Air: number; + OnGround: number; + Dimension: number; + Rotation: number[]; + XpLevel: number; + Score: number; + UUIDMost: number[]; + Sleeping: number; + Pos: number[]; + Fire: number; + XpP: number; + EnderItems: any[]; + foodLevel: number; foodExhaustionLevel: number; - HurtTime: number; - SelectedItemSlot: number; - Inventory: SelectedItem[]; - foodTickTimer: number; + HurtTime: number; + SelectedItemSlot: number; + Inventory: SelectedItem[]; + foodTickTimer: number; } export interface Attribute { @@ -111,55 +111,55 @@ export interface Attribute { } export interface SelectedItem { - Slot?: number; - id: string; - Count: number; + Slot?: number; + id: string; + Count: number; Damage: number; } export interface Abilities { invulnerable: number; - mayfly: number; - instabuild: number; - walkSpeed: number; - mayBuild: number; - flying: number; - flySpeed: number; + mayfly: number; + instabuild: number; + walkSpeed: number; + mayBuild: number; + flying: number; + flySpeed: number; } // 1.16+ export interface WorldGenSettings { /** 0,1 */ - bonus_chest: number; - seed: number[]; + bonus_chest: number; + seed: number[]; /** 0,1 */ generate_features: number; - dimensions: Dimensions; + dimensions: Dimensions; } export interface Dimensions { // :overworld, :the_nether, :the_end - [key: string]: WorldGen; + [key: string]: WorldGen; } export interface WorldGen { generator: WorldGenGenerator; // same as key - type: string; + type: string; } export interface WorldGenGenerator { - settings: string; - seed: number[]; + settings: string; + seed: number[]; biome_source: PurpleBiomeSource; - type: string; + type: string; } export interface PurpleBiomeSource { - seed: number[]; + seed: number[]; /** only for overworld 0,1 */ large_biomes?: number; // :noise, :flat, ? - type: string; + type: string; } diff --git a/src/microsoftAuthflow.ts b/src/microsoftAuthflow.ts new file mode 100644 index 00000000..d759a7dc --- /dev/null +++ b/src/microsoftAuthflow.ts @@ -0,0 +1,182 @@ +export const getProxyDetails = async (proxyBaseUrl: string) => { + 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`) + } + return result +} + +export default async ({ tokenCaches, proxyBaseUrl, setProgressText = (text) => { }, setCacheResult, connectingServer }) => { + let onMsaCodeCallback + let connectingVersion = '' + // const authEndpoint = 'http://localhost:3000/' + // const sessionEndpoint = 'http://localhost:3000/session' + let authEndpoint: URL | undefined + let sessionEndpoint: URL | undefined + const result = await getProxyDetails(proxyBaseUrl) + + try { + const json = await result.json() + authEndpoint = urlWithBase(json.capabilities.authEndpoint, proxyBaseUrl) + sessionEndpoint = urlWithBase(json.capabilities.sessionEndpoint, proxyBaseUrl) + if (!authEndpoint) throw new Error('No auth endpoint') + } catch (err) { + console.error(err) + throw new Error(`Selected proxy server ${proxyBaseUrl} does not support Microsoft authentication`) + } + const authFlow = { + async getMinecraftJavaToken () { + setProgressText('Authenticating with Microsoft account') + if (!window.crypto && !isPageSecure()) throw new Error('Crypto API is available only in secure contexts. Be sure to use https!') + let result = null + await fetch(authEndpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + ...tokenCaches, + // important to set this param and not fake it as auth server might reject the request otherwise + connectingServer, + connectingServerVersion: connectingVersion + }), + }) + .catch(e => { + throw new Error(`Failed to connect to auth server (network error): ${e.message}`) + }) + .then(async response => { + if (!response.ok) { + throw new Error(`Auth server error (${response.status}): ${await response.text()}`) + } + + const reader = response.body!.getReader() + const decoder = new TextDecoder('utf8') + + const processText = ({ done, value = undefined as Uint8Array | undefined }) => { + if (done) { + return + } + + const processChunk = (chunkStr) => { + let json: any + try { + json = JSON.parse(chunkStr) + } catch (err) {} + if (!json) return + if (json.user_code) { + onMsaCodeCallback(json) + // this.codeCallback(json) + } + if (json.error) throw new Error(`Auth server error: ${json.error}`) + if (json.token) result = json + if (json.newCache) setCacheResult(json.newCache) + } + + const strings = decoder.decode(value) + + for (const chunk of strings.split('\n\n')) { + processChunk(chunk) + } + + return reader.read().then(processText) + } + return reader.read().then(processText) + }) + const restoredData = await restoreData(result) + if (restoredData?.certificates?.profileKeys?.privatePEM) { + restoredData.certificates.profileKeys.private = restoredData.certificates.profileKeys.privatePEM + } + return restoredData + } + } + return { + authFlow, + sessionEndpoint, + setOnMsaCodeCallback (callback) { + onMsaCodeCallback = callback + }, + setConnectingVersion (version) { + connectingVersion = version + } + } +} + +function isPageSecure (url = window.location.href) { + return !url.startsWith('http:') +} + +// restore dates from strings +const restoreData = async (json) => { + const promises = [] as Array> + if (typeof json === 'object' && json) { + for (const [key, value] of Object.entries(json)) { + if (typeof value === 'string') { + promises.push(tryRestorePublicKey(value, key, json)) + if (value.endsWith('Z')) { + const date = new Date(value) + if (!isNaN(date.getTime())) { + json[key] = date + } + } + } + if (typeof value === 'object') { + // eslint-disable-next-line no-await-in-loop + await restoreData(value) + } + } + } + + await Promise.all(promises) + + return json +} + +const tryRestorePublicKey = async (value: string, name: string, parent: { [x: string]: any }) => { + value = value.trim() + if (!name.endsWith('PEM') || !value.startsWith('-----BEGIN RSA PUBLIC KEY-----') || !value.endsWith('-----END RSA PUBLIC KEY-----')) return + const der = pemToArrayBuffer(value) + const key = await window.crypto.subtle.importKey( + 'spki', // Specify that the data is in SPKI format + der, + { + name: 'RSA-OAEP', + hash: { name: 'SHA-256' } + }, + true, + ['encrypt'] // Specify key usages + ) + const originalName = name.replace('PEM', '') + const exported = await window.crypto.subtle.exportKey('spki', key) + const exportedBuffer = new Uint8Array(exported) + parent[originalName] = { + export () { + return exportedBuffer + } + } +} + +function pemToArrayBuffer (pem) { + // Fetch the part of the PEM string between header and footer + const pemHeader = '-----BEGIN RSA PUBLIC KEY-----' + const pemFooter = '-----END RSA PUBLIC KEY-----' + const pemContents = pem.slice(pemHeader.length, pem.length - pemFooter.length).trim() + const binaryDerString = atob(pemContents.replaceAll(/\s/g, '')) + const binaryDer = new Uint8Array(binaryDerString.length) + for (let i = 0; i < binaryDerString.length; i++) { + binaryDer[i] = binaryDerString.codePointAt(i)! + } + return binaryDer.buffer +} + +const urlWithBase = (url: string, base: string) => { + const defaultBase = isPageSecure() ? 'https' : 'http' + if (!base.startsWith('http')) base = `${defaultBase}://${base}` + const urlObj = new URL(url, base) + base = base.replace(/^https?:\/\//, '') + urlObj.host = base.includes(':') ? base : `${base}:${isPageSecure(base) ? '443' : '80'}` + return urlObj +} diff --git a/src/mineflayer/cameraShake.ts b/src/mineflayer/cameraShake.ts new file mode 100644 index 00000000..9e271da5 --- /dev/null +++ b/src/mineflayer/cameraShake.ts @@ -0,0 +1,25 @@ +import { getThreeJsRendererMethods } from 'renderer/viewer/three/threeJsMethods' + +customEvents.on('mineflayerBotCreated', () => { + customEvents.on('hurtAnimation', (yaw) => { + getThreeJsRendererMethods()?.shakeFromDamage() + }) + + bot._client.on('hurt_animation', ({ entityId, yaw }) => { + if (entityId === bot.entity.id) { + customEvents.emit('hurtAnimation', yaw) + } + }) + bot.on('entityHurt', ({ id }) => { + if (id === bot.entity.id) { + customEvents.emit('hurtAnimation') + } + }) + let { health } = bot + bot.on('health', () => { + if (bot.health < health) { + customEvents.emit('hurtAnimation') + } + health = bot.health + }) +}) diff --git a/src/mineflayer/entityStatus.ts b/src/mineflayer/entityStatus.ts new file mode 100644 index 00000000..e13784bc --- /dev/null +++ b/src/mineflayer/entityStatus.ts @@ -0,0 +1,70 @@ +export const EntityStatus = { + JUMP: 1, + HURT: 2, // legacy + DEATH: 3, + START_ATTACKING: 4, + STOP_ATTACKING: 5, + TAMING_FAILED: 6, + TAMING_SUCCEEDED: 7, + SHAKE_WETNESS: 8, + USE_ITEM_COMPLETE: 9, + EAT_GRASS: 10, + OFFER_FLOWER: 11, + LOVE_HEARTS: 12, + VILLAGER_ANGRY: 13, + VILLAGER_HAPPY: 14, + WITCH_HAT_MAGIC: 15, + ZOMBIE_CONVERTING: 16, + FIREWORKS_EXPLODE: 17, + IN_LOVE_HEARTS: 18, + SQUID_ANIM_SYNCH: 19, + SILVERFISH_MERGE_ANIM: 20, + GUARDIAN_ATTACK_SOUND: 21, + REDUCED_DEBUG_INFO: 22, + FULL_DEBUG_INFO: 23, + PERMISSION_LEVEL_ALL: 24, + PERMISSION_LEVEL_MODERATORS: 25, + PERMISSION_LEVEL_GAMEMASTERS: 26, + PERMISSION_LEVEL_ADMINS: 27, + PERMISSION_LEVEL_OWNERS: 28, + ATTACK_BLOCKED: 29, + SHIELD_DISABLED: 30, + FISHING_ROD_REEL_IN: 31, + ARMORSTAND_WOBBLE: 32, + THORNED: 33, // legacy + STOP_OFFER_FLOWER: 34, + TALISMAN_ACTIVATE: 35, // legacy + DROWNED: 36, // legacy + BURNED: 37, // legacy + DOLPHIN_LOOKING_FOR_TREASURE: 38, + RAVAGER_STUNNED: 39, + TRUSTING_FAILED: 40, + TRUSTING_SUCCEEDED: 41, + VILLAGER_SWEAT: 42, + BAD_OMEN_TRIGGERED: 43, // legacy + POKED: 44, // legacy + FOX_EAT: 45, + TELEPORT: 46, + MAINHAND_BREAK: 47, + OFFHAND_BREAK: 48, + HEAD_BREAK: 49, + CHEST_BREAK: 50, + LEGS_BREAK: 51, + FEET_BREAK: 52, + HONEY_SLIDE: 53, + HONEY_JUMP: 54, + SWAP_HANDS: 55, + CANCEL_SHAKE_WETNESS: 56, + FROZEN: 57, // legacy + START_RAM: 58, + END_RAM: 59, + POOF: 60, + TENDRILS_SHIVER: 61, + SONIC_CHARGE: 62, + SNIFFER_DIGGING_SOUND: 63, + ARMADILLO_PEEK: 64, + BODY_BREAK: 65, + SHAKE: 66 +} as const + +export type EntityStatusName = keyof typeof EntityStatus diff --git a/src/mineflayer/items.ts b/src/mineflayer/items.ts new file mode 100644 index 00000000..48d0dfe0 --- /dev/null +++ b/src/mineflayer/items.ts @@ -0,0 +1,139 @@ +import mojangson from 'mojangson' +import nbt from 'prismarine-nbt' +import { fromFormattedString } from '@xmcl/text-component' +import { getItemSelector, ItemSpecificContextProperties, PlayerStateRenderer } from 'renderer/viewer/lib/basePlayerState' +import { getItemDefinition } from 'mc-assets/dist/itemDefinitions' +import { MessageFormatPart } from '../chatUtils' +import { ResourcesManager, ResourcesManagerCommon, ResourcesManagerTransferred } from '../resourcesManager' + +type RenderSlotComponent = { + type: string, + data: any + // example + // { + // "type": "item_model", + // "data": "aa:ss" + // } +} +export type RenderItem = Pick & { + components?: RenderSlotComponent[], + // componentMap?: Map +} +export type GeneralInputItem = Pick & { + components?: RenderSlotComponent[], + displayName?: string + modelResolved?: boolean +} + +type JsonString = string +type PossibleItemProps = { + CustomModelData?: number + Damage?: number + display?: { Name?: JsonString } // {"text":"Knife","color":"white","italic":"true"} +} + +export const getItemMetadata = (item: GeneralInputItem, resourcesManager: ResourcesManagerCommon) => { + let customText = undefined as string | any | undefined + let customModel = undefined as string | undefined + + let itemId = item.name + if (!itemId.includes(':')) { + itemId = `minecraft:${itemId}` + } + const customModelDataDefinitions = resourcesManager.currentResources?.customItemModelNames[itemId] + + if (item.components) { + const componentMap = new Map() + for (const component of item.components) { + componentMap.set(component.type, component) + } + + const customTextComponent = componentMap.get('custom_name') || componentMap.get('item_name') + if (customTextComponent) { + customText = typeof customTextComponent.data === 'string' ? customTextComponent.data : nbt.simplify(customTextComponent.data) + } + const customModelComponent = componentMap.get('item_model') + if (customModelComponent) { + customModel = customModelComponent.data + } + if (customModelDataDefinitions) { + const customModelDataComponent: any = componentMap.get('custom_model_data') + if (customModelDataComponent?.data) { + let customModelData: number | undefined + if (typeof customModelDataComponent.data === 'number') { + customModelData = customModelDataComponent.data + } else if (typeof customModelDataComponent.data === 'object' + && 'floats' in customModelDataComponent.data + && Array.isArray(customModelDataComponent.data.floats) + && customModelDataComponent.data.floats.length > 0) { + customModelData = customModelDataComponent.data.floats[0] + } + if (customModelData && customModelDataDefinitions[customModelData]) { + customModel = customModelDataDefinitions[customModelData] + } + } + } + const loreComponent = componentMap.get('lore') + if (loreComponent) { + customText ??= item.displayName ?? item.name + // todo test + customText += `\n${JSON.stringify(loreComponent.data)}` + } + } + if (item.nbt) { + const itemNbt: PossibleItemProps = nbt.simplify(item.nbt) + const customName = itemNbt.display?.Name + if (customName) { + customText = customName + } + if (customModelDataDefinitions && itemNbt.CustomModelData && customModelDataDefinitions[itemNbt.CustomModelData]) { + customModel = customModelDataDefinitions[itemNbt.CustomModelData] + } + } + + return { + customText, + customModel + } +} + + +export const getItemNameRaw = (item: Pick | null, resourcesManager: ResourcesManagerCommon) => { + if (!item) return '' + const { customText } = getItemMetadata(item as GeneralInputItem, resourcesManager) + if (!customText) return + try { + if (typeof customText === 'object') { + return customText + } + const parsed = customText.startsWith('{') && customText.endsWith('}') ? mojangson.simplify(mojangson.parse(customText)) : fromFormattedString(customText) + if (parsed.extra) { + return parsed as Record + } else { + return parsed as MessageFormatPart + } + } catch (err) { + return { + text: JSON.stringify(customText) + } + } +} + +export const getItemModelName = (item: GeneralInputItem, specificProps: ItemSpecificContextProperties, resourcesManager: ResourcesManagerCommon, playerState: PlayerStateRenderer) => { + let itemModelName = item.name + const { customModel } = getItemMetadata(item, resourcesManager) + if (customModel) { + itemModelName = customModel + } + + const itemSelector = getItemSelector(playerState, { + ...specificProps + }) + const modelFromDef = getItemDefinition(appViewer.resourcesManager.itemsDefinitionsStore, { + name: itemModelName, + version: appViewer.resourcesManager.currentResources!.version, + properties: itemSelector + })?.model + const model = (modelFromDef === 'minecraft:special' ? undefined : modelFromDef) ?? itemModelName + return model +} diff --git a/src/mineflayer/java-tester/commands.ts b/src/mineflayer/java-tester/commands.ts new file mode 100644 index 00000000..1925c4d7 --- /dev/null +++ b/src/mineflayer/java-tester/commands.ts @@ -0,0 +1,68 @@ +import { versionToNumber } from 'flying-squid/dist/utils' + +const customStickNbt = (tags: Record) => { + let cmd = '/give @p stick' + const wrapIntoQuotes = versionToNumber(bot.version) < versionToNumber('1.21.5') + cmd += `[${Object.entries(tags).map(([key, value]) => { + if (typeof value === 'object') { + value = JSON.stringify(value) + } + return `${key}=${wrapIntoQuotes ? `'${value}'` : value}` + }).join(',')}]` + return cmd +} + +const writeCmd = (cmd: string) => { + if (!cmd.startsWith('/')) cmd = `/${cmd}` + console.log('Executing', cmd) + bot.chat(cmd) +} + +let msg = 0 +const LIMIT_MSG = 100 +export const javaServerTester = { + itemCustomLore () { + const cmd = customStickNbt({ + lore: [{ text: 'This Stick is very sticky.' }] + }) + writeCmd(cmd) + }, + + itemCustomModel () { + const cmd = customStickNbt({ + item_model: 'minecraft:diamond' + }) + writeCmd(cmd) + }, + itemCustomModel2 () { + const cmd = customStickNbt({ + item_model: 'diamond' + }) + writeCmd(cmd) + }, + + itemCustomName () { + const cmd = customStickNbt({ + custom_name: [{ text: 'diamond' }] + }) + writeCmd(cmd) + }, + itemCustomName2 () { + const cmd = customStickNbt({ + custom_name: [{ translate: 'item.diamond.name' }] + }) + writeCmd(cmd) + }, + + spamChat () { + for (let i = msg; i < msg + LIMIT_MSG; i++) { + bot.chat('Hello, world, ' + i) + } + msg += LIMIT_MSG + }, + spamChatComplexMessage () { + for (let i = msg; i < msg + LIMIT_MSG; i++) { + bot.chat('/tell @a ' + i) + } + } +} diff --git a/src/mineflayer/java-tester/index.ts b/src/mineflayer/java-tester/index.ts new file mode 100644 index 00000000..d395b8f3 --- /dev/null +++ b/src/mineflayer/java-tester/index.ts @@ -0,0 +1,6 @@ +import { javaServerTester } from './commands' + +window.javaServerTester = javaServerTester +customEvents.on('mineflayerBotCreated', () => { + // +}) diff --git a/src/mineflayer/maps.ts b/src/mineflayer/maps.ts new file mode 100644 index 00000000..5e968205 --- /dev/null +++ b/src/mineflayer/maps.ts @@ -0,0 +1,24 @@ +import { mapDownloader } from 'mineflayer-item-map-downloader' +import { setImageConverter } from 'mineflayer-item-map-downloader/lib/util' +import { getThreeJsRendererMethods } from 'renderer/viewer/three/threeJsMethods' + +setImageConverter((buf: Uint8Array) => { + const canvas = document.createElement('canvas') + const ctx = canvas.getContext('2d')! + canvas.width = 128 + canvas.height = 128 + const imageData = ctx.createImageData(canvas.width, canvas.height) + imageData.data.set(buf) + ctx.putImageData(imageData, 0, 0) + // data url + return canvas.toDataURL('image/png') +}) + +customEvents.on('mineflayerBotCreated', () => { + bot.on('login', () => { + bot.loadPlugin(mapDownloader) + bot.mapDownloader.on('new_map', ({ png, id }) => { + getThreeJsRendererMethods()?.updateMap(id, png) + }) + }) +}) diff --git a/src/mineflayer/mc-protocol.ts b/src/mineflayer/mc-protocol.ts new file mode 100644 index 00000000..cd21d01f --- /dev/null +++ b/src/mineflayer/mc-protocol.ts @@ -0,0 +1,139 @@ +import net from 'net' +import { Client } from 'minecraft-protocol' +import { appQueryParams } from '../appParams' +import { downloadAllMinecraftData, getVersionAutoSelect } from '../connect' +import { gameAdditionalState } from '../globalState' +import { ProgressReporter } from '../core/progressReporter' +import { parseServerAddress } from '../parseServerAddress' +import { getCurrentProxy } from '../react/ServersList' +import { pingServerVersion, validatePacket } from './minecraft-protocol-extra' +import { getWebsocketStream } from './websocket-core' + +let lastPacketTime = 0 +customEvents.on('mineflayerBotCreated', () => { + // const oldParsePacketBuffer = bot._client.deserializer.parsePacketBuffer + // try { + // const parsed = oldParsePacketBuffer(buffer) + // } catch (err) { + // debugger + // reportError(new Error(`Error parsing packet ${buffer.subarray(0, 30).toString('hex')}`, { cause: err })) + // throw err + // } + // } + class MinecraftProtocolError extends Error { + constructor (message: string, cause?: Error, public data?: any) { + if (data?.customPayload) { + message += ` (Custom payload: ${data.customPayload.channel})` + } + super(message, { cause }) + this.name = 'MinecraftProtocolError' + } + } + + const onClientError = (err, data) => { + const error = new MinecraftProtocolError(`Minecraft protocol client error: ${err.message}`, err, data) + reportError(error) + } + if (typeof bot._client['_events'].error === 'function') { + // dont report to bot for more explicit error + bot._client['_events'].error = onClientError + } else { + bot._client.on('error' as any, onClientError) + } + + // todo move more code here + if (!appQueryParams.noPacketsValidation) { + (bot._client as unknown as Client).on('packet', (data, packetMeta, buffer, fullBuffer) => { + validatePacket(packetMeta.name, data, fullBuffer, true) + lastPacketTime = performance.now() + }); + (bot._client as unknown as Client).on('writePacket', (name, params) => { + validatePacket(name, params, Buffer.alloc(0), false) + }) + } +}) + +setInterval(() => { + if (!bot || !lastPacketTime) return + if (bot.player?.ping > 500) { // TODO: we cant rely on server ping 1. weird calculations 2. available with delays instead patch minecraft-protocol to get latency of keep_alive packet + gameAdditionalState.poorConnection = true + } else { + gameAdditionalState.poorConnection = false + } + if (performance.now() - lastPacketTime < 2000) { + gameAdditionalState.noConnection = false + return + } + gameAdditionalState.noConnection = true +}, 1000) + + +export const getServerInfo = async (ip: string, port?: number, preferredVersion = getVersionAutoSelect(), ping = false, progressReporter?: ProgressReporter, setProxyParams?: ProxyParams) => { + await downloadAllMinecraftData() + const isWebSocket = ip.startsWith('ws://') || ip.startsWith('wss://') + let stream + if (isWebSocket) { + progressReporter?.setMessage('Connecting to WebSocket server') + stream = (await getWebsocketStream(ip)).mineflayerStream + progressReporter?.setMessage('WebSocket connected. Ping packet sent, waiting for response') + } else if (setProxyParams) { + setProxy(setProxyParams) + } + window.setLoadingMessage = (message?: string) => { + if (message === undefined) { + progressReporter?.endStage('dns') + } else { + progressReporter?.beginStage('dns', message) + } + } + return pingServerVersion(ip, port, { + ...(stream ? { stream } : {}), + ...(ping ? { noPongTimeout: 3000 } : {}), + ...(preferredVersion ? { version: preferredVersion } : {}), + }).finally(() => { + window.setLoadingMessage = undefined + }) +} + +globalThis.debugTestPing = async (ip: string) => { + const parsed = parseServerAddress(ip, false) + const result = await getServerInfo(parsed.host, parsed.port ? Number(parsed.port) : undefined, undefined, true, undefined, { address: getCurrentProxy(), }) + console.log('result', result) + return result +} + +export const getDefaultProxyParams = () => { + return { + headers: { + Authorization: `Bearer ${new URLSearchParams(location.search).get('token') ?? ''}` + } + } +} + +export type ProxyParams = { + address?: string + headers?: Record +} + +export const setProxy = (proxyParams: ProxyParams) => { + if (proxyParams.address?.startsWith(':')) { + proxyParams.address = `${location.protocol}//${location.hostname}${proxyParams.address}` + } + if (proxyParams.address && location.port !== '80' && location.port !== '443' && !/:\d+$/.test(proxyParams.address)) { + const https = proxyParams.address.startsWith('https://') || location.protocol === 'https:' + proxyParams.address = `${proxyParams.address}:${https ? 443 : 80}` + } + + const parsedProxy = parseServerAddress(proxyParams.address, false) + const proxy = { host: parsedProxy.host, port: parsedProxy.port } + proxyParams.headers ??= getDefaultProxyParams().headers + net['setProxy']({ + hostname: proxy.host, + port: proxy.port, + headers: proxyParams.headers, + artificialDelay: appQueryParams.addPing ? Number(appQueryParams.addPing) : undefined + }) + return { + proxy + } +} diff --git a/src/mineflayer/minecraft-protocol-extra.ts b/src/mineflayer/minecraft-protocol-extra.ts new file mode 100644 index 00000000..65260979 --- /dev/null +++ b/src/mineflayer/minecraft-protocol-extra.ts @@ -0,0 +1,119 @@ +import EventEmitter from 'events' +import clientAutoVersion from 'minecraft-protocol/src/client/autoVersion' + +export const pingServerVersion = async (ip: string, port?: number, mergeOptions: Record = {}) => { + const fakeClient = new EventEmitter() as any + const options = { + host: ip, + port, + noPongTimeout: 10_000, + closeTimeout: 20_000, + ...mergeOptions, + } + let latency = 0 + let fullInfo: any = null + fakeClient.autoVersionHooks = [(res) => { + latency = res.latency + fullInfo = res + }] + + // TODO use client.socket.destroy() instead of client.end() for faster cleanup + clientAutoVersion(fakeClient, options) + await Promise.race([ + new Promise((resolve, reject) => { + fakeClient.once('connect_allowed', () => { + resolve() + }) + }), + new Promise((resolve, reject) => { + fakeClient.on('error', (err) => { + reject(new Error(err.message ?? err)) + }) + if (mergeOptions.stream) { + mergeOptions.stream.on('end', (err) => { + setTimeout(() => { + reject(new Error('Connection closed. Please report if you see this but the server is actually fine.')) + }) + }) + } + }) + ]) + + return { + version: fakeClient.version, + latency, + fullInfo, + } +} + +const MAX_PACKET_SIZE = 2_097_152 // 2mb +const CHAT_MAX_PACKET_DEPTH = 200 // todo improve perf + +const CHAT_VALIDATE_PACKETS = new Set([ + 'chat', + 'system_chat', + 'player_chat', + 'profileless_chat', + 'kick_disconnect', + 'resource_pack_send', + 'action_bar', + 'set_title_text', + 'set_title_subtitle', + 'title', + 'death_combat_event', + 'server_data', + 'scoreboard_objective', + 'scoreboard_team', + 'playerlist_header', + 'boss_bar' +]) + +export const validatePacket = (name: string, data: any, fullBuffer: Buffer, isFromServer: boolean) => { + // todo find out why chat is so slow with react + if (!isFromServer) return + + if (fullBuffer.length > MAX_PACKET_SIZE) { + console.groupCollapsed(`Packet ${name} is too large: ${fullBuffer.length} bytes`) + console.log(data) + console.groupEnd() + throw new Error(`Packet ${name} is too large: ${fullBuffer.length} bytes`) + } + + if (CHAT_VALIDATE_PACKETS.has(name)) { + // todo count total number of objects instead of max depth + const maxDepth = getObjectMaxDepth(data) + if (maxDepth > CHAT_MAX_PACKET_DEPTH) { + console.groupCollapsed(`Packet ${name} have too many nested objects: ${maxDepth}`) + console.log(data) + console.groupEnd() + throw new Error(`Packet ${name} have too many nested objects: ${maxDepth}`) + } + } +} + +function getObjectMaxDepth (obj: unknown, currentDepth = 0): number { + // Base case: null or primitive types have depth 0 + if (obj === null || typeof obj !== 'object' || obj instanceof Buffer) { + return currentDepth + } + + // Handle arrays and objects + let maxDepth = currentDepth + + if (Array.isArray(obj)) { + // For arrays, check each element + for (const item of obj) { + const depth = getObjectMaxDepth(item, currentDepth + 1) + maxDepth = Math.max(maxDepth, depth) + } + } else { + // For objects, check each value + // eslint-disable-next-line guard-for-in + for (const key in obj) { + const depth = getObjectMaxDepth(obj[key], currentDepth + 1) + maxDepth = Math.max(maxDepth, depth) + } + } + + return maxDepth +} diff --git a/src/mineflayer/playerState.ts b/src/mineflayer/playerState.ts new file mode 100644 index 00000000..33f7af77 --- /dev/null +++ b/src/mineflayer/playerState.ts @@ -0,0 +1,200 @@ +import { HandItemBlock } from 'renderer/viewer/three/holdingBlock' +import { getInitialPlayerState, getPlayerStateUtils, PlayerStateReactive, PlayerStateRenderer, PlayerStateUtils } from 'renderer/viewer/lib/basePlayerState' +import { subscribe } from 'valtio' +import { subscribeKey } from 'valtio/utils' +import { gameAdditionalState } from '../globalState' +import { options } from '../optionsStorage' + +/** + * can be used only in main thread. Mainly for more convenient reactive state updates. + * In renderer/ directory, use PlayerStateControllerRenderer type or worldRenderer.playerState. + */ +export class PlayerStateControllerMain { + disableStateUpdates = false + + private timeOffGround = 0 + private lastUpdateTime = performance.now() + + // Held item state + private isUsingItem = false + ready = false + + reactive: PlayerStateReactive + utils: PlayerStateUtils + + constructor () { + customEvents.on('mineflayerBotCreated', () => { + this.ready = false + bot.on('inject_allowed', () => { + if (this.ready) return + this.ready = true + this.botCreated() + }) + bot.on('end', () => { + this.ready = false + }) + }) + } + + private onBotCreatedOrGameJoined () { + this.reactive.username = bot.username ?? '' + } + + private botCreated () { + console.log('bot created & plugins injected') + this.reactive = getInitialPlayerState() + this.reactive.perspective = options.defaultPerspective + this.utils = getPlayerStateUtils(this.reactive) + this.onBotCreatedOrGameJoined() + + const handleDimensionData = (data) => { + let hasSkyLight = 1 + try { + hasSkyLight = data.dimension.value.has_skylight.value + } catch {} + this.reactive.lightingDisabled = bot.game.dimension === 'the_nether' || bot.game.dimension === 'the_end' || !hasSkyLight + } + + bot._client.on('login', (packet) => { + handleDimensionData(packet) + }) + bot._client.on('respawn', (packet) => { + handleDimensionData(packet) + }) + + // Movement tracking + bot.on('move', () => { + this.updateMovementState() + }) + + // Item tracking + bot.on('heldItemChanged', () => { + return this.updateHeldItem(false) + }) + bot.inventory.on('updateSlot', (index) => { + if (index === 45) this.updateHeldItem(true) + }) + const updateSneakingOrFlying = () => { + this.updateMovementState() + this.reactive.sneaking = bot.controlState.sneak + this.reactive.flying = gameAdditionalState.isFlying + this.reactive.eyeHeight = bot.controlState.sneak && !gameAdditionalState.isFlying ? 1.27 : 1.62 + } + bot.on('physicsTick', () => { + if (this.isUsingItem) this.reactive.itemUsageTicks++ + updateSneakingOrFlying() + }) + // todo move from gameAdditionalState to reactive directly + subscribeKey(gameAdditionalState, 'isSneaking', () => { + updateSneakingOrFlying() + }) + subscribeKey(gameAdditionalState, 'isFlying', () => { + updateSneakingOrFlying() + }) + + // Initial held items setup + this.updateHeldItem(false) + this.updateHeldItem(true) + + bot.on('game', () => { + this.reactive.gameMode = bot.game.gameMode + }) + this.reactive.gameMode = bot.game?.gameMode + + customEvents.on('gameLoaded', () => { + this.reactive.team = bot.teamMap[bot.username] + }) + + this.watchReactive() + } + + // #region Movement and Physics State + private updateMovementState () { + if (!bot?.entity || this.disableStateUpdates) return + + const { velocity } = bot.entity + const isOnGround = bot.entity.onGround + const VELOCITY_THRESHOLD = 0.01 + const SPRINTING_VELOCITY = 0.15 + const OFF_GROUND_THRESHOLD = 0 // ms before switching to SNEAKING when off ground + + const now = performance.now() + const deltaTime = now - this.lastUpdateTime + this.lastUpdateTime = now + + // this.lastVelocity = velocity + + // Update time off ground + if (isOnGround) { + this.timeOffGround = 0 + } else { + this.timeOffGround += deltaTime + } + + if (gameAdditionalState.isSneaking || gameAdditionalState.isFlying || (this.timeOffGround > OFF_GROUND_THRESHOLD)) { + this.reactive.movementState = 'SNEAKING' + } else if (Math.abs(velocity.x) > VELOCITY_THRESHOLD || Math.abs(velocity.z) > VELOCITY_THRESHOLD) { + this.reactive.movementState = Math.abs(velocity.x) > SPRINTING_VELOCITY || Math.abs(velocity.z) > SPRINTING_VELOCITY + ? 'SPRINTING' + : 'WALKING' + } else { + this.reactive.movementState = 'NOT_MOVING' + } + } + + // #region Held Item State + private updateHeldItem (isLeftHand: boolean) { + const newItem = isLeftHand ? bot.inventory.slots[45] : bot.heldItem + if (!newItem) { + if (isLeftHand) { + this.reactive.heldItemOff = undefined + } else { + this.reactive.heldItemMain = undefined + } + return + } + + const block = loadedData.blocksByName[newItem.name] + const blockProperties = block ? new window.PrismarineBlock(block.id, 'void', newItem.metadata).getProperties() : {} + const item: HandItemBlock = { + name: newItem.name, + properties: blockProperties, + id: newItem.type, + type: block ? 'block' : 'item', + fullItem: newItem, + } + + if (isLeftHand) { + this.reactive.heldItemOff = item + } else { + this.reactive.heldItemMain = item + } + // this.events.emit('heldItemChanged', item, isLeftHand) + } + + startUsingItem () { + if (this.isUsingItem) return + this.isUsingItem = true + this.reactive.itemUsageTicks = 0 + } + + stopUsingItem () { + this.isUsingItem = false + this.reactive.itemUsageTicks = 0 + } + + getItemUsageTicks (): number { + return this.reactive.itemUsageTicks + } + + watchReactive () { + subscribeKey(this.reactive, 'eyeHeight', () => { + appViewer.backend?.updateCamera(bot.entity.position, bot.entity.yaw, bot.entity.pitch) + }) + } + + // #endregion +} + +export const playerState = new PlayerStateControllerMain() +window.playerState = playerState diff --git a/src/mineflayer/plugins/index.ts b/src/mineflayer/plugins/index.ts new file mode 100644 index 00000000..6ac11376 --- /dev/null +++ b/src/mineflayer/plugins/index.ts @@ -0,0 +1,21 @@ +import { lastConnectOptions } from '../../react/AppStatusProvider' +import mouse from './mouse' +import packetsPatcher from './packetsPatcher' +import { localRelayServerPlugin } from './packetsRecording' +import ping from './ping' +import webFeatures from './webFeatures' + +// register +webFeatures() +packetsPatcher() + + +customEvents.on('mineflayerBotCreated', () => { + if (lastConnectOptions.value!.server) { + bot.loadPlugin(ping) + } + bot.loadPlugin(mouse) + if (!lastConnectOptions.value!.worldStateFileContents) { + bot.loadPlugin(localRelayServerPlugin) + } +}) diff --git a/src/mineflayer/plugins/mouse.ts b/src/mineflayer/plugins/mouse.ts new file mode 100644 index 00000000..14e19345 --- /dev/null +++ b/src/mineflayer/plugins/mouse.ts @@ -0,0 +1,122 @@ +import { createMouse } from 'mineflayer-mouse' +import { Bot } from 'mineflayer' +import { Block } from 'prismarine-block' +import { getThreeJsRendererMethods } from 'renderer/viewer/three/threeJsMethods' +import { isGameActive, showModal } from '../../globalState' + +import { isCypress } from '../../standaloneUtils' +import { playerState } from '../playerState' +import { sendVideoInteraction, videoCursorInteraction } from '../../customChannels' + +function cursorBlockDisplay (bot: Bot) { + const updateCursorBlock = (data?: { block: Block }) => { + if (!data?.block || bot.game.gameMode === 'spectator') { + playerState.reactive.lookingAtBlock = undefined + return + } + + const { block } = data + playerState.reactive.lookingAtBlock = { + x: block.position.x, + y: block.position.y, + z: block.position.z, + shapes: bot.mouse.getBlockCursorShapes(block).map(shape => { + return bot.mouse.getDataFromShape(shape) + }) + } + } + + bot.on('highlightCursorBlock', updateCursorBlock) + bot.on('game', () => { + const block = bot.mouse.getCursorState().cursorBlock + updateCursorBlock(block ? { block } : undefined) + }) + + bot.on('blockBreakProgressStage', (block, stage) => { + const mergedShape = bot.mouse.getMergedCursorShape(block) + playerState.reactive.diggingBlock = stage === null ? undefined : { + x: block.position.x, + y: block.position.y, + z: block.position.z, + stage, + mergedShape: mergedShape ? bot.mouse.getDataFromShape(mergedShape) : undefined + } + }) +} + +export default (bot: Bot) => { + bot.loadPlugin(createMouse({})) + + domListeners(bot) + cursorBlockDisplay(bot) + + otherListeners() +} + +const otherListeners = () => { + bot.on('startDigging', (block) => { + customEvents.emit('digStart') + }) + + bot.on('goingToSleep', () => { + showModal({ reactType: 'bed' }) + }) + + bot.on('botArmSwingStart', (hand) => { + getThreeJsRendererMethods()?.changeHandSwingingState(true, hand === 'left') + }) + + bot.on('botArmSwingEnd', (hand) => { + getThreeJsRendererMethods()?.changeHandSwingingState(false, hand === 'left') + }) + + bot.on('startUsingItem', (item, slot, isOffhand, duration) => { + customEvents.emit('activateItem', item, isOffhand ? 45 : bot.quickBarSlot, isOffhand) + playerState.startUsingItem() + }) + + bot.on('stopUsingItem', () => { + playerState.stopUsingItem() + }) +} + +const domListeners = (bot: Bot) => { + const abortController = new AbortController() + document.addEventListener('mousedown', (e) => { + if (e.isTrusted && !document.pointerLockElement && !isCypress()) return + if (!isGameActive(true)) return + + getThreeJsRendererMethods()?.onPageInteraction() + + const videoInteraction = videoCursorInteraction() + if (videoInteraction) { + sendVideoInteraction(videoInteraction.id, videoInteraction.x, videoInteraction.y, e.button === 0) + return + } + + if (e.button === 0) { + bot.leftClickStart() + } else if (e.button === 2) { + bot.rightClickStart() + } + }, { signal: abortController.signal }) + + document.addEventListener('mouseup', (e) => { + if (e.button === 0) { + bot.leftClickEnd() + } else if (e.button === 2) { + bot.rightClickEnd() + } + }, { signal: abortController.signal }) + + bot.mouse.beforeUpdateChecks = () => { + if (!document.hasFocus() || !isGameActive(true)) { + // deactive all buttons + bot.mouse.buttons.fill(false) + } + } + + bot.on('end', () => { + abortController.abort() + }) +} diff --git a/src/mineflayer/plugins/packetsPatcher.ts b/src/mineflayer/plugins/packetsPatcher.ts new file mode 100644 index 00000000..5e93ef60 --- /dev/null +++ b/src/mineflayer/plugins/packetsPatcher.ts @@ -0,0 +1,50 @@ +export default () => { + // not plugin so its loaded earlier + customEvents.on('mineflayerBotCreated', () => { + botInit() + }) +} + +const waitingPackets = {} as Record> + +const botInit = () => { + // PATCH READING + 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) + } + } + }) + + // PATCH WRITING + + const clientWrite = bot._client.write.bind(bot._client) + const sendAllPackets = (name: string, data: any) => { + for (const packet of waitingPackets[name]) { + clientWrite(packet.name, packet.data) + } + delete waitingPackets[name] + } + + //@ts-expect-error + bot._client.write = (name: string, data: any) => { + // if (name === 'position' || name === 'position_look' || name === 'look' || name === 'teleport_confirm') { + // const chunkX = Math.floor(bot.entity.position.x / 16) + // const chunkZ = Math.floor(bot.entity.position.z / 16) + // const loadedColumns = bot.world.getColumns() + // if (loadedColumns.some((c) => c.chunkX === chunkX && c.chunkZ === chunkZ)) { + // sendAllPackets('position', data) + // } else { + // waitingPackets['position'] = [...(waitingPackets['position'] || []), { name, data }] + // return + // } + // } + if (name === 'settings') { + data['viewDistance'] = Math.max(data['viewDistance'], 3) + } + return clientWrite(name, data) + } + + // PATCH INTERACTIONS +} diff --git a/src/mineflayer/plugins/packetsRecording.ts b/src/mineflayer/plugins/packetsRecording.ts new file mode 100644 index 00000000..b9ba028c --- /dev/null +++ b/src/mineflayer/plugins/packetsRecording.ts @@ -0,0 +1,147 @@ +import { viewerConnector } from 'mcraft-fun-mineflayer' +import { PACKETS_REPLAY_FILE_EXTENSION, WORLD_STATE_FILE_EXTENSION } from 'mcraft-fun-mineflayer/build/worldState' +import { Bot } from 'mineflayer' +import CircularBuffer from 'flying-squid/dist/circularBuffer' +import { PacketsLogger } from 'mcraft-fun-mineflayer/build/packetsLogger' +import { subscribe } from 'valtio' +import { lastConnectOptions } from '../../react/AppStatusProvider' +import { packetsRecordingState } from '../../packetsReplay/packetsReplayLegacy' +import { packetsReplayState } from '../../react/state/packetsReplayState' + +const AUTO_CAPTURE_PACKETS_COUNT = 30 +let circularBuffer: CircularBuffer | undefined +let lastConnectVersion = '' + +export const localRelayServerPlugin = (bot: Bot) => { + lastConnectVersion = bot.version + let ended = false + bot.on('end', () => { + ended = true + }) + + bot.loadPlugin( + viewerConnector({ + tcpEnabled: false, + websocketEnabled: false, + }) + ) + + const downloadFile = (contents: string, filename: string) => { + const a = document.createElement('a') + const blob = new Blob([contents], { type: 'text/plain' }) + const url = URL.createObjectURL(blob) + a.href = url + a.download = filename + a.click() + URL.revokeObjectURL(url) + } + + bot.downloadCurrentWorldState = () => { + const worldState = bot.webViewer._unstable.createStateCaptureFile() + // add readable timestamp to filename + const timestamp = new Date().toISOString().replaceAll(/[-:Z]/g, '') + downloadFile(worldState.contents, `${bot.username}-world-state-${timestamp}.${WORLD_STATE_FILE_EXTENSION}`) + } + + let logger: PacketsLogger | undefined + bot.startPacketsRecording = () => { + bot.webViewer._unstable.startRecording((l) => { + logger = l + }) + } + + bot.stopPacketsRecording = () => { + if (!logger) return + const packets = logger?.contents + logger = undefined + const timestamp = new Date().toISOString().replaceAll(/[-:Z]/g, '') + downloadFile(packets, `${bot.username}-packets-${timestamp}.${PACKETS_REPLAY_FILE_EXTENSION}`) + bot.webViewer._unstable.stopRecording() + } + + circularBuffer = new CircularBuffer(AUTO_CAPTURE_PACKETS_COUNT) + let position = 0 + bot._client.on('writePacket' as any, (name, params) => { + circularBuffer!.add({ name, state: bot._client.state, params, isFromServer: false, timestamp: Date.now() }) + if (packetsRecordingState.active) { + packetsReplayState.packetsPlayback.push({ + name, + data: params, + isFromClient: true, + isUpcoming: false, + position: position++, + timestamp: Date.now(), + }) + packetsReplayState.progress.current++ + } + }) + bot._client.on('packet', (data, { name }) => { + if (name === 'map_chunk') data = { x: data.x, z: data.z } + circularBuffer!.add({ name, state: bot._client.state, params: data, isFromServer: true, timestamp: Date.now() }) + if (packetsRecordingState.active) { + packetsReplayState.packetsPlayback.push({ + name, + data, + isFromClient: false, + isUpcoming: false, + position: position++, + timestamp: Date.now(), + }) + packetsReplayState.progress.total++ + } + }) + const oldWriteChannel = bot._client.writeChannel.bind(bot._client) + bot._client.writeChannel = (channel, params) => { + packetsReplayState.packetsPlayback.push({ + name: channel, + data: params, + isFromClient: true, + isUpcoming: false, + position: position++, + timestamp: Date.now(), + isCustomChannel: true, + }) + oldWriteChannel(channel, params) + } + + upPacketsReplayPanel() +} + +const upPacketsReplayPanel = () => { + if (packetsRecordingState.active && bot) { + packetsReplayState.isOpen = true + packetsReplayState.isMinimized = true + packetsReplayState.isRecording = true + packetsReplayState.replayName = 'Recording all packets for ' + bot.username + } +} + +subscribe(packetsRecordingState, () => { + upPacketsReplayPanel() +}) + +declare module 'mineflayer' { + interface Bot { + downloadCurrentWorldState: () => void + startPacketsRecording: () => void + stopPacketsRecording: () => void + } +} + +export const getLastAutoCapturedPackets = () => circularBuffer?.size +export const downloadAutoCapturedPackets = () => { + const logger = new PacketsLogger({ minecraftVersion: lastConnectVersion }) + logger.relativeTime = false + logger.formattedTime = true + for (const packet of circularBuffer?.getLastElements() ?? []) { + logger.log(packet.isFromServer, { name: packet.name, state: packet.state, time: packet.timestamp }, packet.params) + } + const textContents = logger.contents + const blob = new Blob([textContents], { type: 'text/plain' }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = `${lastConnectOptions.value?.server ?? 'unknown-server'}-${lastConnectOptions.value?.username ?? 'unknown-username'}-auto-captured-packets.txt` + a.click() + URL.revokeObjectURL(url) +} diff --git a/src/mineflayer/plugins/ping.ts b/src/mineflayer/plugins/ping.ts new file mode 100644 index 00000000..d6a23554 --- /dev/null +++ b/src/mineflayer/plugins/ping.ts @@ -0,0 +1,42 @@ +import { versionToNumber } from 'renderer/viewer/common/utils' + +export default () => { + let i = 0 + 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) + }) + } + + let pingId = 0 + bot.pingServer = async () => { + if (versionToNumber(bot.version) < versionToNumber('1.20.2')) return bot.player?.ping ?? -1 + return new Promise((resolve) => { + const curId = pingId++ + bot._client.write('ping_request', { id: BigInt(curId) }) + const date = Date.now() + const onPong = (data: { id: bigint }) => { + if (BigInt(data.id) !== BigInt(curId)) return + bot._client.off('ping_response' as any, onPong) + resolve(Date.now() - date) + } + bot._client.on('ping_response' as any, onPong) + }) + } +} + +declare module 'mineflayer' { + interface Bot { + pingProxy: () => Promise + pingServer: () => Promise + } +} diff --git a/src/mineflayer/plugins/webFeatures.ts b/src/mineflayer/plugins/webFeatures.ts new file mode 100644 index 00000000..c56d7d66 --- /dev/null +++ b/src/mineflayer/plugins/webFeatures.ts @@ -0,0 +1,12 @@ +import { Bot } from 'mineflayer' +import { getAppLanguage } from '../../optionsStorage' + +export default () => { + customEvents.on('mineflayerBotCreated', () => { + bot.loadPlugin(plugin) + }) +} + +const plugin = (bot: Bot) => { + bot.settings['locale'] = getAppLanguage() +} diff --git a/src/mineflayer/timers.ts b/src/mineflayer/timers.ts new file mode 100644 index 00000000..99110718 --- /dev/null +++ b/src/mineflayer/timers.ts @@ -0,0 +1,71 @@ +import { subscribeKey } from 'valtio/utils' +import { preventThrottlingWithSound } from '../core/timers' +import { options } from '../optionsStorage' + +customEvents.on('mineflayerBotCreated', () => { + const abortController = new AbortController() + + const maybeGoBackgroundKickPrevention = () => { + if (options.preventBackgroundTimeoutKick && !bot.backgroundKickPrevention) { + const unsub = preventThrottlingWithSound() + bot.on('end', unsub) + bot.backgroundKickPrevention = true + } + } + maybeGoBackgroundKickPrevention() + subscribeKey(options, 'preventBackgroundTimeoutKick', (value) => { + maybeGoBackgroundKickPrevention() + }) + + // wake lock + const requestWakeLock = async () => { + if (!('wakeLock' in navigator)) { + console.warn('Wake Lock API is not supported in this browser') + return + } + + if (options.preventSleep && !bot.wakeLock && !bot.lockRequested) { + bot.lockRequested = true + bot.wakeLock = await navigator.wakeLock.request('screen').finally(() => { + bot.lockRequested = false + }) + + bot.wakeLock.addEventListener('release', () => { + bot.wakeLock = undefined + }, { + once: true, + }) + } + + if (!options.preventSleep && bot.wakeLock) { + void bot.wakeLock.release() + } + } + document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible') { + // we are back to the tab, request wake lock again + void requestWakeLock() + } + }, { + signal: abortController.signal, + }) + void requestWakeLock() + subscribeKey(options, 'preventSleep', (value) => { + void requestWakeLock() + }) + + bot.on('end', () => { + if (bot.wakeLock) { + void bot.wakeLock.release() + } + abortController.abort() + }) +}) + +declare module 'mineflayer' { + interface Bot { + backgroundKickPrevention?: boolean + wakeLock?: WakeLockSentinel + lockRequested?: boolean + } +} diff --git a/src/mineflayer/userError.ts b/src/mineflayer/userError.ts new file mode 100644 index 00000000..9d3e08a7 --- /dev/null +++ b/src/mineflayer/userError.ts @@ -0,0 +1,6 @@ +export class UserError extends Error { + constructor (message: string) { + super(message) + this.name = 'UserError' + } +} diff --git a/src/mineflayer/websocket-core.ts b/src/mineflayer/websocket-core.ts new file mode 100644 index 00000000..f8163102 --- /dev/null +++ b/src/mineflayer/websocket-core.ts @@ -0,0 +1,63 @@ +import { Duplex } from 'stream' +import { UserError } from './userError' + +class CustomDuplex extends Duplex { + constructor (options, public writeAction) { + super(options) + } + + override _read () {} + + override _write (chunk, encoding, callback) { + this.writeAction(chunk) + callback() + } +} + +export const getWebsocketStream = async (host: string) => { + const baseProtocol = host.startsWith('ws://') ? 'ws' : 'wss' + const hostClean = host.replace('ws://', '').replace('wss://', '') + const hostURL = new URL(`${baseProtocol}://${hostClean}`) + const hostParams = hostURL.searchParams + hostParams.append('client_mcraft', '') + const ws = new WebSocket(`${baseProtocol}://${hostURL.host}${hostURL.pathname}?${hostParams.toString()}`) + const clientDuplex = new CustomDuplex(undefined, data => { + ws.send(data) + }) + + clientDuplex.on('error', () => {}) + + ws.addEventListener('message', async message => { + let { data } = message + if (data instanceof Blob) { + data = await data.arrayBuffer() + } + clientDuplex.push(Buffer.from(data)) + }) + + ws.addEventListener('close', () => { + console.log('ws closed') + clientDuplex.end() + setTimeout(() => { + clientDuplex.emit('end', 'Connection lost') + }, 500) + }) + + ws.addEventListener('error', err => { + console.log('ws error', err) + clientDuplex.emit('error', err) + }) + + await new Promise((resolve, reject) => { + ws.addEventListener('open', resolve) + ws.addEventListener('error', err => { + console.log('ws error', err) + reject(new UserError('Failed to open websocket connection')) + }) + }) + + return { + mineflayerStream: clientDuplex, + ws, + } +} diff --git a/src/mobileShim.ts b/src/mobileShim.ts new file mode 100644 index 00000000..ebf33d6e --- /dev/null +++ b/src/mobileShim.ts @@ -0,0 +1,20 @@ +// fix double tap on mobile + +let lastElement = null as { + clickTime: number + element: HTMLElement +} | null +document.addEventListener('touchstart', (e) => { + if (e.touches.length > 1) { + lastElement = null + return + } + if (lastElement && Date.now() - lastElement.clickTime < 500 && lastElement.element === e.target) { + lastElement.element.dispatchEvent(new MouseEvent('dblclick', { bubbles: true })) + lastElement = null + } + lastElement = { + clickTime: Date.now(), + element: e.target as HTMLElement + } +}, { passive: false }) diff --git a/src/optimizeJson.ts b/src/optimizeJson.ts new file mode 100644 index 00000000..a7fe7d4e --- /dev/null +++ b/src/optimizeJson.ts @@ -0,0 +1,369 @@ +import { versionToNumber } from 'renderer/viewer/common/utils' + +type IdMap = Record + +type DiffData = { + removed: number[], + changed: any[], + removedProps: Array<[number, number[]]>, + added +} + +type SourceData = { + keys: IdMap, + properties: IdMap + source: Record + diffs: Record + arrKey? + __IS_OPTIMIZED__: true +} + +function getRecipesProcessorProcessRecipes (items, blocks) { + return (current) => { + // can require the same multiple times per different versions + const itemsIdsMap = Object.fromEntries(items.map((b) => [b.name, b.id])) + const blocksIdsMap = Object.fromEntries(blocks.map((b) => [b.name, b.id])) + const keys = Object.keys(current) + for (const key of keys) { + if (key === '_proccessed') { + delete current[key] + continue + } + const mapId = (id) => { + if (typeof id !== 'string' && typeof id !== 'number') throw new Error('Incorrect type') + const mapped = itemsIdsMap[id] ?? blocksIdsMap[id] + if (!mapped) { + throw new Error(`No item/block name with id ${id}`) + } + return mapped + } + const processRecipe = (obj) => { + // if (!obj) return + // if (Array.isArray(obj)) { + // obj.forEach((id, i) => { + // obj[i] = mapId(obj[id]) + // }) + // } else if (obj && typeof obj === 'object') { + // if (!'count metadata id'.split(' ').every(x => x in obj)) { + // throw new Error(`process error: Unknown deep object pattern: ${JSON.stringify(obj)}`) + // } + // obj.id = mapId(obj.id) + // } else { + // throw new Error('unknown type') + // } + const parseRecipeItem = (item) => { + if (typeof item === 'number' || typeof item === 'string') return mapId(item) + if (Array.isArray(item)) return [mapId(item), ...item.slice(1)] + if (!item) { + return item + } + if ('id' in item) { + item.id = mapId(item.id) + return item + } + throw new Error('unhandled') + } + const maybeProccessShape = (shape) => { + if (!shape) return + for (const shapeRow of shape) { + for (const [i, item] of shapeRow.entries()) { + shapeRow[i] = parseRecipeItem(item) + } + } + } + if (obj.result) obj.result = parseRecipeItem(obj.result) + maybeProccessShape(obj.inShape) + maybeProccessShape(obj.outShape) + if (obj.ingredients) { + for (const [i, ingredient] of obj.ingredients.entries()) { + obj.ingredients[i] = parseRecipeItem(ingredient) + } + } + } + // eslint-disable-next-line no-useless-catch + try { + const name = mapId(key) + for (const [i, recipe] of current[key].entries()) { + // eslint-disable-next-line no-useless-catch + try { + processRecipe(recipe) + } catch (err) { + // console.warn(`${version} [warn] Removing incorrect recipe: ${err}`) + // delete current[i] + throw err + } + } + current[name] = current[key] + } catch (err) { + // console.warn(`${version} [warn] Removing incorrect recipe: ${err}`) + throw err + } + delete current[key] + } + } +} + +export const restoreMinecraftData = (allVersionData: any, type: string, version: string) => { + let restorer + if (type === 'recipes') { + restorer = getRecipesProcessorProcessRecipes( + JsonOptimizer.restoreData(allVersionData.items, version, undefined), + JsonOptimizer.restoreData(allVersionData.blocks, version, undefined), + ) + } + return JsonOptimizer.restoreData(allVersionData[type], version, restorer) +} + +export default class JsonOptimizer { + keys = {} as IdMap + idToKey = {} as Record + properties = {} as IdMap + source = {} + previousKeys = [] as number[] + previousValues = {} as Record + diffs = {} as Record + + constructor (public arrKey?: string, public ignoreChanges = false, public ignoreRemoved = false) { } + + export () { + const { keys, properties, source, arrKey, diffs } = this + return { + keys, + properties, + source, + arrKey, + diffs, + '__IS_OPTIMIZED__': true + } satisfies SourceData + } + + diffObj (diffing): DiffData { + const removed = [] as number[] + const changed = [] as any[] + const removedProps = [] as any[] + const { arrKey, ignoreChanges, ignoreRemoved } = this + const added = [] as number[] + + if (!diffing || typeof diffing !== 'object') throw new Error('diffing data is not object') + if (Array.isArray(diffing) && !arrKey) throw new Error('arrKey is required for arrays') + const diffingObj = Array.isArray(diffing) ? Object.fromEntries(diffing.map(x => { + const key = JsonOptimizer.getByArrKey(x, arrKey!) + return [key, x] + })) : diffing + + const possiblyNewKeys = Object.keys(diffingObj) + this.keys ??= {} + this.properties ??= {} + let lastRootKeyId = Object.values(this.keys).length + let lastItemKeyId = Object.values(this.properties).length + for (const key of possiblyNewKeys) { + this.keys[key] ??= lastRootKeyId++ + this.idToKey[this.keys[key]] = key + } + const DEBUG = false + + const addDiff = (key, newVal, prevVal) => { + const valueMapped = [] as any[] + const isItemObj = typeof newVal === 'object' && newVal + const keyId = this.keys[key] + if (isItemObj) { + const removedPropsLocal = [] as any[] + for (const [prop, val] of Object.entries(newVal)) { + // mc-data: why push only changed props? eg for blocks only stateId are different between all versions so we skip a lot of duplicated data like block props + if (!isEqualStructured(newVal[prop], prevVal[prop])) { + let keyMapped = this.properties[prop] + if (keyMapped === undefined) { + this.properties[prop] = lastItemKeyId++ + keyMapped = this.properties[prop] + } + valueMapped.push(DEBUG ? prop : keyMapped, newVal[prop]) + } + } + // also add undefined for removed props + for (const prop of Object.keys(prevVal)) { + if (prop in newVal) continue + let keyMapped = this.properties[prop] + if (keyMapped === undefined) { + this.properties[prop] = lastItemKeyId++ + keyMapped = this.properties[prop] + } + removedPropsLocal.push(DEBUG ? prop : keyMapped) + } + removedProps.push([keyId, removedPropsLocal]) + } + changed.push(DEBUG ? key : keyId, isItemObj ? valueMapped : newVal) + } + for (const [id, sourceVal] of Object.entries(this.source)) { + const key = this.idToKey[id] + const diffVal = diffingObj[key] + if (!ignoreChanges && diffVal !== undefined) { + this.previousValues[id] ??= this.source[id] + const prevVal = this.previousValues[id] + if (!isEqualStructured(prevVal, diffVal)) { + addDiff(key, diffVal, prevVal) + } + this.previousValues[id] = diffVal + } + } + for (const [key, val] of Object.entries(diffingObj)) { + const id = this.keys[key] + if (!this.source[id]) { + this.source[id] = val + } + added.push(id) + } + + for (const previousKey of this.previousKeys) { + const key = this.idToKey[previousKey] + if (diffingObj[key] === undefined && !ignoreRemoved) { + removed.push(previousKey) + } + } + + for (const toRemove of removed) { + this.previousKeys.splice(this.previousKeys.indexOf(toRemove), 1) + } + + for (const previousKey of this.previousKeys) { + const index = added.indexOf(previousKey) + if (index === -1) continue + added.splice(index, 1) + } + + this.previousKeys = [...this.previousKeys, ...added] + + return { + removed, + changed, + added, + removedProps + } + } + + recordDiff (key: string, diffObj: string) { + const diff = this.diffObj(diffObj) + // problem is that 274 key 10.20.6 no removed keys in diff created + this.diffs[key] = diff + } + + static isOptimizedChangeDiff (changePossiblyArrDiff) { + if (!Array.isArray(changePossiblyArrDiff)) return false + if (changePossiblyArrDiff.length % 2 !== 0) return false + for (let i = 0; i < changePossiblyArrDiff.length; i += 2) { + if (typeof changePossiblyArrDiff[i] !== 'number') return false + } + return true + } + + static restoreData ({ keys, properties, source, arrKey, diffs }: SourceData, targetKey: string, dataRestorer: ((data) => void) | undefined) { + // if (!diffs[targetKey]) throw new Error(`The requested data to restore with key ${targetKey} does not exist`) + source = structuredClone(source) + const keysById = Object.fromEntries(Object.entries(keys).map(x => [x[1], x[0]])) + const propertiesById = Object.fromEntries(Object.entries(properties).map(x => [x[1], x[0]])) + const dataByKeys = {} as Record + for (const [versionKey, { added, changed, removed, removedProps }] of Object.entries(diffs)) { + for (const toAdd of added) { + dataByKeys[toAdd] = source[toAdd] + } + for (const toRemove of removed) { + delete dataByKeys[toRemove] + } + for (let i = 0; i < changed.length; i += 2) { + const key = changed[i] + const change = changed[i + 1] + const isOptimizedChange = JsonOptimizer.isOptimizedChangeDiff(change) + if (isOptimizedChange) { + // apply optimized diff + for (let k = 0; k < change.length; k += 2) { + const propId = change[k] + const newVal = change[k + 1] + const prop = propertiesById[propId] + // const prop = propId + if (prop === undefined) throw new Error(`Property id change is undefined: ${propId}`) + dataByKeys[key][prop] = newVal + } + } else { + dataByKeys[key] = change + } + } + for (const [key, removePropsId] of removedProps) { + for (const removePropId of removePropsId) { + const removeProp = propertiesById[removePropId] + // todo: this is not correct! + if (Array.isArray(dataByKeys[key])) { + dataByKeys[key].splice(removeProp as any, 1) // splice accepts strings as well + } else { + delete dataByKeys[key][removeProp] + } + } + } + if (versionToNumber(versionKey) <= versionToNumber(targetKey)) { + break + } + } + let data + if (arrKey) { + data = Object.values(dataByKeys) + } else { + data = Object.fromEntries(Object.entries(dataByKeys).map(([key, val]) => [keysById[key], val])) + } + dataRestorer?.(data) + return data + } + + static getByArrKey (item: any, arrKey: string) { + return arrKey.split('+').map(x => item[x]).join('+') + } + + static resolveDefaults (arr) { + if (!Array.isArray(arr)) throw new Error('not an array') + const propsValueCount = {} as { + [key: string]: { + [val: string]: number + } + } + for (const obj of arr) { + if (typeof obj !== 'object' || !obj) continue + for (const [key, val] of Object.entries(obj)) { + const valJson = JSON.stringify(val) + propsValueCount[key] ??= {} + propsValueCount[key][valJson] ??= 0 + propsValueCount[key][valJson] += 1 + } + } + const defaults = Object.fromEntries(Object.entries(propsValueCount).map(([prop, values]) => { + const defaultValue = Object.entries(values).sort(([, count1], [, count2]) => count2 - count1)[0][0] + return [prop, defaultValue] + })) + + const newData = [] as any[] + const noData = {} + for (const [i, obj] of arr.entries()) { + if (typeof obj !== 'object' || !obj) { + newData.push(obj) + continue + } + for (const key of Object.keys(defaults)) { + const val = obj[key] + if (!val) { + noData[key] ??= [] + noData[key].push(key) + continue + } + if (defaults[key] === JSON.stringify(val)) { + delete obj[key] + } + } + newData.push(obj) + } + + return { + data: newData, + defaults + } + } +} + +const isEqualStructured = (val1, val2) => { + return JSON.stringify(val1) === JSON.stringify(val2) +} diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 88e6115f..0cb0fe1e 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -1,18 +1,29 @@ -import { useState } from 'react' +import { useEffect, useRef, useState } from 'react' import { useSnapshot } from 'valtio' -import { openURL } from 'prismarine-viewer/viewer/lib/simpleUtils' -import { miscUiState, openOptionsMenu, showModal } from './globalState' -import { AppOptions, options } from './optionsStorage' +import { openURL } from 'renderer/viewer/lib/simpleUtils' +import { noCase } from 'change-case' +import { versionToNumber } from 'mc-assets/dist/utils' +import { gameAdditionalState, miscUiState, openOptionsMenu, showModal } from './globalState' +import { AppOptions, getChangedSettings, options, resetOptions } from './optionsStorage' import Button from './react/Button' import { OptionMeta, OptionSlider } from './react/OptionsItems' import Slider from './react/Slider' -import { getScreenRefreshRate, setLoadingScreenStatus } from './utils' -import { openFilePicker, resetLocalStorageWithoutWorld } from './browserfs' -import { getResourcePackName, resourcePackState, uninstallTexturePack } from './texturePack' - +import { getScreenRefreshRate } from './utils' +import { setLoadingScreenStatus } from './appStatus' +import { openFilePicker, resetLocalStorage } from './browserfs' +import { completeResourcepackPackInstall, getResourcePackNames, resourcepackReload, resourcePackState, uninstallResourcePack } from './resourcePack' +import { downloadPacketsReplay, packetsRecordingState } from './packetsReplay/packetsReplayLegacy' +import { showInputsModal, showOptionsModal } from './react/SelectOption' +import { ClientMod, getAllMods, modsUpdateStatus } from './clientMods' +import supportedVersions from './supportedVersions.mjs' +import { getVersionAutoSelect } from './connect' +import { createNotificationProgressReporter } from './core/progressReporter' +import { customKeymaps } from './controls' +import { appStorage } from './react/appStorageProvider' +import { exportData, importData } from './core/importExport' export const guiOptionsScheme: { - [t in OptionsGroupType]: Array<{ [K in keyof AppOptions]?: Partial> } & { custom?}> + [t in OptionsGroupType]: Array<{ [K in keyof AppOptions]?: Partial> } & { custom? }> } = { render: [ { @@ -21,13 +32,23 @@ export const guiOptionsScheme: { const [frameLimitMax, setFrameLimitMax] = useState(null as number | null) return
- { - options.frameLimit = newVal > frameLimitMax! ? false : newVal - }} /> -
} }, @@ -42,8 +63,6 @@ export const guiOptionsScheme: { custom () { return + >Keybindings + }, mouseSensX: {}, mouseSensY: { @@ -233,23 +424,40 @@ export const guiOptionsScheme: { text: 'Always Mobile Controls', }, touchButtonsSize: { - min: 40 + min: 40, + disableIf: [ + 'touchMovementType', + 'modern' + ], }, touchButtonsOpacity: { min: 10, - max: 90 + max: 90, + disableIf: [ + 'touchMovementType', + 'modern' + ], }, touchButtonsPosition: { - max: 80 + max: 80, + disableIf: [ + 'touchMovementType', + 'modern' + ], }, - touchControlsType: { - values: [['classic', 'Classic'], ['joystick-buttons', 'New']], + touchMovementType: { + text: 'Movement Controls', + values: [['modern', 'Modern'], ['classic', 'Classic']], + }, + touchInteractionType: { + text: 'Interaction Controls', + values: [['classic', 'Classic'], ['buttons', 'Buttons']], }, }, { custom () { - const { touchControlsType } = useSnapshot(options) - return + return + }, + }, + { + custom () { + return + }, + }, + { + custom () { + return + }, + }, + { + custom () { + const { active, hasRecordedPackets } = useSnapshot(packetsRecordingState) + return + }, + }, + { + packetsLoggerPreset: { + text: 'Packets Logger Preset', + values: [ + ['all', 'All'], + ['no-buffers', 'No Buffers'] + ], + }, + }, + { + debugContro: { + text: 'Debug Controls', + }, + }, + { + debugResponseTimeIndicator: { + text: 'Debug Input Lag', + }, + }, + { + debugChatScroll: { }, } ], + 'export-import': [ + { + custom () { + return Export/Import Data + } + }, + { + custom () { + return + } + }, + { + custom () { + return + } + }, + { + custom () { + return + } + }, + { + custom () { + return + } + } + ], } -export type OptionsGroupType = 'main' | 'render' | 'interface' | 'controls' | 'sound' | 'advanced' | 'VR' +export type OptionsGroupType = 'main' | 'render' | 'interface' | 'controls' | 'sound' | 'advanced' | 'VR' | 'export-import' const Category = ({ children }) =>
{children}
+const UiToggleButton = ({ name, addUiText = false, label = noCase(name) }: { name: string, addUiText?: boolean, label?: string }) => { + const { disabledUiParts } = useSnapshot(options) + + const currentlyDisabled = disabledUiParts.includes(name) + if (addUiText) label = `${label} UI` + return +} + export const tryFindOptionConfig = (option: keyof AppOptions) => { for (const group of Object.values(guiOptionsScheme)) { for (const optionConfig of group) { diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index 2a13abf4..22d5ef26 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -1,110 +1,27 @@ -// todo implement async options storage - 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' +import { appQueryParams, appQueryParamsArray } from './appParams' +import type { AppConfig } from './appConfig' +import { appStorage } from './react/appStorageProvider' +import { miscUiState } from './globalState' +import { defaultOptions } from './defaultOptions' -const defaultOptions = { - renderDistance: 3, - multiplayerRenderDistance: 3, - closeConfirmation: true, - autoFullScreen: false, - mouseRawInput: false, - autoExitFullscreen: false, - localUsername: 'wanderer', - mouseSensX: 50, - mouseSensY: -1, - // mouseInvertX: false, - chatWidth: 320, - chatHeight: 180, - chatScale: 100, - chatOpacity: 100, - chatOpacityOpened: 100, - messagesLimit: 200, - volume: 50, - // fov: 70, - fov: 75, - guiScale: 3, - autoRequestCompletions: true, - touchButtonsSize: 40, - touchButtonsOpacity: 80, - touchButtonsPosition: 12, - touchControlsPositions: getDefaultTouchControlsPositions(), - touchControlsType: 'classic' as 'classic' | 'joystick-buttons', - gpuPreference: 'default' as 'default' | 'high-performance' | 'low-power', - backgroundRendering: '20fps' as 'full' | '20fps' | '5fps', - /** @unstable */ - disableAssets: false, - /** @unstable */ - debugLogNotFrequentPackets: false, - unimplementedContainers: false, - dayCycleAndLighting: true, - loadPlayerSkins: true, - lowMemoryMode: false, - starfieldRendering: true, - // antiAliasing: false, +const isDev = process.env.NODE_ENV === 'development' +const initialAppConfig = process.env?.INLINED_APP_CONFIG as AppConfig ?? {} - showChunkBorders: false, // todo rename option - frameLimit: false as number | false, - alwaysBackupWorldBeforeLoading: undefined as boolean | undefined | null, - alwaysShowMobileControls: false, - excludeCommunicationDebugEvents: [], - preventDevReloadWhilePlaying: false, - numWorkers: 4, - localServerOptions: { - gameMode: 1 - } as any, - preferLoadReadonly: false, - disableLoadPrompts: false, - guestUsername: 'guest', - askGuestName: true, - errorReporting: true, - /** Actually might be useful */ - showCursorBlockInSpectator: false, - renderEntities: true, - smoothLighting: true, - newVersionsLighting: false, - chatSelect: false, - autoJump: 'auto' as 'auto' | 'always' | 'never', - autoParkour: false, - - // advanced bot options - autoRespawn: false, - mutedSounds: [] as string[], - plugins: [] as Array<{ enabled: boolean, name: string, description: string, script: string }>, - /** Wether to popup sign editor on server action */ - autoSignEditor: true, - 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') +// const qsOptionsRaw = new URLSearchParams(location.search).getAll('setting') +const qsOptionsRaw = appQueryParamsArray.setting ?? [] export const qsOptions = Object.fromEntries(qsOptionsRaw.map(o => { const [key, value] = o.split(':') return [key, JSON.parse(value)] })) +// Track which settings are disabled (controlled by QS or forced by config) +export const disabledSettings = proxy({ + value: new Set(Object.keys(qsOptions)) +}) + const migrateOptions = (options: Partial>) => { if (options.highPerformanceGpu) { options.gpuPreference = 'high-performance' @@ -116,15 +33,53 @@ const migrateOptions = (options: Partial>) => { if (options.touchControlsPositions?.jump === undefined) { options.touchControlsPositions!.jump = defaultOptions.touchControlsPositions.jump } + if (options.touchControlsType === 'joystick-buttons') { + options.touchInteractionType = 'buttons' + } return options } +const migrateOptionsLocalStorage = () => { + if (Object.keys(appStorage['options'] ?? {}).length) { + for (const key of Object.keys(appStorage['options'])) { + if (!(key in defaultOptions)) continue // drop unknown options + const defaultValue = defaultOptions[key] + if (JSON.stringify(defaultValue) !== JSON.stringify(appStorage['options'][key])) { + appStorage.changedSettings[key] = appStorage['options'][key] + } + } + delete appStorage['options'] + } +} export type AppOptions = typeof defaultOptions +const isDeepEqual = (a: any, b: any): boolean => { + if (a === b) return true + if (typeof a !== typeof b) return false + if (typeof a !== 'object') return false + if (a === null || b === null) return a === b + if (Array.isArray(a) && Array.isArray(b)) { + if (a.length !== b.length) return false + return a.every((item, index) => isDeepEqual(item, b[index])) + } + const keysA = Object.keys(a) + const keysB = Object.keys(b) + if (keysA.length !== keysB.length) return false + return keysA.every(key => isDeepEqual(a[key], b[key])) +} + +export const getChangedSettings = () => { + return Object.fromEntries( + Object.entries(appStorage.changedSettings).filter(([key, value]) => !isDeepEqual(defaultOptions[key], value)) + ) +} + +migrateOptionsLocalStorage() export const options: AppOptions = proxy({ ...defaultOptions, - ...migrateOptions(JSON.parse(localStorage.options || '{}')), + ...initialAppConfig.defaultSettings, + ...migrateOptions(appStorage.changedSettings), ...qsOptions }) @@ -136,16 +91,25 @@ export const resetOptions = () => { Object.defineProperty(window, 'debugChangedOptions', { get () { - return Object.fromEntries(Object.entries(options).filter(([key, v]) => defaultOptions[key] !== v)) + return getChangedSettings() }, }) -subscribe(options, () => { - const saveOptions = omitObj(options, ...Object.keys(qsOptions) as [any]) - localStorage.options = JSON.stringify(saveOptions) +subscribe(options, (ops) => { + if (appQueryParams.freezeSettings === 'true') return + for (const op of ops) { + const [type, path, value] = op + // let patch + // let accessor = options + // for (const part of path) { + // } + const key = path[0] as string + if (disabledSettings.value.has(key)) continue + appStorage.changedSettings[key] = options[key] + } }) -type WatchValue = >(proxy: T, callback: (p: T) => void) => void +type WatchValue = >(proxy: T, callback: (p: T, isChanged: boolean) => void) => () => void export const watchValue: WatchValue = (proxy, callback) => { const watchedProps = new Set() @@ -154,11 +118,20 @@ export const watchValue: WatchValue = (proxy, callback) => { watchedProps.add(p.toString()) return Reflect.get(target, p, receiver) }, - })) + }), false) + const unsubscribes = [] as Array<() => void> for (const prop of watchedProps) { - subscribeKey(proxy, prop, () => { - callback(proxy) - }) + unsubscribes.push( + subscribeKey(proxy, prop, () => { + callback(proxy, true) + }) + ) + } + + return () => { + for (const unsubscribe of unsubscribes) { + unsubscribe() + } } } @@ -180,3 +153,12 @@ export const useOptionValue = (setting, valueCallback) => { valueCallback(setting) subscribe(setting, valueCallback) } + +export const getAppLanguage = () => { + if (options.language === 'auto') { + return miscUiState.appConfig?.defaultLanguage ?? navigator.language + } + return options.language +} + +export { defaultOptions } from './defaultOptions' diff --git a/src/packetsReplay/packetsReplayLegacy.ts b/src/packetsReplay/packetsReplayLegacy.ts new file mode 100644 index 00000000..a9cc71ec --- /dev/null +++ b/src/packetsReplay/packetsReplayLegacy.ts @@ -0,0 +1,70 @@ +import { proxy } from 'valtio' +import { PacketsLogger } from 'mcraft-fun-mineflayer/build/packetsLogger' +import { options } from '../optionsStorage' + +export const packetsRecordingState = proxy({ + active: options.packetsRecordingAutoStart, + hasRecordedPackets: false +}) + +// eslint-disable-next-line import/no-mutable-exports +export let replayLogger: PacketsLogger | undefined + +const isBufferData = (data: any): boolean => { + if (Buffer.isBuffer(data) || data instanceof Uint8Array) return true + if (typeof data === 'object' && data !== null) { + return Object.values(data).some(value => isBufferData(value)) + } + return false +} + +const processPacketData = (data: any): any => { + if (options.packetsLoggerPreset === 'no-buffers') { + if (Buffer.isBuffer(data)) { + return '[buffer]' + } + if (typeof data === 'object' && data !== null) { + const processed = {} + for (const [key, value] of Object.entries(data)) { + processed[key] = isBufferData(value) ? '[buffer]' : value + } + return processed + } + } + return data +} + +export default () => { + customEvents.on('mineflayerBotCreated', () => { + replayLogger = new PacketsLogger({ minecraftVersion: bot.version }) + replayLogger.contents = '' + packetsRecordingState.hasRecordedPackets = false + const handleServerPacket = (data, { name, state = bot._client.state }) => { + if (!packetsRecordingState.active) { + return + } + replayLogger!.log(true, { name, state }, processPacketData(data)) + packetsRecordingState.hasRecordedPackets = true + } + bot._client.on('packet', handleServerPacket) + bot._client.on('packet_name' as any, (name, data) => { + handleServerPacket(data, { name }) + }) + + bot._client.on('writePacket' as any, (name, data) => { + if (!packetsRecordingState.active) { + return + } + replayLogger!.log(false, { name, state: bot._client.state }, processPacketData(data)) + packetsRecordingState.hasRecordedPackets = true + }) + }) +} + +export const downloadPacketsReplay = async () => { + const a = document.createElement('a') + a.href = `data:text/plain;charset=utf-8,${encodeURIComponent(replayLogger!.contents)}` + a.download = `packets-replay-${new Date().toISOString()}.txt` + a.click() +} +globalThis.downloadPacketsReplay = downloadPacketsReplay diff --git a/src/packetsReplay/replayPackets.ts b/src/packetsReplay/replayPackets.ts new file mode 100644 index 00000000..54b3d652 --- /dev/null +++ b/src/packetsReplay/replayPackets.ts @@ -0,0 +1,366 @@ +/* eslint-disable no-await-in-loop */ +import { createServer, ServerClient } from 'minecraft-protocol' +import { ParsedReplayPacket, parseReplayContents } from 'mcraft-fun-mineflayer/build/packetsLogger' +import { PACKETS_REPLAY_FILE_EXTENSION, WORLD_STATE_FILE_EXTENSION } from 'mcraft-fun-mineflayer/build/worldState' +import MinecraftData from 'minecraft-data' +import { GameMode } from 'mineflayer' +import { UserError } from '../mineflayer/userError' +import { packetsReplayState } from '../react/state/packetsReplayState' +import { getFixedFilesize } from '../react/simpleUtils' +import { appQueryParams } from '../appParams' +import { LocalServer } from '../customServer' + +const SUPPORTED_FORMAT_VERSION = 1 + +type ReplayDefinition = { + minecraftVersion: string + replayAgainst?: 'client' | 'server' + serverIp?: string +} + +interface OpenFileOptions { + contents: string + filename?: string + filesize?: number +} + +export function openFile ({ contents, filename = 'unnamed', filesize }: OpenFileOptions) { + packetsReplayState.replayName = `${filename} (${getFixedFilesize(filesize ?? contents.length)})` + packetsReplayState.isPlaying = false + + const connectOptions = { + worldStateFileContents: contents, + username: 'replay' + } + dispatchEvent(new CustomEvent('connect', { detail: connectOptions })) +} + +export const startLocalReplayServer = (contents: string) => { + const { packets, header } = parseReplayContents(contents) + + packetsReplayState.packetsPlayback = [] + packetsReplayState.isOpen = true + packetsReplayState.isPlaying = true + packetsReplayState.progress = { + current: 0, + total: packets.filter(packet => packet.isFromServer).length + } + packetsReplayState.speed = 1 + packetsReplayState.replayName ||= `local ${getFixedFilesize(contents.length)}` + packetsReplayState.replayName = `${header.minecraftVersion} ${packetsReplayState.replayName}` + + if ('formatVersion' in header && header.formatVersion !== SUPPORTED_FORMAT_VERSION) { + throw new UserError(`Unsupported format version: ${header.formatVersion}`) + } + if ('replayAgainst' in header && header.replayAgainst === 'server') { + throw new Error('not supported') + } + + const server = createServer({ + Server: LocalServer as any, + version: header.minecraftVersion, + keepAlive: false, + 'online-mode': false + }) + + const data = MinecraftData(header.minecraftVersion) + server.on(data.supportFeature('hasConfigurationState') ? 'playerJoin' : 'login' as any, async client => { + await mainPacketsReplayer( + client, + packets, + packetsReplayState.customButtons.validateClientPackets.state ? undefined : true + ) + }) + + return { + server, + version: header.minecraftVersion + } +} + +// time based packets +// const FLATTEN_CLIENT_PACKETS = new Set(['position', 'position_look']) +const FLATTEN_CLIENT_PACKETS = new Set([] as string[]) + +const positions = { + client: 0, + server: 0 +} +const addPacketToReplayer = (name: string, data, isFromClient: boolean, wasUpcoming = false) => { + const side = isFromClient ? 'client' : 'server' + + if (wasUpcoming) { + const lastUpcoming = packetsReplayState.packetsPlayback.find(p => p.isUpcoming && p.name === name) + if (lastUpcoming) { + lastUpcoming.isUpcoming = false + } + } else { + packetsReplayState.packetsPlayback.push({ + name, + data, + isFromClient, + position: ++positions[side]!, + isUpcoming: false, + timestamp: Date.now() + }) + } + + if (!isFromClient && !wasUpcoming) { + packetsReplayState.progress.current++ + } +} + +const IGNORE_SERVER_PACKETS = new Set([ + 'kick_disconnect', +]) + +const ADDITIONAL_DELAY = 500 + +const mainPacketsReplayer = async (client: ServerClient, packets: ParsedReplayPacket[], ignoreClientPacketsWait: string[] | true = []) => { + const writePacket = (name: string, data: any) => { + data = restoreData(data) + client.write(name, data) + } + + const playPackets = packets.filter(p => p.state === 'play') + + let clientPackets = [] as Array<{ name: string, params: any }> + const clientsPacketsWaiter = createPacketsWaiter({ + unexpectedPacketReceived (name, params) { + console.log('unexpectedPacketReceived', name, params) + addPacketToReplayer(name, params, true) + }, + expectedPacketReceived (name, params) { + console.log('expectedPacketReceived', name, params) + addPacketToReplayer(name, params, true, true) + }, + unexpectedPacketsLimit: 15, + onUnexpectedPacketsLimitReached () { + addPacketToReplayer('...', {}, true) + } + }) + + // Patch console.error to detect errors + const originalConsoleError = console.error + let lastSentPacket: { name: string, params: any } | null = null + console.error = (...args) => { + if (lastSentPacket) { + console.log('Got error after packet', lastSentPacket.name, lastSentPacket.params) + } + originalConsoleError.apply(console, args) + if (packetsReplayState.customButtons.stopOnError.state) { + packetsReplayState.isPlaying = false + throw new Error('Replay stopped due to error: ' + args.join(' ')) + } + } + + const playServerPacket = (name: string, params: any) => { + try { + writePacket(name, params) + addPacketToReplayer(name, params, false) + lastSentPacket = { name, params } + } catch (err) { + console.error('Error processing packet:', err) + if (packetsReplayState.customButtons.stopOnError.state) { + packetsReplayState.isPlaying = false + } + } + } + + try { + bot.on('error', (err) => { + console.error('Mineflayer error:', err) + }) + + bot._client.on('writePacket' as any, (name, params) => { + clientsPacketsWaiter.addPacket(name, params) + }) + + console.log('start replaying!') + for (const [i, packet] of playPackets.entries()) { + if (!packetsReplayState.isPlaying) { + await new Promise(resolve => { + const interval = setInterval(() => { + if (packetsReplayState.isPlaying) { + clearInterval(interval) + resolve() + } + }, 100) + }) + } + + if (packet.isFromServer) { + if (packet.params === null) { + console.warn('packet.params is null', packet) + continue + } + playServerPacket(packet.name, packet.params) + if (packet.diff) { + await new Promise(resolve => { + setTimeout(resolve, packet.diff * packetsReplayState.speed + ADDITIONAL_DELAY * (packetsReplayState.customButtons.packetsSenderDelay.state ? 1 : 0)) + }) + } + } else if (ignoreClientPacketsWait !== true && !ignoreClientPacketsWait.includes(packet.name)) { + clientPackets.push({ name: packet.name, params: packet.params }) + if (playPackets[i + 1]?.isFromServer) { + // eslint-disable-next-line @typescript-eslint/no-loop-func + clientPackets = clientPackets.filter((p, index) => { + return !FLATTEN_CLIENT_PACKETS.has(p.name) || index === clientPackets.findIndex(clientPacket => clientPacket.name === p.name) + }) + for (const packet of clientPackets) { + packetsReplayState.packetsPlayback.push({ + name: packet.name, + data: packet.params, + isFromClient: true, + position: positions.client++, + timestamp: Date.now(), + isUpcoming: true, + }) + } + + await Promise.race([ + clientsPacketsWaiter.waitForPackets(clientPackets.map(p => p.name)), + ...(packetsReplayState.customButtons.skipMissingOnTimeout.state ? [new Promise(resolve => { + setTimeout(resolve, 1000) + })] : []) + ]) + clientsPacketsWaiter.stopWaiting() + clientPackets = [] + } + } + } + } finally { + // Restore original console.error + console.error = originalConsoleError + } +} + +export const switchGameMode = (gameMode: GameMode) => { + const gamemodes = { + survival: 0, + creative: 1, + adventure: 2, + spectator: 3 + } + if (gameMode === 'spectator') { + bot._client.emit('abilities', { + // can fly + is flying + flags: 6 + }) + } + bot._client.emit('game_state_change', { + reason: 3, + gameMode: gamemodes[gameMode] + }) +} + +interface PacketsWaiterOptions { + unexpectedPacketReceived?: (name: string, params: any) => void + expectedPacketReceived?: (name: string, params: any) => void + onUnexpectedPacketsLimitReached?: () => void + unexpectedPacketsLimit?: number +} + +interface PacketsWaiter { + addPacket(name: string, params: any): void + waitForPackets(packets: string[]): Promise + stopWaiting(): void +} + +const createPacketsWaiter = (options: PacketsWaiterOptions = {}): PacketsWaiter => { + let packetHandler: ((data: any, name: string) => void) | null = null + const queuedPackets: Array<{ name: string, params: any }> = [] + let isWaiting = false + let unexpectedPacketsCount = 0 + const handlePacket = (data: any, name: string, waitingPackets: string[], resolve: () => void) => { + if (waitingPackets.includes(name)) { + waitingPackets.splice(waitingPackets.indexOf(name), 1) + options.expectedPacketReceived?.(name, data) + } else { + if (options.unexpectedPacketsLimit && unexpectedPacketsCount < options.unexpectedPacketsLimit) { + options.unexpectedPacketReceived?.(name, data) + } + if (options.onUnexpectedPacketsLimitReached && unexpectedPacketsCount === options.unexpectedPacketsLimit) { + options.onUnexpectedPacketsLimitReached?.() + } + unexpectedPacketsCount++ + } + + if (waitingPackets.length === 0) { + resolve() + } + } + + return { + addPacket (name: string, params: any) { + if (packetHandler) { + packetHandler(params, name) + } else { + queuedPackets.push({ name, params }) + } + }, + + async waitForPackets (packets: string[]) { + if (isWaiting) { + throw new Error('Already waiting for packets') + } + unexpectedPacketsCount = 0 + isWaiting = true + + try { + await new Promise(resolve => { + const waitingPackets = [...packets] + + packetHandler = (data: any, name: string) => { + handlePacket(data, name, waitingPackets, resolve) + } + + // Process any queued packets + for (const packet of queuedPackets) { + handlePacket(packet.params, packet.name, waitingPackets, resolve) + } + queuedPackets.length = 0 + }) + } finally { + isWaiting = false + packetHandler = null + } + }, + stopWaiting () { + isWaiting = false + packetHandler = null + queuedPackets.length = 0 + } + } +} + +const isArrayEqual = (a: any[], b: any[]) => { + if (a.length !== b.length) return false + for (const [i, element] of a.entries()) { + if (element !== b[i]) return false + } + return true +} + +const restoreData = (json: any) => { + if (!json) return json + const keys = Object.keys(json) + + if (isArrayEqual(keys.sort(), ['data', 'type'].sort())) { + if (json.type === 'Buffer') { + return Buffer.from(json.data) + } + } + + if (typeof json === 'object' && json) { + for (const [key, value] of Object.entries(json)) { + if (typeof value === 'object') { + json[key] = restoreData(value) + } + } + } + + return json +} + +export const VALID_REPLAY_EXTENSIONS = [`.${PACKETS_REPLAY_FILE_EXTENSION}`, `.${WORLD_STATE_FILE_EXTENSION}`] diff --git a/src/panorama.ts b/src/panorama.ts deleted file mode 100644 index 59df54e4..00000000 --- a/src/panorama.ts +++ /dev/null @@ -1,128 +0,0 @@ -//@ts-check - -import { join } from 'path' -import fs from 'fs' -import { subscribeKey } from 'valtio/utils' -import { EntityMesh } from 'prismarine-viewer/viewer/lib/entity/EntityMesh' -import { fromTexturePackPath, resourcePackState } from './texturePack' -import { options, watchValue } from './optionsStorage' -import { miscUiState } from './globalState' - -let panoramaCubeMap -let shouldDisplayPanorama = false -let panoramaUsesResourcePack = null as boolean | null - -const panoramaFiles = [ - 'panorama_1.png', // WS - 'panorama_3.png', // ES - 'panorama_4.png', // Up - 'panorama_5.png', // Down - 'panorama_0.png', // NS - 'panorama_2.png' // SS -] - -const panoramaResourcePackPath = 'assets/minecraft/textures/gui/title/background' -const possiblyLoadPanoramaFromResourcePack = async (file) => { - let base64Texture - if (panoramaUsesResourcePack) { - try { - base64Texture = await fs.promises.readFile(fromTexturePackPath(join(panoramaResourcePackPath, file)), 'base64') - } catch (err) { - panoramaUsesResourcePack = false - } - } - if (base64Texture) return `data:image/png;base64,${base64Texture}` - else return join('extra-textures/background', file) -} - -const updateResourcePackSupportPanorama = async () => { - try { - await fs.promises.readFile(fromTexturePackPath(join(panoramaResourcePackPath, panoramaFiles[0])), 'base64') - panoramaUsesResourcePack = true - } catch (err) { - panoramaUsesResourcePack = false - } -} - -watchValue(miscUiState, m => { - if (m.appLoaded) { - // Also adds panorama on app load here - watchValue(resourcePackState, async (s) => { - const oldState = panoramaUsesResourcePack - const newState = s.resourcePackInstalled && (await updateResourcePackSupportPanorama(), panoramaUsesResourcePack) - if (newState === oldState) return - removePanorama() - void addPanoramaCubeMap() - }) - } -}) - -subscribeKey(miscUiState, 'loadedDataVersion', () => { - if (miscUiState.loadedDataVersion) removePanorama() - else void addPanoramaCubeMap() -}) - -// Menu panorama background -// TODO-low use abort controller -export async function addPanoramaCubeMap () { - if (panoramaCubeMap || miscUiState.loadedDataVersion || options.disableAssets) return - shouldDisplayPanorama = true - - let time = 0 - viewer.camera.fov = 85 - viewer.camera.near = 0.05 - viewer.camera.updateProjectionMatrix() - viewer.camera.position.set(0, 0, 0) - viewer.camera.rotation.set(0, 0, 0) - const panorGeo = new THREE.BoxGeometry(1000, 1000, 1000) - - const loader = new THREE.TextureLoader() - const panorMaterials = [] as THREE.MeshBasicMaterial[] - await updateResourcePackSupportPanorama() - for (const file of panoramaFiles) { - panorMaterials.push(new THREE.MeshBasicMaterial({ - map: loader.load(await possiblyLoadPanoramaFromResourcePack(file)), - transparent: true, - side: THREE.DoubleSide - })) - } - - if (!shouldDisplayPanorama) return - - const panoramaBox = new THREE.Mesh(panorGeo, panorMaterials) - - panoramaBox.onBeforeRender = () => { - time += 0.01 - panoramaBox.rotation.y = Math.PI + time * 0.01 - panoramaBox.rotation.z = Math.sin(-time * 0.001) * 0.001 - } - - const group = new THREE.Object3D() - group.add(panoramaBox) - - // should be rewritten entirely - for (let i = 0; i < 20; i++) { - const m = new EntityMesh('1.16.4', 'squid').mesh! - m.position.set(Math.random() * 30 - 15, Math.random() * 20 - 10, Math.random() * 10 - 17) - m.rotation.set(0, Math.PI + Math.random(), -Math.PI / 4, 'ZYX') - const v = Math.random() * 0.01 - m.children[0].onBeforeRender = () => { - m.rotation.y += v - m.rotation.z = Math.cos(panoramaBox.rotation.y * 3) * Math.PI / 4 - Math.PI / 2 - } - group.add(m) - } - - viewer.scene.add(group) - panoramaCubeMap = group -} - -export function removePanorama () { - shouldDisplayPanorama = false - if (!panoramaCubeMap) return - viewer.camera.fov = options.fov - viewer.camera.near = 0.1 - viewer.camera.updateProjectionMatrix() - viewer.scene.remove(panoramaCubeMap) - panoramaCubeMap = null -} diff --git a/src/parseServerAddress.ts b/src/parseServerAddress.ts new file mode 100644 index 00000000..acedf70a --- /dev/null +++ b/src/parseServerAddress.ts @@ -0,0 +1,54 @@ + + +export const parseServerAddress = (address: string | undefined, removeHttp = true): ParsedServerAddress => { + if (!address) { + return { host: '', isWebSocket: false, serverIpFull: '' } + } + + if (/^ws:[^/]/.test(address)) address = address.replace('ws:', 'ws://') + if (/^wss:[^/]/.test(address)) address = address.replace('wss:', 'wss://') + const isWebSocket = address.startsWith('ws://') || address.startsWith('wss://') + if (isWebSocket) { + return { host: address, isWebSocket: true, serverIpFull: address } + } + + if (removeHttp) { + address = address.replace(/^https?:\/\//, '') + } + + const parts = address.split(':') + + let version: string | null = null + let port: string | null = null + + for (let i = 0; i < parts.length; i++) { + const part = parts[i] + if (/^\d+\.\d+(\.\d+)?$/.test(part)) { + version = part + parts.splice(i, 1) + i-- + } + if (/^\d+$/.test(part)) { + port = part + parts.splice(i, 1) + i-- + } + } + + const host = parts.join(':') + return { + host, + ...(port ? { port } : {}), + ...(version ? { version } : {}), + isWebSocket: false, + serverIpFull: port ? `${host}:${port}` : host + } +} + +export interface ParsedServerAddress { + host: string + port?: string + version?: string + isWebSocket: boolean + serverIpFull: string +} diff --git a/src/perf_hooks_replacement.js b/src/perf_hooks_replacement.js deleted file mode 100644 index 69b0e2ed..00000000 --- a/src/perf_hooks_replacement.js +++ /dev/null @@ -1 +0,0 @@ -module.exports.performance = window.performance diff --git a/src/preflatMap.json b/src/preflatMap.json index fdf2640f..81c2a20a 100644 --- a/src/preflatMap.json +++ b/src/preflatMap.json @@ -925,18 +925,18 @@ "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]", + "144:0": "player_head[facing=down]", + "144:1": "player_head[facing=up]", + "144:2": "player_head[facing=north]", + "144:3": "player_head[facing=south]", + "144:4": "player_head[facing=west]", + "144:5": "player_head[facing=east]", + "144:8": "player_head[facing=down]", + "144:9": "player_head[facing=up]", + "144:10": "player_head[facing=north]", + "144:11": "player_head[facing=south]", + "144:12": "player_head[facing=west]", + "144:13": "player_head[facing=east]", "145:0": "anvil[facing=south]", "145:1": "anvil[facing=west]", "145:2": "anvil[facing=north]", diff --git a/src/react/AddServerOrConnect.tsx b/src/react/AddServerOrConnect.tsx index 500c1e61..36fd5264 100644 --- a/src/react/AddServerOrConnect.tsx +++ b/src/react/AddServerOrConnect.tsx @@ -1,8 +1,12 @@ -import React from 'react' +import React, { useEffect } from 'react' +import { appQueryParams } from '../appParams' +import { fetchServerStatus, isServerValid } from '../api/mcStatusApi' +import { parseServerAddress } from '../parseServerAddress' import Screen from './Screen' -import Input from './Input' +import Input, { INPUT_LABEL_WIDTH, InputWithLabel } from './Input' import Button from './Button' -import { useIsSmallWidth } from './simpleHooks' +import SelectGameVersion from './SelectGameVersion' +import { usePassesScaledDimensions } from './UIProvider' export interface BaseServerInfo { ip: string @@ -10,7 +14,8 @@ export interface BaseServerInfo { versionOverride?: string proxyOverride?: string usernameOverride?: string - passwordOverride?: string + /** Username or always use new if true */ + authenticatedAccountOverride?: string | true } interface Props { @@ -20,91 +25,232 @@ interface Props { initialData?: BaseServerInfo parseQs?: boolean onQsConnect?: (server: BaseServerInfo) => void - defaults?: Pick + placeholders?: Pick + accounts?: string[] + authenticatedAccounts?: number + versions?: string[] } -export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQs, onQsConnect, defaults }: Props) => { - const qsParams = parseQs ? new URLSearchParams(window.location.search) : undefined +export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQs, onQsConnect, placeholders, accounts, versions }: Props) => { + const isSmallHeight = !usePassesScaledDimensions(null, 350) + const qsParamName = parseQs ? appQueryParams.name : undefined + const qsParamIp = parseQs ? appQueryParams.ip : undefined + const qsParamVersion = parseQs ? appQueryParams.version : undefined + const qsParamProxy = parseQs ? appQueryParams.proxy : undefined + const qsParamUsername = parseQs ? appQueryParams.username : undefined + const qsParamLockConnect = parseQs ? appQueryParams.lockConnect : undefined - const [serverName, setServerName] = React.useState(initialData?.name ?? qsParams?.get('name') ?? '') + const parsedQsIp = parseServerAddress(qsParamIp) + const parsedInitialIp = parseServerAddress(initialData?.ip) - 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(parsedQsIp.serverIpFull || parsedInitialIp.serverIpFull || '') + 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 [passwordOverride, setPasswordOverride] = React.useState(initialData?.passwordOverride ?? qsParams?.get('password') ?? '') - const smallWidth = useIsSmallWidth() - const lockConnect = qsParams?.get('lockConnect') === 'true' + const smallWidth = !usePassesScaledDimensions(400) + const initialAccount = initialData?.authenticatedAccountOverride + const [accountIndex, setAccountIndex] = React.useState(initialAccount === true ? -2 : initialAccount ? (accounts?.includes(initialAccount) ? accounts.indexOf(initialAccount) : -2) : -1) - return -
{ - e.preventDefault() - let ip = serverIp.includes(':') ? serverIp : `${serverIp}:${serverPort}` - ip = ip.replace(/:$/, '') - onConfirm({ - name: serverName, - ip, - versionOverride, - proxyOverride, - usernameOverride, - passwordOverride - }) - }} + const freshAccount = accountIndex === -2 + const noAccountSelected = accountIndex === -1 + const authenticatedAccountOverride = noAccountSelected ? undefined : freshAccount ? true : accounts?.[accountIndex] + + let ipFinal = serverIp + ipFinal = ipFinal.replace(/:$/, '') + const commonUseOptions: BaseServerInfo = { + name: serverName, + ip: ipFinal, + versionOverride: versionOverride || undefined, + proxyOverride: proxyOverride || undefined, + usernameOverride: usernameOverride || undefined, + authenticatedAccountOverride, + } + + const [fetchedServerInfoIp, setFetchedServerInfoIp] = React.useState(undefined) + const [serverOnline, setServerOnline] = React.useState(null as boolean | null) + const [onlinePlayersList, setOnlinePlayersList] = React.useState([]) + + useEffect(() => { + const controller = new AbortController() + + const checkServer = async () => { + if (!qsParamIp || !isServerValid(qsParamIp)) return + + try { + const status = await fetchServerStatus(qsParamIp) + if (!status) return + + setServerOnline(status.raw.online) + setOnlinePlayersList(status.raw.players?.list.map(p => p.name_raw) ?? []) + setFetchedServerInfoIp(qsParamIp) + } catch (err) { + console.error('Failed to fetch server status:', err) + } + } + + void checkServer() + return () => controller.abort() + }, [qsParamIp]) + + const validateUsername = (username: string) => { + if (!username) return undefined + if (onlinePlayersList.includes(username)) { + return { border: 'red solid 1px' } + } + const MINECRAFT_USERNAME_REGEX = /^\w{3,16}$/ + if (!MINECRAFT_USERNAME_REGEX.test(username)) { + return { border: 'red solid 1px' } + } + return undefined + } + + const validateServerIp = () => { + if (!serverIp) return undefined + if (serverOnline) { + return { border: 'lightgreen solid 1px' } + } else { + return { border: 'red solid 1px' } + } + } + + const displayConnectButton = qsParamIp + const serverExamples = ['example.com:25565', 'play.hypixel.net', 'ws://play.pcm.gg', 'wss://play.webmc.fun'] + // pick random example + const example = serverExamples[Math.floor(Math.random() * serverExamples.length)] + + return + { + e.preventDefault() + onConfirm(commonUseOptions) + }} >
-
- 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' */ /> - {!lockConnect && <>} - {qsParams?.get('ip') &&
- -
} + placeholder="Optional, but recommended to specify" + disabled={lockConnect} + /> +
+ + setProxyOverride(value)} + placeholder={serverIp.startsWith('ws://') || serverIp.startsWith('wss://') ? 'Not needed for websocket servers' : placeholders?.proxyOverride} + /> + setUsernameOverride(value)} + placeholder={placeholders?.usernameOverride} + validateInput={!serverOnline || fetchedServerInfoIp !== serverIp ? undefined : validateUsername} + /> + + + {!lockConnect && <> + { + onBack() + }}> + Cancel + + + {displayConnectButton ? translate('Save') : {translate('Save')}} + + } + {displayConnectButton && ( +
+ { + onQsConnect?.(commonUseOptions) + }} + > + {translate('Connect')} + +
+ )}
} -const InputWithLabel = ({ label, span, ...props }: React.ComponentProps & { label, span?}) => { - return
- - -
+const ButtonWrapper = ({ ...props }: React.ComponentProps) => { + props.style ??= {} + props.style.width = INPUT_LABEL_WIDTH + return - - )} - +
+ + + {status} + + +

{description}

+

{lastStatus ? `Last status: ${lastStatus}` : lastStatus}

+ + } + backdrop='dirt' + > + {isError && ( + <> + {showReconnect && onReconnect && } + {actionsSlot} + {!lockConnect && } + {backAction &&
) } diff --git a/src/react/AppStatusProvider.tsx b/src/react/AppStatusProvider.tsx index 6ae39308..9c7b34ac 100644 --- a/src/react/AppStatusProvider.tsx +++ b/src/react/AppStatusProvider.tsx @@ -1,14 +1,21 @@ import { proxy, useSnapshot } from 'valtio' -import { useEffect } from 'react' +import { useEffect, useRef, useState } from 'react' import { activeModalStack, activeModalStacks, hideModal, insertActiveModalStack, miscUiState } from '../globalState' -import { resetLocalStorageWorld } from '../browserfs' -import { fsState } from '../loadSave' -import { guessProblem } from '../guessProblem' +import { guessProblem } from '../errorLoadingScreenHelpers' +import type { ConnectOptions } from '../connect' +import { downloadPacketsReplay, packetsRecordingState, replayLogger } from '../packetsReplay/packetsReplayLegacy' +import { getProxyDetails } from '../microsoftAuthflow' +import { downloadAutoCapturedPackets, getLastAutoCapturedPackets } from '../mineflayer/plugins/packetsRecording' +import { appQueryParams } from '../appParams' import AppStatus from './AppStatus' import DiveTransition from './DiveTransition' import { useDidUpdateEffect } from './utils' import { useIsModalActive } from './utilsApp' import Button from './Button' +import { updateAuthenticatedAccountData, updateLoadedServerData, AuthenticatedAccount } from './serversStorage' +import { showOptionsModal } from './SelectOption' +import LoadingChunks from './LoadingChunks' +import MessageFormattedString from './MessageFormattedString' const initialState = { status: '', @@ -17,30 +24,94 @@ const initialState = { descriptionHint: '', isError: false, hideDots: false, + loadingChunksData: null as null | Record, + loadingChunksDataPlayerChunk: null as null | { x: number, z: number }, + isDisplaying: false, + minecraftJsonMessage: null as null | Record, + showReconnect: false } export const appStatusState = proxy(initialState) -const resetState = () => { +export const resetAppStatusState = () => { Object.assign(appStatusState, initialState) } export const lastConnectOptions = { - value: null as any | null + value: null as ConnectOptions | null +} +globalThis.lastConnectOptions = lastConnectOptions + +const saveReconnectOptions = (options: ConnectOptions) => { + sessionStorage.setItem('reconnectOptions', JSON.stringify({ + value: options, + timestamp: Date.now() + })) +} + +export const reconnectReload = () => { + if (lastConnectOptions.value) { + saveReconnectOptions(lastConnectOptions.value) + window.location.reload() + } +} + +export const quickDevReconnect = () => { + if (!lastConnectOptions.value) { + return + } + + resetAppStatusState() + window.dispatchEvent(new window.CustomEvent('connect', { + detail: lastConnectOptions.value + })) } export default () => { - const { isError, lastStatus, maybeRecoverable, status, hideDots, descriptionHint } = useSnapshot(appStatusState) + const lastState = useRef(JSON.parse(JSON.stringify(appStatusState))) + const currentState = useSnapshot(appStatusState) + const { active: replayActive } = useSnapshot(packetsRecordingState) const isOpen = useIsModalActive('app-status') + if (isOpen) { + lastState.current = JSON.parse(JSON.stringify(currentState)) + } + + const usingState = (isOpen ? currentState : lastState.current) as typeof currentState + const { isError, lastStatus, maybeRecoverable, status, hideDots, descriptionHint, loadingChunksData, loadingChunksDataPlayerChunk, minecraftJsonMessage, showReconnect } = usingState + useDidUpdateEffect(() => { // todo play effect only when world successfully loaded if (!isOpen) { - const divingElem: HTMLElement = document.querySelector('#viewer-canvas')! - divingElem.style.animationName = 'dive-animation' - divingElem.parentElement!.style.perspective = '1200px' - divingElem.onanimationend = () => { - divingElem.parentElement!.style.perspective = '' - divingElem.onanimationend = null + const startDiveAnimation = (divingElem: HTMLElement) => { + divingElem.style.animationName = 'dive-animation' + divingElem.parentElement!.style.perspective = '1200px' + divingElem.onanimationend = () => { + divingElem.parentElement!.style.perspective = '' + divingElem.onanimationend = null + } + } + + const divingElem = document.querySelector('#viewer-canvas') + let observer: MutationObserver | null = null + if (divingElem) { + startDiveAnimation(divingElem as HTMLElement) + } else { + observer = new MutationObserver((mutations) => { + const divingElem = document.querySelector('#viewer-canvas') + if (divingElem) { + startDiveAnimation(divingElem as HTMLElement) + observer!.disconnect() + } + }) + observer.observe(document.body, { + childList: true, + subtree: true + }) + } + return () => { + if (observer) { + observer.disconnect() + } } } }, [isOpen]) @@ -48,47 +119,124 @@ export default () => { useEffect(() => { const controller = new AbortController() window.addEventListener('keyup', (e) => { + if ('input textarea select'.split(' ').includes((e.target as HTMLElement).tagName?.toLowerCase() ?? '')) return if (activeModalStack.at(-1)?.reactType !== 'app-status') return + // todo do only if reconnect is possible if (e.code !== 'KeyR' || !lastConnectOptions.value) return - resetState() - window.dispatchEvent(new window.CustomEvent('connect', { - detail: lastConnectOptions.value - })) + quickDevReconnect() }, { signal: controller.signal }) return () => controller.abort() }, []) - return + const displayAuthButton = status.includes('This server appears to be an online server and you are providing no authentication.') + || JSON.stringify(minecraftJsonMessage ?? {}).toLowerCase().includes('authenticate') + const hasVpnText = (text: string) => text.includes('VPN') || text.includes('Proxy') + const displayVpnButton = hasVpnText(status) || (minecraftJsonMessage && hasVpnText(JSON.stringify(minecraftJsonMessage))) + const authReconnectAction = async () => { + let accounts = [] as AuthenticatedAccount[] + updateAuthenticatedAccountData(oldAccounts => { + accounts = oldAccounts + return oldAccounts + }) + + const account = await showOptionsModal('Choose account to connect with', [...accounts.map(account => account.username), 'Use other account']) + if (!account) return + lastConnectOptions.value!.authenticatedAccount = accounts.find(acc => acc.username === account) || true + quickDevReconnect() + } + + const lastAutoCapturedPackets = getLastAutoCapturedPackets() + const lockConnect = appQueryParams.lockConnect === 'true' + const wasDisconnected = showReconnect + let backAction = undefined as (() => void) | undefined + if (maybeRecoverable && (!lockConnect || !wasDisconnected)) { + backAction = () => { + if (!wasDisconnected) { + hideModal(undefined, undefined, { force: true }) + return + } + resetAppStatusState() + miscUiState.gameLoaded = false + miscUiState.loadedDataVersion = null + window.loadedData = undefined + if (activeModalStacks['main-menu']) { + insertActiveModalStack('main-menu') + if (activeModalStack.at(-1)?.reactType === 'app-status') { + hideModal(undefined, undefined, { force: true }) // workaround: hide loader that was shown on world loading + } + } else { + hideModal(undefined, undefined, { force: true }) + } + } + } + return { - resetState() - miscUiState.gameLoaded = false - miscUiState.loadedDataVersion = null - window.loadedData = undefined - if (activeModalStacks['main-menu']) { - insertActiveModalStack('main-menu') - if (activeModalStack.at(-1)?.reactType === 'app-status') { - hideModal(undefined, undefined, { force: true }) // workaround: hide loader that was shown on world loading - } - } else { - hideModal(undefined, undefined, { force: true }) - } - } : undefined} - // actionsSlot={ - //