Merge remote-tracking branch 'origin/next' into webgpu-true

This commit is contained in:
Vitaly Turovsky 2024-07-10 20:26:04 +03:00
commit 92afdf54fb
243 changed files with 11112 additions and 1090 deletions

View file

@ -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

View file

@ -96,5 +96,22 @@
"unicorn/filename-case": "off",
"max-depth": "off"
},
"overrides": [
{
"files": [
"*.js"
],
"rules": {
"space-before-function-paren": [
"error",
{
"anonymous": "always",
"named": "never",
"asyncArrow": "always"
}
]
}
}
],
"root": true
}

View file

@ -8,6 +8,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@master
- name: Setup Java JDK
uses: actions/setup-java@v1.4.3
with:
java-version: 17
java-package: jre
- name: Install pnpm
run: npm i -g pnpm@9.0.4
- uses: actions/setup-node@v4

View file

@ -1,4 +1,4 @@
name: Deploy to GitHub pages
name: Release
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
@ -17,6 +17,7 @@ jobs:
# - 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
- run: vercel build --token=${{ secrets.VERCEL_TOKEN }} --prod
- run: pnpm build-storybook

1
.gitignore vendored
View file

@ -17,5 +17,6 @@ out
.vercel
generated
storybook-static
server-jar
src/react/npmReactComponents.ts

View file

@ -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

View file

@ -21,7 +21,7 @@ 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
## 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 +37,7 @@ 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.
### Would be useful to have

View file

@ -1,9 +1,22 @@
FROM node:14-alpine
FROM node:18-alpine
# Without git installing the npm packages fails
RUN apk add git
RUN mkdir /app
WORKDIR /app
COPY . /app
RUN npm install
RUN npm run build
# install python and other dependencies
RUN apk add python3 make g++ cairo-dev pango-dev jpeg-dev giflib-dev librsvg-dev
# install pnpm
RUN npm i -g pnpm@9.0.4
RUN pnpm install
# only for prod
RUN pnpm run build
# ---
EXPOSE 8080
# uncomment for development
# EXPOSE 9090
# VOLUME /app/src
# VOLUME /app/prismarine-viewer
# ENTRYPOINT ["pnpm", "run", "run-all"]
# only for prod
ENTRYPOINT ["npm", "run", "prod-start"]

View file

@ -4,19 +4,20 @@
A true Minecraft client running in your browser! A port of the original game to the web, written in JavaScript using modern web technologies.
If you encounter any bugs or usability issues, please report them!
If you encounter any bugs or usability issues, please report them! For development, see [development](#development--debugging).
You can try this out at [mcraft.fun](https://mcraft.fun/), [pcm.gg](https://pcm.gg) (short link) [mcon.vercel.app](https://mcon.vercel.app/) or the GitHub pages deploy. Every commit from the `develop` (default) branch is deployed to [s.mcraft.fun](https://s.mcraft.fun/) - so it's usually newer, but might be less stable.
### Big Features
- Open any zip world file or even folder in read-write mode!
- Connect to cracked servers* (it's possible because of proxy servers, see below)
- Connect to Java servers running in both offline (cracked) and online mode* (it's possible because of proxy servers, see below)
- Singleplayer mode with simple world generations!
- Works offline
- Play with friends over internet! (P2P is powered by Peer.js discovery servers)
- First-class touch (mobile) & controller support
- Resource pack support
- Builtin JEI with recipes & guides for every item (also replaces creative inventory)
- 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)
@ -34,11 +35,13 @@ Zip files and folders are supported. Just drag and drop them into the browser wi
In case of opening zip files they are stored in your ram entirely, so there is a ~300mb file limit on IOS.
Whatever offline mode you used (zip, folder, just single player), you can always export world with the `/export` command typed in the game chat.
![docs-assets/singleplayer-future-city-1-10-2.jpg](./docs-assets/singleplayer-future-city-1-10-2.jpg)
### Servers
You can play almost on any server, supporting offline connections.
You can play almost on any Java server, vanilla servers are fully supported.
See the [Mineflayer](https://github.com/PrismarineJS/mineflayer) repo for the list of supported versions (should support majority of versions).
There is a builtin proxy, but you can also host a your one! Just clone the repo, run `pnpm i` (following CONTRIBUTING.MD) and run `pnpm prod-start`, then you can specify `http://localhost:8080` in the proxy field.
There is a builtin proxy, but you can also host your one! Just clone the repo, run `pnpm i` (following CONTRIBUTING.MD) and run `pnpm prod-start`, then you can specify `http://localhost:8080` in the proxy field.
MS account authentication will be supported soon.
### Rendering
@ -46,8 +49,9 @@ MS account authentication will be supported soon.
#### Three.js Renderer
- Uses WebGL2. Chunks are rendered using Geometry Buffers prepared by 4 mesher workers.
- Supports FXAA
- Doesn't support culling
- Entities & text rendering
- Supports resource packs
- Doesn't support occlusion culling
<!-- TODO proxy server communication graph -->
@ -63,9 +67,9 @@ There are many many settings, that are not exposed in the UI yet. You can find o
To open the console, press `F12`, or if you are on mobile, you can type `#debug` in the URL (browser address bar), it wont't reload the page, but you will see a button to open the console. This way you can change advanced settings and see all errors or warnings. Also this way you can access global variables (described below).
### Debugging
### Development & Debugging
It should be easy to build/start the project locally. See [CONTRIBUTING.MD](./CONTRIBUTING.md) for more info.
It should be easy to build/start the project locally. See [CONTRIBUTING.MD](./CONTRIBUTING.md) for more info. Also you can look at Dockerfile for reference.
There is world renderer playground ([link](https://mcon.vercel.app/playground.html)).
@ -109,10 +113,10 @@ Press `Y` to set query parameters to url of your current game state.
- `?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
<!-- - `?requiresAuth=true` - Show the Microsoft login screen on server connect. Useful for servers that require authentication (running in online mode) -->
- `?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`
@ -120,9 +124,13 @@ Press `Y` to set query parameters to url of your current game state.
### Notable Things that Power this Project
- [Mineflayer](https://github.com/PrismarineJS/mineflayer) - Handles all client-side communications with the server (including the builtin one) - forked
- [Flying Squid](https://github.com/prismarineJS/flying-squid) - The builtin server that makes single player possible! Here forked version is used.
- [Forked Flying Squid (Space Squid)](https://github.com/zardoy/space-squid) - The builtin offline server that makes single player & P2P possible!
- [Prismarine Provider Anvil](https://github.com/PrismarineJS/prismarine-provider-anvil) - Handles world loading (region format)
- [Prismarine Physics](https://github.com/PrismarineJS/prismarine-physics) - Does all the physics calculations
- [Minecraft Protocol](https://github.com/PrismarineJS/node-minecraft-protocol) - Makes connections to servers possible
- [Peer.js](https://peerjs.com/) - P2P networking (when you open to wan)
- [Three.js](https://threejs.org/) - Helping in 3D rendering
### Alternatives
- [https://github.com/ClassiCube/ClassiCube](ClassiCube - Better C# Rewrite) [DEMO](https://www.classicube.net/server/play/?warned=true)

View file

@ -1,9 +1,13 @@
# Minecraft React
Minecraft UI components for React.
```bash
yarn add minecraft-react
pnpm i minecraft-react
```
![demo](https://github-production-user-asset-6210df.s3.amazonaws.com/46503702/346295584-80f3ed4a-cab6-45d2-8896-5e20233cc9b1.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAVCODYLSA53PQK4ZA%2F20240706%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240706T195400Z&X-Amz-Expires=300&X-Amz-Signature=5b063823a57057c4042c15edd1db3edd107e00940fd0e66a2ba1df4e564a2809&X-Amz-SignedHeaders=host&actor_id=46503702&key_id=0&repo_id=432411890)
## Usage
```jsx
@ -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:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 KiB

After

Width:  |  Height:  |  Size: 513 KiB

Before After
Before After

View file

@ -15,9 +15,9 @@
"description": "One of the best servers here. Join now!"
},
{
"ip": "play.minemalia.com",
"ip": "sus.shhnowisnottheti.me",
"version": "1.18.2",
"description": "Only login with existing accounts."
"description": "Creative, your own 'boxes' (islands)"
}
]
}

View file

@ -1,4 +1,6 @@
/* eslint-disable max-nested-callbacks */
/// <reference types="cypress" />
import supportedVersions from '../../src/supportedVersions.mjs'
import { setOptions, cleanVisit, visit } from './shared'
// todo use ssl
@ -12,7 +14,7 @@ const compareRenderedFlatWorld = () => {
}
const testWorldLoad = () => {
cy.document().then({ timeout: 20_000 }, doc => {
return cy.document().then({ timeout: 25_000 }, doc => {
return new Cypress.Promise(resolve => {
doc.addEventListener('cypress-world-ready', resolve)
})
@ -22,7 +24,7 @@ const testWorldLoad = () => {
}
it('Loads & renders singleplayer', () => {
visit('/?singleplayer=1')
cleanVisit('/?singleplayer=1')
setOptions({
localServerOptions: {
generation: {
@ -36,7 +38,7 @@ it('Loads & renders singleplayer', () => {
testWorldLoad()
})
it('Joins to server', () => {
it('Joins to local flying-squid server', () => {
visit('/?ip=localhost&version=1.16.1')
window.localStorage.version = ''
// todo replace with data-test
@ -47,6 +49,45 @@ it('Joins to server', () => {
testWorldLoad()
})
it('Joins to local latest Java vanilla server', () => {
const version = supportedVersions.at(-1)!
cy.task('startServer', [version, 25_590]).then(() => {
visit('/?ip=localhost:25590&username=bot')
cy.get('[data-test-id="connect-qs"]').click()
testWorldLoad().then(() => {
let x = 0
let z = 0
cy.window().then((win) => {
x = win.bot.entity.position.x
z = win.bot.entity.position.z
})
cy.document().trigger('keydown', { code: 'KeyW' })
cy.wait(1500).then(() => {
cy.document().trigger('keyup', { code: 'KeyW' })
cy.window().then(async (win) => {
// eslint-disable-next-line prefer-destructuring
const bot: typeof __type_bot = win.bot
// todo use f3 stats instead
if (bot.entity.position.x === x && bot.entity.position.z === z) {
throw new Error('Player not moved')
}
bot.chat('Hello') // todo assert
bot.chat('/gamemode creative')
// bot.on('message', () => {
void bot.creative.setInventorySlot(bot.inventory.hotbarStart, new win.PrismarineItem(1, 1, 0))
// })
await bot.lookAt(bot.entity.position.offset(1, 0, 1))
}).then(() => {
cy.document().trigger('mousedown', { button: 2, isTrusted: true, force: true }) // right click
cy.document().trigger('mouseup', { button: 2, isTrusted: true, force: true })
cy.wait(1000)
})
})
})
})
})
it('Loads & renders zip world', () => {
cleanVisit()
cy.get('[data-test-id="select-file-folder"]').click({ shiftKey: true })
@ -54,9 +95,14 @@ it('Loads & renders zip world', () => {
testWorldLoad()
})
it.skip('Performance test', () => {
// select that world
// from -2 85 24
// await bot.loadPlugin(pathfinder.pathfinder)
// bot.pathfinder.goto(new pathfinder.goals.GoalXZ(28, -28))
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()
})

View file

@ -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'

View file

@ -2,6 +2,7 @@
import mcServer from 'flying-squid'
import defaultOptions from 'flying-squid/config/default-settings.json' assert { type: 'json' }
/** @type {Options} */
const serverOptions = {
...defaultOptions,
'online-mode': false,

View file

@ -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
}

8
cypress/plugins/ops.json Normal file
View file

@ -0,0 +1,8 @@
[
{
"uuid": "67128b5b-2e6b-3ad1-baa0-1b937b03e5c5",
"name": "bot",
"level": 4,
"bypassesPlayerLimit": false
}
]

View file

@ -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

View file

@ -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<null>((res) => {
waitOn({ resources: [`tcp:localhost:${port}`] }, () => {
setTimeout(() => res(null), coldStart ? 6500 : 2000) // todo retry instead of timeout
})
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View file

@ -60,6 +60,7 @@ const buildOptions = {
net: 'net-browserify',
assert: 'assert',
dns: './src/dns.js',
'yggdrasil': './src/yggdrasilReplacement.ts',
// todo write advancedAliases plugin
},
inject: [
@ -79,11 +80,15 @@ const buildOptions = {
loader: {
// todo use external or resolve issues with duplicating
'.png': 'dataurl',
'.svg': 'dataurl',
'.map': 'empty',
'.vert': 'text',
'.frag': 'text',
'.wgsl': 'text',
'.obj': 'text',
'.woff': 'dataurl',
'.woff2': 'dataurl',
'.ttf': 'dataurl',
},
write: false,
// todo would be better to enable?

View file

@ -14,7 +14,7 @@
</div>
<div>
<div style="font-size: calc(var(--font-size) * 1.8);color: lightgray;" class="title">Loading...</div>
<div style="font-size: var(--font-size);color: rgb(176, 176, 176);" class="subtitle">A true Minecraft client in your browser!</div>
<div style="font-size: var(--font-size);color: rgb(176, 176, 176);margin-top: 3px;text-align: center" class="subtitle">A true Minecraft client in your browser!</div>
</div>
</div>
`
@ -94,9 +94,7 @@
</head>
<body>
<div id="react-root"></div>
<div id="ui-root">
<pmui-playscreen id="play-screen" style="display: none;"></pmui-playscreen>
</div>
<div id="ui-root"></div>
<!-- inject script -->
</body>
</html>

View file

@ -1,5 +1,5 @@
{
"name": "prismarine-web-client",
"name": "minecraft-web-client",
"version": "0.0.0-dev",
"description": "A minecraft client running in a browser",
"scripts": {
@ -50,7 +50,7 @@
"@types/wicg-file-system-access": "^2023.10.2",
"@webgpu/types": "^0.1.40",
"@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",
@ -65,21 +65,21 @@
"esbuild-plugin-polyfill-node": "^0.3.0",
"express": "^4.18.2",
"filesize": "^10.0.12",
"flying-squid": "npm:@zardoy/flying-squid@^0.0.20",
"flying-squid": "npm:@zardoy/flying-squid@^0.0.33",
"fs-extra": "^11.1.1",
"google-drive-browserfs": "github:zardoy/browserfs#google-drive",
"iconify-icon": "^1.0.8",
"jszip": "^3.10.1",
"lodash-es": "^4.17.21",
"math.gl": "^4.0.0",
"minecraft-assets": "^1.12.2",
"minecraft-data": "3.65.0",
"minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol",
"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",
@ -104,6 +104,7 @@
"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": {
@ -117,12 +118,13 @@
"@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.6",
"contro-max": "^0.1.8",
"crypto-browserify": "^3.12.0",
"cypress": "^10.11.0",
"cypress-esbuild-preprocessor": "^1.0.2",
@ -133,7 +135,7 @@
"http-server": "^14.1.1",
"https-browserify": "^1.0.0",
"minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next",
"mineflayer": "github:PrismarineJS/mineflayer",
"mineflayer": "github:zardoy/mineflayer",
"mineflayer-pathfinder": "^2.4.4",
"npm-run-all": "^4.1.5",
"os-browserify": "^0.3.0",
@ -162,7 +164,7 @@
"prismarine-world": "github:zardoy/prismarine-world#next-era",
"minecraft-data": "3.65.0",
"prismarine-provider-anvil": "github:zardoy/prismarine-provider-anvil#everything",
"minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol",
"minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol#master",
"react": "^18.2.0",
"prismarine-chunk": "github:zardoy/prismarine-chunk"
},
@ -170,7 +172,9 @@
"ignoreDependencies": []
},
"patchedDependencies": {
"minecraft-protocol@1.47.0": "patches/minecraft-protocol@1.47.0.patch"
"minecraft-protocol@1.47.0": "patches/minecraft-protocol@1.47.0.patch",
"three@0.154.0": "patches/three@0.154.0.patch",
"pixelarticons@1.8.1": "patches/pixelarticons@1.8.1.patch"
}
},
"packageManager": "pnpm@9.0.4"

View file

@ -26,7 +26,7 @@
},
"module": "./dist/react/npmReactComponents.js",
"types": "./dist/react/npmReactComponents.d.ts",
"repository": "zardoy/prismarine-web-client",
"repository": "zardoy/minecraft-web-client",
"version": "0.0.0-dev",
"dependencies": {},
"peerDependencies": {

View file

@ -12,12 +12,12 @@ index c437ecf3a0e4ab5758a48538c714b7e9651bb5da..d9c9895ae8614550aa09ad60a396ac32
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
@ -34,7 +34,7 @@ index b9d21bab9faccd5dbf1975fc423fc55c73e906c5..99ffd76527b410e3a393181beb260108
+ // clearTimeout(loginTimeout)
+ // })
}
function onJoinServerResponse (err) {
diff --git a/src/client.js b/src/client.js
index c89375e32babbf3559655b1e95f6441b9a30796f..f24cd5dc8fa9a0a4000b184fb3c79590a3ad8b8a 100644
@ -74,7 +74,7 @@ index c89375e32babbf3559655b1e95f6441b9a30796f..f24cd5dc8fa9a0a4000b184fb3c79590
}
@@ -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
@ -83,7 +83,7 @@ index c89375e32babbf3559655b1e95f6441b9a30796f..f24cd5dc8fa9a0a4000b184fb3c79590
+ }
endSocket()
}
@@ -195,6 +206,8 @@ class Client extends EventEmitter {
serializer -> framer -> socket -> splitter -> deserializer */
if (this.serializer) {
@ -94,7 +94,7 @@ index c89375e32babbf3559655b1e95f6441b9a30796f..f24cd5dc8fa9a0a4000b184fb3c79590
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)
@ -106,7 +106,7 @@ index c89375e32babbf3559655b1e95f6441b9a30796f..f24cd5dc8fa9a0a4000b184fb3c79590
+ 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
@ -126,5 +126,63 @@ index 0a5821c32d735e11205a280aa5a503c13533dc14..94a49f661d922478b940d853169b6087
+ /** Can be used to prepare mc data on autoVersion (client.version has selected version) */
+ versionSelectedHook?: (client: Client) => Promise<void> | void
}
export class Server extends EventEmitter {
diff --git a/src/client/chat.js b/src/client/chat.js
index 5cad9954db13d7121ed0a03792c2304156cdf436..ffd7c7d6299ef54854e0923f8d5296bf2a58956b 100644
--- a/src/client/chat.js
+++ b/src/client/chat.js
@@ -111,7 +111,7 @@ module.exports = function (client, options) {
for (const player of packet.data) {
if (!player.chatSession) continue
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
}
@@ -127,7 +127,7 @@ module.exports = function (client, options) {
for (const player of packet.data) {
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
@@ -198,7 +198,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', {
plainMessage: packet.plainMessage,
@@ -363,7 +363,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
@@ -404,7 +404,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,
acknowledged
})
@@ -418,7 +418,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,

View file

@ -0,0 +1,27 @@
diff --git a/fonts/pixelart-icons-font.css b/fonts/pixelart-icons-font.css
index 3b2ebe839370d96bf93ef5ca94a827f07e49378d..103ab4d6b9f3b5c9f41d1407e3cbf4ac392fbf41 100644
--- a/fonts/pixelart-icons-font.css
+++ b/fonts/pixelart-icons-font.css
@@ -1,16 +1,13 @@
@font-face {
font-family: "pixelart-icons-font";
- src: url('pixelart-icons-font.eot?t=1711815892278'); /* IE9*/
- src: url('pixelart-icons-font.eot?t=1711815892278#iefix') format('embedded-opentype'), /* IE6-IE8 */
+ src:
url("pixelart-icons-font.woff2?t=1711815892278") format("woff2"),
url("pixelart-icons-font.woff?t=1711815892278") format("woff"),
url('pixelart-icons-font.ttf?t=1711815892278') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
- url('pixelart-icons-font.svg?t=1711815892278#pixelart-icons-font') format('svg'); /* iOS 4.1- */
}
[class^="pixelart-icons-font-"], [class*=" pixelart-icons-font-"] {
font-family: 'pixelart-icons-font' !important;
- font-size:24px;
font-style:normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@@ -503,4 +500,3 @@
.pixelart-icons-font-zap:before { content: "\ebe4"; }
.pixelart-icons-font-zoom-in:before { content: "\ebe5"; }
.pixelart-icons-font-zoom-out:before { content: "\ebe6"; }
-

View file

@ -0,0 +1,16 @@
diff --git a/examples/jsm/webxr/VRButton.js b/examples/jsm/webxr/VRButton.js
index 6856a21b17aa45d7922bbf776fd2d7e63c7a9b4e..0925b706f7629bd52f0bb5af469536af8f5fce2c 100644
--- a/examples/jsm/webxr/VRButton.js
+++ b/examples/jsm/webxr/VRButton.js
@@ -62,7 +62,10 @@ class VRButton {
// ('local' is always available for immersive sessions and doesn't need to
// be requested separately.)
- const sessionInit = { optionalFeatures: [ 'local-floor', 'bounded-floor', 'hand-tracking', 'layers' ] };
+ const sessionInit = {
+ optionalFeatures: ['local-floor', 'bounded-floor', 'layers'],
+ domOverlay: { root: document.body },
+ };
navigator.xr.requestSession( 'immersive-vr', sessionInit ).then( onSessionStarted );
} else {

384
pnpm-lock.yaml generated
View file

@ -12,14 +12,20 @@ overrides:
prismarine-world: github:zardoy/prismarine-world#next-era
minecraft-data: 3.65.0
prismarine-provider-anvil: github:zardoy/prismarine-provider-anvil#everything
minecraft-protocol: github:PrismarineJS/node-minecraft-protocol
minecraft-protocol: github:PrismarineJS/node-minecraft-protocol#master
react: ^18.2.0
prismarine-chunk: github:zardoy/prismarine-chunk
patchedDependencies:
minecraft-protocol@1.47.0:
hash: 2uxevyasyasdavsxuehfavgkjq
hash: 7otpchsbv7hxsuis4rrrwdtbve
path: patches/minecraft-protocol@1.47.0.patch
pixelarticons@1.8.1:
hash: cclg2qo6d4yjs4evj64nr2mbwa
path: patches/pixelarticons@1.8.1.patch
three@0.154.0:
hash: sj7ocb4p23jym6bkfgueanti2e
path: patches/three@0.154.0.patch
importers:
@ -62,8 +68,8 @@ importers:
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.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@zardoy/utils':
specifier: ^0.0.11
version: 0.0.11
@ -107,17 +113,14 @@ importers:
specifier: ^10.0.12
version: 10.0.12
flying-squid:
specifier: npm:@zardoy/flying-squid@^0.0.20
version: '@zardoy/flying-squid@0.0.20(encoding@0.1.13)'
specifier: npm:@zardoy/flying-squid@^0.0.33
version: '@zardoy/flying-squid@0.0.33(encoding@0.1.13)'
fs-extra:
specifier: ^11.1.1
version: 11.1.1
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
@ -134,8 +137,8 @@ importers:
specifier: 3.65.0
version: 3.65.0
minecraft-protocol:
specifier: github:PrismarineJS/node-minecraft-protocol
version: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(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/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13)
mineflayer-item-map-downloader:
specifier: github:zardoy/mineflayer-item-map-downloader
version: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7(encoding@0.1.13)
@ -144,19 +147,22 @@ importers:
version: 2.0.4
net-browserify:
specifier: github:zardoy/prismarinejs-net-browserify
version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070
version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/231ef1737a078e8cb51e8c695b48d7b43ce3bc53
node-gzip:
specifier: ^1.1.2
version: 1.1.2
peerjs:
specifier: ^1.5.0
version: 1.5.0
pixelarticons:
specifier: ^1.8.1
version: 1.8.1(patch_hash=cclg2qo6d4yjs4evj64nr2mbwa)
pretty-bytes:
specifier: ^6.1.1
version: 6.1.1
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/0228b5252f48a0d6ad7f36d7189851c427fbe8c4(minecraft-data@3.65.0)
prosemirror-example-setup:
specifier: ^1.2.2
version: 1.2.2
@ -223,6 +229,9 @@ importers:
vec3:
specifier: ^0.1.7
version: 0.1.8
wait-on:
specifier: ^7.2.0
version: 7.2.0(debug@4.3.4)
workbox-build:
specifier: ^7.0.0
version: 7.0.0(@types/babel__core@7.20.2)
@ -261,6 +270,9 @@ importers:
'@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
@ -277,7 +289,7 @@ importers:
specifier: ^1.0.0
version: 1.0.0
contro-max:
specifier: ^0.1.6
specifier: ^0.1.8
version: 0.1.8(typescript@5.5.0-beta)
crypto-browserify:
specifier: ^3.12.0
@ -308,10 +320,10 @@ importers:
version: 1.0.0
minecraft-inventory-gui:
specifier: github:zardoy/minecraft-inventory-gui#next
version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/5554c7ab0a74bce52aa5f5f04a48eb8d3b9ac65c(@types/react@18.2.20)(react@18.2.0)
version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/c50afc54e39817f7e4d313ce0f6fdaad71e7e4f4(@types/react@18.2.20)(react@18.2.0)
mineflayer:
specifier: github:PrismarineJS/mineflayer
version: https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/ec76468c8ac4c6232bad3c2b66d4160f95f58396(encoding@0.1.13)
specifier: github:zardoy/mineflayer
version: https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479(encoding@0.1.13)
mineflayer-pathfinder:
specifier: ^2.4.4
version: 2.4.4
@ -344,7 +356,7 @@ importers:
version: 3.0.0
three:
specifier: 0.154.0
version: 0.154.0
version: 0.154.0(patch_hash=sj7ocb4p23jym6bkfgueanti2e)
timers-browserify:
specifier: ^2.0.12
version: 2.0.12
@ -395,10 +407,10 @@ importers:
version: 1.3.6
prismarine-block:
specifier: github:zardoy/prismarine-block#next-era
version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0
version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8
prismarine-chunk:
specifier: github:zardoy/prismarine-chunk
version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0)
version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0)
prismarine-schematic:
specifier: ^1.2.0
version: 1.2.3
@ -416,7 +428,7 @@ importers:
version: 4.7.2
three-stdlib:
specifier: ^2.26.11
version: 2.28.5(three@0.154.0)
version: 2.28.5(three@0.154.0(patch_hash=sj7ocb4p23jym6bkfgueanti2e))
three.meshline:
specifier: ^1.3.0
version: 1.4.0
@ -1718,6 +1730,12 @@ packages:
'@gar/promisify@1.1.3':
resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==}
'@hapi/hoek@9.3.0':
resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
'@hapi/topo@5.1.0':
resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
'@humanwhocodes/config-array@0.11.11':
resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==}
engines: {node: '>=10.10.0'}
@ -1729,9 +1747,6 @@ packages:
'@humanwhocodes/object-schema@1.2.1':
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
'@iconify/types@2.0.0':
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
@ -2405,6 +2420,15 @@ packages:
'@rushstack/eslint-patch@1.4.0':
resolution: {integrity: sha512-cEjvTPU32OM9lUFegJagO0mRnIn+rbqrG89vV8/xLnLFX0DoR0r1oy5IlTga71Q7uT3Qus7qm7wgeiMT/+Irlg==}
'@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==}
@ -2811,15 +2835,12 @@ packages:
'@types/node@16.18.58':
resolution: {integrity: sha512-YGncyA25/MaVtQkjWW9r0EFBukZ+JulsLcVZBlGUfIb96OBMjkoRWwQo5IEWJ8Fj06Go3GHw+bjYDitv6BaGsA==}
'@types/node@20.11.19':
resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==}
'@types/node@20.12.8':
resolution: {integrity: sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==}
'@types/node@20.8.0':
resolution: {integrity: sha512-LzcWltT83s1bthcvjBmiBvGJiiUe84NWRHkw+ZV6Fr41z2FbIzvc815dk2nQ3RAKMuN2fkenM/z3Xv2QzEpYxQ==}
'@types/node@20.8.10':
resolution: {integrity: sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==}
'@types/normalize-package-data@2.4.2':
resolution: {integrity: sha512-lqa4UEhhv/2sjjIQgjX8B+RBjj47eo0mzGasklVJ78UKGQY1r0VpB9XHDaZZO9qzEFDdy4MrXLuEaSmPrPSe/A==}
@ -2904,6 +2925,9 @@ packages:
'@types/unist@3.0.2':
resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==}
'@types/wait-on@5.3.4':
resolution: {integrity: sha512-EBsPjFMrFlMbbUFf9D1Fp+PAB2TwmUn7a3YtHyD9RLuTIk1jDd8SxXVAoez2Ciy+8Jsceo2MYEYZzJ/DvorOKw==}
'@types/webxr@0.5.7':
resolution: {integrity: sha512-Rcgs5c2eNFnHp53YOjgtKfl/zWX1Y+uFGUwlSXrWcZWu3yhANRezmph4MninmqybUYT6g9ZE0aQ9QIdPkLR3Kg==}
@ -3081,17 +3105,17 @@ packages:
resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==}
engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'}
'@zardoy/flying-squid@0.0.20':
resolution: {integrity: sha512-WyejZS2Upzv86g6Ez5Z/4Pd0ea9tkFL2itAj24UNpO7fyzxuTN2Ag1Ouvh+MSkCloXhR4E/yoER2krHW8vzwBw==}
'@zardoy/flying-squid@0.0.33':
resolution: {integrity: sha512-zCgHinWrNbS4HugnA1GBMuKQ0rUemBg//b+XhefxKeGBg9ngk8UVlJoR6cCAaa67zjiauEq/rhnNKnA4V7vtuQ==}
engines: {node: '>=8'}
hasBin: true
'@zardoy/react-util@0.2.0':
resolution: {integrity: sha512-glABtx54mh4XSaK6BNALWE3mlshPjcPwPsRj/GnOXEA7WJY/6n43iJoukbaYF3758mGZRU5Fq6gklyFjBg0yHQ==}
'@zardoy/react-util@0.2.4':
resolution: {integrity: sha512-YRBbXi54QOgWGDSn3NLEMMGrWbfL/gn2khxO31HT0WPFB6IW2rSnB4hcy+S/nc+2D6PRNq4kQxGs4vTAe4a7Xg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
peerDependencies:
react: ^18.2.0
react-dom: ^18.0.0
react-dom: '>=18.0.0'
'@zardoy/utils@0.0.11':
resolution: {integrity: sha512-d6xBnSFCOa98HcL52xSBflJKjKpxfRhtr1eVexy89YujeCHSQhUMmSz9h07xyrulfW60k9tSeYH5reuqoh4l4w==}
@ -3317,9 +3341,6 @@ packages:
resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
engines: {node: '>=0.10.0'}
asap@1.0.0:
resolution: {integrity: sha512-Ej9qjcXY+8Tuy1cNqiwNMwFRXOy9UwgTeMA8LxreodygIPV48lx8PU1ecFxb5ZeU1DpMKxiq6vGLTxcitWZPbA==}
asn1.js@5.4.1:
resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==}
@ -3403,6 +3424,9 @@ packages:
axios@0.21.4:
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
axios@1.7.2:
resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==}
babel-core@7.0.0-bridge.0:
resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==}
peerDependencies:
@ -4208,8 +4232,8 @@ packages:
devlop@1.1.0:
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687:
resolution: {tarball: https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687}
diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015:
resolution: {tarball: https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015}
version: 1.3.0
diff-sequences@29.6.3:
@ -4658,12 +4682,6 @@ packages:
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
engines: {node: '>= 0.6'}
event-promise@0.0.1:
resolution: {integrity: sha512-ouEmk2N0BalybPM0zmj3RHE93AX4p9hAIHZfbbqxolLChqCB6pcLDbYH6zZ8TaiFWImPHfs5kFnNpA0u9RdEaQ==}
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'}
@ -5317,9 +5335,6 @@ packages:
hyphenate-style-name@1.0.4:
resolution: {integrity: sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==}
iconify-icon@1.0.8:
resolution: {integrity: sha512-jvbUKHXf8EnGGArmhlP2IG8VqQLFFyTvTqb9LVL2TKTh7/eCCD1o2HHE9thpbJJb6B8hzhcFb6rOKhvo7reNKA==}
iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
@ -5739,8 +5754,11 @@ packages:
jimp@0.10.3:
resolution: {integrity: sha512-meVWmDMtyUG5uYjFkmzu0zBgnCvvxwWNi27c4cg55vWNVC9ES4Lcwb+ogx+uBBQE3Q+dLKjXaLl0JVW+nUNwbQ==}
jose@4.15.4:
resolution: {integrity: sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==}
joi@17.13.1:
resolution: {integrity: sha512-vaBlIKCyo4FCUtCm7Eu4QZd/q02bWcxfUO6YSXAZOWF6gzcLBeba8kwotUdYJjDLW8Cz8RywsSOqiNJZW0mNvg==}
jose@4.15.5:
resolution: {integrity: sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==}
jpeg-js@0.3.7:
resolution: {integrity: sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==}
@ -6287,8 +6305,8 @@ packages:
minecraft-folder-path@1.2.0:
resolution: {integrity: sha512-qaUSbKWoOsH9brn0JQuBhxNAzTDMwrOXorwuRxdJKKKDYvZhtml+6GVCUrY5HRiEsieBEjCUnhVpDuQiKsiFaw==}
minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/5554c7ab0a74bce52aa5f5f04a48eb8d3b9ac65c:
resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/5554c7ab0a74bce52aa5f5f04a48eb8d3b9ac65c}
minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/c50afc54e39817f7e4d313ce0f6fdaad71e7e4f4:
resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/c50afc54e39817f7e4d313ce0f6fdaad71e7e4f4}
version: 1.0.1
minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc:
@ -6314,8 +6332,8 @@ packages:
resolution: {integrity: sha512-QMMNPx4IyZE7ydAzjvGLQLCnQNUOfkk1qVZKxTTS9q3qPTAewz4GhsVUBtbQ8LSbHthe5RcQ1Sgxs4wlIma/Qw==}
engines: {node: '>=18'}
mineflayer@https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/ec76468c8ac4c6232bad3c2b66d4160f95f58396:
resolution: {tarball: https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/ec76468c8ac4c6232bad3c2b66d4160f95f58396}
mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479:
resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479}
version: 4.20.1
engines: {node: '>=18'}
@ -6479,8 +6497,8 @@ packages:
nested-error-stacks@2.1.1:
resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==}
net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070:
resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070}
net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/231ef1737a078e8cb51e8c695b48d7b43ce3bc53:
resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/231ef1737a078e8cb51e8c695b48d7b43ce3bc53}
version: 0.2.4
nice-try@1.0.5:
@ -6900,6 +6918,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
@ -6997,18 +7018,20 @@ packages:
minecraft-data: 3.65.0
prismarine-registry: ^1.1.0
prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0:
resolution: {tarball: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0}
prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8:
resolution: {tarball: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8}
version: 1.17.1
prismarine-chat@1.10.1:
resolution: {integrity: sha512-XukYcuueuhDxzEXG7r8BZyt6jOObrPPB4JESCgb+/XenB9nExoSHF8eTQWWj8faKPLqm1dRQaYwFJlNBlJZJUw==}
prismarine-chat@1.9.1:
resolution: {integrity: sha512-x7WWa5MNhiLZSO6tw+YyKpzquFZ+DNISVgiV6K3SU0GsishMXe+nto02WhF/4AuFerKdugm9u1d/r4C4zSkJOg==}
prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3:
resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3}
version: 1.35.0
engines: {node: '>=14'}
prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16:
resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16}
prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/cea0b6c792d7dcbb69dfd20fa48be5fd60ce83ef:
resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/cea0b6c792d7dcbb69dfd20fa48be5fd60ce83ef}
version: 1.35.0
engines: {node: '>=14'}
@ -7027,9 +7050,9 @@ packages:
prismarine-physics@1.8.0:
resolution: {integrity: sha512-gbM+S+bmVtOKVv+Z0WGaHMeEeBHISIDsRDRlv8sr0dex3ZJRhuq8djA02CBreguXtI18ZKh6q3TSj2qDr45NHA==}
prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29:
resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29}
version: 2.7.0
prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/0228b5252f48a0d6ad7f36d7189851c427fbe8c4:
resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/0228b5252f48a0d6ad7f36d7189851c427fbe8c4}
version: 2.8.0
prismarine-realms@1.3.2:
resolution: {integrity: sha512-5apl9Ru8veTj5q2OozRc4GZOuSIcs3yY4UEtALiLKHstBe8bRw8vNlaz4Zla3jsQ8yP/ul1b1IJINTRbocuA6g==}
@ -7048,9 +7071,9 @@ packages:
prismarine-windows@2.9.0:
resolution: {integrity: sha512-fm4kOLjGFPov7TEJRmXHoiPabxIQrG36r2mDjlNxfkcLfMHFb3/1ML6mp4iRQa7wL0GK4DIAyiBqCWoeWDxARg==}
prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465:
resolution: {tarball: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465}
version: 3.6.2
prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7:
resolution: {tarball: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7}
version: 3.6.3
engines: {node: '>=8.0.0'}
process-nextick-args@2.0.1:
@ -7085,9 +7108,6 @@ packages:
resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==}
engines: {node: '>=10'}
promise@5.0.0:
resolution: {integrity: sha512-N2BfLz0Sigf7rsm5NnItRwTNqEDUF2ephwEXTcOAf2cO9NwZ9TnIjOmnQNtC0r70CV0S1+uc9mSMmFH7gxk87Q==}
prompts@2.4.2:
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
engines: {node: '>= 6'}
@ -7155,9 +7175,8 @@ packages:
proxy-from-env@1.0.0:
resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==}
proxy-middleware@0.15.0:
resolution: {integrity: sha512-EGCG8SeoIRVMhsqHQUdDigB2i7qU7fCsWASwn54+nPutYO8n4q6EiwMzyfWlC+dzRFExP+kvcnDFdBDHoZBU7Q==}
engines: {node: '>=0.8.0'}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
psl@1.9.0:
resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
@ -7299,6 +7318,12 @@ packages:
react-fast-compare@3.2.2:
resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==}
react-hook-form@7.52.0:
resolution: {integrity: sha512-mJX506Xc6mirzLsmXUJyqlAI3Kj9Ph2RhplYhUVffeOQSnubK2uVqBFOBJmvKikvbFV91pxVXmDiR+QMF19x6A==}
engines: {node: '>=12.22.0'}
peerDependencies:
react: ^18.2.0
react-inspector@6.0.2:
resolution: {integrity: sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==}
peerDependencies:
@ -8752,6 +8777,11 @@ packages:
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==}
@ -10318,6 +10348,12 @@ snapshots:
'@gar/promisify@1.1.3':
optional: true
'@hapi/hoek@9.3.0': {}
'@hapi/topo@5.1.0':
dependencies:
'@hapi/hoek': 9.3.0
'@humanwhocodes/config-array@0.11.11':
dependencies:
'@humanwhocodes/object-schema': 1.2.1
@ -10330,8 +10366,6 @@ snapshots:
'@humanwhocodes/object-schema@1.2.1': {}
'@iconify/types@2.0.0': {}
'@isaacs/cliui@8.0.2':
dependencies:
string-width: 5.1.2
@ -11159,6 +11193,14 @@ snapshots:
'@rushstack/eslint-patch@1.4.0': {}
'@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': {}
@ -11830,8 +11872,7 @@ snapshots:
magic-string: 0.25.9
string.prototype.matchall: 4.0.10
'@tootallnate/once@2.0.0':
optional: true
'@tootallnate/once@2.0.0': {}
'@tweenjs/tween.js@18.6.4': {}
@ -11861,7 +11902,7 @@ snapshots:
'@types/body-parser@1.19.3':
dependencies:
'@types/connect': 3.4.36
'@types/node': 20.8.0
'@types/node': 20.12.8
'@types/chai-subset@1.3.3':
dependencies:
@ -11871,7 +11912,7 @@ snapshots:
'@types/connect@3.4.36':
dependencies:
'@types/node': 20.8.10
'@types/node': 20.12.8
'@types/cookie@0.4.1': {}
@ -11907,7 +11948,7 @@ snapshots:
'@types/express-serve-static-core@4.17.37':
dependencies:
'@types/node': 20.8.0
'@types/node': 20.12.8
'@types/qs': 6.9.8
'@types/range-parser': 1.2.5
'@types/send': 0.17.2
@ -11926,7 +11967,7 @@ snapshots:
'@types/glob@7.2.0':
dependencies:
'@types/minimatch': 5.1.2
'@types/node': 20.8.0
'@types/node': 20.12.8
'@types/graceful-fs@4.1.7':
dependencies:
@ -11985,16 +12026,12 @@ snapshots:
'@types/node@16.18.58': {}
'@types/node@20.11.19':
'@types/node@20.12.8':
dependencies:
undici-types: 5.26.5
'@types/node@20.8.0': {}
'@types/node@20.8.10':
dependencies:
undici-types: 5.26.5
'@types/normalize-package-data@2.4.2': {}
'@types/offscreencanvas@2019.7.2': {}
@ -12051,7 +12088,7 @@ snapshots:
dependencies:
'@types/http-errors': 2.0.2
'@types/mime': 3.0.2
'@types/node': 20.8.0
'@types/node': 20.12.8
'@types/sinonjs__fake-timers@8.1.1': {}
@ -12083,6 +12120,10 @@ snapshots:
'@types/unist@3.0.2': {}
'@types/wait-on@5.3.4':
dependencies:
'@types/node': 20.12.8
'@types/webxr@0.5.7': {}
'@types/wicg-file-system-access@2023.10.2': {}
@ -12099,7 +12140,7 @@ snapshots:
'@types/yauzl@2.10.3':
dependencies:
'@types/node': 20.11.19
'@types/node': 20.12.8
optional: true
'@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)':
@ -12319,32 +12360,33 @@ snapshots:
'@types/emscripten': 1.39.8
tslib: 1.14.1
'@zardoy/flying-squid@0.0.20(encoding@0.1.13)':
'@zardoy/flying-squid@0.0.33(encoding@0.1.13)':
dependencies:
'@tootallnate/once': 2.0.0
change-case: 4.1.2
colors: 1.4.0
diamond-square: https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687
diamond-square: https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015
emit-then: 2.0.0
event-promise: 0.0.1
exit-hook: 2.2.1
flatmap: 0.0.3
long: 5.2.3
minecraft-data: 3.65.0
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13)
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(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-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/cea0b6c792d7dcbb69dfd20fa48be5fd60ce83ef(minecraft-data@3.65.0)
prismarine-entity: 2.3.1
prismarine-item: 1.14.0
prismarine-nbt: 2.5.0
prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0)
prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/0228b5252f48a0d6ad7f36d7189851c427fbe8c4(minecraft-data@3.65.0)
prismarine-windows: 2.9.0
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7
rambda: 9.2.0
random-seed: 0.3.0
range: 0.0.3
readline: 1.3.0
sanitize-filename: 1.6.3
typed-emitter: 1.4.0
uuid-1345: 1.0.2
vec3: 0.1.8
@ -12354,11 +12396,12 @@ snapshots:
- encoding
- supports-color
'@zardoy/react-util@0.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
'@zardoy/react-util@0.2.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
classnames: 2.5.1
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-hook-form: 7.52.0(react@18.2.0)
'@zardoy/utils@0.0.11':
dependencies:
@ -12592,8 +12635,6 @@ snapshots:
arrify@1.0.1: {}
asap@1.0.0: {}
asn1.js@5.4.1:
dependencies:
bn.js: 4.12.0
@ -12668,6 +12709,14 @@ snapshots:
transitivePeerDependencies:
- debug
axios@1.7.2(debug@4.3.4):
dependencies:
follow-redirects: 1.15.6(debug@4.3.4)
form-data: 4.0.0
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
babel-core@7.0.0-bridge.0(@babel/core@7.22.11):
dependencies:
'@babel/core': 7.22.11
@ -13686,10 +13735,11 @@ snapshots:
dependencies:
dequal: 2.0.3
diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687:
diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015:
dependencies:
minecraft-data: 3.65.0
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0)
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/cea0b6c792d7dcbb69dfd20fa48be5fd60ce83ef(minecraft-data@3.65.0)
prismarine-registry: 1.7.0
random-seed: 0.3.0
vec3: 0.1.8
@ -14413,20 +14463,6 @@ snapshots:
etag@1.8.1: {}
event-promise@0.0.1:
dependencies:
promise: 5.0.0
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: {}
@ -15254,10 +15290,6 @@ snapshots:
hyphenate-style-name@1.0.4: {}
iconify-icon@1.0.8:
dependencies:
'@iconify/types': 2.0.0
iconv-lite@0.4.24:
dependencies:
safer-buffer: 2.1.2
@ -15664,7 +15696,15 @@ snapshots:
core-js: 3.32.1
regenerator-runtime: 0.13.11
jose@4.15.4: {}
joi@17.13.1:
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
jose@4.15.5: {}
jpeg-js@0.3.7: {}
@ -16353,16 +16393,16 @@ snapshots:
minecraft-folder-path@1.2.0: {}
minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/5554c7ab0a74bce52aa5f5f04a48eb8d3b9ac65c(@types/react@18.2.20)(react@18.2.0):
minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/c50afc54e39817f7e4d313ce0f6fdaad71e7e4f4(@types/react@18.2.20)(react@18.2.0):
dependencies:
valtio: 1.11.2(@types/react@18.2.20)(react@18.2.0)
transitivePeerDependencies:
- '@types/react'
- react
minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13):
minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13):
dependencies:
'@types/readable-stream': 4.0.10
'@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)
@ -16373,7 +16413,7 @@ snapshots:
minecraft-folder-path: 1.2.0
node-fetch: 2.7.0(encoding@0.1.13)
node-rsa: 0.4.2
prismarine-auth: 2.4.1(encoding@0.1.13)
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)
@ -16419,7 +16459,7 @@ snapshots:
mineflayer-pathfinder@2.4.4:
dependencies:
minecraft-data: 3.65.0
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8
prismarine-entity: 2.3.1
prismarine-item: 1.14.0
prismarine-nbt: 2.2.1
@ -16429,11 +16469,11 @@ snapshots:
mineflayer@4.20.1(encoding@0.1.13):
dependencies:
minecraft-data: 3.65.0
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13)
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13)
prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0)
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0
prismarine-chat: 1.9.1
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0)
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8
prismarine-chat: 1.10.1
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0)
prismarine-entity: 2.3.1
prismarine-item: 1.14.0
prismarine-nbt: 2.5.0
@ -16441,7 +16481,7 @@ snapshots:
prismarine-recipe: 1.3.1(prismarine-registry@1.7.0)
prismarine-registry: 1.7.0
prismarine-windows: 2.9.0
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7
protodef: 1.15.0
typed-emitter: 1.4.0
vec3: 0.1.8
@ -16449,14 +16489,14 @@ snapshots:
- encoding
- supports-color
mineflayer@https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/ec76468c8ac4c6232bad3c2b66d4160f95f58396(encoding@0.1.13):
mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479(encoding@0.1.13):
dependencies:
minecraft-data: 3.65.0
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13)
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13)
prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0)
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0
prismarine-chat: 1.9.1
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0)
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8
prismarine-chat: 1.10.1
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0)
prismarine-entity: 2.3.1
prismarine-item: 1.14.0
prismarine-nbt: 2.5.0
@ -16464,7 +16504,7 @@ snapshots:
prismarine-recipe: 1.3.1(prismarine-registry@1.7.0)
prismarine-registry: 1.7.0
prismarine-windows: 2.9.0
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7
protodef: 1.15.0
typed-emitter: 1.4.0
vec3: 0.1.8
@ -16646,7 +16686,7 @@ snapshots:
nested-error-stacks@2.1.1: {}
net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070:
net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/231ef1737a078e8cb51e8c695b48d7b43ce3bc53:
dependencies:
body-parser: 1.20.2
express: 4.18.2
@ -17108,6 +17148,8 @@ snapshots:
pirates@4.0.6: {}
pixelarticons@1.8.1(patch_hash=cclg2qo6d4yjs4evj64nr2mbwa): {}
pixelmatch@4.0.2:
dependencies:
pngjs: 3.4.0
@ -17215,11 +17257,11 @@ snapshots:
minecraft-data: 3.65.0
prismarine-registry: 1.7.0
prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0:
prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8:
dependencies:
minecraft-data: 3.65.0
prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0)
prismarine-chat: 1.9.1
prismarine-chat: 1.10.1
prismarine-item: 1.14.0
prismarine-nbt: 2.5.0
prismarine-registry: 1.7.0
@ -17230,17 +17272,23 @@ snapshots:
prismarine-nbt: 2.5.0
prismarine-registry: 1.7.0
prismarine-chat@1.9.1:
dependencies:
mojangson: 2.0.4
prismarine-item: 1.14.0
prismarine-nbt: 2.5.0
prismarine-registry: 1.7.0
prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0):
prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0):
dependencies:
prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0)
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8
prismarine-nbt: 2.5.0
prismarine-registry: 1.7.0
smart-buffer: 4.2.0
uint4: 0.1.2
vec3: 0.1.8
xxhash-wasm: 0.4.2
transitivePeerDependencies:
- minecraft-data
prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/cea0b6c792d7dcbb69dfd20fa48be5fd60ce83ef(minecraft-data@3.65.0):
dependencies:
prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0)
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8
prismarine-nbt: 2.5.0
prismarine-registry: 1.7.0
smart-buffer: 4.2.0
@ -17276,10 +17324,12 @@ snapshots:
prismarine-nbt: 2.5.0
vec3: 0.1.8
prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0):
prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/0228b5252f48a0d6ad7f36d7189851c427fbe8c4(minecraft-data@3.65.0):
dependencies:
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0)
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0)
prismarine-nbt: 2.5.0
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7
uint4: 0.1.2
vec3: 0.1.8
transitivePeerDependencies:
@ -17305,9 +17355,9 @@ snapshots:
prismarine-schematic@1.2.3:
dependencies:
minecraft-data: 3.65.0
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8
prismarine-nbt: 2.2.1
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7
vec3: 0.1.8
prismarine-windows@2.9.0:
@ -17316,7 +17366,7 @@ snapshots:
prismarine-registry: 1.7.0
typed-emitter: 2.1.0
prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465:
prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7:
dependencies:
vec3: 0.1.8
@ -17339,10 +17389,6 @@ snapshots:
retry: 0.12.0
optional: true
promise@5.0.0:
dependencies:
asap: 1.0.0
prompts@2.4.2:
dependencies:
kleur: 3.0.3
@ -17460,7 +17506,7 @@ snapshots:
proxy-from-env@1.0.0: {}
proxy-middleware@0.15.0: {}
proxy-from-env@1.1.0: {}
psl@1.9.0: {}
@ -17631,6 +17677,10 @@ snapshots:
react-fast-compare@3.2.2: {}
react-hook-form@7.52.0(react@18.2.0):
dependencies:
react: 18.2.0
react-inspector@6.0.2(react@18.2.0):
dependencies:
react: 18.2.0
@ -18260,7 +18310,7 @@ snapshots:
dependencies:
'@types/three': 0.156.0
skinview-utils: 0.7.1
three: 0.154.0
three: 0.154.0(patch_hash=sj7ocb4p23jym6bkfgueanti2e)
slash@3.0.0: {}
@ -18729,7 +18779,7 @@ snapshots:
dependencies:
any-promise: 1.3.0
three-stdlib@2.28.5(three@0.154.0):
three-stdlib@2.28.5(three@0.154.0(patch_hash=sj7ocb4p23jym6bkfgueanti2e)):
dependencies:
'@types/draco3d': 1.4.7
'@types/offscreencanvas': 2019.7.2
@ -18737,11 +18787,11 @@ snapshots:
draco3d: 1.5.6
fflate: 0.6.10
potpack: 1.0.2
three: 0.154.0
three: 0.154.0(patch_hash=sj7ocb4p23jym6bkfgueanti2e)
three.meshline@1.4.0: {}
three@0.154.0: {}
three@0.154.0(patch_hash=sj7ocb4p23jym6bkfgueanti2e): {}
throttle-debounce@3.0.1: {}
@ -19291,6 +19341,16 @@ snapshots:
w3c-keyname@2.2.8: {}
wait-on@7.2.0(debug@4.3.4):
dependencies:
axios: 1.7.2(debug@4.3.4)
joi: 17.13.1
lodash: 4.17.21
minimist: 1.2.8
rxjs: 7.8.1
transitivePeerDependencies:
- debug
walker@1.0.8:
dependencies:
makeerror: 1.0.12

View file

@ -6,6 +6,7 @@ import path from 'path'
import { fileURLToPath } from 'url'
import fs from 'fs'
import { dynamicMcDataFiles } from './buildMesherConfig.mjs'
import { mesherSharedPlugins } from '../scripts/esbuildPlugins.mjs'
const allowedBundleFiles = ['legacy', 'versions', 'protocolVersions', 'features']
@ -34,6 +35,7 @@ const buildOptions = {
'process.env.BROWSER': '"true"',
},
plugins: [
...mesherSharedPlugins,
{
name: 'external-json',
setup(build) {

View file

@ -1,6 +0,0 @@
module.exports = {
dispose3 (o) {
o.geometry?.dispose()
o.dispose?.()
}
}

View file

@ -2,7 +2,6 @@
import * as THREE from 'three'
import * as TWEEN from '@tweenjs/tween.js'
import * as Entity from './entity/EntityMesh'
import { dispose3 } from './dispose'
import nbt from 'prismarine-nbt'
import EventEmitter from 'events'
import { PlayerObject, PlayerAnimation } from 'skinview3d'
@ -14,6 +13,7 @@ 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
@ -94,13 +94,14 @@ function getEntityMesh(entity, scene, options, overrides) {
export class Entities extends EventEmitter {
constructor(scene) {
super()
/** @type {THREE.Scene} */
this.scene = scene
this.entities = {}
this.entitiesOptions = {}
this.debugMode = 'none'
this.onSkinUpdate = () => { }
this.clock = new THREE.Clock()
this.visible = true
this.rendering = true
this.itemsTexture = null
this.getItemUv = undefined
}
@ -108,7 +109,7 @@ export class Entities extends EventEmitter {
clear() {
for (const mesh of Object.values(this.entities)) {
this.scene.remove(mesh)
dispose3(mesh)
disposeObject(mesh)
}
this.entities = {}
}
@ -125,10 +126,14 @@ export class Entities extends EventEmitter {
}
}
setVisible(visible, /** @type {THREE.Object3D?} */entity = null) {
this.visible = visible
for (const mesh of entity ? [entity] : Object.values(this.entities)) {
mesh.visible = visible
setRendering(rendering, /** @type {THREE.Object3D?} */entity = null) {
this.rendering = rendering
for (const ent of entity ? [entity] : Object.values(this.entities)) {
if (rendering) {
if (!this.scene.children.includes(ent)) this.scene.add(ent)
} else {
this.scene.remove(ent)
}
}
}
@ -262,11 +267,15 @@ export class Entities extends EventEmitter {
}
displaySimpleText(jsonLike) {
parseEntityLabel(jsonLike) {
if (!jsonLike) return
const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike)
const text = flat(parsed).map(x => x.text)
return text.join('')
try {
const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike)
const text = flat(parsed).map(x => x.text)
return text.join('')
} catch (err) {
return jsonLike
}
}
update(/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) {
@ -392,7 +401,7 @@ export class Entities extends EventEmitter {
this.updatePlayerSkin(entity.id, '', overrides?.texture || stevePng)
}
this.setDebugMode(this.debugMode, group)
this.setVisible(this.visible, group)
this.setRendering(this.rendering, group)
}
//@ts-ignore
@ -405,7 +414,7 @@ export class Entities extends EventEmitter {
}
}
// not player
const displayText = entity.metadata?.[3] && this.displaySimpleText(entity.metadata[2])
const displayText = entity.metadata?.[3] && this.parseEntityLabel(entity.metadata[2])
if (entity.name !== 'player' && displayText) {
addNametag({ ...entity, username: displayText }, this.entitiesOptions, this.entities[entity.id].children.find(c => c.name === 'mesh'))
}
@ -456,7 +465,7 @@ export class Entities extends EventEmitter {
if (e.additionalCleanup) e.additionalCleanup()
this.emit('remove', entity)
this.scene.remove(e)
dispose3(e)
disposeObject(e)
// todo dispose textures as well ?
delete this.entities[entity.id]
}

View file

@ -19,6 +19,29 @@ function sectionKey (x, y, z) {
return `${x},${y},${z}`
}
const batchMessagesLimit = 100
let queuedMessages = [] as any[]
let queueWaiting = false
const postMessage = (data, transferList = []) => {
queuedMessages.push({ data, transferList })
if (queuedMessages.length > batchMessagesLimit) {
drainQueue(0, batchMessagesLimit)
}
if (queueWaiting) return
queueWaiting = true
setTimeout(() => {
queueWaiting = false
drainQueue(0, queuedMessages.length)
})
}
function drainQueue (from, to) {
const messages = queuedMessages.slice(from, to)
global.postMessage(messages.map(m => m.data), messages.flatMap(m => m.transferList) as unknown as string)
queuedMessages = queuedMessages.slice(to)
}
function setSectionDirty (pos, value = true) {
const x = Math.floor(pos.x / 16) * 16
const y = Math.floor(pos.y / 16) * 16
@ -43,7 +66,7 @@ const softCleanup = () => {
world = new World(world.config.version)
}
self.onmessage = ({ data }) => {
const handleMessage = data => {
const globalVar: any = globalThis
if (data.type === 'mcData') {
@ -53,6 +76,7 @@ self.onmessage = ({ data }) => {
if (data.config) {
world ??= new World(data.config.version)
world.config = { ...world.config, ...data.config }
globalThis.world = world
}
if (data.type === 'mesherData') {
@ -80,6 +104,15 @@ self.onmessage = ({ data }) => {
}
}
self.onmessage = ({ data }) => {
if (Array.isArray(data)) {
data.forEach(handleMessage)
return
}
handleMessage(data)
}
setInterval(() => {
if (world === null || !blockStatesReady) return
@ -96,7 +129,7 @@ setInterval(() => {
//@ts-ignore
postMessage({ type: 'geometry', key, geometry }, transferable)
} else {
console.info('[mesher] Missing section', x, y, z)
// console.info('[mesher] Missing section', x, y, z)
}
const dirtyTimes = dirtySections.get(key)
if (!dirtyTimes) throw new Error('dirtySections.get(key) is falsy')

View file

@ -1,7 +1,9 @@
import { Vec3 } from 'vec3'
import type { BlockStatesOutput } from '../../prepare/modelsBuilder'
import { World } from './world'
import { Block } from 'prismarine-block'
import { WorldBlock as Block } from './world'
import legacyJson from '../../../../src/preflatMap.json'
import { versionToNumber } from '../../prepare/utils'
import { BlockType } from '../../../examples/shared'
import { MesherGeometryOutput } from './shared'
@ -48,6 +50,53 @@ function prepareTints (tints) {
})
}
const calculatedBlocksEntries = Object.entries(legacyJson.clientCalculatedBlocks)
export function preflatBlockCalculation (block: Block, world: World, position: Vec3) {
const type = calculatedBlocksEntries.find(([name, blocks]) => blocks.includes(block.name))?.[0]
if (!type) return
switch (type) {
case 'directional': {
const isSolidConnection = !block.name.includes('redstone') && !block.name.includes('tripwire')
const neighbors = [
world.getBlock(position.offset(0, 0, 1)),
world.getBlock(position.offset(0, 0, -1)),
world.getBlock(position.offset(1, 0, 0)),
world.getBlock(position.offset(-1, 0, 0))
]
// set needed props to true: east:'false',north:'false',south:'false',west:'false'
const props = {}
for (const [i, neighbor] of neighbors.entries()) {
const isConnectedToSolid = isSolidConnection ? (neighbor && !neighbor.transparent) : false
if (isConnectedToSolid || neighbor?.name === block.name) {
props[['south', 'north', 'east', 'west'][i]] = 'true'
}
}
return props
}
// case 'gate_in_wall': {}
case 'block_snowy': {
const aboveIsSnow = world.getBlock(position.offset(0, 1, 0))?.name === 'snow'
return {
snowy: `${aboveIsSnow}`
}
}
case 'door': {
// upper half matches lower in
const half = block.getProperties().half
if (half === 'upper') {
// copy other properties
const lower = world.getBlock(position.offset(0, -1, 0))
if (lower?.name === block.name) {
return {
...lower.getProperties(),
half: 'upper'
}
}
}
}
}
}
function tintToGl (tint) {
const r = (tint >> 16) & 0xff
const g = (tint >> 8) & 0xff
@ -267,9 +316,9 @@ function renderLiquid (world, cursor, texture, type, biome, water, attr) {
for (const pos of corners) {
const height = cornerHeights[pos[2] * 2 + pos[0]]
attr.t_positions.push(
(pos[0] ? 1 : 0) + (cursor.x & 15) - 8,
(pos[1] ? height : 0) + (cursor.y & 15) - 8,
(pos[2] ? 1 : 0) + (cursor.z & 15) - 8)
(pos[0] ? 0.999 : 0.001) + (cursor.x & 15) - 8,
(pos[1] ? height - 0.001 : 0.001) + (cursor.y & 15) - 8,
(pos[2] ? 0.999 : 0.001) + (cursor.z & 15) - 8)
attr.t_normals.push(...dir)
attr.t_uvs.push(pos[3] * su + u, pos[4] * sv * (pos[1] ? 1 : height) + v)
attr.t_colors.push(tint[0], tint[1], tint[2])
@ -426,7 +475,7 @@ function renderElement (world: World, cursor: Vec3, element, doAO: boolean, attr
const aos: number[] = []
const neighborPos = position.plus(new Vec3(...dir))
const baseLight = world.getLight(neighborPos) / 15
const baseLight = world.getLight(neighborPos, undefined, undefined, block.name) / 15
for (const pos of corners) {
let vertex = [
(pos[0] ? maxx : minx),
@ -543,7 +592,7 @@ export function getSectionGeometry (sx, sy, sz, world: World) {
for (cursor.z = sz; cursor.z < sz + 16; cursor.z++) {
for (cursor.x = sx; cursor.x < sx + 16; cursor.x++) {
const block = world.getBlock(cursor)!
if (block.name.includes('_sign')) {
if (block.name.includes('_sign') || block.name === 'sign') {
const key = `${cursor.x},${cursor.y},${cursor.z}`
const props: any = block.getProperties()
const facingRotationMap = {
@ -552,14 +601,33 @@ export function getSectionGeometry (sx, sy, sz, world: World) {
"west": 1,
"east": 3
}
const isWall = block.name.endsWith('wall_sign') || block.name.endsWith('hanging_sign')
const isWall = block.name.endsWith('wall_sign') || block.name.endsWith('wall_hanging_sign')
const isHanging = block.name.endsWith('hanging_sign')
attr.signs[key] = {
isWall,
isHanging,
rotation: isWall ? facingRotationMap[props.facing] : +props.rotation
}
}
const biome = block.biome.name
if (block.variant === undefined) {
let preflatRecomputeVariant = !!(block as any)._originalProperties
if (world.preflat) {
const patchProperties = preflatBlockCalculation(block, world, cursor)
if (patchProperties) {
//@ts-ignore
block._originalProperties ??= block._properties
//@ts-ignore
block._properties = { ...block._originalProperties, ...patchProperties }
preflatRecomputeVariant = true
} else {
//@ts-ignore
block._properties = block._originalProperties ?? block._properties
//@ts-ignore
block._originalProperties = undefined
}
}
if (block.variant === undefined || preflatRecomputeVariant) {
block.variant = getModelVariants(block)
}
@ -637,7 +705,7 @@ export function getSectionGeometry (sx, sy, sz, world: World) {
delete attr.t_uvs
attr.positions = new Float32Array(attr.positions) as any
attr.normals = new Float32Array(attr.normals) as any
attr.normals = new Int8Array(attr.normals) as any
attr.colors = new Float32Array(attr.colors) as any
attr.uvs = new Float32Array(attr.uvs) as any
@ -680,7 +748,7 @@ function matchProperties (block: Block, /* to match against */properties: Record
return true
}
function getModelVariants (block: import('prismarine-block').Block) {
function getModelVariants (block: Block) {
// air, cave_air, void_air and so on...
// full list of invisible & special blocks https://minecraft.wiki/w/Model#Blocks_and_fluids
if (block.name === '' || block.name === 'air' || block.name.endsWith('_air')) return []

View file

@ -1,96 +1,140 @@
import { test, expect } from 'vitest'
import { setup } from './mesherTester'
import minecraftData from 'minecraft-data'
import minecraftAssets from 'minecraft-assets'
const version = '1.18.1'
const version = minecraftAssets.versions.at(-1)
const addPositions = [
// [[0, 0, 0], 'diamond_block'],
[[1, 0, 0], 'stone'],
[[-1, 0, 0], 'stone'],
[[0, 1, 0], 'stone'],
[[0, -1, 0], 'stone'],
[[0, 0, 1], 'stone'],
[[0, 0, -1], 'stone'],
// [[0, 0, 0], 'diamond_block'],
// [[1, 0, 0], 'stone'],
// [[-1, 0, 0], 'stone'],
// [[0, 1, 0], 'stone'],
// [[0, -1, 0], 'stone'],
// [[0, 0, 1], 'stone'],
// [[0, 0, -1], 'stone'],
] as const
test('Known blocks are not rendered', () => {
const { mesherWorld, getGeometry, pos, mcData } = setup(version, addPositions as any)
const { mesherWorld, getGeometry, pos, mcData } = setup(version, addPositions as any)
const ignoreAsExpected = ['air', 'cave_air', 'void_air', 'barrier', 'water', 'lava', 'moving_piston', 'light']
let time = 0
let times = 0
const invalidBlocks = {}/* as {[number, number]} */
for (const block of mcData.blocksArray) {
if (block.maxStateId! - block.minStateId! > 100) continue
for (let i = block.minStateId!; i <= block.maxStateId!; i++) {
if (block.transparent) continue
mesherWorld.setBlockStateId(pos, i)
const start = performance.now()
const { centerFaces, totalTiles, centerTileNeighbors } = getGeometry()
time += performance.now() - start
times++
if (centerFaces === 0 && centerTileNeighbors !== 0) {
if (invalidBlocks[block.name]) continue
invalidBlocks[block.name] = [i - block.minStateId!, centerTileNeighbors]
// console.log('INVALID', block.name, centerTileNeighbors, i - block.minStateId)
}
}
}
console.log('Average time', time / times)
// Fully expected
expect(invalidBlocks).toMatchInlineSnapshot(`
{
"creeper_head": [
0,
6,
],
"creeper_wall_head": [
0,
6,
],
"dragon_head": [
0,
6,
],
"dragon_wall_head": [
0,
6,
],
"player_head": [
0,
6,
],
"player_wall_head": [
0,
6,
],
"powder_snow": [
0,
6,
],
"skeleton_skull": [
0,
6,
],
"skeleton_wall_skull": [
0,
6,
],
"wither_skeleton_skull": [
0,
6,
],
"wither_skeleton_wall_skull": [
0,
6,
],
"zombie_head": [
0,
6,
],
"zombie_wall_head": [
0,
6,
],
let time = 0
let times = 0
const invalidBlocks = {}/* as {[number, number]} */
for (const block of mcData.blocksArray) {
if (ignoreAsExpected.includes(block.name)) continue
// if (block.maxStateId! - block.minStateId! > 100) continue
// for (let i = block.minStateId!; i <= block.maxStateId!; i++) {
for (let i = block.defaultState!; i <= block.defaultState!; i++) {
// if (block.transparent) continue
mesherWorld.setBlockStateId(pos, i)
const start = performance.now()
const { centerFaces, totalTiles, centerTileNeighbors } = getGeometry()
time += performance.now() - start
times++
if (centerFaces === 0) {
if (invalidBlocks[block.name]) continue
invalidBlocks[block.name] = true
// invalidBlocks[block.name] = [i - block.defaultState!, centerTileNeighbors]
// console.log('INVALID', block.name, centerTileNeighbors, i - block.minStateId)
}
`)
}
}
console.log('Average time', time / times)
// should be fixed, but to avoid regressions & for visibility
expect(invalidBlocks).toMatchInlineSnapshot(`
{
"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,
"creeper_head": true,
"creeper_wall_head": true,
"cyan_banner": true,
"cyan_bed": true,
"cyan_candle": true,
"cyan_wall_banner": true,
"dragon_head": true,
"dragon_wall_head": true,
"end_gateway": true,
"end_portal": true,
"gray_banner": true,
"gray_bed": true,
"gray_candle": true,
"gray_wall_banner": true,
"green_banner": true,
"green_bed": true,
"green_candle": true,
"green_wall_banner": true,
"light_blue_banner": true,
"light_blue_bed": true,
"light_blue_candle": true,
"light_blue_wall_banner": true,
"light_gray_banner": true,
"light_gray_bed": true,
"light_gray_candle": true,
"light_gray_wall_banner": true,
"lime_banner": true,
"lime_bed": true,
"lime_candle": true,
"lime_wall_banner": true,
"magenta_banner": true,
"magenta_bed": true,
"magenta_candle": true,
"magenta_wall_banner": true,
"orange_banner": true,
"orange_bed": true,
"orange_candle": true,
"orange_wall_banner": true,
"piglin_head": true,
"piglin_wall_head": true,
"pink_banner": true,
"pink_bed": true,
"pink_candle": true,
"pink_petals": true,
"pink_wall_banner": true,
"player_head": true,
"player_wall_head": true,
"powder_snow_cauldron": true,
"purple_banner": true,
"purple_bed": true,
"purple_candle": true,
"purple_wall_banner": true,
"red_banner": true,
"red_bed": true,
"red_candle": true,
"red_wall_banner": true,
"repeater": true,
"sea_pickle": true,
"skeleton_skull": true,
"skeleton_wall_skull": true,
"snow": true,
"structure_void": true,
"turtle_egg": true,
"water_cauldron": true,
"white_banner": true,
"white_bed": true,
"white_candle": true,
"white_wall_banner": true,
"wither_skeleton_skull": true,
"wither_skeleton_wall_skull": true,
"yellow_banner": true,
"yellow_bed": true,
"yellow_candle": true,
"yellow_wall_banner": true,
"zombie_head": true,
"zombie_wall_head": true,
}
`)
})

View file

@ -4,6 +4,7 @@ import { Block } from "prismarine-block"
import { Vec3 } from 'vec3'
import moreBlockDataGeneratedJson from '../moreBlockDataGenerated.json'
import { defaultMesherConfig } from './shared'
import legacyJson from '../../../../src/preflatMap.json'
const ignoreAoBlocks = Object.keys(moreBlockDataGeneratedJson.noOcclusions)
@ -17,7 +18,7 @@ function isCube (shapes) {
return shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1
}
export type WorldBlock = Block & {
export type WorldBlock = Omit<Block, 'position'> & {
variant?: any
// todo
isCube: boolean
@ -30,14 +31,16 @@ export class World {
columns = {} as { [key: string]: import('prismarine-chunk/types/index').PCChunk }
blockCache = {}
biomeCache: { [id: number]: mcData.Biome }
preflat: boolean
constructor(version) {
constructor (version) {
this.Chunk = Chunks(version) as any
this.biomeCache = mcData(version).biomes
this.preflat = !mcData(version).supportFeature('blockStateId')
this.config.version = version
}
getLight (pos: Vec3, isNeighbor = false) {
getLight (pos: Vec3, isNeighbor = false, skipMoreChecks = false, curBlockName = '') {
const { enableLighting, skyLight } = this.config
if (!enableLighting) return 15
// const key = `${pos.x},${pos.y},${pos.z}`
@ -52,8 +55,17 @@ export class World {
) + 2
)
// lightsCache.set(key, result)
if (result === 2 && this.getBlock(pos)?.name.match(/_stairs|slab/)) { // todo this is obviously wrong
result = this.getLight(pos.offset(0, 1, 0))
if (result === 2 && [this.getBlock(pos)?.name ?? '', curBlockName].some(x => x.match(/_stairs|slab|glass_pane/)) && !skipMoreChecks) { // todo this is obviously wrong
const lights = [
this.getLight(pos.offset(0, 1, 0), undefined, true),
this.getLight(pos.offset(0, -1, 0), undefined, true),
this.getLight(pos.offset(0, 0, 1), undefined, true),
this.getLight(pos.offset(0, 0, -1), undefined, true),
this.getLight(pos.offset(1, 0, 0), undefined, true),
this.getLight(pos.offset(-1, 0, 0), undefined, true)
].filter(x => x !== 2)
const min = Math.min(...lights)
result = min
}
if (isNeighbor && result === 2) result = 15 // TODO
return result
@ -91,6 +103,8 @@ export class World {
}
getBlock (pos: Vec3): WorldBlock | null {
// for easier testing
if (!(pos instanceof Vec3)) pos = new Vec3(...pos as [number, number, number])
const key = columnKey(Math.floor(pos.x / 16) * 16, Math.floor(pos.z / 16) * 16)
const column = this.columns[key]
@ -111,6 +125,25 @@ export class World {
throw new Error('position is not reliable, use pos parameter instead of block.position')
}
})
if (this.preflat) {
//@ts-ignore
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('=') as any
if (!isNaN(val)) val = parseInt(val)
return [key, val]
}))
//@ts-ignore
b._properties = newProperties
}
}
}
}
const block = this.blockCache[stateId]
@ -127,6 +160,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)

View file

@ -1,6 +1,5 @@
const THREE = require('three')
const { MeshLine, MeshLineMaterial } = require('three.meshline')
const { dispose3 } = require('./dispose')
function getMesh (primitive, camera) {
if (primitive.type === 'line') {
@ -48,7 +47,7 @@ function getMesh (primitive, camera) {
}
class Primitives {
constructor (scene, camera) {
constructor(scene, camera) {
this.scene = scene
this.camera = camera
this.primitives = {}
@ -57,7 +56,7 @@ class Primitives {
clear () {
for (const mesh of Object.values(this.primitives)) {
this.scene.remove(mesh)
dispose3(mesh)
disposeObject(mesh)
}
this.primitives = {}
}
@ -65,7 +64,7 @@ class Primitives {
update (primitive) {
if (this.primitives[primitive.id]) {
this.scene.remove(this.primitives[primitive.id])
dispose3(this.primitives[primitive.id])
disposeObject(this.primitives[primitive.id])
delete this.primitives[primitive.id]
}

View file

@ -0,0 +1,12 @@
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)
}
}

View file

@ -8,6 +8,7 @@ import { generateSpiralMatrix } from 'flying-squid/dist/utils'
import { defaultWorldRendererConfig } from './worldrendererCommon'
import { sendCameraToWorker } from '../../examples/webgpuRendererMain'
import { WorldRendererThree } from './worldrendererThree'
import { versionToNumber } from '../prepare/utils'
export class Viewer {
scene: THREE.Scene
@ -80,7 +81,8 @@ export class Viewer {
}
setVersion (userVersion: string) {
const texturesVersion = getVersion(userVersion)
let texturesVersion = getVersion(userVersion)
if (versionToNumber(userVersion) < versionToNumber('1.13')) texturesVersion = '1.13.2' // we normalize to post-flatenning in mesher
console.log('[viewer] Using version:', userVersion, 'textures:', texturesVersion)
this.world.setVersion(userVersion, texturesVersion)
this.entities.clear()
@ -203,6 +205,8 @@ export class Viewer {
})
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.")

View file

@ -5,12 +5,14 @@ export class ViewerWrapper {
previousWindowWidth: number
previousWindowHeight: number
globalObject = globalThis as any
stopRenderOnBlur = true
stopRenderOnBlur = false
addedToPage = false
renderInterval = 0
renderIntervalUnfocused: number | undefined
fpsInterval
constructor(public canvas: HTMLCanvasElement, public renderer?: THREE.WebGLRenderer) {
constructor (public canvas: HTMLCanvasElement, public renderer?: THREE.WebGLRenderer) {
if (this.renderer) this.globalObject.renderer = this.renderer
}
addToPage (startRendering = true) {
if (this.addedToPage) throw new Error('Already added to page')
@ -29,7 +31,6 @@ export class ViewerWrapper {
this.canvas.id = 'viewer-canvas'
document.body.appendChild(this.canvas)
if (this.renderer) this.globalObject.renderer = this.renderer
this.addedToPage = true
let max = 0
@ -44,7 +45,7 @@ export class ViewerWrapper {
this.globalObject.requestAnimationFrame(this.render.bind(this))
}
if (typeof window !== 'undefined') {
// this.trackWindowFocus()
this.trackWindowFocus()
}
}
@ -77,11 +78,12 @@ export class ViewerWrapper {
for (const fn of beforeRenderFrame) fn()
this.globalObject.requestAnimationFrame(this.render.bind(this))
if (this.globalObject.stopRender || this.renderer?.xr.isPresenting || (this.stopRenderOnBlur && !this.windowFocused)) return
if (this.renderInterval) {
const renderInterval = (this.windowFocused ? this.renderInterval : this.renderIntervalUnfocused) ?? this.renderInterval
if (renderInterval) {
this.delta += time - this.lastTime
this.lastTime = time
if (this.delta > this.renderInterval) {
this.delta %= this.renderInterval
if (this.delta > renderInterval) {
this.delta %= renderInterval
// continue rendering
} else {
return

View file

@ -0,0 +1,58 @@
export function createWorkerProxy<T extends Record<string, (...args: any[]) => void>> (handlers: T): { __workerProxy: T } {
addEventListener('message', (event) => {
const { type, args } = event.data
if (handlers[type]) {
handlers[type](...args)
}
})
return null as any
}
/**
* in main thread
* ```ts
* // either:
* import type { importedTypeWorkerProxy } from './worker'
* // or:
* type importedTypeWorkerProxy = import('./worker').importedTypeWorkerProxy
*
* const workerChannel = useWorkerProxy<typeof importedTypeWorkerProxy>(worker)
* ```
*/
export const useWorkerProxy = <T extends { __workerProxy: Record<string, (...args: any[]) => void> }> (worker: Worker, autoTransfer = true): T['__workerProxy'] & {
transfer: (...args: Transferable[]) => T['__workerProxy']
} => {
// 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 transfer = autoTransfer ? args.filter(arg => arg instanceof ArrayBuffer || arg instanceof MessagePort || arg instanceof ImageBitmap || arg instanceof OffscreenCanvas) : []
worker.postMessage({
type: prop,
args,
}, transfer)
}
}
})
}
// const workerProxy = createWorkerProxy({
// startRender (canvas: HTMLCanvasElement) {
// },
// })
// const worker = useWorkerProxy(null, workerProxy)
// worker.

View file

@ -19,7 +19,7 @@ export class WorldDataEmitter extends EventEmitter {
private eventListeners: Record<string, any> = {};
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)) {
constructor (public 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)
@ -83,10 +83,11 @@ export class WorldDataEmitter extends EventEmitter {
get (_target, posKey, receiver) {
if (typeof posKey !== 'string') return
const [x, y, z] = posKey.split(',').map(Number)
return bot.world.getBlock(new Vec3(x, y, z)).entity
return bot.world.getBlock(new Vec3(x, y, z))?.entity
},
}))
this.emitter.emit('renderDistance', this.viewDistance)
this.emitter.emit('time', bot.time.timeOfDay)
})
// node.js stream data event pattern
if (this.emitter.listenerCount('blockEntities')) {
@ -122,9 +123,23 @@ export class WorldDataEmitter extends EventEmitter {
}
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)))
let i = 0
const interval = setInterval(() => {
if (i >= positions.length) {
clearInterval(interval)
return
}
this.loadChunk(positions[i])
i++
}, 1)
}
readdDebug () {
const clonedLoadedChunks = { ...this.loadedChunks }
this.unloadAllChunks()
for (const loadedChunk in clonedLoadedChunks) {
const [x, z] = loadedChunk.split(',').map(Number)
this.loadChunk(new Vec3(x, 0, z))
}
}
@ -186,7 +201,7 @@ export class WorldDataEmitter extends EventEmitter {
const positions = generateSpiralMatrix(this.viewDistance).map(([x, z]) => {
const pos = new Vec3((botX + x) * 16, 0, (botZ + z) * 16)
if (!this.loadedChunks[`${pos.x},${pos.z}`]) return pos
return undefined
return undefined!
}).filter(a => !!a)
this.lastPos.update(pos)
await this._loadChunks(positions)

View file

@ -73,10 +73,10 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
const src = typeof window === 'undefined' ? `${__dirname}/${workerName}` : workerName
const worker: any = new Worker(src)
worker.onmessage = async ({ data }) => {
const handleMessage = (data) => {
if (!this.active) return
this.handleWorkerMessage(data)
await new Promise(resolve => {
new Promise(resolve => {
setTimeout(resolve, 0)
})
if (data.type === 'sectionFinished') {
@ -105,6 +105,13 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
this.renderUpdateEmitter.emit('update')
}
}
worker.onmessage = ({ data }) => {
if (Array.isArray(data)) {
data.forEach(handleMessage)
return
}
handleMessage(data)
}
if (worker.on) worker.on('message', (data) => { worker.onmessage({ data }) })
this.workers.push(worker)
}
@ -123,6 +130,8 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
allChunksLoaded?(): void
timeUpdated?(newTime: number): void
updateViewerPosition (pos: Vec3) {
this.viewerPosition = pos
for (const [key, value] of Object.entries(this.loadedChunks)) {
@ -213,6 +222,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
}
addColumn (x: number, z: number, chunk: any, isLightUpdate: boolean) {
if (!this.active) return
if (this.workers.length === 0) throw new Error('workers not initialized yet')
this.initialChunksLoad = false
this.loadedChunks[`${x},${z}`] = true
@ -254,6 +264,9 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
if ((pos.z & 15) === 15) this.setSectionDirty(pos.offset(0, 0, 16))
}
queueAwaited = false
messagesQueue = {} as { [workerIndex: string]: any[] }
setSectionDirty (pos: Vec3, value = true) {
if (this.viewDistance === -1) throw new Error('viewDistance not set')
this.allChunksFinished = false
@ -267,7 +280,9 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
// is always dispatched to the same worker
const hash = mod(Math.floor(pos.x / 16) + Math.floor(pos.y / 16) + Math.floor(pos.z / 16), this.workers.length)
this.sectionsOutstanding.set(key, (this.sectionsOutstanding.get(key) ?? 0) + 1)
this.workers[hash].postMessage({
this.messagesQueue[hash] ??= []
this.messagesQueue[hash].push({
// this.workers[hash].postMessage({
type: 'dirty',
x: pos.x,
y: pos.y,
@ -275,6 +290,21 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
value,
config: this.mesherConfig,
})
this.dispatchMessages()
}
dispatchMessages () {
if (this.queueAwaited) return
this.queueAwaited = true
setTimeout(() => {
// group messages and send as one
for (const workerIndex in this.messagesQueue) {
const worker = this.workers[Number(workerIndex)]
worker.postMessage(this.messagesQueue[workerIndex])
}
this.messagesQueue = {}
this.queueAwaited = false
})
}
// Listen for chunk rendering updates emitted if a worker finished a render and resolve if the number

View file

@ -1,7 +1,6 @@
import * as THREE from 'three'
import { Vec3 } from 'vec3'
import nbt from 'prismarine-nbt'
import { dispose3 } from './dispose'
import PrismarineChatLoader from 'prismarine-chat'
import { renderSign } from '../sign-renderer/'
import { chunkPos, sectionPos } from './simpleUtils'
@ -12,6 +11,7 @@ function mod (x, n) {
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
@ -19,13 +19,27 @@ export class WorldRendererThree extends WorldRendererCommon {
sectionObjects: Record<string, THREE.Object3D> = {}
chunkTextures = new Map<string, { [pos: string]: THREE.Texture }>()
signsCache = new Map<string, any>()
starField: StarField
cameraSectionPos: Vec3 = new Vec3(0, 0, 0)
get tilesRendered () {
return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj as any).tilesCount, 0)
}
constructor(public scene: THREE.Scene, public renderer: THREE.WebGLRenderer, public config: WorldRendererConfig) {
constructor (public scene: THREE.Scene, public renderer: THREE.WebGLRenderer, public config: WorldRendererConfig) {
super(config)
this.starField = new StarField(scene)
}
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()
}
}
/**
@ -33,16 +47,18 @@ export class WorldRendererThree extends WorldRendererCommon {
*/
updatePosDataChunk (key: string) {
const [x, y, z] = key.split(',').map(x => Math.floor(+x / 16))
const [xPlayer, yPlayer, zPlayer] = this.camera.position.toArray().map(x => Math.floor(x / 16))
// sum of distances: x + y + z
const chunkDistance = Math.abs(x - xPlayer) + Math.abs(y - yPlayer) + Math.abs(z - zPlayer)
const chunkDistance = Math.abs(x - this.cameraSectionPos.x) + Math.abs(y - this.cameraSectionPos.y) + Math.abs(z - this.cameraSectionPos.z)
const section = this.sectionObjects[key].children.find(child => child.name === 'mesh')!
section.renderOrder = 500 - chunkDistance
}
updateViewerPosition (pos: Vec3): void {
this.viewerPosition = pos
for (const [key, value] of Object.entries(this.sectionObjects)) {
const cameraPos = this.camera.position.toArray().map(x => Math.floor(x / 16)) as [number, number, number]
this.cameraSectionPos = new Vec3(...cameraPos)
for (const key in this.sectionObjects) {
const value = this.sectionObjects[key]
if (!value) continue
this.updatePosDataChunk(key)
}
@ -53,7 +69,7 @@ export class WorldRendererThree extends WorldRendererCommon {
let object: THREE.Object3D = this.sectionObjects[data.key]
if (object) {
this.scene.remove(object)
dispose3(object)
disposeObject(object)
delete this.sectionObjects[data.key]
}
@ -86,7 +102,10 @@ export class WorldRendererThree extends WorldRendererCommon {
mesh.name = 'mesh'
object = new THREE.Group()
object.add(mesh)
const boxHelper = new THREE.BoxHelper(mesh, 0xffff00)
// mesh with static dimensions: 16x16x16
const staticChunkMesh = new THREE.Mesh(new THREE.BoxGeometry(16, 16, 16), new THREE.MeshBasicMaterial({ color: 0x000000, transparent: true, opacity: 0 }))
staticChunkMesh.position.set(data.geometry.sx, data.geometry.sy, data.geometry.sz)
const boxHelper = new THREE.BoxHelper(staticChunkMesh, 0xffff00)
boxHelper.name = 'helper'
object.add(boxHelper)
object.name = 'chunk'
@ -97,17 +116,22 @@ export class WorldRendererThree extends WorldRendererCommon {
}
// should not compute it once
if (Object.keys(data.geometry.signs).length) {
for (const [posKey, { isWall, rotation }] of Object.entries(data.geometry.signs)) {
for (const [posKey, { isWall, isHanging, rotation }] of Object.entries(data.geometry.signs)) {
const [x, y, z] = posKey.split(',')
const signBlockEntity = this.blockEntities[posKey]
if (!signBlockEntity) continue
const sign = this.renderSign(new Vec3(+x, +y, +z), rotation, isWall, nbt.simplify(signBlockEntity))
const sign = this.renderSign(new Vec3(+x, +y, +z), rotation, isWall, isHanging, nbt.simplify(signBlockEntity))
if (!sign) continue
object.add(sign)
}
}
this.sectionObjects[data.key] = object
this.updatePosDataChunk(data.key)
object.matrixAutoUpdate = false
mesh.onAfterRender = (renderer, scene, camera, geometry, material, group) => {
// mesh.matrixAutoUpdate = false
}
this.scene.add(object)
}
@ -142,10 +166,11 @@ export class WorldRendererThree extends WorldRendererCommon {
render () {
tweenJs.update()
this.renderer.render(this.scene, this.camera)
const cam = this.camera instanceof THREE.Group ? this.camera.children.find(child => child instanceof THREE.PerspectiveCamera) as THREE.PerspectiveCamera : this.camera
this.renderer.render(this.scene, cam)
}
renderSign (position: Vec3, rotation: number, isWall: boolean, blockEntity) {
renderSign (position: Vec3, rotation: number, isWall: boolean, isHanging: boolean, blockEntity) {
const tex = this.getSignTexture(position, blockEntity)
if (!tex) return
@ -161,14 +186,16 @@ export class WorldRendererThree extends WorldRendererCommon {
const mesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), new THREE.MeshBasicMaterial({ map: tex, transparent: true, }))
mesh.renderOrder = 999
// todo @sa2urami shouldnt all this be done in worker?
mesh.scale.set(1, 7 / 16, 1)
if (isWall) {
mesh.position.set(0, 0, -(8 - 1.5) / 16 + 0.001)
const lineHeight = 7 / 16
const scaleFactor = isHanging ? 1.3 : 1
mesh.scale.set(1 * scaleFactor, lineHeight * scaleFactor, 1 * scaleFactor)
const thickness = (isHanging ? 2 : 1.5) / 16
const wallSpacing = 0.25 / 16
if (isWall && !isHanging) {
mesh.position.set(0, 0, -0.5 + thickness + wallSpacing + 0.0001)
} else {
// standing
const faceEnd = 8.75
mesh.position.set(0, 0, (faceEnd - 16 / 2) / 16 + 0.001)
mesh.position.set(0, 0, thickness / 2 + 0.0001)
}
const group = new THREE.Group()
@ -176,8 +203,10 @@ export class WorldRendererThree extends WorldRendererCommon {
rotation * (isWall ? 90 : 45 / 2)
), 0)
group.add(mesh)
const y = isWall ? 4.5 / 16 + mesh.scale.y / 2 : (1 - (mesh.scale.y / 2))
group.position.set(position.x + 0.5, position.y + y, position.z + 0.5)
const height = (isHanging ? 10 : 8) / 16
const heightOffset = (isHanging ? 0 : isWall ? 4.333 : 9.333) / 16
const textPosition = height / 2 + heightOffset
group.position.set(position.x + 0.5, position.y + textPosition, position.z + 0.5)
return group
}
@ -244,6 +273,24 @@ export class WorldRendererThree extends WorldRendererCommon {
}
}
readdChunks () {
for (const key of Object.keys(this.sectionObjects)) {
this.scene.remove(this.sectionObjects[key])
}
setTimeout(() => {
for (const key of Object.keys(this.sectionObjects)) {
this.scene.add(this.sectionObjects[key])
}
}, 500)
}
disableUpdates (children = this.scene.children) {
for (const child of children) {
child.matrixWorldNeedsUpdate = false
this.disableUpdates(child.children ?? [])
}
}
removeColumn (x, z) {
super.removeColumn(x, z)
@ -254,7 +301,7 @@ export class WorldRendererThree extends WorldRendererCommon {
const mesh = this.sectionObjects[key]
if (mesh) {
this.scene.remove(mesh)
dispose3(mesh)
disposeObject(mesh)
}
delete this.sectionObjects[key]
}
@ -265,3 +312,113 @@ export class WorldRendererThree extends WorldRendererCommon {
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 <tonemapping_fragment>
#include <${version >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}>
}`,
})
}
}

View file

@ -31,20 +31,11 @@ export type JsonAtlas = {
[file: string]: {
u: number,
v: number,
su?: number,
sv?: number,
animatedFrames?: number
}
}
}
export const makeTextureAtlas = (
input: string[],
getInputData: (name) => { contents: string, tileWidthMult?: number },
tilesCount = input.length,
suSvOptimize: 'remove' | null = null,
renderAnimated = true
): {
export const makeTextureAtlas = (input: string[], getInputData: (name) => { contents: string, tileWidthMult?: number, origSizeTextures?}, tilesCount = input.length, suSvOptimize: 'remove' | null = null): {
image: Buffer,
canvas: Canvas,
json: JsonAtlas
@ -56,53 +47,62 @@ export const makeTextureAtlas = (
const canvas = new Canvas(imgSize, imgSize, 'png' as any)
const g = canvas.getContext('2d')
const texturesIndex = {} as JsonAtlas['textures']
const texturesIndex = {}
let nextX = 0
let nextY = 0
let rowMaxY = 0
const goToNextRow = () => {
nextX = 0
nextY += rowMaxY
rowMaxY = 0
}
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);
const keyValue = input[i]
const inputData = getInputData(keyValue)
img.src = inputData.contents
const renderWidth = tileSize * (inputData.tileWidthMult ?? 1)
let animatedFrames = 0
const addDebugText = (x, y) => {
return // disable debug text
g.fillStyle = 'black'
g.font = '8px Arial'
g.fillText(i, x, y)
}
if (img.height > tileSize && renderAnimated) {
const frames = img.height / tileSize;
animatedFrames = frames
console.log("Animated texture", keyValue, frames)
offset += frames - 1
for (let i = 0; i < frames; i++) {
const x = ((pos + i) % texSize) * tileSize
const y = Math.floor((pos + i) / texSize) * tileSize
g.drawImage(img, 0, i * tileSize, renderWidth, tileSize, x, y, renderWidth, tileSize)
addDebugText(x, y)
let su = suSv
let sv = suSv
let renderWidth = tileSize * (inputData.tileWidthMult ?? 1)
let renderHeight = tileSize
if (inputData.origSizeTextures?.[keyValue]) {
// todo check have enough space
renderWidth = Math.ceil(img.width / tileSize) * tileSize
renderHeight = Math.ceil(img.height / tileSize) * tileSize
su = renderWidth / imgSize
sv = renderHeight / imgSize
if (renderHeight > imgSize || renderWidth > imgSize) {
throw new Error('Texture ' + keyValue + ' is too big')
}
} else {
g.drawImage(img, 0, 0, renderWidth, tileSize, x, y, renderWidth, tileSize)
addDebugText(x, y)
}
if (nextX + renderWidth > imgSize) {
goToNextRow()
}
const x = nextX
const y = nextY
nextX += renderWidth
rowMaxY = Math.max(rowMaxY, renderHeight)
if (nextX >= imgSize) {
goToNextRow()
}
g.drawImage(img, 0, 0, renderWidth, renderHeight, x, y, renderWidth, renderHeight)
const cleanName = keyValue.split('.').slice(0, -1).join('.') || keyValue
texturesIndex[cleanName] = {
u: x / imgSize,
v: y / imgSize,
...suSvOptimize === 'remove' ? {} : {
su: suSv,
sv: suSv
},
textureName: cleanName,
animatedFrames: animatedFrames || undefined
su: su,
sv: sv
}
}
}
@ -123,7 +123,7 @@ export function makeBlockTextureAtlas (mcAssets: McAssets) {
// const textureFiles = mostEncounteredBlocks.map(x => x + '.png')
textureFiles.unshift(...localTextures)
const { generated: additionalTextures, twoTileTextures } = getAdditionalTextures()
const { generated: additionalTextures, origSizeTextures } = getAdditionalTextures()
textureFiles.push(...Object.keys(additionalTextures))
const atlas = makeTextureAtlas(textureFiles, name => {
@ -136,7 +136,8 @@ export function makeBlockTextureAtlas (mcAssets: McAssets) {
return {
contents,
tileWidthMult: twoTileTextures.includes(name) ? 2 : undefined,
// tileWidthMult: twoTileTextures.includes(name) ? 2 : undefined,
origSizeTextures
}
})
return atlas

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign",
"textures": {
"sign": "entity/sign"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign_wall",
"textures": {
"sign": "entity/sign"
}
}

View file

@ -0,0 +1,140 @@
{
"elements": [
{
"from": [
7.25,
0,
7.25
],
"to": [
8.75,
9.333,
8.75
],
"faces": {
"north": {
"uv": [
1.5,
8,
2,
15
],
"texture": "#sign"
},
"east": {
"uv": [
1,
8,
1.5,
15
],
"texture": "#sign"
},
"south": {
"uv": [
0.5,
8,
1,
15
],
"texture": "#sign"
},
"west": {
"uv": [
0,
8,
0.5,
15
],
"texture": "#sign"
},
"up": {
"uv": [
0.5,
7,
1,
8
],
"texture": "#sign"
},
"down": {
"uv": [
1,
7,
1.5,
8
],
"texture": "#sign"
}
}
},
{
"from": [
0,
9.333,
7.25
],
"to": [
16,
17.333,
8.75
],
"faces": {
"north": {
"uv": [
7,
1,
13,
7
],
"texture": "#sign"
},
"east": {
"uv": [
6.5,
1,
7,
7
],
"texture": "#sign"
},
"south": {
"uv": [
0.5,
1,
6.5,
7
],
"texture": "#sign"
},
"west": {
"uv": [
0,
1,
0.5,
7
],
"texture": "#sign"
},
"up": {
"uv": [
0.5,
0,
6.5,
1
],
"texture": "#sign"
},
"down": {
"uv": [
6.5,
1,
12.5,
0
],
"texture": "#sign"
}
}
}
]
}

View file

@ -0,0 +1,72 @@
{
"elements": [
{
"from": [
0,
4.333,
0.25
],
"to": [
16,
12.333,
1.75
],
"faces": {
"north": {
"uv": [
7,
1,
13,
7
],
"texture": "#sign"
},
"east": {
"uv": [
6.5,
1,
7,
7
],
"texture": "#sign"
},
"south": {
"uv": [
0.5,
1,
6.5,
7
],
"texture": "#sign"
},
"west": {
"uv": [
0,
1,
0.5,
7
],
"texture": "#sign"
},
"up": {
"uv": [
0.5,
0,
6.5,
1
],
"texture": "#sign"
},
"down": {
"uv": [
6.5,
1,
12.5,
0
],
"texture": "#sign"
}
}
}
]
}

View file

@ -0,0 +1,67 @@
{
"variants": {
"rotation=0": {
"model": "sign/oak"
},
"rotation=1": {
"model": "sign/oak",
"y": 22.5
},
"rotation=2": {
"model": "sign/oak",
"y": 45
},
"rotation=3": {
"model": "sign/oak",
"y": 67.5
},
"rotation=4": {
"model": "sign/oak",
"y": 90
},
"rotation=5": {
"model": "sign/oak",
"y": 112.5
},
"rotation=6": {
"model": "sign/oak",
"y": 135
},
"rotation=7": {
"model": "sign/oak",
"y": 157.5
},
"rotation=8": {
"model": "sign/oak",
"y": 180
},
"rotation=9": {
"model": "sign/oak",
"y": 202.5
},
"rotation=10": {
"model": "sign/oak",
"y": 225
},
"rotation=11": {
"model": "sign/oak",
"y": 247.5
},
"rotation=12": {
"model": "sign/oak",
"y": 270
},
"rotation=13": {
"model": "sign/oak",
"y": 292.5
},
"rotation=14": {
"model": "sign/oak",
"y": 315
},
"rotation=15": {
"model": "sign/oak",
"y": 337.5
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=south": {
"model": "sign/oak_wall"
},
"facing=west": {
"model": "sign/oak_wall",
"y": 90
},
"facing=north": {
"model": "sign/oak_wall",
"y": 180
},
"facing=east": {
"model": "sign/oak_wall",
"y": 270
}
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign",
"textures": {
"sign": "entity/signs/acacia"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign_wall",
"textures": {
"sign": "entity/signs/acacia"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign",
"textures": {
"sign": "entity/signs/birch"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign_wall",
"textures": {
"sign": "entity/signs/birch"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign",
"textures": {
"sign": "entity/signs/dark_oak"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign_wall",
"textures": {
"sign": "entity/signs/dark_oak"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign",
"textures": {
"sign": "entity/signs/jungle"
}
}

View file

@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench by TyBraniff for Bluemaps support.",
"parent": "sign/sign_wall",
"textures": {
"sign": "entity/signs/jungle"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign",
"textures": {
"sign": "entity/signs/spruce"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign_wall",
"textures": {
"sign": "entity/signs/spruce"
}
}

View file

@ -0,0 +1,67 @@
{
"variants": {
"rotation=0": {
"model": "sign/acacia"
},
"rotation=1": {
"model": "sign/acacia",
"y": 22.5
},
"rotation=2": {
"model": "sign/acacia",
"y": 45
},
"rotation=3": {
"model": "sign/acacia",
"y": 67.5
},
"rotation=4": {
"model": "sign/acacia",
"y": 90
},
"rotation=5": {
"model": "sign/acacia",
"y": 112.5
},
"rotation=6": {
"model": "sign/acacia",
"y": 135
},
"rotation=7": {
"model": "sign/acacia",
"y": 157.5
},
"rotation=8": {
"model": "sign/acacia",
"y": 180
},
"rotation=9": {
"model": "sign/acacia",
"y": 202.5
},
"rotation=10": {
"model": "sign/acacia",
"y": 225
},
"rotation=11": {
"model": "sign/acacia",
"y": 247.5
},
"rotation=12": {
"model": "sign/acacia",
"y": 270
},
"rotation=13": {
"model": "sign/acacia",
"y": 292.5
},
"rotation=14": {
"model": "sign/acacia",
"y": 315
},
"rotation=15": {
"model": "sign/acacia",
"y": 337.5
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=south": {
"model": "sign/acacia_wall"
},
"facing=west": {
"model": "sign/acacia_wall",
"y": 90
},
"facing=north": {
"model": "sign/acacia_wall",
"y": 180
},
"facing=east": {
"model": "sign/acacia_wall",
"y": 270
}
}
}

View file

@ -0,0 +1,67 @@
{
"variants": {
"rotation=0": {
"model": "sign/birch"
},
"rotation=1": {
"model": "sign/birch",
"y": 22.5
},
"rotation=2": {
"model": "sign/birch",
"y": 45
},
"rotation=3": {
"model": "sign/birch",
"y": 67.5
},
"rotation=4": {
"model": "sign/birch",
"y": 90
},
"rotation=5": {
"model": "sign/birch",
"y": 112.5
},
"rotation=6": {
"model": "sign/birch",
"y": 135
},
"rotation=7": {
"model": "sign/birch",
"y": 157.5
},
"rotation=8": {
"model": "sign/birch",
"y": 180
},
"rotation=9": {
"model": "sign/birch",
"y": 202.5
},
"rotation=10": {
"model": "sign/birch",
"y": 225
},
"rotation=11": {
"model": "sign/birch",
"y": 247.5
},
"rotation=12": {
"model": "sign/birch",
"y": 270
},
"rotation=13": {
"model": "sign/birch",
"y": 292.5
},
"rotation=14": {
"model": "sign/birch",
"y": 315
},
"rotation=15": {
"model": "sign/birch",
"y": 337.5
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=south": {
"model": "sign/birch_wall"
},
"facing=west": {
"model": "sign/birch_wall",
"y": 90
},
"facing=north": {
"model": "sign/birch_wall",
"y": 180
},
"facing=east": {
"model": "sign/birch_wall",
"y": 270
}
}
}

View file

@ -0,0 +1,67 @@
{
"variants": {
"rotation=0": {
"model": "sign/dark_oak"
},
"rotation=1": {
"model": "sign/dark_oak",
"y": 22.5
},
"rotation=2": {
"model": "sign/dark_oak",
"y": 45
},
"rotation=3": {
"model": "sign/dark_oak",
"y": 67.5
},
"rotation=4": {
"model": "sign/dark_oak",
"y": 90
},
"rotation=5": {
"model": "sign/dark_oak",
"y": 112.5
},
"rotation=6": {
"model": "sign/dark_oak",
"y": 135
},
"rotation=7": {
"model": "sign/dark_oak",
"y": 157.5
},
"rotation=8": {
"model": "sign/dark_oak",
"y": 180
},
"rotation=9": {
"model": "sign/dark_oak",
"y": 202.5
},
"rotation=10": {
"model": "sign/dark_oak",
"y": 225
},
"rotation=11": {
"model": "sign/dark_oak",
"y": 247.5
},
"rotation=12": {
"model": "sign/dark_oak",
"y": 270
},
"rotation=13": {
"model": "sign/dark_oak",
"y": 292.5
},
"rotation=14": {
"model": "sign/dark_oak",
"y": 315
},
"rotation=15": {
"model": "sign/dark_oak",
"y": 337.5
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=south": {
"model": "sign/dark_oak_wall"
},
"facing=west": {
"model": "sign/dark_oak_wall",
"y": 90
},
"facing=north": {
"model": "sign/dark_oak_wall",
"y": 180
},
"facing=east": {
"model": "sign/dark_oak_wall",
"y": 270
}
}
}

View file

@ -0,0 +1,67 @@
{
"variants": {
"rotation=0": {
"model": "sign/jungle"
},
"rotation=1": {
"model": "sign/jungle",
"y": 22.5
},
"rotation=2": {
"model": "sign/jungle",
"y": 45
},
"rotation=3": {
"model": "sign/jungle",
"y": 67.5
},
"rotation=4": {
"model": "sign/jungle",
"y": 90
},
"rotation=5": {
"model": "sign/jungle",
"y": 112.5
},
"rotation=6": {
"model": "sign/jungle",
"y": 135
},
"rotation=7": {
"model": "sign/jungle",
"y": 157.5
},
"rotation=8": {
"model": "sign/jungle",
"y": 180
},
"rotation=9": {
"model": "sign/jungle",
"y": 202.5
},
"rotation=10": {
"model": "sign/jungle",
"y": 225
},
"rotation=11": {
"model": "sign/jungle",
"y": 247.5
},
"rotation=12": {
"model": "sign/jungle",
"y": 270
},
"rotation=13": {
"model": "sign/jungle",
"y": 292.5
},
"rotation=14": {
"model": "sign/jungle",
"y": 315
},
"rotation=15": {
"model": "sign/jungle",
"y": 337.5
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=south": {
"model": "sign/jungle_wall"
},
"facing=west": {
"model": "sign/jungle_wall",
"y": 90
},
"facing=north": {
"model": "sign/jungle_wall",
"y": 180
},
"facing=east": {
"model": "sign/jungle_wall",
"y": 270
}
}
}

View file

@ -0,0 +1,67 @@
{
"variants": {
"rotation=0": {
"model": "sign/oak"
},
"rotation=1": {
"model": "sign/oak",
"y": 22.5
},
"rotation=2": {
"model": "sign/oak",
"y": 45
},
"rotation=3": {
"model": "sign/oak",
"y": 67.5
},
"rotation=4": {
"model": "sign/oak",
"y": 90
},
"rotation=5": {
"model": "sign/oak",
"y": 112.5
},
"rotation=6": {
"model": "sign/oak",
"y": 135
},
"rotation=7": {
"model": "sign/oak",
"y": 157.5
},
"rotation=8": {
"model": "sign/oak",
"y": 180
},
"rotation=9": {
"model": "sign/oak",
"y": 202.5
},
"rotation=10": {
"model": "sign/oak",
"y": 225
},
"rotation=11": {
"model": "sign/oak",
"y": 247.5
},
"rotation=12": {
"model": "sign/oak",
"y": 270
},
"rotation=13": {
"model": "sign/oak",
"y": 292.5
},
"rotation=14": {
"model": "sign/oak",
"y": 315
},
"rotation=15": {
"model": "sign/oak",
"y": 337.5
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=south": {
"model": "sign/oak_wall"
},
"facing=west": {
"model": "sign/oak_wall",
"y": 90
},
"facing=north": {
"model": "sign/oak_wall",
"y": 180
},
"facing=east": {
"model": "sign/oak_wall",
"y": 270
}
}
}

View file

@ -0,0 +1,67 @@
{
"variants": {
"rotation=0": {
"model": "sign/spruce"
},
"rotation=1": {
"model": "sign/spruce",
"y": 22.5
},
"rotation=2": {
"model": "sign/spruce",
"y": 45
},
"rotation=3": {
"model": "sign/spruce",
"y": 67.5
},
"rotation=4": {
"model": "sign/spruce",
"y": 90
},
"rotation=5": {
"model": "sign/spruce",
"y": 112.5
},
"rotation=6": {
"model": "sign/spruce",
"y": 135
},
"rotation=7": {
"model": "sign/spruce",
"y": 157.5
},
"rotation=8": {
"model": "sign/spruce",
"y": 180
},
"rotation=9": {
"model": "sign/spruce",
"y": 202.5
},
"rotation=10": {
"model": "sign/spruce",
"y": 225
},
"rotation=11": {
"model": "sign/spruce",
"y": 247.5
},
"rotation=12": {
"model": "sign/spruce",
"y": 270
},
"rotation=13": {
"model": "sign/spruce",
"y": 292.5
},
"rotation=14": {
"model": "sign/spruce",
"y": 315
},
"rotation=15": {
"model": "sign/spruce",
"y": 337.5
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=south": {
"model": "sign/spruce_wall"
},
"facing=west": {
"model": "sign/spruce_wall",
"y": 90
},
"facing=north": {
"model": "sign/spruce_wall",
"y": 180
},
"facing=east": {
"model": "sign/spruce_wall",
"y": 270
}
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign",
"textures": {
"sign": "entity/signs/crimson"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign_wall",
"textures": {
"sign": "entity/signs/crimson"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign",
"textures": {
"sign": "entity/signs/warped"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign_wall",
"textures": {
"sign": "entity/signs/warped"
}
}

View file

@ -0,0 +1,67 @@
{
"variants": {
"rotation=0": {
"model": "sign/crimson"
},
"rotation=1": {
"model": "sign/crimson",
"y": 22.5
},
"rotation=2": {
"model": "sign/crimson",
"y": 45
},
"rotation=3": {
"model": "sign/crimson",
"y": 67.5
},
"rotation=4": {
"model": "sign/crimson",
"y": 90
},
"rotation=5": {
"model": "sign/crimson",
"y": 112.5
},
"rotation=6": {
"model": "sign/crimson",
"y": 135
},
"rotation=7": {
"model": "sign/crimson",
"y": 157.5
},
"rotation=8": {
"model": "sign/crimson",
"y": 180
},
"rotation=9": {
"model": "sign/crimson",
"y": 202.5
},
"rotation=10": {
"model": "sign/crimson",
"y": 225
},
"rotation=11": {
"model": "sign/crimson",
"y": 247.5
},
"rotation=12": {
"model": "sign/crimson",
"y": 270
},
"rotation=13": {
"model": "sign/crimson",
"y": 292.5
},
"rotation=14": {
"model": "sign/crimson",
"y": 315
},
"rotation=15": {
"model": "sign/crimson",
"y": 337.5
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=south": {
"model": "sign/crimson_wall"
},
"facing=west": {
"model": "sign/crimson_wall",
"y": 90
},
"facing=north": {
"model": "sign/crimson_wall",
"y": 180
},
"facing=east": {
"model": "sign/crimson_wall",
"y": 270
}
}
}

View file

@ -0,0 +1,67 @@
{
"variants": {
"rotation=0": {
"model": "sign/warped"
},
"rotation=1": {
"model": "sign/warped",
"y": 22.5
},
"rotation=2": {
"model": "sign/warped",
"y": 45
},
"rotation=3": {
"model": "sign/warped",
"y": 67.5
},
"rotation=4": {
"model": "sign/warped",
"y": 90
},
"rotation=5": {
"model": "sign/warped",
"y": 112.5
},
"rotation=6": {
"model": "sign/warped",
"y": 135
},
"rotation=7": {
"model": "sign/warped",
"y": 157.5
},
"rotation=8": {
"model": "sign/warped",
"y": 180
},
"rotation=9": {
"model": "sign/warped",
"y": 202.5
},
"rotation=10": {
"model": "sign/warped",
"y": 225
},
"rotation=11": {
"model": "sign/warped",
"y": 247.5
},
"rotation=12": {
"model": "sign/warped",
"y": 270
},
"rotation=13": {
"model": "sign/warped",
"y": 292.5
},
"rotation=14": {
"model": "sign/warped",
"y": 315
},
"rotation=15": {
"model": "sign/warped",
"y": 337.5
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=south": {
"model": "sign/warped_wall"
},
"facing=west": {
"model": "sign/warped_wall",
"y": 90
},
"facing=north": {
"model": "sign/warped_wall",
"y": 180
},
"facing=east": {
"model": "sign/warped_wall",
"y": 270
}
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign",
"textures": {
"sign": "entity/signs/mangrove"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign_wall",
"textures": {
"sign": "entity/signs/mangrove"
}
}

View file

@ -0,0 +1,67 @@
{
"variants": {
"rotation=0": {
"model": "sign/mangrove"
},
"rotation=1": {
"model": "sign/mangrove",
"y": 22.5
},
"rotation=2": {
"model": "sign/mangrove",
"y": 45
},
"rotation=3": {
"model": "sign/mangrove",
"y": 67.5
},
"rotation=4": {
"model": "sign/mangrove",
"y": 90
},
"rotation=5": {
"model": "sign/mangrove",
"y": 112.5
},
"rotation=6": {
"model": "sign/mangrove",
"y": 135
},
"rotation=7": {
"model": "sign/mangrove",
"y": 157.5
},
"rotation=8": {
"model": "sign/mangrove",
"y": 180
},
"rotation=9": {
"model": "sign/mangrove",
"y": 202.5
},
"rotation=10": {
"model": "sign/mangrove",
"y": 225
},
"rotation=11": {
"model": "sign/mangrove",
"y": 247.5
},
"rotation=12": {
"model": "sign/mangrove",
"y": 270
},
"rotation=13": {
"model": "sign/mangrove",
"y": 292.5
},
"rotation=14": {
"model": "sign/mangrove",
"y": 315
},
"rotation=15": {
"model": "sign/mangrove",
"y": 337.5
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=south": {
"model": "sign/mangrove_wall"
},
"facing=west": {
"model": "sign/mangrove_wall",
"y": 90
},
"facing=north": {
"model": "sign/mangrove_wall",
"y": 180
},
"facing=east": {
"model": "sign/mangrove_wall",
"y": 270
}
}
}

View file

@ -0,0 +1,47 @@
{
"texture_size": [32, 32],
"textures": {
"0": "entity/decorated_pot/decorated_pot_base"
},
"elements": [
{
"name": "Body",
"from": [1, 0, 1],
"to": [15, 16, 15],
"faces": {
"north": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"},
"east": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"},
"south": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"},
"west": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"},
"up": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"},
"down": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"}
}
},
{
"name": "Neck",
"from": [5, 16, 5],
"to": [11, 17, 11],
"faces": {
"north": {"uv": [6, 5.5, 9, 6], "texture": "#0"},
"east": {"uv": [9, 5.5, 12, 6], "texture": "#0"},
"south": {"uv": [2.5, 5.5, 5.5, 6], "texture": "#0"},
"west": {"uv": [0, 5.5, 3, 6], "texture": "#0"},
"up": {"uv": [0, 0, 3, 3], "texture": "#0"},
"down": {"uv": [0, 0, 3, 3], "texture": "#0"}
}
},
{
"name": "Head",
"from": [4, 17, 4],
"to": [12, 20, 12],
"faces": {
"north": {"uv": [0, 4, 4, 5.5], "texture": "#0"},
"east": {"uv": [4, 4, 8, 5.5], "texture": "#0"},
"south": {"uv": [8, 4, 12, 5.5], "texture": "#0"},
"west": {"uv": [12, 4, 16, 5.5], "texture": "#0"},
"up": {"uv": [4, 0, 8, 4], "texture": "#0"},
"down": {"uv": [8, 0, 12, 4], "texture": "#0"}
}
}
]
}

View file

@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench by TyBraniff for Bluemaps support.",
"parent": "sign/hanging",
"textures": {
"wood": "entity/signs/hanging/acacia"
}
}

View file

@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench by TyBraniff for Bluemaps support.",
"parent": "sign/wall_hanging",
"textures": {
"wood": "entity/signs/hanging/acacia"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign",
"textures": {
"sign": "entity/signs/bamboo"
}
}

View file

@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench by TyBraniff for Bluemaps support.",
"parent": "sign/hanging",
"textures": {
"wood": "entity/signs/hanging/bamboo"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign_wall",
"textures": {
"sign": "entity/signs/bamboo"
}
}

View file

@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench by TyBraniff for Bluemaps support.",
"parent": "sign/wall_hanging",
"textures": {
"wood": "entity/signs/hanging/bamboo"
}
}

View file

@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench by TyBraniff for Bluemaps support.",
"parent": "sign/hanging",
"textures": {
"wood": "entity/signs/hanging/birch"
}
}

View file

@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench by TyBraniff for Bluemaps support.",
"parent": "sign/wall_hanging",
"textures": {
"wood": "entity/signs/hanging/birch"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign",
"textures": {
"sign": "entity/signs/cherry"
}
}

View file

@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench by TyBraniff for Bluemaps support.",
"parent": "sign/hanging",
"textures": {
"wood": "entity/signs/hanging/cherry"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "sign/sign_wall",
"textures": {
"sign": "entity/signs/cherry"
}
}

View file

@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench by TyBraniff for Bluemaps support.",
"parent": "sign/wall_hanging",
"textures": {
"wood": "entity/signs/hanging/cherry"
}
}

View file

@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench by TyBraniff for Bluemaps support.",
"parent": "sign/hanging",
"textures": {
"wood": "entity/signs/hanging/crimson"
}
}

View file

@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench by TyBraniff for Bluemaps support.",
"parent": "sign/wall_hanging",
"textures": {
"wood": "entity/signs/hanging/crimson"
}
}

Some files were not shown because too many files have changed in this diff Show more