Compare commits
111 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad275ae7d1 | ||
|
|
88bcc2fe41 | ||
|
|
15157484ab |
||
|
|
9769b9c023 |
||
|
|
923a70c7be |
||
|
|
cedb077cce |
||
|
|
9eb2124684 | ||
|
|
465190b1ea |
||
|
|
43a3a6398c |
||
|
|
627165ee76 |
||
|
|
226e4be4de |
||
|
|
e90b7269ee |
||
|
|
221e482e18 |
||
|
|
cfb9e9f6be |
||
|
|
0f5b33cb94 |
||
|
|
b0415ba05a | ||
|
|
f12d84e5e5 |
||
|
|
e506c5ad89 |
||
|
|
72c58f6ae5 |
||
|
|
d91080d8b2 |
||
|
|
c41b5b3b27 |
||
|
|
9a1cb498fe |
||
|
|
a11aee6881 |
||
|
|
b0d881c827 |
||
|
|
25bd72cd31 |
||
|
|
c0b33897ed |
||
|
|
1705a52b20 |
||
|
|
b7c25283ad |
||
|
|
a3cb14ee1d |
||
|
|
cdc6ea3438 |
||
|
|
225f9572e3 |
||
|
|
a213f11047 |
||
|
|
1c2e857059 |
||
|
|
75daafb08a |
||
|
|
a906e4a3db |
||
|
|
7c891e819a |
||
|
|
d60f9fc55f |
||
|
|
6329671f7f | ||
|
|
634e711c93 | ||
|
|
18400e3852 |
||
|
|
f45e1823e6 | ||
|
|
169bde30b2 |
||
|
|
17df58de1d |
||
|
|
0896b61df0 |
||
|
|
8dd6715b3e |
||
|
|
ce601caf2a |
||
|
|
a2bd1bda04 | ||
|
|
c8416261c6 |
||
|
|
369586897a |
||
|
|
4d977d39b4 |
||
|
|
f1f407851a |
||
|
|
f13e535ea1 |
||
|
|
9bcdd292e0 |
||
|
|
eb7670160b |
||
|
|
e222e7fcfd |
||
|
|
396c65b6f5 |
||
|
|
e3525dd5ec |
||
|
|
c907eaec23 |
||
|
|
dedb5683cd | ||
|
|
8c5c575cc3 | ||
|
|
d5e5baaac0 |
||
|
|
3a7e26cd65 |
||
|
|
825097fe26 |
||
|
|
6a215966ad | ||
|
|
0d20c70ee7 | ||
|
|
abc0b4f31e |
||
|
|
7220e3921f |
||
|
|
7efd187b29 |
||
|
|
0c032cdc57 |
||
|
|
0600a730e9 |
||
|
|
37ffc6566b |
||
|
|
d30849b41a | ||
|
|
f846da28f6 |
||
|
|
eb4173bfcb |
||
|
|
a87f6d3fa3 |
||
|
|
05624b2dc5 |
||
|
|
dbfeb6f7a5 | ||
|
|
575c8e62ee | ||
|
|
ede0b6772e |
||
|
|
96010e940b | ||
|
|
0c09a93f8f |
||
|
|
3c53bcf3ec |
||
|
|
1cef205fdc |
||
|
|
e94d4d78e5 |
||
|
|
c2ff35ba62 |
||
|
|
016f6a5c11 |
||
|
|
0c09e30305 | ||
|
|
9d9cc2d576 |
||
|
|
e722135925 |
||
|
|
33327bf680 |
||
|
|
829d7e20f2 |
||
|
|
3ae7447094 | ||
|
|
f58eb01c79 |
||
|
|
fd64dac2c0 | ||
|
|
f61ed17f81 | ||
|
|
f4d5a4695d |
||
|
|
ceaf169c7b |
||
|
|
a5296f9499 |
||
|
|
32b525c0e2 | ||
|
|
fa907169f2 |
||
|
|
ee129f5696 | ||
|
|
6933880cff |
||
|
|
ec7b3b920d | ||
|
|
59b689d931 |
||
|
|
d16b1fe7f4 |
||
|
|
4c3b996be6 | ||
|
|
0fea4a1383 |
||
|
|
ae56415f05 |
||
|
|
4990d9f42f |
||
|
|
2bf48a1ad6 |
||
|
|
24b2e33153 |
42 changed files with 219 additions and 1438 deletions
2
.github/workflows/benchmark.yml
vendored
2
.github/workflows/benchmark.yml
vendored
|
|
@ -26,7 +26,7 @@ jobs:
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 18
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
- name: Move Cypress to dependencies
|
- name: Move Cypress to dependencies
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
|
|
@ -49,10 +49,6 @@ jobs:
|
||||||
publish_dir: .vercel/output/static
|
publish_dir: .vercel/output/static
|
||||||
force_orphan: true
|
force_orphan: true
|
||||||
|
|
||||||
# Create CNAME file for custom domain
|
|
||||||
- name: Create CNAME file
|
|
||||||
run: echo "github.mcraft.fun" > .vercel/output/static/CNAME
|
|
||||||
|
|
||||||
- name: Deploy to mwc-mcraft-pages repository
|
- name: Deploy to mwc-mcraft-pages repository
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
with:
|
with:
|
||||||
|
|
@ -61,6 +57,7 @@ jobs:
|
||||||
publish_dir: .vercel/output/static
|
publish_dir: .vercel/output/static
|
||||||
publish_branch: main
|
publish_branch: main
|
||||||
destination_dir: docs
|
destination_dir: docs
|
||||||
|
cname: github.mcraft.fun
|
||||||
force_orphan: true
|
force_orphan: true
|
||||||
|
|
||||||
- name: Change index.html title
|
- name: Change index.html title
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,6 @@ There is a builtin proxy, but you can also host your one! Just clone the repo, r
|
||||||
|
|
||||||
[](https://app.koyeb.com/deploy?name=minecraft-web-client&type=git&repository=zardoy%2Fminecraft-web-client&branch=next&builder=dockerfile&env%5B%5D=&ports=8080%3Bhttp%3B%2F)
|
[](https://app.koyeb.com/deploy?name=minecraft-web-client&type=git&repository=zardoy%2Fminecraft-web-client&branch=next&builder=dockerfile&env%5B%5D=&ports=8080%3Bhttp%3B%2F)
|
||||||
|
|
||||||
> **Note**: If you want to make **your own** Minecraft server accessible to web clients (without our proxies), you can use [mwc-proxy](https://github.com/zardoy/mwc-proxy) - a lightweight JS WebSocket proxy that runs on the same server as your Minecraft server, allowing players to connect directly via `wss://play.example.com`. `?client_mcraft` is added to the URL, so the proxy will know that it's this client.
|
|
||||||
|
|
||||||
Proxy servers are used to connect to Minecraft servers which use TCP protocol. When you connect connect to a server with a proxy, websocket connection is created between you (browser client) and the proxy server located in Europe, then the proxy connects to the Minecraft server and sends the data to the client (you) without any packet deserialization to avoid any additional delays. That said all the Minecraft protocol packets are processed by the client, right in your browser.
|
Proxy servers are used to connect to Minecraft servers which use TCP protocol. When you connect connect to a server with a proxy, websocket connection is created between you (browser client) and the proxy server located in Europe, then the proxy connects to the Minecraft server and sends the data to the client (you) without any packet deserialization to avoid any additional delays. That said all the Minecraft protocol packets are processed by the client, right in your browser.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
|
@ -178,7 +176,6 @@ Server specific:
|
||||||
- `?lockConnect=true` - Only works then `ip` parameter is set. Disables cancel/save buttons and all inputs in the connect screen already set as parameters. Useful for integrates iframes.
|
- `?lockConnect=true` - Only works then `ip` parameter is set. Disables cancel/save buttons and all inputs in the connect screen already set as parameters. Useful for integrates iframes.
|
||||||
- `?autoConnect=true` - Only works then `ip` and `version` parameters are set and `allowAutoConnect` is `true` in config.json! Directly connects to the specified server. Useful for integrates iframes.
|
- `?autoConnect=true` - Only works then `ip` and `version` parameters are set and `allowAutoConnect` is `true` in config.json! Directly connects to the specified server. Useful for integrates iframes.
|
||||||
- `?serversList=<list_or_url>` - `<list_or_url>` can be a list of servers in the format `ip:version,ip` or a url to a json file with the same format (array) or a txt file with line-delimited list of server IPs.
|
- `?serversList=<list_or_url>` - `<list_or_url>` can be a list of servers in the format `ip:version,ip` or a url to a json file with the same format (array) or a txt file with line-delimited list of server IPs.
|
||||||
- `?addPing=<ping>` - Add a latency to both sides of the connection. Useful for testing ping issues. For example `?addPing=100` will add 200ms to your ping.
|
|
||||||
|
|
||||||
Single player specific:
|
Single player specific:
|
||||||
|
|
||||||
|
|
@ -235,4 +232,3 @@ Only during development:
|
||||||
|
|
||||||
- [https://github.com/ClassiCube/ClassiCube](ClassiCube - Better C# Rewrite) [DEMO](https://www.classicube.net/server/play/?warned=true)
|
- [https://github.com/ClassiCube/ClassiCube](ClassiCube - Better C# Rewrite) [DEMO](https://www.classicube.net/server/play/?warned=true)
|
||||||
- [https://m.eaglercraft.com/](EaglerCraft) - Eaglercraft runnable on mobile (real Minecraft in the browser)
|
- [https://m.eaglercraft.com/](EaglerCraft) - Eaglercraft runnable on mobile (real Minecraft in the browser)
|
||||||
- [js-minecraft](https://github.com/LabyStudio/js-minecraft) - An insanely well done clone from the graphical side that inspired many features here
|
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,6 @@
|
||||||
{
|
{
|
||||||
"ip": "wss://play.mcraft.fun"
|
"ip": "wss://play.mcraft.fun"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ip": "wss://play.webmc.fun",
|
|
||||||
"name": "WebMC"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ip": "wss://ws.fuchsmc.net"
|
"ip": "wss://ws.fuchsmc.net"
|
||||||
},
|
},
|
||||||
|
|
@ -31,7 +27,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"rightSideText": "A Minecraft client clone in the browser!",
|
"rightSideText": "A Minecraft client clone in the browser!",
|
||||||
"splashText": "The sunset is coming!",
|
"splashText": "We are back!",
|
||||||
"splashTextFallback": "Welcome!",
|
"splashTextFallback": "Welcome!",
|
||||||
"pauseLinks": [
|
"pauseLinks": [
|
||||||
[
|
[
|
||||||
|
|
|
||||||
|
|
@ -80,14 +80,14 @@
|
||||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"filesize": "^10.0.12",
|
"filesize": "^10.0.12",
|
||||||
"flying-squid": "npm:@zardoy/flying-squid@^0.0.104",
|
"flying-squid": "npm:@zardoy/flying-squid@^0.0.62",
|
||||||
"framer-motion": "^12.9.2",
|
"framer-motion": "^12.9.2",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"google-drive-browserfs": "github:zardoy/browserfs#google-drive",
|
"google-drive-browserfs": "github:zardoy/browserfs#google-drive",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mcraft-fun-mineflayer": "^0.1.23",
|
"mcraft-fun-mineflayer": "^0.1.23",
|
||||||
"minecraft-data": "3.98.0",
|
"minecraft-data": "3.92.0",
|
||||||
"minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol#master",
|
"minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol#master",
|
||||||
"mineflayer-item-map-downloader": "github:zardoy/mineflayer-item-map-downloader",
|
"mineflayer-item-map-downloader": "github:zardoy/mineflayer-item-map-downloader",
|
||||||
"mojangson": "^2.0.4",
|
"mojangson": "^2.0.4",
|
||||||
|
|
@ -157,7 +157,7 @@
|
||||||
"mc-assets": "^0.2.62",
|
"mc-assets": "^0.2.62",
|
||||||
"minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next",
|
"minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next",
|
||||||
"mineflayer": "github:zardoy/mineflayer#gen-the-master",
|
"mineflayer": "github:zardoy/mineflayer#gen-the-master",
|
||||||
"mineflayer-mouse": "^0.1.21",
|
"mineflayer-mouse": "^0.1.17",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"os-browserify": "^0.3.0",
|
"os-browserify": "^0.3.0",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
|
|
@ -205,7 +205,7 @@
|
||||||
"diamond-square": "github:zardoy/diamond-square",
|
"diamond-square": "github:zardoy/diamond-square",
|
||||||
"prismarine-block": "github:zardoy/prismarine-block#next-era",
|
"prismarine-block": "github:zardoy/prismarine-block#next-era",
|
||||||
"prismarine-world": "github:zardoy/prismarine-world#next-era",
|
"prismarine-world": "github:zardoy/prismarine-world#next-era",
|
||||||
"minecraft-data": "3.98.0",
|
"minecraft-data": "3.92.0",
|
||||||
"prismarine-provider-anvil": "github:zardoy/prismarine-provider-anvil#everything",
|
"prismarine-provider-anvil": "github:zardoy/prismarine-provider-anvil#everything",
|
||||||
"prismarine-physics": "github:zardoy/prismarine-physics",
|
"prismarine-physics": "github:zardoy/prismarine-physics",
|
||||||
"minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol#master",
|
"minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol#master",
|
||||||
|
|
|
||||||
148
pnpm-lock.yaml
generated
148
pnpm-lock.yaml
generated
|
|
@ -13,7 +13,7 @@ overrides:
|
||||||
diamond-square: github:zardoy/diamond-square
|
diamond-square: github:zardoy/diamond-square
|
||||||
prismarine-block: github:zardoy/prismarine-block#next-era
|
prismarine-block: github:zardoy/prismarine-block#next-era
|
||||||
prismarine-world: github:zardoy/prismarine-world#next-era
|
prismarine-world: github:zardoy/prismarine-world#next-era
|
||||||
minecraft-data: 3.98.0
|
minecraft-data: 3.92.0
|
||||||
prismarine-provider-anvil: github:zardoy/prismarine-provider-anvil#everything
|
prismarine-provider-anvil: github:zardoy/prismarine-provider-anvil#everything
|
||||||
prismarine-physics: github:zardoy/prismarine-physics
|
prismarine-physics: github:zardoy/prismarine-physics
|
||||||
minecraft-protocol: github:PrismarineJS/node-minecraft-protocol#master
|
minecraft-protocol: github:PrismarineJS/node-minecraft-protocol#master
|
||||||
|
|
@ -121,8 +121,8 @@ importers:
|
||||||
specifier: ^10.0.12
|
specifier: ^10.0.12
|
||||||
version: 10.1.6
|
version: 10.1.6
|
||||||
flying-squid:
|
flying-squid:
|
||||||
specifier: npm:@zardoy/flying-squid@^0.0.104
|
specifier: npm:@zardoy/flying-squid@^0.0.62
|
||||||
version: '@zardoy/flying-squid@0.0.104(encoding@0.1.13)'
|
version: '@zardoy/flying-squid@0.0.62(encoding@0.1.13)'
|
||||||
framer-motion:
|
framer-motion:
|
||||||
specifier: ^12.9.2
|
specifier: ^12.9.2
|
||||||
version: 12.9.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 12.9.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
|
@ -140,13 +140,13 @@ importers:
|
||||||
version: 4.17.21
|
version: 4.17.21
|
||||||
mcraft-fun-mineflayer:
|
mcraft-fun-mineflayer:
|
||||||
specifier: ^0.1.23
|
specifier: ^0.1.23
|
||||||
version: 0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13))
|
version: 0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/86e65631e79c490021afc63c80091a7bb6019fa8(encoding@0.1.13))
|
||||||
minecraft-data:
|
minecraft-data:
|
||||||
specifier: 3.98.0
|
specifier: 3.92.0
|
||||||
version: 3.98.0
|
version: 3.92.0
|
||||||
minecraft-protocol:
|
minecraft-protocol:
|
||||||
specifier: github:PrismarineJS/node-minecraft-protocol#master
|
specifier: github:PrismarineJS/node-minecraft-protocol#master
|
||||||
version: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13)
|
version: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/c561917bf7e7966911321512c2a6895a3f9da074(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13)
|
||||||
mineflayer-item-map-downloader:
|
mineflayer-item-map-downloader:
|
||||||
specifier: github:zardoy/mineflayer-item-map-downloader
|
specifier: github:zardoy/mineflayer-item-map-downloader
|
||||||
version: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824(patch_hash=a731ebbace2d8790c973ab3a5ba33494a6e9658533a9710dd8ba36f86db061ad)(encoding@0.1.13)
|
version: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824(patch_hash=a731ebbace2d8790c973ab3a5ba33494a6e9658533a9710dd8ba36f86db061ad)(encoding@0.1.13)
|
||||||
|
|
@ -155,7 +155,7 @@ importers:
|
||||||
version: 2.0.4
|
version: 2.0.4
|
||||||
net-browserify:
|
net-browserify:
|
||||||
specifier: github:zardoy/prismarinejs-net-browserify
|
specifier: github:zardoy/prismarinejs-net-browserify
|
||||||
version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e754999ffdea67853bc9b10553b5e9908b40f618
|
version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/17fb901e8ea480a52c8fd46373695be172be8aa5
|
||||||
node-gzip:
|
node-gzip:
|
||||||
specifier: ^1.1.2
|
specifier: ^1.1.2
|
||||||
version: 1.1.2
|
version: 1.1.2
|
||||||
|
|
@ -170,7 +170,7 @@ importers:
|
||||||
version: 6.1.1
|
version: 6.1.1
|
||||||
prismarine-provider-anvil:
|
prismarine-provider-anvil:
|
||||||
specifier: github:zardoy/prismarine-provider-anvil#everything
|
specifier: github:zardoy/prismarine-provider-anvil#everything
|
||||||
version: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.98.0)
|
version: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.92.0)
|
||||||
prosemirror-example-setup:
|
prosemirror-example-setup:
|
||||||
specifier: ^1.2.2
|
specifier: ^1.2.2
|
||||||
version: 1.2.3
|
version: 1.2.3
|
||||||
|
|
@ -345,10 +345,10 @@ importers:
|
||||||
version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/89c33d396f3fde4804c71f4be3c203ade1833b41(@types/react@18.3.18)(react@18.3.1)
|
version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/89c33d396f3fde4804c71f4be3c203ade1833b41(@types/react@18.3.18)(react@18.3.1)
|
||||||
mineflayer:
|
mineflayer:
|
||||||
specifier: github:zardoy/mineflayer#gen-the-master
|
specifier: github:zardoy/mineflayer#gen-the-master
|
||||||
version: https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13)
|
version: https://codeload.github.com/zardoy/mineflayer/tar.gz/86e65631e79c490021afc63c80091a7bb6019fa8(encoding@0.1.13)
|
||||||
mineflayer-mouse:
|
mineflayer-mouse:
|
||||||
specifier: ^0.1.21
|
specifier: ^0.1.17
|
||||||
version: 0.1.21
|
version: 0.1.17
|
||||||
npm-run-all:
|
npm-run-all:
|
||||||
specifier: ^4.1.5
|
specifier: ^4.1.5
|
||||||
version: 4.1.5
|
version: 4.1.5
|
||||||
|
|
@ -436,7 +436,7 @@ importers:
|
||||||
version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
||||||
prismarine-chunk:
|
prismarine-chunk:
|
||||||
specifier: github:zardoy/prismarine-chunk#master
|
specifier: github:zardoy/prismarine-chunk#master
|
||||||
version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0)
|
version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.92.0)
|
||||||
prismarine-schematic:
|
prismarine-schematic:
|
||||||
specifier: ^1.2.0
|
specifier: ^1.2.0
|
||||||
version: 1.2.3
|
version: 1.2.3
|
||||||
|
|
@ -3387,13 +3387,13 @@ packages:
|
||||||
resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==}
|
resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==}
|
||||||
engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'}
|
engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'}
|
||||||
|
|
||||||
'@zardoy/flying-squid@0.0.104':
|
'@zardoy/flying-squid@0.0.49':
|
||||||
resolution: {integrity: sha512-jGhQ7fn7o8UN+mUwZbt9674D37YLuBi+Au4TwKcopCA6huIQdHTFNl2e+0ZSTI5mnhN+NpyVoR3vmtH6L58vHQ==}
|
resolution: {integrity: sha512-Kt4wr5/R+44tcLU9gjuNG2an9weWeKEpIoKXfsgJN2GGQqdnbd5nBpxfGDdgZ9aMdFugsVW8BsyPZNhj9vbMXA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
'@zardoy/flying-squid@0.0.49':
|
'@zardoy/flying-squid@0.0.62':
|
||||||
resolution: {integrity: sha512-Kt4wr5/R+44tcLU9gjuNG2an9weWeKEpIoKXfsgJN2GGQqdnbd5nBpxfGDdgZ9aMdFugsVW8BsyPZNhj9vbMXA==}
|
resolution: {integrity: sha512-M6icydO/yrmwevBhmgKcqEPC63AhWfU/Es9N/uadVrmKaxGm2FQMMLcybbutRYm1xZ6qsdxDUOUZnN56PsVwfQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
|
@ -6444,12 +6444,6 @@ packages:
|
||||||
resolution: {integrity: sha512-RYZeD1+joNlPuUpi+tIWkbP0ieVJr+R6IFkI6/8juhSxx9zE4osoSmteybrfspGm8A6u+YbbY1epqRKEMwVR6Q==}
|
resolution: {integrity: sha512-RYZeD1+joNlPuUpi+tIWkbP0ieVJr+R6IFkI6/8juhSxx9zE4osoSmteybrfspGm8A6u+YbbY1epqRKEMwVR6Q==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
|
|
||||||
mc-bridge@0.1.3:
|
|
||||||
resolution: {integrity: sha512-H9jPt2xEU77itC27dSz3qazHYqN9qVsv4HgMPozg7RqQ1uwgXmEa+ojKIlDtXf/TLJsG6Kv4EbzGa8a1Wh72uA==}
|
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
|
||||||
peerDependencies:
|
|
||||||
minecraft-data: 3.98.0
|
|
||||||
|
|
||||||
mcraft-fun-mineflayer@0.1.23:
|
mcraft-fun-mineflayer@0.1.23:
|
||||||
resolution: {integrity: sha512-qmI1rQQ0Ro5zJdi99rClWLF+mS9JZffgNX2vyWWesS3Hsk3Xblp/8swYTJKHSaFpNgzkVfXV92fEIrBqeH6iKA==}
|
resolution: {integrity: sha512-qmI1rQQ0Ro5zJdi99rClWLF+mS9JZffgNX2vyWWesS3Hsk3Xblp/8swYTJKHSaFpNgzkVfXV92fEIrBqeH6iKA==}
|
||||||
version: 0.1.23
|
version: 0.1.23
|
||||||
|
|
@ -6658,8 +6652,8 @@ packages:
|
||||||
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
minecraft-data@3.98.0:
|
minecraft-data@3.92.0:
|
||||||
resolution: {integrity: sha512-JAPqJ/TZoxMUlAPPdWUh1v5wdqvYGFSZ4rW9bUtmaKBkGpomDSjw4V02ocBqbxKJvcTtmc5nM/LfN9/0DDqHrQ==}
|
resolution: {integrity: sha512-CGfO50svzm+pSRa4Mbq4owsmRKbPCNkSZ3MCOyH+epC7yNjh+PUhPQFHWq72O51qsY7pAB5qM/bJn1ncwG1J5g==}
|
||||||
|
|
||||||
minecraft-folder-path@1.2.0:
|
minecraft-folder-path@1.2.0:
|
||||||
resolution: {integrity: sha512-qaUSbKWoOsH9brn0JQuBhxNAzTDMwrOXorwuRxdJKKKDYvZhtml+6GVCUrY5HRiEsieBEjCUnhVpDuQiKsiFaw==}
|
resolution: {integrity: sha512-qaUSbKWoOsH9brn0JQuBhxNAzTDMwrOXorwuRxdJKKKDYvZhtml+6GVCUrY5HRiEsieBEjCUnhVpDuQiKsiFaw==}
|
||||||
|
|
@ -6668,9 +6662,9 @@ packages:
|
||||||
resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/89c33d396f3fde4804c71f4be3c203ade1833b41}
|
resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/89c33d396f3fde4804c71f4be3c203ade1833b41}
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
|
|
||||||
minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9:
|
minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/c561917bf7e7966911321512c2a6895a3f9da074:
|
||||||
resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9}
|
resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/c561917bf7e7966911321512c2a6895a3f9da074}
|
||||||
version: 1.62.0
|
version: 1.61.0
|
||||||
engines: {node: '>=22'}
|
engines: {node: '>=22'}
|
||||||
|
|
||||||
minecraft-wrap@1.6.0:
|
minecraft-wrap@1.6.0:
|
||||||
|
|
@ -6684,12 +6678,12 @@ packages:
|
||||||
resolution: {tarball: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824}
|
resolution: {tarball: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824}
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
|
|
||||||
mineflayer-mouse@0.1.21:
|
mineflayer-mouse@0.1.17:
|
||||||
resolution: {integrity: sha512-1XTVuw3twIrEcqQ1QRSB8NcStIUEZ+tbxiAG6rOrN/9M4thhtlS5PTJzFdmdrcYgWEBLvuOdJszaKE5zFfiXhg==}
|
resolution: {integrity: sha512-0eCR8pnGb42Qd9QmAxOjl0PhA5Fa+9+6H1G/YsbsO5rg5mDf94Tusqp/8NAGLPQCPVDzbarLskXdjR3h0E0bEQ==}
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
|
||||||
mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659:
|
mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/86e65631e79c490021afc63c80091a7bb6019fa8:
|
||||||
resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659}
|
resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/86e65631e79c490021afc63c80091a7bb6019fa8}
|
||||||
version: 8.0.0
|
version: 8.0.0
|
||||||
engines: {node: '>=22'}
|
engines: {node: '>=22'}
|
||||||
|
|
||||||
|
|
@ -6855,8 +6849,8 @@ packages:
|
||||||
neo-async@2.6.2:
|
neo-async@2.6.2:
|
||||||
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
||||||
|
|
||||||
net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e754999ffdea67853bc9b10553b5e9908b40f618:
|
net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/17fb901e8ea480a52c8fd46373695be172be8aa5:
|
||||||
resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e754999ffdea67853bc9b10553b5e9908b40f618}
|
resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/17fb901e8ea480a52c8fd46373695be172be8aa5}
|
||||||
version: 0.2.4
|
version: 0.2.4
|
||||||
|
|
||||||
nice-try@1.0.5:
|
nice-try@1.0.5:
|
||||||
|
|
@ -7387,7 +7381,7 @@ packages:
|
||||||
prismarine-biome@1.3.0:
|
prismarine-biome@1.3.0:
|
||||||
resolution: {integrity: sha512-GY6nZxq93mTErT7jD7jt8YS1aPrOakbJHh39seYsJFXvueIOdHAmW16kYQVrTVMW5MlWLQVxV/EquRwOgr4MnQ==}
|
resolution: {integrity: sha512-GY6nZxq93mTErT7jD7jt8YS1aPrOakbJHh39seYsJFXvueIOdHAmW16kYQVrTVMW5MlWLQVxV/EquRwOgr4MnQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
minecraft-data: 3.98.0
|
minecraft-data: 3.92.0
|
||||||
prismarine-registry: ^1.1.0
|
prismarine-registry: ^1.1.0
|
||||||
|
|
||||||
prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9:
|
prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9:
|
||||||
|
|
@ -11343,8 +11337,8 @@ snapshots:
|
||||||
'@nxg-org/mineflayer-trajectories@1.2.0(encoding@0.1.13)':
|
'@nxg-org/mineflayer-trajectories@1.2.0(encoding@0.1.13)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nxg-org/mineflayer-util-plugin': 1.8.4
|
'@nxg-org/mineflayer-util-plugin': 1.8.4
|
||||||
minecraft-data: 3.98.0
|
minecraft-data: 3.92.0
|
||||||
mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13)
|
mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/86e65631e79c490021afc63c80091a7bb6019fa8(encoding@0.1.13)
|
||||||
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
||||||
prismarine-item: 1.17.0
|
prismarine-item: 1.17.0
|
||||||
prismarine-physics: https://codeload.github.com/zardoy/prismarine-physics/tar.gz/353e25b800149393f40539ec381218be44cbb03b
|
prismarine-physics: https://codeload.github.com/zardoy/prismarine-physics/tar.gz/353e25b800149393f40539ec381218be44cbb03b
|
||||||
|
|
@ -13094,7 +13088,7 @@ snapshots:
|
||||||
'@types/emscripten': 1.40.0
|
'@types/emscripten': 1.40.0
|
||||||
tslib: 1.14.1
|
tslib: 1.14.1
|
||||||
|
|
||||||
'@zardoy/flying-squid@0.0.104(encoding@0.1.13)':
|
'@zardoy/flying-squid@0.0.49(encoding@0.1.13)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tootallnate/once': 2.0.0
|
'@tootallnate/once': 2.0.0
|
||||||
chalk: 5.4.1
|
chalk: 5.4.1
|
||||||
|
|
@ -13104,18 +13098,16 @@ snapshots:
|
||||||
exit-hook: 2.2.1
|
exit-hook: 2.2.1
|
||||||
flatmap: 0.0.3
|
flatmap: 0.0.3
|
||||||
long: 5.3.1
|
long: 5.3.1
|
||||||
mc-bridge: 0.1.3(minecraft-data@3.98.0)
|
minecraft-data: 3.92.0
|
||||||
minecraft-data: 3.98.0
|
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/c561917bf7e7966911321512c2a6895a3f9da074(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13)
|
||||||
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13)
|
|
||||||
mkdirp: 2.1.6
|
mkdirp: 2.1.6
|
||||||
node-gzip: 1.1.2
|
node-gzip: 1.1.2
|
||||||
node-rsa: 1.1.1
|
node-rsa: 1.1.1
|
||||||
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.92.0)
|
||||||
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0)
|
|
||||||
prismarine-entity: 2.5.0
|
prismarine-entity: 2.5.0
|
||||||
prismarine-item: 1.17.0
|
prismarine-item: 1.17.0
|
||||||
prismarine-nbt: 2.7.0
|
prismarine-nbt: 2.7.0
|
||||||
prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.98.0)
|
prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.92.0)
|
||||||
prismarine-windows: 2.9.0
|
prismarine-windows: 2.9.0
|
||||||
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c
|
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c
|
||||||
rambda: 9.4.2
|
rambda: 9.4.2
|
||||||
|
|
@ -13132,7 +13124,7 @@ snapshots:
|
||||||
- encoding
|
- encoding
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@zardoy/flying-squid@0.0.49(encoding@0.1.13)':
|
'@zardoy/flying-squid@0.0.62(encoding@0.1.13)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tootallnate/once': 2.0.0
|
'@tootallnate/once': 2.0.0
|
||||||
chalk: 5.4.1
|
chalk: 5.4.1
|
||||||
|
|
@ -13142,16 +13134,16 @@ snapshots:
|
||||||
exit-hook: 2.2.1
|
exit-hook: 2.2.1
|
||||||
flatmap: 0.0.3
|
flatmap: 0.0.3
|
||||||
long: 5.3.1
|
long: 5.3.1
|
||||||
minecraft-data: 3.98.0
|
minecraft-data: 3.92.0
|
||||||
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13)
|
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/c561917bf7e7966911321512c2a6895a3f9da074(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13)
|
||||||
mkdirp: 2.1.6
|
mkdirp: 2.1.6
|
||||||
node-gzip: 1.1.2
|
node-gzip: 1.1.2
|
||||||
node-rsa: 1.1.1
|
node-rsa: 1.1.1
|
||||||
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0)
|
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.92.0)
|
||||||
prismarine-entity: 2.5.0
|
prismarine-entity: 2.5.0
|
||||||
prismarine-item: 1.17.0
|
prismarine-item: 1.17.0
|
||||||
prismarine-nbt: 2.7.0
|
prismarine-nbt: 2.7.0
|
||||||
prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.98.0)
|
prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.92.0)
|
||||||
prismarine-windows: 2.9.0
|
prismarine-windows: 2.9.0
|
||||||
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c
|
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c
|
||||||
rambda: 9.4.2
|
rambda: 9.4.2
|
||||||
|
|
@ -14542,8 +14534,8 @@ snapshots:
|
||||||
|
|
||||||
diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/cfaad2d1d5909fdfa63c8cc7bc05fb5e87782d71:
|
diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/cfaad2d1d5909fdfa63c8cc7bc05fb5e87782d71:
|
||||||
dependencies:
|
dependencies:
|
||||||
minecraft-data: 3.98.0
|
minecraft-data: 3.92.0
|
||||||
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0)
|
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.92.0)
|
||||||
prismarine-registry: 1.11.0
|
prismarine-registry: 1.11.0
|
||||||
random-seed: 0.3.0
|
random-seed: 0.3.0
|
||||||
vec3: 0.1.10
|
vec3: 0.1.10
|
||||||
|
|
@ -16986,16 +16978,12 @@ snapshots:
|
||||||
maxrects-packer: '@zardoy/maxrects-packer@2.7.4'
|
maxrects-packer: '@zardoy/maxrects-packer@2.7.4'
|
||||||
zod: 3.24.2
|
zod: 3.24.2
|
||||||
|
|
||||||
mc-bridge@0.1.3(minecraft-data@3.98.0):
|
mcraft-fun-mineflayer@0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/86e65631e79c490021afc63c80091a7bb6019fa8(encoding@0.1.13)):
|
||||||
dependencies:
|
|
||||||
minecraft-data: 3.98.0
|
|
||||||
|
|
||||||
mcraft-fun-mineflayer@0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13)):
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@zardoy/flying-squid': 0.0.49(encoding@0.1.13)
|
'@zardoy/flying-squid': 0.0.49(encoding@0.1.13)
|
||||||
exit-hook: 2.2.1
|
exit-hook: 2.2.1
|
||||||
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13)
|
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/c561917bf7e7966911321512c2a6895a3f9da074(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13)
|
||||||
mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13)
|
mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/86e65631e79c490021afc63c80091a7bb6019fa8(encoding@0.1.13)
|
||||||
prismarine-item: 1.17.0
|
prismarine-item: 1.17.0
|
||||||
ws: 8.18.1
|
ws: 8.18.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
|
@ -17302,7 +17290,7 @@ snapshots:
|
||||||
|
|
||||||
min-indent@1.0.1: {}
|
min-indent@1.0.1: {}
|
||||||
|
|
||||||
minecraft-data@3.98.0: {}
|
minecraft-data@3.92.0: {}
|
||||||
|
|
||||||
minecraft-folder-path@1.2.0: {}
|
minecraft-folder-path@1.2.0: {}
|
||||||
|
|
||||||
|
|
@ -17313,7 +17301,7 @@ snapshots:
|
||||||
- '@types/react'
|
- '@types/react'
|
||||||
- react
|
- react
|
||||||
|
|
||||||
minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13):
|
minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/c561917bf7e7966911321512c2a6895a3f9da074(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node-rsa': 1.1.4
|
'@types/node-rsa': 1.1.4
|
||||||
'@types/readable-stream': 4.0.18
|
'@types/readable-stream': 4.0.18
|
||||||
|
|
@ -17322,7 +17310,7 @@ snapshots:
|
||||||
debug: 4.4.0(supports-color@8.1.1)
|
debug: 4.4.0(supports-color@8.1.1)
|
||||||
endian-toggle: 0.0.0
|
endian-toggle: 0.0.0
|
||||||
lodash.merge: 4.6.2
|
lodash.merge: 4.6.2
|
||||||
minecraft-data: 3.98.0
|
minecraft-data: 3.92.0
|
||||||
minecraft-folder-path: 1.2.0
|
minecraft-folder-path: 1.2.0
|
||||||
node-fetch: 2.7.0(encoding@0.1.13)
|
node-fetch: 2.7.0(encoding@0.1.13)
|
||||||
node-rsa: 0.4.2
|
node-rsa: 0.4.2
|
||||||
|
|
@ -17365,13 +17353,13 @@ snapshots:
|
||||||
|
|
||||||
mineflayer-item-map-downloader@https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824(patch_hash=a731ebbace2d8790c973ab3a5ba33494a6e9658533a9710dd8ba36f86db061ad)(encoding@0.1.13):
|
mineflayer-item-map-downloader@https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824(patch_hash=a731ebbace2d8790c973ab3a5ba33494a6e9658533a9710dd8ba36f86db061ad)(encoding@0.1.13):
|
||||||
dependencies:
|
dependencies:
|
||||||
mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13)
|
mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/86e65631e79c490021afc63c80091a7bb6019fa8(encoding@0.1.13)
|
||||||
sharp: 0.30.7
|
sharp: 0.30.7
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- encoding
|
- encoding
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
mineflayer-mouse@0.1.21:
|
mineflayer-mouse@0.1.17:
|
||||||
dependencies:
|
dependencies:
|
||||||
change-case: 5.4.4
|
change-case: 5.4.4
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
|
|
@ -17380,15 +17368,15 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dd3b1ff38506d6f72d90e8444186e4e75fe82659(encoding@0.1.13):
|
mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/86e65631e79c490021afc63c80091a7bb6019fa8(encoding@0.1.13):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nxg-org/mineflayer-physics-util': 1.8.10
|
'@nxg-org/mineflayer-physics-util': 1.8.10
|
||||||
minecraft-data: 3.98.0
|
minecraft-data: 3.92.0
|
||||||
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/bf89f7e86526c54d8c43f555d8f6dfa4948fd2d9(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13)
|
minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/c561917bf7e7966911321512c2a6895a3f9da074(patch_hash=4ebdae314c68d01ce7879445c0b8bde5f90373abba8b66ed00d42e7a5f542f8b)(encoding@0.1.13)
|
||||||
prismarine-biome: 1.3.0(minecraft-data@3.98.0)(prismarine-registry@1.11.0)
|
prismarine-biome: 1.3.0(minecraft-data@3.92.0)(prismarine-registry@1.11.0)
|
||||||
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
||||||
prismarine-chat: 1.11.0
|
prismarine-chat: 1.11.0
|
||||||
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0)
|
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.92.0)
|
||||||
prismarine-entity: 2.5.0
|
prismarine-entity: 2.5.0
|
||||||
prismarine-item: 1.17.0
|
prismarine-item: 1.17.0
|
||||||
prismarine-nbt: 2.7.0
|
prismarine-nbt: 2.7.0
|
||||||
|
|
@ -17586,7 +17574,7 @@ snapshots:
|
||||||
|
|
||||||
neo-async@2.6.2: {}
|
neo-async@2.6.2: {}
|
||||||
|
|
||||||
net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e754999ffdea67853bc9b10553b5e9908b40f618:
|
net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/17fb901e8ea480a52c8fd46373695be172be8aa5:
|
||||||
dependencies:
|
dependencies:
|
||||||
body-parser: 1.20.3
|
body-parser: 1.20.3
|
||||||
express: 4.21.2
|
express: 4.21.2
|
||||||
|
|
@ -18174,15 +18162,15 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
prismarine-biome@1.3.0(minecraft-data@3.98.0)(prismarine-registry@1.11.0):
|
prismarine-biome@1.3.0(minecraft-data@3.92.0)(prismarine-registry@1.11.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
minecraft-data: 3.98.0
|
minecraft-data: 3.92.0
|
||||||
prismarine-registry: 1.11.0
|
prismarine-registry: 1.11.0
|
||||||
|
|
||||||
prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9:
|
prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9:
|
||||||
dependencies:
|
dependencies:
|
||||||
minecraft-data: 3.98.0
|
minecraft-data: 3.92.0
|
||||||
prismarine-biome: 1.3.0(minecraft-data@3.98.0)(prismarine-registry@1.11.0)
|
prismarine-biome: 1.3.0(minecraft-data@3.92.0)(prismarine-registry@1.11.0)
|
||||||
prismarine-chat: 1.11.0
|
prismarine-chat: 1.11.0
|
||||||
prismarine-item: 1.17.0
|
prismarine-item: 1.17.0
|
||||||
prismarine-nbt: 2.7.0
|
prismarine-nbt: 2.7.0
|
||||||
|
|
@ -18194,9 +18182,9 @@ snapshots:
|
||||||
prismarine-nbt: 2.7.0
|
prismarine-nbt: 2.7.0
|
||||||
prismarine-registry: 1.11.0
|
prismarine-registry: 1.11.0
|
||||||
|
|
||||||
prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0):
|
prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.92.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
prismarine-biome: 1.3.0(minecraft-data@3.98.0)(prismarine-registry@1.11.0)
|
prismarine-biome: 1.3.0(minecraft-data@3.92.0)(prismarine-registry@1.11.0)
|
||||||
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
||||||
prismarine-nbt: 2.7.0
|
prismarine-nbt: 2.7.0
|
||||||
prismarine-registry: 1.11.0
|
prismarine-registry: 1.11.0
|
||||||
|
|
@ -18225,14 +18213,14 @@ snapshots:
|
||||||
|
|
||||||
prismarine-physics@https://codeload.github.com/zardoy/prismarine-physics/tar.gz/353e25b800149393f40539ec381218be44cbb03b:
|
prismarine-physics@https://codeload.github.com/zardoy/prismarine-physics/tar.gz/353e25b800149393f40539ec381218be44cbb03b:
|
||||||
dependencies:
|
dependencies:
|
||||||
minecraft-data: 3.98.0
|
minecraft-data: 3.92.0
|
||||||
prismarine-nbt: 2.7.0
|
prismarine-nbt: 2.7.0
|
||||||
vec3: 0.1.10
|
vec3: 0.1.10
|
||||||
|
|
||||||
prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.98.0):
|
prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.92.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
||||||
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.98.0)
|
prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.92.0)
|
||||||
prismarine-nbt: 2.7.0
|
prismarine-nbt: 2.7.0
|
||||||
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c
|
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c
|
||||||
uint4: 0.1.2
|
uint4: 0.1.2
|
||||||
|
|
@ -18254,13 +18242,13 @@ snapshots:
|
||||||
|
|
||||||
prismarine-registry@1.11.0:
|
prismarine-registry@1.11.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
minecraft-data: 3.98.0
|
minecraft-data: 3.92.0
|
||||||
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
||||||
prismarine-nbt: 2.7.0
|
prismarine-nbt: 2.7.0
|
||||||
|
|
||||||
prismarine-schematic@1.2.3:
|
prismarine-schematic@1.2.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
minecraft-data: 3.98.0
|
minecraft-data: 3.92.0
|
||||||
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9
|
||||||
prismarine-nbt: 2.7.0
|
prismarine-nbt: 2.7.0
|
||||||
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c
|
prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c
|
||||||
|
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
import { PlayerObject, PlayerAnimation } from 'skinview3d'
|
|
||||||
import * as THREE from 'three'
|
|
||||||
import { WalkingGeneralSwing } from '../three/entity/animations'
|
|
||||||
import { loadSkinImage, stevePngUrl } from './utils/skins'
|
|
||||||
|
|
||||||
export type PlayerObjectType = PlayerObject & {
|
|
||||||
animation?: PlayerAnimation
|
|
||||||
realPlayerUuid: string
|
|
||||||
realUsername: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createPlayerObject (options: {
|
|
||||||
username?: string
|
|
||||||
uuid?: string
|
|
||||||
scale?: number
|
|
||||||
}): {
|
|
||||||
playerObject: PlayerObjectType
|
|
||||||
wrapper: THREE.Group
|
|
||||||
} {
|
|
||||||
const wrapper = new THREE.Group()
|
|
||||||
const playerObject = new PlayerObject() as PlayerObjectType
|
|
||||||
|
|
||||||
playerObject.realPlayerUuid = options.uuid ?? ''
|
|
||||||
playerObject.realUsername = options.username ?? ''
|
|
||||||
playerObject.position.set(0, 16, 0)
|
|
||||||
|
|
||||||
// fix issues with starfield
|
|
||||||
playerObject.traverse((obj) => {
|
|
||||||
if (obj instanceof THREE.Mesh && obj.material instanceof THREE.MeshStandardMaterial) {
|
|
||||||
obj.material.transparent = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
wrapper.add(playerObject as any)
|
|
||||||
const scale = options.scale ?? (1 / 16)
|
|
||||||
wrapper.scale.set(scale, scale, scale)
|
|
||||||
wrapper.rotation.set(0, Math.PI, 0)
|
|
||||||
|
|
||||||
// Set up animation
|
|
||||||
playerObject.animation = new WalkingGeneralSwing()
|
|
||||||
;(playerObject.animation as WalkingGeneralSwing).isMoving = false
|
|
||||||
playerObject.animation.update(playerObject, 0)
|
|
||||||
|
|
||||||
return { playerObject, wrapper }
|
|
||||||
}
|
|
||||||
|
|
||||||
export const applySkinToPlayerObject = async (playerObject: PlayerObjectType, skinUrl: string) => {
|
|
||||||
return loadSkinImage(skinUrl || stevePngUrl).then(({ canvas }) => {
|
|
||||||
const skinTexture = new THREE.CanvasTexture(canvas)
|
|
||||||
skinTexture.magFilter = THREE.NearestFilter
|
|
||||||
skinTexture.minFilter = THREE.NearestFilter
|
|
||||||
skinTexture.needsUpdate = true
|
|
||||||
playerObject.skin.map = skinTexture as any
|
|
||||||
}).catch(console.error)
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,6 @@ import { Vec3 } from 'vec3'
|
||||||
import { BotEvents } from 'mineflayer'
|
import { BotEvents } from 'mineflayer'
|
||||||
import { proxy } from 'valtio'
|
import { proxy } from 'valtio'
|
||||||
import TypedEmitter from 'typed-emitter'
|
import TypedEmitter from 'typed-emitter'
|
||||||
import { Biome } from 'minecraft-data'
|
|
||||||
import { delayedIterator } from '../../playground/shared'
|
import { delayedIterator } from '../../playground/shared'
|
||||||
import { chunkPos } from './simpleUtils'
|
import { chunkPos } from './simpleUtils'
|
||||||
|
|
||||||
|
|
@ -29,8 +28,6 @@ export type WorldDataEmitterEvents = {
|
||||||
updateLight: (data: { pos: Vec3 }) => void
|
updateLight: (data: { pos: Vec3 }) => void
|
||||||
onWorldSwitch: () => void
|
onWorldSwitch: () => void
|
||||||
end: () => void
|
end: () => void
|
||||||
biomeUpdate: (data: { biome: Biome }) => void
|
|
||||||
biomeReset: () => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorldDataEmitterWorker extends (EventEmitter as new () => TypedEmitter<WorldDataEmitterEvents>) {
|
export class WorldDataEmitterWorker extends (EventEmitter as new () => TypedEmitter<WorldDataEmitterEvents>) {
|
||||||
|
|
@ -363,37 +360,8 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter<Wo
|
||||||
delete this.debugChunksInfo[`${pos.x},${pos.z}`]
|
delete this.debugChunksInfo[`${pos.x},${pos.z}`]
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBiomeId: number | null = null
|
|
||||||
|
|
||||||
udpateBiome (pos: Vec3) {
|
|
||||||
try {
|
|
||||||
const biomeId = this.world.getBiome(pos)
|
|
||||||
if (biomeId !== this.lastBiomeId) {
|
|
||||||
this.lastBiomeId = biomeId
|
|
||||||
const biomeData = loadedData.biomes[biomeId]
|
|
||||||
if (biomeData) {
|
|
||||||
this.emitter.emit('biomeUpdate', {
|
|
||||||
biome: biomeData
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// unknown biome
|
|
||||||
this.emitter.emit('biomeReset')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('error updating biome', e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lastPosCheck: Vec3 | null = null
|
|
||||||
async updatePosition (pos: Vec3, force = false) {
|
async updatePosition (pos: Vec3, force = false) {
|
||||||
if (!this.allowPositionUpdate) return
|
if (!this.allowPositionUpdate) return
|
||||||
const posFloored = pos.floored()
|
|
||||||
if (!force && this.lastPosCheck && this.lastPosCheck.equals(posFloored)) return
|
|
||||||
this.lastPosCheck = posFloored
|
|
||||||
|
|
||||||
this.udpateBiome(pos)
|
|
||||||
|
|
||||||
const [lastX, lastZ] = chunkPos(this.lastPos)
|
const [lastX, lastZ] = chunkPos(this.lastPos)
|
||||||
const [botX, botZ] = chunkPos(pos)
|
const [botX, botZ] = chunkPos(pos)
|
||||||
if (lastX !== botX || lastZ !== botZ || force) {
|
if (lastX !== botX || lastZ !== botZ || force) {
|
||||||
|
|
|
||||||
|
|
@ -32,45 +32,31 @@ const toMajorVersion = version => {
|
||||||
export const worldCleanup = buildCleanupDecorator('resetWorld')
|
export const worldCleanup = buildCleanupDecorator('resetWorld')
|
||||||
|
|
||||||
export const defaultWorldRendererConfig = {
|
export const defaultWorldRendererConfig = {
|
||||||
// Debug settings
|
|
||||||
showChunkBorders: false,
|
showChunkBorders: false,
|
||||||
enableDebugOverlay: false,
|
|
||||||
|
|
||||||
// Performance settings
|
|
||||||
mesherWorkers: 4,
|
mesherWorkers: 4,
|
||||||
addChunksBatchWaitTime: 200,
|
isPlayground: false,
|
||||||
_experimentalSmoothChunkLoading: true,
|
renderEars: true,
|
||||||
_renderByChunks: false,
|
skinTexturesProxy: undefined as string | undefined,
|
||||||
|
// game renderer setting actually
|
||||||
// Rendering engine settings
|
showHand: false,
|
||||||
dayCycle: true,
|
viewBobbing: false,
|
||||||
|
extraBlockRenderers: true,
|
||||||
|
clipWorldBelowY: undefined as number | undefined,
|
||||||
smoothLighting: true,
|
smoothLighting: true,
|
||||||
enableLighting: true,
|
enableLighting: true,
|
||||||
starfield: true,
|
starfield: true,
|
||||||
defaultSkybox: true,
|
addChunksBatchWaitTime: 200,
|
||||||
renderEntities: true,
|
|
||||||
extraBlockRenderers: true,
|
|
||||||
foreground: true,
|
|
||||||
fov: 75,
|
|
||||||
volume: 1,
|
|
||||||
|
|
||||||
// Camera visual related settings
|
|
||||||
showHand: false,
|
|
||||||
viewBobbing: false,
|
|
||||||
renderEars: true,
|
|
||||||
highlightBlockColor: 'blue',
|
|
||||||
|
|
||||||
// Player models
|
|
||||||
fetchPlayerSkins: true,
|
|
||||||
skinTexturesProxy: undefined as string | undefined,
|
|
||||||
|
|
||||||
// VR settings
|
|
||||||
vrSupport: true,
|
vrSupport: true,
|
||||||
vrPageGameRendering: true,
|
vrPageGameRendering: true,
|
||||||
|
renderEntities: true,
|
||||||
// World settings
|
fov: 75,
|
||||||
clipWorldBelowY: undefined as number | undefined,
|
fetchPlayerSkins: true,
|
||||||
isPlayground: false
|
highlightBlockColor: 'blue',
|
||||||
|
foreground: true,
|
||||||
|
enableDebugOverlay: false,
|
||||||
|
_experimentalSmoothChunkLoading: true,
|
||||||
|
_renderByChunks: false,
|
||||||
|
volume: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WorldRendererConfig = typeof defaultWorldRendererConfig
|
export type WorldRendererConfig = typeof defaultWorldRendererConfig
|
||||||
|
|
@ -510,10 +496,6 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
||||||
|
|
||||||
timeUpdated? (newTime: number): void
|
timeUpdated? (newTime: number): void
|
||||||
|
|
||||||
biomeUpdated? (biome: any): void
|
|
||||||
|
|
||||||
biomeReset? (): void
|
|
||||||
|
|
||||||
updateViewerPosition (pos: Vec3) {
|
updateViewerPosition (pos: Vec3) {
|
||||||
this.viewerChunkPosition = pos
|
this.viewerChunkPosition = pos
|
||||||
for (const [key, value] of Object.entries(this.loadedChunks)) {
|
for (const [key, value] of Object.entries(this.loadedChunks)) {
|
||||||
|
|
@ -835,9 +817,12 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
||||||
})
|
})
|
||||||
|
|
||||||
worldEmitter.on('time', (timeOfDay) => {
|
worldEmitter.on('time', (timeOfDay) => {
|
||||||
if (!this.worldRendererConfig.dayCycle) return
|
|
||||||
this.timeUpdated?.(timeOfDay)
|
this.timeUpdated?.(timeOfDay)
|
||||||
|
|
||||||
|
if (timeOfDay < 0 || timeOfDay > 24_000) {
|
||||||
|
throw new Error('Invalid time of day. It should be between 0 and 24000.')
|
||||||
|
}
|
||||||
|
|
||||||
this.timeOfTheDay = timeOfDay
|
this.timeOfTheDay = timeOfDay
|
||||||
|
|
||||||
// if (this.worldRendererConfig.skyLight === skyLight) return
|
// if (this.worldRendererConfig.skyLight === skyLight) return
|
||||||
|
|
@ -846,14 +831,6 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
||||||
// (this).rerenderAllChunks?.()
|
// (this).rerenderAllChunks?.()
|
||||||
// }
|
// }
|
||||||
})
|
})
|
||||||
|
|
||||||
worldEmitter.on('biomeUpdate', ({ biome }) => {
|
|
||||||
this.biomeUpdated?.(biome)
|
|
||||||
})
|
|
||||||
|
|
||||||
worldEmitter.on('biomeReset', () => {
|
|
||||||
this.biomeReset?.()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setBlockStateIdInner (pos: Vec3, stateId: number | undefined, needAoRecalculation = true) {
|
setBlockStateIdInner (pos: Vec3, stateId: number | undefined, needAoRecalculation = true) {
|
||||||
|
|
|
||||||
|
|
@ -80,12 +80,8 @@ export class CameraShake {
|
||||||
camera.setRotationFromQuaternion(yawQuat)
|
camera.setRotationFromQuaternion(yawQuat)
|
||||||
} else {
|
} else {
|
||||||
// For regular camera, apply all rotations
|
// For regular camera, apply all rotations
|
||||||
// Add tiny offsets to prevent z-fighting at ideal angles (90, 180, 270 degrees)
|
const pitchQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), this.basePitch)
|
||||||
const pitchOffset = this.addAntiZfightingOffset(this.basePitch)
|
const yawQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), this.baseYaw)
|
||||||
const yawOffset = this.addAntiZfightingOffset(this.baseYaw)
|
|
||||||
|
|
||||||
const pitchQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), pitchOffset)
|
|
||||||
const yawQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), yawOffset)
|
|
||||||
const rollQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 0, 1), THREE.MathUtils.degToRad(this.rollAngle))
|
const rollQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 0, 1), THREE.MathUtils.degToRad(this.rollAngle))
|
||||||
// Combine rotations in the correct order: pitch -> yaw -> roll
|
// Combine rotations in the correct order: pitch -> yaw -> roll
|
||||||
const finalQuat = yawQuat.multiply(pitchQuat).multiply(rollQuat)
|
const finalQuat = yawQuat.multiply(pitchQuat).multiply(rollQuat)
|
||||||
|
|
@ -100,21 +96,4 @@ export class CameraShake {
|
||||||
private easeInOut (t: number): number {
|
private easeInOut (t: number): number {
|
||||||
return t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2
|
return t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
private addAntiZfightingOffset (angle: number): number {
|
|
||||||
const offset = 0.001 // Very small offset in radians (about 0.057 degrees)
|
|
||||||
|
|
||||||
// Check if the angle is close to ideal angles (0, π/2, π, 3π/2)
|
|
||||||
const normalizedAngle = ((angle % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2)
|
|
||||||
const tolerance = 0.01 // Tolerance for considering an angle "ideal"
|
|
||||||
|
|
||||||
if (Math.abs(normalizedAngle) < tolerance ||
|
|
||||||
Math.abs(normalizedAngle - Math.PI / 2) < tolerance ||
|
|
||||||
Math.abs(normalizedAngle - Math.PI) < tolerance ||
|
|
||||||
Math.abs(normalizedAngle - 3 * Math.PI / 2) < tolerance) {
|
|
||||||
return angle + offset
|
|
||||||
}
|
|
||||||
|
|
||||||
return angle
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import { ItemSpecificContextProperties } from '../lib/basePlayerState'
|
||||||
import { loadSkinFromUsername, loadSkinImage, stevePngUrl } from '../lib/utils/skins'
|
import { loadSkinFromUsername, loadSkinImage, stevePngUrl } from '../lib/utils/skins'
|
||||||
import { renderComponent } from '../sign-renderer'
|
import { renderComponent } from '../sign-renderer'
|
||||||
import { createCanvas } from '../lib/utils'
|
import { createCanvas } from '../lib/utils'
|
||||||
import { PlayerObjectType } from '../lib/createPlayerObject'
|
|
||||||
import { getBlockMeshFromModel } from './holdingBlock'
|
import { getBlockMeshFromModel } from './holdingBlock'
|
||||||
import { createItemMesh } from './itemMesh'
|
import { createItemMesh } from './itemMesh'
|
||||||
import * as Entity from './entity/EntityMesh'
|
import * as Entity from './entity/EntityMesh'
|
||||||
|
|
@ -34,6 +33,12 @@ export const steveTexture = loadThreeJsTextureFromUrl(stevePngUrl)
|
||||||
|
|
||||||
export const TWEEN_DURATION = 120
|
export const TWEEN_DURATION = 120
|
||||||
|
|
||||||
|
type PlayerObjectType = PlayerObject & {
|
||||||
|
animation?: PlayerAnimation
|
||||||
|
realPlayerUuid: string
|
||||||
|
realUsername: string
|
||||||
|
}
|
||||||
|
|
||||||
function convert2sComplementToHex (complement: number) {
|
function convert2sComplementToHex (complement: number) {
|
||||||
if (complement < 0) {
|
if (complement < 0) {
|
||||||
complement = (0xFF_FF_FF_FF + complement + 1) >>> 0
|
complement = (0xFF_FF_FF_FF + complement + 1) >>> 0
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,10 @@
|
||||||
import * as THREE from 'three'
|
import * as THREE from 'three'
|
||||||
import { DebugGui } from '../lib/DebugGui'
|
|
||||||
|
|
||||||
export const DEFAULT_TEMPERATURE = 0.75
|
|
||||||
|
|
||||||
export class SkyboxRenderer {
|
export class SkyboxRenderer {
|
||||||
private texture: THREE.Texture | null = null
|
private texture: THREE.Texture | null = null
|
||||||
private mesh: THREE.Mesh<THREE.SphereGeometry, THREE.MeshBasicMaterial> | null = null
|
private mesh: THREE.Mesh<THREE.SphereGeometry, THREE.MeshBasicMaterial> | null = null
|
||||||
private skyMesh: THREE.Mesh | null = null
|
|
||||||
private voidMesh: THREE.Mesh | null = null
|
|
||||||
|
|
||||||
// World state
|
constructor (private readonly scene: THREE.Scene, public initialImage: string | null) {}
|
||||||
private worldTime = 0
|
|
||||||
private partialTicks = 0
|
|
||||||
private viewDistance = 4
|
|
||||||
private temperature = DEFAULT_TEMPERATURE
|
|
||||||
private inWater = false
|
|
||||||
private waterBreathing = false
|
|
||||||
private fogBrightness = 0
|
|
||||||
private prevFogBrightness = 0
|
|
||||||
private readonly fogOrangeness = 0 // Debug property to control sky color orangeness
|
|
||||||
private readonly distanceFactor = 2.7
|
|
||||||
|
|
||||||
private readonly brightnessAtPosition = 1
|
|
||||||
debugGui: DebugGui
|
|
||||||
|
|
||||||
constructor (private readonly scene: THREE.Scene, public defaultSkybox: boolean, public initialImage: string | null) {
|
|
||||||
this.debugGui = new DebugGui('skybox_renderer', this, [
|
|
||||||
'temperature',
|
|
||||||
'worldTime',
|
|
||||||
'inWater',
|
|
||||||
'waterBreathing',
|
|
||||||
'fogOrangeness',
|
|
||||||
'brightnessAtPosition',
|
|
||||||
'distanceFactor'
|
|
||||||
], {
|
|
||||||
brightnessAtPosition: { min: 0, max: 1, step: 0.01 },
|
|
||||||
temperature: { min: 0, max: 1, step: 0.01 },
|
|
||||||
worldTime: { min: 0, max: 24_000, step: 1 },
|
|
||||||
fogOrangeness: { min: -1, max: 1, step: 0.01 },
|
|
||||||
distanceFactor: { min: 0, max: 5, step: 0.01 },
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!initialImage) {
|
|
||||||
this.createGradientSky()
|
|
||||||
}
|
|
||||||
// this.debugGui.activate()
|
|
||||||
}
|
|
||||||
|
|
||||||
async init () {
|
async init () {
|
||||||
if (this.initialImage) {
|
if (this.initialImage) {
|
||||||
|
|
@ -99,290 +58,12 @@ export class SkyboxRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update (cameraPosition: THREE.Vector3, newViewDistance: number) {
|
update (cameraPosition: THREE.Vector3) {
|
||||||
if (newViewDistance !== this.viewDistance) {
|
|
||||||
this.viewDistance = newViewDistance
|
|
||||||
this.updateSkyColors()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.mesh) {
|
if (this.mesh) {
|
||||||
// Update skybox position
|
|
||||||
this.mesh.position.copy(cameraPosition)
|
this.mesh.position.copy(cameraPosition)
|
||||||
} else if (this.skyMesh) {
|
|
||||||
// Update gradient sky position
|
|
||||||
this.skyMesh.position.copy(cameraPosition)
|
|
||||||
this.voidMesh?.position.copy(cameraPosition)
|
|
||||||
this.updateSkyColors() // Update colors based on time of day
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update world time
|
|
||||||
updateTime (timeOfDay: number, partialTicks = 0) {
|
|
||||||
if (this.debugGui.visible) return
|
|
||||||
this.worldTime = timeOfDay
|
|
||||||
this.partialTicks = partialTicks
|
|
||||||
this.updateSkyColors()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update view distance
|
|
||||||
updateViewDistance (viewDistance: number) {
|
|
||||||
this.viewDistance = viewDistance
|
|
||||||
this.updateSkyColors()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update temperature (for biome support)
|
|
||||||
updateTemperature (temperature: number) {
|
|
||||||
if (this.debugGui.visible) return
|
|
||||||
this.temperature = temperature
|
|
||||||
this.updateSkyColors()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update water state
|
|
||||||
updateWaterState (inWater: boolean, waterBreathing: boolean) {
|
|
||||||
if (this.debugGui.visible) return
|
|
||||||
this.inWater = inWater
|
|
||||||
this.waterBreathing = waterBreathing
|
|
||||||
this.updateSkyColors()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update default skybox setting
|
|
||||||
updateDefaultSkybox (defaultSkybox: boolean) {
|
|
||||||
if (this.debugGui.visible) return
|
|
||||||
this.defaultSkybox = defaultSkybox
|
|
||||||
this.updateSkyColors()
|
|
||||||
}
|
|
||||||
|
|
||||||
private createGradientSky () {
|
|
||||||
const size = 64
|
|
||||||
const scale = 256 / size + 2
|
|
||||||
|
|
||||||
{
|
|
||||||
const geometry = new THREE.PlaneGeometry(size * scale * 2, size * scale * 2)
|
|
||||||
geometry.rotateX(-Math.PI / 2)
|
|
||||||
geometry.translate(0, 16, 0)
|
|
||||||
|
|
||||||
const material = new THREE.MeshBasicMaterial({
|
|
||||||
color: 0xff_ff_ff,
|
|
||||||
side: THREE.DoubleSide,
|
|
||||||
depthTest: false
|
|
||||||
})
|
|
||||||
|
|
||||||
this.skyMesh = new THREE.Mesh(geometry, material)
|
|
||||||
this.scene.add(this.skyMesh)
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const geometry = new THREE.PlaneGeometry(size * scale * 2, size * scale * 2)
|
|
||||||
geometry.rotateX(-Math.PI / 2)
|
|
||||||
geometry.translate(0, -16, 0)
|
|
||||||
|
|
||||||
const material = new THREE.MeshBasicMaterial({
|
|
||||||
color: 0xff_ff_ff,
|
|
||||||
side: THREE.DoubleSide,
|
|
||||||
depthTest: false
|
|
||||||
})
|
|
||||||
|
|
||||||
this.voidMesh = new THREE.Mesh(geometry, material)
|
|
||||||
this.scene.add(this.voidMesh)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateSkyColors()
|
|
||||||
}
|
|
||||||
|
|
||||||
private getFogColor (partialTicks = 0): THREE.Vector3 {
|
|
||||||
const angle = this.getCelestialAngle(partialTicks)
|
|
||||||
let rotation = Math.cos(angle * Math.PI * 2) * 2 + 0.5
|
|
||||||
rotation = Math.max(0, Math.min(1, rotation))
|
|
||||||
|
|
||||||
let x = 0.752_941_2
|
|
||||||
let y = 0.847_058_83
|
|
||||||
let z = 1
|
|
||||||
|
|
||||||
x *= (rotation * 0.94 + 0.06)
|
|
||||||
y *= (rotation * 0.94 + 0.06)
|
|
||||||
z *= (rotation * 0.91 + 0.09)
|
|
||||||
|
|
||||||
return new THREE.Vector3(x, y, z)
|
|
||||||
}
|
|
||||||
|
|
||||||
private getSkyColor (x = 0, z = 0, partialTicks = 0): THREE.Vector3 {
|
|
||||||
const angle = this.getCelestialAngle(partialTicks)
|
|
||||||
let brightness = Math.cos(angle * 3.141_593 * 2) * 2 + 0.5
|
|
||||||
|
|
||||||
if (brightness < 0) brightness = 0
|
|
||||||
if (brightness > 1) brightness = 1
|
|
||||||
|
|
||||||
const temperature = this.getTemperature(x, z)
|
|
||||||
const rgb = this.getSkyColorByTemp(temperature)
|
|
||||||
|
|
||||||
const red = ((rgb >> 16) & 0xff) / 255
|
|
||||||
const green = ((rgb >> 8) & 0xff) / 255
|
|
||||||
const blue = (rgb & 0xff) / 255
|
|
||||||
|
|
||||||
return new THREE.Vector3(
|
|
||||||
red * brightness,
|
|
||||||
green * brightness,
|
|
||||||
blue * brightness
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private calculateCelestialAngle (time: number, partialTicks: number): number {
|
|
||||||
const modTime = (time % 24_000)
|
|
||||||
let angle = (modTime + partialTicks) / 24_000 - 0.25
|
|
||||||
|
|
||||||
if (angle < 0) {
|
|
||||||
angle++
|
|
||||||
}
|
|
||||||
if (angle > 1) {
|
|
||||||
angle--
|
|
||||||
}
|
|
||||||
|
|
||||||
angle = 1 - ((Math.cos(angle * Math.PI) + 1) / 2)
|
|
||||||
angle += (angle - angle) / 3
|
|
||||||
|
|
||||||
return angle
|
|
||||||
}
|
|
||||||
|
|
||||||
private getCelestialAngle (partialTicks: number): number {
|
|
||||||
return this.calculateCelestialAngle(this.worldTime, partialTicks)
|
|
||||||
}
|
|
||||||
|
|
||||||
private getTemperature (x: number, z: number): number {
|
|
||||||
return this.temperature
|
|
||||||
}
|
|
||||||
|
|
||||||
private getSkyColorByTemp (temperature: number): number {
|
|
||||||
temperature /= 3
|
|
||||||
if (temperature < -1) temperature = -1
|
|
||||||
if (temperature > 1) temperature = 1
|
|
||||||
|
|
||||||
// Apply debug fog orangeness to hue - positive values make it more orange, negative make it less orange
|
|
||||||
const baseHue = 0.622_222_2 - temperature * 0.05
|
|
||||||
// Orange is around hue 0.08-0.15, so we need to shift from blue-purple (0.62) toward orange
|
|
||||||
// Use a more dramatic shift and also increase saturation for more noticeable effect
|
|
||||||
const orangeHue = 0.12 // Orange hue value
|
|
||||||
const hue = this.fogOrangeness > 0
|
|
||||||
? baseHue + (orangeHue - baseHue) * this.fogOrangeness * 0.8 // Blend toward orange
|
|
||||||
: baseHue + this.fogOrangeness * 0.1 // Subtle shift for negative values
|
|
||||||
const saturation = 0.5 + temperature * 0.1 + Math.abs(this.fogOrangeness) * 0.3 // Increase saturation with orangeness
|
|
||||||
const brightness = 1
|
|
||||||
|
|
||||||
return this.hsbToRgb(hue, saturation, brightness)
|
|
||||||
}
|
|
||||||
|
|
||||||
private hsbToRgb (hue: number, saturation: number, brightness: number): number {
|
|
||||||
let r = 0; let g = 0; let b = 0
|
|
||||||
if (saturation === 0) {
|
|
||||||
r = g = b = Math.floor(brightness * 255 + 0.5)
|
|
||||||
} else {
|
|
||||||
const h = (hue - Math.floor(hue)) * 6
|
|
||||||
const f = h - Math.floor(h)
|
|
||||||
const p = brightness * (1 - saturation)
|
|
||||||
const q = brightness * (1 - saturation * f)
|
|
||||||
const t = brightness * (1 - (saturation * (1 - f)))
|
|
||||||
switch (Math.floor(h)) {
|
|
||||||
case 0:
|
|
||||||
r = Math.floor(brightness * 255 + 0.5)
|
|
||||||
g = Math.floor(t * 255 + 0.5)
|
|
||||||
b = Math.floor(p * 255 + 0.5)
|
|
||||||
break
|
|
||||||
case 1:
|
|
||||||
r = Math.floor(q * 255 + 0.5)
|
|
||||||
g = Math.floor(brightness * 255 + 0.5)
|
|
||||||
b = Math.floor(p * 255 + 0.5)
|
|
||||||
break
|
|
||||||
case 2:
|
|
||||||
r = Math.floor(p * 255 + 0.5)
|
|
||||||
g = Math.floor(brightness * 255 + 0.5)
|
|
||||||
b = Math.floor(t * 255 + 0.5)
|
|
||||||
break
|
|
||||||
case 3:
|
|
||||||
r = Math.floor(p * 255 + 0.5)
|
|
||||||
g = Math.floor(q * 255 + 0.5)
|
|
||||||
b = Math.floor(brightness * 255 + 0.5)
|
|
||||||
break
|
|
||||||
case 4:
|
|
||||||
r = Math.floor(t * 255 + 0.5)
|
|
||||||
g = Math.floor(p * 255 + 0.5)
|
|
||||||
b = Math.floor(brightness * 255 + 0.5)
|
|
||||||
break
|
|
||||||
case 5:
|
|
||||||
r = Math.floor(brightness * 255 + 0.5)
|
|
||||||
g = Math.floor(p * 255 + 0.5)
|
|
||||||
b = Math.floor(q * 255 + 0.5)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0xff_00_00_00 | (r << 16) | (g << 8) | (Math.trunc(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
private updateSkyColors () {
|
|
||||||
if (!this.skyMesh || !this.voidMesh) return
|
|
||||||
|
|
||||||
// If default skybox is disabled, hide the skybox meshes
|
|
||||||
if (!this.defaultSkybox) {
|
|
||||||
this.skyMesh.visible = false
|
|
||||||
this.voidMesh.visible = false
|
|
||||||
if (this.mesh) {
|
|
||||||
this.mesh.visible = false
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show skybox meshes when default skybox is enabled
|
|
||||||
this.skyMesh.visible = true
|
|
||||||
this.voidMesh.visible = true
|
|
||||||
if (this.mesh) {
|
|
||||||
this.mesh.visible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update fog brightness with smooth transition
|
|
||||||
this.prevFogBrightness = this.fogBrightness
|
|
||||||
const renderDistance = this.viewDistance / 32
|
|
||||||
const targetBrightness = this.brightnessAtPosition * (1 - renderDistance) + renderDistance
|
|
||||||
this.fogBrightness += (targetBrightness - this.fogBrightness) * 0.1
|
|
||||||
|
|
||||||
// Handle water fog
|
|
||||||
if (this.inWater) {
|
|
||||||
const waterViewDistance = this.waterBreathing ? 100 : 5
|
|
||||||
this.scene.fog = new THREE.Fog(new THREE.Color(0, 0, 1), 0.0025, waterViewDistance)
|
|
||||||
this.scene.background = new THREE.Color(0, 0, 1)
|
|
||||||
|
|
||||||
// Update sky and void colors for underwater effect
|
|
||||||
;(this.skyMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(0, 0, 1))
|
|
||||||
;(this.voidMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(0, 0, 0.6))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normal sky colors
|
|
||||||
const viewDistance = this.viewDistance * 16
|
|
||||||
const viewFactor = 1 - (0.25 + 0.75 * this.viewDistance / 32) ** 0.25
|
|
||||||
|
|
||||||
const angle = this.getCelestialAngle(this.partialTicks)
|
|
||||||
const skyColor = this.getSkyColor(0, 0, this.partialTicks)
|
|
||||||
const fogColor = this.getFogColor(this.partialTicks)
|
|
||||||
|
|
||||||
const brightness = Math.cos(angle * Math.PI * 2) * 2 + 0.5
|
|
||||||
const clampedBrightness = Math.max(0, Math.min(1, brightness))
|
|
||||||
|
|
||||||
// Interpolate fog brightness
|
|
||||||
const interpolatedBrightness = this.prevFogBrightness + (this.fogBrightness - this.prevFogBrightness) * this.partialTicks
|
|
||||||
|
|
||||||
const red = (fogColor.x + (skyColor.x - fogColor.x) * viewFactor) * clampedBrightness * interpolatedBrightness
|
|
||||||
const green = (fogColor.y + (skyColor.y - fogColor.y) * viewFactor) * clampedBrightness * interpolatedBrightness
|
|
||||||
const blue = (fogColor.z + (skyColor.z - fogColor.z) * viewFactor) * clampedBrightness * interpolatedBrightness
|
|
||||||
|
|
||||||
this.scene.background = new THREE.Color(red, green, blue)
|
|
||||||
this.scene.fog = new THREE.Fog(new THREE.Color(red, green, blue), 0.0025, viewDistance * this.distanceFactor)
|
|
||||||
|
|
||||||
;(this.skyMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(skyColor.x, skyColor.y, skyColor.z))
|
|
||||||
;(this.voidMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(
|
|
||||||
skyColor.x * 0.2 + 0.04,
|
|
||||||
skyColor.y * 0.2 + 0.04,
|
|
||||||
skyColor.z * 0.6 + 0.1
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose () {
|
dispose () {
|
||||||
if (this.texture) {
|
if (this.texture) {
|
||||||
this.texture.dispose()
|
this.texture.dispose()
|
||||||
|
|
@ -392,15 +73,5 @@ export class SkyboxRenderer {
|
||||||
;(this.mesh.material as THREE.Material).dispose()
|
;(this.mesh.material as THREE.Material).dispose()
|
||||||
this.scene.remove(this.mesh)
|
this.scene.remove(this.mesh)
|
||||||
}
|
}
|
||||||
if (this.skyMesh) {
|
|
||||||
this.skyMesh.geometry.dispose()
|
|
||||||
;(this.skyMesh.material as THREE.Material).dispose()
|
|
||||||
this.scene.remove(this.skyMesh)
|
|
||||||
}
|
|
||||||
if (this.voidMesh) {
|
|
||||||
this.voidMesh.geometry.dispose()
|
|
||||||
;(this.voidMesh.material as THREE.Material).dispose()
|
|
||||||
this.scene.remove(this.voidMesh)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ export const WAYPOINT_CONFIG = {
|
||||||
CANVAS_SCALE: 2,
|
CANVAS_SCALE: 2,
|
||||||
ARROW: {
|
ARROW: {
|
||||||
enabledDefault: false,
|
enabledDefault: false,
|
||||||
pixelSize: 50,
|
pixelSize: 30,
|
||||||
paddingPx: 50,
|
paddingPx: 50,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -50,7 +50,6 @@ export function createWaypointSprite (options: {
|
||||||
depthTest?: boolean,
|
depthTest?: boolean,
|
||||||
// Y offset in world units used by updateScaleWorld only (screen-pixel API ignores this)
|
// Y offset in world units used by updateScaleWorld only (screen-pixel API ignores this)
|
||||||
labelYOffset?: number,
|
labelYOffset?: number,
|
||||||
metadata?: any,
|
|
||||||
}): WaypointSprite {
|
}): WaypointSprite {
|
||||||
const color = options.color ?? 0xFF_00_00
|
const color = options.color ?? 0xFF_00_00
|
||||||
const depthTest = options.depthTest ?? false
|
const depthTest = options.depthTest ?? false
|
||||||
|
|
@ -132,22 +131,16 @@ export function createWaypointSprite (options: {
|
||||||
canvas.height = size
|
canvas.height = size
|
||||||
const ctx = canvas.getContext('2d')!
|
const ctx = canvas.getContext('2d')!
|
||||||
ctx.clearRect(0, 0, size, size)
|
ctx.clearRect(0, 0, size, size)
|
||||||
|
|
||||||
// Draw arrow shape
|
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
ctx.moveTo(size * 0.15, size * 0.5)
|
ctx.moveTo(size * 0.2, size * 0.5)
|
||||||
ctx.lineTo(size * 0.85, size * 0.5)
|
ctx.lineTo(size * 0.8, size * 0.5)
|
||||||
ctx.lineTo(size * 0.5, size * 0.15)
|
ctx.lineTo(size * 0.5, size * 0.2)
|
||||||
ctx.closePath()
|
ctx.closePath()
|
||||||
|
ctx.lineWidth = 4
|
||||||
// Use waypoint color for arrow
|
|
||||||
const colorHex = `#${color.toString(16).padStart(6, '0')}`
|
|
||||||
ctx.lineWidth = 6
|
|
||||||
ctx.strokeStyle = 'black'
|
ctx.strokeStyle = 'black'
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
ctx.fillStyle = colorHex
|
ctx.fillStyle = 'white'
|
||||||
ctx.fill()
|
ctx.fill()
|
||||||
|
|
||||||
const texture = new THREE.CanvasTexture(canvas)
|
const texture = new THREE.CanvasTexture(canvas)
|
||||||
const material = new THREE.SpriteMaterial({ map: texture, transparent: true, depthTest: false, depthWrite: false })
|
const material = new THREE.SpriteMaterial({ map: texture, transparent: true, depthTest: false, depthWrite: false })
|
||||||
arrowSprite = new THREE.Sprite(material)
|
arrowSprite = new THREE.Sprite(material)
|
||||||
|
|
@ -176,9 +169,6 @@ export function createWaypointSprite (options: {
|
||||||
ensureArrow()
|
ensureArrow()
|
||||||
if (!arrowSprite) return true
|
if (!arrowSprite) return true
|
||||||
|
|
||||||
// Check if onlyLeftRight is enabled in metadata
|
|
||||||
const onlyLeftRight = options.metadata?.onlyLeftRight === true
|
|
||||||
|
|
||||||
// Build camera basis using camera.up to respect custom orientations
|
// Build camera basis using camera.up to respect custom orientations
|
||||||
const forward = new THREE.Vector3()
|
const forward = new THREE.Vector3()
|
||||||
camera.getWorldDirection(forward) // camera look direction
|
camera.getWorldDirection(forward) // camera look direction
|
||||||
|
|
@ -223,20 +213,6 @@ export function createWaypointSprite (options: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply onlyLeftRight logic - restrict arrows to left/right edges only
|
|
||||||
if (onlyLeftRight) {
|
|
||||||
// Force the arrow to appear only on left or right edges
|
|
||||||
if (Math.abs(rx) > Math.abs(ry)) {
|
|
||||||
// Horizontal direction is dominant, keep it
|
|
||||||
ry = 0
|
|
||||||
} else {
|
|
||||||
// Vertical direction is dominant, but we want only left/right
|
|
||||||
// So choose left or right based on the sign of rx
|
|
||||||
rx = rx >= 0 ? 1 : -1
|
|
||||||
ry = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Place on the rectangle border [-1,1]x[-1,1]
|
// Place on the rectangle border [-1,1]x[-1,1]
|
||||||
const s = Math.max(Math.abs(rx), Math.abs(ry)) || 1
|
const s = Math.max(Math.abs(rx), Math.abs(ry)) || 1
|
||||||
let ndcX = rx / s
|
let ndcX = rx / s
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ interface WaypointOptions {
|
||||||
color?: number
|
color?: number
|
||||||
label?: string
|
label?: string
|
||||||
minDistance?: number
|
minDistance?: number
|
||||||
metadata?: any
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WaypointsRenderer {
|
export class WaypointsRenderer {
|
||||||
|
|
@ -72,14 +71,13 @@ export class WaypointsRenderer {
|
||||||
this.removeWaypoint(id)
|
this.removeWaypoint(id)
|
||||||
|
|
||||||
const color = options.color ?? 0xFF_00_00
|
const color = options.color ?? 0xFF_00_00
|
||||||
const { label, metadata } = options
|
const { label } = options
|
||||||
const minDistance = options.minDistance ?? 0
|
const minDistance = options.minDistance ?? 0
|
||||||
|
|
||||||
const sprite = createWaypointSprite({
|
const sprite = createWaypointSprite({
|
||||||
position: new THREE.Vector3(x, y, z),
|
position: new THREE.Vector3(x, y, z),
|
||||||
color,
|
color,
|
||||||
label: (label || id),
|
label: (label || id),
|
||||||
metadata,
|
|
||||||
})
|
})
|
||||||
sprite.enableOffscreenArrow(true)
|
sprite.enableOffscreenArrow(true)
|
||||||
sprite.setArrowParent(this.waypointScene)
|
sprite.setArrowParent(this.waypointScene)
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export class CursorBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
cursorLineMaterial: LineMaterial
|
cursorLineMaterial: LineMaterial
|
||||||
interactionLines: null | { blockPos: Vec3, mesh: THREE.Group, shapePositions: BlocksShapes | undefined } = null
|
interactionLines: null | { blockPos: Vec3, mesh: THREE.Group } = null
|
||||||
prevColor: string | undefined
|
prevColor: string | undefined
|
||||||
blockBreakMesh: THREE.Mesh
|
blockBreakMesh: THREE.Mesh
|
||||||
breakTextures: THREE.Texture[] = []
|
breakTextures: THREE.Texture[] = []
|
||||||
|
|
@ -62,13 +62,6 @@ export class CursorBlock {
|
||||||
this.worldRenderer.onReactivePlayerStateUpdated('gameMode', () => {
|
this.worldRenderer.onReactivePlayerStateUpdated('gameMode', () => {
|
||||||
this.updateLineMaterial()
|
this.updateLineMaterial()
|
||||||
})
|
})
|
||||||
// todo figure out why otherwise fog from skybox breaks it
|
|
||||||
setTimeout(() => {
|
|
||||||
this.updateLineMaterial()
|
|
||||||
if (this.interactionLines) {
|
|
||||||
this.setHighlightCursorBlock(this.interactionLines.blockPos, this.interactionLines.shapePositions, true)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update functions
|
// Update functions
|
||||||
|
|
@ -76,9 +69,6 @@ export class CursorBlock {
|
||||||
const inCreative = this.worldRenderer.playerStateReactive.gameMode === 'creative'
|
const inCreative = this.worldRenderer.playerStateReactive.gameMode === 'creative'
|
||||||
const pixelRatio = this.worldRenderer.renderer.getPixelRatio()
|
const pixelRatio = this.worldRenderer.renderer.getPixelRatio()
|
||||||
|
|
||||||
if (this.cursorLineMaterial) {
|
|
||||||
this.cursorLineMaterial.dispose()
|
|
||||||
}
|
|
||||||
this.cursorLineMaterial = new LineMaterial({
|
this.cursorLineMaterial = new LineMaterial({
|
||||||
color: (() => {
|
color: (() => {
|
||||||
switch (this.worldRenderer.worldRendererConfig.highlightBlockColor) {
|
switch (this.worldRenderer.worldRendererConfig.highlightBlockColor) {
|
||||||
|
|
@ -125,8 +115,8 @@ export class CursorBlock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setHighlightCursorBlock (blockPos: Vec3 | null, shapePositions?: BlocksShapes, force = false): void {
|
setHighlightCursorBlock (blockPos: Vec3 | null, shapePositions?: BlocksShapes): void {
|
||||||
if (blockPos && this.interactionLines && blockPos.equals(this.interactionLines.blockPos) && !force) {
|
if (blockPos && this.interactionLines && blockPos.equals(this.interactionLines.blockPos)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (this.interactionLines !== null) {
|
if (this.interactionLines !== null) {
|
||||||
|
|
@ -150,7 +140,7 @@ export class CursorBlock {
|
||||||
}
|
}
|
||||||
this.worldRenderer.scene.add(group)
|
this.worldRenderer.scene.add(group)
|
||||||
group.visible = !this.cursorLinesHidden
|
group.visible = !this.cursorLinesHidden
|
||||||
this.interactionLines = { blockPos, mesh: group, shapePositions }
|
this.interactionLines = { blockPos, mesh: group }
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import { Vec3 } from 'vec3'
|
||||||
import nbt from 'prismarine-nbt'
|
import nbt from 'prismarine-nbt'
|
||||||
import PrismarineChatLoader from 'prismarine-chat'
|
import PrismarineChatLoader from 'prismarine-chat'
|
||||||
import * as tweenJs from '@tweenjs/tween.js'
|
import * as tweenJs from '@tweenjs/tween.js'
|
||||||
import { Biome } from 'minecraft-data'
|
|
||||||
import { renderSign } from '../sign-renderer'
|
import { renderSign } from '../sign-renderer'
|
||||||
import { DisplayWorldOptions, GraphicsInitOptions } from '../../../src/appViewer'
|
import { DisplayWorldOptions, GraphicsInitOptions } from '../../../src/appViewer'
|
||||||
import { chunkPos, sectionPos } from '../lib/simpleUtils'
|
import { chunkPos, sectionPos } from '../lib/simpleUtils'
|
||||||
|
|
@ -25,7 +24,7 @@ import { CameraShake } from './cameraShake'
|
||||||
import { ThreeJsMedia } from './threeJsMedia'
|
import { ThreeJsMedia } from './threeJsMedia'
|
||||||
import { Fountain } from './threeJsParticles'
|
import { Fountain } from './threeJsParticles'
|
||||||
import { WaypointsRenderer } from './waypoints'
|
import { WaypointsRenderer } from './waypoints'
|
||||||
import { DEFAULT_TEMPERATURE, SkyboxRenderer } from './skyboxRenderer'
|
import { SkyboxRenderer } from './skyboxRenderer'
|
||||||
|
|
||||||
type SectionKey = string
|
type SectionKey = string
|
||||||
|
|
||||||
|
|
@ -98,7 +97,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
||||||
this.holdingBlockLeft = new HoldingBlock(this, true)
|
this.holdingBlockLeft = new HoldingBlock(this, true)
|
||||||
|
|
||||||
// Initialize skybox renderer
|
// Initialize skybox renderer
|
||||||
this.skyboxRenderer = new SkyboxRenderer(this.scene, this.worldRendererConfig.defaultSkybox, null)
|
this.skyboxRenderer = new SkyboxRenderer(this.scene, null)
|
||||||
void this.skyboxRenderer.init()
|
void this.skyboxRenderer.init()
|
||||||
|
|
||||||
this.addDebugOverlay()
|
this.addDebugOverlay()
|
||||||
|
|
@ -174,10 +173,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
||||||
override watchReactivePlayerState () {
|
override watchReactivePlayerState () {
|
||||||
super.watchReactivePlayerState()
|
super.watchReactivePlayerState()
|
||||||
this.onReactivePlayerStateUpdated('inWater', (value) => {
|
this.onReactivePlayerStateUpdated('inWater', (value) => {
|
||||||
this.skyboxRenderer.updateWaterState(value, this.playerStateReactive.waterBreathing)
|
this.scene.fog = value ? new THREE.Fog(0x00_00_ff, 0.1, this.playerStateReactive.waterBreathing ? 100 : 20) : null
|
||||||
})
|
|
||||||
this.onReactivePlayerStateUpdated('waterBreathing', (value) => {
|
|
||||||
this.skyboxRenderer.updateWaterState(this.playerStateReactive.inWater, value)
|
|
||||||
})
|
})
|
||||||
this.onReactivePlayerStateUpdated('ambientLight', (value) => {
|
this.onReactivePlayerStateUpdated('ambientLight', (value) => {
|
||||||
if (!value) return
|
if (!value) return
|
||||||
|
|
@ -206,9 +202,6 @@ export class WorldRendererThree extends WorldRendererCommon {
|
||||||
this.onReactiveConfigUpdated('showChunkBorders', (value) => {
|
this.onReactiveConfigUpdated('showChunkBorders', (value) => {
|
||||||
this.updateShowChunksBorder(value)
|
this.updateShowChunksBorder(value)
|
||||||
})
|
})
|
||||||
this.onReactiveConfigUpdated('defaultSkybox', (value) => {
|
|
||||||
this.skyboxRenderer.updateDefaultSkybox(value)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
changeHandSwingingState (isAnimationPlaying: boolean, isLeft = false) {
|
changeHandSwingingState (isAnimationPlaying: boolean, isLeft = false) {
|
||||||
|
|
@ -271,19 +264,6 @@ export class WorldRendererThree extends WorldRendererCommon {
|
||||||
} else {
|
} else {
|
||||||
this.starField.remove()
|
this.starField.remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.skyboxRenderer.updateTime(newTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
biomeUpdated (biome: Biome): void {
|
|
||||||
if (biome?.temperature !== undefined) {
|
|
||||||
this.skyboxRenderer.updateTemperature(biome.temperature)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
biomeReset (): void {
|
|
||||||
// Reset to default temperature when biome is unknown
|
|
||||||
this.skyboxRenderer.updateTemperature(DEFAULT_TEMPERATURE)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getItemRenderData (item: Record<string, any>, specificProps: ItemSpecificContextProperties) {
|
getItemRenderData (item: Record<string, any>, specificProps: ItemSpecificContextProperties) {
|
||||||
|
|
@ -736,7 +716,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
||||||
|
|
||||||
// Update skybox position to follow camera
|
// Update skybox position to follow camera
|
||||||
const cameraPos = this.getCameraPosition()
|
const cameraPos = this.getCameraPosition()
|
||||||
this.skyboxRenderer.update(cameraPos, this.viewDistance)
|
this.skyboxRenderer.update(cameraPos)
|
||||||
|
|
||||||
const sizeOrFovChanged = sizeChanged || this.displayOptions.inWorldRenderingConfig.fov !== this.camera.fov
|
const sizeOrFovChanged = sizeChanged || this.displayOptions.inWorldRenderingConfig.fov !== this.camera.fov
|
||||||
if (sizeOrFovChanged) {
|
if (sizeOrFovChanged) {
|
||||||
|
|
@ -787,17 +767,12 @@ export class WorldRendererThree extends WorldRendererCommon {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderHead (position: Vec3, rotation: number, isWall: boolean, blockEntity) {
|
renderHead (position: Vec3, rotation: number, isWall: boolean, blockEntity) {
|
||||||
let textureData: string
|
const textures = blockEntity.SkullOwner?.Properties?.textures[0]
|
||||||
if (blockEntity.SkullOwner) {
|
if (!textures) return
|
||||||
textureData = blockEntity.SkullOwner.Properties?.textures?.[0]?.Value
|
|
||||||
} else {
|
|
||||||
textureData = blockEntity.profile?.properties?.find(p => p.name === 'textures')?.value
|
|
||||||
}
|
|
||||||
if (!textureData) return
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decodedData = JSON.parse(Buffer.from(textureData, 'base64').toString())
|
const textureData = JSON.parse(Buffer.from(textures.Value, 'base64').toString())
|
||||||
let skinUrl = decodedData.textures?.SKIN?.url
|
let skinUrl = textureData.textures?.SKIN?.url
|
||||||
const { skinTexturesProxy } = this.worldRendererConfig
|
const { skinTexturesProxy } = this.worldRendererConfig
|
||||||
if (skinTexturesProxy) {
|
if (skinTexturesProxy) {
|
||||||
skinUrl = skinUrl?.replace('http://textures.minecraft.net/', skinTexturesProxy)
|
skinUrl = skinUrl?.replace('http://textures.minecraft.net/', skinTexturesProxy)
|
||||||
|
|
|
||||||
|
|
@ -371,7 +371,6 @@ console.log('size', fs.lstatSync(filePath).size / 1000 / 1000, gzipSizeFromFileS
|
||||||
|
|
||||||
const { defaultVersion } = MCProtocol
|
const { defaultVersion } = MCProtocol
|
||||||
const data = MinecraftData(defaultVersion)
|
const data = MinecraftData(defaultVersion)
|
||||||
console.log('defaultVersion', defaultVersion, !!data)
|
|
||||||
const initialMcData = {
|
const initialMcData = {
|
||||||
[defaultVersion]: {
|
[defaultVersion]: {
|
||||||
version: data.version,
|
version: data.version,
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ export type AppConfig = {
|
||||||
// defaultVersion?: string
|
// defaultVersion?: string
|
||||||
peerJsServer?: string
|
peerJsServer?: string
|
||||||
peerJsServerFallback?: string
|
peerJsServerFallback?: string
|
||||||
promoteServers?: Array<{ ip, description, name?, version?, }>
|
promoteServers?: Array<{ ip, description, version? }>
|
||||||
mapsProvider?: string
|
mapsProvider?: string
|
||||||
|
|
||||||
appParams?: Record<string, any> // query string params
|
appParams?: Record<string, any> // query string params
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@ export type AppQsParams = {
|
||||||
connectText?: string
|
connectText?: string
|
||||||
freezeSettings?: string
|
freezeSettings?: string
|
||||||
testIosCrash?: string
|
testIosCrash?: string
|
||||||
addPing?: string
|
|
||||||
|
|
||||||
// Replay params
|
// Replay params
|
||||||
replayFilter?: string
|
replayFilter?: string
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,7 @@ let audioContext: AudioContext
|
||||||
const sounds: Record<string, any> = {}
|
const sounds: Record<string, any> = {}
|
||||||
|
|
||||||
// Track currently playing sounds and their gain nodes
|
// Track currently playing sounds and their gain nodes
|
||||||
const activeSounds: Array<{
|
const activeSounds: Array<{ source: AudioBufferSourceNode; gainNode: GainNode; volumeMultiplier: number }> = []
|
||||||
source: AudioBufferSourceNode;
|
|
||||||
gainNode: GainNode;
|
|
||||||
volumeMultiplier: number;
|
|
||||||
isMusic: boolean;
|
|
||||||
}> = []
|
|
||||||
window.activeSounds = activeSounds
|
window.activeSounds = activeSounds
|
||||||
|
|
||||||
// load as many resources on page load as possible instead on demand as user can disable internet connection after he thinks the page is loaded
|
// load as many resources on page load as possible instead on demand as user can disable internet connection after he thinks the page is loaded
|
||||||
|
|
@ -48,7 +43,7 @@ export async function loadSound (path: string, contents = path) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadOrPlaySound = async (url, soundVolume = 1, loadTimeout = options.remoteSoundsLoadTimeout, loop = false, isMusic = false) => {
|
export const loadOrPlaySound = async (url, soundVolume = 1, loadTimeout = options.remoteSoundsLoadTimeout, loop = false) => {
|
||||||
const soundBuffer = sounds[url]
|
const soundBuffer = sounds[url]
|
||||||
if (!soundBuffer) {
|
if (!soundBuffer) {
|
||||||
const start = Date.now()
|
const start = Date.now()
|
||||||
|
|
@ -56,11 +51,11 @@ export const loadOrPlaySound = async (url, soundVolume = 1, loadTimeout = option
|
||||||
if (cancelled || Date.now() - start > loadTimeout) return
|
if (cancelled || Date.now() - start > loadTimeout) return
|
||||||
}
|
}
|
||||||
|
|
||||||
return playSound(url, soundVolume, loop, isMusic)
|
return playSound(url, soundVolume, loop)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function playSound (url, soundVolume = 1, loop = false, isMusic = false) {
|
export async function playSound (url, soundVolume = 1, loop = false) {
|
||||||
const volume = soundVolume * (options.volume / 100) * (isMusic ? options.musicVolume / 100 : 1)
|
const volume = soundVolume * (options.volume / 100)
|
||||||
|
|
||||||
if (!volume) return
|
if (!volume) return
|
||||||
|
|
||||||
|
|
@ -87,7 +82,7 @@ export async function playSound (url, soundVolume = 1, loop = false, isMusic = f
|
||||||
source.start(0)
|
source.start(0)
|
||||||
|
|
||||||
// Add to active sounds
|
// Add to active sounds
|
||||||
activeSounds.push({ source, gainNode, volumeMultiplier: soundVolume, isMusic })
|
activeSounds.push({ source, gainNode, volumeMultiplier: soundVolume })
|
||||||
|
|
||||||
const callbacks = [] as Array<() => void>
|
const callbacks = [] as Array<() => void>
|
||||||
source.onended = () => {
|
source.onended = () => {
|
||||||
|
|
@ -115,7 +110,6 @@ export async function playSound (url, soundVolume = 1, loop = false, isMusic = f
|
||||||
console.warn('Failed to stop sound:', err)
|
console.warn('Failed to stop sound:', err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
gainNode,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,11 +137,11 @@ export function stopSound (url: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changeVolumeOfCurrentlyPlayingSounds (newVolume: number, newMusicVolume: number) {
|
export function changeVolumeOfCurrentlyPlayingSounds (newVolume: number) {
|
||||||
const normalizedVolume = newVolume / 100
|
const normalizedVolume = newVolume / 100
|
||||||
for (const { gainNode, volumeMultiplier, isMusic } of activeSounds) {
|
for (const { gainNode, volumeMultiplier } of activeSounds) {
|
||||||
try {
|
try {
|
||||||
gainNode.gain.value = normalizedVolume * volumeMultiplier * (isMusic ? newMusicVolume / 100 : 1)
|
gainNode.gain.value = normalizedVolume * volumeMultiplier
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('Failed to change sound volume:', err)
|
console.warn('Failed to change sound volume:', err)
|
||||||
}
|
}
|
||||||
|
|
@ -155,9 +149,5 @@ export function changeVolumeOfCurrentlyPlayingSounds (newVolume: number, newMusi
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribeKey(options, 'volume', () => {
|
subscribeKey(options, 'volume', () => {
|
||||||
changeVolumeOfCurrentlyPlayingSounds(options.volume, options.musicVolume)
|
changeVolumeOfCurrentlyPlayingSounds(options.volume)
|
||||||
})
|
|
||||||
|
|
||||||
subscribeKey(options, 'musicVolume', () => {
|
|
||||||
changeVolumeOfCurrentlyPlayingSounds(options.volume, options.musicVolume)
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,19 @@ const registerBlockInteractionsCustomizationChannel = () => {
|
||||||
|
|
||||||
registerChannel(CHANNEL_NAME, packetStructure, (data) => {
|
registerChannel(CHANNEL_NAME, packetStructure, (data) => {
|
||||||
const config = JSON.parse(data.newConfiguration)
|
const config = JSON.parse(data.newConfiguration)
|
||||||
bot.mouse.setConfigFromPacket(config)
|
if (config.customBreakTime !== undefined && Object.values(config.customBreakTime).every(x => typeof x === 'number')) {
|
||||||
|
bot.mouse.customBreakTime = config.customBreakTime
|
||||||
|
}
|
||||||
|
if (config.customBreakTimeToolAllowance !== undefined) {
|
||||||
|
bot.mouse.customBreakTimeToolAllowance = new Set(config.customBreakTimeToolAllowance)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.blockPlacePrediction !== undefined) {
|
||||||
|
bot.mouse.settings.blockPlacePrediction = config.blockPlacePrediction
|
||||||
|
}
|
||||||
|
if (config.blockPlacePredictionDelay !== undefined) {
|
||||||
|
bot.mouse.settings.blockPlacePredictionDelay = config.blockPlacePredictionDelay
|
||||||
|
}
|
||||||
}, true)
|
}, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,30 +94,15 @@ const registerWaypointChannels = () => {
|
||||||
{
|
{
|
||||||
name: 'color',
|
name: 'color',
|
||||||
type: 'i32'
|
type: 'i32'
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'metadataJson',
|
|
||||||
type: ['pstring', { countType: 'i16' }]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
registerChannel('minecraft-web-client:waypoint-add', packetStructure, (data) => {
|
registerChannel('minecraft-web-client:waypoint-add', packetStructure, (data) => {
|
||||||
// Parse metadata if provided
|
|
||||||
let metadata: any = {}
|
|
||||||
if (data.metadataJson && data.metadataJson.trim() !== '') {
|
|
||||||
try {
|
|
||||||
metadata = JSON.parse(data.metadataJson)
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('Failed to parse waypoint metadataJson:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getThreeJsRendererMethods()?.addWaypoint(data.id, data.x, data.y, data.z, {
|
getThreeJsRendererMethods()?.addWaypoint(data.id, data.x, data.y, data.z, {
|
||||||
minDistance: data.minDistance,
|
minDistance: data.minDistance,
|
||||||
label: data.label || undefined,
|
label: data.label || undefined,
|
||||||
color: data.color || undefined,
|
color: data.color || undefined
|
||||||
metadata
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
46
src/dayCycle.ts
Normal file
46
src/dayCycle.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { options } from './optionsStorage'
|
||||||
|
import { assertDefined } from './utils'
|
||||||
|
import { updateBackground } from './water'
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const timeUpdated = () => {
|
||||||
|
// 0 morning
|
||||||
|
const dayTotal = 24_000
|
||||||
|
const evening = 11_500
|
||||||
|
const night = 13_500
|
||||||
|
const morningStart = 23_000
|
||||||
|
const morningEnd = 23_961
|
||||||
|
const timeProgress = options.dayCycleAndLighting ? bot.time.timeOfDay : 0
|
||||||
|
|
||||||
|
// todo check actual colors
|
||||||
|
const dayColorRainy = { r: 111 / 255, g: 156 / 255, b: 236 / 255 }
|
||||||
|
// todo yes, we should make animations (and rain)
|
||||||
|
// eslint-disable-next-line unicorn/numeric-separators-style
|
||||||
|
const dayColor = bot.isRaining ? dayColorRainy : { r: 0.6784313725490196, g: 0.8470588235294118, b: 0.9019607843137255 } // lightblue
|
||||||
|
// let newColor = dayColor
|
||||||
|
let int = 1
|
||||||
|
if (timeProgress < evening) {
|
||||||
|
// stay dayily
|
||||||
|
} else if (timeProgress < night) {
|
||||||
|
const progressNorm = timeProgress - evening
|
||||||
|
const progressMax = night - evening
|
||||||
|
int = 1 - progressNorm / progressMax
|
||||||
|
} else if (timeProgress < morningStart) {
|
||||||
|
int = 0
|
||||||
|
} else if (timeProgress < morningEnd) {
|
||||||
|
const progressNorm = timeProgress - morningStart
|
||||||
|
const progressMax = night - morningEnd
|
||||||
|
int = progressNorm / progressMax
|
||||||
|
}
|
||||||
|
// todo need to think wisely how to set these values & also move directional light around!
|
||||||
|
const colorInt = Math.max(int, 0.1)
|
||||||
|
updateBackground({ r: dayColor.r * colorInt, g: dayColor.g * colorInt, b: dayColor.b * colorInt })
|
||||||
|
if (!options.newVersionsLighting && bot.supportFeature('blockStateId')) {
|
||||||
|
appViewer.playerState.reactive.ambientLight = Math.max(int, 0.25)
|
||||||
|
appViewer.playerState.reactive.directionalLight = Math.min(int, 0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.on('time', timeUpdated)
|
||||||
|
timeUpdated()
|
||||||
|
}
|
||||||
|
|
@ -16,8 +16,7 @@ export const defaultOptions = {
|
||||||
chatOpacityOpened: 100,
|
chatOpacityOpened: 100,
|
||||||
messagesLimit: 200,
|
messagesLimit: 200,
|
||||||
volume: 50,
|
volume: 50,
|
||||||
enableMusic: true,
|
enableMusic: false,
|
||||||
musicVolume: 50,
|
|
||||||
// fov: 70,
|
// fov: 70,
|
||||||
fov: 75,
|
fov: 75,
|
||||||
defaultPerspective: 'first_person' as 'first_person' | 'third_person_back' | 'third_person_front',
|
defaultPerspective: 'first_person' as 'first_person' | 'third_person_back' | 'third_person_front',
|
||||||
|
|
@ -42,7 +41,6 @@ export const defaultOptions = {
|
||||||
renderEars: true,
|
renderEars: true,
|
||||||
lowMemoryMode: false,
|
lowMemoryMode: false,
|
||||||
starfieldRendering: true,
|
starfieldRendering: true,
|
||||||
defaultSkybox: true,
|
|
||||||
enabledResourcepack: null as string | null,
|
enabledResourcepack: null as string | null,
|
||||||
useVersionsTextures: 'latest',
|
useVersionsTextures: 'latest',
|
||||||
serverResourcePacks: 'prompt' as 'prompt' | 'always' | 'never',
|
serverResourcePacks: 'prompt' as 'prompt' | 'always' | 'never',
|
||||||
|
|
@ -85,7 +83,6 @@ export const defaultOptions = {
|
||||||
localServerOptions: {
|
localServerOptions: {
|
||||||
gameMode: 1
|
gameMode: 1
|
||||||
} as any,
|
} as any,
|
||||||
saveLoginPassword: 'prompt' as 'prompt' | 'never' | 'always',
|
|
||||||
preferLoadReadonly: false,
|
preferLoadReadonly: false,
|
||||||
experimentalClientSelfReload: false,
|
experimentalClientSelfReload: false,
|
||||||
remoteSoundsSupport: false,
|
remoteSoundsSupport: false,
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,6 @@ import { WorldRendererThree } from 'renderer/viewer/three/worldrendererThree'
|
||||||
import { enable, disable, enabled } from 'debug'
|
import { enable, disable, enabled } from 'debug'
|
||||||
import { Vec3 } from 'vec3'
|
import { Vec3 } from 'vec3'
|
||||||
|
|
||||||
customEvents.on('mineflayerBotCreated', () => {
|
|
||||||
window.debugServerPacketNames = Object.fromEntries(Object.keys(loadedData.protocol.play.toClient.types).map(name => {
|
|
||||||
name = name.replace('packet_', '')
|
|
||||||
return [name, name]
|
|
||||||
}))
|
|
||||||
window.debugClientPacketNames = Object.fromEntries(Object.keys(loadedData.protocol.play.toServer.types).map(name => {
|
|
||||||
name = name.replace('packet_', '')
|
|
||||||
return [name, name]
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
window.Vec3 = Vec3
|
window.Vec3 = Vec3
|
||||||
window.cursorBlockRel = (x = 0, y = 0, z = 0) => {
|
window.cursorBlockRel = (x = 0, y = 0, z = 0) => {
|
||||||
const newPos = bot.blockAtCursor(5)?.position.offset(x, y, z)
|
const newPos = bot.blockAtCursor(5)?.position.offset(x, y, z)
|
||||||
|
|
|
||||||
|
|
@ -246,29 +246,22 @@ customEvents.on('gameLoaded', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// even if not found, still record to cache
|
// even if not found, still record to cache
|
||||||
void getThreeJsRendererMethods()!.updatePlayerSkin(entityId, player.username, player.uuid, skinUrl ?? true, capeUrl)
|
void getThreeJsRendererMethods()?.updatePlayerSkin(entityId, player.username, player.uuid, skinUrl ?? true, capeUrl)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reportError(new Error('Error applying skin texture:', { cause: err }))
|
console.error('Error decoding player texture:', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.on('playerJoined', updateSkin)
|
bot.on('playerJoined', updateSkin)
|
||||||
bot.on('playerUpdated', updateSkin)
|
bot.on('playerUpdated', updateSkin)
|
||||||
for (const entity of Object.values(bot.players)) {
|
|
||||||
updateSkin(entity)
|
|
||||||
}
|
|
||||||
|
|
||||||
const teamUpdated = (team: Team) => {
|
bot.on('teamUpdated', (team: Team) => {
|
||||||
for (const entity of Object.values(bot.entities)) {
|
for (const entity of Object.values(bot.entities)) {
|
||||||
if (entity.type === 'player' && entity.username && team.members.includes(entity.username) || entity.uuid && team.members.includes(entity.uuid)) {
|
if (entity.type === 'player' && entity.username && team.members.includes(entity.username) || entity.uuid && team.members.includes(entity.uuid)) {
|
||||||
bot.emit('entityUpdate', entity)
|
bot.emit('entityUpdate', entity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
bot.on('teamUpdated', teamUpdated)
|
|
||||||
for (const team of Object.values(bot.teams)) {
|
|
||||||
teamUpdated(team)
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateEntityNameTags = (team: Team) => {
|
const updateEntityNameTags = (team: Team) => {
|
||||||
for (const entity of Object.values(bot.entities)) {
|
for (const entity of Object.values(bot.entities)) {
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ import { isCypress } from './standaloneUtils'
|
||||||
|
|
||||||
import { startLocalServer, unsupportedLocalServerFeatures } from './createLocalServer'
|
import { startLocalServer, unsupportedLocalServerFeatures } from './createLocalServer'
|
||||||
import defaultServerOptions from './defaultLocalServerOptions'
|
import defaultServerOptions from './defaultLocalServerOptions'
|
||||||
|
import dayCycle from './dayCycle'
|
||||||
|
|
||||||
import { onAppLoad, resourcepackReload, resourcePackState } from './resourcePack'
|
import { onAppLoad, resourcepackReload, resourcePackState } from './resourcePack'
|
||||||
import { ConnectPeerOptions, connectToPeer } from './localServerMultiplayer'
|
import { ConnectPeerOptions, connectToPeer } from './localServerMultiplayer'
|
||||||
|
|
@ -304,7 +305,7 @@ export async function connect (connectOptions: ConnectOptions) {
|
||||||
|
|
||||||
if (connectOptions.server && !connectOptions.viewerWsConnect && !parsedServer.isWebSocket) {
|
if (connectOptions.server && !connectOptions.viewerWsConnect && !parsedServer.isWebSocket) {
|
||||||
console.log(`using proxy ${proxy.host}:${proxy.port || location.port}`)
|
console.log(`using proxy ${proxy.host}:${proxy.port || location.port}`)
|
||||||
net['setProxy']({ hostname: proxy.host, port: proxy.port, headers: { Authorization: `Bearer ${new URLSearchParams(location.search).get('token') ?? ''}` }, artificialDelay: appQueryParams.addPing ? Number(appQueryParams.addPing) : undefined })
|
net['setProxy']({ hostname: proxy.host, port: proxy.port, headers: { Authorization: `Bearer ${new URLSearchParams(location.search).get('token') ?? ''}` } })
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderDistance = singleplayer ? renderDistanceSingleplayer : multiplayerRenderDistance
|
const renderDistance = singleplayer ? renderDistanceSingleplayer : multiplayerRenderDistance
|
||||||
|
|
@ -793,6 +794,7 @@ export async function connect (connectOptions: ConnectOptions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
initMotionTracking()
|
initMotionTracking()
|
||||||
|
dayCycle()
|
||||||
|
|
||||||
// Bot position callback
|
// Bot position callback
|
||||||
const botPosition = () => {
|
const botPosition = () => {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import PrismarineChatLoader from 'prismarine-chat'
|
||||||
import * as nbt from 'prismarine-nbt'
|
import * as nbt from 'prismarine-nbt'
|
||||||
import { BlockModel } from 'mc-assets'
|
import { BlockModel } from 'mc-assets'
|
||||||
import { renderSlot } from 'renderer/viewer/three/renderSlot'
|
import { renderSlot } from 'renderer/viewer/three/renderSlot'
|
||||||
import { loadSkinFromUsername } from 'renderer/viewer/lib/utils/skins'
|
|
||||||
import Generic95 from '../assets/generic_95.png'
|
import Generic95 from '../assets/generic_95.png'
|
||||||
import { appReplacableResources } from './generated/resources'
|
import { appReplacableResources } from './generated/resources'
|
||||||
import { activeModalStack, hideCurrentModal, hideModal, miscUiState, showModal } from './globalState'
|
import { activeModalStack, hideCurrentModal, hideModal, miscUiState, showModal } from './globalState'
|
||||||
|
|
@ -24,7 +23,6 @@ import { getItemDescription } from './itemsDescriptions'
|
||||||
import { MessageFormatPart } from './chatUtils'
|
import { MessageFormatPart } from './chatUtils'
|
||||||
import { GeneralInputItem, getItemMetadata, getItemModelName, getItemNameRaw, RenderItem } from './mineflayer/items'
|
import { GeneralInputItem, getItemMetadata, getItemModelName, getItemNameRaw, RenderItem } from './mineflayer/items'
|
||||||
import { playerState } from './mineflayer/playerState'
|
import { playerState } from './mineflayer/playerState'
|
||||||
import { modelViewerState } from './react/OverlayModelViewer'
|
|
||||||
|
|
||||||
const loadedImagesCache = new Map<string, HTMLImageElement | ImageBitmap>()
|
const loadedImagesCache = new Map<string, HTMLImageElement | ImageBitmap>()
|
||||||
const cleanLoadedImagesCache = () => {
|
const cleanLoadedImagesCache = () => {
|
||||||
|
|
@ -42,34 +40,6 @@ export const jeiCustomCategories = proxy({
|
||||||
value: [] as Array<{ id: string, categoryTitle: string, items: any[] }>
|
value: [] as Array<{ id: string, categoryTitle: string, items: any[] }>
|
||||||
})
|
})
|
||||||
|
|
||||||
let remotePlayerSkin: string | undefined | Promise<string>
|
|
||||||
|
|
||||||
export const showInventoryPlayer = () => {
|
|
||||||
modelViewerState.model = {
|
|
||||||
positioning: {
|
|
||||||
windowWidth: 176,
|
|
||||||
windowHeight: 166,
|
|
||||||
x: 25,
|
|
||||||
y: 8,
|
|
||||||
width: 50,
|
|
||||||
height: 70,
|
|
||||||
scaled: true,
|
|
||||||
onlyInitialScale: true,
|
|
||||||
followCursor: true,
|
|
||||||
},
|
|
||||||
// models: ['https://bucket.mcraft.fun/sitarbuckss.glb'],
|
|
||||||
// debug: true,
|
|
||||||
steveModelSkin: appViewer.playerState.reactive.playerSkin ?? (typeof remotePlayerSkin === 'string' ? remotePlayerSkin : ''),
|
|
||||||
}
|
|
||||||
if (remotePlayerSkin === undefined && !appViewer.playerState.reactive.playerSkin) {
|
|
||||||
remotePlayerSkin = loadSkinFromUsername(bot.username, 'skin').then(a => {
|
|
||||||
setTimeout(() => { showInventoryPlayer() }, 0) // todo patch instead and make reactive
|
|
||||||
remotePlayerSkin = a ?? ''
|
|
||||||
return remotePlayerSkin
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const onGameLoad = () => {
|
export const onGameLoad = () => {
|
||||||
version = bot.version
|
version = bot.version
|
||||||
|
|
||||||
|
|
@ -422,12 +392,7 @@ const openWindow = (type: string | undefined, title: string | any = undefined) =
|
||||||
miscUiState.displaySearchInput = false
|
miscUiState.displaySearchInput = false
|
||||||
destroyFn()
|
destroyFn()
|
||||||
skipClosePacketSending = false
|
skipClosePacketSending = false
|
||||||
|
|
||||||
modelViewerState.model = undefined
|
|
||||||
})
|
})
|
||||||
if (type === undefined) {
|
|
||||||
showInventoryPlayer()
|
|
||||||
}
|
|
||||||
cleanLoadedImagesCache()
|
cleanLoadedImagesCache()
|
||||||
const inv = openItemsCanvas(type)
|
const inv = openItemsCanvas(type)
|
||||||
inv.canvasManager.children[0].mobileHelpers = miscUiState.currentTouch
|
inv.canvasManager.children[0].mobileHelpers = miscUiState.currentTouch
|
||||||
|
|
@ -470,7 +435,6 @@ const openWindow = (type: string | undefined, title: string | any = undefined) =
|
||||||
const isRightClick = type === 'rightclick'
|
const isRightClick = type === 'rightclick'
|
||||||
const isLeftClick = type === 'leftclick'
|
const isLeftClick = type === 'leftclick'
|
||||||
if (isLeftClick || isRightClick) {
|
if (isLeftClick || isRightClick) {
|
||||||
modelViewerState.model = undefined
|
|
||||||
inv.canvasManager.children[0].showRecipesOrUsages(isLeftClick, item)
|
inv.canvasManager.children[0].showRecipesOrUsages(isLeftClick, item)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -502,7 +466,6 @@ const openWindow = (type: string | undefined, title: string | any = undefined) =
|
||||||
if (freeSlot === null) return
|
if (freeSlot === null) return
|
||||||
void bot.creative.setInventorySlot(freeSlot, item)
|
void bot.creative.setInventorySlot(freeSlot, item)
|
||||||
} else {
|
} else {
|
||||||
modelViewerState.model = undefined
|
|
||||||
inv.canvasManager.children[0].showRecipesOrUsages(!isRightclick, mapSlots([item], true)[0])
|
inv.canvasManager.children[0].showRecipesOrUsages(!isRightclick, mapSlots([item], true)[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,8 +130,7 @@ export const setProxy = (proxyParams: ProxyParams) => {
|
||||||
net['setProxy']({
|
net['setProxy']({
|
||||||
hostname: proxy.host,
|
hostname: proxy.host,
|
||||||
port: proxy.port,
|
port: proxy.port,
|
||||||
headers: proxyParams.headers,
|
headers: proxyParams.headers
|
||||||
artificialDelay: appQueryParams.addPing ? Number(appQueryParams.addPing) : undefined
|
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
proxy
|
proxy
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ const domListeners = (bot: Bot) => {
|
||||||
}, { signal: abortController.signal })
|
}, { signal: abortController.signal })
|
||||||
|
|
||||||
bot.mouse.beforeUpdateChecks = () => {
|
bot.mouse.beforeUpdateChecks = () => {
|
||||||
if (!document.hasFocus() || !isGameActive(true)) {
|
if (!document.hasFocus()) {
|
||||||
// deactive all buttons
|
// deactive all buttons
|
||||||
bot.mouse.buttons.fill(false)
|
bot.mouse.buttons.fill(false)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,9 @@ class CustomDuplex extends Duplex {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getWebsocketStream = async (host: string) => {
|
export const getWebsocketStream = async (host: string) => {
|
||||||
const baseProtocol = host.startsWith('ws://') ? 'ws' : 'wss'
|
const baseProtocol = location.protocol === 'https:' ? 'wss' : host.startsWith('ws://') ? 'ws' : 'wss'
|
||||||
const hostClean = host.replace('ws://', '').replace('wss://', '')
|
const hostClean = host.replace('ws://', '').replace('wss://', '')
|
||||||
const hostURL = new URL(`${baseProtocol}://${hostClean}`)
|
const ws = new WebSocket(`${baseProtocol}://${hostClean}`)
|
||||||
const hostParams = hostURL.searchParams
|
|
||||||
hostParams.append('client_mcraft', '')
|
|
||||||
const ws = new WebSocket(`${baseProtocol}://${hostURL.host}${hostURL.pathname}?${hostParams.toString()}`)
|
|
||||||
const clientDuplex = new CustomDuplex(undefined, data => {
|
const clientDuplex = new CustomDuplex(undefined, data => {
|
||||||
ws.send(data)
|
ws.send(data)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -480,24 +480,6 @@ export const guiOptionsScheme: {
|
||||||
],
|
],
|
||||||
sound: [
|
sound: [
|
||||||
{ volume: {} },
|
{ volume: {} },
|
||||||
{
|
|
||||||
custom () {
|
|
||||||
return <OptionSlider
|
|
||||||
valueOverride={options.enableMusic ? undefined : 0}
|
|
||||||
onChange={(value) => {
|
|
||||||
options.musicVolume = value
|
|
||||||
}}
|
|
||||||
item={{
|
|
||||||
type: 'slider',
|
|
||||||
id: 'musicVolume',
|
|
||||||
text: 'Music Volume',
|
|
||||||
min: 0,
|
|
||||||
max: 100,
|
|
||||||
unit: '%',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
custom () {
|
custom () {
|
||||||
return <Button label='Sound Muffler' onClick={() => showModal({ reactType: 'sound-muffler' })} inScreen />
|
return <Button label='Sound Muffler' onClick={() => showModal({ reactType: 'sound-muffler' })} inScreen />
|
||||||
|
|
@ -568,16 +550,6 @@ export const guiOptionsScheme: {
|
||||||
return <Category>Server Connection</Category>
|
return <Category>Server Connection</Category>
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
saveLoginPassword: {
|
|
||||||
tooltip: 'Controls whether to save login passwords for servers in this browser memory.',
|
|
||||||
values: [
|
|
||||||
'prompt',
|
|
||||||
'always',
|
|
||||||
'never'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
custom () {
|
custom () {
|
||||||
const { serversAutoVersionSelect } = useSnapshot(options)
|
const { serversAutoVersionSelect } = useSnapshot(options)
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@ export const startLocalReplayServer = (contents: string) => {
|
||||||
const server = createServer({
|
const server = createServer({
|
||||||
Server: LocalServer as any,
|
Server: LocalServer as any,
|
||||||
version: header.minecraftVersion,
|
version: header.minecraftVersion,
|
||||||
keepAlive: false,
|
|
||||||
'online-mode': false
|
'online-mode': false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQ
|
||||||
}
|
}
|
||||||
|
|
||||||
const displayConnectButton = qsParamIp
|
const displayConnectButton = qsParamIp
|
||||||
const serverExamples = ['example.com:25565', 'play.hypixel.net', 'ws://play.pcm.gg', 'wss://play.webmc.fun']
|
const serverExamples = ['example.com:25565', 'play.hypixel.net', 'ws://play.pcm.gg']
|
||||||
// pick random example
|
// pick random example
|
||||||
const example = serverExamples[Math.floor(Math.random() * serverExamples.length)]
|
const example = serverExamples[Math.floor(Math.random() * serverExamples.length)]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,9 +125,7 @@ export default ({
|
||||||
const chatInput = useRef<HTMLInputElement>(null!)
|
const chatInput = useRef<HTMLInputElement>(null!)
|
||||||
const chatMessages = useRef<HTMLDivElement>(null)
|
const chatMessages = useRef<HTMLDivElement>(null)
|
||||||
const chatHistoryPos = useRef(sendHistoryRef.current.length)
|
const chatHistoryPos = useRef(sendHistoryRef.current.length)
|
||||||
const commandHistoryPos = useRef(0)
|
|
||||||
const inputCurrentlyEnteredValue = useRef('')
|
const inputCurrentlyEnteredValue = useRef('')
|
||||||
const commandHistoryRef = useRef(sendHistoryRef.current.filter((msg: string) => msg.startsWith('/')))
|
|
||||||
|
|
||||||
const { scrollToBottom, isAtBottom, wasAtBottom, currentlyAtBottom } = useScrollBehavior(chatMessages, { messages, opened })
|
const { scrollToBottom, isAtBottom, wasAtBottom, currentlyAtBottom } = useScrollBehavior(chatMessages, { messages, opened })
|
||||||
const [rightNowAtBottom, setRightNowAtBottom] = useState(false)
|
const [rightNowAtBottom, setRightNowAtBottom] = useState(false)
|
||||||
|
|
@ -144,9 +142,6 @@ export default ({
|
||||||
sendHistoryRef.current = newHistory
|
sendHistoryRef.current = newHistory
|
||||||
window.sessionStorage.chatHistory = JSON.stringify(newHistory)
|
window.sessionStorage.chatHistory = JSON.stringify(newHistory)
|
||||||
chatHistoryPos.current = newHistory.length
|
chatHistoryPos.current = newHistory.length
|
||||||
// Update command history (only messages starting with /)
|
|
||||||
commandHistoryRef.current = newHistory.filter((msg: string) => msg.startsWith('/'))
|
|
||||||
commandHistoryPos.current = commandHistoryRef.current.length
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const acceptComplete = (item: string) => {
|
const acceptComplete = (item: string) => {
|
||||||
|
|
@ -185,21 +180,6 @@ export default ({
|
||||||
updateInputValue(sendHistoryRef.current[chatHistoryPos.current] || inputCurrentlyEnteredValue.current || '')
|
updateInputValue(sendHistoryRef.current[chatHistoryPos.current] || inputCurrentlyEnteredValue.current || '')
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCommandArrowUp = () => {
|
|
||||||
if (commandHistoryPos.current === 0 || commandHistoryRef.current.length === 0) return
|
|
||||||
if (commandHistoryPos.current === commandHistoryRef.current.length) { // started navigating command history
|
|
||||||
inputCurrentlyEnteredValue.current = chatInput.current.value
|
|
||||||
}
|
|
||||||
commandHistoryPos.current--
|
|
||||||
updateInputValue(commandHistoryRef.current[commandHistoryPos.current] || '')
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCommandArrowDown = () => {
|
|
||||||
if (commandHistoryPos.current === commandHistoryRef.current.length) return
|
|
||||||
commandHistoryPos.current++
|
|
||||||
updateInputValue(commandHistoryRef.current[commandHistoryPos.current] || inputCurrentlyEnteredValue.current || '')
|
|
||||||
}
|
|
||||||
|
|
||||||
const auxInputFocus = (direction: 'up' | 'down') => {
|
const auxInputFocus = (direction: 'up' | 'down') => {
|
||||||
chatInput.current.focus()
|
chatInput.current.focus()
|
||||||
if (direction === 'up') {
|
if (direction === 'up') {
|
||||||
|
|
@ -223,7 +203,6 @@ export default ({
|
||||||
updateInputValue(chatInputValueGlobal.value)
|
updateInputValue(chatInputValueGlobal.value)
|
||||||
chatInputValueGlobal.value = ''
|
chatInputValueGlobal.value = ''
|
||||||
chatHistoryPos.current = sendHistoryRef.current.length
|
chatHistoryPos.current = sendHistoryRef.current.length
|
||||||
commandHistoryPos.current = commandHistoryRef.current.length
|
|
||||||
if (!usingTouch) {
|
if (!usingTouch) {
|
||||||
chatInput.current.focus()
|
chatInput.current.focus()
|
||||||
}
|
}
|
||||||
|
|
@ -545,19 +524,9 @@ export default ({
|
||||||
onBlur={() => setIsInputFocused(false)}
|
onBlur={() => setIsInputFocused(false)}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.code === 'ArrowUp') {
|
if (e.code === 'ArrowUp') {
|
||||||
if (e.altKey) {
|
handleArrowUp()
|
||||||
handleCommandArrowUp()
|
|
||||||
e.preventDefault()
|
|
||||||
} else {
|
|
||||||
handleArrowUp()
|
|
||||||
}
|
|
||||||
} else if (e.code === 'ArrowDown') {
|
} else if (e.code === 'ArrowDown') {
|
||||||
if (e.altKey) {
|
handleArrowDown()
|
||||||
handleCommandArrowDown()
|
|
||||||
e.preventDefault()
|
|
||||||
} else {
|
|
||||||
handleArrowDown()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (e.code === 'Tab') {
|
if (e.code === 'Tab') {
|
||||||
if (completionItemsSource.length) {
|
if (completionItemsSource.length) {
|
||||||
|
|
|
||||||
|
|
@ -73,28 +73,16 @@ export default () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const builtinHandled = tryHandleBuiltinCommand(message)
|
const builtinHandled = tryHandleBuiltinCommand(message)
|
||||||
if (getServerIndex() !== undefined && (message.startsWith('/login') || message.startsWith('/register')) && options.saveLoginPassword !== 'never') {
|
if (getServerIndex() !== undefined && (message.startsWith('/login') || message.startsWith('/register'))) {
|
||||||
const savePassword = () => {
|
showNotification('Click here to save your password in browser for auto-login', undefined, false, undefined, () => {
|
||||||
let hadPassword = false
|
|
||||||
updateLoadedServerData((server) => {
|
updateLoadedServerData((server) => {
|
||||||
server.autoLogin ??= {}
|
server.autoLogin ??= {}
|
||||||
const password = message.split(' ')[1]
|
const password = message.split(' ')[1]
|
||||||
hadPassword = !!server.autoLogin[bot.username]
|
|
||||||
server.autoLogin[bot.username] = password
|
server.autoLogin[bot.username] = password
|
||||||
return { ...server }
|
return { ...server }
|
||||||
})
|
})
|
||||||
if (options.saveLoginPassword === 'always') {
|
hideNotification()
|
||||||
const message = hadPassword ? 'Password updated in browser for auto-login' : 'Password saved in browser for auto-login'
|
})
|
||||||
showNotification(message, undefined, false, undefined)
|
|
||||||
} else {
|
|
||||||
hideNotification()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (options.saveLoginPassword === 'prompt') {
|
|
||||||
showNotification('Click here to save your password in browser for auto-login', undefined, false, undefined, savePassword)
|
|
||||||
} else {
|
|
||||||
savePassword()
|
|
||||||
}
|
|
||||||
notificationProxy.id = 'auto-login'
|
notificationProxy.id = 'auto-login'
|
||||||
const listener = () => {
|
const listener = () => {
|
||||||
hideNotification()
|
hideNotification()
|
||||||
|
|
|
||||||
|
|
@ -161,15 +161,7 @@ export const OptionButton = ({ item, onClick, valueText, cacheKey }: {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const OptionSlider = ({
|
export const OptionSlider = ({ item }: { item: Extract<OptionMeta, { type: 'slider' }> }) => {
|
||||||
item,
|
|
||||||
onChange,
|
|
||||||
valueOverride
|
|
||||||
}: {
|
|
||||||
item: Extract<OptionMeta, { type: 'slider' }>
|
|
||||||
onChange?: (value: number) => void
|
|
||||||
valueOverride?: number
|
|
||||||
}) => {
|
|
||||||
const { disabledBecauseOfSetting } = useCommonComponentsProps(item)
|
const { disabledBecauseOfSetting } = useCommonComponentsProps(item)
|
||||||
|
|
||||||
const optionValue = useSnapshot(options)[item.id!]
|
const optionValue = useSnapshot(options)[item.id!]
|
||||||
|
|
@ -182,7 +174,7 @@ export const OptionSlider = ({
|
||||||
return (
|
return (
|
||||||
<Slider
|
<Slider
|
||||||
label={item.text!}
|
label={item.text!}
|
||||||
value={valueOverride ?? options[item.id!]}
|
value={options[item.id!]}
|
||||||
data-setting={item.id}
|
data-setting={item.id}
|
||||||
disabledReason={isLocked(item) ? 'qs' : disabledBecauseOfSetting ? `Disabled because ${item.disableIf![0]} is ${item.disableIf![1]}` : item.disabledReason}
|
disabledReason={isLocked(item) ? 'qs' : disabledBecauseOfSetting ? `Disabled because ${item.disableIf![0]} is ${item.disableIf![1]}` : item.disabledReason}
|
||||||
min={item.min}
|
min={item.min}
|
||||||
|
|
@ -192,7 +184,6 @@ export const OptionSlider = ({
|
||||||
updateOnDragEnd={item.delayApply}
|
updateOnDragEnd={item.delayApply}
|
||||||
updateValue={(value) => {
|
updateValue={(value) => {
|
||||||
options[item.id!] = value
|
options[item.id!] = value
|
||||||
onChange?.(value)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,554 +0,0 @@
|
||||||
import { proxy, useSnapshot, subscribe } from 'valtio'
|
|
||||||
import { useEffect, useMemo, useRef } from 'react'
|
|
||||||
import * as THREE from 'three'
|
|
||||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
|
|
||||||
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
|
|
||||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
|
|
||||||
import { applySkinToPlayerObject, createPlayerObject, PlayerObjectType } from '../../renderer/viewer/lib/createPlayerObject'
|
|
||||||
import { currentScaling } from '../scaleInterface'
|
|
||||||
import { activeModalStack } from '../globalState'
|
|
||||||
|
|
||||||
THREE.ColorManagement.enabled = false
|
|
||||||
|
|
||||||
export const modelViewerState = proxy({
|
|
||||||
model: undefined as undefined | {
|
|
||||||
models?: string[] // Array of model URLs (URL itself is the cache key)
|
|
||||||
steveModelSkin?: string
|
|
||||||
debug?: boolean
|
|
||||||
// absolute positioning
|
|
||||||
positioning: {
|
|
||||||
windowWidth: number
|
|
||||||
windowHeight: number
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
width: number
|
|
||||||
height: number
|
|
||||||
scaled?: boolean
|
|
||||||
onlyInitialScale?: boolean
|
|
||||||
followCursor?: boolean
|
|
||||||
}
|
|
||||||
modelCustomization?: { [modelUrl: string]: { color?: string, opacity?: number, metalness?: number, roughness?: number } }
|
|
||||||
resetRotationOnReleae?: boolean
|
|
||||||
continiousRender?: boolean
|
|
||||||
alwaysRender?: boolean
|
|
||||||
}
|
|
||||||
})
|
|
||||||
globalThis.modelViewerState = modelViewerState
|
|
||||||
|
|
||||||
// Global debug function to get camera and model values
|
|
||||||
globalThis.getModelViewerValues = () => {
|
|
||||||
const scene = globalThis.sceneRef?.current
|
|
||||||
if (!scene) return null
|
|
||||||
|
|
||||||
const { camera, playerObject } = scene
|
|
||||||
if (!playerObject) return null
|
|
||||||
|
|
||||||
const wrapper = playerObject.parent
|
|
||||||
if (!wrapper) return null
|
|
||||||
|
|
||||||
const box = new THREE.Box3().setFromObject(wrapper)
|
|
||||||
const size = box.getSize(new THREE.Vector3())
|
|
||||||
const center = box.getCenter(new THREE.Vector3())
|
|
||||||
|
|
||||||
return {
|
|
||||||
camera: {
|
|
||||||
position: camera.position.clone(),
|
|
||||||
fov: camera.fov,
|
|
||||||
aspect: camera.aspect
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
position: wrapper.position.clone(),
|
|
||||||
rotation: wrapper.rotation.clone(),
|
|
||||||
scale: wrapper.scale.clone(),
|
|
||||||
size,
|
|
||||||
center
|
|
||||||
},
|
|
||||||
cursor: {
|
|
||||||
position: globalThis.cursorPosition || { x: 0, y: 0 },
|
|
||||||
normalized: globalThis.cursorPosition ? {
|
|
||||||
x: globalThis.cursorPosition.x * 2 - 1,
|
|
||||||
y: globalThis.cursorPosition.y * 2 - 1
|
|
||||||
} : { x: 0, y: 0 }
|
|
||||||
},
|
|
||||||
visibleArea: {
|
|
||||||
height: 2 * Math.tan(camera.fov * Math.PI / 180 / 2) * camera.position.z,
|
|
||||||
width: 2 * Math.tan(camera.fov * Math.PI / 180 / 2) * camera.position.z * camera.aspect
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribe(activeModalStack, () => {
|
|
||||||
if (!modelViewerState.model || !modelViewerState.model?.alwaysRender) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (activeModalStack.length === 0) {
|
|
||||||
modelViewerState.model = undefined
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
const { model } = useSnapshot(modelViewerState)
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null)
|
|
||||||
const sceneRef = useRef<{
|
|
||||||
scene: THREE.Scene
|
|
||||||
camera: THREE.PerspectiveCamera
|
|
||||||
renderer: THREE.WebGLRenderer
|
|
||||||
controls: OrbitControls
|
|
||||||
playerObject?: PlayerObjectType
|
|
||||||
dispose: () => void
|
|
||||||
}>()
|
|
||||||
const initialScale = useMemo(() => {
|
|
||||||
return currentScaling.scale
|
|
||||||
}, [])
|
|
||||||
globalThis.sceneRef = sceneRef
|
|
||||||
|
|
||||||
// Cursor following state
|
|
||||||
const cursorPosition = useRef({ x: 0, y: 0 })
|
|
||||||
const isFollowingCursor = useRef(false)
|
|
||||||
|
|
||||||
// Model management state
|
|
||||||
const loadedModels = useRef<Map<string, THREE.Object3D>>(new Map())
|
|
||||||
const modelLoaders = useRef<Map<string, GLTFLoader | OBJLoader>>(new Map())
|
|
||||||
|
|
||||||
// Model management functions
|
|
||||||
const loadModel = (modelUrl: string) => {
|
|
||||||
if (loadedModels.current.has(modelUrl)) return // Already loaded
|
|
||||||
|
|
||||||
const isGLTF = modelUrl.toLowerCase().endsWith('.gltf') || modelUrl.toLowerCase().endsWith('.glb')
|
|
||||||
const loader = isGLTF ? new GLTFLoader() : new OBJLoader()
|
|
||||||
modelLoaders.current.set(modelUrl, loader)
|
|
||||||
|
|
||||||
const onLoad = (object: THREE.Object3D) => {
|
|
||||||
// Apply customization if available and enable shadows
|
|
||||||
const customization = model?.modelCustomization?.[modelUrl]
|
|
||||||
object.traverse((child) => {
|
|
||||||
if (child instanceof THREE.Mesh) {
|
|
||||||
// Enable shadow casting and receiving for all meshes
|
|
||||||
child.castShadow = true
|
|
||||||
child.receiveShadow = true
|
|
||||||
|
|
||||||
if (child.material && customization) {
|
|
||||||
const material = child.material as THREE.MeshStandardMaterial
|
|
||||||
if (customization.color) {
|
|
||||||
material.color.setHex(parseInt(customization.color.replace('#', ''), 16))
|
|
||||||
}
|
|
||||||
if (customization.opacity !== undefined) {
|
|
||||||
material.opacity = customization.opacity
|
|
||||||
material.transparent = customization.opacity < 1
|
|
||||||
}
|
|
||||||
if (customization.metalness !== undefined) {
|
|
||||||
material.metalness = customization.metalness
|
|
||||||
}
|
|
||||||
if (customization.roughness !== undefined) {
|
|
||||||
material.roughness = customization.roughness
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Center and scale model
|
|
||||||
const box = new THREE.Box3().setFromObject(object)
|
|
||||||
const center = box.getCenter(new THREE.Vector3())
|
|
||||||
const size = box.getSize(new THREE.Vector3())
|
|
||||||
const maxDim = Math.max(size.x, size.y, size.z)
|
|
||||||
const scale = 2 / maxDim
|
|
||||||
object.scale.setScalar(scale)
|
|
||||||
object.position.sub(center.multiplyScalar(scale))
|
|
||||||
|
|
||||||
// Store the model using URL as key
|
|
||||||
loadedModels.current.set(modelUrl, object)
|
|
||||||
sceneRef.current?.scene.add(object)
|
|
||||||
|
|
||||||
// Trigger render
|
|
||||||
if (sceneRef.current) {
|
|
||||||
setTimeout(() => {
|
|
||||||
const render = () => sceneRef.current?.renderer.render(sceneRef.current.scene, sceneRef.current.camera)
|
|
||||||
render()
|
|
||||||
}, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isGLTF) {
|
|
||||||
(loader as GLTFLoader).load(modelUrl, (gltf) => {
|
|
||||||
onLoad(gltf.scene)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
(loader as OBJLoader).load(modelUrl, onLoad)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const removeModel = (modelUrl: string) => {
|
|
||||||
const model = loadedModels.current.get(modelUrl)
|
|
||||||
if (model) {
|
|
||||||
sceneRef.current?.scene.remove(model)
|
|
||||||
model.traverse((child) => {
|
|
||||||
if (child instanceof THREE.Mesh) {
|
|
||||||
if (child.material) {
|
|
||||||
if (Array.isArray(child.material)) {
|
|
||||||
for (const mat of child.material) {
|
|
||||||
mat.dispose()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
child.material.dispose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (child.geometry) {
|
|
||||||
child.geometry.dispose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
loadedModels.current.delete(modelUrl)
|
|
||||||
}
|
|
||||||
modelLoaders.current.delete(modelUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe to model changes
|
|
||||||
useEffect(() => {
|
|
||||||
if (!modelViewerState.model?.models) return
|
|
||||||
|
|
||||||
const modelsChanged = () => {
|
|
||||||
const currentModels = modelViewerState.model?.models || []
|
|
||||||
const currentModelUrls = new Set(currentModels)
|
|
||||||
const loadedModelUrls = new Set(loadedModels.current.keys())
|
|
||||||
|
|
||||||
// Remove models that are no longer in the state
|
|
||||||
for (const modelUrl of loadedModelUrls) {
|
|
||||||
if (!currentModelUrls.has(modelUrl)) {
|
|
||||||
removeModel(modelUrl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add new models
|
|
||||||
for (const modelUrl of currentModels) {
|
|
||||||
if (!loadedModelUrls.has(modelUrl)) {
|
|
||||||
loadModel(modelUrl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const unsubscribe = subscribe(modelViewerState.model.models, modelsChanged)
|
|
||||||
|
|
||||||
let unmounted = false
|
|
||||||
setTimeout(() => {
|
|
||||||
if (unmounted) return
|
|
||||||
modelsChanged()
|
|
||||||
})
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
unmounted = true
|
|
||||||
unsubscribe?.()
|
|
||||||
}
|
|
||||||
}, [model?.models])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!model || !containerRef.current) return
|
|
||||||
|
|
||||||
// Setup scene
|
|
||||||
const scene = new THREE.Scene()
|
|
||||||
scene.background = null // Transparent background
|
|
||||||
|
|
||||||
// Setup camera with optimal settings for player model viewing
|
|
||||||
const camera = new THREE.PerspectiveCamera(
|
|
||||||
50, // Reduced FOV for better model viewing
|
|
||||||
model.positioning.width / model.positioning.height,
|
|
||||||
0.1,
|
|
||||||
1000
|
|
||||||
)
|
|
||||||
camera.position.set(0, 0, 3) // Position camera to view player model optimally
|
|
||||||
|
|
||||||
// Setup renderer with pixel density awareness
|
|
||||||
const renderer = new THREE.WebGLRenderer({ alpha: true })
|
|
||||||
let scale = window.devicePixelRatio || 1
|
|
||||||
if (modelViewerState.model?.positioning.scaled) {
|
|
||||||
scale *= currentScaling.scale
|
|
||||||
}
|
|
||||||
renderer.setPixelRatio(scale)
|
|
||||||
renderer.setSize(model.positioning.width, model.positioning.height)
|
|
||||||
|
|
||||||
// Enable shadow rendering for depth and realism
|
|
||||||
renderer.shadowMap.enabled = true
|
|
||||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap // Soft shadows for better quality
|
|
||||||
renderer.shadowMap.autoUpdate = true
|
|
||||||
|
|
||||||
containerRef.current.appendChild(renderer.domElement)
|
|
||||||
|
|
||||||
// Setup controls
|
|
||||||
const controls = new OrbitControls(camera, renderer.domElement)
|
|
||||||
// controls.enableZoom = false
|
|
||||||
// controls.enablePan = false
|
|
||||||
controls.minPolarAngle = Math.PI / 2 // Lock vertical rotation
|
|
||||||
controls.maxPolarAngle = Math.PI / 2
|
|
||||||
controls.enableDamping = true
|
|
||||||
controls.dampingFactor = 0.05
|
|
||||||
|
|
||||||
// Add ambient light for overall illumination
|
|
||||||
const ambientLight = new THREE.AmbientLight(0xff_ff_ff, 0.4) // Reduced intensity to allow shadows
|
|
||||||
scene.add(ambientLight)
|
|
||||||
|
|
||||||
// Add directional light for shadows and depth (similar to Minecraft inventory lighting)
|
|
||||||
const directionalLight = new THREE.DirectionalLight(0xff_ff_ff, 0.6)
|
|
||||||
directionalLight.position.set(2, 2, 2) // Position light from top-right-front
|
|
||||||
directionalLight.target.position.set(0, 0, 0) // Point towards center of scene
|
|
||||||
|
|
||||||
// Configure shadow properties for optimal quality
|
|
||||||
directionalLight.castShadow = true
|
|
||||||
directionalLight.shadow.mapSize.width = 2048 // High resolution shadow map
|
|
||||||
directionalLight.shadow.mapSize.height = 2048
|
|
||||||
directionalLight.shadow.camera.near = 0.1
|
|
||||||
directionalLight.shadow.camera.far = 10
|
|
||||||
directionalLight.shadow.camera.left = -3
|
|
||||||
directionalLight.shadow.camera.right = 3
|
|
||||||
directionalLight.shadow.camera.top = 3
|
|
||||||
directionalLight.shadow.camera.bottom = -3
|
|
||||||
directionalLight.shadow.bias = -0.0001 // Reduce shadow acne
|
|
||||||
|
|
||||||
scene.add(directionalLight)
|
|
||||||
scene.add(directionalLight.target)
|
|
||||||
|
|
||||||
// Cursor following function
|
|
||||||
const updatePlayerLookAt = () => {
|
|
||||||
if (!isFollowingCursor.current || !sceneRef.current?.playerObject) return
|
|
||||||
|
|
||||||
const { playerObject } = sceneRef.current
|
|
||||||
const { x, y } = cursorPosition.current
|
|
||||||
|
|
||||||
// Convert 0-1 cursor position to normalized coordinates (-1 to 1)
|
|
||||||
const normalizedX = x * 2 - 1
|
|
||||||
const normalizedY = y * 2 - 1 // Inverted: top of screen = negative pitch, bottom = positive pitch
|
|
||||||
|
|
||||||
// Calculate head rotation based on cursor position
|
|
||||||
// Limit head movement to realistic angles
|
|
||||||
const maxHeadYaw = Math.PI / 3 // 60 degrees
|
|
||||||
const maxHeadPitch = Math.PI / 4 // 45 degrees
|
|
||||||
|
|
||||||
const headYaw = normalizedX * maxHeadYaw
|
|
||||||
const headPitch = normalizedY * maxHeadPitch
|
|
||||||
|
|
||||||
// Apply head rotation with smooth interpolation
|
|
||||||
const lerpFactor = 0.1 // Smooth interpolation factor
|
|
||||||
playerObject.skin.head.rotation.y = THREE.MathUtils.lerp(
|
|
||||||
playerObject.skin.head.rotation.y,
|
|
||||||
headYaw,
|
|
||||||
lerpFactor
|
|
||||||
)
|
|
||||||
playerObject.skin.head.rotation.x = THREE.MathUtils.lerp(
|
|
||||||
playerObject.skin.head.rotation.x,
|
|
||||||
headPitch,
|
|
||||||
lerpFactor
|
|
||||||
)
|
|
||||||
|
|
||||||
// Apply slight body rotation for more natural movement
|
|
||||||
const bodyYaw = headYaw * 0.3 // Body follows head but with less rotation
|
|
||||||
playerObject.rotation.y = THREE.MathUtils.lerp(
|
|
||||||
playerObject.rotation.y,
|
|
||||||
bodyYaw,
|
|
||||||
lerpFactor * 0.5 // Slower body movement
|
|
||||||
)
|
|
||||||
|
|
||||||
render()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render function
|
|
||||||
const render = () => {
|
|
||||||
renderer.render(scene, camera)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup animation/render strategy
|
|
||||||
if (model.continiousRender) {
|
|
||||||
// Continuous animation loop
|
|
||||||
const animate = () => {
|
|
||||||
requestAnimationFrame(animate)
|
|
||||||
render()
|
|
||||||
}
|
|
||||||
animate()
|
|
||||||
} else {
|
|
||||||
// Render only on camera movement
|
|
||||||
controls.addEventListener('change', render)
|
|
||||||
// Initial render
|
|
||||||
render()
|
|
||||||
// Render after model loads
|
|
||||||
if (model.steveModelSkin !== undefined) {
|
|
||||||
// Create player model
|
|
||||||
const { playerObject, wrapper } = createPlayerObject({
|
|
||||||
scale: 1 // Start with base scale, will adjust below
|
|
||||||
})
|
|
||||||
|
|
||||||
// Enable shadows for player object
|
|
||||||
wrapper.traverse((child) => {
|
|
||||||
if (child instanceof THREE.Mesh) {
|
|
||||||
child.castShadow = true
|
|
||||||
child.receiveShadow = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Calculate proper scale and positioning for camera view
|
|
||||||
const box = new THREE.Box3().setFromObject(wrapper)
|
|
||||||
const size = box.getSize(new THREE.Vector3())
|
|
||||||
const center = box.getCenter(new THREE.Vector3())
|
|
||||||
|
|
||||||
// Calculate scale to fit within camera view (considering FOV and distance)
|
|
||||||
const cameraDistance = camera.position.z
|
|
||||||
const fov = camera.fov * Math.PI / 180 // Convert to radians
|
|
||||||
const visibleHeight = 2 * Math.tan(fov / 2) * cameraDistance
|
|
||||||
const visibleWidth = visibleHeight * (model.positioning.width / model.positioning.height)
|
|
||||||
|
|
||||||
const scaleFactor = Math.min(
|
|
||||||
(visibleHeight) / size.y,
|
|
||||||
(visibleWidth) / size.x
|
|
||||||
)
|
|
||||||
|
|
||||||
wrapper.scale.multiplyScalar(scaleFactor)
|
|
||||||
|
|
||||||
// Center the player object
|
|
||||||
wrapper.position.sub(center.multiplyScalar(scaleFactor))
|
|
||||||
|
|
||||||
// Rotate to face camera (remove the default 180° rotation)
|
|
||||||
wrapper.rotation.set(0, 0, 0)
|
|
||||||
|
|
||||||
scene.add(wrapper)
|
|
||||||
sceneRef.current = {
|
|
||||||
...sceneRef.current!,
|
|
||||||
playerObject
|
|
||||||
}
|
|
||||||
|
|
||||||
void applySkinToPlayerObject(playerObject, model.steveModelSkin).then(() => {
|
|
||||||
setTimeout(render, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Set up cursor following if enabled
|
|
||||||
if (model.positioning.followCursor) {
|
|
||||||
isFollowingCursor.current = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Window cursor tracking for followCursor
|
|
||||||
let lastCursorUpdate = 0
|
|
||||||
let waitingRender = false
|
|
||||||
const handleWindowPointerMove = (event: PointerEvent) => {
|
|
||||||
if (!model.positioning.followCursor) return
|
|
||||||
|
|
||||||
// Track cursor position as 0-1 across the entire window
|
|
||||||
const newPosition = {
|
|
||||||
x: event.clientX / window.innerWidth,
|
|
||||||
y: event.clientY / window.innerHeight
|
|
||||||
}
|
|
||||||
cursorPosition.current = newPosition
|
|
||||||
globalThis.cursorPosition = newPosition // Expose for debug
|
|
||||||
lastCursorUpdate = Date.now()
|
|
||||||
updatePlayerLookAt()
|
|
||||||
if (!waitingRender) {
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
render()
|
|
||||||
waitingRender = false
|
|
||||||
})
|
|
||||||
waitingRender = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add window event listeners
|
|
||||||
if (model.positioning.followCursor) {
|
|
||||||
window.addEventListener('pointermove', handleWindowPointerMove)
|
|
||||||
isFollowingCursor.current = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store refs for cleanup
|
|
||||||
sceneRef.current = {
|
|
||||||
...sceneRef.current!,
|
|
||||||
scene,
|
|
||||||
camera,
|
|
||||||
renderer,
|
|
||||||
controls,
|
|
||||||
dispose () {
|
|
||||||
if (!model.continiousRender) {
|
|
||||||
controls.removeEventListener('change', render)
|
|
||||||
}
|
|
||||||
if (model.positioning.followCursor) {
|
|
||||||
window.removeEventListener('pointermove', handleWindowPointerMove)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up loaded models
|
|
||||||
for (const [modelUrl, model] of loadedModels.current) {
|
|
||||||
scene.remove(model)
|
|
||||||
model.traverse((child) => {
|
|
||||||
if (child instanceof THREE.Mesh) {
|
|
||||||
if (child.material) {
|
|
||||||
if (Array.isArray(child.material)) {
|
|
||||||
for (const mat of child.material) {
|
|
||||||
mat.dispose()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
child.material.dispose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (child.geometry) {
|
|
||||||
child.geometry.dispose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
loadedModels.current.clear()
|
|
||||||
modelLoaders.current.clear()
|
|
||||||
|
|
||||||
const playerObject = sceneRef.current?.playerObject
|
|
||||||
if (playerObject?.skin.map) {
|
|
||||||
(playerObject.skin.map as unknown as THREE.Texture).dispose()
|
|
||||||
}
|
|
||||||
renderer.dispose()
|
|
||||||
renderer.domElement?.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
sceneRef.current?.dispose()
|
|
||||||
}
|
|
||||||
}, [model])
|
|
||||||
|
|
||||||
if (!model) return null
|
|
||||||
|
|
||||||
const { x, y, width, height, scaled, onlyInitialScale } = model.positioning
|
|
||||||
const { windowWidth } = model.positioning
|
|
||||||
const { windowHeight } = model.positioning
|
|
||||||
const scaleValue = onlyInitialScale ? initialScale : 'var(--guiScale)'
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className='overlay-model-viewer-container'
|
|
||||||
style={{
|
|
||||||
zIndex: 100,
|
|
||||||
position: 'fixed',
|
|
||||||
inset: 0,
|
|
||||||
width: '100dvw',
|
|
||||||
height: '100dvh',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
transform: scaled ? `scale(${scaleValue})` : 'none',
|
|
||||||
pointerEvents: 'none',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className='overlay-model-viewer-window'
|
|
||||||
style={{
|
|
||||||
width: windowWidth,
|
|
||||||
height: windowHeight,
|
|
||||||
position: 'relative',
|
|
||||||
pointerEvents: 'none',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
ref={containerRef}
|
|
||||||
className='overlay-model-viewer'
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
left: x,
|
|
||||||
top: y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
pointerEvents: 'auto',
|
|
||||||
backgroundColor: model.debug ? 'red' : undefined,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -119,7 +119,6 @@ const Inner = ({ hidden, customServersList }: { hidden?: boolean, customServersL
|
||||||
...serversListProvided,
|
...serversListProvided,
|
||||||
...(customServersList ? [] : (miscUiState.appConfig?.promoteServers ?? [])).map((server): StoreServerItem => ({
|
...(customServersList ? [] : (miscUiState.appConfig?.promoteServers ?? [])).map((server): StoreServerItem => ({
|
||||||
ip: server.ip,
|
ip: server.ip,
|
||||||
name: server.name,
|
|
||||||
versionOverride: server.version,
|
versionOverride: server.version,
|
||||||
description: server.description,
|
description: server.description,
|
||||||
isRecommended: true
|
isRecommended: true
|
||||||
|
|
@ -168,7 +167,6 @@ const Inner = ({ hidden, customServersList }: { hidden?: boolean, customServersL
|
||||||
console.log('pingResult.fullInfo.description', pingResult.fullInfo.description)
|
console.log('pingResult.fullInfo.description', pingResult.fullInfo.description)
|
||||||
data = {
|
data = {
|
||||||
formattedText: pingResult.fullInfo.description,
|
formattedText: pingResult.fullInfo.description,
|
||||||
icon: pingResult.fullInfo.favicon,
|
|
||||||
textNameRight: `ws ${pingResult.latency}ms`,
|
textNameRight: `ws ${pingResult.latency}ms`,
|
||||||
textNameRightGrayed: `${pingResult.fullInfo.players?.online ?? '??'}/${pingResult.fullInfo.players?.max ?? '??'}`,
|
textNameRightGrayed: `${pingResult.fullInfo.players?.online ?? '??'}/${pingResult.fullInfo.players?.max ?? '??'}`,
|
||||||
offline: false
|
offline: false
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,6 @@ import FullscreenTime from './react/FullscreenTime'
|
||||||
import StorageConflictModal from './react/StorageConflictModal'
|
import StorageConflictModal from './react/StorageConflictModal'
|
||||||
import FireRenderer from './react/FireRenderer'
|
import FireRenderer from './react/FireRenderer'
|
||||||
import MonacoEditor from './react/MonacoEditor'
|
import MonacoEditor from './react/MonacoEditor'
|
||||||
import OverlayModelViewer from './react/OverlayModelViewer'
|
|
||||||
|
|
||||||
const isFirefox = ua.getBrowser().name === 'Firefox'
|
const isFirefox = ua.getBrowser().name === 'Firefox'
|
||||||
if (isFirefox) {
|
if (isFirefox) {
|
||||||
|
|
@ -260,7 +259,6 @@ const App = () => {
|
||||||
</div>
|
</div>
|
||||||
<div />
|
<div />
|
||||||
<DebugEdges />
|
<DebugEdges />
|
||||||
<OverlayModelViewer />
|
|
||||||
<MonacoEditor />
|
<MonacoEditor />
|
||||||
<DebugResponseTimeIndicator />
|
<DebugResponseTimeIndicator />
|
||||||
</RobustPortal>
|
</RobustPortal>
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,6 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 12;
|
z-index: 12;
|
||||||
/* Account for GUI scaling */
|
|
||||||
width: calc(100dvw / var(--guiScale, 1));
|
|
||||||
height: calc(100dvh / var(--guiScale, 1));
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-content {
|
.screen-content {
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ class MusicSystem {
|
||||||
private currentMusic: string | null = null
|
private currentMusic: string | null = null
|
||||||
|
|
||||||
async playMusic (url: string, musicVolume = 1) {
|
async playMusic (url: string, musicVolume = 1) {
|
||||||
if (!options.enableMusic || this.currentMusic || options.musicVolume === 0) return
|
if (!options.enableMusic || this.currentMusic) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { onEnded } = await loadOrPlaySound(url, musicVolume, 5000, undefined, true) ?? {}
|
const { onEnded } = await loadOrPlaySound(url, 0.5 * musicVolume, 5000) ?? {}
|
||||||
|
|
||||||
if (!onEnded) return
|
if (!onEnded) return
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
import { subscribeKey } from 'valtio/utils'
|
import { subscribeKey } from 'valtio/utils'
|
||||||
import { isMobile } from 'renderer/viewer/lib/simpleUtils'
|
import { isMobile } from 'renderer/viewer/lib/simpleUtils'
|
||||||
import { WorldDataEmitter } from 'renderer/viewer/lib/worldDataEmitter'
|
import { WorldDataEmitter } from 'renderer/viewer/lib/worldDataEmitter'
|
||||||
import { setSkinsConfig } from 'renderer/viewer/lib/utils/skins'
|
|
||||||
import { options, watchValue } from './optionsStorage'
|
import { options, watchValue } from './optionsStorage'
|
||||||
import { reloadChunks } from './utils'
|
import { reloadChunks } from './utils'
|
||||||
import { miscUiState } from './globalState'
|
import { miscUiState } from './globalState'
|
||||||
|
|
@ -98,8 +97,6 @@ export const watchOptionsAfterViewerInit = () => {
|
||||||
appViewer.inWorldRenderingConfig.highlightBlockColor = o.highlightBlockColor
|
appViewer.inWorldRenderingConfig.highlightBlockColor = o.highlightBlockColor
|
||||||
appViewer.inWorldRenderingConfig._experimentalSmoothChunkLoading = o.rendererSharedOptions._experimentalSmoothChunkLoading
|
appViewer.inWorldRenderingConfig._experimentalSmoothChunkLoading = o.rendererSharedOptions._experimentalSmoothChunkLoading
|
||||||
appViewer.inWorldRenderingConfig._renderByChunks = o.rendererSharedOptions._renderByChunks
|
appViewer.inWorldRenderingConfig._renderByChunks = o.rendererSharedOptions._renderByChunks
|
||||||
|
|
||||||
setSkinsConfig({ apiEnabled: o.loadPlayerSkins })
|
|
||||||
})
|
})
|
||||||
|
|
||||||
appViewer.inWorldRenderingConfig.smoothLighting = options.smoothLighting
|
appViewer.inWorldRenderingConfig.smoothLighting = options.smoothLighting
|
||||||
|
|
@ -119,10 +116,6 @@ export const watchOptionsAfterViewerInit = () => {
|
||||||
appViewer.inWorldRenderingConfig.starfield = o.starfieldRendering
|
appViewer.inWorldRenderingConfig.starfield = o.starfieldRendering
|
||||||
})
|
})
|
||||||
|
|
||||||
watchValue(options, o => {
|
|
||||||
appViewer.inWorldRenderingConfig.defaultSkybox = o.defaultSkybox
|
|
||||||
})
|
|
||||||
|
|
||||||
watchValue(options, o => {
|
watchValue(options, o => {
|
||||||
// appViewer.inWorldRenderingConfig.neighborChunkUpdates = o.neighborChunkUpdates
|
// appViewer.inWorldRenderingConfig.neighborChunkUpdates = o.neighborChunkUpdates
|
||||||
})
|
})
|
||||||
|
|
@ -135,6 +128,5 @@ export const watchOptionsAfterWorldViewInit = (worldView: WorldDataEmitter) => {
|
||||||
appViewer.inWorldRenderingConfig.renderEars = o.renderEars
|
appViewer.inWorldRenderingConfig.renderEars = o.renderEars
|
||||||
appViewer.inWorldRenderingConfig.showHand = o.showHand
|
appViewer.inWorldRenderingConfig.showHand = o.showHand
|
||||||
appViewer.inWorldRenderingConfig.viewBobbing = o.viewBobbing
|
appViewer.inWorldRenderingConfig.viewBobbing = o.viewBobbing
|
||||||
appViewer.inWorldRenderingConfig.dayCycle = o.dayCycleAndLighting
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue