Merge branch 'master' into 1.13_assets
This commit is contained in:
commit
c0c940a4c2
|
@ -0,0 +1,20 @@
|
|||
image: ubuntu/latest
|
||||
packages:
|
||||
- curl
|
||||
- libegl1-mesa-dev
|
||||
- libgles2-mesa-dev
|
||||
- pkg-config
|
||||
- libssl-dev
|
||||
sources:
|
||||
- https://github.com/iceiix/stevenarella
|
||||
tasks:
|
||||
- setup: |
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh
|
||||
sh ./rustup.sh -y
|
||||
source $HOME/.cargo/env
|
||||
cargo --version
|
||||
- build: |
|
||||
source $HOME/.cargo/env
|
||||
cd stevenarella
|
||||
cargo build
|
||||
cargo test
|
|
@ -1,6 +1,11 @@
|
|||
# Rust
|
||||
target/
|
||||
**/*.rs.bk
|
||||
.rust/
|
||||
|
||||
working/
|
||||
*.log
|
||||
pkg
|
||||
|
||||
# IntelliJ
|
||||
.idea
|
||||
|
|
19
.travis.yml
19
.travis.yml
|
@ -3,13 +3,17 @@ sudo: required
|
|||
dist: trusty
|
||||
rust:
|
||||
- nightly
|
||||
- beta
|
||||
- stable
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
fast_finish: true
|
||||
cache: cargo
|
||||
include:
|
||||
- env: WASM=true
|
||||
- env: WASM=false
|
||||
cache:
|
||||
cargo: true
|
||||
timeout: 1000
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo chown root:wheel /usr/local/bin/brew ; fi
|
||||
|
@ -17,8 +21,15 @@ before_install:
|
|||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y gcc libegl1-mesa-dev libgles2-mesa-dev ; fi
|
||||
script:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/lib" ; fi
|
||||
- travis_wait 30 cargo build --verbose
|
||||
- cargo test --verbose
|
||||
- if [[ "$WASM" == "true" ]]; then
|
||||
rustup target add wasm32-unknown-unknown;
|
||||
cargo install wasm-bindgen-cli;
|
||||
cargo install wasm-pack;
|
||||
travis_wait 120 wasm-pack build;
|
||||
else
|
||||
travis_wait 30 cargo build --verbose;
|
||||
cargo test --verbose;
|
||||
fi
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
|
File diff suppressed because it is too large
Load Diff
58
Cargo.toml
58
Cargo.toml
|
@ -3,6 +3,13 @@ name = "stevenarella"
|
|||
version = "0.0.1"
|
||||
authors = [ "Thinkofdeath <thinkofdeath@spigotmc.org>", "iceiix <ice_ix@protonmail.ch>" ]
|
||||
edition = "2018"
|
||||
description = "Multi-protocol multi-platform Minecraft-compatible client"
|
||||
repository = "https://github.com/iceiix/stevenarella"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
path = "src/main.rs"
|
||||
|
||||
[profile.dev]
|
||||
# Steven runs horrendously slow with no optimizations, and often freezes.
|
||||
|
@ -11,28 +18,35 @@ edition = "2018"
|
|||
opt-level = 1
|
||||
|
||||
[dependencies]
|
||||
sha-1 = "0.8.1"
|
||||
glutin = "0.19.0"
|
||||
byteorder = "1.2.7"
|
||||
reqwest = "0.9.5"
|
||||
serde = "1.0.84"
|
||||
serde_json = "1.0.34"
|
||||
flate2 = "1.0.6"
|
||||
zip = "0.5.0"
|
||||
image = "0.20.1"
|
||||
rand = "0.5.5"
|
||||
hex = "0.3.2"
|
||||
base64 = "0.10.0"
|
||||
log = { version = "0.4.6", features = ["std"] }
|
||||
cgmath = "0.16.1"
|
||||
lazy_static = "1.2.0"
|
||||
collision = "0.18.0"
|
||||
aes = "0.3.2"
|
||||
cfb8 = "0.3.1"
|
||||
cfg-if = "0.1.9"
|
||||
wasm-bindgen = "0.2.44"
|
||||
sha-1 = "0.8.2"
|
||||
glutin = "0.22.0"
|
||||
byteorder = "1.3.4"
|
||||
serde = "1.0.104"
|
||||
serde_json = "1.0.55"
|
||||
flate2 = { version = "1.0.14", features = ["rust_backend"], default-features = false }
|
||||
zip = { version = "0.5.6", features = ["deflate"], default-features = false }
|
||||
image = "0.23.6"
|
||||
rand = "0.7.3"
|
||||
rand_pcg = "0.2.1"
|
||||
base64 = "0.12.2"
|
||||
log = { version = "0.4.8", features = ["std"] }
|
||||
cgmath = "0.17.0"
|
||||
lazy_static = "1.4.0"
|
||||
collision = "0.20.1"
|
||||
rsa_public_encrypt_pkcs1 = "0.2.0"
|
||||
structopt = "0.3.15"
|
||||
clipboard = "0.5.0"
|
||||
# clippy = "*"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
reqwest = { version = "0.10.6", features = [ "blocking" ]}
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
stdweb = "0.4.20"
|
||||
winit = { version = "0.20.0", features = [ "stdweb" ]}
|
||||
|
||||
[dependencies.steven_gl]
|
||||
path = "./gl"
|
||||
version = "0"
|
||||
|
@ -48,3 +62,11 @@ version = "0"
|
|||
[dependencies.steven_shared]
|
||||
path = "./shared"
|
||||
version = "0"
|
||||
|
||||
[dependencies.steven_protocol]
|
||||
path = "./protocol"
|
||||
version = "0"
|
||||
|
||||
[dependencies.std_or_web]
|
||||
path = "./std_or_web"
|
||||
version = "0"
|
||||
|
|
58
README.md
58
README.md
|
@ -1,5 +1,5 @@
|
|||
# Stevenarella
|
||||
[![Build Status](https://travis-ci.org/iceiix/stevenarella.svg)](https://travis-ci.org/iceiix/stevenarella)
|
||||
[![builds.sr.ht status](https://builds.sr.ht/~iceiix/stevenarella.svg)](https://builds.sr.ht/~iceiix/stevenarella?)
|
||||
|
||||
Multi-protocol Minecraft-compatible client written in Rust
|
||||
|
||||
|
@ -13,10 +13,22 @@ Don't expect it to go anywhere, just doing this for fun.
|
|||
|
||||
In action: http://gfycat.com/NeedyElaborateGypsymoth
|
||||
|
||||
## Community chatroom
|
||||
|
||||
We have a chatroom on [EsperNet](https://esper.net): `irc.esper.net` server, `#stevenarella` channel.
|
||||
|
||||
Join with your favorite IRC client or [Matrix](https://matrix.to/#/#_espernet_#stevenarella:matrix.org).
|
||||
|
||||
## Protocol support
|
||||
|
||||
| Game version | Protocol version | Supported? |
|
||||
| ------ | --- | --- |
|
||||
| 1.15.1 | 575 | ✓ |
|
||||
| 1.14.4 | 498 | ✓ |
|
||||
| 1.14.3 | 490 | ✓ |
|
||||
| 1.14.2 | 485 | ✓ |
|
||||
| 1.14.1 | 480 | ✓ |
|
||||
| 1.14 | 477 | ✓ |
|
||||
| 19w02a | 452 | ✓ |
|
||||
| 18w50a | 451 | ✓ |
|
||||
| 1.13.2 | 404 | ✓ |
|
||||
|
@ -35,14 +47,10 @@ development is not in lock-step with the server version. The level of
|
|||
support varies, but the goal is to support major versions from 1.7.10
|
||||
up to the current latest major version. Occasionally, snapshots are also supported.
|
||||
|
||||
Forge servers are currently supported on 1.7.10 - 1.12.2.
|
||||
|
||||
Support for older protocols will _not_ be dropped as newer protocols are added.
|
||||
|
||||
## Credits
|
||||
|
||||
Thanks to [@thinkofname](https://github.com/thinkofname/) for
|
||||
the original [Steven (Rust)](https://github.com/thinkofname/steven),
|
||||
which Stevenarella is an updated and enhanced version of.
|
||||
|
||||
## Downloads
|
||||
|
||||
Windows users can download pre-compiled builds from here: https://ci.appveyor.com/project/iceiix/stevenarella
|
||||
|
@ -52,7 +60,7 @@ The Visual Studio 2017 Redistributable is required to run these builds.
|
|||
|
||||
## Building
|
||||
|
||||
Requires Rust stable version 1.31.0 or newer to build.
|
||||
Requires Rust stable version 1.44.1 or newer to build.
|
||||
|
||||
Compile and run:
|
||||
```bash
|
||||
|
@ -63,6 +71,8 @@ Just compile:
|
|||
cargo build --release
|
||||
```
|
||||
|
||||
For progress on web support, see [www/](./www).
|
||||
|
||||
## Running
|
||||
|
||||
### Standalone
|
||||
|
@ -71,6 +81,36 @@ Just running Stevenarella via a double click (Windows) or `./stevenarella` (ever
|
|||
will bring up a login screen followed by a server list which you can select a server
|
||||
from.
|
||||
|
||||
## License
|
||||
## Contributions
|
||||
|
||||
Stevenarella is an [OPEN Open Source Project](https://github.com/openopensource/openopensource.github.io):
|
||||
|
||||
> Individuals making significant and valuable contributions are given
|
||||
> commit-access to the project to contribute as they see fit. This project
|
||||
> is more like an open wiki than a standard guarded open source project.
|
||||
|
||||
### Rules
|
||||
|
||||
There are a few basic ground-rules for contributors:
|
||||
|
||||
1. **No `--force` pushes** or modifying the Git history on the `master` branch.
|
||||
1. **Non-master branches** ought to be used for ongoing work.
|
||||
1. **External API changes and significant modifications** ought to be subject to an **internal pull-request** to solicit feedback from other contributors.
|
||||
1. Internal pull-requests to solicit feedback are *encouraged* for any other non-trivial contribution but left to the discretion of the contributor.
|
||||
1. Contributors should attempt to adhere to the prevailing code-style. Please install and run [cargo fmt](https://github.com/rust-lang/rustfmt) before merging any changes.
|
||||
|
||||
### Changes to this arrangement
|
||||
|
||||
This is an experiment and feedback is welcome! This document may also be
|
||||
subject to pull-requests or changes by contributors where you believe
|
||||
you have something valuable to add or change.
|
||||
|
||||
### Credits
|
||||
|
||||
Thanks to [@thinkofname](https://github.com/thinkofname/) for
|
||||
the original [Steven (Rust)](https://github.com/thinkofname/steven),
|
||||
which Stevenarella is an updated and enhanced version of.
|
||||
|
||||
### License
|
||||
|
||||
Dual-licensed MIT and ApacheV2
|
||||
|
|
|
@ -4,7 +4,7 @@ clone_depth: 1
|
|||
skip_branch_with_pr: true
|
||||
branches:
|
||||
only:
|
||||
- updates
|
||||
- master
|
||||
platform:
|
||||
- x64
|
||||
build_script:
|
||||
|
@ -21,7 +21,7 @@ build_script:
|
|||
|
||||
appveyor AddMessage "Platform rust: %RUST_INSTALL%"
|
||||
|
||||
appveyor DownloadFile "https://static.rust-lang.org/dist/rust-1.31.0-%RUST_INSTALL%.exe" -FileName rust-install.exe
|
||||
appveyor DownloadFile "https://static.rust-lang.org/dist/rust-1.44.1-%RUST_INSTALL%.exe" -FileName rust-install.exe
|
||||
|
||||
"./rust-install.exe" /VERYSILENT /NORESTART /DIR="C:\Rust\"
|
||||
|
||||
|
|
|
@ -1,168 +1,314 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "approx"
|
||||
version = "0.1.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.4"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cgmath"
|
||||
version = "0.16.1"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "collision"
|
||||
version = "0.18.0"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.2.0"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.9"
|
||||
version = "0.2.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.1.31"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-bigint 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-bigint 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.43"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.24"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.10"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.14"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.3"
|
||||
name = "rand_chacha"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.3.18"
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_isaac"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_jitter"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_os"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_xorshift"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.82"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.82"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.6.7"
|
||||
version = "0.6.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "steven_blocks"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"collision 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"collision 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"steven_shared 0.0.1",
|
||||
]
|
||||
|
||||
|
@ -172,35 +318,22 @@ version = "0.0.1"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.23"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -218,31 +351,43 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94"
|
||||
"checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a"
|
||||
"checksum bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4440d5cb623bb7390ae27fec0bb6c61111969860f8e3ae198bfa0663645e67cf"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c"
|
||||
"checksum collision 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "928b2092661bb4cd6f5e5a39c639ac6553a1e69750fab6de2edb86e2304f9eaa"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "95ca44454e7cfe7f8a2095a41a10c79d96a177c0b1672cbf1a30d901a9c16ee5"
|
||||
"checksum num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "be45b3e341522564415a07118d7cf44896d0919e7a1bb21d59ad82af48256324"
|
||||
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
|
||||
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
|
||||
"checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5"
|
||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||
"checksum rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "9cf81518cd579f8a9c58c0a71328bdb9be15c754181261da82583092dc8a7ff0"
|
||||
"checksum serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)" = "6fa52f19aee12441d5ad11c9a00459122bd8f98707cadf9778c540674f1935b6"
|
||||
"checksum serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)" = "96a7f9496ac65a2db5929afa087b54f8fc5008dcfbe48a8874ed20049b0d6154"
|
||||
"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db"
|
||||
"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3"
|
||||
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||
"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
|
||||
"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "283944cdecc44bf0b8dd010ec9af888d3b4f142844fdbe026c20ef68148d6fe7"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum collision 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6107f6be76c2269a9c8d89e707a66122bd3086f987fa508133a5f774e8ac4ced"
|
||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
"checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db"
|
||||
"checksum num-bigint 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "343b3df15c945a59e72aae31e89a7cfc9e11850e96d4fde6fed5e3c7c8d9c887"
|
||||
"checksum num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc"
|
||||
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
|
||||
"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e"
|
||||
"checksum num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454"
|
||||
"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
|
||||
"checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc"
|
||||
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
||||
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
||||
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
|
||||
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
|
||||
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
|
||||
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
|
||||
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
|
||||
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
|
||||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
||||
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
|
||||
"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
|
||||
"checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8"
|
||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
|
|
@ -5,9 +5,9 @@ authors = [ "Thinkofdeath <thinkofdeath@spigotmc.org>" ]
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1.1.0"
|
||||
cgmath = "0.16.1"
|
||||
collision = "0.18.0"
|
||||
lazy_static = "1.4.0"
|
||||
cgmath = "0.17.0"
|
||||
collision = "0.20.1"
|
||||
|
||||
|
||||
[dependencies.steven_shared]
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,3 @@
|
|||
|
||||
pub struct Material {
|
||||
pub renderable: bool,
|
||||
pub should_cull_against: bool,
|
||||
|
|
|
@ -1,50 +1,56 @@
|
|||
[root]
|
||||
name = "steven_gl"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"gl_generator 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.3.3"
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "gl_generator"
|
||||
version = "0.4.2"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xml-rs 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "khronos_api"
|
||||
version = "1.0.0"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.8"
|
||||
version = "0.2.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.5"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "steven_gl"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"gl_generator 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.2.2"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum gl_generator 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
|
||||
"checksum khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5"
|
||||
|
|
|
@ -6,8 +6,8 @@ edition = "2018"
|
|||
build = "build.rs"
|
||||
|
||||
[build-dependencies]
|
||||
gl_generator = "0.9.0"
|
||||
khronos_api = "2.2.0"
|
||||
gl_generator = "0.14.0"
|
||||
khronos_api = "3.1.0"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
libc = "0.2.66"
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
use gl_generator::{Api, Fallbacks, GlobalGenerator, Profile, Registry};
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::BufWriter;
|
||||
use std::path::Path;
|
||||
use gl_generator::{Registry, Api, Profile, Fallbacks, GlobalGenerator};
|
||||
|
||||
fn main() {
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
let dest = Path::new(&out_dir);
|
||||
|
||||
let mut file = BufWriter::new(File::create(&dest.join("bindings.rs")).unwrap());
|
||||
Registry::new(Api::Gl,
|
||||
(3, 2),
|
||||
Profile::Core,
|
||||
Fallbacks::All,
|
||||
[])
|
||||
Registry::new(Api::Gl, (3, 2), Profile::Core, Fallbacks::All, [])
|
||||
.write_bindings(GlobalGenerator, &mut file)
|
||||
.unwrap();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
[package]
|
||||
name = "steven_protocol"
|
||||
version = "0.0.1"
|
||||
authors = [ "Thinkofdeath <thinkofdeath@spigotmc.org>", "iceiix <ice_ix@protonmail.ch>" ]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
serde = "1.0.104"
|
||||
serde_json = "1.0.55"
|
||||
hex = "0.4.0"
|
||||
sha-1 = "0.8.2"
|
||||
aes = "0.3.2"
|
||||
cfb8 = "0.3.2"
|
||||
byteorder = "1.3.4"
|
||||
log = { version = "0.4.8", features = ["std"] }
|
||||
flate2 = { version = "1.0.14", features = ["rust_backend"], default-features = false }
|
||||
num-traits = "0.2.10"
|
||||
|
||||
[dependencies.steven_shared]
|
||||
path = "../shared"
|
||||
version = "0"
|
||||
|
||||
[dependencies.std_or_web]
|
||||
path = "../std_or_web"
|
||||
version = "0"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
reqwest = { version = "0.10.6", features = [ "blocking" ]}
|
|
@ -22,7 +22,6 @@ pub enum Component {
|
|||
}
|
||||
|
||||
impl Component {
|
||||
|
||||
pub fn from_string(str: &str) -> Self {
|
||||
let mut component;
|
||||
match serde_json::from_str::<serde_json::Value>(str) {
|
||||
|
@ -31,7 +30,7 @@ impl Component {
|
|||
Err(_) => {
|
||||
component = Component::Text(TextComponent::new(str));
|
||||
convert_legacy(&mut component);
|
||||
},
|
||||
}
|
||||
}
|
||||
component
|
||||
}
|
||||
|
@ -47,7 +46,9 @@ impl Component {
|
|||
Component::Text(TextComponent::from_value(v, modifier))
|
||||
} else if v.get("translate").is_some() {
|
||||
// TODO: translations
|
||||
Component::Text(TextComponent::new(v.get("translate").unwrap().as_str().unwrap()))
|
||||
Component::Text(TextComponent::new(
|
||||
v.get("translate").unwrap().as_str().unwrap(),
|
||||
))
|
||||
} else {
|
||||
modifier.color = Some(Color::RGB(255, 0, 0));
|
||||
Component::Text(TextComponent {
|
||||
|
@ -100,9 +101,10 @@ impl Modifier {
|
|||
underlined: v.get("underlined").map_or(Option::None, |v| v.as_bool()),
|
||||
strikethrough: v.get("strikethrough").map_or(Option::None, |v| v.as_bool()),
|
||||
obfuscated: v.get("obfuscated").map_or(Option::None, |v| v.as_bool()),
|
||||
color: v.get("color")
|
||||
.map_or(Option::None, |v| v.as_str())
|
||||
.map(|v| Color::from_string(&v.to_owned())),
|
||||
color: v
|
||||
.get("color")
|
||||
.map_or(Option::None, |v| v.as_str())
|
||||
.map(|v| Color::from_string(&v.to_owned())),
|
||||
extra: Option::None,
|
||||
};
|
||||
if let Some(extra) = v.get("extra") {
|
||||
|
@ -132,7 +134,9 @@ impl TextComponent {
|
|||
pub fn new(val: &str) -> TextComponent {
|
||||
TextComponent {
|
||||
text: val.to_owned(),
|
||||
modifier: Modifier { ..Default::default() },
|
||||
modifier: Modifier {
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,8 +323,9 @@ pub fn convert_legacy(c: &mut Component) {
|
|||
current.text = txt.text[last..i].to_owned();
|
||||
last = next.0 + 1;
|
||||
|
||||
let mut modifier = if (color_char >= 'a' && color_char <= 'f') ||
|
||||
(color_char >= '0' && color_char <= '9') {
|
||||
let mut modifier = if (color_char >= 'a' && color_char <= 'f')
|
||||
|| (color_char >= '0' && color_char <= '9')
|
||||
{
|
||||
Default::default()
|
||||
} else {
|
||||
current.modifier.clone()
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
use crate::nbt;
|
||||
use crate::protocol::{self, Serializable};
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use std::io;
|
||||
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Stack {
|
||||
|
@ -25,7 +25,6 @@ pub struct Stack {
|
|||
tag: Option<nbt::NamedTag>,
|
||||
}
|
||||
|
||||
|
||||
impl Default for Stack {
|
||||
fn default() -> Stack {
|
||||
Stack {
|
||||
|
@ -39,12 +38,12 @@ impl Default for Stack {
|
|||
|
||||
impl Serializable for Option<Stack> {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Option<Stack>, protocol::Error> {
|
||||
let protocol_version = unsafe { protocol::CURRENT_PROTOCOL_VERSION };
|
||||
let protocol_version = protocol::current_protocol_version();
|
||||
|
||||
if protocol_version >= 404 {
|
||||
let present = buf.read_u8()? != 0;
|
||||
if !present {
|
||||
return Ok(None)
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#![recursion_limit = "300"]
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
|
||||
pub mod format;
|
||||
pub mod item;
|
||||
pub mod nbt;
|
||||
pub mod protocol;
|
||||
pub mod types;
|
||||
|
||||
use steven_shared as shared;
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! create_ids {
|
|
@ -16,9 +16,9 @@ use std::collections::HashMap;
|
|||
use std::io;
|
||||
use std::io::Read;
|
||||
|
||||
use super::protocol::Serializable;
|
||||
use super::protocol;
|
||||
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
||||
use super::protocol::Serializable;
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Tag {
|
||||
|
@ -41,7 +41,6 @@ pub enum Tag {
|
|||
pub struct NamedTag(pub String, pub Tag);
|
||||
|
||||
impl Tag {
|
||||
|
||||
pub fn new_compound() -> Tag {
|
||||
Tag::Compound(HashMap::new())
|
||||
}
|
||||
|
@ -163,7 +162,6 @@ impl Tag {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
fn internal_id(&self) -> u8 {
|
||||
match *self {
|
||||
Tag::End => 0,
|
||||
|
@ -304,7 +302,8 @@ pub fn write_string<W: io::Write>(buf: &mut W, s: &str) -> Result<(), protocol::
|
|||
|
||||
pub fn read_string<R: io::Read>(buf: &mut R) -> Result<String, protocol::Error> {
|
||||
let len: i16 = buf.read_i16::<BigEndian>()?;
|
||||
let mut ret = String::new();
|
||||
buf.take(len as u64).read_to_string(&mut ret)?;
|
||||
let mut bytes = Vec::<u8>::new();
|
||||
buf.take(len as u64).read_to_end(&mut bytes)?;
|
||||
let ret = String::from_utf8(bytes).unwrap();
|
||||
Result::Ok(ret)
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
use byteorder::WriteBytesExt;
|
||||
use log::debug;
|
||||
/// Implements https://wiki.vg/Minecraft_Forge_Handshake
|
||||
use std::io;
|
||||
|
||||
use super::{Error, LenPrefixed, Serializable, VarInt};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Phase {
|
||||
// Client handshake states (written)
|
||||
Start,
|
||||
WaitingServerData,
|
||||
WaitingServerComplete,
|
||||
PendingComplete,
|
||||
|
||||
// Server handshake states (read)
|
||||
WaitingCAck,
|
||||
|
||||
// Both client and server handshake states (different values on the wire)
|
||||
Complete,
|
||||
}
|
||||
|
||||
impl Serializable for Phase {
|
||||
/// Read server handshake state from server
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
let phase: i8 = Serializable::read_from(buf)?;
|
||||
Ok(match phase {
|
||||
2 => Phase::WaitingCAck,
|
||||
3 => Phase::Complete,
|
||||
_ => panic!("bad FML|HS server phase: {}", phase),
|
||||
})
|
||||
}
|
||||
|
||||
/// Send client handshake state from client
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
buf.write_u8(match self {
|
||||
Phase::WaitingServerData => 2,
|
||||
Phase::WaitingServerComplete => 3,
|
||||
Phase::PendingComplete => 4,
|
||||
Phase::Complete => 5,
|
||||
_ => panic!("bad FML|HS client phase: {:?}", self),
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ForgeMod {
|
||||
pub modid: String,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
impl Serializable for ForgeMod {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
Ok(ForgeMod {
|
||||
modid: Serializable::read_from(buf)?,
|
||||
version: Serializable::read_from(buf)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
self.modid.write_to(buf)?;
|
||||
self.version.write_to(buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ModIdMapping {
|
||||
pub name: String,
|
||||
pub id: VarInt,
|
||||
}
|
||||
|
||||
impl Serializable for ModIdMapping {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
Ok(ModIdMapping {
|
||||
name: Serializable::read_from(buf)?,
|
||||
id: Serializable::read_from(buf)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
self.name.write_to(buf)?;
|
||||
self.id.write_to(buf)
|
||||
}
|
||||
}
|
||||
|
||||
pub static BLOCK_NAMESPACE: &'static str = "\u{1}";
|
||||
pub static ITEM_NAMESPACE: &'static str = "\u{2}";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FmlHs {
|
||||
ServerHello {
|
||||
fml_protocol_version: i8,
|
||||
override_dimension: Option<i32>,
|
||||
},
|
||||
ClientHello {
|
||||
fml_protocol_version: i8,
|
||||
},
|
||||
ModList {
|
||||
mods: LenPrefixed<VarInt, ForgeMod>,
|
||||
},
|
||||
RegistryData {
|
||||
has_more: bool,
|
||||
name: String,
|
||||
ids: LenPrefixed<VarInt, ModIdMapping>,
|
||||
substitutions: LenPrefixed<VarInt, String>,
|
||||
dummies: LenPrefixed<VarInt, String>,
|
||||
},
|
||||
ModIdData {
|
||||
mappings: LenPrefixed<VarInt, ModIdMapping>,
|
||||
block_substitutions: LenPrefixed<VarInt, String>,
|
||||
item_substitutions: LenPrefixed<VarInt, String>,
|
||||
},
|
||||
HandshakeAck {
|
||||
phase: Phase,
|
||||
},
|
||||
HandshakeReset,
|
||||
}
|
||||
|
||||
impl Serializable for FmlHs {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
let discriminator: u8 = Serializable::read_from(buf)?;
|
||||
|
||||
match discriminator {
|
||||
0 => {
|
||||
let fml_protocol_version: i8 = Serializable::read_from(buf)?;
|
||||
let override_dimension = if fml_protocol_version > 1 {
|
||||
let dimension: i32 = Serializable::read_from(buf)?;
|
||||
Some(dimension)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
debug!(
|
||||
"FML|HS ServerHello: fml_protocol_version={}, override_dimension={:?}",
|
||||
fml_protocol_version, override_dimension
|
||||
);
|
||||
|
||||
Ok(FmlHs::ServerHello {
|
||||
fml_protocol_version,
|
||||
override_dimension,
|
||||
})
|
||||
}
|
||||
1 => panic!("Received unexpected FML|HS ClientHello from server"),
|
||||
2 => Ok(FmlHs::ModList {
|
||||
mods: Serializable::read_from(buf)?,
|
||||
}),
|
||||
3 => {
|
||||
let protocol_version = super::current_protocol_version();
|
||||
|
||||
if protocol_version >= 47 {
|
||||
Ok(FmlHs::RegistryData {
|
||||
has_more: Serializable::read_from(buf)?,
|
||||
name: Serializable::read_from(buf)?,
|
||||
ids: Serializable::read_from(buf)?,
|
||||
substitutions: Serializable::read_from(buf)?,
|
||||
dummies: Serializable::read_from(buf)?,
|
||||
})
|
||||
} else {
|
||||
Ok(FmlHs::ModIdData {
|
||||
mappings: Serializable::read_from(buf)?,
|
||||
block_substitutions: Serializable::read_from(buf)?,
|
||||
item_substitutions: Serializable::read_from(buf)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
255 => Ok(FmlHs::HandshakeAck {
|
||||
phase: Serializable::read_from(buf)?,
|
||||
}),
|
||||
_ => panic!("Unhandled FML|HS packet: discriminator={}", discriminator),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
match self {
|
||||
FmlHs::ClientHello {
|
||||
fml_protocol_version,
|
||||
} => {
|
||||
buf.write_u8(1)?;
|
||||
fml_protocol_version.write_to(buf)
|
||||
}
|
||||
FmlHs::ModList { mods } => {
|
||||
buf.write_u8(2)?;
|
||||
mods.write_to(buf)
|
||||
}
|
||||
FmlHs::HandshakeAck { phase } => {
|
||||
buf.write_u8(255)?;
|
||||
phase.write_to(buf)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,31 +16,51 @@
|
|||
#![allow(non_camel_case_types)]
|
||||
|
||||
use aes::Aes128;
|
||||
use cfb8::Cfb8;
|
||||
use cfb8::stream_cipher::{NewStreamCipher, StreamCipher};
|
||||
use serde_json;
|
||||
use cfb8::Cfb8;
|
||||
use hex;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use reqwest;
|
||||
use serde_json;
|
||||
use std_or_web::fs;
|
||||
|
||||
pub mod forge;
|
||||
pub mod mojang;
|
||||
|
||||
use crate::nbt;
|
||||
use crate::format;
|
||||
use std::fmt;
|
||||
use std::default;
|
||||
use std::net::TcpStream;
|
||||
use std::io;
|
||||
use std::io::{Write, Read};
|
||||
use std::convert;
|
||||
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
|
||||
use crate::nbt;
|
||||
use crate::shared::Position;
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use flate2::read::{ZlibDecoder, ZlibEncoder};
|
||||
use flate2::Compression;
|
||||
use std::time::{Instant, Duration};
|
||||
use crate::shared::Position;
|
||||
use log::debug;
|
||||
use std::convert;
|
||||
use std::default;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::io::{Read, Write};
|
||||
use std::net::TcpStream;
|
||||
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
pub const SUPPORTED_PROTOCOLS: [i32; 12] = [404, 451, 452, 340, 316, 315, 210, 109, 107, 74, 47, 5];
|
||||
pub const SUPPORTED_PROTOCOLS: [i32; 18] = [
|
||||
575, 498, 490, 485, 480, 477, 452, 451, 404, 340, 316, 315, 210, 109, 107, 74, 47, 5,
|
||||
];
|
||||
|
||||
// TODO: switch to using thread_local storage?, see https://doc.rust-lang.org/std/macro.thread_local.html
|
||||
pub static mut CURRENT_PROTOCOL_VERSION: i32 = SUPPORTED_PROTOCOLS[0];
|
||||
static CURRENT_PROTOCOL_VERSION: AtomicI32 = AtomicI32::new(SUPPORTED_PROTOCOLS[0]);
|
||||
static NETWORK_DEBUG: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub fn current_protocol_version() -> i32 {
|
||||
CURRENT_PROTOCOL_VERSION.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn enable_network_debug() {
|
||||
NETWORK_DEBUG.store(true, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn is_network_debug() -> bool {
|
||||
NETWORK_DEBUG.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Helper macro for defining packets
|
||||
#[macro_export]
|
||||
|
@ -215,7 +235,7 @@ impl Serializable for Vec<u8> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serializable for Option<nbt::NamedTag>{
|
||||
impl Serializable for Option<nbt::NamedTag> {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Option<nbt::NamedTag>, Error> {
|
||||
let ty = buf.read_u8()?;
|
||||
if ty == 0 {
|
||||
|
@ -239,7 +259,10 @@ impl Serializable for Option<nbt::NamedTag>{
|
|||
}
|
||||
}
|
||||
|
||||
impl <T> Serializable for Option<T> where T : Serializable {
|
||||
impl<T> Serializable for Option<T>
|
||||
where
|
||||
T: Serializable,
|
||||
{
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Option<T>, Error> {
|
||||
Result::Ok(Some(T::read_from(buf)?))
|
||||
}
|
||||
|
@ -256,8 +279,9 @@ impl Serializable for String {
|
|||
let len = VarInt::read_from(buf)?.0;
|
||||
debug_assert!(len >= 0, "Negative string length: {}", len);
|
||||
debug_assert!(len <= 65536, "String length too big: {}", len);
|
||||
let mut ret = String::new();
|
||||
buf.take(len as u64).read_to_string(&mut ret)?;
|
||||
let mut bytes = Vec::<u8>::new();
|
||||
buf.take(len as u64).read_to_end(&mut bytes)?;
|
||||
let ret = String::from_utf8(bytes).unwrap();
|
||||
Result::Ok(ret)
|
||||
}
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
|
@ -271,10 +295,10 @@ impl Serializable for String {
|
|||
impl Serializable for format::Component {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
let len = VarInt::read_from(buf)?.0;
|
||||
let mut ret = String::new();
|
||||
buf.take(len as u64).read_to_string(&mut ret)?;
|
||||
let val: serde_json::Value = serde_json::from_str(&ret[..]).unwrap();
|
||||
Result::Ok(Self::from_value(&val))
|
||||
let mut bytes = Vec::<u8>::new();
|
||||
buf.take(len as u64).read_to_end(&mut bytes)?;
|
||||
let ret = String::from_utf8(bytes).unwrap();
|
||||
Result::Ok(Self::from_string(&ret[..]))
|
||||
}
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
let val = serde_json::to_string(&self.to_value()).unwrap();
|
||||
|
@ -299,11 +323,7 @@ impl Serializable for bool {
|
|||
Result::Ok(buf.read_u8()? != 0)
|
||||
}
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
buf.write_u8(if *self {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
})?;
|
||||
buf.write_u8(if *self { 1 } else { 0 })?;
|
||||
Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -403,7 +423,6 @@ pub struct UUID(u64, u64);
|
|||
|
||||
impl UUID {
|
||||
pub fn from_str(s: &str) -> UUID {
|
||||
use hex;
|
||||
// TODO: Panics aren't the best idea here
|
||||
if s.len() != 36 {
|
||||
panic!("Invalid UUID format");
|
||||
|
@ -415,9 +434,9 @@ impl UUID {
|
|||
parts.extend_from_slice(&hex::decode(&s[24..36]).unwrap());
|
||||
let mut high = 0u64;
|
||||
let mut low = 0u64;
|
||||
for i in 0 .. 8 {
|
||||
high |= (parts[i] as u64) << (56 - i*8);
|
||||
low |= (parts[i + 8] as u64) << (56 - i*8);
|
||||
for i in 0..8 {
|
||||
high |= (parts[i] as u64) << (56 - i * 8);
|
||||
low |= (parts[i + 8] as u64) << (56 - i * 8);
|
||||
}
|
||||
UUID(high, low)
|
||||
}
|
||||
|
@ -431,8 +450,10 @@ impl Default for UUID {
|
|||
|
||||
impl Serializable for UUID {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<UUID, Error> {
|
||||
Result::Ok(UUID(buf.read_u64::<BigEndian>()?,
|
||||
buf.read_u64::<BigEndian>()?))
|
||||
Result::Ok(UUID(
|
||||
buf.read_u64::<BigEndian>()?,
|
||||
buf.read_u64::<BigEndian>()?,
|
||||
))
|
||||
}
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
buf.write_u64::<BigEndian>(self.0)?;
|
||||
|
@ -441,10 +462,46 @@ impl Serializable for UUID {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Biomes3D {
|
||||
pub data: [i32; 1024],
|
||||
}
|
||||
|
||||
pub trait Lengthable : Serializable + Copy + Default {
|
||||
fn into(self) -> usize;
|
||||
fn from(_: usize) -> Self;
|
||||
impl fmt::Debug for Biomes3D {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Biomes3D(")?;
|
||||
for i in 0..1024 {
|
||||
write!(f, "{}, ", self.data[i])?;
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Biomes3D {
|
||||
fn default() -> Self {
|
||||
Biomes3D { data: [0; 1024] }
|
||||
}
|
||||
}
|
||||
|
||||
impl Serializable for Biomes3D {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Biomes3D, Error> {
|
||||
let mut data: [i32; 1024] = [0; 1024];
|
||||
|
||||
// Non-length-prefixed three-dimensional biome data
|
||||
for i in 0..1024 {
|
||||
let b: i32 = Serializable::read_from(buf)?;
|
||||
data[i] = b;
|
||||
}
|
||||
|
||||
Result::Ok(Biomes3D { data })
|
||||
}
|
||||
fn write_to<W: io::Write>(&self, _buf: &mut W) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Lengthable: Serializable + Copy + Default {
|
||||
fn into_len(self) -> usize;
|
||||
fn from_len(_: usize) -> Self;
|
||||
}
|
||||
|
||||
pub struct LenPrefixed<L: Lengthable, V> {
|
||||
|
@ -452,7 +509,7 @@ pub struct LenPrefixed<L: Lengthable, V> {
|
|||
pub data: Vec<V>,
|
||||
}
|
||||
|
||||
impl <L: Lengthable, V: Default> LenPrefixed<L, V> {
|
||||
impl<L: Lengthable, V: Default> LenPrefixed<L, V> {
|
||||
pub fn new(data: Vec<V>) -> LenPrefixed<L, V> {
|
||||
LenPrefixed {
|
||||
len: Default::default(),
|
||||
|
@ -461,10 +518,10 @@ impl <L: Lengthable, V: Default> LenPrefixed<L, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl <L: Lengthable, V: Serializable> Serializable for LenPrefixed<L, V> {
|
||||
impl<L: Lengthable, V: Serializable> Serializable for LenPrefixed<L, V> {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<LenPrefixed<L, V>, Error> {
|
||||
let len_data: L = Serializable::read_from(buf)?;
|
||||
let len: usize = len_data.into();
|
||||
let len: usize = len_data.into_len();
|
||||
let mut data: Vec<V> = Vec::with_capacity(len);
|
||||
for _ in 0..len {
|
||||
data.push(Serializable::read_from(buf)?);
|
||||
|
@ -476,7 +533,7 @@ impl <L: Lengthable, V: Serializable> Serializable for LenPrefixed<L, V> {
|
|||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
let len_data: L = L::from(self.data.len());
|
||||
let len_data: L = L::from_len(self.data.len());
|
||||
len_data.write_to(buf)?;
|
||||
let data = &self.data;
|
||||
for val in data {
|
||||
|
@ -486,8 +543,7 @@ impl <L: Lengthable, V: Serializable> Serializable for LenPrefixed<L, V> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl <L: Lengthable, V: Default> Default for LenPrefixed<L, V> {
|
||||
impl<L: Lengthable, V: Default> Default for LenPrefixed<L, V> {
|
||||
fn default() -> Self {
|
||||
LenPrefixed {
|
||||
len: default::Default::default(),
|
||||
|
@ -496,7 +552,7 @@ impl <L: Lengthable, V: Default> Default for LenPrefixed<L, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl <L: Lengthable, V: fmt::Debug> fmt::Debug for LenPrefixed<L, V> {
|
||||
impl<L: Lengthable, V: fmt::Debug> fmt::Debug for LenPrefixed<L, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.data.fmt(f)
|
||||
}
|
||||
|
@ -508,7 +564,7 @@ pub struct LenPrefixedBytes<L: Lengthable> {
|
|||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl <L: Lengthable> LenPrefixedBytes<L> {
|
||||
impl<L: Lengthable> LenPrefixedBytes<L> {
|
||||
pub fn new(data: Vec<u8>) -> LenPrefixedBytes<L> {
|
||||
LenPrefixedBytes {
|
||||
len: Default::default(),
|
||||
|
@ -517,10 +573,10 @@ impl <L: Lengthable> LenPrefixedBytes<L> {
|
|||
}
|
||||
}
|
||||
|
||||
impl <L: Lengthable> Serializable for LenPrefixedBytes<L> {
|
||||
impl<L: Lengthable> Serializable for LenPrefixedBytes<L> {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<LenPrefixedBytes<L>, Error> {
|
||||
let len_data: L = Serializable::read_from(buf)?;
|
||||
let len: usize = len_data.into();
|
||||
let len: usize = len_data.into_len();
|
||||
let mut data: Vec<u8> = Vec::with_capacity(len);
|
||||
buf.take(len as u64).read_to_end(&mut data)?;
|
||||
Result::Ok(LenPrefixedBytes {
|
||||
|
@ -530,15 +586,14 @@ impl <L: Lengthable> Serializable for LenPrefixedBytes<L> {
|
|||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
let len_data: L = L::from(self.data.len());
|
||||
let len_data: L = L::from_len(self.data.len());
|
||||
len_data.write_to(buf)?;
|
||||
buf.write_all(&self.data[..])?;
|
||||
Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl <L: Lengthable> Default for LenPrefixedBytes<L> {
|
||||
impl<L: Lengthable> Default for LenPrefixedBytes<L> {
|
||||
fn default() -> Self {
|
||||
LenPrefixedBytes {
|
||||
len: default::Default::default(),
|
||||
|
@ -547,64 +602,161 @@ impl <L: Lengthable> Default for LenPrefixedBytes<L> {
|
|||
}
|
||||
}
|
||||
|
||||
impl <L: Lengthable> fmt::Debug for LenPrefixedBytes<L> {
|
||||
impl<L: Lengthable> fmt::Debug for LenPrefixedBytes<L> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.data.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Lengthable for bool {
|
||||
fn into(self) -> usize {
|
||||
if self { 1 } else { 0 }
|
||||
fn into_len(self) -> usize {
|
||||
if self {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn from(u: usize) -> bool {
|
||||
fn from_len(u: usize) -> bool {
|
||||
u != 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Lengthable for u8 {
|
||||
fn into(self) -> usize {
|
||||
fn into_len(self) -> usize {
|
||||
self as usize
|
||||
}
|
||||
|
||||
fn from(u: usize) -> u8 {
|
||||
fn from_len(u: usize) -> u8 {
|
||||
u as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl Lengthable for i16 {
|
||||
fn into(self) -> usize {
|
||||
fn into_len(self) -> usize {
|
||||
self as usize
|
||||
}
|
||||
|
||||
fn from(u: usize) -> i16 {
|
||||
fn from_len(u: usize) -> i16 {
|
||||
u as i16
|
||||
}
|
||||
}
|
||||
|
||||
impl Lengthable for i32 {
|
||||
fn into(self) -> usize {
|
||||
fn into_len(self) -> usize {
|
||||
self as usize
|
||||
}
|
||||
|
||||
fn from(u: usize) -> i32 {
|
||||
fn from_len(u: usize) -> i32 {
|
||||
u as i32
|
||||
}
|
||||
}
|
||||
|
||||
use num_traits::cast::{cast, NumCast};
|
||||
/// `FixedPoint5` has the 5 least-significant bits for the fractional
|
||||
/// part, upper for integer part: https://wiki.vg/Data_types#Fixed-point_numbers
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FixedPoint5<T>(T);
|
||||
|
||||
impl<T: Serializable> Serializable for FixedPoint5<T> {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
Ok(Self(Serializable::read_from(buf)?))
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
self.0.write_to(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: default::Default> default::Default for FixedPoint5<T> {
|
||||
fn default() -> Self {
|
||||
Self(T::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NumCast> convert::From<f64> for FixedPoint5<T> {
|
||||
fn from(x: f64) -> Self {
|
||||
let n: T = cast(x * 32.0).unwrap();
|
||||
FixedPoint5::<T>(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NumCast> convert::From<FixedPoint5<T>> for f64 {
|
||||
fn from(x: FixedPoint5<T>) -> Self {
|
||||
let f: f64 = cast(x.0).unwrap();
|
||||
f / 32.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for FixedPoint5<T>
|
||||
where
|
||||
T: fmt::Display,
|
||||
f64: convert::From<T>,
|
||||
T: NumCast + Copy,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let x: f64 = (*self).into();
|
||||
write!(f, "FixedPoint5(#{} = {}f)", self.0, x)
|
||||
}
|
||||
}
|
||||
|
||||
/// `FixedPoint12` is like `FixedPoint5` but the fractional part is 12-bit
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FixedPoint12<T>(T);
|
||||
|
||||
impl<T: Serializable> Serializable for FixedPoint12<T> {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
Ok(Self(Serializable::read_from(buf)?))
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
self.0.write_to(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: default::Default> default::Default for FixedPoint12<T> {
|
||||
fn default() -> Self {
|
||||
Self(T::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NumCast> convert::From<f64> for FixedPoint12<T> {
|
||||
fn from(x: f64) -> Self {
|
||||
let n: T = cast(x * 32.0 * 128.0).unwrap();
|
||||
FixedPoint12::<T>(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NumCast> convert::From<FixedPoint12<T>> for f64 {
|
||||
fn from(x: FixedPoint12<T>) -> Self {
|
||||
let f: f64 = cast(x.0).unwrap();
|
||||
f / (32.0 * 128.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for FixedPoint12<T>
|
||||
where
|
||||
T: fmt::Display,
|
||||
f64: convert::From<T>,
|
||||
T: NumCast + Copy,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let x: f64 = (*self).into();
|
||||
write!(f, "FixedPoint12(#{} = {}f)", self.0, x)
|
||||
}
|
||||
}
|
||||
|
||||
/// `VarInt` have a variable size (between 1 and 5 bytes) when encoded based
|
||||
/// on the size of the number
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VarInt(pub i32);
|
||||
|
||||
impl Lengthable for VarInt {
|
||||
fn into(self) -> usize {
|
||||
fn into_len(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
|
||||
fn from(u: usize) -> VarInt {
|
||||
fn from_len(u: usize) -> VarInt {
|
||||
VarInt(u as i32)
|
||||
}
|
||||
}
|
||||
|
@ -612,7 +764,7 @@ impl Lengthable for VarInt {
|
|||
impl Serializable for VarInt {
|
||||
/// Decodes a `VarInt` from the Reader
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<VarInt, Error> {
|
||||
const PART : u32 = 0x7F;
|
||||
const PART: u32 = 0x7F;
|
||||
let mut size = 0;
|
||||
let mut val = 0u32;
|
||||
loop {
|
||||
|
@ -623,7 +775,7 @@ impl Serializable for VarInt {
|
|||
return Result::Err(Error::Err("VarInt too big".to_owned()));
|
||||
}
|
||||
if (b & 0x80) == 0 {
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -632,7 +784,7 @@ impl Serializable for VarInt {
|
|||
|
||||
/// Encodes a `VarInt` into the Writer
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
const PART : u32 = 0x7F;
|
||||
const PART: u32 = 0x7F;
|
||||
let mut val = self.0 as u32;
|
||||
loop {
|
||||
if (val & !PART) == 0 {
|
||||
|
@ -657,17 +809,80 @@ impl fmt::Debug for VarInt {
|
|||
}
|
||||
}
|
||||
|
||||
/// `VarShort` have a variable size (2 or 3 bytes) and are backwards-compatible
|
||||
/// with vanilla shorts, used for Forge custom payloads
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VarShort(pub i32);
|
||||
|
||||
impl Lengthable for VarShort {
|
||||
fn into_len(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
|
||||
fn from_len(u: usize) -> VarShort {
|
||||
VarShort(u as i32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serializable for VarShort {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<VarShort, Error> {
|
||||
let low = buf.read_u16::<BigEndian>()? as u32;
|
||||
let val = if (low & 0x8000) != 0 {
|
||||
let high = buf.read_u8()? as u32;
|
||||
|
||||
(high << 15) | (low & 0x7fff)
|
||||
} else {
|
||||
low
|
||||
};
|
||||
|
||||
Result::Ok(VarShort(val as i32))
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
assert!(
|
||||
self.0 >= 0 && self.0 <= 0x7fffff,
|
||||
"VarShort invalid value: {}",
|
||||
self.0
|
||||
);
|
||||
let mut low = self.0 & 0x7fff;
|
||||
let high = (self.0 & 0x7f8000) >> 15;
|
||||
if high != 0 {
|
||||
low |= 0x8000;
|
||||
}
|
||||
|
||||
buf.write_u16::<BigEndian>(low as u16)?;
|
||||
|
||||
if high != 0 {
|
||||
buf.write_u8(high as u8)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl default::Default for VarShort {
|
||||
fn default() -> VarShort {
|
||||
VarShort(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for VarShort {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// `VarLong` have a variable size (between 1 and 10 bytes) when encoded based
|
||||
/// on the size of the number
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VarLong(pub i64);
|
||||
|
||||
impl Lengthable for VarLong {
|
||||
fn into(self) -> usize {
|
||||
fn into_len(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
|
||||
fn from(u: usize) -> VarLong {
|
||||
fn from_len(u: usize) -> VarLong {
|
||||
VarLong(u as i64)
|
||||
}
|
||||
}
|
||||
|
@ -675,7 +890,7 @@ impl Lengthable for VarLong {
|
|||
impl Serializable for VarLong {
|
||||
/// Decodes a `VarLong` from the Reader
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<VarLong, Error> {
|
||||
const PART : u64 = 0x7F;
|
||||
const PART: u64 = 0x7F;
|
||||
let mut size = 0;
|
||||
let mut val = 0u64;
|
||||
loop {
|
||||
|
@ -686,7 +901,7 @@ impl Serializable for VarLong {
|
|||
return Result::Err(Error::Err("VarLong too big".to_owned()));
|
||||
}
|
||||
if (b & 0x80) == 0 {
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -695,7 +910,7 @@ impl Serializable for VarLong {
|
|||
|
||||
/// Encodes a `VarLong` into the Writer
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
const PART : u64 = 0x7F;
|
||||
const PART: u64 = 0x7F;
|
||||
let mut val = self.0 as u64;
|
||||
loop {
|
||||
if (val & !PART) == 0 {
|
||||
|
@ -726,7 +941,7 @@ impl Serializable for Position {
|
|||
Ok(Position::new(
|
||||
((pos as i64) >> 38) as i32,
|
||||
(((pos as i64) >> 26) & 0xFFF) as i32,
|
||||
((pos as i64) << 38 >> 38) as i32
|
||||
((pos as i64) << 38 >> 38) as i32,
|
||||
))
|
||||
}
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), Error> {
|
||||
|
@ -738,7 +953,6 @@ impl Serializable for Position {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// Direction is used to define whether packets are going to the
|
||||
/// server or the client.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
@ -764,6 +978,7 @@ pub enum Error {
|
|||
Disconnect(format::Component),
|
||||
IOError(io::Error),
|
||||
Json(serde_json::Error),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Reqwest(reqwest::Error),
|
||||
}
|
||||
|
||||
|
@ -779,23 +994,14 @@ impl convert::From<serde_json::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl convert::From<reqwest::Error> for Error {
|
||||
fn from(e: reqwest::Error) -> Error {
|
||||
Error::Reqwest(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::Err(ref val) => &val[..],
|
||||
Error::Disconnect(_) => "Disconnect",
|
||||
Error::IOError(ref e) => e.description(),
|
||||
Error::Json(ref e) => e.description(),
|
||||
Error::Reqwest(ref e) => e.description(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ::std::error::Error for Error {}
|
||||
|
||||
impl ::std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
|
@ -804,6 +1010,7 @@ impl ::std::fmt::Display for Error {
|
|||
Error::Disconnect(ref val) => write!(f, "{}", val),
|
||||
Error::IOError(ref e) => e.fmt(f),
|
||||
Error::Json(ref e) => e.fmt(f),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Error::Reqwest(ref e) => e.fmt(f),
|
||||
}
|
||||
}
|
||||
|
@ -822,15 +1029,11 @@ pub struct Conn {
|
|||
cipher: Option<Aes128Cfb>,
|
||||
|
||||
compression_threshold: i32,
|
||||
compression_read: Option<ZlibDecoder<io::Cursor<Vec<u8>>>>,
|
||||
compression_write: Option<ZlibEncoder<io::Cursor<Vec<u8>>>>,
|
||||
}
|
||||
|
||||
impl Conn {
|
||||
pub fn new(target: &str, protocol_version: i32) -> Result<Conn, Error> {
|
||||
unsafe {
|
||||
CURRENT_PROTOCOL_VERSION = protocol_version;
|
||||
}
|
||||
CURRENT_PROTOCOL_VERSION.store(protocol_version, Ordering::Relaxed);
|
||||
|
||||
// TODO SRV record support
|
||||
let mut parts = target.split(':').collect::<Vec<&str>>();
|
||||
|
@ -850,8 +1053,6 @@ impl Conn {
|
|||
protocol_version,
|
||||
cipher: Option::None,
|
||||
compression_threshold: -1,
|
||||
compression_read: Option::None,
|
||||
compression_write: Option::None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -866,16 +1067,21 @@ impl Conn {
|
|||
0
|
||||
};
|
||||
if self.compression_threshold >= 0 && buf.len() as i32 > self.compression_threshold {
|
||||
if self.compression_write.is_none() {
|
||||
self.compression_write = Some(ZlibEncoder::new(io::Cursor::new(Vec::new()), Compression::default()));
|
||||
}
|
||||
extra = 0;
|
||||
let uncompressed_size = buf.len();
|
||||
let mut new = Vec::new();
|
||||
VarInt(uncompressed_size as i32).write_to(&mut new)?;
|
||||
let write = self.compression_write.as_mut().unwrap();
|
||||
write.reset(io::Cursor::new(buf));
|
||||
let mut write = ZlibEncoder::new(io::Cursor::new(buf), Compression::default());
|
||||
write.read_to_end(&mut new)?;
|
||||
if is_network_debug() {
|
||||
debug!(
|
||||
"Compressed for sending {} bytes to {} since > threshold {}, new={:?}",
|
||||
uncompressed_size,
|
||||
new.len(),
|
||||
self.compression_threshold,
|
||||
new
|
||||
);
|
||||
}
|
||||
buf = new;
|
||||
}
|
||||
|
||||
|
@ -896,17 +1102,22 @@ impl Conn {
|
|||
let mut buf = io::Cursor::new(ibuf);
|
||||
|
||||
if self.compression_threshold >= 0 {
|
||||
if self.compression_read.is_none() {
|
||||
self.compression_read = Some(ZlibDecoder::new(io::Cursor::new(Vec::new())));
|
||||
}
|
||||
let uncompressed_size = VarInt::read_from(&mut buf)?.0;
|
||||
if uncompressed_size != 0 {
|
||||
let mut new = Vec::with_capacity(uncompressed_size as usize);
|
||||
{
|
||||
let reader = self.compression_read.as_mut().unwrap();
|
||||
reader.reset(buf);
|
||||
let mut reader = ZlibDecoder::new(buf);
|
||||
reader.read_to_end(&mut new)?;
|
||||
}
|
||||
if is_network_debug() {
|
||||
debug!(
|
||||
"Decompressed threshold={} len={} uncompressed_size={} to {} bytes",
|
||||
self.compression_threshold,
|
||||
len,
|
||||
uncompressed_size,
|
||||
new.len()
|
||||
);
|
||||
}
|
||||
buf = io::Cursor::new(new);
|
||||
}
|
||||
}
|
||||
|
@ -917,17 +1128,31 @@ impl Conn {
|
|||
Direction::Serverbound => Direction::Clientbound,
|
||||
};
|
||||
|
||||
if is_network_debug() {
|
||||
debug!(
|
||||
"about to parse id={:x}, dir={:?} state={:?}",
|
||||
id, dir, self.state
|
||||
);
|
||||
fs::File::create("last-packet")?.write_all(buf.get_ref())?;
|
||||
}
|
||||
|
||||
let packet = packet::packet_by_id(self.protocol_version, self.state, dir, id, &mut buf)?;
|
||||
|
||||
if is_network_debug() {
|
||||
debug!("packet = {:?}", packet);
|
||||
}
|
||||
|
||||
match packet {
|
||||
Some(val) => {
|
||||
let pos = buf.position() as usize;
|
||||
let ibuf = buf.into_inner();
|
||||
if ibuf.len() != pos {
|
||||
return Result::Err(Error::Err(format!("Failed to read all of packet 0x{:X}, \
|
||||
return Result::Err(Error::Err(format!(
|
||||
"Failed to read all of packet 0x{:X}, \
|
||||
had {} bytes left",
|
||||
id,
|
||||
ibuf.len() - pos)))
|
||||
id,
|
||||
ibuf.len() - pos
|
||||
)));
|
||||
}
|
||||
Result::Ok(val)
|
||||
}
|
||||
|
@ -945,10 +1170,10 @@ impl Conn {
|
|||
}
|
||||
|
||||
pub fn do_status(mut self) -> Result<(Status, Duration), Error> {
|
||||
use serde_json::Value;
|
||||
use self::packet::status::serverbound::*;
|
||||
use self::packet::handshake::serverbound::Handshake;
|
||||
use self::packet::status::serverbound::*;
|
||||
use self::packet::Packet;
|
||||
use serde_json::Value;
|
||||
let host = self.host.clone();
|
||||
let port = self.port;
|
||||
self.write_packet(Handshake {
|
||||
|
@ -987,28 +1212,88 @@ impl Conn {
|
|||
let version = val.get("version").ok_or(invalid_status())?;
|
||||
let players = val.get("players").ok_or(invalid_status())?;
|
||||
|
||||
Ok((Status {
|
||||
version: StatusVersion {
|
||||
name: version.get("name").and_then(Value::as_str).ok_or(invalid_status())?
|
||||
.to_owned(),
|
||||
protocol: version.get("protocol")
|
||||
.and_then(Value::as_i64)
|
||||
.ok_or(invalid_status())? as i32,
|
||||
// For modded servers, get the list of Forge mods installed
|
||||
let mut forge_mods: std::vec::Vec<crate::protocol::forge::ForgeMod> = vec![];
|
||||
if let Some(modinfo) = val.get("modinfo") {
|
||||
if let Some(modinfo_type) = modinfo.get("type") {
|
||||
if modinfo_type == "FML" {
|
||||
if let Some(modlist) = modinfo.get("modList") {
|
||||
if let Value::Array(items) = modlist {
|
||||
for item in items {
|
||||
if let Value::Object(obj) = item {
|
||||
let modid =
|
||||
obj.get("modid").unwrap().as_str().unwrap().to_string();
|
||||
let version =
|
||||
obj.get("version").unwrap().as_str().unwrap().to_string();
|
||||
|
||||
forge_mods
|
||||
.push(crate::protocol::forge::ForgeMod { modid, version });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"Unrecognized modinfo type in server ping response: {} in {}",
|
||||
modinfo_type, modinfo
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Forge 1.13+ TODO: update for 1.14+ and test
|
||||
if let Some(forge_data) = val.get("forgeData") {
|
||||
if let Some(mods) = forge_data.get("mods") {
|
||||
if let Value::Array(items) = mods {
|
||||
for item in items {
|
||||
if let Value::Object(obj) = item {
|
||||
let modid = obj.get("modId").unwrap().as_str().unwrap().to_string();
|
||||
let modmarker =
|
||||
obj.get("modmarker").unwrap().as_str().unwrap().to_string();
|
||||
|
||||
let version = modmarker;
|
||||
|
||||
forge_mods.push(crate::protocol::forge::ForgeMod { modid, version });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok((
|
||||
Status {
|
||||
version: StatusVersion {
|
||||
name: version
|
||||
.get("name")
|
||||
.and_then(Value::as_str)
|
||||
.ok_or(invalid_status())?
|
||||
.to_owned(),
|
||||
protocol: version
|
||||
.get("protocol")
|
||||
.and_then(Value::as_i64)
|
||||
.ok_or(invalid_status())? as i32,
|
||||
},
|
||||
players: StatusPlayers {
|
||||
max: players
|
||||
.get("max")
|
||||
.and_then(Value::as_i64)
|
||||
.ok_or(invalid_status())? as i32,
|
||||
online: players
|
||||
.get("online")
|
||||
.and_then(Value::as_i64)
|
||||
.ok_or(invalid_status())? as i32,
|
||||
sample: Vec::new(), /* TODO */
|
||||
},
|
||||
description: format::Component::from_value(
|
||||
val.get("description").ok_or(invalid_status())?,
|
||||
),
|
||||
favicon: val
|
||||
.get("favicon")
|
||||
.and_then(Value::as_str)
|
||||
.map(|v| v.to_owned()),
|
||||
forge_mods,
|
||||
},
|
||||
players: StatusPlayers {
|
||||
max: players.get("max")
|
||||
.and_then(Value::as_i64)
|
||||
.ok_or(invalid_status())? as i32,
|
||||
online: players.get("online")
|
||||
.and_then(Value::as_i64)
|
||||
.ok_or(invalid_status())? as i32,
|
||||
sample: Vec::new(), /* TODO */
|
||||
},
|
||||
description: format::Component::from_value(val.get("description")
|
||||
.ok_or(invalid_status())?),
|
||||
favicon: val.get("favicon").and_then(Value::as_str).map(|v| v.to_owned()),
|
||||
},
|
||||
ping))
|
||||
ping,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1018,6 +1303,7 @@ pub struct Status {
|
|||
pub players: StatusPlayers,
|
||||
pub description: format::Component,
|
||||
pub favicon: Option<String>,
|
||||
pub forge_mods: Vec<crate::protocol::forge::ForgeMod>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -1088,8 +1374,6 @@ impl Clone for Conn {
|
|||
protocol_version: self.protocol_version,
|
||||
cipher: Option::None,
|
||||
compression_threshold: self.compression_threshold,
|
||||
compression_read: Option::None,
|
||||
compression_write: Option::None,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,9 +12,10 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use sha1::{self, Digest};
|
||||
use serde_json::json;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use reqwest;
|
||||
use serde_json::json;
|
||||
use sha1::{self, Digest};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Profile {
|
||||
|
@ -28,20 +29,22 @@ const LOGIN_URL: &str = "https://authserver.mojang.com/authenticate";
|
|||
const REFRESH_URL: &str = "https://authserver.mojang.com/refresh";
|
||||
const VALIDATE_URL: &str = "https://authserver.mojang.com/validate";
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl Profile {
|
||||
pub fn login(username: &str, password: &str, token: &str) -> Result<Profile, super::Error> {
|
||||
let req_msg = json!({
|
||||
"username": username,
|
||||
"password": password,
|
||||
"clientToken": token,
|
||||
"agent": {
|
||||
"name": "Minecraft",
|
||||
"version": 1
|
||||
}});
|
||||
"username": username,
|
||||
"password": password,
|
||||
"clientToken": token,
|
||||
"agent": {
|
||||
"name": "Minecraft",
|
||||
"version": 1
|
||||
}});
|
||||
let req = serde_json::to_string(&req_msg)?;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let res = client.post(LOGIN_URL)
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let res = client
|
||||
.post(LOGIN_URL)
|
||||
.header(reqwest::header::CONTENT_TYPE, "application/json")
|
||||
.body(req)
|
||||
.send()?;
|
||||
|
@ -51,33 +54,47 @@ impl Profile {
|
|||
return Err(super::Error::Err(format!(
|
||||
"{}: {}",
|
||||
error,
|
||||
ret.get("errorMessage").and_then(|v| v.as_str()).unwrap())
|
||||
));
|
||||
ret.get("errorMessage").and_then(|v| v.as_str()).unwrap()
|
||||
)));
|
||||
}
|
||||
Ok(Profile {
|
||||
username: ret.pointer("/selectedProfile/name").and_then(|v| v.as_str()).unwrap().to_owned(),
|
||||
id: ret.pointer("/selectedProfile/id").and_then(|v| v.as_str()).unwrap().to_owned(),
|
||||
access_token: ret.get("accessToken").and_then(|v| v.as_str()).unwrap().to_owned(),
|
||||
username: ret
|
||||
.pointer("/selectedProfile/name")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap()
|
||||
.to_owned(),
|
||||
id: ret
|
||||
.pointer("/selectedProfile/id")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap()
|
||||
.to_owned(),
|
||||
access_token: ret
|
||||
.get("accessToken")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap()
|
||||
.to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn refresh(self, token: &str) -> Result<Profile, super::Error> {
|
||||
let req_msg = json!({
|
||||
"accessToken": self.access_token.clone(),
|
||||
"clientToken": token
|
||||
});
|
||||
"accessToken": self.access_token.clone(),
|
||||
"clientToken": token
|
||||
});
|
||||
let req = serde_json::to_string(&req_msg)?;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let res = client.post(VALIDATE_URL)
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let res = client
|
||||
.post(VALIDATE_URL)
|
||||
.header(reqwest::header::CONTENT_TYPE, "application/json")
|
||||
.body(req)
|
||||
.send()?;
|
||||
|
||||
if res.status() != reqwest::StatusCode::NO_CONTENT {
|
||||
let req = serde_json::to_string(&req_msg)?; // TODO: fix parsing twice to avoid move
|
||||
// Refresh needed
|
||||
let res = client.post(REFRESH_URL)
|
||||
// Refresh needed
|
||||
let res = client
|
||||
.post(REFRESH_URL)
|
||||
.header(reqwest::header::CONTENT_TYPE, "application/json")
|
||||
.body(req)
|
||||
.send()?;
|
||||
|
@ -87,19 +104,36 @@ impl Profile {
|
|||
return Err(super::Error::Err(format!(
|
||||
"{}: {}",
|
||||
error,
|
||||
ret.get("errorMessage").and_then(|v| v.as_str()).unwrap())
|
||||
));
|
||||
ret.get("errorMessage").and_then(|v| v.as_str()).unwrap()
|
||||
)));
|
||||
}
|
||||
return Ok(Profile {
|
||||
username: ret.pointer("/selectedProfile/name").and_then(|v| v.as_str()).unwrap().to_owned(),
|
||||
id: ret.pointer("/selectedProfile/id").and_then(|v| v.as_str()).unwrap().to_owned(),
|
||||
access_token: ret.get("accessToken").and_then(|v| v.as_str()).unwrap().to_owned(),
|
||||
username: ret
|
||||
.pointer("/selectedProfile/name")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap()
|
||||
.to_owned(),
|
||||
id: ret
|
||||
.pointer("/selectedProfile/id")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap()
|
||||
.to_owned(),
|
||||
access_token: ret
|
||||
.get("accessToken")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap()
|
||||
.to_owned(),
|
||||
});
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn join_server(&self, server_id: &str, shared_key: &[u8], public_key: &[u8]) -> Result<(), super::Error> {
|
||||
pub fn join_server(
|
||||
&self,
|
||||
server_id: &str,
|
||||
shared_key: &[u8],
|
||||
public_key: &[u8],
|
||||
) -> Result<(), super::Error> {
|
||||
let mut hasher = sha1::Sha1::new();
|
||||
hasher.input(server_id.as_bytes());
|
||||
hasher.input(shared_key);
|
||||
|
@ -112,8 +146,12 @@ impl Profile {
|
|||
if negative {
|
||||
twos_compliment(&mut hash);
|
||||
}
|
||||
let hash_str = hash.iter().map(|b| format!("{:02x}", b)).collect::<Vec<String>>().join("");
|
||||
let hash_val = hash_str.trim_left_matches('0');
|
||||
let hash_str = hash
|
||||
.iter()
|
||||
.map(|b| format!("{:02x}", b))
|
||||
.collect::<Vec<String>>()
|
||||
.join("");
|
||||
let hash_val = hash_str.trim_start_matches('0');
|
||||
let hash_str = if negative {
|
||||
"-".to_owned() + &hash_val[..]
|
||||
} else {
|
||||
|
@ -127,8 +165,9 @@ impl Profile {
|
|||
});
|
||||
let join = serde_json::to_string(&join_msg).unwrap();
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let res = client.post(JOIN_URL)
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let res = client
|
||||
.post(JOIN_URL)
|
||||
.header(reqwest::header::CONTENT_TYPE, "application/json")
|
||||
.body(join)
|
||||
.send()?;
|
|
@ -57,6 +57,9 @@ state_packets!(
|
|||
field transaction_id: VarInt =,
|
||||
field location: Position =,
|
||||
}
|
||||
packet SetDifficulty {
|
||||
field new_difficulty: u8 =,
|
||||
}
|
||||
/// TabComplete is sent by the client when the client presses tab in
|
||||
/// the chat box.
|
||||
packet TabComplete {
|
||||
|
@ -128,6 +131,11 @@ state_packets!(
|
|||
field id: u8 =,
|
||||
field enchantment: u8 =,
|
||||
}
|
||||
/// ClickWindowButton is used for clicking an enchantment, lectern, stonecutter, or loom.
|
||||
packet ClickWindowButton {
|
||||
field id: u8 =,
|
||||
field button: u8 =,
|
||||
}
|
||||
/// ClickWindow is sent when the client clicks in a window.
|
||||
packet ClickWindow {
|
||||
field id: u8 =,
|
||||
|
@ -158,7 +166,7 @@ state_packets!(
|
|||
}
|
||||
packet PluginMessageServerbound_i16 {
|
||||
field channel: String =,
|
||||
field data: LenPrefixedBytes<i16> =,
|
||||
field data: LenPrefixedBytes<VarShort> =,
|
||||
}
|
||||
packet EditBook {
|
||||
field new_book: Option<item::Stack> =,
|
||||
|
@ -202,6 +210,9 @@ state_packets!(
|
|||
packet KeepAliveServerbound_i32 {
|
||||
field id: i32 =,
|
||||
}
|
||||
packet LockDifficulty {
|
||||
field locked: bool =,
|
||||
}
|
||||
/// PlayerPosition is used to update the player's position.
|
||||
packet PlayerPosition {
|
||||
field x: f64 =,
|
||||
|
@ -370,6 +381,12 @@ state_packets!(
|
|||
field slot: i16 =,
|
||||
field clicked_item: Option<item::Stack> =,
|
||||
}
|
||||
packet UpdateJigsawBlock {
|
||||
field location: Position =,
|
||||
field attachment_type: String =,
|
||||
field target_pool: String =,
|
||||
field final_state: String =,
|
||||
}
|
||||
packet UpdateStructureBlock {
|
||||
field location: Position =,
|
||||
field action: VarInt =,
|
||||
|
@ -483,9 +500,9 @@ state_packets!(
|
|||
field entity_id: VarInt =,
|
||||
field uuid: UUID =,
|
||||
field ty: u8 =,
|
||||
field x: i32 =,
|
||||
field y: i32 =,
|
||||
field z: i32 =,
|
||||
field x: FixedPoint5<i32> =,
|
||||
field y: FixedPoint5<i32> =,
|
||||
field z: FixedPoint5<i32> =,
|
||||
field pitch: i8 =,
|
||||
field yaw: i8 =,
|
||||
field data: i32 =,
|
||||
|
@ -496,9 +513,9 @@ state_packets!(
|
|||
packet SpawnObject_i32_NoUUID {
|
||||
field entity_id: VarInt =,
|
||||
field ty: u8 =,
|
||||
field x: i32 =,
|
||||
field y: i32 =,
|
||||
field z: i32 =,
|
||||
field x: FixedPoint5<i32> =,
|
||||
field y: FixedPoint5<i32> =,
|
||||
field z: FixedPoint5<i32> =,
|
||||
field pitch: i8 =,
|
||||
field yaw: i8 =,
|
||||
field data: i32 =,
|
||||
|
@ -518,9 +535,9 @@ state_packets!(
|
|||
}
|
||||
packet SpawnExperienceOrb_i32 {
|
||||
field entity_id: VarInt =,
|
||||
field x: i32 =,
|
||||
field y: i32 =,
|
||||
field z: i32 =,
|
||||
field x: FixedPoint5<i32> =,
|
||||
field y: FixedPoint5<i32> =,
|
||||
field z: FixedPoint5<i32> =,
|
||||
field count: i16 =,
|
||||
}
|
||||
/// SpawnGlobalEntity spawns an entity which is visible from anywhere in the
|
||||
|
@ -535,13 +552,27 @@ state_packets!(
|
|||
packet SpawnGlobalEntity_i32 {
|
||||
field entity_id: VarInt =,
|
||||
field ty: u8 =,
|
||||
field x: i32 =,
|
||||
field y: i32 =,
|
||||
field z: i32 =,
|
||||
field x: FixedPoint5<i32> =,
|
||||
field y: FixedPoint5<i32> =,
|
||||
field z: FixedPoint5<i32> =,
|
||||
}
|
||||
/// SpawnMob is used to spawn a living entity into the world when it is in
|
||||
/// range of the client.
|
||||
packet SpawnMob {
|
||||
packet SpawnMob_NoMeta {
|
||||
field entity_id: VarInt =,
|
||||
field uuid: UUID =,
|
||||
field ty: VarInt =,
|
||||
field x: f64 =,
|
||||
field y: f64 =,
|
||||
field z: f64 =,
|
||||
field yaw: i8 =,
|
||||
field pitch: i8 =,
|
||||
field head_pitch: i8 =,
|
||||
field velocity_x: i16 =,
|
||||
field velocity_y: i16 =,
|
||||
field velocity_z: i16 =,
|
||||
}
|
||||
packet SpawnMob_WithMeta {
|
||||
field entity_id: VarInt =,
|
||||
field uuid: UUID =,
|
||||
field ty: VarInt =,
|
||||
|
@ -575,9 +606,9 @@ state_packets!(
|
|||
field entity_id: VarInt =,
|
||||
field uuid: UUID =,
|
||||
field ty: u8 =,
|
||||
field x: i32 =,
|
||||
field y: i32 =,
|
||||
field z: i32 =,
|
||||
field x: FixedPoint5<i32> =,
|
||||
field y: FixedPoint5<i32> =,
|
||||
field z: FixedPoint5<i32> =,
|
||||
field yaw: i8 =,
|
||||
field pitch: i8 =,
|
||||
field head_pitch: i8 =,
|
||||
|
@ -589,9 +620,9 @@ state_packets!(
|
|||
packet SpawnMob_u8_i32_NoUUID {
|
||||
field entity_id: VarInt =,
|
||||
field ty: u8 =,
|
||||
field x: i32 =,
|
||||
field y: i32 =,
|
||||
field z: i32 =,
|
||||
field x: FixedPoint5<i32> =,
|
||||
field y: FixedPoint5<i32> =,
|
||||
field z: FixedPoint5<i32> =,
|
||||
field yaw: i8 =,
|
||||
field pitch: i8 =,
|
||||
field head_pitch: i8 =,
|
||||
|
@ -602,7 +633,14 @@ state_packets!(
|
|||
}
|
||||
/// SpawnPainting spawns a painting into the world when it is in range of
|
||||
/// the client. The title effects the size and the texture of the painting.
|
||||
packet SpawnPainting {
|
||||
packet SpawnPainting_VarInt {
|
||||
field entity_id: VarInt =,
|
||||
field uuid: UUID =,
|
||||
field motive: VarInt =,
|
||||
field location: Position =,
|
||||
field direction: u8 =,
|
||||
}
|
||||
packet SpawnPainting_String {
|
||||
field entity_id: VarInt =,
|
||||
field uuid: UUID =,
|
||||
field title: String =,
|
||||
|
@ -626,6 +664,15 @@ state_packets!(
|
|||
/// SpawnPlayer is used to spawn a player when they are in range of the client.
|
||||
/// This packet alone isn't enough to display the player as the skin and username
|
||||
/// information is in the player information packet.
|
||||
packet SpawnPlayer_f64_NoMeta {
|
||||
field entity_id: VarInt =,
|
||||
field uuid: UUID =,
|
||||
field x: f64 =,
|
||||
field y: f64 =,
|
||||
field z: f64 =,
|
||||
field yaw: i8 =,
|
||||
field pitch: i8 =,
|
||||
}
|
||||
packet SpawnPlayer_f64 {
|
||||
field entity_id: VarInt =,
|
||||
field uuid: UUID =,
|
||||
|
@ -639,9 +686,9 @@ state_packets!(
|
|||
packet SpawnPlayer_i32 {
|
||||
field entity_id: VarInt =,
|
||||
field uuid: UUID =,
|
||||
field x: i32 =,
|
||||
field y: i32 =,
|
||||
field z: i32 =,
|
||||
field x: FixedPoint5<i32> =,
|
||||
field y: FixedPoint5<i32> =,
|
||||
field z: FixedPoint5<i32> =,
|
||||
field yaw: i8 =,
|
||||
field pitch: i8 =,
|
||||
field metadata: types::Metadata =,
|
||||
|
@ -649,9 +696,9 @@ state_packets!(
|
|||
packet SpawnPlayer_i32_HeldItem {
|
||||
field entity_id: VarInt =,
|
||||
field uuid: UUID =,
|
||||
field x: i32 =,
|
||||
field y: i32 =,
|
||||
field z: i32 =,
|
||||
field x: FixedPoint5<i32> =,
|
||||
field y: FixedPoint5<i32> =,
|
||||
field z: FixedPoint5<i32> =,
|
||||
field yaw: i8 =,
|
||||
field pitch: i8 =,
|
||||
field current_item: u16 =,
|
||||
|
@ -662,9 +709,9 @@ state_packets!(
|
|||
field uuid: String =,
|
||||
field name: String =,
|
||||
field properties: LenPrefixed<VarInt, packet::SpawnProperty> =,
|
||||
field x: i32 =,
|
||||
field y: i32 =,
|
||||
field z: i32 =,
|
||||
field x: FixedPoint5<i32> =,
|
||||
field y: FixedPoint5<i32> =,
|
||||
field z: FixedPoint5<i32> =,
|
||||
field yaw: i8 =,
|
||||
field pitch: i8 =,
|
||||
field current_item: u16 =,
|
||||
|
@ -753,6 +800,10 @@ state_packets!(
|
|||
packet ServerDifficulty {
|
||||
field difficulty: u8 =,
|
||||
}
|
||||
packet ServerDifficulty_Locked {
|
||||
field difficulty: u8 =,
|
||||
field locked: bool =,
|
||||
}
|
||||
/// TabCompleteReply is sent as a reply to a tab completion request.
|
||||
/// The matches should be possible completions for the command/chat the
|
||||
/// player sent.
|
||||
|
@ -859,7 +910,7 @@ state_packets!(
|
|||
}
|
||||
packet PluginMessageClientbound_i16 {
|
||||
field channel: String =,
|
||||
field data: LenPrefixedBytes<i16> =,
|
||||
field data: LenPrefixedBytes<VarShort> =,
|
||||
}
|
||||
/// Plays a sound by name on the client
|
||||
packet NamedSoundEffect {
|
||||
|
@ -941,6 +992,16 @@ state_packets!(
|
|||
}
|
||||
/// ChunkData sends or updates a single chunk on the client. If New is set
|
||||
/// then biome data should be sent too.
|
||||
packet ChunkData_Biomes3D {
|
||||
field chunk_x: i32 =,
|
||||
field chunk_z: i32 =,
|
||||
field new: bool =,
|
||||
field bitmask: VarInt =,
|
||||
field heightmaps: Option<nbt::NamedTag> =,
|
||||
field biomes: Biomes3D = when(|p: &ChunkData_Biomes3D| p.new),
|
||||
field data: LenPrefixedBytes<VarInt> =,
|
||||
field block_entities: LenPrefixed<VarInt, Option<nbt::NamedTag>> =,
|
||||
}
|
||||
packet ChunkData_HeightMap {
|
||||
field chunk_x: i32 =,
|
||||
field chunk_z: i32 =,
|
||||
|
@ -1010,7 +1071,25 @@ state_packets!(
|
|||
}
|
||||
/// Particle spawns particles at the target location with the various
|
||||
/// modifiers.
|
||||
packet Particle {
|
||||
packet Particle_f64 {
|
||||
field particle_id: i32 =,
|
||||
field long_distance: bool =,
|
||||
field x: f64 =,
|
||||
field y: f64=,
|
||||
field z: f64 =,
|
||||
field offset_x: f32 =,
|
||||
field offset_y: f32 =,
|
||||
field offset_z: f32 =,
|
||||
field speed: f32 =,
|
||||
field count: i32 =,
|
||||
field block_state: VarInt = when(|p: &Particle_f64| p.particle_id == 3 || p.particle_id == 20),
|
||||
field red: f32 = when(|p: &Particle_f64| p.particle_id == 11),
|
||||
field green: f32 = when(|p: &Particle_f64| p.particle_id == 11),
|
||||
field blue: f32 = when(|p: &Particle_f64| p.particle_id == 11),
|
||||
field scale: f32 = when(|p: &Particle_f64| p.particle_id == 11),
|
||||
field item: Option<nbt::NamedTag> = when(|p: &Particle_f64| p.particle_id == 27),
|
||||
}
|
||||
packet Particle_Data {
|
||||
field particle_id: i32 =,
|
||||
field long_distance: bool =,
|
||||
field x: f32 =,
|
||||
|
@ -1021,8 +1100,26 @@ state_packets!(
|
|||
field offset_z: f32 =,
|
||||
field speed: f32 =,
|
||||
field count: i32 =,
|
||||
field data1: VarInt = when(|p: &Particle| p.particle_id == 36 || p.particle_id == 37 || p.particle_id == 38 || p.particle_id == 46),
|
||||
field data2: VarInt = when(|p: &Particle| p.particle_id == 36),
|
||||
field block_state: VarInt = when(|p: &Particle_Data| p.particle_id == 3 || p.particle_id == 20),
|
||||
field red: f32 = when(|p: &Particle_Data| p.particle_id == 11),
|
||||
field green: f32 = when(|p: &Particle_Data| p.particle_id == 11),
|
||||
field blue: f32 = when(|p: &Particle_Data| p.particle_id == 11),
|
||||
field scale: f32 = when(|p: &Particle_Data| p.particle_id == 11),
|
||||
field item: Option<nbt::NamedTag> = when(|p: &Particle_Data| p.particle_id == 27),
|
||||
}
|
||||
packet Particle_VarIntArray {
|
||||
field particle_id: i32 =,
|
||||
field long_distance: bool =,
|
||||
field x: f32 =,
|
||||
field y: f32 =,
|
||||
field z: f32 =,
|
||||
field offset_x: f32 =,
|
||||
field offset_y: f32 =,
|
||||
field offset_z: f32 =,
|
||||
field speed: f32 =,
|
||||
field count: i32 =,
|
||||
field data1: VarInt = when(|p: &Particle_VarIntArray| p.particle_id == 36 || p.particle_id == 37 || p.particle_id == 38 || p.particle_id == 46),
|
||||
field data2: VarInt = when(|p: &Particle_VarIntArray| p.particle_id == 36),
|
||||
}
|
||||
packet Particle_Named {
|
||||
field particle_id: String =,
|
||||
|
@ -1037,6 +1134,44 @@ state_packets!(
|
|||
}
|
||||
/// JoinGame is sent after completing the login process. This
|
||||
/// sets the initial state for the client.
|
||||
packet JoinGame_HashedSeed_Respawn {
|
||||
/// The entity id the client will be referenced by
|
||||
field entity_id: i32 =,
|
||||
/// The starting gamemode of the client
|
||||
field gamemode: u8 =,
|
||||
/// The dimension the client is starting in
|
||||
field dimension: i32 =,
|
||||
/// Truncated SHA-256 hash of world's seed
|
||||
field hashed_seed: i64 =,
|
||||
/// The max number of players on the server
|
||||
field max_players: u8 =,
|
||||
/// The level type of the server
|
||||
field level_type: String =,
|
||||
/// The render distance (2-32)
|
||||
field view_distance: VarInt =,
|
||||
/// Whether the client should reduce the amount of debug
|
||||
/// information it displays in F3 mode
|
||||
field reduced_debug_info: bool =,
|
||||
/// Whether to prompt or immediately respawn
|
||||
field enable_respawn_screen: bool =,
|
||||
}
|
||||
packet JoinGame_i32_ViewDistance {
|
||||
/// The entity id the client will be referenced by
|
||||
field entity_id: i32 =,
|
||||
/// The starting gamemode of the client
|
||||
field gamemode: u8 =,
|
||||
/// The dimension the client is starting in
|
||||
field dimension: i32 =,
|
||||
/// The max number of players on the server
|
||||
field max_players: u8 =,
|
||||
/// The level type of the server
|
||||
field level_type: String =,
|
||||
/// The render distance (2-32)
|
||||
field view_distance: VarInt =,
|
||||
/// Whether the client should reduce the amount of debug
|
||||
/// information it displays in F3 mode
|
||||
field reduced_debug_info: bool =,
|
||||
}
|
||||
packet JoinGame_i32 {
|
||||
/// The entity id the client will be referenced by
|
||||
field entity_id: i32 =,
|
||||
|
@ -1108,48 +1243,48 @@ state_packets!(
|
|||
/// EntityMove moves the entity with the id by the offsets provided.
|
||||
packet EntityMove_i16 {
|
||||
field entity_id: VarInt =,
|
||||
field delta_x: i16 =,
|
||||
field delta_y: i16 =,
|
||||
field delta_z: i16 =,
|
||||
field delta_x: FixedPoint12<i16> =,
|
||||
field delta_y: FixedPoint12<i16> =,
|
||||
field delta_z: FixedPoint12<i16> =,
|
||||
field on_ground: bool =,
|
||||
}
|
||||
packet EntityMove_i8 {
|
||||
field entity_id: VarInt =,
|
||||
field delta_x: i8 =,
|
||||
field delta_y: i8 =,
|
||||
field delta_z: i8 =,
|
||||
field delta_x: FixedPoint5<i8> =,
|
||||
field delta_y: FixedPoint5<i8> =,
|
||||
field delta_z: FixedPoint5<i8> =,
|
||||
field on_ground: bool =,
|
||||
}
|
||||
packet EntityMove_i8_i32_NoGround {
|
||||
field entity_id: i32 =,
|
||||
field delta_x: i8 =,
|
||||
field delta_y: i8 =,
|
||||
field delta_z: i8 =,
|
||||
field delta_x: FixedPoint5<i8> =,
|
||||
field delta_y: FixedPoint5<i8> =,
|
||||
field delta_z: FixedPoint5<i8> =,
|
||||
}
|
||||
/// EntityLookAndMove is a combination of EntityMove and EntityLook.
|
||||
packet EntityLookAndMove_i16 {
|
||||
field entity_id: VarInt =,
|
||||
field delta_x: i16 =,
|
||||
field delta_y: i16 =,
|
||||
field delta_z: i16 =,
|
||||
field delta_x: FixedPoint12<i16> =,
|
||||
field delta_y: FixedPoint12<i16> =,
|
||||
field delta_z: FixedPoint12<i16> =,
|
||||
field yaw: i8 =,
|
||||
field pitch: i8 =,
|
||||
field on_ground: bool =,
|
||||
}
|
||||
packet EntityLookAndMove_i8 {
|
||||
field entity_id: VarInt =,
|
||||
field delta_x: i8 =,
|
||||
field delta_y: i8 =,
|
||||
field delta_z: i8 =,
|
||||
field delta_x: FixedPoint5<i8> =,
|
||||
field delta_y: FixedPoint5<i8> =,
|
||||
field delta_z: FixedPoint5<i8> =,
|
||||
field yaw: i8 =,
|
||||
field pitch: i8 =,
|
||||
field on_ground: bool =,
|
||||
}
|
||||
packet EntityLookAndMove_i8_i32_NoGround {
|
||||
field entity_id: i32 =,
|
||||
field delta_x: i8 =,
|
||||
field delta_y: i8 =,
|
||||
field delta_z: i8 =,
|
||||
field delta_x: FixedPoint5<i8> =,
|
||||
field delta_y: FixedPoint5<i8> =,
|
||||
field delta_z: FixedPoint5<i8> =,
|
||||
field yaw: i8 =,
|
||||
field pitch: i8 =,
|
||||
}
|
||||
|
@ -1259,6 +1394,14 @@ state_packets!(
|
|||
field pitch: f32 =,
|
||||
field flags: u8 =,
|
||||
}
|
||||
packet TeleportPlayer_OnGround {
|
||||
field x: f64 =,
|
||||
field eyes_y: f64 =,
|
||||
field z: f64 =,
|
||||
field yaw: f32 =,
|
||||
field pitch: f32 =,
|
||||
field on_ground: bool =,
|
||||
}
|
||||
/// EntityUsedBed is sent by the server when a player goes to bed.
|
||||
packet EntityUsedBed {
|
||||
field entity_id: VarInt =,
|
||||
|
@ -1316,6 +1459,13 @@ state_packets!(
|
|||
field gamemode: u8 =,
|
||||
field level_type: String =,
|
||||
}
|
||||
packet Respawn_HashedSeed {
|
||||
field dimension: i32 =,
|
||||
field hashed_seed: i64 =,
|
||||
field difficulty: u8 =,
|
||||
field gamemode: u8 =,
|
||||
field level_type: String =,
|
||||
}
|
||||
/// EntityHeadLook rotates an entity's head to the new angle.
|
||||
packet EntityHeadLook {
|
||||
field entity_id: VarInt =,
|
||||
|
@ -1359,6 +1509,15 @@ state_packets!(
|
|||
packet SetCurrentHotbarSlot {
|
||||
field slot: u8 =,
|
||||
}
|
||||
/// UpdateViewPosition is used to determine what chunks should be remain loaded.
|
||||
packet UpdateViewPosition {
|
||||
field chunk_x: VarInt =,
|
||||
field chunk_z: VarInt =,
|
||||
}
|
||||
/// UpdateViewDistance is sent by the integrated server when changing render distance.
|
||||
packet UpdateViewDistance {
|
||||
field view_distance: VarInt =,
|
||||
}
|
||||
/// ScoreboardDisplay is used to set the display position of a scoreboard.
|
||||
packet ScoreboardDisplay {
|
||||
field position: u8 =,
|
||||
|
@ -1456,17 +1615,30 @@ state_packets!(
|
|||
field passengers: LenPrefixed<VarInt, VarInt> =,
|
||||
}
|
||||
/// Teams creates and updates teams
|
||||
packet Teams {
|
||||
packet Teams_VarInt {
|
||||
field name: String =,
|
||||
field mode: u8 =,
|
||||
field display_name: Option<String> = when(|p: &Teams| p.mode == 0 || p.mode == 2),
|
||||
field prefix: Option<String> = when(|p: &Teams| p.mode == 0 || p.mode == 2),
|
||||
field suffix: Option<String> = when(|p: &Teams| p.mode == 0 || p.mode == 2),
|
||||
field flags: Option<u8> = when(|p: &Teams| p.mode == 0 || p.mode == 2),
|
||||
field name_tag_visibility: Option<String> = when(|p: &Teams| p.mode == 0 || p.mode == 2),
|
||||
field collision_rule: Option<String> = when(|p: &Teams| p.mode == 0 || p.mode == 2),
|
||||
field color: Option<i8> = when(|p: &Teams| p.mode == 0 || p.mode == 2),
|
||||
field players: Option<LenPrefixed<VarInt, String>> = when(|p: &Teams| p.mode == 0 || p.mode == 3 || p.mode == 4),
|
||||
field display_name: Option<String> = when(|p: &Teams_VarInt| p.mode == 0 || p.mode == 2),
|
||||
field flags: Option<u8> = when(|p: &Teams_VarInt| p.mode == 0 || p.mode == 2),
|
||||
field name_tag_visibility: Option<String> = when(|p: &Teams_VarInt| p.mode == 0 || p.mode == 2),
|
||||
field collision_rule: Option<String> = when(|p: &Teams_VarInt| p.mode == 0 || p.mode == 2),
|
||||
field formatting: Option<VarInt> = when(|p: &Teams_VarInt| p.mode == 0 || p.mode == 2),
|
||||
field prefix: Option<String> = when(|p: &Teams_VarInt| p.mode == 0 || p.mode == 2),
|
||||
field suffix: Option<String> = when(|p: &Teams_VarInt| p.mode == 0 || p.mode == 2),
|
||||
field players: Option<LenPrefixed<VarInt, String>> = when(|p: &Teams_VarInt| p.mode == 0 || p.mode == 3 || p.mode == 4),
|
||||
}
|
||||
packet Teams_u8 {
|
||||
field name: String =,
|
||||
field mode: u8 =,
|
||||
field data: Vec<u8> =,
|
||||
field display_name: Option<String> = when(|p: &Teams_u8| p.mode == 0 || p.mode == 2),
|
||||
field prefix: Option<String> = when(|p: &Teams_u8| p.mode == 0 || p.mode == 2),
|
||||
field suffix: Option<String> = when(|p: &Teams_u8| p.mode == 0 || p.mode == 2),
|
||||
field flags: Option<u8> = when(|p: &Teams_u8| p.mode == 0 || p.mode == 2),
|
||||
field name_tag_visibility: Option<String> = when(|p: &Teams_u8| p.mode == 0 || p.mode == 2),
|
||||
field collision_rule: Option<String> = when(|p: &Teams_u8| p.mode == 0 || p.mode == 2),
|
||||
field color: Option<i8> = when(|p: &Teams_u8| p.mode == 0 || p.mode == 2),
|
||||
field players: Option<LenPrefixed<VarInt, String>> = when(|p: &Teams_u8| p.mode == 0 || p.mode == 3 || p.mode == 4),
|
||||
}
|
||||
packet Teams_NoVisColor {
|
||||
field name: String =,
|
||||
|
@ -1617,26 +1789,30 @@ state_packets!(
|
|||
}
|
||||
packet EntityTeleport_i32 {
|
||||
field entity_id: VarInt =,
|
||||
field x: i32 =,
|
||||
field y: i32 =,
|
||||
field z: i32 =,
|
||||
field x: FixedPoint5<i32> =,
|
||||
field y: FixedPoint5<i32> =,
|
||||
field z: FixedPoint5<i32> =,
|
||||
field yaw: i8 =,
|
||||
field pitch: i8 =,
|
||||
field on_ground: bool =,
|
||||
}
|
||||
packet EntityTeleport_i32_i32_NoGround {
|
||||
field entity_id: i32 =,
|
||||
field x: i32 =,
|
||||
field y: i32 =,
|
||||
field z: i32 =,
|
||||
field x: FixedPoint5<i32> =,
|
||||
field y: FixedPoint5<i32> =,
|
||||
field z: FixedPoint5<i32> =,
|
||||
field yaw: i8 =,
|
||||
field pitch: i8 =,
|
||||
}
|
||||
packet Advancements {
|
||||
field data: Vec<u8> =,
|
||||
/* TODO: fix parsing modded advancements 1.12.2 (e.g. SevTech Ages)
|
||||
* see https://github.com/iceiix/stevenarella/issues/148
|
||||
field reset_clear: bool =,
|
||||
field mapping: LenPrefixed<VarInt, packet::Advancement> =,
|
||||
field identifiers: LenPrefixed<VarInt, String> =,
|
||||
field progress: LenPrefixed<VarInt, packet::AdvancementProgress> =,
|
||||
*/
|
||||
}
|
||||
/// EntityProperties updates the properties for an entity.
|
||||
packet EntityProperties {
|
||||
|
@ -1675,6 +1851,12 @@ state_packets!(
|
|||
field fluid_tags: LenPrefixed<VarInt, packet::Tags> =,
|
||||
field entity_tags: LenPrefixed<VarInt, packet::Tags> =,
|
||||
}
|
||||
packet AcknowledgePlayerDigging {
|
||||
field location: Position =,
|
||||
field block: VarInt =,
|
||||
field status: VarInt =,
|
||||
field successful: bool =,
|
||||
}
|
||||
packet UpdateLight {
|
||||
field chunk_x: VarInt =,
|
||||
field chunk_z: VarInt =,
|
||||
|
@ -1683,9 +1865,23 @@ state_packets!(
|
|||
field empty_sky_light_mask: VarInt =,
|
||||
field light_arrays: Vec<u8> =,
|
||||
}
|
||||
packet TradeList {
|
||||
packet TradeList_WithoutRestock {
|
||||
field id: VarInt =,
|
||||
field trades: LenPrefixed<u8, packet::Trade> =,
|
||||
field villager_level: VarInt =,
|
||||
field experience: VarInt =,
|
||||
field is_regular_villager: bool =,
|
||||
}
|
||||
packet TradeList_WithRestock {
|
||||
field id: VarInt =,
|
||||
field trades: LenPrefixed<u8, packet::Trade> =,
|
||||
field villager_level: VarInt =,
|
||||
field experience: VarInt =,
|
||||
field is_regular_villager: bool =,
|
||||
field can_restock: bool =,
|
||||
}
|
||||
packet CoFHLib_SendUUID {
|
||||
field player_uuid: UUID =,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1997,7 +2193,8 @@ impl Serializable for Advancement {
|
|||
};
|
||||
|
||||
let criteria: LenPrefixed<VarInt, String> = Serializable::read_from(buf)?;
|
||||
let requirements: LenPrefixed<VarInt, LenPrefixed<VarInt, String>> = Serializable::read_from(buf)?;
|
||||
let requirements: LenPrefixed<VarInt, LenPrefixed<VarInt, String>> =
|
||||
Serializable::read_from(buf)?;
|
||||
Ok(Advancement {
|
||||
id,
|
||||
parent_id,
|
||||
|
@ -2014,7 +2211,6 @@ impl Serializable for Advancement {
|
|||
self.criteria.write_to(buf)?;
|
||||
self.requirements.write_to(buf)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -2068,7 +2264,6 @@ impl Serializable for AdvancementDisplay {
|
|||
self.x_coord.write_to(buf)?;
|
||||
self.y_coord.write_to(buf)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -2119,8 +2314,6 @@ impl Serializable for CriterionProgress {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EntityProperty {
|
||||
pub key: String,
|
||||
|
@ -2167,7 +2360,6 @@ impl Serializable for EntityProperty_i16 {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct PropertyModifier {
|
||||
pub uuid: UUID,
|
||||
|
@ -2238,33 +2430,25 @@ impl Serializable for PlayerInfoData {
|
|||
};
|
||||
m.players.push(p);
|
||||
}
|
||||
1 => {
|
||||
m.players.push(PlayerDetail::UpdateGamemode {
|
||||
uuid,
|
||||
gamemode: Serializable::read_from(buf)?,
|
||||
})
|
||||
}
|
||||
2 => {
|
||||
m.players.push(PlayerDetail::UpdateLatency {
|
||||
uuid,
|
||||
ping: Serializable::read_from(buf)?,
|
||||
})
|
||||
}
|
||||
3 => {
|
||||
m.players.push(PlayerDetail::UpdateDisplayName {
|
||||
uuid,
|
||||
display: {
|
||||
if bool::read_from(buf)? {
|
||||
Some(Serializable::read_from(buf)?)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
4 => {
|
||||
m.players.push(PlayerDetail::Remove { uuid: uuid })
|
||||
}
|
||||
1 => m.players.push(PlayerDetail::UpdateGamemode {
|
||||
uuid,
|
||||
gamemode: Serializable::read_from(buf)?,
|
||||
}),
|
||||
2 => m.players.push(PlayerDetail::UpdateLatency {
|
||||
uuid,
|
||||
ping: Serializable::read_from(buf)?,
|
||||
}),
|
||||
3 => m.players.push(PlayerDetail::UpdateDisplayName {
|
||||
uuid,
|
||||
display: {
|
||||
if bool::read_from(buf)? {
|
||||
Some(Serializable::read_from(buf)?)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
}),
|
||||
4 => m.players.push(PlayerDetail::Remove { uuid: uuid }),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
@ -2378,6 +2562,11 @@ pub enum RecipeData {
|
|||
experience: f32,
|
||||
cooking_time: VarInt,
|
||||
},
|
||||
Stonecutting {
|
||||
group: String,
|
||||
ingredient: RecipeIngredient,
|
||||
result: Option<item::Stack>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for RecipeData {
|
||||
|
@ -2395,17 +2584,36 @@ pub struct Recipe {
|
|||
|
||||
impl Serializable for Recipe {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
let id = String::read_from(buf)?;
|
||||
let ty = String::read_from(buf)?;
|
||||
let (id, ty) = {
|
||||
let a = String::read_from(buf)?;
|
||||
let b = String::read_from(buf)?;
|
||||
|
||||
let data =
|
||||
match ty.as_ref() {
|
||||
"crafting_shapeless" => RecipeData::Shapeless {
|
||||
let protocol_version = super::current_protocol_version();
|
||||
|
||||
// 1.14+ swaps recipe identifier and type, and adds namespace to type
|
||||
if protocol_version >= 477 {
|
||||
let ty = a;
|
||||
let id = b;
|
||||
|
||||
if ty.find(':').is_some() {
|
||||
(id, ty)
|
||||
} else {
|
||||
(id, format!("minecraft:{}", ty))
|
||||
}
|
||||
} else {
|
||||
let ty = b;
|
||||
let id = a;
|
||||
(id, format!("minecraft:{}", ty))
|
||||
}
|
||||
};
|
||||
|
||||
let data = match ty.as_ref() {
|
||||
"minecraft:crafting_shapeless" => RecipeData::Shapeless {
|
||||
group: Serializable::read_from(buf)?,
|
||||
ingredients: Serializable::read_from(buf)?,
|
||||
result: Serializable::read_from(buf)?,
|
||||
},
|
||||
"crafting_shaped" => {
|
||||
"minecraft:crafting_shaped" => {
|
||||
let width: VarInt = Serializable::read_from(buf)?;
|
||||
let height: VarInt = Serializable::read_from(buf)?;
|
||||
let group: String = Serializable::read_from(buf)?;
|
||||
|
@ -2413,56 +2621,67 @@ impl Serializable for Recipe {
|
|||
let capacity = width.0 as usize * height.0 as usize;
|
||||
|
||||
let mut ingredients = Vec::with_capacity(capacity);
|
||||
for _ in 0 .. capacity {
|
||||
for _ in 0..capacity {
|
||||
ingredients.push(Serializable::read_from(buf)?);
|
||||
}
|
||||
let result: Option<item::Stack> = Serializable::read_from(buf)?;
|
||||
|
||||
RecipeData::Shaped { width, height, group, ingredients, result }
|
||||
RecipeData::Shaped {
|
||||
width,
|
||||
height,
|
||||
group,
|
||||
ingredients,
|
||||
result,
|
||||
}
|
||||
}
|
||||
"crafting_special_armordye" => RecipeData::ArmorDye,
|
||||
"crafting_special_bookcloning" => RecipeData::BookCloning,
|
||||
"crafting_special_mapcloning" => RecipeData::MapCloning,
|
||||
"crafting_special_mapextending" => RecipeData::MapExtending,
|
||||
"crafting_special_firework_rocket" => RecipeData::FireworkRocket,
|
||||
"crafting_special_firework_star" => RecipeData::FireworkStar,
|
||||
"crafting_special_firework_star_fade" => RecipeData::FireworkStarFade,
|
||||
"crafting_special_repairitem" => RecipeData::RepairItem,
|
||||
"crafting_special_tippedarrow" => RecipeData::TippedArrow,
|
||||
"crafting_special_bannerduplicate" => RecipeData::BannerDuplicate,
|
||||
"crafting_special_banneraddpattern" => RecipeData::BannerAddPattern,
|
||||
"crafting_special_shielddecoration" => RecipeData::ShieldDecoration,
|
||||
"crafting_special_shulkerboxcoloring" => RecipeData::ShulkerBoxColoring,
|
||||
"crafting_special_suspiciousstew" => RecipeData::SuspiciousStew,
|
||||
"smelting" => RecipeData::Smelting {
|
||||
"minecraft:crafting_special_armordye" => RecipeData::ArmorDye,
|
||||
"minecraft:crafting_special_bookcloning" => RecipeData::BookCloning,
|
||||
"minecraft:crafting_special_mapcloning" => RecipeData::MapCloning,
|
||||
"minecraft:crafting_special_mapextending" => RecipeData::MapExtending,
|
||||
"minecraft:crafting_special_firework_rocket" => RecipeData::FireworkRocket,
|
||||
"minecraft:crafting_special_firework_star" => RecipeData::FireworkStar,
|
||||
"minecraft:crafting_special_firework_star_fade" => RecipeData::FireworkStarFade,
|
||||
"minecraft:crafting_special_repairitem" => RecipeData::RepairItem,
|
||||
"minecraft:crafting_special_tippedarrow" => RecipeData::TippedArrow,
|
||||
"minecraft:crafting_special_bannerduplicate" => RecipeData::BannerDuplicate,
|
||||
"minecraft:crafting_special_banneraddpattern" => RecipeData::BannerAddPattern,
|
||||
"minecraft:crafting_special_shielddecoration" => RecipeData::ShieldDecoration,
|
||||
"minecraft:crafting_special_shulkerboxcoloring" => RecipeData::ShulkerBoxColoring,
|
||||
"minecraft:crafting_special_suspiciousstew" => RecipeData::SuspiciousStew,
|
||||
"minecraft:smelting" => RecipeData::Smelting {
|
||||
group: Serializable::read_from(buf)?,
|
||||
ingredient: Serializable::read_from(buf)?,
|
||||
result: Serializable::read_from(buf)?,
|
||||
experience: Serializable::read_from(buf)?,
|
||||
cooking_time: Serializable::read_from(buf)?,
|
||||
},
|
||||
"blasting" => RecipeData::Blasting {
|
||||
"minecraft:blasting" => RecipeData::Blasting {
|
||||
group: Serializable::read_from(buf)?,
|
||||
ingredient: Serializable::read_from(buf)?,
|
||||
result: Serializable::read_from(buf)?,
|
||||
experience: Serializable::read_from(buf)?,
|
||||
cooking_time: Serializable::read_from(buf)?,
|
||||
},
|
||||
"smoking" => RecipeData::Smoking {
|
||||
"minecraft:smoking" => RecipeData::Smoking {
|
||||
group: Serializable::read_from(buf)?,
|
||||
ingredient: Serializable::read_from(buf)?,
|
||||
result: Serializable::read_from(buf)?,
|
||||
experience: Serializable::read_from(buf)?,
|
||||
cooking_time: Serializable::read_from(buf)?,
|
||||
},
|
||||
"campfire" => RecipeData::Campfire {
|
||||
"minecraft:campfire" | "minecraft:campfire_cooking" => RecipeData::Campfire {
|
||||
group: Serializable::read_from(buf)?,
|
||||
ingredient: Serializable::read_from(buf)?,
|
||||
result: Serializable::read_from(buf)?,
|
||||
experience: Serializable::read_from(buf)?,
|
||||
cooking_time: Serializable::read_from(buf)?,
|
||||
},
|
||||
_ => panic!("unrecognized recipe type: {}", ty)
|
||||
"minecraft:stonecutting" => RecipeData::Stonecutting {
|
||||
group: Serializable::read_from(buf)?,
|
||||
ingredient: Serializable::read_from(buf)?,
|
||||
result: Serializable::read_from(buf)?,
|
||||
},
|
||||
_ => panic!("unrecognized recipe type: {}", ty),
|
||||
};
|
||||
|
||||
Ok(Recipe { id, ty, data })
|
||||
|
@ -2501,10 +2720,16 @@ pub struct Trade {
|
|||
pub trades_disabled: bool,
|
||||
pub tool_uses: i32,
|
||||
pub max_trade_uses: i32,
|
||||
pub xp: i32,
|
||||
pub special_price: i32,
|
||||
pub price_multiplier: f32,
|
||||
pub demand: Option<i32>,
|
||||
}
|
||||
|
||||
impl Serializable for Trade {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
let protocol_version = super::current_protocol_version();
|
||||
|
||||
Ok(Trade {
|
||||
input_item_1: Serializable::read_from(buf)?,
|
||||
output_item: Serializable::read_from(buf)?,
|
||||
|
@ -2513,6 +2738,14 @@ impl Serializable for Trade {
|
|||
trades_disabled: Serializable::read_from(buf)?,
|
||||
tool_uses: Serializable::read_from(buf)?,
|
||||
max_trade_uses: Serializable::read_from(buf)?,
|
||||
xp: Serializable::read_from(buf)?,
|
||||
special_price: Serializable::read_from(buf)?,
|
||||
price_multiplier: Serializable::read_from(buf)?,
|
||||
demand: if protocol_version >= 498 {
|
||||
Some(Serializable::read_from(buf)?)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2521,7 +2754,6 @@ impl Serializable for Trade {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct CommandNode {
|
||||
pub flags: u8,
|
||||
|
@ -2566,6 +2798,8 @@ pub enum CommandProperty {
|
|||
},
|
||||
GameProfile,
|
||||
BlockPos,
|
||||
ColumnPos,
|
||||
Time,
|
||||
Vec3,
|
||||
Vec2,
|
||||
BlockState,
|
||||
|
@ -2577,6 +2811,8 @@ pub enum CommandProperty {
|
|||
Message,
|
||||
Nbt,
|
||||
NbtPath,
|
||||
NbtTag,
|
||||
NbtCompoundTag,
|
||||
Objective,
|
||||
ObjectiveCriteria,
|
||||
Operation,
|
||||
|
@ -2596,10 +2832,13 @@ pub enum CommandProperty {
|
|||
Range {
|
||||
decimals: bool,
|
||||
},
|
||||
IntRange,
|
||||
FloatRange,
|
||||
ItemEnchantment,
|
||||
EntitySummon,
|
||||
Dimension,
|
||||
}
|
||||
|
||||
|
||||
impl Serializable for CommandNode {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, Error> {
|
||||
let flags: u8 = Serializable::read_from(buf)?;
|
||||
|
@ -2621,11 +2860,12 @@ impl Serializable for CommandNode {
|
|||
None
|
||||
};
|
||||
|
||||
let name: Option<String> = if node_type == CommandNodeType::Argument || node_type == CommandNodeType::Literal {
|
||||
Serializable::read_from(buf)?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let name: Option<String> =
|
||||
if node_type == CommandNodeType::Argument || node_type == CommandNodeType::Literal {
|
||||
Serializable::read_from(buf)?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let parser: Option<String> = if node_type == CommandNodeType::Argument {
|
||||
Serializable::read_from(buf)?
|
||||
} else {
|
||||
|
@ -2637,30 +2877,56 @@ impl Serializable for CommandNode {
|
|||
"brigadier:bool" => CommandProperty::Bool,
|
||||
"brigadier:double" => {
|
||||
let flags = Serializable::read_from(buf)?;
|
||||
let min = if flags & 0x01 != 0 { Some(Serializable::read_from(buf)?) } else { None };
|
||||
let max = if flags & 0x02 != 0 { Some(Serializable::read_from(buf)?) } else { None };
|
||||
let min = if flags & 0x01 != 0 {
|
||||
Some(Serializable::read_from(buf)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let max = if flags & 0x02 != 0 {
|
||||
Some(Serializable::read_from(buf)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
CommandProperty::Double { flags, min, max }
|
||||
},
|
||||
}
|
||||
"brigadier:float" => {
|
||||
let flags = Serializable::read_from(buf)?;
|
||||
let min = if flags & 0x01 != 0 { Some(Serializable::read_from(buf)?) } else { None };
|
||||
let max = if flags & 0x02 != 0 { Some(Serializable::read_from(buf)?) } else { None };
|
||||
let min = if flags & 0x01 != 0 {
|
||||
Some(Serializable::read_from(buf)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let max = if flags & 0x02 != 0 {
|
||||
Some(Serializable::read_from(buf)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
CommandProperty::Float { flags, min, max }
|
||||
},
|
||||
}
|
||||
"brigadier:integer" => {
|
||||
let flags = Serializable::read_from(buf)?;
|
||||
let min = if flags & 0x01 != 0 { Some(Serializable::read_from(buf)?) } else { None };
|
||||
let max = if flags & 0x02 != 0 { Some(Serializable::read_from(buf)?) } else { None };
|
||||
let min = if flags & 0x01 != 0 {
|
||||
Some(Serializable::read_from(buf)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let max = if flags & 0x02 != 0 {
|
||||
Some(Serializable::read_from(buf)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
CommandProperty::Integer { flags, min, max }
|
||||
}
|
||||
"brigadier:string" => CommandProperty::String {
|
||||
token_type: Serializable::read_from(buf)?,
|
||||
},
|
||||
"brigadier:string" => {
|
||||
CommandProperty::String { token_type: Serializable::read_from(buf)? }
|
||||
},
|
||||
"minecraft:entity" => {
|
||||
CommandProperty::Entity { flags: Serializable::read_from(buf)? }
|
||||
"minecraft:entity" => CommandProperty::Entity {
|
||||
flags: Serializable::read_from(buf)?,
|
||||
},
|
||||
"minecraft:game_profile" => CommandProperty::GameProfile,
|
||||
"minecraft:block_pos" => CommandProperty::BlockPos,
|
||||
"minecraft:column_pos" => CommandProperty::ColumnPos,
|
||||
"minecraft:time" => CommandProperty::Time,
|
||||
"minecraft:vec3" => CommandProperty::Vec3,
|
||||
"minecraft:vec2" => CommandProperty::Vec2,
|
||||
"minecraft:block_state" => CommandProperty::BlockState,
|
||||
|
@ -2672,14 +2938,16 @@ impl Serializable for CommandNode {
|
|||
"minecraft:message" => CommandProperty::Message,
|
||||
"minecraft:nbt" => CommandProperty::Nbt,
|
||||
"minecraft:nbt_path" => CommandProperty::NbtPath,
|
||||
"minecraft:nbt_tag" => CommandProperty::NbtTag,
|
||||
"minecraft:nbt_compound_tag" => CommandProperty::NbtCompoundTag,
|
||||
"minecraft:objective" => CommandProperty::Objective,
|
||||
"minecraft:objective_criteria" => CommandProperty::ObjectiveCriteria,
|
||||
"minecraft:operation" => CommandProperty::Operation,
|
||||
"minecraft:particle" => CommandProperty::Particle,
|
||||
"minecraft:rotation" => CommandProperty::Rotation,
|
||||
"minecraft:scoreboard_slot" => CommandProperty::ScoreboardSlot,
|
||||
"minecraft:score_holder" => {
|
||||
CommandProperty::ScoreHolder { flags: Serializable::read_from(buf)? }
|
||||
"minecraft:score_holder" => CommandProperty::ScoreHolder {
|
||||
flags: Serializable::read_from(buf)?,
|
||||
},
|
||||
"minecraft:swizzle" => CommandProperty::Swizzle,
|
||||
"minecraft:team" => CommandProperty::Team,
|
||||
|
@ -2688,10 +2956,14 @@ impl Serializable for CommandNode {
|
|||
"minecraft:mob_effect" => CommandProperty::MobEffect,
|
||||
"minecraft:function" => CommandProperty::Function,
|
||||
"minecraft:entity_anchor" => CommandProperty::EntityAnchor,
|
||||
"minecraft:range" => {
|
||||
CommandProperty::Range { decimals: Serializable::read_from(buf)? }
|
||||
"minecraft:range" => CommandProperty::Range {
|
||||
decimals: Serializable::read_from(buf)?,
|
||||
},
|
||||
"minecraft:int_range" => CommandProperty::IntRange,
|
||||
"minecraft:float_range" => CommandProperty::FloatRange,
|
||||
"minecraft:item_enchantment" => CommandProperty::ItemEnchantment,
|
||||
"minecraft:entity_summon" => CommandProperty::EntitySummon,
|
||||
"minecraft:dimension" => CommandProperty::Dimension,
|
||||
_ => panic!("unsupported command node parser {}", parse),
|
||||
})
|
||||
} else {
|
||||
|
@ -2704,12 +2976,18 @@ impl Serializable for CommandNode {
|
|||
None
|
||||
};
|
||||
|
||||
Ok(CommandNode { flags, children, redirect_node, name, parser, properties, suggestions_type })
|
||||
Ok(CommandNode {
|
||||
flags,
|
||||
children,
|
||||
redirect_node,
|
||||
name,
|
||||
parser,
|
||||
properties,
|
||||
suggestions_type,
|
||||
})
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, _: &mut W) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
use super::*;
|
||||
|
||||
mod v15w39c;
|
||||
mod v18w50a;
|
||||
mod v19w02a;
|
||||
mod v1_10_2;
|
||||
mod v1_11_2;
|
||||
mod v1_12_2;
|
||||
mod v1_13_2;
|
||||
mod v1_14;
|
||||
mod v1_14_1;
|
||||
mod v1_14_2;
|
||||
mod v1_14_3;
|
||||
mod v1_14_4;
|
||||
mod v1_15_1;
|
||||
mod v1_7_10;
|
||||
mod v1_8_9;
|
||||
mod v1_9;
|
||||
mod v1_9_2;
|
||||
|
||||
// https://wiki.vg/Protocol_History
|
||||
// https://wiki.vg/Protocol_version_numbers#Versions_after_the_Netty_rewrite
|
||||
|
||||
pub fn protocol_name_to_protocol_version(s: String) -> i32 {
|
||||
match s.as_ref() {
|
||||
"" => SUPPORTED_PROTOCOLS[0],
|
||||
"1.15.1" => 575,
|
||||
"1.14.4" => 498,
|
||||
"1.14.3" => 490,
|
||||
"1.14.2" => 485,
|
||||
"1.14.1" => 480,
|
||||
"1.14" => 477,
|
||||
"19w02a" => 452,
|
||||
"18w50a" => 451,
|
||||
"1.13.2" => 404,
|
||||
"1.12.2" => 340,
|
||||
"1.11.2" => 316,
|
||||
"1.11" => 315,
|
||||
"1.10.2" => 210,
|
||||
"1.9.2" => 109,
|
||||
"1.9" => 107,
|
||||
"15w39c" => 74,
|
||||
"1.8.9" => 47,
|
||||
"1.7.10" => 5,
|
||||
_ => {
|
||||
if let Ok(n) = s.parse::<i32>() {
|
||||
n
|
||||
} else {
|
||||
panic!("Unrecognized protocol name: {}", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn translate_internal_packet_id_for_version(
|
||||
version: i32,
|
||||
state: State,
|
||||
dir: Direction,
|
||||
id: i32,
|
||||
to_internal: bool,
|
||||
) -> i32 {
|
||||
match version {
|
||||
575 => v1_15_1::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
498 => v1_14_4::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
490 => v1_14_3::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
485 => v1_14_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
480 => v1_14_1::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
477 => v1_14::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
452 => v19w02a::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
451 => v18w50a::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
404 => v1_13_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
340 => v1_12_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
316 => v1_11_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
315 => v1_11_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
210 => v1_10_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
109 => v1_9_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
107 => v1_9::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
74 => v15w39c::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
47 => v1_8_9::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
5 => v1_7_10::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
_ => panic!("unsupported protocol version: {}", version),
|
||||
}
|
||||
}
|
|
@ -71,7 +71,7 @@ protocol_packet_ids!(
|
|||
0x1f => KeepAliveClientbound_VarInt
|
||||
0x20 => ChunkData_NoEntities
|
||||
0x21 => Effect
|
||||
0x22 => Particle
|
||||
0x22 => Particle_VarIntArray
|
||||
0x23 => NamedSoundEffect_u8_NoCategory
|
||||
0x24 => JoinGame_i8
|
||||
0x25 => Maps
|
||||
|
@ -101,7 +101,7 @@ protocol_packet_ids!(
|
|||
0x3d => SetExperience
|
||||
0x3e => UpdateHealth
|
||||
0x3f => ScoreboardObjective
|
||||
0x40 => Teams
|
||||
0x40 => Teams_u8
|
||||
0x41 => UpdateScore
|
||||
0x42 => SpawnPosition
|
||||
0x43 => TimeUpdate
|
||||
|
@ -137,5 +137,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -56,8 +56,8 @@ protocol_packet_ids!(
|
|||
0x00 => SpawnObject
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob
|
||||
0x04 => SpawnPainting
|
||||
0x03 => SpawnMob_WithMeta
|
||||
0x04 => SpawnPainting_String
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
|
@ -89,7 +89,7 @@ protocol_packet_ids!(
|
|||
0x21 => KeepAliveClientbound_i64
|
||||
0x22 => ChunkData_HeightMap
|
||||
0x23 => Effect
|
||||
0x24 => Particle
|
||||
0x24 => Particle_VarIntArray
|
||||
0x25 => JoinGame_i32
|
||||
0x26 => Maps
|
||||
0x27 => Entity
|
||||
|
@ -125,7 +125,7 @@ protocol_packet_ids!(
|
|||
0x45 => UpdateHealth
|
||||
0x46 => ScoreboardObjective
|
||||
0x47 => SetPassengers
|
||||
0x48 => Teams
|
||||
0x48 => Teams_u8
|
||||
0x49 => UpdateScore
|
||||
0x4a => SpawnPosition
|
||||
0x4b => TimeUpdate
|
||||
|
@ -168,5 +168,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -56,8 +56,8 @@ protocol_packet_ids!(
|
|||
0x00 => SpawnObject
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob
|
||||
0x04 => SpawnPainting
|
||||
0x03 => SpawnMob_WithMeta
|
||||
0x04 => SpawnPainting_String
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
|
@ -89,7 +89,7 @@ protocol_packet_ids!(
|
|||
0x21 => KeepAliveClientbound_i64
|
||||
0x22 => ChunkData_HeightMap
|
||||
0x23 => Effect
|
||||
0x24 => Particle
|
||||
0x24 => Particle_Data
|
||||
0x25 => JoinGame_i32
|
||||
0x26 => Maps
|
||||
0x27 => Entity
|
||||
|
@ -125,7 +125,7 @@ protocol_packet_ids!(
|
|||
0x45 => UpdateHealth
|
||||
0x46 => ScoreboardObjective
|
||||
0x47 => SetPassengers
|
||||
0x48 => Teams
|
||||
0x48 => Teams_u8
|
||||
0x49 => UpdateScore
|
||||
0x4a => SpawnPosition
|
||||
0x4b => TimeUpdate
|
||||
|
@ -142,7 +142,7 @@ protocol_packet_ids!(
|
|||
0x57 => TagsWithEntities
|
||||
0x58 => UpdateLight
|
||||
0x59 => WindowOpen_VarInt
|
||||
0x5a => TradeList
|
||||
0x5a => TradeList_WithoutRestock // TODO: without 1.14 added fields
|
||||
}
|
||||
}
|
||||
login Login {
|
||||
|
@ -170,5 +170,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ protocol_packet_ids!(
|
|||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob_u8
|
||||
0x04 => SpawnPainting
|
||||
0x04 => SpawnPainting_String
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
|
@ -74,7 +74,7 @@ protocol_packet_ids!(
|
|||
0x1f => KeepAliveClientbound_VarInt
|
||||
0x20 => ChunkData
|
||||
0x21 => Effect
|
||||
0x22 => Particle
|
||||
0x22 => Particle_VarIntArray
|
||||
0x23 => JoinGame_i32
|
||||
0x24 => Maps
|
||||
0x25 => EntityMove_i16
|
||||
|
@ -105,7 +105,7 @@ protocol_packet_ids!(
|
|||
0x3e => UpdateHealth
|
||||
0x3f => ScoreboardObjective
|
||||
0x40 => SetPassengers
|
||||
0x41 => Teams
|
||||
0x41 => Teams_u8
|
||||
0x42 => UpdateScore
|
||||
0x43 => SpawnPosition
|
||||
0x44 => TimeUpdate
|
||||
|
@ -141,5 +141,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -43,8 +43,8 @@ protocol_packet_ids!(
|
|||
0x00 => SpawnObject
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob
|
||||
0x04 => SpawnPainting
|
||||
0x03 => SpawnMob_WithMeta
|
||||
0x04 => SpawnPainting_String
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
|
@ -74,7 +74,7 @@ protocol_packet_ids!(
|
|||
0x1f => KeepAliveClientbound_VarInt
|
||||
0x20 => ChunkData
|
||||
0x21 => Effect
|
||||
0x22 => Particle
|
||||
0x22 => Particle_VarIntArray
|
||||
0x23 => JoinGame_i32
|
||||
0x24 => Maps
|
||||
0x25 => EntityMove_i16
|
||||
|
@ -105,7 +105,7 @@ protocol_packet_ids!(
|
|||
0x3e => UpdateHealth
|
||||
0x3f => ScoreboardObjective
|
||||
0x40 => SetPassengers
|
||||
0x41 => Teams
|
||||
0x41 => Teams_u8
|
||||
0x42 => UpdateScore
|
||||
0x43 => SpawnPosition
|
||||
0x44 => TimeUpdate
|
||||
|
@ -141,5 +141,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -46,8 +46,8 @@ protocol_packet_ids!(
|
|||
0x00 => SpawnObject
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob
|
||||
0x04 => SpawnPainting
|
||||
0x03 => SpawnMob_WithMeta
|
||||
0x04 => SpawnPainting_VarInt
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
|
@ -77,7 +77,7 @@ protocol_packet_ids!(
|
|||
0x1f => KeepAliveClientbound_i64
|
||||
0x20 => ChunkData
|
||||
0x21 => Effect
|
||||
0x22 => Particle
|
||||
0x22 => Particle_VarIntArray
|
||||
0x23 => JoinGame_i32
|
||||
0x24 => Maps
|
||||
0x25 => Entity
|
||||
|
@ -111,7 +111,7 @@ protocol_packet_ids!(
|
|||
0x41 => UpdateHealth
|
||||
0x42 => ScoreboardObjective
|
||||
0x43 => SetPassengers
|
||||
0x44 => Teams
|
||||
0x44 => Teams_u8
|
||||
0x45 => UpdateScore
|
||||
0x46 => SpawnPosition
|
||||
0x47 => TimeUpdate
|
||||
|
@ -148,5 +148,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -56,8 +56,8 @@ protocol_packet_ids!(
|
|||
0x00 => SpawnObject
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob
|
||||
0x04 => SpawnPainting
|
||||
0x03 => SpawnMob_WithMeta
|
||||
0x04 => SpawnPainting_VarInt
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
|
@ -89,7 +89,7 @@ protocol_packet_ids!(
|
|||
0x21 => KeepAliveClientbound_i64
|
||||
0x22 => ChunkData
|
||||
0x23 => Effect
|
||||
0x24 => Particle
|
||||
0x24 => Particle_Data
|
||||
0x25 => JoinGame_i32
|
||||
0x26 => Maps
|
||||
0x27 => Entity
|
||||
|
@ -124,7 +124,7 @@ protocol_packet_ids!(
|
|||
0x44 => UpdateHealth
|
||||
0x45 => ScoreboardObjective
|
||||
0x46 => SetPassengers
|
||||
0x47 => Teams
|
||||
0x47 => Teams_VarInt
|
||||
0x48 => UpdateScore
|
||||
0x49 => SpawnPosition
|
||||
0x4a => TimeUpdate
|
||||
|
@ -165,5 +165,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
protocol_packet_ids!(
|
||||
handshake Handshaking {
|
||||
serverbound Serverbound {
|
||||
0x00 => Handshake
|
||||
}
|
||||
clientbound Clientbound {
|
||||
}
|
||||
}
|
||||
play Play {
|
||||
serverbound Serverbound {
|
||||
0x00 => TeleportConfirm
|
||||
0x01 => QueryBlockNBT
|
||||
0x02 => SetDifficulty
|
||||
0x03 => ChatMessage
|
||||
0x04 => ClientStatus
|
||||
0x05 => ClientSettings
|
||||
0x06 => TabComplete
|
||||
0x07 => ConfirmTransactionServerbound
|
||||
0x08 => ClickWindowButton
|
||||
0x09 => ClickWindow
|
||||
0x0a => CloseWindow
|
||||
0x0b => PluginMessageServerbound
|
||||
0x0c => EditBook
|
||||
0x0d => QueryEntityNBT
|
||||
0x0e => UseEntity
|
||||
0x0f => KeepAliveServerbound_i64
|
||||
0x10 => LockDifficulty
|
||||
0x11 => PlayerPosition
|
||||
0x12 => PlayerPositionLook
|
||||
0x13 => PlayerLook
|
||||
0x14 => Player
|
||||
0x15 => VehicleMove
|
||||
0x16 => SteerBoat
|
||||
0x17 => PickItem
|
||||
0x18 => CraftRecipeRequest
|
||||
0x19 => ClientAbilities
|
||||
0x1a => PlayerDigging
|
||||
0x1b => PlayerAction
|
||||
0x1c => SteerVehicle
|
||||
0x1d => CraftingBookData
|
||||
0x1e => NameItem
|
||||
0x1f => ResourcePackStatus
|
||||
0x20 => AdvancementTab
|
||||
0x21 => SelectTrade
|
||||
0x22 => SetBeaconEffect
|
||||
0x23 => HeldItemChange
|
||||
0x24 => UpdateCommandBlock
|
||||
0x25 => UpdateCommandBlockMinecart
|
||||
0x26 => CreativeInventoryAction
|
||||
0x27 => UpdateJigsawBlock
|
||||
0x28 => UpdateStructureBlock
|
||||
0x29 => SetSign
|
||||
0x2a => ArmSwing
|
||||
0x2b => SpectateTeleport
|
||||
0x2c => PlayerBlockPlacement_f32
|
||||
0x2d => UseItem
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => SpawnObject
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob_WithMeta
|
||||
0x04 => SpawnPainting_VarInt
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
0x08 => BlockBreakAnimation
|
||||
0x09 => UpdateBlockEntity
|
||||
0x0a => BlockAction
|
||||
0x0b => BlockChange_VarInt
|
||||
0x0c => BossBar
|
||||
0x0d => ServerDifficulty_Locked
|
||||
0x0e => ServerMessage
|
||||
0x0f => MultiBlockChange_VarInt
|
||||
0x10 => TabCompleteReply
|
||||
0x11 => DeclareCommands
|
||||
0x12 => ConfirmTransaction
|
||||
0x13 => WindowClose
|
||||
0x14 => WindowItems
|
||||
0x15 => WindowProperty
|
||||
0x16 => WindowSetSlot
|
||||
0x17 => SetCooldown
|
||||
0x18 => PluginMessageClientbound
|
||||
0x19 => NamedSoundEffect
|
||||
0x1a => Disconnect
|
||||
0x1b => EntityAction
|
||||
0x1c => Explosion
|
||||
0x1d => ChunkUnload
|
||||
0x1e => ChangeGameState
|
||||
0x1f => WindowOpenHorse
|
||||
0x20 => KeepAliveClientbound_i64
|
||||
0x21 => ChunkData_HeightMap
|
||||
0x22 => Effect
|
||||
0x23 => Particle_Data
|
||||
0x24 => UpdateLight
|
||||
0x25 => JoinGame_i32_ViewDistance
|
||||
0x26 => Maps
|
||||
0x27 => TradeList_WithoutRestock
|
||||
0x28 => EntityMove_i16
|
||||
0x29 => EntityLookAndMove_i16
|
||||
0x2a => EntityLook_VarInt
|
||||
0x2b => Entity
|
||||
0x2c => VehicleTeleport
|
||||
0x2d => OpenBook
|
||||
0x2e => WindowOpen_VarInt
|
||||
0x2f => SignEditorOpen
|
||||
0x30 => CraftRecipeResponse
|
||||
0x31 => PlayerAbilities
|
||||
0x32 => CombatEvent
|
||||
0x33 => PlayerInfo
|
||||
0x34 => FacePlayer
|
||||
0x35 => TeleportPlayer_WithConfirm
|
||||
0x36 => UnlockRecipes_WithSmelting
|
||||
0x37 => EntityDestroy
|
||||
0x38 => EntityRemoveEffect
|
||||
0x39 => ResourcePackSend
|
||||
0x3a => Respawn
|
||||
0x3b => EntityHeadLook
|
||||
0x3c => SelectAdvancementTab
|
||||
0x3d => WorldBorder
|
||||
0x3e => Camera
|
||||
0x3f => SetCurrentHotbarSlot
|
||||
0x40 => UpdateViewPosition
|
||||
0x41 => UpdateViewDistance
|
||||
0x42 => ScoreboardDisplay
|
||||
0x43 => EntityMetadata
|
||||
0x44 => EntityAttach
|
||||
0x45 => EntityVelocity
|
||||
0x46 => EntityEquipment
|
||||
0x47 => SetExperience
|
||||
0x48 => UpdateHealth
|
||||
0x49 => ScoreboardObjective
|
||||
0x4a => SetPassengers
|
||||
0x4b => Teams_VarInt
|
||||
0x4c => UpdateScore
|
||||
0x4d => SpawnPosition
|
||||
0x4e => TimeUpdate
|
||||
0x4f => Title
|
||||
0x50 => EntitySoundEffect
|
||||
0x51 => SoundEffect
|
||||
0x52 => StopSound
|
||||
0x53 => PlayerListHeaderFooter
|
||||
0x54 => NBTQueryResponse
|
||||
0x55 => CollectItem
|
||||
0x56 => EntityTeleport_f64
|
||||
0x57 => Advancements
|
||||
0x58 => EntityProperties
|
||||
0x59 => EntityEffect
|
||||
0x5a => DeclareRecipes
|
||||
0x5b => TagsWithEntities
|
||||
}
|
||||
}
|
||||
login Login {
|
||||
serverbound Serverbound {
|
||||
0x00 => LoginStart
|
||||
0x01 => EncryptionResponse
|
||||
0x02 => LoginPluginResponse
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => LoginDisconnect
|
||||
0x01 => EncryptionRequest
|
||||
0x02 => LoginSuccess
|
||||
0x03 => SetInitialCompression
|
||||
0x04 => LoginPluginRequest
|
||||
}
|
||||
}
|
||||
status Status {
|
||||
serverbound Serverbound {
|
||||
0x00 => StatusRequest
|
||||
0x01 => StatusPing
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => StatusResponse
|
||||
0x01 => StatusPong
|
||||
}
|
||||
}
|
||||
);
|
|
@ -0,0 +1,177 @@
|
|||
protocol_packet_ids!(
|
||||
handshake Handshaking {
|
||||
serverbound Serverbound {
|
||||
0x00 => Handshake
|
||||
}
|
||||
clientbound Clientbound {
|
||||
}
|
||||
}
|
||||
play Play {
|
||||
serverbound Serverbound {
|
||||
0x00 => TeleportConfirm
|
||||
0x01 => QueryBlockNBT
|
||||
0x02 => SetDifficulty
|
||||
0x03 => ChatMessage
|
||||
0x04 => ClientStatus
|
||||
0x05 => ClientSettings
|
||||
0x06 => TabComplete
|
||||
0x07 => ConfirmTransactionServerbound
|
||||
0x08 => ClickWindowButton
|
||||
0x09 => ClickWindow
|
||||
0x0a => CloseWindow
|
||||
0x0b => PluginMessageServerbound
|
||||
0x0c => EditBook
|
||||
0x0d => QueryEntityNBT
|
||||
0x0e => UseEntity
|
||||
0x0f => KeepAliveServerbound_i64
|
||||
0x10 => LockDifficulty
|
||||
0x11 => PlayerPosition
|
||||
0x12 => PlayerPositionLook
|
||||
0x13 => PlayerLook
|
||||
0x14 => Player
|
||||
0x15 => VehicleMove
|
||||
0x16 => SteerBoat
|
||||
0x17 => PickItem
|
||||
0x18 => CraftRecipeRequest
|
||||
0x19 => ClientAbilities
|
||||
0x1a => PlayerDigging
|
||||
0x1b => PlayerAction
|
||||
0x1c => SteerVehicle
|
||||
0x1d => CraftingBookData
|
||||
0x1e => NameItem
|
||||
0x1f => ResourcePackStatus
|
||||
0x20 => AdvancementTab
|
||||
0x21 => SelectTrade
|
||||
0x22 => SetBeaconEffect
|
||||
0x23 => HeldItemChange
|
||||
0x24 => UpdateCommandBlock
|
||||
0x25 => UpdateCommandBlockMinecart
|
||||
0x26 => CreativeInventoryAction
|
||||
0x27 => UpdateJigsawBlock
|
||||
0x28 => UpdateStructureBlock
|
||||
0x29 => SetSign
|
||||
0x2a => ArmSwing
|
||||
0x2b => SpectateTeleport
|
||||
0x2c => PlayerBlockPlacement_f32
|
||||
0x2d => UseItem
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => SpawnObject
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob_WithMeta
|
||||
0x04 => SpawnPainting_VarInt
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
0x08 => BlockBreakAnimation
|
||||
0x09 => UpdateBlockEntity
|
||||
0x0a => BlockAction
|
||||
0x0b => BlockChange_VarInt
|
||||
0x0c => BossBar
|
||||
0x0d => ServerDifficulty_Locked
|
||||
0x0e => ServerMessage
|
||||
0x0f => MultiBlockChange_VarInt
|
||||
0x10 => TabCompleteReply
|
||||
0x11 => DeclareCommands
|
||||
0x12 => ConfirmTransaction
|
||||
0x13 => WindowClose
|
||||
0x14 => WindowItems
|
||||
0x15 => WindowProperty
|
||||
0x16 => WindowSetSlot
|
||||
0x17 => SetCooldown
|
||||
0x18 => PluginMessageClientbound
|
||||
0x19 => NamedSoundEffect
|
||||
0x1a => Disconnect
|
||||
0x1b => EntityAction
|
||||
0x1c => Explosion
|
||||
0x1d => ChunkUnload
|
||||
0x1e => ChangeGameState
|
||||
0x1f => WindowOpenHorse
|
||||
0x20 => KeepAliveClientbound_i64
|
||||
0x21 => ChunkData_HeightMap
|
||||
0x22 => Effect
|
||||
0x23 => Particle_Data
|
||||
0x24 => UpdateLight
|
||||
0x25 => JoinGame_i32_ViewDistance
|
||||
0x26 => Maps
|
||||
0x27 => TradeList_WithoutRestock
|
||||
0x28 => EntityMove_i16
|
||||
0x29 => EntityLookAndMove_i16
|
||||
0x2a => EntityLook_VarInt
|
||||
0x2b => Entity
|
||||
0x2c => VehicleTeleport
|
||||
0x2d => OpenBook
|
||||
0x2e => WindowOpen_VarInt
|
||||
0x2f => SignEditorOpen
|
||||
0x30 => CraftRecipeResponse
|
||||
0x31 => PlayerAbilities
|
||||
0x32 => CombatEvent
|
||||
0x33 => PlayerInfo
|
||||
0x34 => FacePlayer
|
||||
0x35 => TeleportPlayer_WithConfirm
|
||||
0x36 => UnlockRecipes_WithSmelting
|
||||
0x37 => EntityDestroy
|
||||
0x38 => EntityRemoveEffect
|
||||
0x39 => ResourcePackSend
|
||||
0x3a => Respawn
|
||||
0x3b => EntityHeadLook
|
||||
0x3c => SelectAdvancementTab
|
||||
0x3d => WorldBorder
|
||||
0x3e => Camera
|
||||
0x3f => SetCurrentHotbarSlot
|
||||
0x40 => UpdateViewPosition
|
||||
0x41 => UpdateViewDistance
|
||||
0x42 => ScoreboardDisplay
|
||||
0x43 => EntityMetadata
|
||||
0x44 => EntityAttach
|
||||
0x45 => EntityVelocity
|
||||
0x46 => EntityEquipment
|
||||
0x47 => SetExperience
|
||||
0x48 => UpdateHealth
|
||||
0x49 => ScoreboardObjective
|
||||
0x4a => SetPassengers
|
||||
0x4b => Teams_VarInt
|
||||
0x4c => UpdateScore
|
||||
0x4d => SpawnPosition
|
||||
0x4e => TimeUpdate
|
||||
0x4f => Title
|
||||
0x50 => EntitySoundEffect
|
||||
0x51 => SoundEffect
|
||||
0x52 => StopSound
|
||||
0x53 => PlayerListHeaderFooter
|
||||
0x54 => NBTQueryResponse
|
||||
0x55 => CollectItem
|
||||
0x56 => EntityTeleport_f64
|
||||
0x57 => Advancements
|
||||
0x58 => EntityProperties
|
||||
0x59 => EntityEffect
|
||||
0x5a => DeclareRecipes
|
||||
0x5b => TagsWithEntities
|
||||
}
|
||||
}
|
||||
login Login {
|
||||
serverbound Serverbound {
|
||||
0x00 => LoginStart
|
||||
0x01 => EncryptionResponse
|
||||
0x02 => LoginPluginResponse
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => LoginDisconnect
|
||||
0x01 => EncryptionRequest
|
||||
0x02 => LoginSuccess
|
||||
0x03 => SetInitialCompression
|
||||
0x04 => LoginPluginRequest
|
||||
}
|
||||
}
|
||||
status Status {
|
||||
serverbound Serverbound {
|
||||
0x00 => StatusRequest
|
||||
0x01 => StatusPing
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => StatusResponse
|
||||
0x01 => StatusPong
|
||||
}
|
||||
}
|
||||
);
|
|
@ -0,0 +1,177 @@
|
|||
protocol_packet_ids!(
|
||||
handshake Handshaking {
|
||||
serverbound Serverbound {
|
||||
0x00 => Handshake
|
||||
}
|
||||
clientbound Clientbound {
|
||||
}
|
||||
}
|
||||
play Play {
|
||||
serverbound Serverbound {
|
||||
0x00 => TeleportConfirm
|
||||
0x01 => QueryBlockNBT
|
||||
0x02 => SetDifficulty
|
||||
0x03 => ChatMessage
|
||||
0x04 => ClientStatus
|
||||
0x05 => ClientSettings
|
||||
0x06 => TabComplete
|
||||
0x07 => ConfirmTransactionServerbound
|
||||
0x08 => ClickWindowButton
|
||||
0x09 => ClickWindow
|
||||
0x0a => CloseWindow
|
||||
0x0b => PluginMessageServerbound
|
||||
0x0c => EditBook
|
||||
0x0d => QueryEntityNBT
|
||||
0x0e => UseEntity
|
||||
0x0f => KeepAliveServerbound_i64
|
||||
0x10 => LockDifficulty
|
||||
0x11 => PlayerPosition
|
||||
0x12 => PlayerPositionLook
|
||||
0x13 => PlayerLook
|
||||
0x14 => Player
|
||||
0x15 => VehicleMove
|
||||
0x16 => SteerBoat
|
||||
0x17 => PickItem
|
||||
0x18 => CraftRecipeRequest
|
||||
0x19 => ClientAbilities
|
||||
0x1a => PlayerDigging
|
||||
0x1b => PlayerAction
|
||||
0x1c => SteerVehicle
|
||||
0x1d => CraftingBookData
|
||||
0x1e => NameItem
|
||||
0x1f => ResourcePackStatus
|
||||
0x20 => AdvancementTab
|
||||
0x21 => SelectTrade
|
||||
0x22 => SetBeaconEffect
|
||||
0x23 => HeldItemChange
|
||||
0x24 => UpdateCommandBlock
|
||||
0x25 => UpdateCommandBlockMinecart
|
||||
0x26 => CreativeInventoryAction
|
||||
0x27 => UpdateJigsawBlock
|
||||
0x28 => UpdateStructureBlock
|
||||
0x29 => SetSign
|
||||
0x2a => ArmSwing
|
||||
0x2b => SpectateTeleport
|
||||
0x2c => PlayerBlockPlacement_f32
|
||||
0x2d => UseItem
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => SpawnObject
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob_WithMeta
|
||||
0x04 => SpawnPainting_VarInt
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
0x08 => BlockBreakAnimation
|
||||
0x09 => UpdateBlockEntity
|
||||
0x0a => BlockAction
|
||||
0x0b => BlockChange_VarInt
|
||||
0x0c => BossBar
|
||||
0x0d => ServerDifficulty_Locked
|
||||
0x0e => ServerMessage
|
||||
0x0f => MultiBlockChange_VarInt
|
||||
0x10 => TabCompleteReply
|
||||
0x11 => DeclareCommands
|
||||
0x12 => ConfirmTransaction
|
||||
0x13 => WindowClose
|
||||
0x14 => WindowItems
|
||||
0x15 => WindowProperty
|
||||
0x16 => WindowSetSlot
|
||||
0x17 => SetCooldown
|
||||
0x18 => PluginMessageClientbound
|
||||
0x19 => NamedSoundEffect
|
||||
0x1a => Disconnect
|
||||
0x1b => EntityAction
|
||||
0x1c => Explosion
|
||||
0x1d => ChunkUnload
|
||||
0x1e => ChangeGameState
|
||||
0x1f => WindowOpenHorse
|
||||
0x20 => KeepAliveClientbound_i64
|
||||
0x21 => ChunkData_HeightMap
|
||||
0x22 => Effect
|
||||
0x23 => Particle_Data
|
||||
0x24 => UpdateLight
|
||||
0x25 => JoinGame_i32_ViewDistance
|
||||
0x26 => Maps
|
||||
0x27 => TradeList_WithoutRestock
|
||||
0x28 => EntityMove_i16
|
||||
0x29 => EntityLookAndMove_i16
|
||||
0x2a => EntityLook_VarInt
|
||||
0x2b => Entity
|
||||
0x2c => VehicleTeleport
|
||||
0x2d => OpenBook
|
||||
0x2e => WindowOpen_VarInt
|
||||
0x2f => SignEditorOpen
|
||||
0x30 => CraftRecipeResponse
|
||||
0x31 => PlayerAbilities
|
||||
0x32 => CombatEvent
|
||||
0x33 => PlayerInfo
|
||||
0x34 => FacePlayer
|
||||
0x35 => TeleportPlayer_WithConfirm
|
||||
0x36 => UnlockRecipes_WithSmelting
|
||||
0x37 => EntityDestroy
|
||||
0x38 => EntityRemoveEffect
|
||||
0x39 => ResourcePackSend
|
||||
0x3a => Respawn
|
||||
0x3b => EntityHeadLook
|
||||
0x3c => SelectAdvancementTab
|
||||
0x3d => WorldBorder
|
||||
0x3e => Camera
|
||||
0x3f => SetCurrentHotbarSlot
|
||||
0x40 => UpdateViewPosition
|
||||
0x41 => UpdateViewDistance
|
||||
0x42 => ScoreboardDisplay
|
||||
0x43 => EntityMetadata
|
||||
0x44 => EntityAttach
|
||||
0x45 => EntityVelocity
|
||||
0x46 => EntityEquipment
|
||||
0x47 => SetExperience
|
||||
0x48 => UpdateHealth
|
||||
0x49 => ScoreboardObjective
|
||||
0x4a => SetPassengers
|
||||
0x4b => Teams_VarInt
|
||||
0x4c => UpdateScore
|
||||
0x4d => SpawnPosition
|
||||
0x4e => TimeUpdate
|
||||
0x4f => Title
|
||||
0x50 => EntitySoundEffect
|
||||
0x51 => SoundEffect
|
||||
0x52 => StopSound
|
||||
0x53 => PlayerListHeaderFooter
|
||||
0x54 => NBTQueryResponse
|
||||
0x55 => CollectItem
|
||||
0x56 => EntityTeleport_f64
|
||||
0x57 => Advancements
|
||||
0x58 => EntityProperties
|
||||
0x59 => EntityEffect
|
||||
0x5a => DeclareRecipes
|
||||
0x5b => TagsWithEntities
|
||||
}
|
||||
}
|
||||
login Login {
|
||||
serverbound Serverbound {
|
||||
0x00 => LoginStart
|
||||
0x01 => EncryptionResponse
|
||||
0x02 => LoginPluginResponse
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => LoginDisconnect
|
||||
0x01 => EncryptionRequest
|
||||
0x02 => LoginSuccess
|
||||
0x03 => SetInitialCompression
|
||||
0x04 => LoginPluginRequest
|
||||
}
|
||||
}
|
||||
status Status {
|
||||
serverbound Serverbound {
|
||||
0x00 => StatusRequest
|
||||
0x01 => StatusPing
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => StatusResponse
|
||||
0x01 => StatusPong
|
||||
}
|
||||
}
|
||||
);
|
|
@ -0,0 +1,177 @@
|
|||
protocol_packet_ids!(
|
||||
handshake Handshaking {
|
||||
serverbound Serverbound {
|
||||
0x00 => Handshake
|
||||
}
|
||||
clientbound Clientbound {
|
||||
}
|
||||
}
|
||||
play Play {
|
||||
serverbound Serverbound {
|
||||
0x00 => TeleportConfirm
|
||||
0x01 => QueryBlockNBT
|
||||
0x02 => SetDifficulty
|
||||
0x03 => ChatMessage
|
||||
0x04 => ClientStatus
|
||||
0x05 => ClientSettings
|
||||
0x06 => TabComplete
|
||||
0x07 => ConfirmTransactionServerbound
|
||||
0x08 => ClickWindowButton
|
||||
0x09 => ClickWindow
|
||||
0x0a => CloseWindow
|
||||
0x0b => PluginMessageServerbound
|
||||
0x0c => EditBook
|
||||
0x0d => QueryEntityNBT
|
||||
0x0e => UseEntity
|
||||
0x0f => KeepAliveServerbound_i64
|
||||
0x10 => LockDifficulty
|
||||
0x11 => PlayerPosition
|
||||
0x12 => PlayerPositionLook
|
||||
0x13 => PlayerLook
|
||||
0x14 => Player
|
||||
0x15 => VehicleMove
|
||||
0x16 => SteerBoat
|
||||
0x17 => PickItem
|
||||
0x18 => CraftRecipeRequest
|
||||
0x19 => ClientAbilities
|
||||
0x1a => PlayerDigging
|
||||
0x1b => PlayerAction
|
||||
0x1c => SteerVehicle
|
||||
0x1d => CraftingBookData
|
||||
0x1e => NameItem
|
||||
0x1f => ResourcePackStatus
|
||||
0x20 => AdvancementTab
|
||||
0x21 => SelectTrade
|
||||
0x22 => SetBeaconEffect
|
||||
0x23 => HeldItemChange
|
||||
0x24 => UpdateCommandBlock
|
||||
0x25 => UpdateCommandBlockMinecart
|
||||
0x26 => CreativeInventoryAction
|
||||
0x27 => UpdateJigsawBlock
|
||||
0x28 => UpdateStructureBlock
|
||||
0x29 => SetSign
|
||||
0x2a => ArmSwing
|
||||
0x2b => SpectateTeleport
|
||||
0x2c => PlayerBlockPlacement_f32
|
||||
0x2d => UseItem
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => SpawnObject
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob_WithMeta
|
||||
0x04 => SpawnPainting_VarInt
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
0x08 => BlockBreakAnimation
|
||||
0x09 => UpdateBlockEntity
|
||||
0x0a => BlockAction
|
||||
0x0b => BlockChange_VarInt
|
||||
0x0c => BossBar
|
||||
0x0d => ServerDifficulty_Locked
|
||||
0x0e => ServerMessage
|
||||
0x0f => MultiBlockChange_VarInt
|
||||
0x10 => TabCompleteReply
|
||||
0x11 => DeclareCommands
|
||||
0x12 => ConfirmTransaction
|
||||
0x13 => WindowClose
|
||||
0x14 => WindowItems
|
||||
0x15 => WindowProperty
|
||||
0x16 => WindowSetSlot
|
||||
0x17 => SetCooldown
|
||||
0x18 => PluginMessageClientbound
|
||||
0x19 => NamedSoundEffect
|
||||
0x1a => Disconnect
|
||||
0x1b => EntityAction
|
||||
0x1c => Explosion
|
||||
0x1d => ChunkUnload
|
||||
0x1e => ChangeGameState
|
||||
0x1f => WindowOpenHorse
|
||||
0x20 => KeepAliveClientbound_i64
|
||||
0x21 => ChunkData_HeightMap
|
||||
0x22 => Effect
|
||||
0x23 => Particle_Data
|
||||
0x24 => UpdateLight
|
||||
0x25 => JoinGame_i32_ViewDistance
|
||||
0x26 => Maps
|
||||
0x27 => TradeList_WithRestock
|
||||
0x28 => EntityMove_i16
|
||||
0x29 => EntityLookAndMove_i16
|
||||
0x2a => EntityLook_VarInt
|
||||
0x2b => Entity
|
||||
0x2c => VehicleTeleport
|
||||
0x2d => OpenBook
|
||||
0x2e => WindowOpen_VarInt
|
||||
0x2f => SignEditorOpen
|
||||
0x30 => CraftRecipeResponse
|
||||
0x31 => PlayerAbilities
|
||||
0x32 => CombatEvent
|
||||
0x33 => PlayerInfo
|
||||
0x34 => FacePlayer
|
||||
0x35 => TeleportPlayer_WithConfirm
|
||||
0x36 => UnlockRecipes_WithSmelting
|
||||
0x37 => EntityDestroy
|
||||
0x38 => EntityRemoveEffect
|
||||
0x39 => ResourcePackSend
|
||||
0x3a => Respawn
|
||||
0x3b => EntityHeadLook
|
||||
0x3c => SelectAdvancementTab
|
||||
0x3d => WorldBorder
|
||||
0x3e => Camera
|
||||
0x3f => SetCurrentHotbarSlot
|
||||
0x40 => UpdateViewPosition
|
||||
0x41 => UpdateViewDistance
|
||||
0x42 => ScoreboardDisplay
|
||||
0x43 => EntityMetadata
|
||||
0x44 => EntityAttach
|
||||
0x45 => EntityVelocity
|
||||
0x46 => EntityEquipment
|
||||
0x47 => SetExperience
|
||||
0x48 => UpdateHealth
|
||||
0x49 => ScoreboardObjective
|
||||
0x4a => SetPassengers
|
||||
0x4b => Teams_VarInt
|
||||
0x4c => UpdateScore
|
||||
0x4d => SpawnPosition
|
||||
0x4e => TimeUpdate
|
||||
0x4f => Title
|
||||
0x50 => EntitySoundEffect
|
||||
0x51 => SoundEffect
|
||||
0x52 => StopSound
|
||||
0x53 => PlayerListHeaderFooter
|
||||
0x54 => NBTQueryResponse
|
||||
0x55 => CollectItem
|
||||
0x56 => EntityTeleport_f64
|
||||
0x57 => Advancements
|
||||
0x58 => EntityProperties
|
||||
0x59 => EntityEffect
|
||||
0x5a => DeclareRecipes
|
||||
0x5b => TagsWithEntities
|
||||
}
|
||||
}
|
||||
login Login {
|
||||
serverbound Serverbound {
|
||||
0x00 => LoginStart
|
||||
0x01 => EncryptionResponse
|
||||
0x02 => LoginPluginResponse
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => LoginDisconnect
|
||||
0x01 => EncryptionRequest
|
||||
0x02 => LoginSuccess
|
||||
0x03 => SetInitialCompression
|
||||
0x04 => LoginPluginRequest
|
||||
}
|
||||
}
|
||||
status Status {
|
||||
serverbound Serverbound {
|
||||
0x00 => StatusRequest
|
||||
0x01 => StatusPing
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => StatusResponse
|
||||
0x01 => StatusPong
|
||||
}
|
||||
}
|
||||
);
|
|
@ -0,0 +1,178 @@
|
|||
protocol_packet_ids!(
|
||||
handshake Handshaking {
|
||||
serverbound Serverbound {
|
||||
0x00 => Handshake
|
||||
}
|
||||
clientbound Clientbound {
|
||||
}
|
||||
}
|
||||
play Play {
|
||||
serverbound Serverbound {
|
||||
0x00 => TeleportConfirm
|
||||
0x01 => QueryBlockNBT
|
||||
0x02 => SetDifficulty
|
||||
0x03 => ChatMessage
|
||||
0x04 => ClientStatus
|
||||
0x05 => ClientSettings
|
||||
0x06 => TabComplete
|
||||
0x07 => ConfirmTransactionServerbound
|
||||
0x08 => ClickWindowButton
|
||||
0x09 => ClickWindow
|
||||
0x0a => CloseWindow
|
||||
0x0b => PluginMessageServerbound
|
||||
0x0c => EditBook
|
||||
0x0d => QueryEntityNBT
|
||||
0x0e => UseEntity
|
||||
0x0f => KeepAliveServerbound_i64
|
||||
0x10 => LockDifficulty
|
||||
0x11 => PlayerPosition
|
||||
0x12 => PlayerPositionLook
|
||||
0x13 => PlayerLook
|
||||
0x14 => Player
|
||||
0x15 => VehicleMove
|
||||
0x16 => SteerBoat
|
||||
0x17 => PickItem
|
||||
0x18 => CraftRecipeRequest
|
||||
0x19 => ClientAbilities
|
||||
0x1a => PlayerDigging
|
||||
0x1b => PlayerAction
|
||||
0x1c => SteerVehicle
|
||||
0x1d => CraftingBookData
|
||||
0x1e => NameItem
|
||||
0x1f => ResourcePackStatus
|
||||
0x20 => AdvancementTab
|
||||
0x21 => SelectTrade
|
||||
0x22 => SetBeaconEffect
|
||||
0x23 => HeldItemChange
|
||||
0x24 => UpdateCommandBlock
|
||||
0x25 => UpdateCommandBlockMinecart
|
||||
0x26 => CreativeInventoryAction
|
||||
0x27 => UpdateJigsawBlock
|
||||
0x28 => UpdateStructureBlock
|
||||
0x29 => SetSign
|
||||
0x2a => ArmSwing
|
||||
0x2b => SpectateTeleport
|
||||
0x2c => PlayerBlockPlacement_f32
|
||||
0x2d => UseItem
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => SpawnObject
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob_WithMeta
|
||||
0x04 => SpawnPainting_VarInt
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
0x08 => BlockBreakAnimation
|
||||
0x09 => UpdateBlockEntity
|
||||
0x0a => BlockAction
|
||||
0x0b => BlockChange_VarInt
|
||||
0x0c => BossBar
|
||||
0x0d => ServerDifficulty_Locked
|
||||
0x0e => ServerMessage
|
||||
0x0f => MultiBlockChange_VarInt
|
||||
0x10 => TabCompleteReply
|
||||
0x11 => DeclareCommands
|
||||
0x12 => ConfirmTransaction
|
||||
0x13 => WindowClose
|
||||
0x14 => WindowItems
|
||||
0x15 => WindowProperty
|
||||
0x16 => WindowSetSlot
|
||||
0x17 => SetCooldown
|
||||
0x18 => PluginMessageClientbound
|
||||
0x19 => NamedSoundEffect
|
||||
0x1a => Disconnect
|
||||
0x1b => EntityAction
|
||||
0x1c => Explosion
|
||||
0x1d => ChunkUnload
|
||||
0x1e => ChangeGameState
|
||||
0x1f => WindowOpenHorse
|
||||
0x20 => KeepAliveClientbound_i64
|
||||
0x21 => ChunkData_HeightMap
|
||||
0x22 => Effect
|
||||
0x23 => Particle_Data
|
||||
0x24 => UpdateLight
|
||||
0x25 => JoinGame_i32_ViewDistance
|
||||
0x26 => Maps
|
||||
0x27 => TradeList_WithRestock
|
||||
0x28 => EntityMove_i16
|
||||
0x29 => EntityLookAndMove_i16
|
||||
0x2a => EntityLook_VarInt
|
||||
0x2b => Entity
|
||||
0x2c => VehicleTeleport
|
||||
0x2d => OpenBook
|
||||
0x2e => WindowOpen_VarInt
|
||||
0x2f => SignEditorOpen
|
||||
0x30 => CraftRecipeResponse
|
||||
0x31 => PlayerAbilities
|
||||
0x32 => CombatEvent
|
||||
0x33 => PlayerInfo
|
||||
0x34 => FacePlayer
|
||||
0x35 => TeleportPlayer_WithConfirm
|
||||
0x36 => UnlockRecipes_WithSmelting
|
||||
0x37 => EntityDestroy
|
||||
0x38 => EntityRemoveEffect
|
||||
0x39 => ResourcePackSend
|
||||
0x3a => Respawn
|
||||
0x3b => EntityHeadLook
|
||||
0x3c => SelectAdvancementTab
|
||||
0x3d => WorldBorder
|
||||
0x3e => Camera
|
||||
0x3f => SetCurrentHotbarSlot
|
||||
0x40 => UpdateViewPosition
|
||||
0x41 => UpdateViewDistance
|
||||
0x42 => ScoreboardDisplay
|
||||
0x43 => EntityMetadata
|
||||
0x44 => EntityAttach
|
||||
0x45 => EntityVelocity
|
||||
0x46 => EntityEquipment
|
||||
0x47 => SetExperience
|
||||
0x48 => UpdateHealth
|
||||
0x49 => ScoreboardObjective
|
||||
0x4a => SetPassengers
|
||||
0x4b => Teams_VarInt
|
||||
0x4c => UpdateScore
|
||||
0x4d => SpawnPosition
|
||||
0x4e => TimeUpdate
|
||||
0x4f => Title
|
||||
0x50 => EntitySoundEffect
|
||||
0x51 => SoundEffect
|
||||
0x52 => StopSound
|
||||
0x53 => PlayerListHeaderFooter
|
||||
0x54 => NBTQueryResponse
|
||||
0x55 => CollectItem
|
||||
0x56 => EntityTeleport_f64
|
||||
0x57 => Advancements
|
||||
0x58 => EntityProperties
|
||||
0x59 => EntityEffect
|
||||
0x5a => DeclareRecipes
|
||||
0x5b => TagsWithEntities
|
||||
0x5c => AcknowledgePlayerDigging
|
||||
}
|
||||
}
|
||||
login Login {
|
||||
serverbound Serverbound {
|
||||
0x00 => LoginStart
|
||||
0x01 => EncryptionResponse
|
||||
0x02 => LoginPluginResponse
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => LoginDisconnect
|
||||
0x01 => EncryptionRequest
|
||||
0x02 => LoginSuccess
|
||||
0x03 => SetInitialCompression
|
||||
0x04 => LoginPluginRequest
|
||||
}
|
||||
}
|
||||
status Status {
|
||||
serverbound Serverbound {
|
||||
0x00 => StatusRequest
|
||||
0x01 => StatusPing
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => StatusResponse
|
||||
0x01 => StatusPong
|
||||
}
|
||||
}
|
||||
);
|
|
@ -0,0 +1,178 @@
|
|||
protocol_packet_ids!(
|
||||
handshake Handshaking {
|
||||
serverbound Serverbound {
|
||||
0x00 => Handshake
|
||||
}
|
||||
clientbound Clientbound {
|
||||
}
|
||||
}
|
||||
play Play {
|
||||
serverbound Serverbound {
|
||||
0x00 => TeleportConfirm
|
||||
0x01 => QueryBlockNBT
|
||||
0x02 => SetDifficulty
|
||||
0x03 => ChatMessage
|
||||
0x04 => ClientStatus
|
||||
0x05 => ClientSettings
|
||||
0x06 => TabComplete
|
||||
0x07 => ConfirmTransactionServerbound
|
||||
0x08 => ClickWindowButton
|
||||
0x09 => ClickWindow
|
||||
0x0a => CloseWindow
|
||||
0x0b => PluginMessageServerbound
|
||||
0x0c => EditBook
|
||||
0x0d => QueryEntityNBT
|
||||
0x0e => UseEntity
|
||||
0x0f => KeepAliveServerbound_i64
|
||||
0x10 => LockDifficulty
|
||||
0x11 => PlayerPosition
|
||||
0x12 => PlayerPositionLook
|
||||
0x13 => PlayerLook
|
||||
0x14 => Player
|
||||
0x15 => VehicleMove
|
||||
0x16 => SteerBoat
|
||||
0x17 => PickItem
|
||||
0x18 => CraftRecipeRequest
|
||||
0x19 => ClientAbilities
|
||||
0x1a => PlayerDigging
|
||||
0x1b => PlayerAction
|
||||
0x1c => SteerVehicle
|
||||
0x1d => CraftingBookData
|
||||
0x1e => NameItem
|
||||
0x1f => ResourcePackStatus
|
||||
0x20 => AdvancementTab
|
||||
0x21 => SelectTrade
|
||||
0x22 => SetBeaconEffect
|
||||
0x23 => HeldItemChange
|
||||
0x24 => UpdateCommandBlock
|
||||
0x25 => UpdateCommandBlockMinecart
|
||||
0x26 => CreativeInventoryAction
|
||||
0x27 => UpdateJigsawBlock
|
||||
0x28 => UpdateStructureBlock
|
||||
0x29 => SetSign
|
||||
0x2a => ArmSwing
|
||||
0x2b => SpectateTeleport
|
||||
0x2c => PlayerBlockPlacement_f32
|
||||
0x2d => UseItem
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => SpawnObject
|
||||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob_NoMeta
|
||||
0x04 => SpawnPainting_VarInt
|
||||
0x05 => SpawnPlayer_f64_NoMeta
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
0x08 => AcknowledgePlayerDigging
|
||||
0x09 => BlockBreakAnimation
|
||||
0x0a => UpdateBlockEntity
|
||||
0x0b => BlockAction
|
||||
0x0c => BlockChange_VarInt
|
||||
0x0d => BossBar
|
||||
0x0e => ServerDifficulty_Locked
|
||||
0x0f => ServerMessage
|
||||
0x10 => MultiBlockChange_VarInt
|
||||
0x11 => TabCompleteReply
|
||||
0x12 => DeclareCommands
|
||||
0x13 => ConfirmTransaction
|
||||
0x14 => WindowClose
|
||||
0x15 => WindowItems
|
||||
0x16 => WindowProperty
|
||||
0x17 => WindowSetSlot
|
||||
0x18 => SetCooldown
|
||||
0x19 => PluginMessageClientbound
|
||||
0x1a => NamedSoundEffect
|
||||
0x1b => Disconnect
|
||||
0x1c => EntityAction
|
||||
0x1d => Explosion
|
||||
0x1e => ChunkUnload
|
||||
0x1f => ChangeGameState
|
||||
0x20 => WindowOpenHorse
|
||||
0x21 => KeepAliveClientbound_i64
|
||||
0x22 => ChunkData_Biomes3D
|
||||
0x23 => Effect
|
||||
0x24 => Particle_f64
|
||||
0x25 => UpdateLight
|
||||
0x26 => JoinGame_HashedSeed_Respawn
|
||||
0x27 => Maps
|
||||
0x28 => TradeList_WithRestock
|
||||
0x29 => EntityMove_i16
|
||||
0x2a => EntityLookAndMove_i16
|
||||
0x2b => EntityLook_VarInt
|
||||
0x2c => Entity
|
||||
0x2d => VehicleTeleport
|
||||
0x2e => OpenBook
|
||||
0x2f => WindowOpen_VarInt
|
||||
0x30 => SignEditorOpen
|
||||
0x31 => CraftRecipeResponse
|
||||
0x32 => PlayerAbilities
|
||||
0x33 => CombatEvent
|
||||
0x34 => PlayerInfo
|
||||
0x35 => FacePlayer
|
||||
0x36 => TeleportPlayer_WithConfirm
|
||||
0x37 => UnlockRecipes_WithSmelting
|
||||
0x38 => EntityDestroy
|
||||
0x39 => EntityRemoveEffect
|
||||
0x3a => ResourcePackSend
|
||||
0x3b => Respawn_HashedSeed
|
||||
0x3c => EntityHeadLook
|
||||
0x3d => SelectAdvancementTab
|
||||
0x3e => WorldBorder
|
||||
0x3f => Camera
|
||||
0x40 => SetCurrentHotbarSlot
|
||||
0x41 => UpdateViewPosition
|
||||
0x42 => UpdateViewDistance
|
||||
0x43 => ScoreboardDisplay
|
||||
0x44 => EntityMetadata
|
||||
0x45 => EntityAttach
|
||||
0x46 => EntityVelocity
|
||||
0x47 => EntityEquipment
|
||||
0x48 => SetExperience
|
||||
0x49 => UpdateHealth
|
||||
0x4a => ScoreboardObjective
|
||||
0x4b => SetPassengers
|
||||
0x4c => Teams_VarInt
|
||||
0x4d => UpdateScore
|
||||
0x4e => SpawnPosition
|
||||
0x4f => TimeUpdate
|
||||
0x50 => Title
|
||||
0x51 => EntitySoundEffect
|
||||
0x52 => SoundEffect
|
||||
0x53 => StopSound
|
||||
0x54 => PlayerListHeaderFooter
|
||||
0x55 => NBTQueryResponse
|
||||
0x56 => CollectItem
|
||||
0x57 => EntityTeleport_f64
|
||||
0x58 => Advancements
|
||||
0x59 => EntityProperties
|
||||
0x5a => EntityEffect
|
||||
0x5b => DeclareRecipes
|
||||
0x5c => TagsWithEntities
|
||||
}
|
||||
}
|
||||
login Login {
|
||||
serverbound Serverbound {
|
||||
0x00 => LoginStart
|
||||
0x01 => EncryptionResponse
|
||||
0x02 => LoginPluginResponse
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => LoginDisconnect
|
||||
0x01 => EncryptionRequest
|
||||
0x02 => LoginSuccess
|
||||
0x03 => SetInitialCompression
|
||||
0x04 => LoginPluginRequest
|
||||
}
|
||||
}
|
||||
status Status {
|
||||
serverbound Serverbound {
|
||||
0x00 => StatusRequest
|
||||
0x01 => StatusPing
|
||||
}
|
||||
clientbound Clientbound {
|
||||
0x00 => StatusResponse
|
||||
0x01 => StatusPong
|
||||
}
|
||||
}
|
||||
);
|
|
@ -42,7 +42,7 @@ protocol_packet_ids!(
|
|||
0x05 => SpawnPosition_i32
|
||||
0x06 => UpdateHealth_u16
|
||||
0x07 => Respawn
|
||||
0x08 => TeleportPlayer_NoConfirm
|
||||
0x08 => TeleportPlayer_OnGround
|
||||
0x09 => SetCurrentHotbarSlot
|
||||
0x0a => EntityUsedBed_i32
|
||||
0x0b => Animation
|
||||
|
@ -99,6 +99,7 @@ protocol_packet_ids!(
|
|||
0x3e => Teams_NoVisColor
|
||||
0x3f => PluginMessageClientbound_i16
|
||||
0x40 => Disconnect
|
||||
-0x1a => CoFHLib_SendUUID
|
||||
}
|
||||
}
|
||||
login Login {
|
||||
|
@ -123,5 +124,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ protocol_packet_ids!(
|
|||
0x27 => Explosion
|
||||
0x28 => Effect
|
||||
0x29 => NamedSoundEffect_u8_NoCategory
|
||||
0x2a => Particle
|
||||
0x2a => Particle_VarIntArray
|
||||
0x2b => ChangeGameState
|
||||
0x2c => SpawnGlobalEntity_i32
|
||||
0x2d => WindowOpen
|
||||
|
@ -98,7 +98,7 @@ protocol_packet_ids!(
|
|||
0x3b => ScoreboardObjective
|
||||
0x3c => UpdateScore
|
||||
0x3d => ScoreboardDisplay
|
||||
0x3e => Teams
|
||||
0x3e => Teams_u8
|
||||
0x3f => PluginMessageClientbound
|
||||
0x40 => Disconnect
|
||||
0x41 => ServerDifficulty
|
||||
|
@ -135,5 +135,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ protocol_packet_ids!(
|
|||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob_u8
|
||||
0x04 => SpawnPainting
|
||||
0x04 => SpawnPainting_String
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
|
@ -74,7 +74,7 @@ protocol_packet_ids!(
|
|||
0x1f => KeepAliveClientbound_VarInt
|
||||
0x20 => ChunkData_NoEntities
|
||||
0x21 => Effect
|
||||
0x22 => Particle
|
||||
0x22 => Particle_VarIntArray
|
||||
0x23 => JoinGame_i8
|
||||
0x24 => Maps
|
||||
0x25 => EntityMove_i16
|
||||
|
@ -105,7 +105,7 @@ protocol_packet_ids!(
|
|||
0x3e => UpdateHealth
|
||||
0x3f => ScoreboardObjective
|
||||
0x40 => SetPassengers
|
||||
0x41 => Teams
|
||||
0x41 => Teams_u8
|
||||
0x42 => UpdateScore
|
||||
0x43 => SpawnPosition
|
||||
0x44 => TimeUpdate
|
||||
|
@ -142,5 +142,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ protocol_packet_ids!(
|
|||
0x01 => SpawnExperienceOrb
|
||||
0x02 => SpawnGlobalEntity
|
||||
0x03 => SpawnMob_u8
|
||||
0x04 => SpawnPainting
|
||||
0x04 => SpawnPainting_String
|
||||
0x05 => SpawnPlayer_f64
|
||||
0x06 => Animation
|
||||
0x07 => Statistics
|
||||
|
@ -74,7 +74,7 @@ protocol_packet_ids!(
|
|||
0x1f => KeepAliveClientbound_VarInt
|
||||
0x20 => ChunkData_NoEntities
|
||||
0x21 => Effect
|
||||
0x22 => Particle
|
||||
0x22 => Particle_VarIntArray
|
||||
0x23 => JoinGame_i32
|
||||
0x24 => Maps
|
||||
0x25 => EntityMove_i16
|
||||
|
@ -105,7 +105,7 @@ protocol_packet_ids!(
|
|||
0x3e => UpdateHealth
|
||||
0x3f => ScoreboardObjective
|
||||
0x40 => SetPassengers
|
||||
0x41 => Teams
|
||||
0x41 => Teams_u8
|
||||
0x42 => UpdateScore
|
||||
0x43 => SpawnPosition
|
||||
0x44 => TimeUpdate
|
||||
|
@ -142,5 +142,3 @@ protocol_packet_ids!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ impl Map {
|
|||
}
|
||||
pub fn from_raw(bits: Vec<u64>, size: usize) -> Map {
|
||||
Map {
|
||||
length: (bits.len()*64 + (size-1)) / size,
|
||||
length: (bits.len() * 64 + (size - 1)) / size,
|
||||
bit_size: size,
|
||||
bits,
|
||||
}
|
|
@ -12,8 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
pub mod set;
|
||||
pub mod map;
|
||||
pub mod set;
|
||||
|
||||
pub use self::set::Set;
|
||||
pub use self::map::Map;
|
||||
pub use self::set::Set;
|
|
@ -34,7 +34,9 @@ fn test_set() {
|
|||
|
||||
impl Set {
|
||||
pub fn new(size: usize) -> Set {
|
||||
Set { data: vec![0; (size + 63) / 64] }
|
||||
Set {
|
||||
data: vec![0; (size + 63) / 64],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, new_size: usize) {
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
use std::hash::Hasher;
|
||||
|
||||
pub struct FNVHash(u64);
|
|
@ -12,24 +12,24 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::io;
|
||||
use std::fmt;
|
||||
use crate::protocol;
|
||||
use crate::protocol::Serializable;
|
||||
use crate::protocol::LenPrefixed;
|
||||
use crate::format;
|
||||
use crate::item;
|
||||
use crate::shared::Position;
|
||||
use crate::nbt;
|
||||
use crate::protocol;
|
||||
use crate::protocol::LenPrefixed;
|
||||
use crate::protocol::Serializable;
|
||||
use crate::shared::Position;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct MetadataKey<T: MetaValue> {
|
||||
index: i32,
|
||||
ty: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl <T: MetaValue> MetadataKey<T> {
|
||||
impl<T: MetaValue> MetadataKey<T> {
|
||||
#[allow(dead_code)]
|
||||
fn new(index: i32) -> MetadataKey<T> {
|
||||
MetadataKey {
|
||||
|
@ -45,7 +45,9 @@ pub struct Metadata {
|
|||
|
||||
impl Metadata {
|
||||
pub fn new() -> Metadata {
|
||||
Metadata { map: HashMap::new() }
|
||||
Metadata {
|
||||
map: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get<T: MetaValue>(&self, key: &MetadataKey<T>) -> Option<&T> {
|
||||
|
@ -77,14 +79,22 @@ impl Metadata {
|
|||
3 => m.put_raw(index, f32::read_from(buf)?),
|
||||
4 => m.put_raw(index, String::read_from(buf)?),
|
||||
5 => m.put_raw(index, Option::<item::Stack>::read_from(buf)?),
|
||||
6 => m.put_raw(index,
|
||||
[i32::read_from(buf)?,
|
||||
i32::read_from(buf)?,
|
||||
i32::read_from(buf)?]),
|
||||
7 => m.put_raw(index,
|
||||
[f32::read_from(buf)?,
|
||||
f32::read_from(buf)?,
|
||||
f32::read_from(buf)?]),
|
||||
6 => m.put_raw(
|
||||
index,
|
||||
[
|
||||
i32::read_from(buf)?,
|
||||
i32::read_from(buf)?,
|
||||
i32::read_from(buf)?,
|
||||
],
|
||||
),
|
||||
7 => m.put_raw(
|
||||
index,
|
||||
[
|
||||
f32::read_from(buf)?,
|
||||
f32::read_from(buf)?,
|
||||
f32::read_from(buf)?,
|
||||
],
|
||||
),
|
||||
_ => return Err(protocol::Error::Err("unknown metadata type".to_owned())),
|
||||
}
|
||||
}
|
||||
|
@ -100,8 +110,7 @@ impl Metadata {
|
|||
let ty_index: u8 = *k as u8;
|
||||
const TYPE_SHIFT: usize = 5;
|
||||
|
||||
match *v
|
||||
{
|
||||
match *v {
|
||||
Value::Byte(ref val) => {
|
||||
u8::write_to(&(ty_index | (0 << TYPE_SHIFT)), buf)?;
|
||||
val.write_to(buf)?;
|
||||
|
@ -165,10 +174,14 @@ impl Metadata {
|
|||
4 => m.put_raw(index, format::Component::read_from(buf)?),
|
||||
5 => m.put_raw(index, Option::<item::Stack>::read_from(buf)?),
|
||||
6 => m.put_raw(index, bool::read_from(buf)?),
|
||||
7 => m.put_raw(index,
|
||||
[f32::read_from(buf)?,
|
||||
f32::read_from(buf)?,
|
||||
f32::read_from(buf)?]),
|
||||
7 => m.put_raw(
|
||||
index,
|
||||
[
|
||||
f32::read_from(buf)?,
|
||||
f32::read_from(buf)?,
|
||||
f32::read_from(buf)?,
|
||||
],
|
||||
),
|
||||
8 => m.put_raw(index, Position::read_from(buf)?),
|
||||
9 => {
|
||||
if bool::read_from(buf)? {
|
||||
|
@ -287,13 +300,20 @@ impl Metadata {
|
|||
2 => m.put_raw(index, f32::read_from(buf)?),
|
||||
3 => m.put_raw(index, String::read_from(buf)?),
|
||||
4 => m.put_raw(index, format::Component::read_from(buf)?),
|
||||
5 => m.put_raw(index, LenPrefixed::<bool, format::Component>::read_from(buf)?),
|
||||
5 => m.put_raw(
|
||||
index,
|
||||
LenPrefixed::<bool, format::Component>::read_from(buf)?,
|
||||
),
|
||||
6 => m.put_raw(index, Option::<item::Stack>::read_from(buf)?),
|
||||
7 => m.put_raw(index, bool::read_from(buf)?),
|
||||
8 => m.put_raw(index,
|
||||
[f32::read_from(buf)?,
|
||||
f32::read_from(buf)?,
|
||||
f32::read_from(buf)?]),
|
||||
8 => m.put_raw(
|
||||
index,
|
||||
[
|
||||
f32::read_from(buf)?,
|
||||
f32::read_from(buf)?,
|
||||
f32::read_from(buf)?,
|
||||
],
|
||||
),
|
||||
9 => m.put_raw(index, Position::read_from(buf)?),
|
||||
10 => {
|
||||
if bool::read_from(buf)? {
|
||||
|
@ -322,6 +342,14 @@ impl Metadata {
|
|||
}
|
||||
15 => panic!("TODO: particle"),
|
||||
16 => m.put_raw(index, VillagerData::read_from(buf)?),
|
||||
17 => {
|
||||
if bool::read_from(buf)? {
|
||||
m.put_raw(index, Option::<protocol::VarInt>::read_from(buf)?);
|
||||
} else {
|
||||
m.put_raw::<Option<protocol::VarInt>>(index, None);
|
||||
}
|
||||
}
|
||||
18 => m.put_raw(index, PoseData::read_from(buf)?),
|
||||
_ => return Err(protocol::Error::Err("unknown metadata type".to_owned())),
|
||||
}
|
||||
}
|
||||
|
@ -405,19 +433,25 @@ impl Metadata {
|
|||
u8::write_to(&16, buf)?;
|
||||
val.write_to(buf)?;
|
||||
}
|
||||
Value::OptionalVarInt(ref val) => {
|
||||
u8::write_to(&17, buf)?;
|
||||
val.write_to(buf)?;
|
||||
}
|
||||
Value::Pose(ref val) => {
|
||||
u8::write_to(&18, buf)?;
|
||||
val.write_to(buf)?;
|
||||
}
|
||||
_ => panic!("unexpected metadata"),
|
||||
}
|
||||
}
|
||||
u8::write_to(&0xFF, buf)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
impl Serializable for Metadata {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, protocol::Error> {
|
||||
let protocol_version = unsafe { protocol::CURRENT_PROTOCOL_VERSION };
|
||||
let protocol_version = protocol::current_protocol_version();
|
||||
|
||||
if protocol_version >= 404 {
|
||||
Metadata::read_from113(buf)
|
||||
|
@ -429,7 +463,7 @@ impl Serializable for Metadata {
|
|||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, buf: &mut W) -> Result<(), protocol::Error> {
|
||||
let protocol_version = unsafe { protocol::CURRENT_PROTOCOL_VERSION };
|
||||
let protocol_version = protocol::current_protocol_version();
|
||||
|
||||
if protocol_version >= 404 {
|
||||
self.write_to113(buf)
|
||||
|
@ -478,6 +512,8 @@ pub enum Value {
|
|||
NBTTag(nbt::NamedTag),
|
||||
Particle(ParticleData),
|
||||
Villager(VillagerData),
|
||||
OptionalVarInt(Option<protocol::VarInt>),
|
||||
Pose(PoseData),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -553,7 +589,7 @@ impl Serializable for ParticleData {
|
|||
1 => ParticleData::AngryVillager,
|
||||
2 => ParticleData::Barrier,
|
||||
3 => ParticleData::Block {
|
||||
block_state: Serializable::read_from(buf)?
|
||||
block_state: Serializable::read_from(buf)?,
|
||||
},
|
||||
4 => ParticleData::Bubble,
|
||||
5 => ParticleData::Cloud,
|
||||
|
@ -631,7 +667,11 @@ impl Serializable for VillagerData {
|
|||
let villager_type = protocol::VarInt::read_from(buf)?;
|
||||
let profession = protocol::VarInt::read_from(buf)?;
|
||||
let level = protocol::VarInt::read_from(buf)?;
|
||||
Ok(VillagerData { villager_type, profession, level })
|
||||
Ok(VillagerData {
|
||||
villager_type,
|
||||
profession,
|
||||
level,
|
||||
})
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, _buf: &mut W) -> Result<(), protocol::Error> {
|
||||
|
@ -639,6 +679,36 @@ impl Serializable for VillagerData {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PoseData {
|
||||
Standing,
|
||||
FallFlying,
|
||||
Sleeping,
|
||||
Swimming,
|
||||
SpinAttack,
|
||||
Sneaking,
|
||||
Dying,
|
||||
}
|
||||
|
||||
impl Serializable for PoseData {
|
||||
fn read_from<R: io::Read>(buf: &mut R) -> Result<Self, protocol::Error> {
|
||||
let n = protocol::VarInt::read_from(buf)?;
|
||||
Ok(match n.0 {
|
||||
0 => PoseData::Standing,
|
||||
1 => PoseData::FallFlying,
|
||||
2 => PoseData::Sleeping,
|
||||
3 => PoseData::Swimming,
|
||||
4 => PoseData::SpinAttack,
|
||||
5 => PoseData::Sneaking,
|
||||
6 => PoseData::Dying,
|
||||
_ => panic!("unknown pose data: {}", n.0),
|
||||
})
|
||||
}
|
||||
|
||||
fn write_to<W: io::Write>(&self, _buf: &mut W) -> Result<(), protocol::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MetaValue {
|
||||
fn unwrap(_: &Value) -> &Self;
|
||||
|
@ -729,7 +799,6 @@ impl MetaValue for LenPrefixed<bool, format::Component> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl MetaValue for Option<item::Stack> {
|
||||
fn unwrap(value: &Value) -> &Self {
|
||||
match *value {
|
||||
|
@ -862,13 +931,36 @@ impl MetaValue for VillagerData {
|
|||
}
|
||||
}
|
||||
|
||||
impl MetaValue for Option<protocol::VarInt> {
|
||||
fn unwrap(value: &Value) -> &Self {
|
||||
match *value {
|
||||
Value::OptionalVarInt(ref val) => val,
|
||||
_ => panic!("incorrect key"),
|
||||
}
|
||||
}
|
||||
fn wrap(self) -> Value {
|
||||
Value::OptionalVarInt(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl MetaValue for PoseData {
|
||||
fn unwrap(value: &Value) -> &Self {
|
||||
match *value {
|
||||
Value::Pose(ref val) => val,
|
||||
_ => panic!("incorrect key"),
|
||||
}
|
||||
}
|
||||
fn wrap(self) -> Value {
|
||||
Value::Pose(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
const TEST: MetadataKey<String> =
|
||||
MetadataKey {
|
||||
const TEST: MetadataKey<String> = MetadataKey {
|
||||
index: 0,
|
||||
ty: PhantomData,
|
||||
};
|
|
@ -16,8 +16,8 @@ mod metadata;
|
|||
pub use self::metadata::*;
|
||||
|
||||
pub mod bit;
|
||||
pub mod nibble;
|
||||
pub mod hash;
|
||||
pub mod nibble;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Gamemode {
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
pub struct Array {
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
@ -25,8 +24,8 @@ impl Array {
|
|||
}
|
||||
|
||||
pub fn get(&self, idx: usize) -> u8 {
|
||||
let val = self.data[idx>>1];
|
||||
if idx&1 == 0 {
|
||||
let val = self.data[idx >> 1];
|
||||
if idx & 1 == 0 {
|
||||
val & 0xF
|
||||
} else {
|
||||
val >> 4
|
||||
|
@ -36,7 +35,7 @@ impl Array {
|
|||
pub fn set(&mut self, idx: usize, val: u8) {
|
||||
let i = idx >> 1;
|
||||
let old = self.data[i];
|
||||
if idx&1 == 0 {
|
||||
if idx & 1 == 0 {
|
||||
self.data[i] = (old & 0xF0) | (val & 0xF);
|
||||
} else {
|
||||
self.data[i] = (old & 0x0F) | ((val & 0xF) << 4);
|
|
@ -1,4 +1,6 @@
|
|||
[root]
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "steven_resources"
|
||||
version = "0.1.0"
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::io::BufWriter;
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn main() {
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
|
@ -13,7 +13,11 @@ fn main() {
|
|||
build_map(&mut out, &base);
|
||||
|
||||
let mut file = BufWriter::new(fs::File::create(&dest.join("resources.rs")).unwrap());
|
||||
write!(file, "pub fn get_file(name: &str) -> Option<&'static [u8]> {{\n").unwrap();
|
||||
write!(
|
||||
file,
|
||||
"pub fn get_file(name: &str) -> Option<&'static [u8]> {{\n"
|
||||
)
|
||||
.unwrap();
|
||||
write!(file, " match name {{\n").unwrap();
|
||||
for path in &out {
|
||||
let mut absolute_path = std::env::current_dir().unwrap();
|
||||
|
@ -22,10 +26,14 @@ fn main() {
|
|||
let absolute = absolute_path.to_str().unwrap().replace("\\", "/");
|
||||
let relative = path.to_str().unwrap().replace("\\", "/");
|
||||
|
||||
write!(file, " {:?} => Some(include_bytes!(\"{}\")),\n", relative, absolute).unwrap();
|
||||
write!(
|
||||
file,
|
||||
" {:?} => Some(include_bytes!(\"{}\")),\n",
|
||||
relative, absolute
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
write!(file, " _ => None\n }}\n}}\n").unwrap();
|
||||
|
||||
}
|
||||
|
||||
fn build_map(out: &mut Vec<PathBuf>, path: &Path) {
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
|
||||
include!(concat!(env!("OUT_DIR"), "/resources.rs"));
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
[root]
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "steven_shared"
|
||||
version = "0.0.1"
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Axis {
|
||||
Y,
|
||||
Z,
|
||||
X,
|
||||
None
|
||||
None,
|
||||
}
|
||||
|
||||
impl Axis {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
use crate::axis::Axis;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
@ -15,9 +14,12 @@ pub enum Direction {
|
|||
impl Direction {
|
||||
pub fn all() -> Vec<Direction> {
|
||||
vec![
|
||||
Direction::Down, Direction::Up,
|
||||
Direction::North, Direction::South,
|
||||
Direction::West, Direction::East,
|
||||
Direction::Down,
|
||||
Direction::Up,
|
||||
Direction::North,
|
||||
Direction::South,
|
||||
Direction::West,
|
||||
Direction::East,
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -117,7 +119,6 @@ impl Direction {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn horizontal_index(&self) -> usize {
|
||||
match *self {
|
||||
Direction::North => 2,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
pub mod axis;
|
||||
pub use self::axis::Axis;
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
use std::fmt;
|
||||
use crate::direction::Direction;
|
||||
use std::fmt;
|
||||
use std::ops;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
@ -12,11 +11,7 @@ pub struct Position {
|
|||
|
||||
impl Position {
|
||||
pub fn new(x: i32, y: i32, z: i32) -> Position {
|
||||
Position {
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
}
|
||||
Position { x, y, z }
|
||||
}
|
||||
|
||||
pub fn shift(self, dir: Direction) -> Position {
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use crate::world;
|
||||
use crate::world::block;
|
||||
use crate::model;
|
||||
use crate::render;
|
||||
use crate::resources;
|
||||
use crate::model;
|
||||
use crate::types::bit::Set;
|
||||
use crate::shared::Direction;
|
||||
use crate::types::bit::Set;
|
||||
use crate::world;
|
||||
use crate::world::block;
|
||||
use rand::{self, Rng, SeedableRng};
|
||||
use rand_pcg;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::thread;
|
||||
|
||||
const NUM_WORKERS: usize = 8;
|
||||
|
||||
|
@ -22,18 +23,27 @@ pub struct ChunkBuilder {
|
|||
}
|
||||
|
||||
impl ChunkBuilder {
|
||||
pub fn new(resources: Arc<RwLock<resources::Manager>>, textures: Arc<RwLock<render::TextureManager>>) -> ChunkBuilder {
|
||||
let models = Arc::new(RwLock::new(model::Factory::new(resources.clone(), textures)));
|
||||
pub fn new(
|
||||
resources: Arc<RwLock<resources::Manager>>,
|
||||
textures: Arc<RwLock<render::TextureManager>>,
|
||||
) -> ChunkBuilder {
|
||||
let models = Arc::new(RwLock::new(model::Factory::new(
|
||||
resources.clone(),
|
||||
textures,
|
||||
)));
|
||||
|
||||
let mut threads = vec![];
|
||||
let mut free = vec![];
|
||||
let (built_send, built_recv) = mpsc::channel();
|
||||
for i in 0 .. NUM_WORKERS {
|
||||
for i in 0..NUM_WORKERS {
|
||||
let built_send = built_send.clone();
|
||||
let (work_send, work_recv) = mpsc::channel();
|
||||
let models = models.clone();
|
||||
let id = i;
|
||||
threads.push((work_send, thread::spawn(move || build_func(id, models, work_recv, built_send))));
|
||||
threads.push((
|
||||
work_send,
|
||||
thread::spawn(move || build_func(id, models, work_recv, built_send)),
|
||||
));
|
||||
free.push((i, vec![], vec![]));
|
||||
}
|
||||
ChunkBuilder {
|
||||
|
@ -45,7 +55,12 @@ impl ChunkBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, world: &mut world::World, renderer: &mut render::Renderer, version: usize) {
|
||||
pub fn tick(
|
||||
&mut self,
|
||||
world: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
version: usize,
|
||||
) {
|
||||
{
|
||||
if version != self.resource_version {
|
||||
self.resource_version = version;
|
||||
|
@ -56,35 +71,50 @@ impl ChunkBuilder {
|
|||
while let Ok((id, mut val)) = self.built_recv.try_recv() {
|
||||
world.reset_building_flag(val.position);
|
||||
|
||||
if let Some(sec) = world.get_section_mut(val.position.0, val.position.1, val.position.2) {
|
||||
if let Some(sec) = world.get_section_mut(val.position.0, val.position.1, val.position.2)
|
||||
{
|
||||
sec.cull_info = val.cull_info;
|
||||
renderer.update_chunk_solid(&mut sec.render_buffer, &val.solid_buffer, val.solid_count);
|
||||
renderer.update_chunk_trans(&mut sec.render_buffer, &val.trans_buffer, val.trans_count);
|
||||
renderer.update_chunk_solid(
|
||||
&mut sec.render_buffer,
|
||||
&val.solid_buffer,
|
||||
val.solid_count,
|
||||
);
|
||||
renderer.update_chunk_trans(
|
||||
&mut sec.render_buffer,
|
||||
&val.trans_buffer,
|
||||
val.trans_count,
|
||||
);
|
||||
}
|
||||
|
||||
val.solid_buffer.clear();
|
||||
val.trans_buffer.clear();
|
||||
self.free_builders.push((id, val.solid_buffer, val.trans_buffer));
|
||||
self.free_builders
|
||||
.push((id, val.solid_buffer, val.trans_buffer));
|
||||
}
|
||||
if self.free_builders.is_empty() {
|
||||
return;
|
||||
}
|
||||
let dirty_sections = world.get_render_list().iter()
|
||||
.map(|v| v.0)
|
||||
.filter(|v| world.is_section_dirty(*v))
|
||||
.collect::<Vec<_>>();
|
||||
for (x,y, z) in dirty_sections {
|
||||
let dirty_sections = world
|
||||
.get_render_list()
|
||||
.iter()
|
||||
.map(|v| v.0)
|
||||
.filter(|v| world.is_section_dirty(*v))
|
||||
.collect::<Vec<_>>();
|
||||
for (x, y, z) in dirty_sections {
|
||||
let t_id = self.free_builders.pop().unwrap();
|
||||
world.set_building_flag((x, y, z));
|
||||
let (cx, cy, cz) = (x << 4, y << 4, z << 4);
|
||||
let mut snapshot = world.capture_snapshot(cx - 2, cy - 2, cz - 2, 20, 20, 20);
|
||||
snapshot.make_relative(-2, -2, -2);
|
||||
self.threads[t_id.0].0.send(BuildReq {
|
||||
snapshot,
|
||||
position: (x, y, z),
|
||||
solid_buffer: t_id.1,
|
||||
trans_buffer: t_id.2,
|
||||
}).unwrap();
|
||||
self.threads[t_id.0]
|
||||
.0
|
||||
.send(BuildReq {
|
||||
snapshot,
|
||||
position: (x, y, z),
|
||||
solid_buffer: t_id.1,
|
||||
trans_buffer: t_id.2,
|
||||
})
|
||||
.unwrap();
|
||||
if self.free_builders.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
@ -108,8 +138,12 @@ struct BuildReply {
|
|||
cull_info: CullInfo,
|
||||
}
|
||||
|
||||
fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::Receiver<BuildReq>, built_send: mpsc::Sender<(usize, BuildReply)>) {
|
||||
use rand::{self, SeedableRng, Rng};
|
||||
fn build_func(
|
||||
id: usize,
|
||||
models: Arc<RwLock<model::Factory>>,
|
||||
work_recv: mpsc::Receiver<BuildReq>,
|
||||
built_send: mpsc::Sender<(usize, BuildReply)>,
|
||||
) {
|
||||
loop {
|
||||
let BuildReq {
|
||||
snapshot,
|
||||
|
@ -121,22 +155,19 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
|
|||
Err(_) => return,
|
||||
};
|
||||
|
||||
let mut rng = rand::XorShiftRng::from_seed([
|
||||
let mut rng = rand_pcg::Pcg32::from_seed([
|
||||
((position.0 as u32) & 0xff) as u8,
|
||||
(((position.0 as u32) >> 8) & 0xff) as u8,
|
||||
(((position.0 as u32) >> 16) & 0xff) as u8,
|
||||
((position.0 as u32) >> 24) as u8,
|
||||
|
||||
((position.1 as u32) & 0xff) as u8,
|
||||
(((position.1 as u32) >> 8) & 0xff) as u8,
|
||||
(((position.1 as u32) >> 16) & 0xff) as u8,
|
||||
((position.1 as u32) >> 24) as u8,
|
||||
|
||||
((position.2 as u32) & 0xff) as u8,
|
||||
(((position.2 as u32) >> 8) & 0xff) as u8,
|
||||
(((position.2 as u32) >> 16) & 0xff) as u8,
|
||||
((position.2 as u32) >> 24) as u8,
|
||||
|
||||
(((position.0 as u32 ^ position.2 as u32) | 1) & 0xff) as u8,
|
||||
((((position.0 as u32 ^ position.2 as u32) | 1) >> 8) & 0xff) as u8,
|
||||
((((position.0 as u32 ^ position.2 as u32) | 1) >> 16) & 0xff) as u8,
|
||||
|
@ -146,9 +177,9 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
|
|||
let mut solid_count = 0;
|
||||
let mut trans_count = 0;
|
||||
|
||||
for y in 0 .. 16 {
|
||||
for x in 0 .. 16 {
|
||||
for z in 0 .. 16 {
|
||||
for y in 0..16 {
|
||||
for x in 0..16 {
|
||||
for z in 0..16 {
|
||||
let block = snapshot.get_block(x, y, z);
|
||||
let mat = block.get_material();
|
||||
if !mat.renderable {
|
||||
|
@ -160,26 +191,56 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
|
|||
}
|
||||
|
||||
match block {
|
||||
block::Block::Water{..} | block::Block::FlowingWater{..} => {
|
||||
block::Block::Water { .. } | block::Block::FlowingWater { .. } => {
|
||||
let tex = models.read().unwrap().textures.clone();
|
||||
trans_count += model::liquid::render_liquid(tex, false, &snapshot, x, y, z, &mut trans_buffer);
|
||||
trans_count += model::liquid::render_liquid(
|
||||
tex,
|
||||
false,
|
||||
&snapshot,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
&mut trans_buffer,
|
||||
);
|
||||
continue;
|
||||
},
|
||||
block::Block::Lava{..} | block::Block::FlowingLava{..} => {
|
||||
}
|
||||
block::Block::Lava { .. } | block::Block::FlowingLava { .. } => {
|
||||
let tex = models.read().unwrap().textures.clone();
|
||||
solid_count += model::liquid::render_liquid(tex, true, &snapshot, x, y, z, &mut solid_buffer);
|
||||
solid_count += model::liquid::render_liquid(
|
||||
tex,
|
||||
true,
|
||||
&snapshot,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
&mut solid_buffer,
|
||||
);
|
||||
continue;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if mat.transparent {
|
||||
trans_count += model::Factory::get_state_model(
|
||||
&models, block, &mut rng, &snapshot, x, y, z, &mut trans_buffer
|
||||
&models,
|
||||
block,
|
||||
&mut rng,
|
||||
&snapshot,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
&mut trans_buffer,
|
||||
);
|
||||
} else {
|
||||
solid_count += model::Factory::get_state_model(
|
||||
&models, block, &mut rng, &snapshot, x, y, z, &mut solid_buffer
|
||||
&models,
|
||||
block,
|
||||
&mut rng,
|
||||
&snapshot,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
&mut solid_buffer,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -188,14 +249,19 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
|
|||
|
||||
let cull_info = build_cull_info(&snapshot);
|
||||
|
||||
built_send.send((id, BuildReply {
|
||||
position,
|
||||
solid_buffer,
|
||||
solid_count,
|
||||
trans_buffer,
|
||||
trans_count,
|
||||
cull_info,
|
||||
})).unwrap();
|
||||
built_send
|
||||
.send((
|
||||
id,
|
||||
BuildReply {
|
||||
position,
|
||||
solid_buffer,
|
||||
solid_count,
|
||||
trans_buffer,
|
||||
trans_count,
|
||||
cull_info,
|
||||
},
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,9 +269,9 @@ fn build_cull_info(snapshot: &world::Snapshot) -> CullInfo {
|
|||
let mut visited = Set::new(16 * 16 * 16);
|
||||
let mut info = CullInfo::new();
|
||||
|
||||
for y in 0 .. 16 {
|
||||
for z in 0 .. 16 {
|
||||
for x in 0 .. 16 {
|
||||
for y in 0..16 {
|
||||
for z in 0..16 {
|
||||
for x in 0..16 {
|
||||
if visited.get(x | (z << 4) | (y << 8)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -245,7 +311,11 @@ fn flood_fill(snapshot: &world::Snapshot, visited: &mut Set, x: i32, y: i32, z:
|
|||
}
|
||||
visited.set(idx, true);
|
||||
|
||||
if snapshot.get_block(x, y, z).get_material().should_cull_against {
|
||||
if snapshot
|
||||
.get_block(x, y, z)
|
||||
.get_material()
|
||||
.should_cull_against
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -267,7 +337,7 @@ fn flood_fill(snapshot: &world::Snapshot, visited: &mut Set, x: i32, y: i32, z:
|
|||
|
||||
for d in Direction::all() {
|
||||
let (ox, oy, oz) = d.get_offset();
|
||||
next_position.push_back((x+ox, y+oy, z+oz));
|
||||
next_position.push_back((x + ox, y + oy, z + oz));
|
||||
}
|
||||
}
|
||||
touched
|
||||
|
@ -277,7 +347,9 @@ fn flood_fill(snapshot: &world::Snapshot, visited: &mut Set, x: i32, y: i32, z:
|
|||
pub struct CullInfo(u64);
|
||||
|
||||
impl CullInfo {
|
||||
pub fn new() -> CullInfo { Default::default() }
|
||||
pub fn new() -> CullInfo {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn all_vis() -> CullInfo {
|
||||
CullInfo(0xFFFFFFFFFFFFFFFF)
|
||||
|
|
|
@ -12,18 +12,37 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::collections::HashMap;
|
||||
use std::any::Any;
|
||||
use std::cell::{RefCell, Ref};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::fs;
|
||||
use std::io::{BufWriter, Write, BufRead, BufReader};
|
||||
use log;
|
||||
use std::any::Any;
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::collections::HashMap;
|
||||
use std::io::{BufRead, BufReader, BufWriter, Write};
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std_or_web::fs;
|
||||
|
||||
use crate::ui;
|
||||
use crate::format::{Color, Component, TextComponent};
|
||||
use crate::render;
|
||||
use crate::format::{Component, TextComponent, Color};
|
||||
use crate::ui;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use web_sys;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn println_level(level: log::Level, s: String) {
|
||||
let value = &wasm_bindgen::JsValue::from_str(&s);
|
||||
use log::Level::*;
|
||||
match level {
|
||||
Trace => web_sys::console::debug_1(value),
|
||||
Debug => web_sys::console::log_1(value),
|
||||
Info => web_sys::console::info_1(value),
|
||||
Warn => web_sys::console::warn_1(value),
|
||||
Error => web_sys::console::error_1(value),
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn println_level(_level: log::Level, s: String) {
|
||||
println!("{}", s);
|
||||
}
|
||||
|
||||
const FILTERED_CRATES: &[&str] = &[
|
||||
//"reqwest", // TODO: needed?
|
||||
|
@ -36,15 +55,15 @@ pub struct CVar<T: Sized + Any + 'static> {
|
|||
pub description: &'static str,
|
||||
pub mutable: bool,
|
||||
pub serializable: bool,
|
||||
pub default: &'static Fn() -> T,
|
||||
pub default: &'static dyn Fn() -> T,
|
||||
}
|
||||
|
||||
impl Var for CVar<i64> {
|
||||
fn serialize(&self, val: &Box<Any>) -> String {
|
||||
fn serialize(&self, val: &Box<dyn Any>) -> String {
|
||||
val.downcast_ref::<i64>().unwrap().to_string()
|
||||
}
|
||||
|
||||
fn deserialize(&self, input: &str) -> Box<Any> {
|
||||
fn deserialize(&self, input: &str) -> Box<dyn Any> {
|
||||
Box::new(input.parse::<i64>().unwrap())
|
||||
}
|
||||
|
||||
|
@ -58,11 +77,11 @@ impl Var for CVar<i64> {
|
|||
}
|
||||
|
||||
impl Var for CVar<bool> {
|
||||
fn serialize(&self, val: &Box<Any>) -> String {
|
||||
fn serialize(&self, val: &Box<dyn Any>) -> String {
|
||||
val.downcast_ref::<bool>().unwrap().to_string()
|
||||
}
|
||||
|
||||
fn deserialize(&self, input: &str) -> Box<Any> {
|
||||
fn deserialize(&self, input: &str) -> Box<dyn Any> {
|
||||
Box::new(input.parse::<bool>().unwrap())
|
||||
}
|
||||
|
||||
|
@ -76,11 +95,11 @@ impl Var for CVar<bool> {
|
|||
}
|
||||
|
||||
impl Var for CVar<String> {
|
||||
fn serialize(&self, val: &Box<Any>) -> String {
|
||||
fn serialize(&self, val: &Box<dyn Any>) -> String {
|
||||
format!("\"{}\"", val.downcast_ref::<String>().unwrap())
|
||||
}
|
||||
|
||||
fn deserialize(&self, input: &str) -> Box<Any> {
|
||||
fn deserialize(&self, input: &str) -> Box<dyn Any> {
|
||||
Box::new((&input[1..input.len() - 1]).to_owned())
|
||||
}
|
||||
|
||||
|
@ -93,8 +112,8 @@ impl Var for CVar<String> {
|
|||
}
|
||||
|
||||
pub trait Var {
|
||||
fn serialize(&self, val: &Box<Any>) -> String;
|
||||
fn deserialize(&self, input: &str) -> Box<Any>;
|
||||
fn serialize(&self, val: &Box<dyn Any>) -> String;
|
||||
fn deserialize(&self, input: &str) -> Box<dyn Any>;
|
||||
fn description(&self) -> &'static str;
|
||||
fn can_serialize(&self) -> bool;
|
||||
}
|
||||
|
@ -102,26 +121,31 @@ pub trait Var {
|
|||
#[derive(Default)]
|
||||
pub struct Vars {
|
||||
names: HashMap<String, &'static str>,
|
||||
vars: HashMap<&'static str, Box<Var>>,
|
||||
var_values: HashMap<&'static str, RefCell<Box<Any>>>,
|
||||
vars: HashMap<&'static str, Box<dyn Var>>,
|
||||
var_values: HashMap<&'static str, RefCell<Box<dyn Any>>>,
|
||||
}
|
||||
|
||||
impl Vars {
|
||||
pub fn new() -> Vars { Default::default() }
|
||||
pub fn new() -> Vars {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn register<T: Sized + Any>(&mut self, var: CVar<T>)
|
||||
where CVar<T>: Var
|
||||
where
|
||||
CVar<T>: Var,
|
||||
{
|
||||
if self.vars.contains_key(var.name) {
|
||||
panic!("Key registered twice {}", var.name);
|
||||
}
|
||||
self.names.insert(var.name.to_owned(), var.name);
|
||||
self.var_values.insert(var.name, RefCell::new(Box::new((var.default)())));
|
||||
self.var_values
|
||||
.insert(var.name, RefCell::new(Box::new((var.default)())));
|
||||
self.vars.insert(var.name, Box::new(var));
|
||||
}
|
||||
|
||||
pub fn get<T: Sized + Any>(&self, var: CVar<T>) -> Ref<T>
|
||||
where CVar<T>: Var
|
||||
where
|
||||
CVar<T>: Var,
|
||||
{
|
||||
// Should never fail
|
||||
let var = self.var_values.get(var.name).unwrap().borrow();
|
||||
|
@ -129,7 +153,8 @@ impl Vars {
|
|||
}
|
||||
|
||||
pub fn set<T: Sized + Any>(&self, var: CVar<T>, val: T)
|
||||
where CVar<T>: Var
|
||||
where
|
||||
CVar<T>: Var,
|
||||
{
|
||||
*self.var_values.get(var.name).unwrap().borrow_mut() = Box::new(val);
|
||||
self.save_config();
|
||||
|
@ -143,7 +168,10 @@ impl Vars {
|
|||
if line.starts_with('#') || line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let parts = line.splitn(2, ' ').map(|v| v.to_owned()).collect::<Vec<String>>();
|
||||
let parts = line
|
||||
.splitn(2, ' ')
|
||||
.map(|v| v.to_owned())
|
||||
.collect::<Vec<String>>();
|
||||
let (name, arg) = (&parts[0], &parts[1]);
|
||||
if let Some(var_name) = self.names.get(name) {
|
||||
let var = self.vars.get(var_name).unwrap();
|
||||
|
@ -165,11 +193,13 @@ impl Vars {
|
|||
for line in var.description().lines() {
|
||||
write!(file, "# {}\n", line).unwrap();
|
||||
}
|
||||
write!(file,
|
||||
"{} {}\n\n",
|
||||
name,
|
||||
var.serialize(&self.var_values.get(name).unwrap().borrow()))
|
||||
.unwrap();
|
||||
write!(
|
||||
file,
|
||||
"{} {}\n\n",
|
||||
name,
|
||||
var.serialize(&self.var_values.get(name).unwrap().borrow())
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -208,11 +238,13 @@ impl Console {
|
|||
self.active = !self.active;
|
||||
}
|
||||
|
||||
pub fn tick(&mut self,
|
||||
ui_container: &mut ui::Container,
|
||||
renderer: &render::Renderer,
|
||||
delta: f64,
|
||||
width: f64) {
|
||||
pub fn tick(
|
||||
&mut self,
|
||||
ui_container: &mut ui::Container,
|
||||
renderer: &render::Renderer,
|
||||
delta: f64,
|
||||
width: f64,
|
||||
) {
|
||||
if !self.active && self.position <= -220.0 {
|
||||
self.elements = None;
|
||||
return;
|
||||
|
@ -262,12 +294,14 @@ impl Console {
|
|||
break;
|
||||
}
|
||||
let (_, height) = ui::Formatted::compute_size(renderer, line, w - 10.0);
|
||||
elements.lines.push(ui::FormattedBuilder::new()
|
||||
.text(line.clone())
|
||||
.position(5.0, 5.0 + offset)
|
||||
.max_width(w - 10.0)
|
||||
.alignment(ui::VAttach::Bottom, ui::HAttach::Left)
|
||||
.create(&mut *background));
|
||||
elements.lines.push(
|
||||
ui::FormattedBuilder::new()
|
||||
.text(line.clone())
|
||||
.position(5.0, 5.0 + offset)
|
||||
.max_width(w - 10.0)
|
||||
.alignment(ui::VAttach::Bottom, ui::HAttach::Left)
|
||||
.create(&mut *background),
|
||||
);
|
||||
offset += height;
|
||||
}
|
||||
}
|
||||
|
@ -285,11 +319,16 @@ impl Console {
|
|||
file = &file[pos + 4..];
|
||||
}
|
||||
|
||||
println!("[{}:{}][{}] {}",
|
||||
file,
|
||||
record.line().unwrap_or(0),
|
||||
record.level(),
|
||||
record.args());
|
||||
println_level(
|
||||
record.level(),
|
||||
format!(
|
||||
"[{}:{}][{}] {}",
|
||||
file,
|
||||
record.line().unwrap_or(0),
|
||||
record.level(),
|
||||
record.args()
|
||||
),
|
||||
);
|
||||
self.history.remove(0);
|
||||
let mut msg = TextComponent::new("");
|
||||
msg.modifier.extra = Some(vec![
|
||||
|
@ -319,7 +358,7 @@ impl Console {
|
|||
Component::Text(msg)
|
||||
},
|
||||
Component::Text(TextComponent::new("] ")),
|
||||
Component::Text(TextComponent::new(&format!("{}", record.args())))
|
||||
Component::Text(TextComponent::new(&format!("{}", record.args()))),
|
||||
]);
|
||||
self.history.push(Component::Text(msg));
|
||||
self.dirty = true;
|
||||
|
@ -347,8 +386,7 @@ impl log::Log for ConsoleProxy {
|
|||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {
|
||||
}
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
unsafe impl Send for ConsoleProxy {}
|
||||
|
|
246
src/ecs/mod.rs
246
src/ecs/mod.rs
|
@ -13,17 +13,17 @@
|
|||
// limitations under the License.
|
||||
|
||||
use crate::types::bit::Set as BSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::hash::BuildHasherDefault;
|
||||
use crate::types::hash::FNVHash;
|
||||
use std::any::{Any, TypeId};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::hash::BuildHasherDefault;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
use crate::world;
|
||||
use crate::render;
|
||||
use crate::world;
|
||||
|
||||
/// Used to reference an entity.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
|
@ -38,7 +38,7 @@ pub struct Key<T> {
|
|||
id: usize,
|
||||
_t: PhantomData<T>,
|
||||
}
|
||||
impl <T> Clone for Key<T> {
|
||||
impl<T> Clone for Key<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Key {
|
||||
id: self.id,
|
||||
|
@ -46,7 +46,7 @@ impl <T> Clone for Key<T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl <T> Copy for Key<T> {}
|
||||
impl<T> Copy for Key<T> {}
|
||||
|
||||
/// Used to search for entities with the requested components.
|
||||
pub struct Filter {
|
||||
|
@ -56,9 +56,7 @@ pub struct Filter {
|
|||
impl Filter {
|
||||
/// Creates an empty filter which matches everything
|
||||
pub fn new() -> Filter {
|
||||
Filter {
|
||||
bits: BSet::new(0),
|
||||
}
|
||||
Filter { bits: BSet::new(0) }
|
||||
}
|
||||
|
||||
/// Adds the component to the filter.
|
||||
|
@ -74,12 +72,29 @@ impl Filter {
|
|||
/// A system processes entities
|
||||
pub trait System {
|
||||
fn filter(&self) -> &Filter;
|
||||
fn update(&mut self, m: &mut Manager, world: &mut world::World, renderer: &mut render::Renderer);
|
||||
fn update(
|
||||
&mut self,
|
||||
m: &mut Manager,
|
||||
world: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
);
|
||||
|
||||
fn entity_added(&mut self, _m: &mut Manager, _e: Entity, _world: &mut world::World, _renderer: &mut render::Renderer) {
|
||||
fn entity_added(
|
||||
&mut self,
|
||||
_m: &mut Manager,
|
||||
_e: Entity,
|
||||
_world: &mut world::World,
|
||||
_renderer: &mut render::Renderer,
|
||||
) {
|
||||
}
|
||||
|
||||
fn entity_removed(&mut self, _m: &mut Manager, _e: Entity, _world: &mut world::World, _renderer: &mut render::Renderer) {
|
||||
fn entity_removed(
|
||||
&mut self,
|
||||
_m: &mut Manager,
|
||||
_e: Entity,
|
||||
_world: &mut world::World,
|
||||
_renderer: &mut render::Renderer,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,8 +114,8 @@ pub struct Manager {
|
|||
|
||||
component_ids: RefCell<HashMap<TypeId, usize, BuildHasherDefault<FNVHash>>>,
|
||||
|
||||
systems: Option<Vec<Box<System + Send>>>,
|
||||
render_systems: Option<Vec<Box<System + Send>>>,
|
||||
systems: Option<Vec<Box<dyn System + Send>>>,
|
||||
render_systems: Option<Vec<Box<dyn System + Send>>>,
|
||||
|
||||
changed_entity_components: HashSet<Entity, BuildHasherDefault<FNVHash>>,
|
||||
}
|
||||
|
@ -110,11 +125,14 @@ impl Manager {
|
|||
pub fn new() -> Manager {
|
||||
Manager {
|
||||
num_components: 0,
|
||||
entities: vec![(Some(EntityState {
|
||||
last_components: BSet::new(0),
|
||||
components: BSet::new(0),
|
||||
removed: false,
|
||||
}), 0)], // Has the world entity pre-defined
|
||||
entities: vec![(
|
||||
Some(EntityState {
|
||||
last_components: BSet::new(0),
|
||||
components: BSet::new(0),
|
||||
removed: false,
|
||||
}),
|
||||
0,
|
||||
)], // Has the world entity pre-defined
|
||||
free_entities: vec![],
|
||||
components: vec![],
|
||||
|
||||
|
@ -166,7 +184,11 @@ impl Manager {
|
|||
self.process_entity_changes(world, renderer);
|
||||
}
|
||||
|
||||
fn process_entity_changes(&mut self, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||
fn process_entity_changes(
|
||||
&mut self,
|
||||
world: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
) {
|
||||
let changes = self.changed_entity_components.clone();
|
||||
self.changed_entity_components = HashSet::with_hasher(BuildHasherDefault::default());
|
||||
for entity in changes {
|
||||
|
@ -177,11 +199,35 @@ impl Manager {
|
|||
state.components.or(&state.last_components);
|
||||
(cur, orig)
|
||||
};
|
||||
self.trigger_add_for_systems(entity, &state.last_components, &state.components, world, renderer);
|
||||
self.trigger_add_for_render_systems(entity, &state.last_components, &state.components, world, renderer);
|
||||
self.trigger_remove_for_systems(entity, &state.last_components, &state.components, world, renderer);
|
||||
self.trigger_remove_for_render_systems(entity, &state.last_components, &state.components, world, renderer);
|
||||
for i in 0 .. self.components.len() {
|
||||
self.trigger_add_for_systems(
|
||||
entity,
|
||||
&state.last_components,
|
||||
&state.components,
|
||||
world,
|
||||
renderer,
|
||||
);
|
||||
self.trigger_add_for_render_systems(
|
||||
entity,
|
||||
&state.last_components,
|
||||
&state.components,
|
||||
world,
|
||||
renderer,
|
||||
);
|
||||
self.trigger_remove_for_systems(
|
||||
entity,
|
||||
&state.last_components,
|
||||
&state.components,
|
||||
world,
|
||||
renderer,
|
||||
);
|
||||
self.trigger_remove_for_render_systems(
|
||||
entity,
|
||||
&state.last_components,
|
||||
&state.components,
|
||||
world,
|
||||
renderer,
|
||||
);
|
||||
for i in 0..self.components.len() {
|
||||
if !state.components.get(i) && state.last_components.get(i) {
|
||||
let components = self.components.get_mut(i).and_then(|v| v.as_mut()).unwrap();
|
||||
components.remove(entity.id);
|
||||
|
@ -230,7 +276,7 @@ impl Manager {
|
|||
return Entity {
|
||||
id,
|
||||
generation: entity.1,
|
||||
}
|
||||
};
|
||||
}
|
||||
let id = self.entities.len();
|
||||
self.entities.push((
|
||||
|
@ -239,12 +285,9 @@ impl Manager {
|
|||
components: BSet::new(self.num_components),
|
||||
removed: false,
|
||||
}),
|
||||
0
|
||||
0,
|
||||
));
|
||||
Entity {
|
||||
id,
|
||||
generation: 0,
|
||||
}
|
||||
Entity { id, generation: 0 }
|
||||
}
|
||||
|
||||
/// Deallocates an entity and frees its components
|
||||
|
@ -257,12 +300,16 @@ impl Manager {
|
|||
}
|
||||
|
||||
/// Deallocates all entities/components excluding the world entity
|
||||
pub fn remove_all_entities(&mut self, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||
pub fn remove_all_entities(
|
||||
&mut self,
|
||||
world: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
) {
|
||||
for (id, e) in self.entities[1..].iter_mut().enumerate() {
|
||||
if let Some(set) = e.0.as_mut() {
|
||||
set.components = BSet::new(self.components.len());
|
||||
set.removed = true;
|
||||
self.changed_entity_components.insert(Entity{
|
||||
self.changed_entity_components.insert(Entity {
|
||||
id: id + 1,
|
||||
generation: e.1,
|
||||
});
|
||||
|
@ -312,7 +359,13 @@ impl Manager {
|
|||
}
|
||||
let mut e = self.entities.get_mut(entity.id);
|
||||
let set = match e {
|
||||
Some(ref mut val) => if val.1 == entity.generation { &mut val.0 } else { panic!("Missing entity") },
|
||||
Some(ref mut val) => {
|
||||
if val.1 == entity.generation {
|
||||
&mut val.0
|
||||
} else {
|
||||
panic!("Missing entity")
|
||||
}
|
||||
}
|
||||
None => panic!("Missing entity"),
|
||||
};
|
||||
let set = match set.as_mut() {
|
||||
|
@ -327,24 +380,44 @@ impl Manager {
|
|||
}
|
||||
set.components.set(key.id, true);
|
||||
self.changed_entity_components.insert(entity);
|
||||
let components = self.components.get_mut(key.id).and_then(|v| v.as_mut()).unwrap();
|
||||
let components = self
|
||||
.components
|
||||
.get_mut(key.id)
|
||||
.and_then(|v| v.as_mut())
|
||||
.unwrap();
|
||||
components.add(entity.id, val);
|
||||
}
|
||||
|
||||
fn trigger_add_for_systems(&mut self, e: Entity, old_set: &BSet, new_set: &BSet, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||
fn trigger_add_for_systems(
|
||||
&mut self,
|
||||
e: Entity,
|
||||
old_set: &BSet,
|
||||
new_set: &BSet,
|
||||
world: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
) {
|
||||
let mut systems = self.systems.take().unwrap();
|
||||
for sys in &mut systems {
|
||||
if new_set.includes_set(&sys.filter().bits) && !old_set.includes_set(&sys.filter().bits) {
|
||||
if new_set.includes_set(&sys.filter().bits) && !old_set.includes_set(&sys.filter().bits)
|
||||
{
|
||||
sys.entity_added(self, e, world, renderer);
|
||||
}
|
||||
}
|
||||
self.systems = Some(systems);
|
||||
}
|
||||
|
||||
fn trigger_add_for_render_systems(&mut self, e: Entity, old_set: &BSet, new_set: &BSet, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||
fn trigger_add_for_render_systems(
|
||||
&mut self,
|
||||
e: Entity,
|
||||
old_set: &BSet,
|
||||
new_set: &BSet,
|
||||
world: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
) {
|
||||
let mut systems = self.render_systems.take().unwrap();
|
||||
for sys in &mut systems {
|
||||
if new_set.includes_set(&sys.filter().bits) && !old_set.includes_set(&sys.filter().bits) {
|
||||
if new_set.includes_set(&sys.filter().bits) && !old_set.includes_set(&sys.filter().bits)
|
||||
{
|
||||
sys.entity_added(self, e, world, renderer);
|
||||
}
|
||||
}
|
||||
|
@ -371,7 +444,13 @@ impl Manager {
|
|||
}
|
||||
let mut e = self.entities.get_mut(entity.id);
|
||||
let set = match e {
|
||||
Some(ref mut val) => if val.1 == entity.generation { &mut val.0 } else { panic!("Missing entity") },
|
||||
Some(ref mut val) => {
|
||||
if val.1 == entity.generation {
|
||||
&mut val.0
|
||||
} else {
|
||||
panic!("Missing entity")
|
||||
}
|
||||
}
|
||||
None => panic!("Missing entity"),
|
||||
};
|
||||
let set = match set.as_mut() {
|
||||
|
@ -382,7 +461,7 @@ impl Manager {
|
|||
panic!("Double change within a single tick");
|
||||
}
|
||||
if !set.components.get(key.id) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
set.components.set(key.id, false);
|
||||
self.changed_entity_components.insert(entity);
|
||||
|
@ -390,20 +469,36 @@ impl Manager {
|
|||
true
|
||||
}
|
||||
|
||||
fn trigger_remove_for_systems(&mut self, e: Entity, old_set: &BSet, new_set: &BSet, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||
fn trigger_remove_for_systems(
|
||||
&mut self,
|
||||
e: Entity,
|
||||
old_set: &BSet,
|
||||
new_set: &BSet,
|
||||
world: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
) {
|
||||
let mut systems = self.systems.take().unwrap();
|
||||
for sys in &mut systems {
|
||||
if !new_set.includes_set(&sys.filter().bits) && old_set.includes_set(&sys.filter().bits) {
|
||||
if !new_set.includes_set(&sys.filter().bits) && old_set.includes_set(&sys.filter().bits)
|
||||
{
|
||||
sys.entity_removed(self, e, world, renderer);
|
||||
}
|
||||
}
|
||||
self.systems = Some(systems);
|
||||
}
|
||||
|
||||
fn trigger_remove_for_render_systems(&mut self, e: Entity, old_set: &BSet, new_set: &BSet, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||
fn trigger_remove_for_render_systems(
|
||||
&mut self,
|
||||
e: Entity,
|
||||
old_set: &BSet,
|
||||
new_set: &BSet,
|
||||
world: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
) {
|
||||
let mut systems = self.render_systems.take().unwrap();
|
||||
for sys in &mut systems {
|
||||
if !new_set.includes_set(&sys.filter().bits) && old_set.includes_set(&sys.filter().bits) {
|
||||
if !new_set.includes_set(&sys.filter().bits) && old_set.includes_set(&sys.filter().bits)
|
||||
{
|
||||
sys.entity_removed(self, e, world, renderer);
|
||||
}
|
||||
}
|
||||
|
@ -424,7 +519,13 @@ impl Manager {
|
|||
None => return None,
|
||||
};
|
||||
let set = match self.entities.get(entity.id).as_ref() {
|
||||
Some(val) => if val.1 == entity.generation { &val.0 } else { return None },
|
||||
Some(val) => {
|
||||
if val.1 == entity.generation {
|
||||
&val.0
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
None => return None,
|
||||
};
|
||||
if !set.as_ref().map_or(false, |v| v.components.get(key.id)) {
|
||||
|
@ -442,13 +543,23 @@ impl Manager {
|
|||
}
|
||||
|
||||
/// Returns the given component that the key points to if it exists.
|
||||
pub fn get_component_mut<'a, 'b: 'a, T>(&'a mut self, entity: Entity, key: Key<T>) -> Option<&'b mut T> {
|
||||
pub fn get_component_mut<'a, 'b: 'a, T>(
|
||||
&'a mut self,
|
||||
entity: Entity,
|
||||
key: Key<T>,
|
||||
) -> Option<&'b mut T> {
|
||||
let components = match self.components.get_mut(key.id).and_then(|v| v.as_mut()) {
|
||||
Some(val) => val,
|
||||
None => return None,
|
||||
};
|
||||
let set = match self.entities.get(entity.id).as_ref() {
|
||||
Some(val) => if val.1 == entity.generation { &val.0 } else { return None },
|
||||
Some(val) => {
|
||||
if val.1 == entity.generation {
|
||||
&val.0
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
None => return None,
|
||||
};
|
||||
if !set.as_ref().map_or(false, |v| v.components.get(key.id)) {
|
||||
|
@ -460,7 +571,10 @@ impl Manager {
|
|||
|
||||
/// Same as `get_component_mut` but doesn't require a key. Using a key
|
||||
/// is better for frequent lookups.
|
||||
pub fn get_component_mut_direct<'a, 'b: 'a, T: Any>(&'a mut self, entity: Entity) -> Option<&'b mut T> {
|
||||
pub fn get_component_mut_direct<'a, 'b: 'a, T: Any>(
|
||||
&'a mut self,
|
||||
entity: Entity,
|
||||
) -> Option<&'b mut T> {
|
||||
let key = self.get_key();
|
||||
self.get_component_mut(entity, key)
|
||||
}
|
||||
|
@ -471,7 +585,7 @@ const COMPONENTS_PER_BLOCK: usize = 64;
|
|||
struct ComponentMem {
|
||||
data: Vec<Option<(Vec<u8>, BSet, usize)>>,
|
||||
component_size: usize,
|
||||
drop_func: Box<Fn(*mut u8) + Send>,
|
||||
drop_func: Box<dyn Fn(*mut u8) + Send>,
|
||||
}
|
||||
|
||||
impl ComponentMem {
|
||||
|
@ -479,12 +593,10 @@ impl ComponentMem {
|
|||
ComponentMem {
|
||||
data: vec![],
|
||||
component_size: mem::size_of::<T>(),
|
||||
drop_func: Box::new(|data| {
|
||||
unsafe {
|
||||
let mut val: T = mem::uninitialized();
|
||||
ptr::copy(data as *mut T, &mut val, 1);
|
||||
mem::drop(val);
|
||||
}
|
||||
drop_func: Box::new(|data| unsafe {
|
||||
let mut val: T = mem::MaybeUninit::uninit().assume_init();
|
||||
ptr::copy(data as *mut T, &mut val, 1);
|
||||
mem::drop(val);
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -496,7 +608,11 @@ impl ComponentMem {
|
|||
let idx = index / COMPONENTS_PER_BLOCK;
|
||||
let rem = index % COMPONENTS_PER_BLOCK;
|
||||
if self.data[idx].is_none() {
|
||||
self.data[idx] = Some((vec![0; self.component_size * COMPONENTS_PER_BLOCK], BSet::new(COMPONENTS_PER_BLOCK), 0));
|
||||
self.data[idx] = Some((
|
||||
vec![0; self.component_size * COMPONENTS_PER_BLOCK],
|
||||
BSet::new(COMPONENTS_PER_BLOCK),
|
||||
0,
|
||||
));
|
||||
}
|
||||
let data = self.data[idx].as_mut().unwrap();
|
||||
let start = rem * self.component_size;
|
||||
|
@ -518,7 +634,9 @@ impl ComponentMem {
|
|||
// We don't have access to the actual type in this method so
|
||||
// we use the drop_func which stores the type in its closure
|
||||
// to handle the dropping for us.
|
||||
unsafe { (self.drop_func)(data.0.as_mut_ptr().offset(start as isize)); }
|
||||
unsafe {
|
||||
(self.drop_func)(data.0.as_mut_ptr().offset(start as isize));
|
||||
}
|
||||
data.2 -= 1;
|
||||
data.2
|
||||
};
|
||||
|
@ -532,9 +650,7 @@ impl ComponentMem {
|
|||
let rem = index % COMPONENTS_PER_BLOCK;
|
||||
let data = self.data[idx].as_ref().unwrap();
|
||||
let start = rem * self.component_size;
|
||||
unsafe {
|
||||
&*(data.0.as_ptr().offset(start as isize) as *const T)
|
||||
}
|
||||
unsafe { &*(data.0.as_ptr().offset(start as isize) as *const T) }
|
||||
}
|
||||
|
||||
fn get_mut<T>(&mut self, index: usize) -> &mut T {
|
||||
|
@ -542,9 +658,7 @@ impl ComponentMem {
|
|||
let rem = index % COMPONENTS_PER_BLOCK;
|
||||
let data = self.data[idx].as_mut().unwrap();
|
||||
let start = rem * self.component_size;
|
||||
unsafe {
|
||||
&mut *(data.0.as_mut_ptr().offset(start as isize) as *mut T)
|
||||
}
|
||||
unsafe { &mut *(data.0.as_mut_ptr().offset(start as isize) as *mut T) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -552,10 +666,12 @@ impl Drop for ComponentMem {
|
|||
fn drop(&mut self) {
|
||||
for data in &mut self.data {
|
||||
if let Some(data) = data.as_mut() {
|
||||
for i in 0 .. COMPONENTS_PER_BLOCK {
|
||||
for i in 0..COMPONENTS_PER_BLOCK {
|
||||
if data.1.get(i) {
|
||||
let start = i * self.component_size;
|
||||
unsafe { (self.drop_func)(data.0.as_mut_ptr().offset(start as isize)); }
|
||||
unsafe {
|
||||
(self.drop_func)(data.0.as_mut_ptr().offset(start as isize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
|
||||
pub mod sign;
|
||||
|
||||
use crate::world::block::Block;
|
||||
use crate::shared::Position;
|
||||
use crate::ecs;
|
||||
use crate::shared::Position;
|
||||
use crate::world::block::Block;
|
||||
|
||||
pub fn add_systems(m: &mut ecs::Manager) {
|
||||
sign::add_systems(m);
|
||||
}
|
||||
|
||||
pub enum BlockEntityType {
|
||||
Sign
|
||||
Sign,
|
||||
}
|
||||
|
||||
impl BlockEntityType {
|
||||
pub fn get_block_entity(bl: Block) -> Option<BlockEntityType> {
|
||||
match bl {
|
||||
Block::StandingSign{..} | Block::WallSign{..} => Some(BlockEntityType::Sign),
|
||||
Block::StandingSign { .. } | Block::WallSign { .. } => Some(BlockEntityType::Sign),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
|
||||
use crate::ecs;
|
||||
use crate::format::{self, Component};
|
||||
use crate::render;
|
||||
use crate::render::model::{self, FormatState};
|
||||
use crate::shared::{Direction, Position};
|
||||
use crate::world;
|
||||
use crate::world::block::Block;
|
||||
use crate::render;
|
||||
use crate::render::model::{self, FormatState};
|
||||
|
||||
pub fn add_systems(m: &mut ecs::Manager) {
|
||||
let sys = SignRenderer::new(m);
|
||||
|
@ -13,21 +12,24 @@ pub fn add_systems(m: &mut ecs::Manager) {
|
|||
}
|
||||
|
||||
pub fn init_entity(m: &mut ecs::Manager, e: ecs::Entity) {
|
||||
m.add_component_direct(e, SignInfo {
|
||||
model: None,
|
||||
lines: [
|
||||
Component::Text(format::TextComponent::new("")),
|
||||
Component::Text(format::TextComponent::new("")),
|
||||
Component::Text(format::TextComponent::new("")),
|
||||
Component::Text(format::TextComponent::new("")),
|
||||
],
|
||||
offset_x: 0.0,
|
||||
offset_y: 0.0,
|
||||
offset_z: 0.0,
|
||||
has_stand: false,
|
||||
rotation: 0.0,
|
||||
dirty: false,
|
||||
});
|
||||
m.add_component_direct(
|
||||
e,
|
||||
SignInfo {
|
||||
model: None,
|
||||
lines: [
|
||||
Component::Text(format::TextComponent::new("")),
|
||||
Component::Text(format::TextComponent::new("")),
|
||||
Component::Text(format::TextComponent::new("")),
|
||||
Component::Text(format::TextComponent::new("")),
|
||||
],
|
||||
offset_x: 0.0,
|
||||
offset_y: 0.0,
|
||||
offset_z: 0.0,
|
||||
has_stand: false,
|
||||
rotation: 0.0,
|
||||
dirty: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub struct SignInfo {
|
||||
|
@ -54,9 +56,7 @@ impl SignRenderer {
|
|||
let sign_info = m.get_key();
|
||||
let position = m.get_key();
|
||||
SignRenderer {
|
||||
filter: ecs::Filter::new()
|
||||
.with(position)
|
||||
.with(sign_info),
|
||||
filter: ecs::Filter::new().with(position).with(sign_info),
|
||||
position,
|
||||
sign_info,
|
||||
}
|
||||
|
@ -64,12 +64,16 @@ impl SignRenderer {
|
|||
}
|
||||
|
||||
impl ecs::System for SignRenderer {
|
||||
|
||||
fn filter(&self) -> &ecs::Filter {
|
||||
&self.filter
|
||||
}
|
||||
|
||||
fn update(&mut self, m: &mut ecs::Manager, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||
fn update(
|
||||
&mut self,
|
||||
m: &mut ecs::Manager,
|
||||
world: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
) {
|
||||
for e in m.find(&self.filter) {
|
||||
let position = *m.get_component(e, self.position).unwrap();
|
||||
let info = m.get_component_mut(e, self.sign_info).unwrap();
|
||||
|
@ -85,24 +89,30 @@ impl ecs::System for SignRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
fn entity_added(&mut self, m: &mut ecs::Manager, e: ecs::Entity, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||
fn entity_added(
|
||||
&mut self,
|
||||
m: &mut ecs::Manager,
|
||||
e: ecs::Entity,
|
||||
world: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
) {
|
||||
use cgmath::{Decomposed, Matrix4, Quaternion, Rad, Rotation3, Vector3};
|
||||
use std::f64::consts::PI;
|
||||
use cgmath::{Vector3, Matrix4, Decomposed, Rotation3, Rad, Quaternion};
|
||||
let position = *m.get_component(e, self.position).unwrap();
|
||||
let info = m.get_component_mut(e, self.sign_info).unwrap();
|
||||
info.dirty = false;
|
||||
match world.get_block(position) {
|
||||
Block::WallSign{facing, ..} => {
|
||||
Block::WallSign { facing, .. } => {
|
||||
info.offset_z = 7.5 / 16.0;
|
||||
match facing {
|
||||
Direction::North => {},
|
||||
Direction::North => {}
|
||||
Direction::South => info.rotation = PI,
|
||||
Direction::West => info.rotation = PI / 2.0,
|
||||
Direction::East => info.rotation = -PI / 2.0,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
},
|
||||
Block::StandingSign{rotation, ..} => {
|
||||
}
|
||||
Block::StandingSign { rotation, .. } => {
|
||||
info.offset_y = 5.0 / 16.0;
|
||||
info.has_stand = true;
|
||||
info.rotation = -(rotation.data() as f64 / 16.0) * PI * 2.0 + PI;
|
||||
|
@ -112,30 +122,48 @@ impl ecs::System for SignRenderer {
|
|||
let tex = render::Renderer::get_texture(renderer.get_textures_ref(), "entity/sign");
|
||||
|
||||
macro_rules! rel {
|
||||
($x:expr, $y:expr, $w:expr, $h:expr) => (
|
||||
($x:expr, $y:expr, $w:expr, $h:expr) => {
|
||||
Some(tex.relative(($x) / 64.0, ($y) / 32.0, ($w) / 64.0, ($h) / 32.0))
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
let mut verts = vec![];
|
||||
// Backboard
|
||||
model::append_box(&mut verts, -0.5, -4.0/16.0, -0.5/16.0, 1.0, 8.0/16.0, 1.0/16.0, [
|
||||
rel!(26.0, 0.0, 24.0, 2.0), // Down
|
||||
rel!(2.0, 0.0, 24.0, 2.0), // Up
|
||||
rel!(2.0, 2.0, 24.0, 12.0), // North
|
||||
rel!(26.0, 2.0, 24.0, 12.0), // South
|
||||
rel!(0.0, 2.0, 2.0, 12.0), // West
|
||||
rel!(50.0, 2.0, 2.0, 12.0), // East
|
||||
]);
|
||||
model::append_box(
|
||||
&mut verts,
|
||||
-0.5,
|
||||
-4.0 / 16.0,
|
||||
-0.5 / 16.0,
|
||||
1.0,
|
||||
8.0 / 16.0,
|
||||
1.0 / 16.0,
|
||||
[
|
||||
rel!(26.0, 0.0, 24.0, 2.0), // Down
|
||||
rel!(2.0, 0.0, 24.0, 2.0), // Up
|
||||
rel!(2.0, 2.0, 24.0, 12.0), // North
|
||||
rel!(26.0, 2.0, 24.0, 12.0), // South
|
||||
rel!(0.0, 2.0, 2.0, 12.0), // West
|
||||
rel!(50.0, 2.0, 2.0, 12.0), // East
|
||||
],
|
||||
);
|
||||
if info.has_stand {
|
||||
model::append_box(&mut verts, -0.5/16.0, -0.25-9.0/16.0, -0.5/16.0, 1.0/16.0, 9.0/16.0, 1.0/16.0, [
|
||||
rel!(4.0, 14.0, 2.0, 2.0), // Down
|
||||
rel!(2.0, 14.0, 2.0, 2.0), // Up
|
||||
rel!(2.0, 16.0, 2.0, 12.0), // North
|
||||
rel!(6.0, 16.0, 2.0, 12.0), // South
|
||||
rel!(0.0, 16.0, 2.0, 12.0), // West
|
||||
rel!(4.0, 16.0, 2.0, 12.0), // East
|
||||
]);
|
||||
model::append_box(
|
||||
&mut verts,
|
||||
-0.5 / 16.0,
|
||||
-0.25 - 9.0 / 16.0,
|
||||
-0.5 / 16.0,
|
||||
1.0 / 16.0,
|
||||
9.0 / 16.0,
|
||||
1.0 / 16.0,
|
||||
[
|
||||
rel!(4.0, 14.0, 2.0, 2.0), // Down
|
||||
rel!(2.0, 14.0, 2.0, 2.0), // Up
|
||||
rel!(2.0, 16.0, 2.0, 12.0), // North
|
||||
rel!(6.0, 16.0, 2.0, 12.0), // South
|
||||
rel!(0.0, 16.0, 2.0, 12.0), // West
|
||||
rel!(4.0, 16.0, 2.0, 12.0), // East
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
for (i, line) in info.lines.iter().enumerate() {
|
||||
|
@ -154,15 +182,12 @@ impl ecs::System for SignRenderer {
|
|||
// Center align text
|
||||
for vert in &mut state.text {
|
||||
vert.x += width * 0.5;
|
||||
vert.y -= (Y_SCALE + 0.4/16.0) * (i as f32);
|
||||
vert.y -= (Y_SCALE + 0.4 / 16.0) * (i as f32);
|
||||
}
|
||||
verts.extend_from_slice(&state.text);
|
||||
}
|
||||
|
||||
let model = renderer.model.create_model(
|
||||
model::DEFAULT,
|
||||
vec![verts]
|
||||
);
|
||||
let model = renderer.model.create_model(model::DEFAULT, vec![verts]);
|
||||
|
||||
{
|
||||
let mdl = renderer.model.get_model(model).unwrap();
|
||||
|
@ -173,14 +198,28 @@ impl ecs::System for SignRenderer {
|
|||
mdl.matrix[0] = Matrix4::from(Decomposed {
|
||||
scale: 1.0,
|
||||
rot: Quaternion::from_angle_y(Rad(info.rotation as f32)),
|
||||
disp: Vector3::new(position.x as f32 + 0.5, -position.y as f32 - 0.5, position.z as f32 + 0.5),
|
||||
}) * Matrix4::from_translation(Vector3::new(info.offset_x as f32, -info.offset_y as f32, info.offset_z as f32));
|
||||
disp: Vector3::new(
|
||||
position.x as f32 + 0.5,
|
||||
-position.y as f32 - 0.5,
|
||||
position.z as f32 + 0.5,
|
||||
),
|
||||
}) * Matrix4::from_translation(Vector3::new(
|
||||
info.offset_x as f32,
|
||||
-info.offset_y as f32,
|
||||
info.offset_z as f32,
|
||||
));
|
||||
}
|
||||
|
||||
info.model = Some(model);
|
||||
}
|
||||
|
||||
fn entity_removed(&mut self, m: &mut ecs::Manager, e: ecs::Entity, _: &mut world::World, renderer: &mut render::Renderer) {
|
||||
fn entity_removed(
|
||||
&mut self,
|
||||
m: &mut ecs::Manager,
|
||||
e: ecs::Entity,
|
||||
_: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
) {
|
||||
let info = m.get_component_mut(e, self.sign_info).unwrap();
|
||||
if let Some(model) = info.model {
|
||||
renderer.model.remove_model(model);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
pub mod player;
|
||||
pub mod block_entity;
|
||||
pub mod player;
|
||||
|
||||
use crate::ecs;
|
||||
use cgmath::Vector3;
|
||||
|
@ -96,10 +95,7 @@ pub struct Rotation {
|
|||
|
||||
impl Rotation {
|
||||
pub fn new(yaw: f64, pitch: f64) -> Rotation {
|
||||
Rotation {
|
||||
yaw,
|
||||
pitch,
|
||||
}
|
||||
Rotation { yaw, pitch }
|
||||
}
|
||||
|
||||
pub fn zero() -> Rotation {
|
||||
|
@ -114,10 +110,7 @@ pub struct TargetRotation {
|
|||
|
||||
impl TargetRotation {
|
||||
pub fn new(yaw: f64, pitch: f64) -> TargetRotation {
|
||||
TargetRotation {
|
||||
yaw,
|
||||
pitch,
|
||||
}
|
||||
TargetRotation { yaw, pitch }
|
||||
}
|
||||
|
||||
pub fn zero() -> TargetRotation {
|
||||
|
@ -131,7 +124,9 @@ pub struct Gravity {
|
|||
}
|
||||
|
||||
impl Gravity {
|
||||
pub fn new() -> Gravity { Default::default() }
|
||||
pub fn new() -> Gravity {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bounds {
|
||||
|
@ -140,9 +135,7 @@ pub struct Bounds {
|
|||
|
||||
impl Bounds {
|
||||
pub fn new(bounds: Aabb3<f64>) -> Bounds {
|
||||
Bounds {
|
||||
bounds,
|
||||
}
|
||||
Bounds { bounds }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +145,9 @@ pub struct GameInfo {
|
|||
}
|
||||
|
||||
impl GameInfo {
|
||||
pub fn new() -> GameInfo { Default::default() }
|
||||
pub fn new() -> GameInfo {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -162,5 +157,7 @@ pub struct Light {
|
|||
}
|
||||
|
||||
impl Light {
|
||||
pub fn new() -> Light { Default::default() }
|
||||
pub fn new() -> Light {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,20 @@
|
|||
|
||||
use crate::ecs;
|
||||
use super::{
|
||||
Position,
|
||||
TargetPosition,
|
||||
Velocity,
|
||||
Rotation,
|
||||
TargetRotation,
|
||||
Gravity,
|
||||
Bounds,
|
||||
GameInfo,
|
||||
Light
|
||||
Bounds, GameInfo, Gravity, Light, Position, Rotation, TargetPosition, TargetRotation, Velocity,
|
||||
};
|
||||
use crate::world;
|
||||
use crate::ecs;
|
||||
use crate::format;
|
||||
use crate::render;
|
||||
use crate::render::model::{self, FormatState};
|
||||
use crate::types::Gamemode;
|
||||
use collision::{Aabb, Aabb3};
|
||||
use cgmath::{self, Point3, Vector3, Matrix4, Decomposed, Rotation3, Rad, Quaternion};
|
||||
use std::collections::HashMap;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use crate::types::hash::FNVHash;
|
||||
use crate::settings::Stevenkey;
|
||||
use crate::shared::Position as BPosition;
|
||||
use crate::format;
|
||||
use crate::types::hash::FNVHash;
|
||||
use crate::types::Gamemode;
|
||||
use crate::world;
|
||||
use cgmath::{self, Decomposed, Matrix4, Point3, Quaternion, Rad, Rotation3, Vector3};
|
||||
use collision::{Aabb, Aabb3};
|
||||
use std::collections::HashMap;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use std::time::Instant;
|
||||
|
||||
pub fn add_systems(m: &mut ecs::Manager) {
|
||||
let sys = MovementHandler::new(m);
|
||||
|
@ -42,10 +34,13 @@ pub fn create_local(m: &mut ecs::Manager) -> ecs::Entity {
|
|||
m.add_component_direct(entity, Gamemode::Survival);
|
||||
m.add_component_direct(entity, Gravity::new());
|
||||
m.add_component_direct(entity, PlayerMovement::new());
|
||||
m.add_component_direct(entity, Bounds::new(Aabb3::new(
|
||||
Point3::new(-0.3, 0.0, -0.3),
|
||||
Point3::new(0.3, 1.8, 0.3)
|
||||
)));
|
||||
m.add_component_direct(
|
||||
entity,
|
||||
Bounds::new(Aabb3::new(
|
||||
Point3::new(-0.3, 0.0, -0.3),
|
||||
Point3::new(0.3, 1.8, 0.3),
|
||||
)),
|
||||
);
|
||||
m.add_component_direct(entity, PlayerModel::new("", false, false, true));
|
||||
m.add_component_direct(entity, Light::new());
|
||||
entity
|
||||
|
@ -58,16 +53,18 @@ pub fn create_remote(m: &mut ecs::Manager, name: &str) -> ecs::Entity {
|
|||
m.add_component_direct(entity, Rotation::new(0.0, 0.0));
|
||||
m.add_component_direct(entity, TargetRotation::new(0.0, 0.0));
|
||||
m.add_component_direct(entity, Velocity::new(0.0, 0.0, 0.0));
|
||||
m.add_component_direct(entity, Bounds::new(Aabb3::new(
|
||||
Point3::new(-0.3, 0.0, -0.3),
|
||||
Point3::new(0.3, 1.8, 0.3)
|
||||
)));
|
||||
m.add_component_direct(
|
||||
entity,
|
||||
Bounds::new(Aabb3::new(
|
||||
Point3::new(-0.3, 0.0, -0.3),
|
||||
Point3::new(0.3, 1.8, 0.3),
|
||||
)),
|
||||
);
|
||||
m.add_component_direct(entity, PlayerModel::new(name, true, true, false));
|
||||
m.add_component_direct(entity, Light::new());
|
||||
entity
|
||||
}
|
||||
|
||||
|
||||
pub struct PlayerModel {
|
||||
model: Option<model::ModelKey>,
|
||||
skin_url: Option<String>,
|
||||
|
@ -154,16 +151,23 @@ enum PlayerModelPart {
|
|||
|
||||
// TODO: Setup culling
|
||||
impl ecs::System for PlayerRenderer {
|
||||
|
||||
fn filter(&self) -> &ecs::Filter {
|
||||
&self.filter
|
||||
}
|
||||
|
||||
fn update(&mut self, m: &mut ecs::Manager, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||
fn update(
|
||||
&mut self,
|
||||
m: &mut ecs::Manager,
|
||||
world: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
) {
|
||||
use std::f32::consts::PI;
|
||||
use std::f64::consts::PI as PI64;
|
||||
let world_entity = m.get_world();
|
||||
let delta = m.get_component_mut(world_entity, self.game_info).unwrap().delta;
|
||||
let delta = m
|
||||
.get_component_mut(world_entity, self.game_info)
|
||||
.unwrap()
|
||||
.delta;
|
||||
for e in m.find(&self.filter) {
|
||||
let player_model = m.get_component_mut(e, self.player_model).unwrap();
|
||||
let position = m.get_component_mut(e, self.position).unwrap();
|
||||
|
@ -182,8 +186,8 @@ impl ecs::System for PlayerRenderer {
|
|||
mdl.sky_light = light.sky_light;
|
||||
|
||||
let offset = if player_model.first_person {
|
||||
let ox = (rotation.yaw - PI64/2.0).cos() * 0.25;
|
||||
let oz = -(rotation.yaw - PI64/2.0).sin() * 0.25;
|
||||
let ox = (rotation.yaw - PI64 / 2.0).cos() * 0.25;
|
||||
let oz = -(rotation.yaw - PI64 / 2.0).sin() * 0.25;
|
||||
Vector3::new(
|
||||
position.position.x as f32 - ox as f32,
|
||||
-position.position.y as f32,
|
||||
|
@ -204,24 +208,28 @@ impl ecs::System for PlayerRenderer {
|
|||
|
||||
// TODO This sucks
|
||||
if player_model.has_name_tag {
|
||||
let ang = (position.position.x - renderer.camera.pos.x).atan2(position.position.z - renderer.camera.pos.z) as f32;
|
||||
let ang = (position.position.x - renderer.camera.pos.x)
|
||||
.atan2(position.position.z - renderer.camera.pos.z)
|
||||
as f32;
|
||||
mdl.matrix[PlayerModelPart::NameTag as usize] = Matrix4::from(Decomposed {
|
||||
scale: 1.0,
|
||||
rot: Quaternion::from_angle_y(Rad(ang)),
|
||||
disp: offset + Vector3::new(0.0, (-24.0/16.0) - 0.6, 0.0),
|
||||
disp: offset + Vector3::new(0.0, (-24.0 / 16.0) - 0.6, 0.0),
|
||||
});
|
||||
}
|
||||
|
||||
mdl.matrix[PlayerModelPart::Head as usize] = offset_matrix * Matrix4::from(Decomposed {
|
||||
scale: 1.0,
|
||||
rot: Quaternion::from_angle_x(Rad(-rotation.pitch as f32)),
|
||||
disp: Vector3::new(0.0, -12.0/16.0 - 12.0/16.0, 0.0),
|
||||
});
|
||||
mdl.matrix[PlayerModelPart::Body as usize] = offset_matrix * Matrix4::from(Decomposed {
|
||||
scale: 1.0,
|
||||
rot: Quaternion::from_angle_x(Rad(0.0)),
|
||||
disp: Vector3::new(0.0, -12.0/16.0 - 6.0/16.0, 0.0),
|
||||
});
|
||||
mdl.matrix[PlayerModelPart::Head as usize] = offset_matrix
|
||||
* Matrix4::from(Decomposed {
|
||||
scale: 1.0,
|
||||
rot: Quaternion::from_angle_x(Rad(-rotation.pitch as f32)),
|
||||
disp: Vector3::new(0.0, -12.0 / 16.0 - 12.0 / 16.0, 0.0),
|
||||
});
|
||||
mdl.matrix[PlayerModelPart::Body as usize] = offset_matrix
|
||||
* Matrix4::from(Decomposed {
|
||||
scale: 1.0,
|
||||
rot: Quaternion::from_angle_x(Rad(0.0)),
|
||||
disp: Vector3::new(0.0, -12.0 / 16.0 - 6.0 / 16.0, 0.0),
|
||||
});
|
||||
|
||||
let mut time = player_model.time;
|
||||
let mut dir = player_model.dir;
|
||||
|
@ -231,16 +239,18 @@ impl ecs::System for PlayerRenderer {
|
|||
}
|
||||
let ang = ((time / 15.0) - 1.0) * (PI64 / 4.0);
|
||||
|
||||
mdl.matrix[PlayerModelPart::LegRight as usize] = offset_matrix * Matrix4::from(Decomposed {
|
||||
scale: 1.0,
|
||||
rot: Quaternion::from_angle_x(Rad(ang as f32)),
|
||||
disp: Vector3::new(2.0/16.0, -12.0/16.0, 0.0),
|
||||
});
|
||||
mdl.matrix[PlayerModelPart::LegLeft as usize] = offset_matrix * Matrix4::from(Decomposed {
|
||||
scale: 1.0,
|
||||
rot: Quaternion::from_angle_x(Rad(-ang as f32)),
|
||||
disp: Vector3::new(-2.0/16.0, -12.0/16.0, 0.0),
|
||||
});
|
||||
mdl.matrix[PlayerModelPart::LegRight as usize] = offset_matrix
|
||||
* Matrix4::from(Decomposed {
|
||||
scale: 1.0,
|
||||
rot: Quaternion::from_angle_x(Rad(ang as f32)),
|
||||
disp: Vector3::new(2.0 / 16.0, -12.0 / 16.0, 0.0),
|
||||
});
|
||||
mdl.matrix[PlayerModelPart::LegLeft as usize] = offset_matrix
|
||||
* Matrix4::from(Decomposed {
|
||||
scale: 1.0,
|
||||
rot: Quaternion::from_angle_x(Rad(-ang as f32)),
|
||||
disp: Vector3::new(-2.0 / 16.0, -12.0 / 16.0, 0.0),
|
||||
});
|
||||
|
||||
let mut i_time = player_model.idle_time;
|
||||
i_time += delta * 0.02;
|
||||
|
@ -255,17 +265,31 @@ impl ecs::System for PlayerRenderer {
|
|||
player_model.arm_time -= delta;
|
||||
}
|
||||
|
||||
mdl.matrix[PlayerModelPart::ArmRight as usize] = offset_matrix * Matrix4::from_translation(
|
||||
Vector3::new(6.0/16.0, -12.0/16.0-12.0/16.0, 0.0)
|
||||
) * Matrix4::from(Quaternion::from_angle_x(Rad(-(ang * 0.75) as f32)))
|
||||
* Matrix4::from(Quaternion::from_angle_z(Rad((i_time.cos() * 0.06 - 0.06) as f32)))
|
||||
* Matrix4::from(Quaternion::from_angle_x(Rad((i_time.sin() * 0.06 - ((7.5 - (player_model.arm_time-7.5).abs()) / 7.5)) as f32)));
|
||||
mdl.matrix[PlayerModelPart::ArmRight as usize] = offset_matrix
|
||||
* Matrix4::from_translation(Vector3::new(
|
||||
6.0 / 16.0,
|
||||
-12.0 / 16.0 - 12.0 / 16.0,
|
||||
0.0,
|
||||
))
|
||||
* Matrix4::from(Quaternion::from_angle_x(Rad(-(ang * 0.75) as f32)))
|
||||
* Matrix4::from(Quaternion::from_angle_z(Rad(
|
||||
(i_time.cos() * 0.06 - 0.06) as f32
|
||||
)))
|
||||
* Matrix4::from(Quaternion::from_angle_x(Rad((i_time.sin() * 0.06
|
||||
- ((7.5 - (player_model.arm_time - 7.5).abs()) / 7.5))
|
||||
as f32)));
|
||||
|
||||
mdl.matrix[PlayerModelPart::ArmLeft as usize] = offset_matrix * Matrix4::from_translation(
|
||||
Vector3::new(-6.0/16.0, -12.0/16.0-12.0/16.0, 0.0)
|
||||
) * Matrix4::from(Quaternion::from_angle_x(Rad((ang * 0.75) as f32)))
|
||||
* Matrix4::from(Quaternion::from_angle_z(Rad(-(i_time.cos() * 0.06 - 0.06) as f32)))
|
||||
* Matrix4::from(Quaternion::from_angle_x(Rad(-(i_time.sin() * 0.06) as f32)));
|
||||
mdl.matrix[PlayerModelPart::ArmLeft as usize] = offset_matrix
|
||||
* Matrix4::from_translation(Vector3::new(
|
||||
-6.0 / 16.0,
|
||||
-12.0 / 16.0 - 12.0 / 16.0,
|
||||
0.0,
|
||||
))
|
||||
* Matrix4::from(Quaternion::from_angle_x(Rad((ang * 0.75) as f32)))
|
||||
* Matrix4::from(Quaternion::from_angle_z(Rad(
|
||||
-(i_time.cos() * 0.06 - 0.06) as f32
|
||||
)))
|
||||
* Matrix4::from(Quaternion::from_angle_x(Rad(-(i_time.sin() * 0.06) as f32)));
|
||||
|
||||
let mut update = true;
|
||||
if position.moved {
|
||||
|
@ -296,7 +320,13 @@ impl ecs::System for PlayerRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
fn entity_added(&mut self, m: &mut ecs::Manager, e: ecs::Entity, _: &mut world::World, renderer: &mut render::Renderer) {
|
||||
fn entity_added(
|
||||
&mut self,
|
||||
m: &mut ecs::Manager,
|
||||
e: ecs::Entity,
|
||||
_: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
) {
|
||||
let player_model = m.get_component_mut(e, self.player_model).unwrap();
|
||||
|
||||
player_model.dirty = false;
|
||||
|
@ -308,76 +338,133 @@ impl ecs::System for PlayerRenderer {
|
|||
};
|
||||
|
||||
macro_rules! srel {
|
||||
($x:expr, $y:expr, $w:expr, $h:expr) => (
|
||||
($x:expr, $y:expr, $w:expr, $h:expr) => {
|
||||
Some(skin.relative(($x) / 64.0, ($y) / 64.0, ($w) / 64.0, ($h) / 64.0))
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
let mut head_verts = vec![];
|
||||
if player_model.has_head {
|
||||
model::append_box(&mut head_verts, -4.0/16.0, 0.0, -4.0/16.0, 8.0/16.0, 8.0/16.0, 8.0/16.0, [
|
||||
srel!(16.0, 0.0, 8.0, 8.0), // Down
|
||||
srel!(8.0, 0.0, 8.0, 8.0), // Up
|
||||
srel!(8.0, 8.0, 8.0, 8.0), // North
|
||||
srel!(24.0, 8.0, 8.0, 8.0), // South
|
||||
srel!(16.0, 8.0, 8.0, 8.0), // West
|
||||
srel!(0.0, 8.0, 8.0, 8.0), // East
|
||||
]);
|
||||
model::append_box(&mut head_verts, -4.2/16.0, -0.2/16.0, -4.2/16.0, 8.4/16.0, 8.4/16.0, 8.4/16.0, [
|
||||
srel!((16.0 + 32.0), 0.0, 8.0, 8.0), // Down
|
||||
srel!((8.0 + 32.0), 0.0, 8.0, 8.0), // Up
|
||||
srel!((8.0 + 32.0), 8.0, 8.0, 8.0), // North
|
||||
srel!((24.0 + 32.0), 8.0, 8.0, 8.0), // South
|
||||
srel!((16.0 + 32.0), 8.0, 8.0, 8.0), // West
|
||||
srel!((0.0 + 32.0), 8.0, 8.0, 8.0), // East
|
||||
]);
|
||||
model::append_box(
|
||||
&mut head_verts,
|
||||
-4.0 / 16.0,
|
||||
0.0,
|
||||
-4.0 / 16.0,
|
||||
8.0 / 16.0,
|
||||
8.0 / 16.0,
|
||||
8.0 / 16.0,
|
||||
[
|
||||
srel!(16.0, 0.0, 8.0, 8.0), // Down
|
||||
srel!(8.0, 0.0, 8.0, 8.0), // Up
|
||||
srel!(8.0, 8.0, 8.0, 8.0), // North
|
||||
srel!(24.0, 8.0, 8.0, 8.0), // South
|
||||
srel!(16.0, 8.0, 8.0, 8.0), // West
|
||||
srel!(0.0, 8.0, 8.0, 8.0), // East
|
||||
],
|
||||
);
|
||||
model::append_box(
|
||||
&mut head_verts,
|
||||
-4.2 / 16.0,
|
||||
-0.2 / 16.0,
|
||||
-4.2 / 16.0,
|
||||
8.4 / 16.0,
|
||||
8.4 / 16.0,
|
||||
8.4 / 16.0,
|
||||
[
|
||||
srel!((16.0 + 32.0), 0.0, 8.0, 8.0), // Down
|
||||
srel!((8.0 + 32.0), 0.0, 8.0, 8.0), // Up
|
||||
srel!((8.0 + 32.0), 8.0, 8.0, 8.0), // North
|
||||
srel!((24.0 + 32.0), 8.0, 8.0, 8.0), // South
|
||||
srel!((16.0 + 32.0), 8.0, 8.0, 8.0), // West
|
||||
srel!((0.0 + 32.0), 8.0, 8.0, 8.0), // East
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Cape
|
||||
let mut body_verts = vec![];
|
||||
model::append_box(&mut body_verts, -4.0/16.0, -6.0/16.0, -2.0/16.0, 8.0/16.0, 12.0/16.0, 4.0/16.0, [
|
||||
srel!(28.0, 16.0, 8.0, 4.0), // Down
|
||||
srel!(20.0, 16.0, 8.0, 4.0), // Up
|
||||
srel!(20.0, 20.0, 8.0, 12.0), // North
|
||||
srel!(32.0, 20.0, 8.0, 12.0), // South
|
||||
srel!(16.0, 20.0, 4.0, 12.0), // West
|
||||
srel!(28.0, 20.0, 4.0, 12.0), // East
|
||||
]);
|
||||
model::append_box(&mut body_verts, -4.2/16.0, -6.2/16.0, -2.2/16.0, 8.4/16.0, 12.4/16.0, 4.4/16.0, [
|
||||
srel!(28.0, 16.0 + 16.0, 8.0, 4.0), // Down
|
||||
srel!(20.0, 16.0 + 16.0, 8.0, 4.0), // Up
|
||||
srel!(20.0, 20.0 + 16.0, 8.0, 12.0), // North
|
||||
srel!(32.0, 20.0 + 16.0, 8.0, 12.0), // South
|
||||
srel!(16.0, 20.0 + 16.0, 4.0, 12.0), // West
|
||||
srel!(28.0, 20.0 + 16.0, 4.0, 12.0), // East
|
||||
]);
|
||||
model::append_box(
|
||||
&mut body_verts,
|
||||
-4.0 / 16.0,
|
||||
-6.0 / 16.0,
|
||||
-2.0 / 16.0,
|
||||
8.0 / 16.0,
|
||||
12.0 / 16.0,
|
||||
4.0 / 16.0,
|
||||
[
|
||||
srel!(28.0, 16.0, 8.0, 4.0), // Down
|
||||
srel!(20.0, 16.0, 8.0, 4.0), // Up
|
||||
srel!(20.0, 20.0, 8.0, 12.0), // North
|
||||
srel!(32.0, 20.0, 8.0, 12.0), // South
|
||||
srel!(16.0, 20.0, 4.0, 12.0), // West
|
||||
srel!(28.0, 20.0, 4.0, 12.0), // East
|
||||
],
|
||||
);
|
||||
model::append_box(
|
||||
&mut body_verts,
|
||||
-4.2 / 16.0,
|
||||
-6.2 / 16.0,
|
||||
-2.2 / 16.0,
|
||||
8.4 / 16.0,
|
||||
12.4 / 16.0,
|
||||
4.4 / 16.0,
|
||||
[
|
||||
srel!(28.0, 16.0 + 16.0, 8.0, 4.0), // Down
|
||||
srel!(20.0, 16.0 + 16.0, 8.0, 4.0), // Up
|
||||
srel!(20.0, 20.0 + 16.0, 8.0, 12.0), // North
|
||||
srel!(32.0, 20.0 + 16.0, 8.0, 12.0), // South
|
||||
srel!(16.0, 20.0 + 16.0, 4.0, 12.0), // West
|
||||
srel!(28.0, 20.0 + 16.0, 4.0, 12.0), // East
|
||||
],
|
||||
);
|
||||
|
||||
let mut part_verts = vec![vec![]; 4];
|
||||
|
||||
for (i, offsets) in [
|
||||
[16.0, 48.0, 0.0, 48.0], // Left left
|
||||
[0.0, 16.0, 0.0, 32.0], // Right Leg
|
||||
[16.0, 48.0, 0.0, 48.0], // Left left
|
||||
[0.0, 16.0, 0.0, 32.0], // Right Leg
|
||||
[32.0, 48.0, 48.0, 48.0], // Left arm
|
||||
[40.0, 16.0, 40.0, 32.0], // Right arm
|
||||
].into_iter().enumerate() {
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
let (ox, oy) = (offsets[0], offsets[1]);
|
||||
model::append_box(&mut part_verts[i], -2.0/16.0, -12.0/16.0, -2.0/16.0, 4.0/16.0, 12.0/16.0, 4.0/16.0, [
|
||||
srel!(ox + 8.0, oy + 0.0, 4.0, 4.0), // Down
|
||||
srel!(ox + 4.0, oy + 0.0, 4.0, 4.0), // Up
|
||||
srel!(ox + 4.0, oy + 4.0, 4.0, 12.0), // North
|
||||
srel!(ox + 12.0, oy + 4.0, 4.0, 12.0), // South
|
||||
srel!(ox + 8.0, oy + 4.0, 4.0, 12.0), // West
|
||||
srel!(ox + 0.0, oy + 4.0, 4.0, 12.0), // East
|
||||
]);
|
||||
model::append_box(
|
||||
&mut part_verts[i],
|
||||
-2.0 / 16.0,
|
||||
-12.0 / 16.0,
|
||||
-2.0 / 16.0,
|
||||
4.0 / 16.0,
|
||||
12.0 / 16.0,
|
||||
4.0 / 16.0,
|
||||
[
|
||||
srel!(ox + 8.0, oy + 0.0, 4.0, 4.0), // Down
|
||||
srel!(ox + 4.0, oy + 0.0, 4.0, 4.0), // Up
|
||||
srel!(ox + 4.0, oy + 4.0, 4.0, 12.0), // North
|
||||
srel!(ox + 12.0, oy + 4.0, 4.0, 12.0), // South
|
||||
srel!(ox + 8.0, oy + 4.0, 4.0, 12.0), // West
|
||||
srel!(ox + 0.0, oy + 4.0, 4.0, 12.0), // East
|
||||
],
|
||||
);
|
||||
let (ox, oy) = (offsets[2], offsets[3]);
|
||||
model::append_box(&mut part_verts[i], -2.2/16.0, -12.2/16.0, -2.2/16.0, 4.4/16.0, 12.4/16.0, 4.4/16.0, [
|
||||
srel!(ox + 8.0, oy + 0.0, 4.0, 4.0), // Down
|
||||
srel!(ox + 4.0, oy + 0.0, 4.0, 4.0), // Up
|
||||
srel!(ox + 4.0, oy + 4.0, 4.0, 12.0), // North
|
||||
srel!(ox + 12.0, oy + 4.0, 4.0, 12.0), // South
|
||||
srel!(ox + 8.0, oy + 4.0, 4.0, 12.0), // West
|
||||
srel!(ox + 0.0, oy + 4.0, 4.0, 12.0), // East
|
||||
]);
|
||||
model::append_box(
|
||||
&mut part_verts[i],
|
||||
-2.2 / 16.0,
|
||||
-12.2 / 16.0,
|
||||
-2.2 / 16.0,
|
||||
4.4 / 16.0,
|
||||
12.4 / 16.0,
|
||||
4.4 / 16.0,
|
||||
[
|
||||
srel!(ox + 8.0, oy + 0.0, 4.0, 4.0), // Down
|
||||
srel!(ox + 4.0, oy + 0.0, 4.0, 4.0), // Up
|
||||
srel!(ox + 4.0, oy + 4.0, 4.0, 12.0), // North
|
||||
srel!(ox + 12.0, oy + 4.0, 4.0, 12.0), // South
|
||||
srel!(ox + 8.0, oy + 4.0, 4.0, 12.0), // West
|
||||
srel!(ox + 0.0, oy + 4.0, 4.0, 12.0), // East
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
let mut name_verts = vec![];
|
||||
|
@ -422,17 +509,27 @@ impl ecs::System for PlayerRenderer {
|
|||
part_verts[1].clone(),
|
||||
part_verts[2].clone(),
|
||||
part_verts[3].clone(),
|
||||
name_verts
|
||||
]
|
||||
name_verts,
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
fn entity_removed(&mut self, m: &mut ecs::Manager, e: ecs::Entity, _: &mut world::World, renderer: &mut render::Renderer) {
|
||||
fn entity_removed(
|
||||
&mut self,
|
||||
m: &mut ecs::Manager,
|
||||
e: ecs::Entity,
|
||||
_: &mut world::World,
|
||||
renderer: &mut render::Renderer,
|
||||
) {
|
||||
let player_model = m.get_component_mut(e, self.player_model).unwrap();
|
||||
if let Some(model) = player_model.model.take() {
|
||||
renderer.model.remove_model(model);
|
||||
if let Some(url) = player_model.skin_url.as_ref() {
|
||||
renderer.get_textures_ref().read().unwrap().release_skin(url);
|
||||
renderer
|
||||
.get_textures_ref()
|
||||
.read()
|
||||
.unwrap()
|
||||
.release_skin(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -441,17 +538,22 @@ impl ecs::System for PlayerRenderer {
|
|||
#[derive(Default)]
|
||||
pub struct PlayerMovement {
|
||||
pub flying: bool,
|
||||
pub want_to_fly: bool,
|
||||
pub when_last_jump_pressed: Option<Instant>,
|
||||
pub when_last_jump_released: Option<Instant>,
|
||||
pub did_touch_ground: bool,
|
||||
pub pressed_keys: HashMap<Stevenkey, bool, BuildHasherDefault<FNVHash>>,
|
||||
}
|
||||
|
||||
impl PlayerMovement {
|
||||
pub fn new() -> PlayerMovement { Default::default() }
|
||||
pub fn new() -> PlayerMovement {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn calculate_movement(&self, player_yaw: f64) -> (f64, f64) {
|
||||
use std::f64::consts::PI;
|
||||
let mut forward = 0.0f64;
|
||||
let mut yaw = player_yaw - (PI/2.0);
|
||||
let mut yaw = player_yaw - (PI / 2.0);
|
||||
if self.is_key_pressed(Stevenkey::Forward) || self.is_key_pressed(Stevenkey::Backward) {
|
||||
forward = 1.0;
|
||||
if self.is_key_pressed(Stevenkey::Backward) {
|
||||
|
@ -462,7 +564,9 @@ impl PlayerMovement {
|
|||
(PI / 2.0) / (forward.abs() + 1.0)
|
||||
} else if self.is_key_pressed(Stevenkey::Right) {
|
||||
-(PI / 2.0) / (forward.abs() + 1.0)
|
||||
} else { 0.0 };
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
if self.is_key_pressed(Stevenkey::Left) || self.is_key_pressed(Stevenkey::Right) {
|
||||
forward = 1.0;
|
||||
}
|
||||
|
@ -517,7 +621,6 @@ impl MovementHandler {
|
|||
}
|
||||
|
||||
impl ecs::System for MovementHandler {
|
||||
|
||||
fn filter(&self) -> &ecs::Filter {
|
||||
&self.filter
|
||||
}
|
||||
|
@ -533,6 +636,30 @@ impl ecs::System for MovementHandler {
|
|||
let gamemode = m.get_component(e, self.gamemode).unwrap();
|
||||
movement.flying |= gamemode.always_fly();
|
||||
|
||||
// Detect double-tapping jump to toggle creative flight
|
||||
if movement.is_key_pressed(Stevenkey::Jump) {
|
||||
if movement.when_last_jump_pressed.is_none() {
|
||||
movement.when_last_jump_pressed = Some(Instant::now());
|
||||
if !movement.when_last_jump_released.is_none() {
|
||||
let dt = movement.when_last_jump_pressed.unwrap()
|
||||
- movement.when_last_jump_released.unwrap();
|
||||
if dt.as_secs() == 0
|
||||
&& dt.subsec_millis() <= crate::settings::DOUBLE_JUMP_MS
|
||||
{
|
||||
movement.want_to_fly = !movement.want_to_fly;
|
||||
//info!("double jump! dt={:?} toggle want_to_fly = {}", dt, movement.want_to_fly);
|
||||
|
||||
if gamemode.can_fly() && !gamemode.always_fly() {
|
||||
movement.flying = movement.want_to_fly;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if !movement.when_last_jump_pressed.is_none() {
|
||||
movement.when_last_jump_released = Some(Instant::now());
|
||||
movement.when_last_jump_pressed = None;
|
||||
}
|
||||
|
||||
let position = m.get_component_mut(e, self.position).unwrap();
|
||||
let rotation = m.get_component(e, self.rotation).unwrap();
|
||||
let velocity = m.get_component_mut(e, self.velocity).unwrap();
|
||||
|
@ -542,11 +669,16 @@ impl ecs::System for MovementHandler {
|
|||
|
||||
let mut last_position = position.position;
|
||||
|
||||
if world.is_chunk_loaded((position.position.x as i32) >> 4, (position.position.z as i32) >> 4) {
|
||||
if world.is_chunk_loaded(
|
||||
(position.position.x as i32) >> 4,
|
||||
(position.position.z as i32) >> 4,
|
||||
) {
|
||||
let (forward, yaw) = movement.calculate_movement(rotation.yaw);
|
||||
let mut speed = if movement.is_key_pressed(Stevenkey::Sprint) {
|
||||
0.2806
|
||||
} else { 0.21585 };
|
||||
} else {
|
||||
0.21585
|
||||
};
|
||||
if movement.flying {
|
||||
speed *= 2.5;
|
||||
|
||||
|
@ -557,7 +689,8 @@ impl ecs::System for MovementHandler {
|
|||
position.position.y -= speed;
|
||||
}
|
||||
} else if gravity.as_ref().map_or(false, |v| v.on_ground) {
|
||||
if movement.is_key_pressed(Stevenkey::Jump) && velocity.velocity.y.abs() < 0.001 {
|
||||
if movement.is_key_pressed(Stevenkey::Jump) && velocity.velocity.y.abs() < 0.001
|
||||
{
|
||||
velocity.velocity.y = 0.42;
|
||||
}
|
||||
} else {
|
||||
|
@ -579,12 +712,14 @@ impl ecs::System for MovementHandler {
|
|||
// We handle each axis separately to allow for a sliding
|
||||
// effect when pushing up against walls.
|
||||
|
||||
let (bounds, xhit) = check_collisions(world, position, &last_position, player_bounds);
|
||||
let (bounds, xhit) =
|
||||
check_collisions(world, position, &last_position, player_bounds);
|
||||
position.position.x = bounds.min.x + 0.3;
|
||||
last_position.x = position.position.x;
|
||||
|
||||
position.position.z = target.z;
|
||||
let (bounds, zhit) = check_collisions(world, position, &last_position, player_bounds);
|
||||
let (bounds, zhit) =
|
||||
check_collisions(world, position, &last_position, player_bounds);
|
||||
position.position.z = bounds.min.z + 0.3;
|
||||
last_position.z = position.position.z;
|
||||
|
||||
|
@ -599,8 +734,12 @@ impl ecs::System for MovementHandler {
|
|||
let mut oz = position.position.z;
|
||||
position.position.x = target.x;
|
||||
position.position.z = target.z;
|
||||
for offset in 1 .. 9 {
|
||||
let mini = player_bounds.add_v(cgmath::Vector3::new(0.0, offset as f64 / 16.0, 0.0));
|
||||
for offset in 1..9 {
|
||||
let mini = player_bounds.add_v(cgmath::Vector3::new(
|
||||
0.0,
|
||||
offset as f64 / 16.0,
|
||||
0.0,
|
||||
));
|
||||
let (_, hit) = check_collisions(world, position, &last_position, mini);
|
||||
if !hit {
|
||||
target.y += offset as f64 / 16.0;
|
||||
|
@ -614,7 +753,8 @@ impl ecs::System for MovementHandler {
|
|||
}
|
||||
|
||||
position.position.y = target.y;
|
||||
let (bounds, yhit) = check_collisions(world, position, &last_position, player_bounds);
|
||||
let (bounds, yhit) =
|
||||
check_collisions(world, position, &last_position, player_bounds);
|
||||
position.position.y = bounds.min.y;
|
||||
last_position.y = position.position.y;
|
||||
if yhit {
|
||||
|
@ -622,10 +762,8 @@ impl ecs::System for MovementHandler {
|
|||
}
|
||||
|
||||
if let Some(gravity) = gravity {
|
||||
let ground = Aabb3::new(
|
||||
Point3::new(-0.3, -0.005, -0.3),
|
||||
Point3::new(0.3, 0.0, 0.3)
|
||||
);
|
||||
let ground =
|
||||
Aabb3::new(Point3::new(-0.3, -0.005, -0.3), Point3::new(0.3, 0.0, 0.3));
|
||||
let prev = gravity.on_ground;
|
||||
let (_, hit) = check_collisions(world, position, &last_position, ground);
|
||||
gravity.on_ground = hit;
|
||||
|
@ -639,8 +777,12 @@ impl ecs::System for MovementHandler {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
fn check_collisions(world: &world::World, position: &mut TargetPosition, last_position: &Vector3<f64>, bounds: Aabb3<f64>) -> (Aabb3<f64>, bool) {
|
||||
fn check_collisions(
|
||||
world: &world::World,
|
||||
position: &mut TargetPosition,
|
||||
last_position: &Vector3<f64>,
|
||||
bounds: Aabb3<f64>,
|
||||
) -> (Aabb3<f64>, bool) {
|
||||
let mut bounds = bounds.add_v(position.position);
|
||||
|
||||
let dir = position.position - last_position;
|
||||
|
@ -653,9 +795,9 @@ fn check_collisions(world: &world::World, position: &mut TargetPosition, last_po
|
|||
let max_z = (bounds.max.z + 1.0) as i32;
|
||||
|
||||
let mut hit = false;
|
||||
for y in min_y .. max_y {
|
||||
for z in min_z .. max_z {
|
||||
for x in min_x .. max_x {
|
||||
for y in min_y..max_y {
|
||||
for z in min_z..max_z {
|
||||
for x in min_x..max_x {
|
||||
let block = world.get_block(BPosition::new(x, y, z));
|
||||
if block.get_material().collidable {
|
||||
for bb in block.get_collision_boxes() {
|
||||
|
@ -680,14 +822,12 @@ trait Collidable<T> {
|
|||
|
||||
impl Collidable<Aabb3<f64>> for Aabb3<f64> {
|
||||
fn collides(&self, t: &Aabb3<f64>) -> bool {
|
||||
!(
|
||||
t.min.x >= self.max.x ||
|
||||
t.max.x <= self.min.x ||
|
||||
t.min.y >= self.max.y ||
|
||||
t.max.y <= self.min.y ||
|
||||
t.min.z >= self.max.z ||
|
||||
t.max.z <= self.min.z
|
||||
)
|
||||
!(t.min.x >= self.max.x
|
||||
|| t.max.x <= self.min.x
|
||||
|| t.min.y >= self.max.y
|
||||
|| t.max.y <= self.min.y
|
||||
|| t.min.z >= self.max.z
|
||||
|| t.max.z <= self.min.z)
|
||||
}
|
||||
|
||||
fn move_out_of(mut self, other: Self, dir: cgmath::Vector3<f64>) -> Self {
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
|
||||
use super::*;
|
||||
use crate::ecs;
|
||||
use crate::world;
|
||||
use crate::render;
|
||||
use crate::shared::Position as BPos;
|
||||
use crate::world;
|
||||
use cgmath::InnerSpace;
|
||||
|
||||
pub struct ApplyVelocity {
|
||||
|
@ -18,9 +17,7 @@ impl ApplyVelocity {
|
|||
let position = m.get_key();
|
||||
let velocity = m.get_key();
|
||||
ApplyVelocity {
|
||||
filter: ecs::Filter::new()
|
||||
.with(position)
|
||||
.with(velocity),
|
||||
filter: ecs::Filter::new().with(position).with(velocity),
|
||||
position,
|
||||
velocity,
|
||||
movement: m.get_key(),
|
||||
|
@ -29,7 +26,6 @@ impl ApplyVelocity {
|
|||
}
|
||||
|
||||
impl ecs::System for ApplyVelocity {
|
||||
|
||||
fn filter(&self) -> &ecs::Filter {
|
||||
&self.filter
|
||||
}
|
||||
|
@ -58,9 +54,7 @@ impl ApplyGravity {
|
|||
let gravity = m.get_key::<Gravity>();
|
||||
let velocity = m.get_key();
|
||||
ApplyGravity {
|
||||
filter: ecs::Filter::new()
|
||||
.with(gravity)
|
||||
.with(velocity),
|
||||
filter: ecs::Filter::new().with(gravity).with(velocity),
|
||||
velocity,
|
||||
movement: m.get_key(),
|
||||
}
|
||||
|
@ -68,7 +62,6 @@ impl ApplyGravity {
|
|||
}
|
||||
|
||||
impl ecs::System for ApplyGravity {
|
||||
|
||||
fn filter(&self) -> &ecs::Filter {
|
||||
&self.filter
|
||||
}
|
||||
|
@ -98,15 +91,13 @@ impl UpdateLastPosition {
|
|||
pub fn new(m: &mut ecs::Manager) -> UpdateLastPosition {
|
||||
let position = m.get_key();
|
||||
UpdateLastPosition {
|
||||
filter: ecs::Filter::new()
|
||||
.with(position),
|
||||
filter: ecs::Filter::new().with(position),
|
||||
position,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ecs::System for UpdateLastPosition {
|
||||
|
||||
fn filter(&self) -> &ecs::Filter {
|
||||
&self.filter
|
||||
}
|
||||
|
@ -133,9 +124,7 @@ impl LerpPosition {
|
|||
let position = m.get_key();
|
||||
let target_position = m.get_key();
|
||||
LerpPosition {
|
||||
filter: ecs::Filter::new()
|
||||
.with(position)
|
||||
.with(target_position),
|
||||
filter: ecs::Filter::new().with(position).with(target_position),
|
||||
position,
|
||||
target_position,
|
||||
game_info: m.get_key(),
|
||||
|
@ -144,20 +133,24 @@ impl LerpPosition {
|
|||
}
|
||||
|
||||
impl ecs::System for LerpPosition {
|
||||
|
||||
fn filter(&self) -> &ecs::Filter {
|
||||
&self.filter
|
||||
}
|
||||
|
||||
fn update(&mut self, m: &mut ecs::Manager, _: &mut world::World, _: &mut render::Renderer) {
|
||||
let world_entity = m.get_world();
|
||||
let delta = m.get_component_mut(world_entity, self.game_info).unwrap().delta.min(5.0);
|
||||
let delta = m
|
||||
.get_component_mut(world_entity, self.game_info)
|
||||
.unwrap()
|
||||
.delta
|
||||
.min(5.0);
|
||||
for e in m.find(&self.filter) {
|
||||
let pos = m.get_component_mut(e, self.position).unwrap();
|
||||
let target_pos = m.get_component(e, self.target_position).unwrap();
|
||||
|
||||
pos.position = pos.position + (target_pos.position - pos.position) * delta * target_pos.lerp_amount;
|
||||
let len = (pos.position - target_pos.position).magnitude2() ;
|
||||
pos.position = pos.position
|
||||
+ (target_pos.position - pos.position) * delta * target_pos.lerp_amount;
|
||||
let len = (pos.position - target_pos.position).magnitude2();
|
||||
if len < 0.001 || len > 100.0 * 100.0 {
|
||||
pos.position = target_pos.position;
|
||||
}
|
||||
|
@ -177,9 +170,7 @@ impl LerpRotation {
|
|||
let rotation = m.get_key();
|
||||
let target_rotation = m.get_key();
|
||||
LerpRotation {
|
||||
filter: ecs::Filter::new()
|
||||
.with(rotation)
|
||||
.with(target_rotation),
|
||||
filter: ecs::Filter::new().with(rotation).with(target_rotation),
|
||||
rotation,
|
||||
target_rotation,
|
||||
game_info: m.get_key(),
|
||||
|
@ -188,7 +179,6 @@ impl LerpRotation {
|
|||
}
|
||||
|
||||
impl ecs::System for LerpRotation {
|
||||
|
||||
fn filter(&self) -> &ecs::Filter {
|
||||
&self.filter
|
||||
}
|
||||
|
@ -196,12 +186,16 @@ impl ecs::System for LerpRotation {
|
|||
fn update(&mut self, m: &mut ecs::Manager, _: &mut world::World, _: &mut render::Renderer) {
|
||||
use std::f64::consts::PI;
|
||||
let world_entity = m.get_world();
|
||||
let delta = m.get_component_mut(world_entity, self.game_info).unwrap().delta.min(5.0);
|
||||
let delta = m
|
||||
.get_component_mut(world_entity, self.game_info)
|
||||
.unwrap()
|
||||
.delta
|
||||
.min(5.0);
|
||||
for e in m.find(&self.filter) {
|
||||
let rot = m.get_component_mut(e, self.rotation).unwrap();
|
||||
let target_rot = m.get_component_mut(e, self.target_rotation).unwrap();
|
||||
target_rot.yaw = (PI*2.0 + target_rot.yaw) % (PI*2.0);
|
||||
target_rot.pitch = (PI*2.0 + target_rot.pitch) % (PI*2.0);
|
||||
target_rot.yaw = (PI * 2.0 + target_rot.yaw) % (PI * 2.0);
|
||||
target_rot.pitch = (PI * 2.0 + target_rot.pitch) % (PI * 2.0);
|
||||
|
||||
let mut delta_yaw = target_rot.yaw - rot.yaw;
|
||||
let mut delta_pitch = target_rot.pitch - rot.pitch;
|
||||
|
@ -215,8 +209,8 @@ impl ecs::System for LerpRotation {
|
|||
|
||||
rot.yaw += delta_yaw * 0.2 * delta;
|
||||
rot.pitch += delta_pitch * 0.2 * delta;
|
||||
rot.yaw = (PI*2.0 + rot.yaw) % (PI*2.0);
|
||||
rot.pitch = (PI*2.0 + rot.pitch) % (PI*2.0);
|
||||
rot.yaw = (PI * 2.0 + rot.yaw) % (PI * 2.0);
|
||||
rot.pitch = (PI * 2.0 + rot.pitch) % (PI * 2.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +219,7 @@ pub struct LightEntity {
|
|||
filter: ecs::Filter,
|
||||
position: ecs::Key<Position>,
|
||||
bounds: ecs::Key<Bounds>,
|
||||
light: ecs::Key<Light>
|
||||
light: ecs::Key<Light>,
|
||||
}
|
||||
|
||||
impl LightEntity {
|
||||
|
@ -234,10 +228,7 @@ impl LightEntity {
|
|||
let bounds = m.get_key();
|
||||
let light = m.get_key();
|
||||
LightEntity {
|
||||
filter: ecs::Filter::new()
|
||||
.with(position)
|
||||
.with(bounds)
|
||||
.with(light),
|
||||
filter: ecs::Filter::new().with(position).with(bounds).with(light),
|
||||
position,
|
||||
bounds,
|
||||
light,
|
||||
|
@ -246,7 +237,6 @@ impl LightEntity {
|
|||
}
|
||||
|
||||
impl ecs::System for LightEntity {
|
||||
|
||||
fn filter(&self) -> &ecs::Filter {
|
||||
&self.filter
|
||||
}
|
||||
|
@ -269,14 +259,13 @@ impl ecs::System for LightEntity {
|
|||
|
||||
let length = (bounds.bounds.max - bounds.bounds.min).magnitude() as f32;
|
||||
|
||||
for y in min_y .. max_y {
|
||||
for z in min_z .. max_z {
|
||||
for x in min_x .. max_x {
|
||||
let dist = length - (
|
||||
((x as f32 + 0.5) - pos.position.x as f32).powi(2)
|
||||
for y in min_y..max_y {
|
||||
for z in min_z..max_z {
|
||||
for x in min_x..max_x {
|
||||
let dist = length
|
||||
- (((x as f32 + 0.5) - pos.position.x as f32).powi(2)
|
||||
+ ((y as f32 + 0.5) - pos.position.y as f32).powi(2)
|
||||
+ ((z as f32 + 0.5) - pos.position.z as f32).powi(2)
|
||||
)
|
||||
+ ((z as f32 + 0.5) - pos.position.z as f32).powi(2))
|
||||
.sqrt()
|
||||
.min(length);
|
||||
let dist = dist / length;
|
||||
|
|
425
src/gl/mod.rs
425
src/gl/mod.rs
|
@ -13,16 +13,16 @@
|
|||
// limitations under the License.
|
||||
|
||||
extern crate steven_gl as gl;
|
||||
use glutin::GlContext;
|
||||
|
||||
use std::ops::BitOr;
|
||||
use log::{error, info};
|
||||
use std::ffi;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::ops::BitOr;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ptr;
|
||||
|
||||
/// Inits the gl library. This should be called once a context is ready.
|
||||
pub fn init(vid: & glutin::GlWindow) {
|
||||
pub fn init(vid: &glutin::WindowedContext<glutin::PossiblyCurrent>) {
|
||||
gl::load_with(|s| vid.get_proc_address(s) as *const _);
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,13 @@ pub fn draw_elements(ty: DrawType, count: i32, dty: Type, offset: usize) {
|
|||
|
||||
pub fn multi_draw_elements(ty: DrawType, count: &[i32], dty: Type, offsets: &[usize]) {
|
||||
unsafe {
|
||||
gl::MultiDrawElements(ty, count.as_ptr(), dty, offsets.as_ptr() as *const _, count.len() as i32);
|
||||
gl::MultiDrawElements(
|
||||
ty,
|
||||
count.as_ptr(),
|
||||
dty,
|
||||
offsets.as_ptr() as *const _,
|
||||
count.len() as i32,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +113,9 @@ pub fn clear(flags: ClearFlags) {
|
|||
}
|
||||
|
||||
pub fn depth_mask(f: bool) {
|
||||
unsafe { gl::DepthMask(f as u8); }
|
||||
unsafe {
|
||||
gl::DepthMask(f as u8);
|
||||
}
|
||||
}
|
||||
|
||||
/// `Func` is a function to be preformed on two values.
|
||||
|
@ -171,7 +179,12 @@ pub fn blend_func(s_factor: Factor, d_factor: Factor) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn blend_func_separate(s_factor_rgb: Factor, d_factor_rgb: Factor, s_factor_a: Factor, d_factor_a: Factor) {
|
||||
pub fn blend_func_separate(
|
||||
s_factor_rgb: Factor,
|
||||
d_factor_rgb: Factor,
|
||||
s_factor_a: Factor,
|
||||
d_factor_a: Factor,
|
||||
) {
|
||||
unsafe {
|
||||
gl::BlendFuncSeparate(s_factor_rgb, d_factor_rgb, s_factor_a, d_factor_a);
|
||||
}
|
||||
|
@ -270,180 +283,208 @@ impl Texture {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_pixels(&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pixels: &mut [u8]) {
|
||||
pub fn get_pixels(
|
||||
&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pixels: &mut [u8],
|
||||
) {
|
||||
unsafe {
|
||||
gl::GetTexImage(target,
|
||||
level,
|
||||
format,
|
||||
ty,
|
||||
pixels.as_mut_ptr() as *mut gl::types::GLvoid);
|
||||
gl::GetTexImage(
|
||||
target,
|
||||
level,
|
||||
format,
|
||||
ty,
|
||||
pixels.as_mut_ptr() as *mut gl::types::GLvoid,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_2d(&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pix: Option<&[u8]>) {
|
||||
pub fn image_2d(
|
||||
&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pix: Option<&[u8]>,
|
||||
) {
|
||||
unsafe {
|
||||
let ptr = match pix {
|
||||
Some(val) => val.as_ptr() as *const gl::types::GLvoid,
|
||||
None => ptr::null(),
|
||||
};
|
||||
gl::TexImage2D(target,
|
||||
level,
|
||||
format as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
0,
|
||||
format,
|
||||
ty,
|
||||
ptr
|
||||
gl::TexImage2D(
|
||||
target,
|
||||
level,
|
||||
format as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
0,
|
||||
format,
|
||||
ty,
|
||||
ptr,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sub_image_2d(&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pix: &[u8]) {
|
||||
pub fn sub_image_2d(
|
||||
&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pix: &[u8],
|
||||
) {
|
||||
unsafe {
|
||||
gl::TexSubImage2D(target,
|
||||
level,
|
||||
x as i32,
|
||||
y as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
format,
|
||||
ty,
|
||||
pix.as_ptr() as *const _
|
||||
gl::TexSubImage2D(
|
||||
target,
|
||||
level,
|
||||
x as i32,
|
||||
y as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
format,
|
||||
ty,
|
||||
pix.as_ptr() as *const _,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_2d_ex(&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
internal_format: TextureFormat,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pix: Option<&[u8]>) {
|
||||
pub fn image_2d_ex(
|
||||
&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
internal_format: TextureFormat,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pix: Option<&[u8]>,
|
||||
) {
|
||||
unsafe {
|
||||
let ptr = match pix {
|
||||
Some(val) => val.as_ptr() as *const gl::types::GLvoid,
|
||||
None => ptr::null(),
|
||||
};
|
||||
gl::TexImage2D(target,
|
||||
level,
|
||||
internal_format as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
0,
|
||||
format,
|
||||
ty,
|
||||
ptr
|
||||
gl::TexImage2D(
|
||||
target,
|
||||
level,
|
||||
internal_format as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
0,
|
||||
format,
|
||||
ty,
|
||||
ptr,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_2d_sample(&self,
|
||||
target: TextureTarget,
|
||||
samples: i32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: TextureFormat,
|
||||
fixed: bool) {
|
||||
pub fn image_2d_sample(
|
||||
&self,
|
||||
target: TextureTarget,
|
||||
samples: i32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: TextureFormat,
|
||||
fixed: bool,
|
||||
) {
|
||||
unsafe {
|
||||
let result: &mut [i32] = &mut [0; 1];
|
||||
gl::GetIntegerv(gl::MAX_SAMPLES, &mut result[0]);
|
||||
let use_samples =
|
||||
if samples > result[0] {
|
||||
println!("glTexImage2DMultisample: requested {} samples but GL_MAX_SAMPLES is {}", samples, result[0]);
|
||||
result[0]
|
||||
} else {
|
||||
samples
|
||||
};
|
||||
let use_samples = if samples > result[0] {
|
||||
info!(
|
||||
"glTexImage2DMultisample: requested {} samples but GL_MAX_SAMPLES is {}",
|
||||
samples, result[0]
|
||||
);
|
||||
result[0]
|
||||
} else {
|
||||
samples
|
||||
};
|
||||
|
||||
gl::TexImage2DMultisample(target,
|
||||
use_samples,
|
||||
format,
|
||||
width as i32,
|
||||
height as i32,
|
||||
fixed as u8
|
||||
gl::TexImage2DMultisample(
|
||||
target,
|
||||
use_samples,
|
||||
format,
|
||||
width as i32,
|
||||
height as i32,
|
||||
fixed as u8,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_3d(&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
depth: u32,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pix: &[u8]) {
|
||||
pub fn image_3d(
|
||||
&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
depth: u32,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pix: &[u8],
|
||||
) {
|
||||
unsafe {
|
||||
gl::TexImage3D(target,
|
||||
level,
|
||||
format as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
depth as i32,
|
||||
0,
|
||||
format,
|
||||
ty,
|
||||
pix.as_ptr() as *const gl::types::GLvoid);
|
||||
gl::TexImage3D(
|
||||
target,
|
||||
level,
|
||||
format as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
depth as i32,
|
||||
0,
|
||||
format,
|
||||
ty,
|
||||
pix.as_ptr() as *const gl::types::GLvoid,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sub_image_3d(&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
z: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
depth: u32,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pix: &[u8]) {
|
||||
pub fn sub_image_3d(
|
||||
&self,
|
||||
target: TextureTarget,
|
||||
level: i32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
z: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
depth: u32,
|
||||
format: TextureFormat,
|
||||
ty: Type,
|
||||
pix: &[u8],
|
||||
) {
|
||||
unsafe {
|
||||
gl::TexSubImage3D(target,
|
||||
level,
|
||||
x as i32,
|
||||
y as i32,
|
||||
z as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
depth as i32,
|
||||
format,
|
||||
ty,
|
||||
pix.as_ptr() as *const gl::types::GLvoid);
|
||||
gl::TexSubImage3D(
|
||||
target,
|
||||
level,
|
||||
x as i32,
|
||||
y as i32,
|
||||
z as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
depth as i32,
|
||||
format,
|
||||
ty,
|
||||
pix.as_ptr() as *const gl::types::GLvoid,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_parameter(&self,
|
||||
target: TextureTarget,
|
||||
param: TextureParameter,
|
||||
value: TextureValue) {
|
||||
pub fn set_parameter(
|
||||
&self,
|
||||
target: TextureTarget,
|
||||
param: TextureParameter,
|
||||
value: TextureValue,
|
||||
) {
|
||||
unsafe {
|
||||
gl::TexParameteri(target, param, value);
|
||||
}
|
||||
|
@ -495,9 +536,8 @@ impl Program {
|
|||
}
|
||||
|
||||
pub fn uniform_location(&self, name: &str) -> Option<Uniform> {
|
||||
let u = unsafe {
|
||||
gl::GetUniformLocation(self.0, ffi::CString::new(name).unwrap().as_ptr())
|
||||
};
|
||||
let u =
|
||||
unsafe { gl::GetUniformLocation(self.0, ffi::CString::new(name).unwrap().as_ptr()) };
|
||||
if u != -1 {
|
||||
Some(Uniform(u))
|
||||
} else {
|
||||
|
@ -536,10 +576,7 @@ impl Shader {
|
|||
pub fn set_source(&self, src: &str) {
|
||||
unsafe {
|
||||
let src_c = ffi::CString::new(src).unwrap();
|
||||
gl::ShaderSource(self.0,
|
||||
1,
|
||||
&src_c.as_ptr(),
|
||||
ptr::null());
|
||||
gl::ShaderSource(self.0, 1, &src_c.as_ptr(), ptr::null());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -624,7 +661,8 @@ impl Uniform {
|
|||
|
||||
pub fn set_matrix4_multi(&self, m: &[::cgmath::Matrix4<f32>]) {
|
||||
unsafe {
|
||||
gl::UniformMatrix4fv(self.0, m.len() as i32, false as u8, m.as_ptr() as *const _); // TODO: Most likely isn't safe
|
||||
gl::UniformMatrix4fv(self.0, m.len() as i32, false as u8, m.as_ptr() as *const _);
|
||||
// TODO: Most likely isn't safe
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -647,22 +685,26 @@ impl Attribute {
|
|||
|
||||
pub fn vertex_pointer(&self, size: i32, ty: Type, normalized: bool, stride: i32, offset: i32) {
|
||||
unsafe {
|
||||
gl::VertexAttribPointer(self.0 as u32,
|
||||
size,
|
||||
ty,
|
||||
normalized as u8,
|
||||
stride,
|
||||
offset as *const gl::types::GLvoid);
|
||||
gl::VertexAttribPointer(
|
||||
self.0 as u32,
|
||||
size,
|
||||
ty,
|
||||
normalized as u8,
|
||||
stride,
|
||||
offset as *const gl::types::GLvoid,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vertex_pointer_int(&self, size: i32, ty: Type, stride: i32, offset: i32) {
|
||||
unsafe {
|
||||
gl::VertexAttribIPointer(self.0 as u32,
|
||||
size,
|
||||
ty,
|
||||
stride,
|
||||
offset as *const gl::types::GLvoid);
|
||||
gl::VertexAttribIPointer(
|
||||
self.0 as u32,
|
||||
size,
|
||||
ty,
|
||||
stride,
|
||||
offset as *const gl::types::GLvoid,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -753,10 +795,12 @@ impl Buffer {
|
|||
|
||||
pub fn set_data(&self, target: BufferTarget, data: &[u8], usage: BufferUsage) {
|
||||
unsafe {
|
||||
gl::BufferData(target,
|
||||
data.len() as isize,
|
||||
data.as_ptr() as *const gl::types::GLvoid,
|
||||
usage);
|
||||
gl::BufferData(
|
||||
target,
|
||||
data.len() as isize,
|
||||
data.as_ptr() as *const gl::types::GLvoid,
|
||||
usage,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -832,11 +876,12 @@ pub struct Framebuffer(u32);
|
|||
pub fn check_framebuffer_status() {
|
||||
unsafe {
|
||||
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
|
||||
let s =
|
||||
match status {
|
||||
let s = match status {
|
||||
gl::FRAMEBUFFER_UNDEFINED => "GL_FRAMEBUFFER_UNDEFINED",
|
||||
gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
|
||||
gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT",
|
||||
gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => {
|
||||
"GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"
|
||||
}
|
||||
gl::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER => "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER",
|
||||
gl::FRAMEBUFFER_INCOMPLETE_READ_BUFFER => "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER",
|
||||
gl::FRAMEBUFFER_UNSUPPORTED => "GL_FRAMEBUFFER_UNSUPPORTED",
|
||||
|
@ -845,12 +890,14 @@ pub fn check_framebuffer_status() {
|
|||
|
||||
gl::FRAMEBUFFER_COMPLETE => "GL_FRAMEBUFFER_COMPLETE",
|
||||
//gl::FRAMEBUFFER_INCOMPLETE_DIMENSIONS => "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS",
|
||||
_ => "unknown"
|
||||
_ => "unknown",
|
||||
};
|
||||
|
||||
if status != gl::FRAMEBUFFER_COMPLETE {
|
||||
println!("glBindFramebuffer failed, glCheckFrameBufferStatus(GL_FRAMEBUFFER) = {} {}", status, s);
|
||||
panic!("glBindFramebuffer failed, glCheckFrameBufferStatus(GL_FRAMEBUFFER) = {} {}", status, s);
|
||||
panic!(
|
||||
"glBindFramebuffer failed, glCheckFrameBufferStatus(GL_FRAMEBUFFER) = {} {}",
|
||||
status, s
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -860,10 +907,10 @@ pub fn check_gl_error() {
|
|||
loop {
|
||||
let err = gl::GetError();
|
||||
if err == gl::NO_ERROR {
|
||||
break
|
||||
break;
|
||||
}
|
||||
|
||||
println!("glGetError = {}", err);
|
||||
error!("glGetError = {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -895,7 +942,13 @@ impl Framebuffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn texture_2d(&self, attachment: Attachment, target: TextureTarget, tex: &Texture, level: i32) {
|
||||
pub fn texture_2d(
|
||||
&self,
|
||||
attachment: Attachment,
|
||||
target: TextureTarget,
|
||||
tex: &Texture,
|
||||
level: i32,
|
||||
) {
|
||||
unsafe {
|
||||
gl::FramebufferTexture2D(gl::FRAMEBUFFER, attachment, target, tex.0, level);
|
||||
}
|
||||
|
@ -930,10 +983,7 @@ pub fn unbind_framebuffer_draw() {
|
|||
|
||||
pub fn draw_buffers(bufs: &[Attachment]) {
|
||||
unsafe {
|
||||
gl::DrawBuffers(
|
||||
bufs.len() as i32,
|
||||
bufs.as_ptr()
|
||||
);
|
||||
gl::DrawBuffers(bufs.len() as i32, bufs.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -945,14 +995,29 @@ pub fn bind_frag_data_location(p: &Program, cn: u32, name: &str) {
|
|||
}
|
||||
|
||||
pub fn blit_framebuffer(
|
||||
sx0: i32, sy0: i32, sx1: i32, sy1: i32,
|
||||
dx0: i32, dy0: i32, dx1: i32, dy1: i32,
|
||||
mask: ClearFlags, filter: TextureValue) {
|
||||
sx0: i32,
|
||||
sy0: i32,
|
||||
sx1: i32,
|
||||
sy1: i32,
|
||||
dx0: i32,
|
||||
dy0: i32,
|
||||
dx1: i32,
|
||||
dy1: i32,
|
||||
mask: ClearFlags,
|
||||
filter: TextureValue,
|
||||
) {
|
||||
unsafe {
|
||||
gl::BlitFramebuffer(
|
||||
sx0, sy0, sx1, sy1,
|
||||
dx0, dy0, dx1, dy1,
|
||||
mask.internal(), filter as u32
|
||||
sx0,
|
||||
sy0,
|
||||
sx1,
|
||||
sy1,
|
||||
dx0,
|
||||
dy0,
|
||||
dx1,
|
||||
dy1,
|
||||
mask.internal(),
|
||||
filter as u32,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
583
src/main.rs
583
src/main.rs
|
@ -12,43 +12,43 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#![recursion_limit="300"]
|
||||
#![recursion_limit = "300"]
|
||||
|
||||
use std::time::{Instant, Duration};
|
||||
use log::{info, warn};
|
||||
use log::{error, info, warn};
|
||||
use std::time::{Duration, Instant};
|
||||
extern crate steven_shared as shared;
|
||||
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
use structopt::StructOpt;
|
||||
|
||||
extern crate steven_protocol;
|
||||
|
||||
pub mod ecs;
|
||||
pub mod protocol;
|
||||
pub mod format;
|
||||
pub mod nbt;
|
||||
pub mod item;
|
||||
use steven_protocol::format;
|
||||
use steven_protocol::nbt;
|
||||
use steven_protocol::protocol;
|
||||
pub mod gl;
|
||||
pub mod types;
|
||||
pub mod resources;
|
||||
pub mod render;
|
||||
pub mod ui;
|
||||
pub mod screen;
|
||||
pub mod settings;
|
||||
pub mod console;
|
||||
pub mod server;
|
||||
pub mod world;
|
||||
pub mod chunk_builder;
|
||||
use steven_protocol::types;
|
||||
pub mod auth;
|
||||
pub mod model;
|
||||
pub mod chunk_builder;
|
||||
pub mod console;
|
||||
pub mod entity;
|
||||
pub mod model;
|
||||
pub mod render;
|
||||
pub mod resources;
|
||||
pub mod screen;
|
||||
pub mod server;
|
||||
pub mod settings;
|
||||
pub mod ui;
|
||||
pub mod world;
|
||||
|
||||
use std::sync::{Arc, RwLock, Mutex};
|
||||
use std::rc::Rc;
|
||||
use std::marker::PhantomData;
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
use crate::protocol::mojang;
|
||||
use cfg_if::cfg_if;
|
||||
use glutin;
|
||||
use glutin::GlContext;
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::thread;
|
||||
|
||||
const CL_BRAND: console::CVar<String> = console::CVar {
|
||||
ty: PhantomData,
|
||||
|
@ -73,35 +73,40 @@ pub struct Game {
|
|||
chunk_builder: chunk_builder::ChunkBuilder,
|
||||
|
||||
connect_reply: Option<mpsc::Receiver<Result<server::Server, protocol::Error>>>,
|
||||
protocol_version: i32,
|
||||
|
||||
dpi_factor: f64,
|
||||
last_mouse_x: f64,
|
||||
last_mouse_y: f64,
|
||||
last_mouse_xrel: f64,
|
||||
last_mouse_yrel: f64,
|
||||
is_ctrl_pressed: bool,
|
||||
is_logo_pressed: bool,
|
||||
is_fullscreen: bool,
|
||||
default_protocol_version: i32,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
pub fn connect_to(&mut self, address: &str) {
|
||||
// Read saved server protocol version from ping response TODO: get from memory?
|
||||
use std::fs;
|
||||
let file = match fs::File::open("server_versions.json") {
|
||||
Ok(val) => val,
|
||||
Err(_) => return,
|
||||
};
|
||||
let server_versions_info: serde_json::Value = serde_json::from_reader(file).unwrap();
|
||||
let protocol_version = {
|
||||
if let Some(v) = server_versions_info.get(address) {
|
||||
v.as_i64().unwrap() as i32
|
||||
} else {
|
||||
warn!("Server protocol version not known for {} (no ping response?), defaulting to {}", address, protocol::SUPPORTED_PROTOCOLS[0]);
|
||||
protocol::SUPPORTED_PROTOCOLS[0]
|
||||
}
|
||||
};
|
||||
let (protocol_version, forge_mods) =
|
||||
match protocol::Conn::new(&address, self.default_protocol_version)
|
||||
.and_then(|conn| conn.do_status())
|
||||
{
|
||||
Ok(res) => {
|
||||
info!(
|
||||
"Detected server protocol version {}",
|
||||
res.0.version.protocol
|
||||
);
|
||||
(res.0.version.protocol, res.0.forge_mods)
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"Error pinging server {} to get protocol version: {:?}, defaulting to {}",
|
||||
address, err, self.default_protocol_version
|
||||
);
|
||||
(self.default_protocol_version, vec![])
|
||||
}
|
||||
};
|
||||
|
||||
self.protocol_version = protocol_version;
|
||||
let (tx, rx) = mpsc::channel();
|
||||
self.connect_reply = Some(rx);
|
||||
let address = address.to_owned();
|
||||
|
@ -112,7 +117,14 @@ impl Game {
|
|||
access_token: self.vars.get(auth::AUTH_TOKEN).clone(),
|
||||
};
|
||||
thread::spawn(move || {
|
||||
tx.send(server::Server::connect(resources, profile, &address, protocol_version)).unwrap();
|
||||
tx.send(server::Server::connect(
|
||||
resources,
|
||||
profile,
|
||||
&address,
|
||||
protocol_version,
|
||||
forge_mods,
|
||||
))
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -125,9 +137,8 @@ impl Game {
|
|||
}
|
||||
|
||||
if let Some(disconnect_reason) = self.server.disconnect_reason.take() {
|
||||
self.screen_sys.replace_screen(Box::new(screen::ServerList::new(
|
||||
Some(disconnect_reason)
|
||||
)));
|
||||
self.screen_sys
|
||||
.replace_screen(Box::new(screen::ServerList::new(Some(disconnect_reason))));
|
||||
}
|
||||
if !self.server.is_connected() {
|
||||
self.focused = false;
|
||||
|
@ -143,7 +154,7 @@ impl Game {
|
|||
self.focused = true;
|
||||
self.server.remove(&mut self.renderer);
|
||||
self.server = val;
|
||||
},
|
||||
}
|
||||
Err(err) => {
|
||||
let msg = match err {
|
||||
protocol::Error::Disconnect(val) => val,
|
||||
|
@ -151,11 +162,10 @@ impl Game {
|
|||
let mut msg = format::TextComponent::new(&format!("{}", err));
|
||||
msg.modifier.color = Some(format::Color::Red);
|
||||
format::Component::Text(msg)
|
||||
},
|
||||
}
|
||||
};
|
||||
self.screen_sys.replace_screen(Box::new(screen::ServerList::new(
|
||||
Some(msg)
|
||||
)));
|
||||
self.screen_sys
|
||||
.replace_screen(Box::new(screen::ServerList::new(Some(msg))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -166,8 +176,62 @@ impl Game {
|
|||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(name = "Stevenarella")]
|
||||
struct Opt {
|
||||
/// Server to connect to
|
||||
#[structopt(short = "s", long = "server")]
|
||||
server: Option<String>,
|
||||
|
||||
/// Username for offline servers
|
||||
#[structopt(short = "u", long = "username")]
|
||||
username: Option<String>,
|
||||
|
||||
/// Log decoded packets received from network
|
||||
#[structopt(short = "n", long = "network-debug")]
|
||||
network_debug: bool,
|
||||
|
||||
/// Protocol version to use in the autodetection ping
|
||||
#[structopt(short = "p", long = "default-protocol-version")]
|
||||
default_protocol_version: Option<String>,
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_arch = "wasm32")] {
|
||||
extern crate console_error_panic_hook;
|
||||
pub use console_error_panic_hook::set_once as set_panic_hook;
|
||||
} else {
|
||||
#[inline]
|
||||
pub fn set_panic_hook() {}
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_os = "unknown")] {
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn main() { main2(); }
|
||||
} else {
|
||||
#[inline]
|
||||
pub fn main() { main2(); }
|
||||
}
|
||||
}
|
||||
|
||||
fn main2() {
|
||||
let opt = Opt::from_args();
|
||||
|
||||
set_panic_hook();
|
||||
std::env::set_var("RUST_BACKTRACE", "1");
|
||||
|
||||
let con = Arc::new(Mutex::new(console::Console::new()));
|
||||
let proxy = console::ConsoleProxy::new(con.clone());
|
||||
|
||||
log::set_boxed_logger(Box::new(proxy)).unwrap();
|
||||
log::set_max_level(log::LevelFilter::Trace);
|
||||
|
||||
info!("Starting steven");
|
||||
|
||||
let (vars, vsync) = {
|
||||
let mut vars = console::Vars::new();
|
||||
vars.register(CL_BRAND);
|
||||
|
@ -179,32 +243,30 @@ fn main() {
|
|||
(Rc::new(vars), vsync)
|
||||
};
|
||||
|
||||
let proxy = console::ConsoleProxy::new(con.clone());
|
||||
|
||||
log::set_boxed_logger(Box::new(proxy)).unwrap();
|
||||
log::set_max_level(log::LevelFilter::Trace);
|
||||
|
||||
info!("Starting steven");
|
||||
|
||||
let (res, mut resui) = resources::Manager::new();
|
||||
let resource_manager = Arc::new(RwLock::new(res));
|
||||
|
||||
let mut events_loop = glutin::EventsLoop::new();
|
||||
let window_builder = glutin::WindowBuilder::new()
|
||||
let events_loop = glutin::event_loop::EventLoop::new();
|
||||
let window_builder = glutin::window::WindowBuilder::new()
|
||||
.with_title("Stevenarella")
|
||||
.with_dimensions(glutin::dpi::LogicalSize::new(854.0, 480.0));
|
||||
let context = glutin::ContextBuilder::new()
|
||||
.with_inner_size(glutin::dpi::LogicalSize::new(854.0, 480.0));
|
||||
let window = glutin::ContextBuilder::new()
|
||||
.with_stencil_buffer(0)
|
||||
.with_depth_buffer(24)
|
||||
.with_gl(glutin::GlRequest::GlThenGles{opengl_version: (3, 2), opengles_version: (2, 0)})
|
||||
.with_gl(glutin::GlRequest::GlThenGles {
|
||||
opengl_version: (3, 2),
|
||||
opengles_version: (2, 0),
|
||||
})
|
||||
.with_gl_profile(glutin::GlProfile::Core)
|
||||
.with_vsync(vsync);
|
||||
let mut window = glutin::GlWindow::new(window_builder, context, &events_loop)
|
||||
.with_vsync(vsync)
|
||||
.build_windowed(window_builder, &events_loop)
|
||||
.expect("Could not create glutin window.");
|
||||
|
||||
unsafe {
|
||||
window.make_current().expect("Could not set current context.");
|
||||
}
|
||||
let mut window = unsafe {
|
||||
window
|
||||
.make_current()
|
||||
.expect("Could not set current context.")
|
||||
};
|
||||
|
||||
gl::init(&window);
|
||||
|
||||
|
@ -215,10 +277,27 @@ fn main() {
|
|||
let frame_time = 1e9f64 / 60.0;
|
||||
|
||||
let mut screen_sys = screen::ScreenSystem::new();
|
||||
screen_sys.add_screen(Box::new(screen::Login::new(vars.clone())));
|
||||
if opt.server.is_none() {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
screen_sys.add_screen(Box::new(screen::Login::new(vars.clone())));
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
screen_sys.add_screen(Box::new(screen::ServerList::new(None)));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(username) = opt.username {
|
||||
vars.set(auth::CL_USERNAME, username);
|
||||
}
|
||||
|
||||
let textures = renderer.get_textures();
|
||||
let dpi_factor = window.get_current_monitor().get_hidpi_factor();
|
||||
let dpi_factor = window.window().scale_factor();
|
||||
let default_protocol_version = protocol::versions::protocol_name_to_protocol_version(
|
||||
opt.default_protocol_version.unwrap_or("".to_string()),
|
||||
);
|
||||
let mut game = Game {
|
||||
server: server::Server::dummy_server(resource_manager.clone()),
|
||||
focused: false,
|
||||
|
@ -230,25 +309,41 @@ fn main() {
|
|||
should_close: false,
|
||||
chunk_builder: chunk_builder::ChunkBuilder::new(resource_manager, textures),
|
||||
connect_reply: None,
|
||||
protocol_version: protocol::SUPPORTED_PROTOCOLS[0],
|
||||
dpi_factor,
|
||||
last_mouse_x: 0.0,
|
||||
last_mouse_y: 0.0,
|
||||
last_mouse_xrel: 0.0,
|
||||
last_mouse_yrel: 0.0,
|
||||
is_ctrl_pressed: false,
|
||||
is_logo_pressed: false,
|
||||
is_fullscreen: false,
|
||||
default_protocol_version,
|
||||
};
|
||||
game.renderer.camera.pos = cgmath::Point3::new(0.5, 13.2, 0.5);
|
||||
|
||||
if opt.network_debug {
|
||||
protocol::enable_network_debug();
|
||||
}
|
||||
|
||||
if opt.server.is_some() {
|
||||
game.connect_to(&opt.server.unwrap());
|
||||
}
|
||||
|
||||
let mut last_resource_version = 0;
|
||||
while !game.should_close {
|
||||
events_loop.run(move |event, _event_loop, control_flow| {
|
||||
*control_flow = glutin::event_loop::ControlFlow::Poll;
|
||||
|
||||
if !handle_window_event(&mut window, &mut game, &mut ui_container, event) {
|
||||
return;
|
||||
}
|
||||
|
||||
let now = Instant::now();
|
||||
let diff = now.duration_since(last_frame);
|
||||
last_frame = now;
|
||||
let delta = (diff.subsec_nanos() as f64) / frame_time;
|
||||
let (width, height) = window.get_inner_size().unwrap().into();
|
||||
let (physical_width, physical_height) = window.get_inner_size().unwrap().to_physical(game.dpi_factor).into();
|
||||
let physical_size = window.window().inner_size();
|
||||
let (physical_width, physical_height) = physical_size.into();
|
||||
let (width, height) = physical_size.to_logical::<f64>(game.dpi_factor).into();
|
||||
|
||||
let version = {
|
||||
let try_res = game.resource_manager.try_write();
|
||||
|
@ -266,8 +361,8 @@ fn main() {
|
|||
|
||||
let vsync_changed = *game.vars.get(settings::R_VSYNC);
|
||||
if vsync != vsync_changed {
|
||||
println!("Changing vsync currently requires restarting");
|
||||
break;
|
||||
error!("Changing vsync currently requires restarting");
|
||||
game.should_close = true;
|
||||
// TODO: after https://github.com/tomaka/glutin/issues/693 Allow changing vsync on a Window
|
||||
//vsync = vsync_changed;
|
||||
}
|
||||
|
@ -276,18 +371,31 @@ fn main() {
|
|||
game.tick(delta);
|
||||
game.server.tick(&mut game.renderer, delta);
|
||||
|
||||
// Check if window is valid, it might be minimized
|
||||
if physical_width == 0 || physical_height == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
game.renderer.update_camera(physical_width, physical_height);
|
||||
game.server.world.compute_render_list(&mut game.renderer);
|
||||
game.chunk_builder.tick(&mut game.server.world, &mut game.renderer, version);
|
||||
game.chunk_builder
|
||||
.tick(&mut game.server.world, &mut game.renderer, version);
|
||||
|
||||
game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container);
|
||||
game.screen_sys
|
||||
.tick(delta, &mut game.renderer, &mut ui_container);
|
||||
game.console
|
||||
.lock()
|
||||
.unwrap()
|
||||
.tick(&mut ui_container, &game.renderer, delta, width as f64);
|
||||
ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
|
||||
game.renderer.tick(&mut game.server.world, delta, width, height, physical_width, physical_height);
|
||||
|
||||
game.renderer.tick(
|
||||
&mut game.server.world,
|
||||
delta,
|
||||
width,
|
||||
height,
|
||||
physical_width,
|
||||
physical_height,
|
||||
);
|
||||
|
||||
if fps_cap > 0 && !vsync {
|
||||
let frame_time = now.elapsed();
|
||||
|
@ -298,32 +406,44 @@ fn main() {
|
|||
}
|
||||
window.swap_buffers().expect("Failed to swap GL buffers");
|
||||
|
||||
events_loop.poll_events(|event| {
|
||||
handle_window_event(&mut window, &mut game, &mut ui_container, event);
|
||||
});
|
||||
}
|
||||
if game.should_close {
|
||||
*control_flow = glutin::event_loop::ControlFlow::Exit;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_window_event(window: &mut glutin::GlWindow,
|
||||
game: &mut Game,
|
||||
ui_container: &mut ui::Container,
|
||||
event: glutin::Event) {
|
||||
use glutin::*;
|
||||
fn handle_window_event<T>(
|
||||
window: &mut glutin::WindowedContext<glutin::PossiblyCurrent>,
|
||||
game: &mut Game,
|
||||
ui_container: &mut ui::Container,
|
||||
event: glutin::event::Event<T>,
|
||||
) -> bool {
|
||||
use glutin::event::*;
|
||||
match event {
|
||||
Event::DeviceEvent{event, ..} => match event {
|
||||
DeviceEvent::MouseMotion{delta:(xrel, yrel)} => {
|
||||
let (rx, ry) =
|
||||
if xrel > 1000.0 || yrel > 1000.0 {
|
||||
// Heuristic for if we were passed an absolute value instead of relative
|
||||
// Workaround https://github.com/tomaka/glutin/issues/1084 MouseMotion event returns absolute instead of relative values, when running Linux in a VM
|
||||
// Note SDL2 had a hint to handle this scenario:
|
||||
// sdl2::hint::set_with_priority("SDL_MOUSE_RELATIVE_MODE_WARP", "1", &sdl2::hint::Hint::Override);
|
||||
let s = 8000.0 + 0.01;
|
||||
((xrel - game.last_mouse_xrel) / s, (yrel - game.last_mouse_yrel) / s)
|
||||
} else {
|
||||
let s = 2000.0 + 0.01;
|
||||
(xrel / s, yrel / s)
|
||||
};
|
||||
Event::MainEventsCleared => return true,
|
||||
Event::DeviceEvent { event, .. } => match event {
|
||||
DeviceEvent::ModifiersChanged(modifiers_state) => {
|
||||
game.is_ctrl_pressed = modifiers_state.ctrl();
|
||||
game.is_logo_pressed = modifiers_state.logo();
|
||||
}
|
||||
|
||||
DeviceEvent::MouseMotion {
|
||||
delta: (xrel, yrel),
|
||||
} => {
|
||||
let (rx, ry) = if xrel > 1000.0 || yrel > 1000.0 {
|
||||
// Heuristic for if we were passed an absolute value instead of relative
|
||||
// Workaround https://github.com/tomaka/glutin/issues/1084 MouseMotion event returns absolute instead of relative values, when running Linux in a VM
|
||||
// Note SDL2 had a hint to handle this scenario:
|
||||
// sdl2::hint::set_with_priority("SDL_MOUSE_RELATIVE_MODE_WARP", "1", &sdl2::hint::Hint::Override);
|
||||
let s = 8000.0 + 0.01;
|
||||
(
|
||||
(xrel - game.last_mouse_xrel) / s,
|
||||
(yrel - game.last_mouse_yrel) / s,
|
||||
)
|
||||
} else {
|
||||
let s = 2000.0 + 0.01;
|
||||
(xrel / s, yrel / s)
|
||||
};
|
||||
|
||||
game.last_mouse_xrel = xrel;
|
||||
game.last_mouse_yrel = yrel;
|
||||
|
@ -331,141 +451,178 @@ fn handle_window_event(window: &mut glutin::GlWindow,
|
|||
use std::f64::consts::PI;
|
||||
|
||||
if game.focused {
|
||||
window.grab_cursor(true).unwrap();
|
||||
window.hide_cursor(true);
|
||||
window.window().set_cursor_grab(true).unwrap();
|
||||
window.window().set_cursor_visible(false);
|
||||
if let Some(player) = game.server.player {
|
||||
let rotation = game.server.entities.get_component_mut(player, game.server.rotation).unwrap();
|
||||
let rotation = game
|
||||
.server
|
||||
.entities
|
||||
.get_component_mut(player, game.server.rotation)
|
||||
.unwrap();
|
||||
rotation.yaw -= rx;
|
||||
rotation.pitch -= ry;
|
||||
if rotation.pitch < (PI/2.0) + 0.01 {
|
||||
rotation.pitch = (PI/2.0) + 0.01;
|
||||
if rotation.pitch < (PI / 2.0) + 0.01 {
|
||||
rotation.pitch = (PI / 2.0) + 0.01;
|
||||
}
|
||||
if rotation.pitch > (PI/2.0)*3.0 - 0.01 {
|
||||
rotation.pitch = (PI/2.0)*3.0 - 0.01;
|
||||
if rotation.pitch > (PI / 2.0) * 3.0 - 0.01 {
|
||||
rotation.pitch = (PI / 2.0) * 3.0 - 0.01;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
window.grab_cursor(false).unwrap();
|
||||
window.hide_cursor(false);
|
||||
window.window().set_cursor_grab(false).unwrap();
|
||||
window.window().set_cursor_visible(true);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_ => ()
|
||||
_ => (),
|
||||
},
|
||||
|
||||
Event::WindowEvent{event, ..} => match event {
|
||||
WindowEvent::CloseRequested => game.should_close = true,
|
||||
WindowEvent::Resized(logical_size) => {
|
||||
game.dpi_factor = window.get_hidpi_factor();
|
||||
window.resize(logical_size.to_physical(game.dpi_factor));
|
||||
},
|
||||
|
||||
WindowEvent::ReceivedCharacter(codepoint) => {
|
||||
if !game.focused {
|
||||
ui_container.key_type(game, codepoint);
|
||||
Event::WindowEvent { event, .. } => {
|
||||
match event {
|
||||
WindowEvent::CloseRequested => game.should_close = true,
|
||||
WindowEvent::Resized(physical_size) => {
|
||||
window.resize(physical_size);
|
||||
}
|
||||
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
|
||||
game.dpi_factor = scale_factor;
|
||||
}
|
||||
},
|
||||
|
||||
WindowEvent::MouseInput{device_id: _, state, button, modifiers: _} => {
|
||||
match (state, button) {
|
||||
WindowEvent::ReceivedCharacter(codepoint) => {
|
||||
if !game.focused {
|
||||
ui_container.key_type(game, codepoint);
|
||||
}
|
||||
}
|
||||
|
||||
WindowEvent::MouseInput { state, button, .. } => match (state, button) {
|
||||
(ElementState::Released, MouseButton::Left) => {
|
||||
let (width, height) = window.get_inner_size().unwrap().into();
|
||||
let (width, height) = window
|
||||
.window()
|
||||
.inner_size()
|
||||
.to_logical::<f64>(game.dpi_factor)
|
||||
.into();
|
||||
|
||||
if game.server.is_connected() && !game.focused && !game.screen_sys.is_current_closable() {
|
||||
if game.server.is_connected()
|
||||
&& !game.focused
|
||||
&& !game.screen_sys.is_current_closable()
|
||||
{
|
||||
game.focused = true;
|
||||
window.grab_cursor(true).unwrap();
|
||||
window.hide_cursor(true);
|
||||
return;
|
||||
window.window().set_cursor_grab(true).unwrap();
|
||||
window.window().set_cursor_visible(false);
|
||||
} else {
|
||||
if !game.focused {
|
||||
window.window().set_cursor_grab(false).unwrap();
|
||||
window.window().set_cursor_visible(true);
|
||||
ui_container.click_at(
|
||||
game,
|
||||
game.last_mouse_x,
|
||||
game.last_mouse_y,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
}
|
||||
}
|
||||
if !game.focused {
|
||||
window.grab_cursor(false).unwrap();
|
||||
window.hide_cursor(false);
|
||||
ui_container.click_at(game, game.last_mouse_x, game.last_mouse_y, width, height);
|
||||
}
|
||||
},
|
||||
}
|
||||
(ElementState::Pressed, MouseButton::Right) => {
|
||||
if game.focused {
|
||||
game.server.on_right_click(&mut game.renderer);
|
||||
}
|
||||
},
|
||||
(_, _) => ()
|
||||
}
|
||||
},
|
||||
WindowEvent::CursorMoved{device_id: _, position, modifiers: _} => {
|
||||
let (x, y) = position.into();
|
||||
game.last_mouse_x = x;
|
||||
game.last_mouse_y = y;
|
||||
}
|
||||
(_, _) => (),
|
||||
},
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
let (x, y) = position.into();
|
||||
game.last_mouse_x = x;
|
||||
game.last_mouse_y = y;
|
||||
|
||||
if !game.focused {
|
||||
let (width, height) = window.get_inner_size().unwrap().into();
|
||||
ui_container.hover_at(game, x, y, width, height);
|
||||
if !game.focused {
|
||||
let (width, height) = window
|
||||
.window()
|
||||
.inner_size()
|
||||
.to_logical::<f64>(game.dpi_factor)
|
||||
.into();
|
||||
ui_container.hover_at(game, x, y, width, height);
|
||||
}
|
||||
}
|
||||
},
|
||||
WindowEvent::MouseWheel{device_id: _, delta, phase: _, modifiers: _} => {
|
||||
// TODO: line vs pixel delta? does pixel scrolling (e.g. touchpad) need scaling?
|
||||
match delta {
|
||||
MouseScrollDelta::LineDelta(x, y) => {
|
||||
game.screen_sys.on_scroll(x.into(), y.into());
|
||||
},
|
||||
MouseScrollDelta::PixelDelta(position) => {
|
||||
let (x, y) = position.into();
|
||||
game.screen_sys.on_scroll(x, y);
|
||||
},
|
||||
}
|
||||
},
|
||||
WindowEvent::KeyboardInput{device_id: _, input} => {
|
||||
match (input.state, input.virtual_keycode) {
|
||||
(ElementState::Released, Some(VirtualKeyCode::Escape)) => {
|
||||
if game.focused {
|
||||
window.grab_cursor(false).unwrap();
|
||||
window.hide_cursor(false);
|
||||
game.focused = false;
|
||||
game.screen_sys.replace_screen(Box::new(screen::SettingsMenu::new(game.vars.clone(), true)));
|
||||
} else if game.screen_sys.is_current_closable() {
|
||||
window.grab_cursor(true).unwrap();
|
||||
window.hide_cursor(true);
|
||||
game.focused = true;
|
||||
game.screen_sys.pop_screen();
|
||||
WindowEvent::MouseWheel { delta, .. } => {
|
||||
// TODO: line vs pixel delta? does pixel scrolling (e.g. touchpad) need scaling?
|
||||
match delta {
|
||||
MouseScrollDelta::LineDelta(x, y) => {
|
||||
game.screen_sys.on_scroll(x.into(), y.into());
|
||||
}
|
||||
MouseScrollDelta::PixelDelta(position) => {
|
||||
let (x, y) = position.into();
|
||||
game.screen_sys.on_scroll(x, y);
|
||||
}
|
||||
}
|
||||
(ElementState::Pressed, Some(VirtualKeyCode::Grave)) => {
|
||||
game.console.lock().unwrap().toggle();
|
||||
},
|
||||
(ElementState::Pressed, Some(VirtualKeyCode::F11)) => {
|
||||
if game.is_fullscreen {
|
||||
window.set_fullscreen(Some(window.get_current_monitor()));
|
||||
} else {
|
||||
window.set_fullscreen(None);
|
||||
}
|
||||
|
||||
game.is_fullscreen = !game.is_fullscreen;
|
||||
},
|
||||
(ElementState::Pressed, Some(key)) => {
|
||||
if game.focused {
|
||||
if let Some(steven_key) = settings::Stevenkey::get_by_keycode(key, &game.vars) {
|
||||
game.server.key_press(true, steven_key);
|
||||
}
|
||||
} else {
|
||||
let ctrl_pressed = input.modifiers.ctrl;
|
||||
ui_container.key_press(game, key, true, ctrl_pressed);
|
||||
}
|
||||
},
|
||||
(ElementState::Released, Some(key)) => {
|
||||
if game.focused {
|
||||
if let Some(steven_key) = settings::Stevenkey::get_by_keycode(key, &game.vars) {
|
||||
game.server.key_press(false, steven_key);
|
||||
}
|
||||
} else {
|
||||
let ctrl_pressed = input.modifiers.ctrl;
|
||||
ui_container.key_press(game, key, false, ctrl_pressed);
|
||||
}
|
||||
},
|
||||
(_, None) => ()
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
},
|
||||
WindowEvent::KeyboardInput { input, .. } => {
|
||||
match (input.state, input.virtual_keycode) {
|
||||
(ElementState::Released, Some(VirtualKeyCode::Escape)) => {
|
||||
if game.focused {
|
||||
window.window().set_cursor_grab(false).unwrap();
|
||||
window.window().set_cursor_visible(true);
|
||||
game.focused = false;
|
||||
game.screen_sys.replace_screen(Box::new(
|
||||
screen::SettingsMenu::new(game.vars.clone(), true),
|
||||
));
|
||||
} else if game.screen_sys.is_current_closable() {
|
||||
window.window().set_cursor_grab(true).unwrap();
|
||||
window.window().set_cursor_visible(false);
|
||||
game.focused = true;
|
||||
game.screen_sys.pop_screen();
|
||||
}
|
||||
}
|
||||
(ElementState::Pressed, Some(VirtualKeyCode::Grave)) => {
|
||||
game.console.lock().unwrap().toggle();
|
||||
}
|
||||
(ElementState::Pressed, Some(VirtualKeyCode::F11)) => {
|
||||
if !game.is_fullscreen {
|
||||
// TODO: support options for exclusive and simple fullscreen
|
||||
// see https://docs.rs/glutin/0.22.0-alpha5/glutin/window/struct.Window.html#method.set_fullscreen
|
||||
window.window().set_fullscreen(Some(
|
||||
glutin::window::Fullscreen::Borderless(
|
||||
window.window().current_monitor(),
|
||||
),
|
||||
));
|
||||
} else {
|
||||
window.window().set_fullscreen(None);
|
||||
}
|
||||
|
||||
game.is_fullscreen = !game.is_fullscreen;
|
||||
}
|
||||
(ElementState::Pressed, Some(key)) => {
|
||||
if game.focused {
|
||||
if let Some(steven_key) =
|
||||
settings::Stevenkey::get_by_keycode(key, &game.vars)
|
||||
{
|
||||
game.server.key_press(true, steven_key);
|
||||
}
|
||||
} else {
|
||||
let ctrl_pressed = game.is_ctrl_pressed || game.is_logo_pressed;
|
||||
ui_container.key_press(game, key, true, ctrl_pressed);
|
||||
}
|
||||
}
|
||||
(ElementState::Released, Some(key)) => {
|
||||
if game.focused {
|
||||
if let Some(steven_key) =
|
||||
settings::Stevenkey::get_by_keycode(key, &game.vars)
|
||||
{
|
||||
game.server.key_press(false, steven_key);
|
||||
}
|
||||
} else {
|
||||
let ctrl_pressed = game.is_ctrl_pressed;
|
||||
ui_container.key_press(game, key, false, ctrl_pressed);
|
||||
}
|
||||
}
|
||||
(_, None) => (),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
|
||||
use std::io::Write;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use crate::world::{self, block};
|
||||
use crate::shared::Direction;
|
||||
use crate::model::BlockVertex;
|
||||
use crate::render;
|
||||
use crate::shared::Direction;
|
||||
use crate::world::{self, block};
|
||||
use std::io::Write;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lava: bool, snapshot: &world::Snapshot, x: i32, y: i32, z: i32, buf: &mut W) -> usize {
|
||||
pub fn render_liquid<W: Write>(
|
||||
textures: Arc<RwLock<render::TextureManager>>,
|
||||
lava: bool,
|
||||
snapshot: &world::Snapshot,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
buf: &mut W,
|
||||
) -> usize {
|
||||
let get_liquid = if lava {
|
||||
get_lava_level
|
||||
} else {
|
||||
|
@ -20,17 +27,25 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
|
|||
} else {
|
||||
(
|
||||
average_liquid_level(get_liquid, snapshot, x, y, z),
|
||||
average_liquid_level(get_liquid, snapshot, x+1, y, z),
|
||||
average_liquid_level(get_liquid, snapshot, x, y, z+1),
|
||||
average_liquid_level(get_liquid, snapshot, x+1, y, z+1)
|
||||
average_liquid_level(get_liquid, snapshot, x + 1, y, z),
|
||||
average_liquid_level(get_liquid, snapshot, x, y, z + 1),
|
||||
average_liquid_level(get_liquid, snapshot, x + 1, y, z + 1),
|
||||
)
|
||||
};
|
||||
|
||||
let tex = match snapshot.get_block(x, y, z) {
|
||||
block::Block::Water{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/water_still"),
|
||||
block::Block::FlowingWater{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/water_flow"),
|
||||
block::Block::Lava{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/lava_still"),
|
||||
block::Block::FlowingLava{..} => render::Renderer::get_texture(&textures, "minecraft:blocks/lava_flow"),
|
||||
block::Block::Water { .. } => {
|
||||
render::Renderer::get_texture(&textures, "minecraft:blocks/water_still")
|
||||
}
|
||||
block::Block::FlowingWater { .. } => {
|
||||
render::Renderer::get_texture(&textures, "minecraft:blocks/water_flow")
|
||||
}
|
||||
block::Block::Lava { .. } => {
|
||||
render::Renderer::get_texture(&textures, "minecraft:blocks/lava_still")
|
||||
}
|
||||
block::Block::FlowingLava { .. } => {
|
||||
render::Renderer::get_texture(&textures, "minecraft:blocks/lava_flow")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let ux1 = 0i16;
|
||||
|
@ -41,8 +56,11 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
|
|||
for dir in Direction::all() {
|
||||
let (ox, oy, oz) = dir.get_offset();
|
||||
let special = dir == Direction::Up && (tl < 8 || tr < 8 || bl < 8 || br < 8);
|
||||
let block = snapshot.get_block(x+ox, y+oy, z+oz);
|
||||
if special || (!block.get_material().should_cull_against && get_liquid(snapshot, x+ox, y+oy, z+oz).is_none()) {
|
||||
let block = snapshot.get_block(x + ox, y + oy, z + oz);
|
||||
if special
|
||||
|| (!block.get_material().should_cull_against
|
||||
&& get_liquid(snapshot, x + ox, y + oy, z + oz).is_none())
|
||||
{
|
||||
let verts = BlockVertex::face_by_direction(dir);
|
||||
for vert in verts {
|
||||
let mut vert = vert.clone();
|
||||
|
@ -64,7 +82,7 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
|
|||
(0, _) => ((16.0 / 8.0) * (bl as f32)) as i32,
|
||||
(_, _) => ((16.0 / 8.0) * (br as f32)) as i32,
|
||||
};
|
||||
vert.y = (height as f32)/16.0 + (y as f32);
|
||||
vert.y = (height as f32) / 16.0 + (y as f32);
|
||||
}
|
||||
|
||||
vert.x += x as f32;
|
||||
|
@ -72,13 +90,15 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
|
|||
|
||||
let (bl, sl) = super::calculate_light(
|
||||
snapshot,
|
||||
x, y, z,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
vert.x as f64,
|
||||
vert.y as f64,
|
||||
vert.z as f64,
|
||||
dir,
|
||||
!lava,
|
||||
false
|
||||
false,
|
||||
);
|
||||
vert.block_light = bl;
|
||||
vert.sky_light = sl;
|
||||
|
@ -106,15 +126,18 @@ pub fn render_liquid<W: Write>(textures: Arc<RwLock<render::TextureManager>>,lav
|
|||
|
||||
fn average_liquid_level(
|
||||
get: fn(&world::Snapshot, i32, i32, i32) -> Option<i32>,
|
||||
snapshot: &world::Snapshot, x: i32, y: i32, z: i32
|
||||
snapshot: &world::Snapshot,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
) -> i32 {
|
||||
let mut level = 0;
|
||||
for xx in -1 .. 1 {
|
||||
for zz in -1 .. 1 {
|
||||
if get(snapshot, x+xx, y+1, z+zz).is_some() {
|
||||
for xx in -1..1 {
|
||||
for zz in -1..1 {
|
||||
if get(snapshot, x + xx, y + 1, z + zz).is_some() {
|
||||
return 8;
|
||||
}
|
||||
if let Some(l) = get(snapshot, x+xx, y, z+zz) {
|
||||
if let Some(l) = get(snapshot, x + xx, y, z + zz) {
|
||||
let nl = 7 - (l & 0x7);
|
||||
if nl > level {
|
||||
level = nl;
|
||||
|
@ -127,14 +150,14 @@ fn average_liquid_level(
|
|||
|
||||
fn get_water_level(snapshot: &world::Snapshot, x: i32, y: i32, z: i32) -> Option<i32> {
|
||||
match snapshot.get_block(x, y, z) {
|
||||
block::Block::Water{level} | block::Block::FlowingWater{level} => Some(level as i32),
|
||||
block::Block::Water { level } | block::Block::FlowingWater { level } => Some(level as i32),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_lava_level(snapshot: &world::Snapshot, x: i32, y: i32, z: i32) -> Option<i32> {
|
||||
match snapshot.get_block(x, y, z) {
|
||||
block::Block::Lava{level} | block::Block::FlowingLava{level} => Some(level as i32),
|
||||
block::Block::Lava { level } | block::Block::FlowingLava { level } => Some(level as i32),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
562
src/model/mod.rs
562
src/model/mod.rs
|
@ -1,24 +1,24 @@
|
|||
|
||||
pub mod liquid;
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::collections::HashMap;
|
||||
use std::cell::RefCell;
|
||||
use std::io::Write;
|
||||
use byteorder::{WriteBytesExt, NativeEndian};
|
||||
use crate::resources;
|
||||
use crate::render;
|
||||
use crate::resources;
|
||||
use crate::shared::Direction;
|
||||
use crate::world;
|
||||
use crate::world::block::{Block, TintType};
|
||||
use crate::shared::Direction;
|
||||
use byteorder::{NativeEndian, WriteBytesExt};
|
||||
use serde_json;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use std::hash::BuildHasherDefault;
|
||||
use crate::types::hash::FNVHash;
|
||||
use log::{error};
|
||||
use log::error;
|
||||
use std::hash::BuildHasherDefault;
|
||||
|
||||
use rand::Rng;
|
||||
use image::GenericImageView;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::Rng;
|
||||
|
||||
pub struct Factory {
|
||||
resources: Arc<RwLock<resources::Manager>>,
|
||||
|
@ -34,7 +34,7 @@ pub struct Factory {
|
|||
struct Key(String, String);
|
||||
|
||||
macro_rules! try_log {
|
||||
($e:expr) => (
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
|
@ -42,8 +42,8 @@ macro_rules! try_log {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
(opt $e:expr) => (
|
||||
};
|
||||
(opt $e:expr) => {
|
||||
match $e {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
|
@ -51,7 +51,7 @@ macro_rules! try_log {
|
|||
return None;
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
thread_local!(
|
||||
|
@ -59,7 +59,10 @@ thread_local!(
|
|||
);
|
||||
|
||||
impl Factory {
|
||||
pub fn new(resources: Arc<RwLock<resources::Manager>>, textures: Arc<RwLock<render::TextureManager>>) -> Factory {
|
||||
pub fn new(
|
||||
resources: Arc<RwLock<resources::Manager>>,
|
||||
textures: Arc<RwLock<render::TextureManager>>,
|
||||
) -> Factory {
|
||||
Factory {
|
||||
grass_colors: Factory::load_biome_colors(resources.clone(), "grass"),
|
||||
foliage_colors: Factory::load_biome_colors(resources.clone(), "foliage"),
|
||||
|
@ -71,7 +74,11 @@ impl Factory {
|
|||
}
|
||||
|
||||
fn load_biome_colors(res: Arc<RwLock<resources::Manager>>, name: &str) -> image::DynamicImage {
|
||||
let mut val = match res.read().unwrap().open("minecraft", &format!("textures/colormap/{}.png", name)) {
|
||||
let mut val = match res
|
||||
.read()
|
||||
.unwrap()
|
||||
.open("minecraft", &format!("textures/colormap/{}.png", name))
|
||||
{
|
||||
Some(val) => val,
|
||||
None => return image::DynamicImage::new_rgb8(256, 256),
|
||||
};
|
||||
|
@ -86,7 +93,17 @@ impl Factory {
|
|||
self.foliage_colors = Factory::load_biome_colors(self.resources.clone(), "foliage");
|
||||
}
|
||||
|
||||
fn get_model<R: Rng, W: Write>(&self, key: Key, block: Block, rng: &mut R, snapshot: &world::Snapshot, x: i32, y: i32, z: i32, buf: &mut W) -> Result<usize, bool> {
|
||||
fn get_model<R: Rng, W: Write>(
|
||||
&self,
|
||||
key: Key,
|
||||
block: Block,
|
||||
rng: &mut R,
|
||||
snapshot: &world::Snapshot,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
buf: &mut W,
|
||||
) -> Result<usize, bool> {
|
||||
use std::collections::hash_map::Entry;
|
||||
if let Some(model) = self.models.get(&key) {
|
||||
if model.multipart.is_empty() {
|
||||
|
@ -102,7 +119,7 @@ impl Factory {
|
|||
match entry {
|
||||
Entry::Occupied(e) => {
|
||||
return Ok(e.get().render(self, snapshot, x, y, z, buf));
|
||||
},
|
||||
}
|
||||
Entry::Vacant(e) => {
|
||||
let mut res: Option<Model> = None;
|
||||
for rule in &model.multipart {
|
||||
|
@ -118,7 +135,7 @@ impl Factory {
|
|||
if let Some(mdl) = res {
|
||||
return Ok(e.insert(mdl).render(self, snapshot, x, y, z, buf));
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
Err(true)
|
||||
});
|
||||
|
@ -142,7 +159,7 @@ impl Factory {
|
|||
if !ok {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}
|
||||
Rule::Match(ref key, ref val) => {
|
||||
if !block.match_multipart(key, val) {
|
||||
return false;
|
||||
|
@ -153,8 +170,16 @@ impl Factory {
|
|||
true
|
||||
}
|
||||
|
||||
pub fn get_state_model<R: Rng, W: Write>(models: &Arc<RwLock<Factory>>, block: Block, rng: &mut R,
|
||||
snapshot: &world::Snapshot, x: i32, y: i32, z: i32, buf: &mut W) -> usize {
|
||||
pub fn get_state_model<R: Rng, W: Write>(
|
||||
models: &Arc<RwLock<Factory>>,
|
||||
block: Block,
|
||||
rng: &mut R,
|
||||
snapshot: &world::Snapshot,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
buf: &mut W,
|
||||
) -> usize {
|
||||
let (plugin, name) = block.get_model();
|
||||
let key = Key(plugin.to_owned(), name.to_owned());
|
||||
let mut missing_variant;
|
||||
|
@ -176,23 +201,32 @@ impl Factory {
|
|||
Err(val) => missing_variant = val,
|
||||
};
|
||||
}
|
||||
let ret = Factory::get_state_model(models, Block::Missing{}, rng, snapshot, x, y, z, buf);
|
||||
let ret = Factory::get_state_model(models, Block::Missing {}, rng, snapshot, x, y, z, buf);
|
||||
if !missing_variant {
|
||||
// Still no model, replace with placeholder
|
||||
let mut m = models.write().unwrap();
|
||||
let model = m.models.get(&Key("steven".to_owned(), "missing_block".to_owned())).unwrap().clone();
|
||||
let model = m
|
||||
.models
|
||||
.get(&Key("steven".to_owned(), "missing_block".to_owned()))
|
||||
.unwrap()
|
||||
.clone();
|
||||
m.models.insert(key, model);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
fn load_model(&mut self, plugin: &str, name: &str) -> bool {
|
||||
let file = match self.resources.read().unwrap().open(plugin, &format!("blockstates/{}.json", name)) {
|
||||
let file = match self
|
||||
.resources
|
||||
.read()
|
||||
.unwrap()
|
||||
.open(plugin, &format!("blockstates/{}.json", name))
|
||||
{
|
||||
Some(val) => val,
|
||||
None => {
|
||||
error!("Error missing block state for {}:{}", plugin, name);
|
||||
return false;
|
||||
},
|
||||
}
|
||||
};
|
||||
let mdl: serde_json::Value = try_log!(serde_json::from_reader(file));
|
||||
|
||||
|
@ -217,14 +251,12 @@ impl Factory {
|
|||
if let Some(when) = rule.get("when").and_then(|v| v.as_object()) {
|
||||
Self::parse_rules(when, &mut rules);
|
||||
}
|
||||
model.multipart.push(MultipartRule {
|
||||
apply,
|
||||
rules,
|
||||
})
|
||||
model.multipart.push(MultipartRule { apply, rules })
|
||||
}
|
||||
}
|
||||
|
||||
self.models.insert(Key(plugin.to_owned(), name.to_owned()), model);
|
||||
self.models
|
||||
.insert(Key(plugin.to_owned(), name.to_owned()), model);
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -251,9 +283,7 @@ impl Factory {
|
|||
}
|
||||
|
||||
fn parse_model_list(&self, plugin: &str, v: &serde_json::Value) -> Variants {
|
||||
let mut variants = Variants {
|
||||
models: vec![]
|
||||
};
|
||||
let mut variants = Variants { models: vec![] };
|
||||
if let Some(list) = v.as_array() {
|
||||
for val in list {
|
||||
if let Some(mdl) = self.parse_block_state_variant(plugin, val) {
|
||||
|
@ -272,10 +302,15 @@ impl Factory {
|
|||
None => {
|
||||
error!("Couldn't find model name");
|
||||
return None;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
let file = match self.resources.read().unwrap().open(plugin, &format!("models/block/{}.json", model_name)) {
|
||||
let file = match self
|
||||
.resources
|
||||
.read()
|
||||
.unwrap()
|
||||
.open(plugin, &format!("models/block/{}.json", model_name))
|
||||
{
|
||||
Some(val) => val,
|
||||
None => {
|
||||
// 1.13+ paths remove implicit blocks/
|
||||
|
@ -294,9 +329,12 @@ impl Factory {
|
|||
let mut model = match self.parse_model(plugin, &block_model) {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
error!("Failed to parse model {}", format!("models/block/{}.json", model_name));
|
||||
error!(
|
||||
"Failed to parse model {}",
|
||||
format!("models/block/{}.json", model_name)
|
||||
);
|
||||
return None;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
model.y = v.get("y").and_then(|v| v.as_f64()).unwrap_or(0.0);
|
||||
|
@ -309,20 +347,28 @@ impl Factory {
|
|||
fn parse_model(&self, plugin: &str, v: &serde_json::Value) -> Option<RawModel> {
|
||||
let parent = v.get("parent").and_then(|v| v.as_str()).unwrap_or("");
|
||||
let mut model = if !parent.is_empty() && !parent.starts_with("builtin/") {
|
||||
let file = match self.resources.read().unwrap().open(plugin, &format!("models/{}.json", parent)) {
|
||||
let file = match self
|
||||
.resources
|
||||
.read()
|
||||
.unwrap()
|
||||
.open(plugin, &format!("models/{}.json", parent))
|
||||
{
|
||||
Some(val) => val,
|
||||
None => {
|
||||
error!("Couldn't find model {}", format!("models/{}.json", parent));
|
||||
return None;
|
||||
},
|
||||
}
|
||||
};
|
||||
let block_model: serde_json::Value = try_log!(opt serde_json::from_reader(file));
|
||||
match self.parse_model(plugin, &block_model) {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
error!("Failed to parse model {}", format!("models/{}.json", parent));
|
||||
return None
|
||||
},
|
||||
error!(
|
||||
"Failed to parse model {}",
|
||||
format!("models/{}.json", parent)
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RawModel {
|
||||
|
@ -349,7 +395,9 @@ impl Factory {
|
|||
|
||||
if let Some(textures) = v.get("textures").and_then(|v| v.as_object()) {
|
||||
for (k, v) in textures {
|
||||
model.texture_vars.insert(k.clone(), v.as_str().unwrap_or("").to_owned());
|
||||
model
|
||||
.texture_vars
|
||||
.insert(k.clone(), v.as_str().unwrap_or("").to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,16 +421,28 @@ impl Factory {
|
|||
|
||||
fn parse_block_element(&self, v: &serde_json::Value) -> ModelElement {
|
||||
let mut element = ModelElement {
|
||||
from: v.get("from").and_then(|v| v.as_array()).map(|v| [
|
||||
v[0].as_f64().unwrap(),
|
||||
v[1].as_f64().unwrap(),
|
||||
v[2].as_f64().unwrap()
|
||||
]).unwrap(),
|
||||
to: v.get("to").and_then(|v| v.as_array()).map(|v| [
|
||||
v[0].as_f64().unwrap(),
|
||||
v[1].as_f64().unwrap(),
|
||||
v[2].as_f64().unwrap()
|
||||
]).unwrap(),
|
||||
from: v
|
||||
.get("from")
|
||||
.and_then(|v| v.as_array())
|
||||
.map(|v| {
|
||||
[
|
||||
v[0].as_f64().unwrap(),
|
||||
v[1].as_f64().unwrap(),
|
||||
v[2].as_f64().unwrap(),
|
||||
]
|
||||
})
|
||||
.unwrap(),
|
||||
to: v
|
||||
.get("to")
|
||||
.and_then(|v| v.as_array())
|
||||
.map(|v| {
|
||||
[
|
||||
v[0].as_f64().unwrap(),
|
||||
v[1].as_f64().unwrap(),
|
||||
v[2].as_f64().unwrap(),
|
||||
]
|
||||
})
|
||||
.unwrap(),
|
||||
shade: v.get("shade").and_then(|v| v.as_bool()).unwrap_or(false),
|
||||
faces: [None, None, None, None, None, None],
|
||||
rotation: None,
|
||||
|
@ -396,50 +456,58 @@ impl Factory {
|
|||
let mut uv = [0.0, 0.0, 16.0, 16.0];
|
||||
match dir {
|
||||
Direction::North | Direction::South => {
|
||||
uv[0] = element.from[0];
|
||||
uv[2] = element.to[0];
|
||||
uv[1] = 16.0 - element.to[1];
|
||||
uv[3] = 16.0 - element.from[1];
|
||||
},
|
||||
uv[0] = element.from[0];
|
||||
uv[2] = element.to[0];
|
||||
uv[1] = 16.0 - element.to[1];
|
||||
uv[3] = 16.0 - element.from[1];
|
||||
}
|
||||
Direction::West | Direction::East => {
|
||||
uv[0] = element.from[2];
|
||||
uv[2] = element.to[2];
|
||||
uv[1] = 16.0 - element.to[1];
|
||||
uv[3] = 16.0 - element.from[1];
|
||||
},
|
||||
uv[0] = element.from[2];
|
||||
uv[2] = element.to[2];
|
||||
uv[1] = 16.0 - element.to[1];
|
||||
uv[3] = 16.0 - element.from[1];
|
||||
}
|
||||
Direction::Down | Direction::Up => {
|
||||
uv[0] = element.from[0];
|
||||
uv[2] = element.to[0];
|
||||
uv[1] = 16.0 - element.to[2];
|
||||
uv[3] = 16.0 - element.from[2];
|
||||
},
|
||||
uv[0] = element.from[0];
|
||||
uv[2] = element.to[0];
|
||||
uv[1] = 16.0 - element.to[2];
|
||||
uv[3] = 16.0 - element.from[2];
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
uv
|
||||
},
|
||||
|v| [
|
||||
v[0].as_f64().unwrap(),
|
||||
v[1].as_f64().unwrap(),
|
||||
v[2].as_f64().unwrap(),
|
||||
v[3].as_f64().unwrap()
|
||||
]
|
||||
|v| {
|
||||
[
|
||||
v[0].as_f64().unwrap(),
|
||||
v[1].as_f64().unwrap(),
|
||||
v[2].as_f64().unwrap(),
|
||||
v[3].as_f64().unwrap(),
|
||||
]
|
||||
},
|
||||
),
|
||||
texture: face.get("texture")
|
||||
texture: face
|
||||
.get("texture")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|v| if v.starts_with('#') {
|
||||
v.to_owned()
|
||||
} else {
|
||||
"#".to_owned() + v
|
||||
}).unwrap(),
|
||||
.map(|v| {
|
||||
if v.starts_with('#') {
|
||||
v.to_owned()
|
||||
} else {
|
||||
"#".to_owned() + v
|
||||
}
|
||||
})
|
||||
.unwrap(),
|
||||
cull_face: Direction::from_string(
|
||||
face.get("cullface")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("invalid")
|
||||
),
|
||||
rotation: face.get("rotation")
|
||||
face.get("cullface")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("invalid"),
|
||||
),
|
||||
rotation: face
|
||||
.get("rotation")
|
||||
.and_then(|v| v.as_i64())
|
||||
.map_or(0, |v| v as i32),
|
||||
tint_index: face.get("tintindex")
|
||||
tint_index: face
|
||||
.get("tintindex")
|
||||
.and_then(|v| v.as_i64())
|
||||
.map_or(-1, |v| v as i32),
|
||||
});
|
||||
|
@ -449,14 +517,29 @@ impl Factory {
|
|||
|
||||
if let Some(rotation) = v.get("rotation") {
|
||||
element.rotation = Some(BlockRotation {
|
||||
origin: rotation.get("origin").and_then(|v| v.as_array()).map_or([8.0, 8.0, 8.0], |v| [
|
||||
v[0].as_f64().unwrap(),
|
||||
v[1].as_f64().unwrap(),
|
||||
v[2].as_f64().unwrap()
|
||||
]),
|
||||
axis: rotation.get("axis").and_then(|v| v.as_str()).unwrap_or("").to_owned(),
|
||||
angle: rotation.get("angle").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||
rescale: rotation.get("rescale").and_then(|v| v.as_bool()).unwrap_or(false),
|
||||
origin: rotation.get("origin").and_then(|v| v.as_array()).map_or(
|
||||
[8.0, 8.0, 8.0],
|
||||
|v| {
|
||||
[
|
||||
v[0].as_f64().unwrap(),
|
||||
v[1].as_f64().unwrap(),
|
||||
v[2].as_f64().unwrap(),
|
||||
]
|
||||
},
|
||||
),
|
||||
axis: rotation
|
||||
.get("axis")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("")
|
||||
.to_owned(),
|
||||
angle: rotation
|
||||
.get("angle")
|
||||
.and_then(|v| v.as_f64())
|
||||
.unwrap_or(0.0),
|
||||
rescale: rotation
|
||||
.get("rescale")
|
||||
.and_then(|v| v.as_bool())
|
||||
.unwrap_or(false),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -486,29 +569,33 @@ impl Factory {
|
|||
};
|
||||
if raw.x > 0.0 {
|
||||
let o = (raw.x as i32) / 90;
|
||||
processed_face.cull_face = rotate_direction(processed_face.cull_face, o, FACE_ROTATION_X, &[
|
||||
Direction::East,
|
||||
Direction::West,
|
||||
Direction::Invalid,
|
||||
]);
|
||||
processed_face.facing = rotate_direction(processed_face.facing, o, FACE_ROTATION_X, &[
|
||||
Direction::East,
|
||||
Direction::West,
|
||||
Direction::Invalid,
|
||||
]);
|
||||
processed_face.cull_face = rotate_direction(
|
||||
processed_face.cull_face,
|
||||
o,
|
||||
FACE_ROTATION_X,
|
||||
&[Direction::East, Direction::West, Direction::Invalid],
|
||||
);
|
||||
processed_face.facing = rotate_direction(
|
||||
processed_face.facing,
|
||||
o,
|
||||
FACE_ROTATION_X,
|
||||
&[Direction::East, Direction::West, Direction::Invalid],
|
||||
);
|
||||
}
|
||||
if raw.y > 0.0 {
|
||||
let o = (raw.y as i32) / 90;
|
||||
processed_face.cull_face = rotate_direction(processed_face.cull_face, o, FACE_ROTATION, &[
|
||||
Direction::Up,
|
||||
Direction::Down,
|
||||
Direction::Invalid,
|
||||
]);
|
||||
processed_face.facing = rotate_direction(processed_face.facing, o, FACE_ROTATION, &[
|
||||
Direction::Up,
|
||||
Direction::Down,
|
||||
Direction::Invalid,
|
||||
]);
|
||||
processed_face.cull_face = rotate_direction(
|
||||
processed_face.cull_face,
|
||||
o,
|
||||
FACE_ROTATION,
|
||||
&[Direction::Up, Direction::Down, Direction::Invalid],
|
||||
);
|
||||
processed_face.facing = rotate_direction(
|
||||
processed_face.facing,
|
||||
o,
|
||||
FACE_ROTATION,
|
||||
&[Direction::Up, Direction::Down, Direction::Invalid],
|
||||
);
|
||||
}
|
||||
|
||||
let mut verts = BlockVertex::face_by_direction(all_dirs[i]).to_vec();
|
||||
|
@ -529,24 +616,24 @@ impl Factory {
|
|||
let oy2 = uy2;
|
||||
match face.rotation {
|
||||
270 => {
|
||||
uy1 = tw*16 - ox2;
|
||||
uy2 = tw*16 - ox1;
|
||||
uy1 = tw * 16 - ox2;
|
||||
uy2 = tw * 16 - ox1;
|
||||
ux1 = oy1;
|
||||
ux2 = oy2;
|
||||
},
|
||||
}
|
||||
180 => {
|
||||
uy1 = th*16 - oy2;
|
||||
uy2 = th*16 - oy1;
|
||||
ux1 = tw*16 - ox2;
|
||||
ux2 = tw*16 - ox1;
|
||||
},
|
||||
uy1 = th * 16 - oy2;
|
||||
uy2 = th * 16 - oy1;
|
||||
ux1 = tw * 16 - ox2;
|
||||
ux2 = tw * 16 - ox1;
|
||||
}
|
||||
90 => {
|
||||
uy1 = ox1;
|
||||
uy2 = ox2;
|
||||
ux1 = th*16 - oy2;
|
||||
ux2 = th*16 - oy1;
|
||||
},
|
||||
_ => {},
|
||||
ux1 = th * 16 - oy2;
|
||||
ux2 = th * 16 - oy1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -589,40 +676,40 @@ impl Factory {
|
|||
let s = angle.sin();
|
||||
let x = v.x;
|
||||
let z = v.z;
|
||||
v.x = x*c - z*s;
|
||||
v.z = z*c + x*s;
|
||||
v.x = x * c - z * s;
|
||||
v.z = z * c + x * s;
|
||||
|
||||
if r.rescale {
|
||||
v.x *= ci;
|
||||
v.z *= ci;
|
||||
}
|
||||
},
|
||||
}
|
||||
"x" => {
|
||||
let c = angle.cos();
|
||||
let s = angle.sin();
|
||||
let z = v.z;
|
||||
let y = v.y;
|
||||
v.z = z*c - y*s;
|
||||
v.y = y*c + z*s;
|
||||
v.z = z * c - y * s;
|
||||
v.y = y * c + z * s;
|
||||
|
||||
if r.rescale {
|
||||
v.z *= ci;
|
||||
v.y *= ci;
|
||||
}
|
||||
},
|
||||
}
|
||||
"z" => {
|
||||
let c = angle.cos();
|
||||
let s = angle.sin();
|
||||
let x = v.x;
|
||||
let y = v.y;
|
||||
v.x = x*c - y*s;
|
||||
v.y = y*c + x*s;
|
||||
v.x = x * c - y * s;
|
||||
v.y = y * c + x * s;
|
||||
|
||||
if r.rescale {
|
||||
v.x *= ci;
|
||||
v.y *= ci;
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
v.x += (r.origin[0] / 16.0) as f32;
|
||||
|
@ -636,8 +723,8 @@ impl Factory {
|
|||
let s = rot_x.sin();
|
||||
let z = v.z - 0.5;
|
||||
let y = v.y - 0.5;
|
||||
v.z = 0.5 + (z*c - y*s);
|
||||
v.y = 0.5 + (y*c + z*s);
|
||||
v.z = 0.5 + (z * c - y * s);
|
||||
v.y = 0.5 + (y * c + z * s);
|
||||
}
|
||||
|
||||
if raw.y > 0.0 {
|
||||
|
@ -646,8 +733,8 @@ impl Factory {
|
|||
let s = rot_y.sin();
|
||||
let x = v.x - 0.5;
|
||||
let z = v.z - 0.5;
|
||||
v.x = 0.5 + (x*c - z*s);
|
||||
v.z = 0.5 + (z*c + x*s);
|
||||
v.x = 0.5 + (x * c - z * s);
|
||||
v.z = 0.5 + (z * c + x * s);
|
||||
}
|
||||
|
||||
if v.toffsetx == 0 {
|
||||
|
@ -663,35 +750,42 @@ impl Factory {
|
|||
}
|
||||
|
||||
if face.rotation > 0 {
|
||||
let rot_y = (-face.rotation as f64 * (::std::f64::consts::PI / 180.0)) as f32;
|
||||
let rot_y =
|
||||
(-face.rotation as f64 * (::std::f64::consts::PI / 180.0)) as f32;
|
||||
let c = rot_y.cos() as i16;
|
||||
let s = rot_y.sin() as i16;
|
||||
let x = v.toffsetx - 8*tw;
|
||||
let y = v.toffsety - 8*th;
|
||||
v.toffsetx = 8*tw + (x*c - y*s);
|
||||
v.toffsety = 8*th + (y*c + x*s);
|
||||
let x = v.toffsetx - 8 * tw;
|
||||
let y = v.toffsety - 8 * th;
|
||||
v.toffsetx = 8 * tw + (x * c - y * s);
|
||||
v.toffsety = 8 * th + (y * c + x * s);
|
||||
}
|
||||
|
||||
if raw.uvlock && raw.y > 0.0
|
||||
&& (processed_face.facing == Direction::Up || processed_face.facing == Direction::Down) {
|
||||
if raw.uvlock
|
||||
&& raw.y > 0.0
|
||||
&& (processed_face.facing == Direction::Up
|
||||
|| processed_face.facing == Direction::Down)
|
||||
{
|
||||
let rot_y = (raw.y * (::std::f64::consts::PI / 180.0)) as f32;
|
||||
let c = rot_y.cos() as i16;
|
||||
let s = rot_y.sin() as i16;
|
||||
let x = v.toffsetx - 8*tw;
|
||||
let y = v.toffsety - 8*th;
|
||||
v.toffsetx = 8*tw + (x*c - y*s);
|
||||
v.toffsety = 8*th + (y*c + x*s);
|
||||
let x = v.toffsetx - 8 * tw;
|
||||
let y = v.toffsety - 8 * th;
|
||||
v.toffsetx = 8 * tw + (x * c - y * s);
|
||||
v.toffsety = 8 * th + (y * c + x * s);
|
||||
}
|
||||
|
||||
if raw.uvlock && raw.x > 0.0
|
||||
&& (processed_face.facing != Direction::Up && processed_face.facing != Direction::Down) {
|
||||
if raw.uvlock
|
||||
&& raw.x > 0.0
|
||||
&& (processed_face.facing != Direction::Up
|
||||
&& processed_face.facing != Direction::Down)
|
||||
{
|
||||
let rot_x = (raw.x * (::std::f64::consts::PI / 180.0)) as f32;
|
||||
let c = rot_x.cos() as i16;
|
||||
let s = rot_x.sin() as i16;
|
||||
let x = v.toffsetx - 8*tw;
|
||||
let y = v.toffsety - 8*th;
|
||||
v.toffsetx = 8*tw + (x*c - y*s);
|
||||
v.toffsety = 8*th + (y*c + x*s);
|
||||
let x = v.toffsetx - 8 * tw;
|
||||
let y = v.toffsety - 8 * th;
|
||||
v.toffsetx = 8 * tw + (x * c - y * s);
|
||||
v.toffsety = 8 * th + (y * c + x * s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -719,15 +813,18 @@ const FACE_ROTATION_X: &[Direction] = &[
|
|||
Direction::Up,
|
||||
];
|
||||
|
||||
fn rotate_direction(val: Direction, offset: i32, rots: &[Direction], invalid: &[Direction]) -> Direction {
|
||||
fn rotate_direction(
|
||||
val: Direction,
|
||||
offset: i32,
|
||||
rots: &[Direction],
|
||||
invalid: &[Direction],
|
||||
) -> Direction {
|
||||
for d in invalid {
|
||||
if *d == val {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
let pos = rots.iter()
|
||||
.position(|v| *v == val)
|
||||
.unwrap_or(0) as i32;
|
||||
let pos = rots.iter().position(|v| *v == val).unwrap_or(0) as i32;
|
||||
rots[(rots.len() as i32 + pos + offset) as usize % rots.len()]
|
||||
}
|
||||
|
||||
|
@ -763,7 +860,7 @@ pub struct Variants {
|
|||
impl Variants {
|
||||
fn choose_model<R: Rng>(&self, rng: &mut R) -> &Model {
|
||||
// TODO: Weighted random
|
||||
rng.choose(&self.models).unwrap()
|
||||
self.models.choose(rng).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -773,7 +870,7 @@ enum BuiltinType {
|
|||
Generated,
|
||||
Entity,
|
||||
Compass,
|
||||
Clock
|
||||
Clock,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -795,7 +892,11 @@ struct RawModel {
|
|||
impl RawModel {
|
||||
fn lookup_texture(&self, name: &str) -> String {
|
||||
if !name.is_empty() && name.starts_with('#') {
|
||||
let tex = self.texture_vars.get(&name[1..]).cloned().unwrap_or("".to_owned());
|
||||
let tex = self
|
||||
.texture_vars
|
||||
.get(&name[1..])
|
||||
.cloned()
|
||||
.unwrap_or("".to_owned());
|
||||
return self.lookup_texture(&tex);
|
||||
}
|
||||
name.to_owned()
|
||||
|
@ -858,7 +959,15 @@ impl Model {
|
|||
self.faces.extend_from_slice(&other.faces);
|
||||
}
|
||||
|
||||
fn render<W: Write>(&self, factory: &Factory, snapshot: &world::Snapshot, x: i32, y: i32, z: i32, buf: &mut W) -> usize {
|
||||
fn render<W: Write>(
|
||||
&self,
|
||||
factory: &Factory,
|
||||
snapshot: &world::Snapshot,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
buf: &mut W,
|
||||
) -> usize {
|
||||
let this = snapshot.get_block(x, y, z);
|
||||
let this_mat = this.get_material();
|
||||
let mut indices = 0;
|
||||
|
@ -885,9 +994,19 @@ impl Model {
|
|||
let (mut cr, mut cg, mut cb) = if face.tint_index == 0 {
|
||||
match tint {
|
||||
TintType::Default => (255, 255, 255),
|
||||
TintType::Color{r, g, b} => (r, g, b),
|
||||
TintType::Grass => calculate_biome(snapshot, vert.x as i32, vert.z as i32, &factory.grass_colors),
|
||||
TintType::Foliage => calculate_biome(snapshot, vert.x as i32, vert.z as i32, &factory.foliage_colors),
|
||||
TintType::Color { r, g, b } => (r, g, b),
|
||||
TintType::Grass => calculate_biome(
|
||||
snapshot,
|
||||
vert.x as i32,
|
||||
vert.z as i32,
|
||||
&factory.grass_colors,
|
||||
),
|
||||
TintType::Foliage => calculate_biome(
|
||||
snapshot,
|
||||
vert.x as i32,
|
||||
vert.z as i32,
|
||||
&factory.foliage_colors,
|
||||
),
|
||||
}
|
||||
} else {
|
||||
(255, 255, 255)
|
||||
|
@ -904,13 +1023,15 @@ impl Model {
|
|||
|
||||
let (bl, sl) = calculate_light(
|
||||
snapshot,
|
||||
x, y, z,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
vert.x as f64,
|
||||
vert.y as f64,
|
||||
vert.z as f64,
|
||||
face.facing,
|
||||
self.ambient_occlusion,
|
||||
this_mat.force_shade
|
||||
this_mat.force_shade,
|
||||
);
|
||||
vert.block_light = bl;
|
||||
vert.sky_light = sl;
|
||||
|
@ -921,15 +1042,20 @@ impl Model {
|
|||
}
|
||||
}
|
||||
|
||||
fn calculate_biome(snapshot: &world::Snapshot, x: i32, z: i32, img: &image::DynamicImage) -> (u8, u8, u8) {
|
||||
use std::cmp::{min, max};
|
||||
fn calculate_biome(
|
||||
snapshot: &world::Snapshot,
|
||||
x: i32,
|
||||
z: i32,
|
||||
img: &image::DynamicImage,
|
||||
) -> (u8, u8, u8) {
|
||||
use std::cmp::{max, min};
|
||||
let mut count = 0;
|
||||
let mut r = 0;
|
||||
let mut g = 0;
|
||||
let mut b = 0;
|
||||
for xx in -1 .. 2 {
|
||||
for zz in -1 .. 2 {
|
||||
let bi = snapshot.get_biome(x+xx, z+zz);
|
||||
for xx in -1..2 {
|
||||
for zz in -1..2 {
|
||||
let bi = snapshot.get_biome(x + xx, z + zz);
|
||||
let color_index = bi.get_color_index();
|
||||
let ix = color_index & 0xFF;
|
||||
let iy = color_index >> 8;
|
||||
|
@ -939,19 +1065,29 @@ fn calculate_biome(snapshot: &world::Snapshot, x: i32, z: i32, img: &image::Dyna
|
|||
|
||||
let col = img.get_pixel(ix as u32, iy as u32);
|
||||
let col = bi.process_color(col);
|
||||
r += col.data[0] as u32;
|
||||
g += col.data[1] as u32;
|
||||
b += col.data[2] as u32;
|
||||
r += col.0[0] as u32;
|
||||
g += col.0[1] as u32;
|
||||
b += col.0[2] as u32;
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
((r/count) as u8, (g/count) as u8, (b/count) as u8)
|
||||
((r / count) as u8, (g / count) as u8, (b / count) as u8)
|
||||
}
|
||||
|
||||
fn calculate_light(snapshot: &world::Snapshot, orig_x: i32, orig_y: i32, orig_z: i32,
|
||||
x: f64, y: f64, z: f64, face: Direction, smooth: bool, force: bool) -> (u16, u16) {
|
||||
use std::cmp::max;
|
||||
fn calculate_light(
|
||||
snapshot: &world::Snapshot,
|
||||
orig_x: i32,
|
||||
orig_y: i32,
|
||||
orig_z: i32,
|
||||
x: f64,
|
||||
y: f64,
|
||||
z: f64,
|
||||
face: Direction,
|
||||
smooth: bool,
|
||||
force: bool,
|
||||
) -> (u16, u16) {
|
||||
use crate::world::block;
|
||||
use std::cmp::max;
|
||||
let (ox, oy, oz) = face.get_offset();
|
||||
|
||||
let s_block_light = snapshot.get_block_light(orig_x + ox, orig_y + oy, orig_z + oz);
|
||||
|
@ -971,16 +1107,21 @@ fn calculate_light(snapshot: &world::Snapshot, orig_x: i32, orig_y: i32, orig_z:
|
|||
let dy = (oy as f64) * 0.6;
|
||||
let dz = (oz as f64) * 0.6;
|
||||
|
||||
for ox in [-0.6, 0.0].into_iter() {
|
||||
for oy in [-0.6, 0.0].into_iter() {
|
||||
for oz in [-0.6, 0.0].into_iter() {
|
||||
for ox in [-0.6, 0.0].iter() {
|
||||
for oy in [-0.6, 0.0].iter() {
|
||||
for oz in [-0.6, 0.0].iter() {
|
||||
let lx = (x + ox + dx).round() as i32;
|
||||
let ly = (y + oy + dy).round() as i32;
|
||||
let lz = (z + oz + dz).round() as i32;
|
||||
let mut bl = snapshot.get_block_light(lx, ly, lz);
|
||||
let mut sl = snapshot.get_sky_light(lx, ly, lz);
|
||||
if (force && match snapshot.get_block(lx, ly, lz) { block::Air{} => false, _ => true })
|
||||
|| (sl == 0 && bl == 0){
|
||||
if (force
|
||||
&& match snapshot.get_block(lx, ly, lz) {
|
||||
block::Air {} => false,
|
||||
_ => true,
|
||||
})
|
||||
|| (sl == 0 && bl == 0)
|
||||
{
|
||||
bl = s_block_light;
|
||||
sl = s_sky_light;
|
||||
}
|
||||
|
@ -991,43 +1132,50 @@ fn calculate_light(snapshot: &world::Snapshot, orig_x: i32, orig_y: i32, orig_z:
|
|||
}
|
||||
}
|
||||
|
||||
((((block_light * 4000) / count) as u16), (((sky_light * 4000) / count) as u16))
|
||||
(
|
||||
(((block_light * 4000) / count) as u16),
|
||||
(((sky_light * 4000) / count) as u16),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub const PRECOMPUTED_VERTS: [&[BlockVertex; 4]; 6] = [
|
||||
&[ // Up
|
||||
&[
|
||||
// Up
|
||||
BlockVertex::base(0.0, 1.0, 0.0, 0, 0),
|
||||
BlockVertex::base(1.0, 1.0, 0.0, 1, 0),
|
||||
BlockVertex::base(0.0, 1.0, 1.0, 0, 1),
|
||||
BlockVertex::base(1.0, 1.0, 1.0, 1, 1),
|
||||
],
|
||||
&[ // Down
|
||||
&[
|
||||
// Down
|
||||
BlockVertex::base(0.0, 0.0, 0.0, 0, 1),
|
||||
BlockVertex::base(0.0, 0.0, 1.0, 0, 0),
|
||||
BlockVertex::base(1.0, 0.0, 0.0, 1, 1),
|
||||
BlockVertex::base(1.0, 0.0, 1.0, 1, 0),
|
||||
],
|
||||
&[ // North
|
||||
&[
|
||||
// North
|
||||
BlockVertex::base(0.0, 0.0, 0.0, 1, 1),
|
||||
BlockVertex::base(1.0, 0.0, 0.0, 0, 1),
|
||||
BlockVertex::base(0.0, 1.0, 0.0, 1, 0),
|
||||
BlockVertex::base(1.0, 1.0, 0.0, 0, 0),
|
||||
],
|
||||
&[ // South
|
||||
&[
|
||||
// South
|
||||
BlockVertex::base(0.0, 0.0, 1.0, 0, 1),
|
||||
BlockVertex::base(0.0, 1.0, 1.0, 0, 0),
|
||||
BlockVertex::base(1.0, 0.0, 1.0, 1, 1),
|
||||
BlockVertex::base(1.0, 1.0, 1.0, 1, 0),
|
||||
],
|
||||
&[ // West
|
||||
&[
|
||||
// West
|
||||
BlockVertex::base(0.0, 0.0, 0.0, 0, 1),
|
||||
BlockVertex::base(0.0, 1.0, 0.0, 0, 0),
|
||||
BlockVertex::base(0.0, 0.0, 1.0, 1, 1),
|
||||
BlockVertex::base(0.0, 1.0, 1.0, 1, 0),
|
||||
],
|
||||
&[ // East
|
||||
&[
|
||||
// East
|
||||
BlockVertex::base(1.0, 0.0, 0.0, 1, 1),
|
||||
BlockVertex::base(1.0, 0.0, 1.0, 0, 1),
|
||||
BlockVertex::base(1.0, 1.0, 0.0, 1, 0),
|
||||
|
@ -1057,11 +1205,21 @@ pub struct BlockVertex {
|
|||
impl BlockVertex {
|
||||
const fn base(x: f32, y: f32, z: f32, tx: i16, ty: i16) -> BlockVertex {
|
||||
BlockVertex {
|
||||
x, y, z,
|
||||
tx: 0, ty: 0, tw: 0, th: 0,
|
||||
toffsetx: tx, toffsety: ty, tatlas: 0,
|
||||
r: 0, g: 0, b: 0,
|
||||
block_light: 0, sky_light: 0,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
tx: 0,
|
||||
ty: 0,
|
||||
tw: 0,
|
||||
th: 0,
|
||||
toffsetx: tx,
|
||||
toffsety: ty,
|
||||
tatlas: 0,
|
||||
r: 0,
|
||||
g: 0,
|
||||
b: 0,
|
||||
block_light: 0,
|
||||
sky_light: 0,
|
||||
}
|
||||
}
|
||||
pub fn write<W: Write>(&self, w: &mut W) {
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
use crate::protocol::*;
|
||||
|
||||
mod v19w02a;
|
||||
mod v18w50a;
|
||||
mod v1_13_2;
|
||||
mod v1_12_2;
|
||||
mod v1_11_2;
|
||||
mod v1_10_2;
|
||||
mod v1_9_2;
|
||||
mod v1_9;
|
||||
mod v15w39c;
|
||||
mod v1_8_9;
|
||||
mod v1_7_10;
|
||||
|
||||
pub fn translate_internal_packet_id_for_version(version: i32, state: State, dir: Direction, id: i32, to_internal: bool) -> i32 {
|
||||
match version {
|
||||
// https://wiki.vg/Protocol_History
|
||||
// https://wiki.vg/Protocol_version_numbers#Versions_after_the_Netty_rewrite
|
||||
|
||||
// 19w02a
|
||||
452 => v19w02a::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
||||
// 18w50a
|
||||
451 => v18w50a::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
||||
// 1.13.2
|
||||
404 => v1_13_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
||||
// 1.12.2
|
||||
340 => v1_12_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
||||
// 1.11.2
|
||||
316 => v1_11_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
||||
// 1.11
|
||||
315 => v1_11_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
||||
// 1.10.2
|
||||
210 => v1_10_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
||||
// 1.9.2
|
||||
109 => v1_9_2::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
||||
// 1.9
|
||||
107 => v1_9::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
||||
// 15w39a/b/c
|
||||
74 => v15w39c::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
||||
// 1.8.9 - 1.8
|
||||
47 => v1_8_9::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
||||
// 1.7.10 - 1.7.6
|
||||
5 => v1_7_10::translate_internal_packet_id(state, dir, id, to_internal),
|
||||
|
||||
_ => panic!("unsupported protocol version"),
|
||||
}
|
||||
}
|
|
@ -26,7 +26,9 @@ pub struct Rect {
|
|||
|
||||
impl Atlas {
|
||||
pub fn new(width: usize, height: usize) -> Atlas {
|
||||
let mut a = Atlas { free_space: Vec::new() };
|
||||
let mut a = Atlas {
|
||||
free_space: Vec::new(),
|
||||
};
|
||||
a.free_space.push(Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
@ -78,13 +80,15 @@ impl Atlas {
|
|||
} else {
|
||||
if t.height > height {
|
||||
// Split by height
|
||||
self.free_space.insert(0,
|
||||
Rect {
|
||||
x: t.x,
|
||||
y: t.y + height,
|
||||
width,
|
||||
height: t.height - height,
|
||||
});
|
||||
self.free_space.insert(
|
||||
0,
|
||||
Rect {
|
||||
x: t.x,
|
||||
y: t.y + height,
|
||||
width,
|
||||
height: t.height - height,
|
||||
},
|
||||
);
|
||||
target_index += 1;
|
||||
}
|
||||
t.x += width;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use cgmath::{Point3, Matrix4};
|
||||
use byteorder::{WriteBytesExt, NativeEndian};
|
||||
use crate::gl;
|
||||
use super::glsl;
|
||||
use crate::gl;
|
||||
use byteorder::{NativeEndian, WriteBytesExt};
|
||||
use cgmath::{Matrix4, Point3};
|
||||
use log::error;
|
||||
|
||||
pub struct Clouds {
|
||||
program: gl::Program,
|
||||
|
@ -47,13 +47,13 @@ impl Clouds {
|
|||
v.compile();
|
||||
|
||||
if v.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
println!("Src: {}", vertex);
|
||||
error!("Src: {}", vertex);
|
||||
panic!("Shader error: {}", v.get_info_log());
|
||||
} else {
|
||||
let log = v.get_info_log();
|
||||
let log = log.trim().trim_matches('\u{0}');
|
||||
if !log.is_empty() {
|
||||
println!("{}", log);
|
||||
error!("{}", log);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,13 +62,13 @@ impl Clouds {
|
|||
g.compile();
|
||||
|
||||
if g.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
println!("Src: {}", geo);
|
||||
error!("Src: {}", geo);
|
||||
panic!("Shader error: {}", g.get_info_log());
|
||||
} else {
|
||||
let log = g.get_info_log();
|
||||
let log = log.trim().trim_matches('\u{0}');
|
||||
if !log.is_empty() {
|
||||
println!("{}", log);
|
||||
error!("{}", log);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,13 +77,13 @@ impl Clouds {
|
|||
f.compile();
|
||||
|
||||
if f.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
println!("Src: {}", fragment);
|
||||
error!("Src: {}", fragment);
|
||||
panic!("Shader error: {}", f.get_info_log());
|
||||
} else {
|
||||
let log = f.get_info_log();
|
||||
let log = log.trim().trim_matches('\u{0}');
|
||||
if !log.is_empty() {
|
||||
println!("{}", log);
|
||||
error!("{}", log);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,8 +114,8 @@ impl Clouds {
|
|||
|
||||
let mut data = vec![];
|
||||
let mut num_points = 0;
|
||||
for x in -160 .. 160 {
|
||||
for z in -160 .. 160 {
|
||||
for x in -160..160 {
|
||||
for z in -160..160 {
|
||||
let _ = data.write_f32::<NativeEndian>(x as f32);
|
||||
let _ = data.write_f32::<NativeEndian>(128.0);
|
||||
let _ = data.write_f32::<NativeEndian>(z as f32);
|
||||
|
@ -125,11 +125,19 @@ impl Clouds {
|
|||
|
||||
buffer.set_data(gl::ARRAY_BUFFER, &data, gl::STATIC_DRAW);
|
||||
|
||||
let heightmap_data = vec![0; 512*512];
|
||||
let heightmap_data = vec![0; 512 * 512];
|
||||
|
||||
let texture = gl::Texture::new();
|
||||
texture.bind(gl::TEXTURE_2D);
|
||||
texture.image_2d(gl::TEXTURE_2D, 0, 512, 512, gl::RED, gl::UNSIGNED_BYTE, Some(&heightmap_data));
|
||||
texture.image_2d(
|
||||
gl::TEXTURE_2D,
|
||||
0,
|
||||
512,
|
||||
512,
|
||||
gl::RED,
|
||||
gl::UNSIGNED_BYTE,
|
||||
Some(&heightmap_data),
|
||||
);
|
||||
texture.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST);
|
||||
texture.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
|
||||
|
||||
|
@ -162,7 +170,15 @@ impl Clouds {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, camera_pos: &Point3<f64>, perspective_matrix: &Matrix4<f32>, camera_matrix: &Matrix4<f32>, light_level: f32, sky_offset: f32, delta: f64) {
|
||||
pub fn draw(
|
||||
&mut self,
|
||||
camera_pos: &Point3<f64>,
|
||||
perspective_matrix: &Matrix4<f32>,
|
||||
camera_matrix: &Matrix4<f32>,
|
||||
light_level: f32,
|
||||
sky_offset: f32,
|
||||
delta: f64,
|
||||
) {
|
||||
self.offset += delta;
|
||||
|
||||
let tex = super::Renderer::get_texture(&self.textures, "steven:environment/clouds");
|
||||
|
@ -172,12 +188,16 @@ impl Clouds {
|
|||
self.u_camera_matrix.set_matrix4(camera_matrix);
|
||||
self.u_sky_offset.set_float(sky_offset);
|
||||
self.u_light_level.set_float(light_level);
|
||||
self.u_offset.set_float3(camera_pos.x.floor() as f32, 0.0, camera_pos.z.floor() as f32);
|
||||
self.u_offset.set_float3(
|
||||
camera_pos.x.floor() as f32,
|
||||
0.0,
|
||||
camera_pos.z.floor() as f32,
|
||||
);
|
||||
self.u_texture_info.set_float4(
|
||||
tex.get_x() as f32,
|
||||
tex.get_y() as f32,
|
||||
tex.get_width() as f32,
|
||||
tex.get_height() as f32
|
||||
tex.get_height() as f32,
|
||||
);
|
||||
self.u_atlas.set_float(tex.atlas as f32);
|
||||
self.u_cloud_offset.set_float((self.offset / 60.0) as f32);
|
||||
|
@ -186,7 +206,17 @@ impl Clouds {
|
|||
gl::active_texture(1);
|
||||
self.texture.bind(gl::TEXTURE_2D);
|
||||
if self.dirty {
|
||||
self.texture.sub_image_2d(gl::TEXTURE_2D, 0, 0, 0, 512, 512, gl::RED, gl::UNSIGNED_BYTE, &self.heightmap_data);
|
||||
self.texture.sub_image_2d(
|
||||
gl::TEXTURE_2D,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
512,
|
||||
512,
|
||||
gl::RED,
|
||||
gl::UNSIGNED_BYTE,
|
||||
&self.heightmap_data,
|
||||
);
|
||||
self.dirty = false;
|
||||
}
|
||||
self.u_cloud_map.set_int(1);
|
||||
|
|
|
@ -20,13 +20,16 @@ pub struct Registry {
|
|||
}
|
||||
|
||||
impl Registry {
|
||||
pub fn new() -> Registry { Default::default() }
|
||||
pub fn new() -> Registry {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn register(&mut self, name: &str, source: &str) {
|
||||
if self.shaders.contains_key(name) {
|
||||
panic!("shader {} is already defined", name);
|
||||
}
|
||||
self.shaders.insert(name.to_owned(), source.trim().to_owned());
|
||||
self.shaders
|
||||
.insert(name.to_owned(), source.trim().to_owned());
|
||||
}
|
||||
|
||||
pub fn get(&self, name: &str) -> String {
|
||||
|
|
|
@ -16,29 +16,32 @@ mod atlas;
|
|||
pub mod glsl;
|
||||
#[macro_use]
|
||||
pub mod shaders;
|
||||
pub mod ui;
|
||||
pub mod model;
|
||||
pub mod clouds;
|
||||
pub mod model;
|
||||
pub mod ui;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::io::Write;
|
||||
use crate::resources;
|
||||
use crate::gl;
|
||||
use crate::resources;
|
||||
use crate::world;
|
||||
use byteorder::{NativeEndian, WriteBytesExt};
|
||||
use cgmath::prelude::*;
|
||||
use collision;
|
||||
use image;
|
||||
use image::{GenericImage, GenericImageView};
|
||||
use byteorder::{WriteBytesExt, NativeEndian};
|
||||
use serde_json;
|
||||
use cgmath::prelude::*;
|
||||
use crate::world;
|
||||
use collision;
|
||||
use log::{error, trace};
|
||||
use serde_json;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use std::hash::BuildHasherDefault;
|
||||
use crate::types::hash::FNVHash;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use reqwest;
|
||||
|
||||
const ATLAS_SIZE: usize = 1024;
|
||||
|
||||
|
@ -97,7 +100,9 @@ pub struct ChunkBuffer {
|
|||
}
|
||||
|
||||
impl ChunkBuffer {
|
||||
pub fn new() -> ChunkBuffer { Default::default() }
|
||||
pub fn new() -> ChunkBuffer {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
struct ChunkRenderInfo {
|
||||
|
@ -153,19 +158,19 @@ init_shader! {
|
|||
|
||||
impl Renderer {
|
||||
pub fn new(res: Arc<RwLock<resources::Manager>>) -> Renderer {
|
||||
let version = {
|
||||
res.read().unwrap().version()
|
||||
};
|
||||
let version = { res.read().unwrap().version() };
|
||||
let tex = gl::Texture::new();
|
||||
tex.bind(gl::TEXTURE_2D_ARRAY);
|
||||
tex.image_3d(gl::TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
ATLAS_SIZE as u32,
|
||||
ATLAS_SIZE as u32,
|
||||
1,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
&[0; ATLAS_SIZE * ATLAS_SIZE * 4]);
|
||||
tex.image_3d(
|
||||
gl::TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
ATLAS_SIZE as u32,
|
||||
ATLAS_SIZE as u32,
|
||||
1,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
&[0; ATLAS_SIZE * ATLAS_SIZE * 4],
|
||||
);
|
||||
tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
|
||||
tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MIN_FILTER, gl::NEAREST);
|
||||
tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
|
||||
|
@ -245,9 +250,13 @@ impl Renderer {
|
|||
if rm.version() != self.resource_version {
|
||||
self.resource_version = rm.version();
|
||||
trace!("Updating textures to {}", self.resource_version);
|
||||
self.textures.write().unwrap().update_textures(self.resource_version);
|
||||
self.textures
|
||||
.write()
|
||||
.unwrap()
|
||||
.update_textures(self.resource_version);
|
||||
|
||||
self.model.rebuild_models(self.resource_version, &self.textures);
|
||||
self.model
|
||||
.rebuild_models(self.resource_version, &self.textures);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,34 +265,50 @@ impl Renderer {
|
|||
self.height = height;
|
||||
gl::viewport(0, 0, width as i32, height as i32);
|
||||
|
||||
self.perspective_matrix = cgmath::Matrix4::from(
|
||||
cgmath::PerspectiveFov {
|
||||
fovy: cgmath::Rad::from(cgmath::Deg(90f32)),
|
||||
aspect: (width as f32 / height as f32),
|
||||
near: 0.1f32,
|
||||
far: 500.0f32,
|
||||
}
|
||||
);
|
||||
let fovy = cgmath::Rad::from(cgmath::Deg(90.0_f32));
|
||||
let aspect = (width as f32 / height as f32).max(1.0);
|
||||
|
||||
self.perspective_matrix = cgmath::Matrix4::from(cgmath::PerspectiveFov {
|
||||
fovy,
|
||||
aspect,
|
||||
near: 0.1f32,
|
||||
far: 500.0f32,
|
||||
});
|
||||
|
||||
self.init_trans(width, height);
|
||||
}
|
||||
|
||||
self.view_vector = cgmath::Vector3::new(
|
||||
((self.camera.yaw - PI64/2.0).cos() * -self.camera.pitch.cos()) as f32,
|
||||
((self.camera.yaw - PI64 / 2.0).cos() * -self.camera.pitch.cos()) as f32,
|
||||
(-self.camera.pitch.sin()) as f32,
|
||||
(-(self.camera.yaw - PI64/2.0).sin() * -self.camera.pitch.cos()) as f32
|
||||
(-(self.camera.yaw - PI64 / 2.0).sin() * -self.camera.pitch.cos()) as f32,
|
||||
);
|
||||
let camera = cgmath::Point3::new(
|
||||
-self.camera.pos.x as f32,
|
||||
-self.camera.pos.y as f32,
|
||||
self.camera.pos.z as f32,
|
||||
);
|
||||
let camera = cgmath::Point3::new(-self.camera.pos.x as f32, -self.camera.pos.y as f32, self.camera.pos.z as f32);
|
||||
let camera_matrix = cgmath::Matrix4::look_at(
|
||||
camera,
|
||||
camera + cgmath::Point3::new(-self.view_vector.x, -self.view_vector.y, self.view_vector.z).to_vec(),
|
||||
cgmath::Vector3::new(0.0, -1.0, 0.0)
|
||||
camera
|
||||
+ cgmath::Point3::new(-self.view_vector.x, -self.view_vector.y, self.view_vector.z)
|
||||
.to_vec(),
|
||||
cgmath::Vector3::new(0.0, -1.0, 0.0),
|
||||
);
|
||||
self.camera_matrix = camera_matrix * cgmath::Matrix4::from_nonuniform_scale(-1.0, 1.0, 1.0);
|
||||
self.frustum = collision::Frustum::from_matrix4(self.perspective_matrix * self.camera_matrix).unwrap();
|
||||
self.frustum =
|
||||
collision::Frustum::from_matrix4(self.perspective_matrix * self.camera_matrix).unwrap();
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, world: &mut world::World, delta: f64, width: u32, height: u32, physical_width: u32, physical_height: u32) {
|
||||
pub fn tick(
|
||||
&mut self,
|
||||
world: &mut world::World,
|
||||
delta: f64,
|
||||
width: u32,
|
||||
height: u32,
|
||||
physical_width: u32,
|
||||
physical_height: u32,
|
||||
) {
|
||||
self.update_textures(delta);
|
||||
|
||||
let trans = self.trans.as_mut().unwrap();
|
||||
|
@ -296,18 +321,22 @@ impl Renderer {
|
|||
|
||||
let time_offset = self.sky_offset * 0.9;
|
||||
gl::clear_color(
|
||||
(122.0 / 255.0) * time_offset,
|
||||
(165.0 / 255.0) * time_offset,
|
||||
(247.0 / 255.0) * time_offset,
|
||||
1.0
|
||||
(122.0 / 255.0) * time_offset,
|
||||
(165.0 / 255.0) * time_offset,
|
||||
(247.0 / 255.0) * time_offset,
|
||||
1.0,
|
||||
);
|
||||
gl::clear(gl::ClearFlags::Color | gl::ClearFlags::Depth);
|
||||
|
||||
// Chunk rendering
|
||||
self.chunk_shader.program.use_program();
|
||||
|
||||
self.chunk_shader.perspective_matrix.set_matrix4(&self.perspective_matrix);
|
||||
self.chunk_shader.camera_matrix.set_matrix4(&self.camera_matrix);
|
||||
self.chunk_shader
|
||||
.perspective_matrix
|
||||
.set_matrix4(&self.perspective_matrix);
|
||||
self.chunk_shader
|
||||
.camera_matrix
|
||||
.set_matrix4(&self.camera_matrix);
|
||||
self.chunk_shader.texture.set_int(0);
|
||||
self.chunk_shader.light_level.set_float(self.light_level);
|
||||
self.chunk_shader.sky_offset.set_float(self.sky_offset);
|
||||
|
@ -315,36 +344,71 @@ impl Renderer {
|
|||
for (pos, info) in world.get_render_list() {
|
||||
if let Some(solid) = info.solid.as_ref() {
|
||||
if solid.count > 0 {
|
||||
self.chunk_shader.offset.set_int3(pos.0, pos.1 * 4096, pos.2);
|
||||
self.chunk_shader
|
||||
.offset
|
||||
.set_int3(pos.0, pos.1 * 4096, pos.2);
|
||||
solid.array.bind();
|
||||
gl::draw_elements(gl::TRIANGLES, solid.count as i32, self.element_buffer_type, 0);
|
||||
gl::draw_elements(
|
||||
gl::TRIANGLES,
|
||||
solid.count as i32,
|
||||
self.element_buffer_type,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Line rendering
|
||||
// Model rendering
|
||||
self.model.draw(&self.frustum, &self.perspective_matrix, &self.camera_matrix, self.light_level, self.sky_offset);
|
||||
self.model.draw(
|
||||
&self.frustum,
|
||||
&self.perspective_matrix,
|
||||
&self.camera_matrix,
|
||||
self.light_level,
|
||||
self.sky_offset,
|
||||
);
|
||||
if world.copy_cloud_heightmap(&mut self.clouds.heightmap_data) {
|
||||
self.clouds.dirty = true;
|
||||
}
|
||||
self.clouds.draw(&self.camera.pos, &self.perspective_matrix, &self.camera_matrix, self.light_level, self.sky_offset, delta);
|
||||
self.clouds.draw(
|
||||
&self.camera.pos,
|
||||
&self.perspective_matrix,
|
||||
&self.camera_matrix,
|
||||
self.light_level,
|
||||
self.sky_offset,
|
||||
delta,
|
||||
);
|
||||
|
||||
// Trans chunk rendering
|
||||
self.chunk_shader_alpha.program.use_program();
|
||||
self.chunk_shader_alpha.perspective_matrix.set_matrix4(&self.perspective_matrix);
|
||||
self.chunk_shader_alpha.camera_matrix.set_matrix4(&self.camera_matrix);
|
||||
self.chunk_shader_alpha
|
||||
.perspective_matrix
|
||||
.set_matrix4(&self.perspective_matrix);
|
||||
self.chunk_shader_alpha
|
||||
.camera_matrix
|
||||
.set_matrix4(&self.camera_matrix);
|
||||
self.chunk_shader_alpha.texture.set_int(0);
|
||||
self.chunk_shader_alpha.light_level.set_float(self.light_level);
|
||||
self.chunk_shader_alpha.sky_offset.set_float(self.sky_offset);
|
||||
self.chunk_shader_alpha
|
||||
.light_level
|
||||
.set_float(self.light_level);
|
||||
self.chunk_shader_alpha
|
||||
.sky_offset
|
||||
.set_float(self.sky_offset);
|
||||
|
||||
// Copy the depth buffer
|
||||
trans.main.bind_read();
|
||||
trans.trans.bind_draw();
|
||||
gl::blit_framebuffer(
|
||||
0, 0, physical_width as i32, physical_height as i32,
|
||||
0, 0, physical_width as i32, physical_height as i32,
|
||||
gl::ClearFlags::Depth, gl::NEAREST
|
||||
0,
|
||||
0,
|
||||
physical_width as i32,
|
||||
physical_height as i32,
|
||||
0,
|
||||
0,
|
||||
physical_width as i32,
|
||||
physical_height as i32,
|
||||
gl::ClearFlags::Depth,
|
||||
gl::NEAREST,
|
||||
);
|
||||
|
||||
gl::enable(gl::BLEND);
|
||||
|
@ -354,14 +418,26 @@ impl Renderer {
|
|||
gl::clear(gl::ClearFlags::Color);
|
||||
gl::clear_buffer(gl::COLOR, 0, &[0.0, 0.0, 0.0, 1.0]);
|
||||
gl::clear_buffer(gl::COLOR, 1, &[0.0, 0.0, 0.0, 0.0]);
|
||||
gl::blend_func_separate(gl::ONE_FACTOR, gl::ONE_FACTOR, gl::ZERO_FACTOR, gl::ONE_MINUS_SRC_ALPHA);
|
||||
gl::blend_func_separate(
|
||||
gl::ONE_FACTOR,
|
||||
gl::ONE_FACTOR,
|
||||
gl::ZERO_FACTOR,
|
||||
gl::ONE_MINUS_SRC_ALPHA,
|
||||
);
|
||||
|
||||
for (pos, info) in world.get_render_list().into_iter().rev() {
|
||||
for (pos, info) in world.get_render_list().iter().rev() {
|
||||
if let Some(trans) = info.trans.as_ref() {
|
||||
if trans.count > 0 {
|
||||
self.chunk_shader_alpha.offset.set_int3(pos.0, pos.1 * 4096, pos.2);
|
||||
self.chunk_shader_alpha
|
||||
.offset
|
||||
.set_int3(pos.0, pos.1 * 4096, pos.2);
|
||||
trans.array.bind();
|
||||
gl::draw_elements(gl::TRIANGLES, trans.count as i32, self.element_buffer_type, 0);
|
||||
gl::draw_elements(
|
||||
gl::TRIANGLES,
|
||||
trans.count as i32,
|
||||
self.element_buffer_type,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -390,7 +466,8 @@ impl Renderer {
|
|||
let (data, ty) = self::generate_element_buffer(size);
|
||||
self.element_buffer_type = ty;
|
||||
self.element_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
||||
self.element_buffer.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW);
|
||||
self.element_buffer
|
||||
.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW);
|
||||
self.element_buffer_size = size;
|
||||
}
|
||||
}
|
||||
|
@ -426,16 +503,27 @@ impl Renderer {
|
|||
info.buffer.bind(gl::ARRAY_BUFFER);
|
||||
if new || info.buffer_size < data.len() {
|
||||
info.buffer_size = data.len();
|
||||
info.buffer.set_data(gl::ARRAY_BUFFER, data, gl::DYNAMIC_DRAW);
|
||||
info.buffer
|
||||
.set_data(gl::ARRAY_BUFFER, data, gl::DYNAMIC_DRAW);
|
||||
} else {
|
||||
info.buffer.re_set_data(gl::ARRAY_BUFFER, data);
|
||||
}
|
||||
|
||||
self.chunk_shader.position.vertex_pointer(3, gl::FLOAT, false, 40, 0);
|
||||
self.chunk_shader.texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 40, 12);
|
||||
self.chunk_shader.texture_offset.vertex_pointer(3, gl::SHORT, false, 40, 20);
|
||||
self.chunk_shader.color.vertex_pointer(3, gl::UNSIGNED_BYTE, true, 40, 28);
|
||||
self.chunk_shader.lighting.vertex_pointer(2, gl::UNSIGNED_SHORT, false, 40, 32);
|
||||
self.chunk_shader
|
||||
.position
|
||||
.vertex_pointer(3, gl::FLOAT, false, 40, 0);
|
||||
self.chunk_shader
|
||||
.texture_info
|
||||
.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 40, 12);
|
||||
self.chunk_shader
|
||||
.texture_offset
|
||||
.vertex_pointer(3, gl::SHORT, false, 40, 20);
|
||||
self.chunk_shader
|
||||
.color
|
||||
.vertex_pointer(3, gl::UNSIGNED_BYTE, true, 40, 28);
|
||||
self.chunk_shader
|
||||
.lighting
|
||||
.vertex_pointer(2, gl::UNSIGNED_SHORT, false, 40, 32);
|
||||
|
||||
info.count = count;
|
||||
}
|
||||
|
@ -471,16 +559,27 @@ impl Renderer {
|
|||
info.buffer.bind(gl::ARRAY_BUFFER);
|
||||
if new || info.buffer_size < data.len() {
|
||||
info.buffer_size = data.len();
|
||||
info.buffer.set_data(gl::ARRAY_BUFFER, data, gl::DYNAMIC_DRAW);
|
||||
info.buffer
|
||||
.set_data(gl::ARRAY_BUFFER, data, gl::DYNAMIC_DRAW);
|
||||
} else {
|
||||
info.buffer.re_set_data(gl::ARRAY_BUFFER, data);
|
||||
}
|
||||
|
||||
self.chunk_shader_alpha.position.vertex_pointer(3, gl::FLOAT, false, 40, 0);
|
||||
self.chunk_shader_alpha.texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 40, 12);
|
||||
self.chunk_shader_alpha.texture_offset.vertex_pointer(3, gl::SHORT, false, 40, 20);
|
||||
self.chunk_shader_alpha.color.vertex_pointer(3, gl::UNSIGNED_BYTE, true, 40, 28);
|
||||
self.chunk_shader_alpha.lighting.vertex_pointer(2, gl::UNSIGNED_SHORT, false, 40, 32);
|
||||
self.chunk_shader_alpha
|
||||
.position
|
||||
.vertex_pointer(3, gl::FLOAT, false, 40, 0);
|
||||
self.chunk_shader_alpha
|
||||
.texture_info
|
||||
.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 40, 12);
|
||||
self.chunk_shader_alpha
|
||||
.texture_offset
|
||||
.vertex_pointer(3, gl::SHORT, false, 40, 20);
|
||||
self.chunk_shader_alpha
|
||||
.color
|
||||
.vertex_pointer(3, gl::UNSIGNED_BYTE, true, 40, 28);
|
||||
self.chunk_shader_alpha
|
||||
.lighting
|
||||
.vertex_pointer(2, gl::UNSIGNED_SHORT, false, 40, 32);
|
||||
|
||||
info.count = count;
|
||||
}
|
||||
|
@ -495,19 +594,23 @@ impl Renderer {
|
|||
unsafe {
|
||||
data.set_len(len);
|
||||
}
|
||||
self.gl_texture.get_pixels(gl::TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
&mut data[..]);
|
||||
self.gl_texture.image_3d(gl::TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
ATLAS_SIZE as u32,
|
||||
ATLAS_SIZE as u32,
|
||||
tex.atlases.len() as u32,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
&data[..]);
|
||||
self.gl_texture.get_pixels(
|
||||
gl::TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
&mut data[..],
|
||||
);
|
||||
self.gl_texture.image_3d(
|
||||
gl::TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
ATLAS_SIZE as u32,
|
||||
ATLAS_SIZE as u32,
|
||||
tex.atlases.len() as u32,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
&data[..],
|
||||
);
|
||||
self.texture_layers = tex.atlases.len();
|
||||
}
|
||||
tex.pending_uploads.len()
|
||||
|
@ -519,17 +622,19 @@ impl Renderer {
|
|||
let atlas = upload.0;
|
||||
let rect = upload.1;
|
||||
let img = &upload.2;
|
||||
self.gl_texture.sub_image_3d(gl::TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
rect.x as u32,
|
||||
rect.y as u32,
|
||||
atlas as u32,
|
||||
rect.width as u32,
|
||||
rect.height as u32,
|
||||
1,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
&img[..]);
|
||||
self.gl_texture.sub_image_3d(
|
||||
gl::TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
rect.x as u32,
|
||||
rect.y as u32,
|
||||
atlas as u32,
|
||||
rect.width as u32,
|
||||
rect.height as u32,
|
||||
1,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
&img[..],
|
||||
);
|
||||
}
|
||||
tex.pending_uploads.clear();
|
||||
}
|
||||
|
@ -561,30 +666,36 @@ impl Renderer {
|
|||
if ani.remaining_time <= 0.0 {
|
||||
ani.current_frame = (ani.current_frame + 1) % ani.frames.len();
|
||||
ani.remaining_time += ani.frames[ani.current_frame].time as f64;
|
||||
let offset = ani.texture.width * ani.texture.width *
|
||||
ani.frames[ani.current_frame].index * 4;
|
||||
let offset =
|
||||
ani.texture.width * ani.texture.width * ani.frames[ani.current_frame].index * 4;
|
||||
let offset2 = offset + ani.texture.width * ani.texture.width * 4;
|
||||
self.gl_texture.sub_image_3d(gl::TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
ani.texture.get_x() as u32,
|
||||
ani.texture.get_y() as u32,
|
||||
ani.texture.atlas as u32,
|
||||
ani.texture.get_width() as u32,
|
||||
ani.texture.get_height() as u32,
|
||||
1,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
&ani.data[offset..offset2]);
|
||||
self.gl_texture.sub_image_3d(
|
||||
gl::TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
ani.texture.get_x() as u32,
|
||||
ani.texture.get_y() as u32,
|
||||
ani.texture.atlas as u32,
|
||||
ani.texture.get_width() as u32,
|
||||
ani.texture.get_height() as u32,
|
||||
1,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
&ani.data[offset..offset2],
|
||||
);
|
||||
} else {
|
||||
ani.remaining_time -= delta / 3.0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn init_trans(&mut self, width: u32, height: u32) {
|
||||
self.trans = None;
|
||||
self.trans = Some(TransInfo::new(width, height, &self.chunk_shader_alpha, &self.trans_shader));
|
||||
self.trans = Some(TransInfo::new(
|
||||
width,
|
||||
height,
|
||||
&self.chunk_shader_alpha,
|
||||
&self.trans_shader,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn get_textures(&self) -> Arc<RwLock<TextureManager>> {
|
||||
|
@ -610,9 +721,7 @@ impl Renderer {
|
|||
}
|
||||
|
||||
pub fn get_texture(textures: &RwLock<TextureManager>, name: &str) -> Texture {
|
||||
let tex = {
|
||||
textures.read().unwrap().get_texture(name)
|
||||
};
|
||||
let tex = { textures.read().unwrap().get_texture(name) };
|
||||
match tex {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
|
@ -630,9 +739,7 @@ impl Renderer {
|
|||
}
|
||||
|
||||
pub fn get_skin(&self, textures: &RwLock<TextureManager>, url: &str) -> Texture {
|
||||
let tex = {
|
||||
textures.read().unwrap().get_skin(url)
|
||||
};
|
||||
let tex = { textures.read().unwrap().get_skin(url) };
|
||||
match tex {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
|
@ -680,27 +787,59 @@ init_shader! {
|
|||
}
|
||||
|
||||
impl TransInfo {
|
||||
pub fn new(width: u32, height: u32, chunk_shader: &ChunkShaderAlpha, shader: &TransShader) -> TransInfo {
|
||||
pub fn new(
|
||||
width: u32,
|
||||
height: u32,
|
||||
chunk_shader: &ChunkShaderAlpha,
|
||||
shader: &TransShader,
|
||||
) -> TransInfo {
|
||||
let trans = gl::Framebuffer::new();
|
||||
trans.bind();
|
||||
|
||||
let accum = gl::Texture::new();
|
||||
accum.bind(gl::TEXTURE_2D);
|
||||
accum.image_2d_ex(gl::TEXTURE_2D, 0, width, height, gl::RGBA16F, gl::RGBA, gl::FLOAT, None);
|
||||
accum.image_2d_ex(
|
||||
gl::TEXTURE_2D,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
gl::RGBA16F,
|
||||
gl::RGBA,
|
||||
gl::FLOAT,
|
||||
None,
|
||||
);
|
||||
accum.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR);
|
||||
accum.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAX_LEVEL, gl::LINEAR);
|
||||
trans.texture_2d(gl::COLOR_ATTACHMENT_0, gl::TEXTURE_2D, &accum, 0);
|
||||
|
||||
let revealage = gl::Texture::new();
|
||||
revealage.bind(gl::TEXTURE_2D);
|
||||
revealage.image_2d_ex(gl::TEXTURE_2D, 0, width, height, gl::R16F, gl::RED, gl::FLOAT, None);
|
||||
revealage.image_2d_ex(
|
||||
gl::TEXTURE_2D,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
gl::R16F,
|
||||
gl::RED,
|
||||
gl::FLOAT,
|
||||
None,
|
||||
);
|
||||
revealage.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR);
|
||||
revealage.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAX_LEVEL, gl::LINEAR);
|
||||
trans.texture_2d(gl::COLOR_ATTACHMENT_1, gl::TEXTURE_2D, &revealage, 0);
|
||||
|
||||
let trans_depth = gl::Texture::new();
|
||||
trans_depth.bind(gl::TEXTURE_2D);
|
||||
trans_depth.image_2d_ex(gl::TEXTURE_2D, 0, width, height, gl::DEPTH_COMPONENT24, gl::DEPTH_COMPONENT, gl::UNSIGNED_BYTE, None);
|
||||
trans_depth.image_2d_ex(
|
||||
gl::TEXTURE_2D,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
gl::DEPTH_COMPONENT24,
|
||||
gl::DEPTH_COMPONENT,
|
||||
gl::UNSIGNED_BYTE,
|
||||
None,
|
||||
);
|
||||
trans_depth.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR);
|
||||
trans_depth.set_parameter(gl::TEXTURE_2D, gl::TEXTURE_MAX_LEVEL, gl::LINEAR);
|
||||
trans.texture_2d(gl::DEPTH_ATTACHMENT, gl::TEXTURE_2D, &trans_depth, 0);
|
||||
|
@ -716,13 +855,37 @@ impl TransInfo {
|
|||
|
||||
let fb_color = gl::Texture::new();
|
||||
fb_color.bind(gl::TEXTURE_2D_MULTISAMPLE);
|
||||
fb_color.image_2d_sample(gl::TEXTURE_2D_MULTISAMPLE, NUM_SAMPLES, width, height, gl::RGBA8, false);
|
||||
main.texture_2d(gl::COLOR_ATTACHMENT_0, gl::TEXTURE_2D_MULTISAMPLE, &fb_color, 0);
|
||||
fb_color.image_2d_sample(
|
||||
gl::TEXTURE_2D_MULTISAMPLE,
|
||||
NUM_SAMPLES,
|
||||
width,
|
||||
height,
|
||||
gl::RGBA8,
|
||||
false,
|
||||
);
|
||||
main.texture_2d(
|
||||
gl::COLOR_ATTACHMENT_0,
|
||||
gl::TEXTURE_2D_MULTISAMPLE,
|
||||
&fb_color,
|
||||
0,
|
||||
);
|
||||
|
||||
let fb_depth = gl::Texture::new();
|
||||
fb_depth.bind(gl::TEXTURE_2D_MULTISAMPLE);
|
||||
fb_depth.image_2d_sample(gl::TEXTURE_2D_MULTISAMPLE, NUM_SAMPLES, width, height, gl::DEPTH_COMPONENT24, false);
|
||||
main.texture_2d(gl::DEPTH_ATTACHMENT, gl::TEXTURE_2D_MULTISAMPLE, &fb_depth, 0);
|
||||
fb_depth.image_2d_sample(
|
||||
gl::TEXTURE_2D_MULTISAMPLE,
|
||||
NUM_SAMPLES,
|
||||
width,
|
||||
height,
|
||||
gl::DEPTH_COMPONENT24,
|
||||
false,
|
||||
);
|
||||
main.texture_2d(
|
||||
gl::DEPTH_ATTACHMENT,
|
||||
gl::TEXTURE_2D_MULTISAMPLE,
|
||||
&fb_depth,
|
||||
0,
|
||||
);
|
||||
gl::check_framebuffer_status();
|
||||
|
||||
gl::unbind_framebuffer();
|
||||
|
@ -734,7 +897,11 @@ impl TransInfo {
|
|||
buffer.bind(gl::ARRAY_BUFFER);
|
||||
|
||||
let mut data = vec![];
|
||||
for f in [-1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0].into_iter() {
|
||||
for f in [
|
||||
-1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0,
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
data.write_f32::<NativeEndian>(*f).unwrap();
|
||||
}
|
||||
buffer.set_data(gl::ARRAY_BUFFER, &data, gl::STATIC_DRAW);
|
||||
|
@ -792,7 +959,13 @@ pub struct TextureManager {
|
|||
}
|
||||
|
||||
impl TextureManager {
|
||||
fn new(res: Arc<RwLock<resources::Manager>>) -> (TextureManager, mpsc::Sender<String>, mpsc::Receiver<(String, Option<image::DynamicImage>)>) {
|
||||
fn new(
|
||||
res: Arc<RwLock<resources::Manager>>,
|
||||
) -> (
|
||||
TextureManager,
|
||||
mpsc::Sender<String>,
|
||||
mpsc::Receiver<(String, Option<image::DynamicImage>)>,
|
||||
) {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let (stx, srx) = mpsc::channel();
|
||||
let skin_thread = thread::spawn(|| Self::process_skins(srx, tx));
|
||||
|
@ -818,28 +991,31 @@ impl TextureManager {
|
|||
}
|
||||
|
||||
fn add_defaults(&mut self) {
|
||||
self.put_texture("steven",
|
||||
"missing_texture",
|
||||
2,
|
||||
2,
|
||||
vec![
|
||||
0, 0, 0, 255,
|
||||
255, 0, 255, 255,
|
||||
255, 0, 255, 255,
|
||||
0, 0, 0, 255,
|
||||
]);
|
||||
self.put_texture("steven",
|
||||
"solid",
|
||||
1,
|
||||
1,
|
||||
vec![
|
||||
255, 255, 255, 255,
|
||||
]);
|
||||
self.put_texture(
|
||||
"steven",
|
||||
"missing_texture",
|
||||
2,
|
||||
2,
|
||||
vec![
|
||||
0, 0, 0, 255, 255, 0, 255, 255, 255, 0, 255, 255, 0, 0, 0, 255,
|
||||
],
|
||||
);
|
||||
self.put_texture("steven", "solid", 1, 1, vec![255, 255, 255, 255]);
|
||||
}
|
||||
|
||||
fn process_skins(recv: mpsc::Receiver<String>, reply: mpsc::Sender<(String, Option<image::DynamicImage>)>) {
|
||||
use reqwest;
|
||||
let client = reqwest::Client::new();
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn process_skins(
|
||||
recv: mpsc::Receiver<String>,
|
||||
reply: mpsc::Sender<(String, Option<image::DynamicImage>)>,
|
||||
) {
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn process_skins(
|
||||
recv: mpsc::Receiver<String>,
|
||||
reply: mpsc::Sender<(String, Option<image::DynamicImage>)>,
|
||||
) {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
loop {
|
||||
let hash = match recv.recv() {
|
||||
Ok(val) => val,
|
||||
|
@ -848,20 +1024,24 @@ impl TextureManager {
|
|||
match Self::obtain_skin(&client, &hash) {
|
||||
Ok(img) => {
|
||||
let _ = reply.send((hash, Some(img)));
|
||||
},
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Failed to get skin {:?}: {}", hash, err);
|
||||
let _ = reply.send((hash, None));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn obtain_skin(client: &::reqwest::Client, hash: &str) -> Result<image::DynamicImage, ::std::io::Error> {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn obtain_skin(
|
||||
client: &::reqwest::blocking::Client,
|
||||
hash: &str,
|
||||
) -> Result<image::DynamicImage, ::std::io::Error> {
|
||||
use std::io::Read;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::path::Path;
|
||||
use std_or_web::fs;
|
||||
let path = format!("skin-cache/{}/{}.png", &hash[..2], hash);
|
||||
let cache_path = Path::new(&path);
|
||||
fs::create_dir_all(cache_path.parent().unwrap())?;
|
||||
|
@ -881,7 +1061,7 @@ impl TextureManager {
|
|||
};
|
||||
let mut buf = vec![];
|
||||
match res.read_to_end(&mut buf) {
|
||||
Ok(_) => {},
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
// TODO: different error for failure to read?
|
||||
return Err(Error::new(ErrorKind::InvalidData, err));
|
||||
|
@ -902,10 +1082,11 @@ impl TextureManager {
|
|||
if height == 32 {
|
||||
// Needs changing to the new format
|
||||
let mut new = image::DynamicImage::new_rgba8(64, 64);
|
||||
new.copy_from(&img, 0, 0);
|
||||
for xx in 0 .. 4 {
|
||||
for yy in 0 .. 16 {
|
||||
for section in 0 .. 4 {
|
||||
new.copy_from(&img, 0, 0)
|
||||
.expect("Invalid png image in skin");
|
||||
for xx in 0..4 {
|
||||
for yy in 0..16 {
|
||||
for section in 0..4 {
|
||||
let os = match section {
|
||||
0 => 2,
|
||||
1 => 1,
|
||||
|
@ -913,8 +1094,16 @@ impl TextureManager {
|
|||
3 => 3,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
new.put_pixel(16 + (3 - xx) + section * 4, 48 + yy, img.get_pixel(xx + os * 4, 16 + yy));
|
||||
new.put_pixel(32 + (3 - xx) + section * 4, 48 + yy, img.get_pixel(xx + 40 + os * 4, 16 + yy));
|
||||
new.put_pixel(
|
||||
16 + (3 - xx) + section * 4,
|
||||
48 + yy,
|
||||
img.get_pixel(xx + os * 4, 16 + yy),
|
||||
);
|
||||
new.put_pixel(
|
||||
32 + (3 - xx) + section * 4,
|
||||
48 + yy,
|
||||
img.get_pixel(xx + 40 + os * 4, 16 + yy),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -930,11 +1119,11 @@ impl TextureManager {
|
|||
(32, 48, 16, 16),
|
||||
(40, 16, 16, 16),
|
||||
];
|
||||
for bl in blacklist.into_iter() {
|
||||
for x in bl.0 .. (bl.0 + bl.2) {
|
||||
for y in bl.1 .. (bl.1 + bl.3) {
|
||||
for bl in blacklist.iter() {
|
||||
for x in bl.0..(bl.0 + bl.2) {
|
||||
for y in bl.1..(bl.1 + bl.3) {
|
||||
let mut col = img.get_pixel(x, y);
|
||||
col.data[3] = 255;
|
||||
col.0[3] = 255;
|
||||
img.put_pixel(x, y, col);
|
||||
}
|
||||
}
|
||||
|
@ -966,7 +1155,8 @@ impl TextureManager {
|
|||
let (width, height) = img.dimensions();
|
||||
(width, height, img.to_rgba().into_vec())
|
||||
};
|
||||
let new_tex = self.put_texture("steven-dynamic", n, width as u32, height as u32, data);
|
||||
let new_tex =
|
||||
self.put_texture("steven-dynamic", n, width as u32, height as u32, data);
|
||||
self.dynamic_textures.get_mut(n).unwrap().0 = new_tex;
|
||||
} else if !self.textures.contains_key(name) {
|
||||
self.load_texture(name);
|
||||
|
@ -994,7 +1184,11 @@ impl TextureManager {
|
|||
let res = self.resources.clone();
|
||||
// TODO: This shouldn't be hardcoded to steve but instead
|
||||
// have a way to select alex as a default.
|
||||
let img = if let Some(mut val) = res.read().unwrap().open("minecraft", "textures/entity/steve.png") {
|
||||
let img = if let Some(mut val) = res
|
||||
.read()
|
||||
.unwrap()
|
||||
.open("minecraft", "textures/entity/steve.png")
|
||||
{
|
||||
let mut data = Vec::new();
|
||||
val.read_to_end(&mut data).unwrap();
|
||||
image::load_from_memory(&data).unwrap()
|
||||
|
@ -1007,7 +1201,9 @@ impl TextureManager {
|
|||
}
|
||||
|
||||
fn update_skin(&mut self, hash: String, img: image::DynamicImage) {
|
||||
if !self.skins.contains_key(&hash) { return; }
|
||||
if !self.skins.contains_key(&hash) {
|
||||
return;
|
||||
}
|
||||
let name = format!("steven-dynamic:skin-{}", hash);
|
||||
let tex = self.get_texture(&name).unwrap();
|
||||
let rect = atlas::Rect {
|
||||
|
@ -1017,8 +1213,12 @@ impl TextureManager {
|
|||
height: tex.height,
|
||||
};
|
||||
|
||||
self.pending_uploads.push((tex.atlas, rect, img.to_rgba().into_vec()));
|
||||
self.dynamic_textures.get_mut(&format!("skin-{}", hash)).unwrap().1 = img;
|
||||
self.pending_uploads
|
||||
.push((tex.atlas, rect, img.to_rgba().into_vec()));
|
||||
self.dynamic_textures
|
||||
.get_mut(&format!("skin-{}", hash))
|
||||
.unwrap()
|
||||
.1 = img;
|
||||
}
|
||||
|
||||
fn get_texture(&self, name: &str) -> Option<Texture> {
|
||||
|
@ -1059,23 +1259,27 @@ impl TextureManager {
|
|||
self.insert_texture_dummy(plugin, name);
|
||||
}
|
||||
|
||||
fn load_animation(&mut self,
|
||||
plugin: &str,
|
||||
name: &str,
|
||||
img: &image::DynamicImage,
|
||||
data: Vec<u8>)
|
||||
-> Option<AnimatedTexture> {
|
||||
fn load_animation(
|
||||
&mut self,
|
||||
plugin: &str,
|
||||
name: &str,
|
||||
img: &image::DynamicImage,
|
||||
data: Vec<u8>,
|
||||
) -> Option<AnimatedTexture> {
|
||||
let path = format!("textures/{}.png.mcmeta", name);
|
||||
let res = self.resources.clone();
|
||||
if let Some(val) = res.read().unwrap().open(plugin, &path) {
|
||||
let meta: serde_json::Value = serde_json::from_reader(val).unwrap();
|
||||
let animation = meta.get("animation").unwrap();
|
||||
let frame_time = animation.get("frametime").and_then(|v| v.as_i64()).unwrap_or(1);
|
||||
let interpolate = animation.get("interpolate")
|
||||
.and_then(|v| v.as_bool())
|
||||
.unwrap_or(false);
|
||||
let frames = if let Some(frames) = animation.get("frames")
|
||||
.and_then(|v| v.as_array()) {
|
||||
let frame_time = animation
|
||||
.get("frametime")
|
||||
.and_then(|v| v.as_i64())
|
||||
.unwrap_or(1);
|
||||
let interpolate = animation
|
||||
.get("interpolate")
|
||||
.and_then(|v| v.as_bool())
|
||||
.unwrap_or(false);
|
||||
let frames = if let Some(frames) = animation.get("frames").and_then(|v| v.as_array()) {
|
||||
let mut out = Vec::with_capacity(frames.len());
|
||||
for frame in frames {
|
||||
if let Some(index) = frame.as_i64() {
|
||||
|
@ -1084,7 +1288,7 @@ impl TextureManager {
|
|||
time: frame_time,
|
||||
})
|
||||
} else {
|
||||
out.push(AnimationFrame{
|
||||
out.push(AnimationFrame {
|
||||
index: frame.get("index").unwrap().as_i64().unwrap() as usize,
|
||||
time: frame_time * frame.get("frameTime").unwrap().as_i64().unwrap(),
|
||||
})
|
||||
|
@ -1116,13 +1320,14 @@ impl TextureManager {
|
|||
None
|
||||
}
|
||||
|
||||
fn put_texture(&mut self,
|
||||
plugin: &str,
|
||||
name: &str,
|
||||
width: u32,
|
||||
height: u32,
|
||||
data: Vec<u8>)
|
||||
-> Texture {
|
||||
fn put_texture(
|
||||
&mut self,
|
||||
plugin: &str,
|
||||
name: &str,
|
||||
width: u32,
|
||||
height: u32,
|
||||
data: Vec<u8>,
|
||||
) -> Texture {
|
||||
let (atlas, rect) = self.find_free(width as usize, height as usize);
|
||||
self.pending_uploads.push((atlas, rect, data));
|
||||
|
||||
|
@ -1213,19 +1418,27 @@ impl TextureManager {
|
|||
height,
|
||||
};
|
||||
self.pending_uploads.push((tex.atlas, rect, data));
|
||||
let mut t = tex.relative(0.0, 0.0, (width as f32) / (tex.width as f32), (height as f32) / (tex.height as f32));
|
||||
let mut t = tex.relative(
|
||||
0.0,
|
||||
0.0,
|
||||
(width as f32) / (tex.width as f32),
|
||||
(height as f32) / (tex.height as f32),
|
||||
);
|
||||
let old_name = mem::replace(&mut tex.name, format!("steven-dynamic:{}", name));
|
||||
self.dynamic_textures.insert(name.to_owned(), (tex.clone(), img));
|
||||
self.dynamic_textures
|
||||
.insert(name.to_owned(), (tex.clone(), img));
|
||||
// We need to rename the texture itself so that get_texture calls
|
||||
// work with the new name
|
||||
let mut old = self.textures.remove(&old_name).unwrap();
|
||||
old.name = format!("steven-dynamic:{}", name);
|
||||
t.name = old.name.clone();
|
||||
self.textures.insert(format!("steven-dynamic:{}", name), old);
|
||||
self.textures
|
||||
.insert(format!("steven-dynamic:{}", name), old);
|
||||
t
|
||||
} else {
|
||||
let tex = self.put_texture("steven-dynamic", name, width as u32, height as u32, data);
|
||||
self.dynamic_textures.insert(name.to_owned(), (tex.clone(), img));
|
||||
self.dynamic_textures
|
||||
.insert(name.to_owned(), (tex.clone(), img));
|
||||
tex
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
|
||||
use super::glsl;
|
||||
use super::shaders;
|
||||
use crate::format::{self, Component};
|
||||
use crate::gl;
|
||||
use cgmath::{Point3, Matrix4, SquareMatrix};
|
||||
use crate::model::BlockVertex;
|
||||
use crate::shared::Direction;
|
||||
use crate::types::hash::FNVHash;
|
||||
use byteorder::{NativeEndian, WriteBytesExt};
|
||||
use cgmath::{Matrix4, Point3, SquareMatrix};
|
||||
use collision::{self, Frustum, Sphere};
|
||||
use std::collections::HashMap;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use crate::types::hash::FNVHash;
|
||||
use crate::shared::Direction;
|
||||
use byteorder::{WriteBytesExt, NativeEndian};
|
||||
use crate::model::BlockVertex;
|
||||
use crate::format::{self, Component};
|
||||
|
||||
pub struct Manager {
|
||||
collections: Vec<Collection>,
|
||||
|
@ -42,17 +41,25 @@ impl Manager {
|
|||
m.add_collection(
|
||||
&greg.get("model_vertex"),
|
||||
&greg.get("model_frag"),
|
||||
gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA
|
||||
gl::SRC_ALPHA,
|
||||
gl::ONE_MINUS_SRC_ALPHA,
|
||||
);
|
||||
m.add_collection(
|
||||
&greg.get("sun_vertex"),
|
||||
&greg.get("sun_frag"),
|
||||
gl::SRC_ALPHA, gl::ONE_FACTOR
|
||||
gl::SRC_ALPHA,
|
||||
gl::ONE_FACTOR,
|
||||
);
|
||||
m
|
||||
}
|
||||
|
||||
pub fn add_collection(&mut self, vert: &str, frag: &str, blend_s: gl::Factor, blend_d: gl::Factor) -> CollectionKey {
|
||||
pub fn add_collection(
|
||||
&mut self,
|
||||
vert: &str,
|
||||
frag: &str,
|
||||
blend_s: gl::Factor,
|
||||
blend_d: gl::Factor,
|
||||
) -> CollectionKey {
|
||||
let collection = Collection {
|
||||
shader: ModelShader::new_manual(vert, frag),
|
||||
models: HashMap::with_hasher(BuildHasherDefault::default()),
|
||||
|
@ -84,11 +91,26 @@ impl Manager {
|
|||
collection.shader.texture_offset.map(|v| v.enable());
|
||||
collection.shader.color.map(|v| v.enable());
|
||||
collection.shader.id.map(|v| v.enable());
|
||||
collection.shader.position.map(|v| v.vertex_pointer(3, gl::FLOAT, false, 36, 0));
|
||||
collection.shader.texture_info.map(|v| v.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 36, 12));
|
||||
collection.shader.texture_offset.map(|v| v.vertex_pointer_int(3, gl::SHORT, 36, 20));
|
||||
collection.shader.color.map(|v| v.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 36, 28));
|
||||
collection.shader.id.map(|v| v.vertex_pointer_int(1, gl::UNSIGNED_BYTE, 36, 32));
|
||||
collection
|
||||
.shader
|
||||
.position
|
||||
.map(|v| v.vertex_pointer(3, gl::FLOAT, false, 36, 0));
|
||||
collection
|
||||
.shader
|
||||
.texture_info
|
||||
.map(|v| v.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 36, 12));
|
||||
collection
|
||||
.shader
|
||||
.texture_offset
|
||||
.map(|v| v.vertex_pointer_int(3, gl::SHORT, 36, 20));
|
||||
collection
|
||||
.shader
|
||||
.color
|
||||
.map(|v| v.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 36, 28));
|
||||
collection
|
||||
.shader
|
||||
.id
|
||||
.map(|v| v.vertex_pointer_int(1, gl::UNSIGNED_BYTE, 36, 32));
|
||||
|
||||
let mut model = Model {
|
||||
// For culling only
|
||||
|
@ -125,7 +147,8 @@ impl Manager {
|
|||
if self.max_index < model.count as usize {
|
||||
let (data, ty) = super::generate_element_buffer(model.count as usize);
|
||||
self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
||||
self.index_buffer.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW);
|
||||
self.index_buffer
|
||||
.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW);
|
||||
self.max_index = model.count as usize;
|
||||
self.index_type = ty;
|
||||
}
|
||||
|
@ -156,8 +179,12 @@ impl Manager {
|
|||
let _ = buffer.write_u16::<NativeEndian>(vert.texture.get_y() as u16);
|
||||
let _ = buffer.write_u16::<NativeEndian>(vert.texture.get_width() as u16);
|
||||
let _ = buffer.write_u16::<NativeEndian>(vert.texture.get_height() as u16);
|
||||
let _ = buffer.write_i16::<NativeEndian>(((vert.texture.get_width() as f64) * 16.0 * vert.texture_x) as i16);
|
||||
let _ = buffer.write_i16::<NativeEndian>(((vert.texture.get_height() as f64) * 16.0 * vert.texture_y) as i16);
|
||||
let _ = buffer.write_i16::<NativeEndian>(
|
||||
((vert.texture.get_width() as f64) * 16.0 * vert.texture_x) as i16,
|
||||
);
|
||||
let _ = buffer.write_i16::<NativeEndian>(
|
||||
((vert.texture.get_height() as f64) * 16.0 * vert.texture_y) as i16,
|
||||
);
|
||||
let _ = buffer.write_i16::<NativeEndian>(vert.texture.atlas as i16);
|
||||
let _ = buffer.write_i16::<NativeEndian>(0);
|
||||
let _ = buffer.write_u8(vert.r);
|
||||
|
@ -174,12 +201,18 @@ impl Manager {
|
|||
if buffer.len() < model.buffer_size {
|
||||
model.buffer.re_set_data(gl::ARRAY_BUFFER, &buffer);
|
||||
} else {
|
||||
model.buffer.set_data(gl::ARRAY_BUFFER, &buffer, gl::DYNAMIC_DRAW);
|
||||
model
|
||||
.buffer
|
||||
.set_data(gl::ARRAY_BUFFER, &buffer, gl::DYNAMIC_DRAW);
|
||||
model.buffer_size = buffer.len();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rebuild_models(&mut self, version: usize, textures: &Arc<RwLock<super::TextureManager>>) {
|
||||
pub fn rebuild_models(
|
||||
&mut self,
|
||||
version: usize,
|
||||
textures: &Arc<RwLock<super::TextureManager>>,
|
||||
) {
|
||||
for collection in &mut self.collections {
|
||||
for (_, model) in &mut collection.models {
|
||||
for vert in &mut model.verts {
|
||||
|
@ -200,28 +233,57 @@ impl Manager {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, frustum: &Frustum<f32>, perspective_matrix: &Matrix4<f32>, camera_matrix: &Matrix4<f32>, light_level: f32, sky_offset: f32) {
|
||||
pub fn draw(
|
||||
&mut self,
|
||||
frustum: &Frustum<f32>,
|
||||
perspective_matrix: &Matrix4<f32>,
|
||||
camera_matrix: &Matrix4<f32>,
|
||||
light_level: f32,
|
||||
sky_offset: f32,
|
||||
) {
|
||||
gl::enable(gl::BLEND);
|
||||
for collection in &self.collections {
|
||||
collection.shader.program.use_program();
|
||||
collection.shader.perspective_matrix.map(|v| v.set_matrix4(perspective_matrix));
|
||||
collection.shader.camera_matrix.map(|v| v.set_matrix4(camera_matrix));
|
||||
collection
|
||||
.shader
|
||||
.perspective_matrix
|
||||
.map(|v| v.set_matrix4(perspective_matrix));
|
||||
collection
|
||||
.shader
|
||||
.camera_matrix
|
||||
.map(|v| v.set_matrix4(camera_matrix));
|
||||
collection.shader.texture.map(|v| v.set_int(0));
|
||||
collection.shader.sky_offset.map(|v| v.set_float(sky_offset));
|
||||
collection.shader.light_level.map(|v| v.set_float(light_level));
|
||||
collection
|
||||
.shader
|
||||
.sky_offset
|
||||
.map(|v| v.set_float(sky_offset));
|
||||
collection
|
||||
.shader
|
||||
.light_level
|
||||
.map(|v| v.set_float(light_level));
|
||||
gl::blend_func(collection.blend_s, collection.blend_d);
|
||||
|
||||
for model in collection.models.values() {
|
||||
if model.radius > 0.0 && frustum.contains(&Sphere {
|
||||
center: Point3::new(model.x, -model.y, model.z),
|
||||
radius: model.radius
|
||||
}) == collision::Relation::Out {
|
||||
if model.radius > 0.0
|
||||
&& frustum.contains(&Sphere {
|
||||
center: Point3::new(model.x, -model.y, model.z),
|
||||
radius: model.radius,
|
||||
}) == collision::Relation::Out
|
||||
{
|
||||
continue;
|
||||
}
|
||||
model.array.bind();
|
||||
collection.shader.lighting.map(|v| v.set_float2(model.block_light, model.sky_light));
|
||||
collection.shader.model_matrix.map(|v| v.set_matrix4_multi(&model.matrix));
|
||||
collection.shader.color_mul.map(|v| v.set_float_mutli_raw(model.colors.as_ptr() as *const _, model.colors.len()));
|
||||
collection
|
||||
.shader
|
||||
.lighting
|
||||
.map(|v| v.set_float2(model.block_light, model.sky_light));
|
||||
collection
|
||||
.shader
|
||||
.model_matrix
|
||||
.map(|v| v.set_matrix4_multi(&model.matrix));
|
||||
collection.shader.color_mul.map(|v| {
|
||||
v.set_float_mutli_raw(model.colors.as_ptr() as *const _, model.colors.len())
|
||||
});
|
||||
gl::draw_elements(gl::TRIANGLES, model.count, self.index_type, 0);
|
||||
}
|
||||
}
|
||||
|
@ -301,23 +363,44 @@ init_shader! {
|
|||
// Helper methods
|
||||
pub fn append_box(
|
||||
verts: &mut Vec<Vertex>,
|
||||
x: f32, y: f32, z: f32,
|
||||
w: f32, h: f32, d: f32, textures: [Option<super::Texture>; 6]
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
w: f32,
|
||||
h: f32,
|
||||
d: f32,
|
||||
textures: [Option<super::Texture>; 6],
|
||||
) {
|
||||
append_box_texture_scale(verts, x, y, z, w, h, d, textures, [
|
||||
[1.0, 1.0],
|
||||
[1.0, 1.0],
|
||||
[1.0, 1.0],
|
||||
[1.0, 1.0],
|
||||
[1.0, 1.0],
|
||||
[1.0, 1.0]
|
||||
]);
|
||||
append_box_texture_scale(
|
||||
verts,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
w,
|
||||
h,
|
||||
d,
|
||||
textures,
|
||||
[
|
||||
[1.0, 1.0],
|
||||
[1.0, 1.0],
|
||||
[1.0, 1.0],
|
||||
[1.0, 1.0],
|
||||
[1.0, 1.0],
|
||||
[1.0, 1.0],
|
||||
],
|
||||
);
|
||||
}
|
||||
pub fn append_box_texture_scale(
|
||||
verts: &mut Vec<Vertex>,
|
||||
x: f32, y: f32, z: f32,
|
||||
w: f32, h: f32, d: f32,
|
||||
textures: [Option<super::Texture>; 6], texture_scale: [[f64; 2]; 6]) {
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
w: f32,
|
||||
h: f32,
|
||||
d: f32,
|
||||
textures: [Option<super::Texture>; 6],
|
||||
texture_scale: [[f64; 2]; 6],
|
||||
) {
|
||||
for dir in Direction::all() {
|
||||
let tex = textures[dir.index()].clone();
|
||||
if tex.is_none() {
|
||||
|
@ -326,7 +409,11 @@ pub fn append_box_texture_scale(
|
|||
let tex = tex.unwrap();
|
||||
for vert in BlockVertex::face_by_direction(dir) {
|
||||
let (rr, gg, bb) = if dir == Direction::West || dir == Direction::East {
|
||||
((255.0 * 0.8) as u8, (255.0 * 0.8) as u8, (255.0 * 0.8) as u8)
|
||||
(
|
||||
(255.0 * 0.8) as u8,
|
||||
(255.0 * 0.8) as u8,
|
||||
(255.0 * 0.8) as u8,
|
||||
)
|
||||
} else {
|
||||
(255, 255, 255)
|
||||
};
|
||||
|
@ -356,7 +443,7 @@ pub struct FormatState<'a> {
|
|||
pub x_scale: f32,
|
||||
}
|
||||
|
||||
impl <'a> FormatState<'a> {
|
||||
impl<'a> FormatState<'a> {
|
||||
pub fn build(&mut self, c: &Component, color: format::Color) {
|
||||
match *c {
|
||||
format::Component::Text(ref txt) => {
|
||||
|
|
|
@ -12,11 +12,15 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::render::glsl;
|
||||
use crate::gl;
|
||||
use crate::render::glsl;
|
||||
use log::error;
|
||||
|
||||
pub fn add_shaders(reg: &mut glsl::Registry) {
|
||||
reg.register("lookup_texture", include_str!("shaders/lookup_texture.glsl"));
|
||||
reg.register(
|
||||
"lookup_texture",
|
||||
include_str!("shaders/lookup_texture.glsl"),
|
||||
);
|
||||
reg.register("get_light", include_str!("shaders/get_light.glsl"));
|
||||
|
||||
reg.register("ui_vertex", include_str!("shaders/ui_vertex.glsl"));
|
||||
|
@ -40,12 +44,12 @@ pub fn add_shaders(reg: &mut glsl::Registry) {
|
|||
}
|
||||
|
||||
macro_rules! get_shader {
|
||||
($reg:ident, $name:expr) => (
|
||||
($reg:ident, $name:expr) => {
|
||||
$reg.get($name)
|
||||
);
|
||||
($reg:ident, $name:expr, $def:expr) => (
|
||||
};
|
||||
($reg:ident, $name:expr, $def:expr) => {
|
||||
$reg.get_define($name, $def)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
@ -128,13 +132,13 @@ pub fn create_program(vertex: &str, fragment: &str) -> gl::Program {
|
|||
v.compile();
|
||||
|
||||
if v.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
println!("Src: {}", vertex);
|
||||
error!("Src: {}", vertex);
|
||||
panic!("Shader error: {}", v.get_info_log());
|
||||
} else {
|
||||
let log = v.get_info_log();
|
||||
let log = log.trim().trim_matches('\u{0}');
|
||||
if !log.is_empty() {
|
||||
println!("{}", log);
|
||||
error!("{}", log);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,13 +147,13 @@ pub fn create_program(vertex: &str, fragment: &str) -> gl::Program {
|
|||
f.compile();
|
||||
|
||||
if f.get_parameter(gl::COMPILE_STATUS) == 0 {
|
||||
println!("Src: {}", fragment);
|
||||
error!("Src: {}", fragment);
|
||||
panic!("Shader error: {}", f.get_info_log());
|
||||
} else {
|
||||
let log = f.get_info_log();
|
||||
let log = log.trim().trim_matches('\u{0}');
|
||||
if !log.is_empty() {
|
||||
println!("{}", log);
|
||||
error!("{}", log);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
271
src/render/ui.rs
271
src/render/ui.rs
|
@ -12,16 +12,16 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::collections::HashMap;
|
||||
use crate::resources;
|
||||
use crate::gl;
|
||||
use crate::render;
|
||||
use crate::render::glsl;
|
||||
use crate::render::shaders;
|
||||
use byteorder::{WriteBytesExt, NativeEndian};
|
||||
use crate::resources;
|
||||
use byteorder::{NativeEndian, WriteBytesExt};
|
||||
use image;
|
||||
use image::GenericImageView;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
const UI_WIDTH: f64 = 854.0;
|
||||
const UI_HEIGHT: f64 = 480.0;
|
||||
|
@ -69,10 +69,11 @@ init_shader! {
|
|||
}
|
||||
|
||||
impl UIState {
|
||||
pub fn new(glsl: &glsl::Registry,
|
||||
textures: Arc<RwLock<render::TextureManager>>,
|
||||
res: Arc<RwLock<resources::Manager>>)
|
||||
-> UIState {
|
||||
pub fn new(
|
||||
glsl: &glsl::Registry,
|
||||
textures: Arc<RwLock<render::TextureManager>>,
|
||||
res: Arc<RwLock<resources::Manager>>,
|
||||
) -> UIState {
|
||||
let shader = UIShader::new(glsl);
|
||||
|
||||
let array = gl::VertexArray::new();
|
||||
|
@ -84,9 +85,15 @@ impl UIState {
|
|||
shader.texture_offset.enable();
|
||||
shader.color.enable();
|
||||
shader.position.vertex_pointer_int(3, gl::SHORT, 28, 0);
|
||||
shader.texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 28, 8);
|
||||
shader.texture_offset.vertex_pointer_int(3, gl::SHORT, 28, 16);
|
||||
shader.color.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 28, 24);
|
||||
shader
|
||||
.texture_info
|
||||
.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 28, 8);
|
||||
shader
|
||||
.texture_offset
|
||||
.vertex_pointer_int(3, gl::SHORT, 28, 16);
|
||||
shader
|
||||
.color
|
||||
.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 28, 24);
|
||||
|
||||
let index_buffer = gl::Buffer::new();
|
||||
index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
||||
|
@ -155,17 +162,21 @@ impl UIState {
|
|||
let (data, ty) = render::generate_element_buffer(self.count);
|
||||
self.index_type = ty;
|
||||
self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
||||
self.index_buffer.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW);
|
||||
self.index_buffer
|
||||
.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW);
|
||||
self.max_index = self.count;
|
||||
}
|
||||
|
||||
self.shader.screensize.set_float2(width as f32, height as f32);
|
||||
self.shader
|
||||
.screensize
|
||||
.set_float2(width as f32, height as f32);
|
||||
|
||||
self.buffer.bind(gl::ARRAY_BUFFER);
|
||||
self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER);
|
||||
if self.data.len() > self.prev_size {
|
||||
self.prev_size = self.data.len();
|
||||
self.buffer.set_data(gl::ARRAY_BUFFER, &self.data, gl::STREAM_DRAW);
|
||||
self.buffer
|
||||
.set_data(gl::ARRAY_BUFFER, &self.data, gl::STREAM_DRAW);
|
||||
} else {
|
||||
self.buffer.re_set_data(gl::ARRAY_BUFFER, &self.data);
|
||||
}
|
||||
|
@ -209,15 +220,19 @@ impl UIState {
|
|||
if page == 0 {
|
||||
let sw = (self.page_width / 16.0) as u32;
|
||||
let sh = (self.page_height / 16.0) as u32;
|
||||
return p.relative((cx * sw + info.0 as u32) as f32 / (self.page_width as f32),
|
||||
(cy * sh) as f32 / (self.page_height as f32),
|
||||
(info.1 - info.0) as f32 / (self.page_width as f32),
|
||||
(sh as f32) / (self.page_height as f32))
|
||||
return p.relative(
|
||||
(cx * sw + info.0 as u32) as f32 / (self.page_width as f32),
|
||||
(cy * sh) as f32 / (self.page_height as f32),
|
||||
(info.1 - info.0) as f32 / (self.page_width as f32),
|
||||
(sh as f32) / (self.page_height as f32),
|
||||
);
|
||||
}
|
||||
p.relative((cx * 16 + info.0 as u32) as f32 / 256.0,
|
||||
(cy * 16) as f32 / 256.0,
|
||||
(info.1 - info.0) as f32 / 256.0,
|
||||
16.0 / 256.0)
|
||||
p.relative(
|
||||
(cx * 16 + info.0 as u32) as f32 / 256.0,
|
||||
(cy * 16) as f32 / 256.0,
|
||||
(info.1 - info.0) as f32 / 256.0,
|
||||
16.0 / 256.0,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn size_of_string(&self, val: &str) -> f64 {
|
||||
|
@ -273,7 +288,7 @@ impl UIState {
|
|||
let mut start = true;
|
||||
'x_loop: for x in 0..sw {
|
||||
for y in 0..sh {
|
||||
let a = img.get_pixel(cx + x, cy + y).data[3];
|
||||
let a = img.get_pixel(cx + x, cy + y).0[3];
|
||||
if start && a != 0 {
|
||||
self.font_character_info[i as usize].0 = x as i32;
|
||||
start = false;
|
||||
|
@ -296,44 +311,47 @@ impl UIState {
|
|||
self.new_text_scaled(val, x, y, 1.0, 1.0, r, g, b)
|
||||
}
|
||||
|
||||
pub fn new_text_scaled(&mut self,
|
||||
val: &str,
|
||||
x: f64,
|
||||
y: f64,
|
||||
sx: f64,
|
||||
sy: f64,
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8)
|
||||
-> UIText {
|
||||
pub fn new_text_scaled(
|
||||
&mut self,
|
||||
val: &str,
|
||||
x: f64,
|
||||
y: f64,
|
||||
sx: f64,
|
||||
sy: f64,
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
) -> UIText {
|
||||
self.create_text(val, x, y, sx, sy, 0.0, r, g, b)
|
||||
}
|
||||
|
||||
pub fn new_text_rotated(&mut self,
|
||||
val: &str,
|
||||
x: f64,
|
||||
y: f64,
|
||||
sx: f64,
|
||||
sy: f64,
|
||||
rotation: f64,
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8)
|
||||
-> UIText {
|
||||
pub fn new_text_rotated(
|
||||
&mut self,
|
||||
val: &str,
|
||||
x: f64,
|
||||
y: f64,
|
||||
sx: f64,
|
||||
sy: f64,
|
||||
rotation: f64,
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
) -> UIText {
|
||||
self.create_text(val, x, y, sx, sy, rotation, r, g, b)
|
||||
}
|
||||
|
||||
fn create_text(&mut self,
|
||||
val: &str,
|
||||
x: f64,
|
||||
y: f64,
|
||||
sx: f64,
|
||||
sy: f64,
|
||||
rotation: f64,
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8)
|
||||
-> UIText {
|
||||
fn create_text(
|
||||
&mut self,
|
||||
val: &str,
|
||||
x: f64,
|
||||
y: f64,
|
||||
sx: f64,
|
||||
sy: f64,
|
||||
rotation: f64,
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
) -> UIText {
|
||||
let mut elements = Vec::new();
|
||||
let mut offset = 0.0;
|
||||
for ch in val.chars() {
|
||||
|
@ -361,30 +379,34 @@ impl UIState {
|
|||
dy = (16.0 * 0.5) + (tmpy * c + tmpx * s);
|
||||
}
|
||||
|
||||
let mut shadow = UIElement::new(&texture,
|
||||
x + dsx * sx,
|
||||
y + dsy * sy,
|
||||
w * sx,
|
||||
16.0 * sy,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
1.0);
|
||||
let mut shadow = UIElement::new(
|
||||
&texture,
|
||||
x + dsx * sx,
|
||||
y + dsy * sy,
|
||||
w * sx,
|
||||
16.0 * sy,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
1.0,
|
||||
);
|
||||
shadow.r = ((r as f64) * 0.25) as u8;
|
||||
shadow.g = ((g as f64) * 0.25) as u8;
|
||||
shadow.b = ((b as f64) * 0.25) as u8;
|
||||
shadow.rotation = rotation;
|
||||
elements.push(shadow);
|
||||
|
||||
let mut text = UIElement::new(&texture,
|
||||
x + dx * sx,
|
||||
y + dy * sy,
|
||||
w * sx,
|
||||
16.0 * sy,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
1.0);
|
||||
let mut text = UIElement::new(
|
||||
&texture,
|
||||
x + dx * sx,
|
||||
y + dy * sy,
|
||||
w * sx,
|
||||
16.0 * sy,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
1.0,
|
||||
);
|
||||
text.r = r;
|
||||
text.g = g;
|
||||
text.b = b;
|
||||
|
@ -437,16 +459,17 @@ pub struct UIElement {
|
|||
}
|
||||
|
||||
impl UIElement {
|
||||
pub fn new(tex: &render::Texture,
|
||||
x: f64,
|
||||
y: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
tx: f64,
|
||||
ty: f64,
|
||||
tw: f64,
|
||||
th: f64)
|
||||
-> UIElement {
|
||||
pub fn new(
|
||||
tex: &render::Texture,
|
||||
x: f64,
|
||||
y: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
tx: f64,
|
||||
ty: f64,
|
||||
tw: f64,
|
||||
th: f64,
|
||||
) -> UIElement {
|
||||
let twidth = tex.get_width();
|
||||
let theight = tex.get_height();
|
||||
UIElement {
|
||||
|
@ -474,46 +497,56 @@ impl UIElement {
|
|||
|
||||
pub fn bytes(&self, width: f64, height: f64) -> Vec<u8> {
|
||||
let mut buf = Vec::with_capacity(28 * 4);
|
||||
self.append_vertex(&mut buf,
|
||||
self.x,
|
||||
self.y,
|
||||
self.t_offsetx,
|
||||
self.t_offsety,
|
||||
width,
|
||||
height);
|
||||
self.append_vertex(&mut buf,
|
||||
self.x + self.w,
|
||||
self.y,
|
||||
self.t_offsetx + self.t_sizew,
|
||||
self.t_offsety,
|
||||
width,
|
||||
height);
|
||||
self.append_vertex(&mut buf,
|
||||
self.x,
|
||||
self.y + self.h,
|
||||
self.t_offsetx,
|
||||
self.t_offsety + self.t_sizeh,
|
||||
width,
|
||||
height);
|
||||
self.append_vertex(&mut buf,
|
||||
self.x + self.w,
|
||||
self.y + self.h,
|
||||
self.t_offsetx + self.t_sizew,
|
||||
self.t_offsety + self.t_sizeh,
|
||||
width,
|
||||
height);
|
||||
self.append_vertex(
|
||||
&mut buf,
|
||||
self.x,
|
||||
self.y,
|
||||
self.t_offsetx,
|
||||
self.t_offsety,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
self.append_vertex(
|
||||
&mut buf,
|
||||
self.x + self.w,
|
||||
self.y,
|
||||
self.t_offsetx + self.t_sizew,
|
||||
self.t_offsety,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
self.append_vertex(
|
||||
&mut buf,
|
||||
self.x,
|
||||
self.y + self.h,
|
||||
self.t_offsetx,
|
||||
self.t_offsety + self.t_sizeh,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
self.append_vertex(
|
||||
&mut buf,
|
||||
self.x + self.w,
|
||||
self.y + self.h,
|
||||
self.t_offsetx + self.t_sizew,
|
||||
self.t_offsety + self.t_sizeh,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
buf
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
pub fn append_vertex(&self,
|
||||
buf: &mut Vec<u8>,
|
||||
x: f64,
|
||||
y: f64,
|
||||
tx: i16,
|
||||
ty: i16,
|
||||
width: f64,
|
||||
height: f64) {
|
||||
pub fn append_vertex(
|
||||
&self,
|
||||
buf: &mut Vec<u8>,
|
||||
x: f64,
|
||||
y: f64,
|
||||
tx: i16,
|
||||
ty: i16,
|
||||
width: f64,
|
||||
height: f64,
|
||||
) {
|
||||
let mut dx = x as f64;
|
||||
let mut dy = y as f64;
|
||||
if self.rotation != 0.0 {
|
||||
|
|
176
src/resources.rs
176
src/resources.rs
|
@ -14,16 +14,17 @@
|
|||
|
||||
extern crate steven_resources as internal;
|
||||
|
||||
use std::thread;
|
||||
use std::path;
|
||||
use std::io;
|
||||
use std::fs;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use serde_json;
|
||||
use std::collections::HashMap;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use serde_json;
|
||||
use std::io;
|
||||
use std::path;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std_or_web::fs;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use reqwest;
|
||||
use zip;
|
||||
|
||||
|
@ -36,11 +37,11 @@ const ASSET_VERSION: &str = "1.13.1";
|
|||
const ASSET_INDEX_URL: &str = "https://launchermeta.mojang.com/mc/assets/1.13.1/1e710e31f3ce2fe262373b8cf5e054ee5955d904/1.13.1.json";
|
||||
|
||||
pub trait Pack: Sync + Send {
|
||||
fn open(&self, name: &str) -> Option<Box<io::Read>>;
|
||||
fn open(&self, name: &str) -> Option<Box<dyn io::Read>>;
|
||||
}
|
||||
|
||||
pub struct Manager {
|
||||
packs: Vec<Box<Pack>>,
|
||||
packs: Vec<Box<dyn Pack>>,
|
||||
version: usize,
|
||||
|
||||
vanilla_chan: Option<mpsc::Receiver<bool>>,
|
||||
|
@ -84,14 +85,21 @@ impl Manager {
|
|||
version: 0,
|
||||
vanilla_chan: None,
|
||||
vanilla_assets_chan: None,
|
||||
vanilla_progress: Arc::new(Mutex::new(Progress {
|
||||
tasks: vec![],
|
||||
})),
|
||||
vanilla_progress: Arc::new(Mutex::new(Progress { tasks: vec![] })),
|
||||
};
|
||||
m.add_pack(Box::new(InternalPack));
|
||||
m.download_vanilla();
|
||||
m.download_assets();
|
||||
(m, ManagerUI { progress_ui: vec!{}, num_tasks: 0 })
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
m.download_vanilla();
|
||||
m.download_assets();
|
||||
}
|
||||
(
|
||||
m,
|
||||
ManagerUI {
|
||||
progress_ui: vec![],
|
||||
num_tasks: 0,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the 'version' of the manager. The version is
|
||||
|
@ -100,7 +108,7 @@ impl Manager {
|
|||
self.version
|
||||
}
|
||||
|
||||
pub fn open(&self, plugin: &str, name: &str) -> Option<Box<io::Read>> {
|
||||
pub fn open(&self, plugin: &str, name: &str) -> Option<Box<dyn io::Read>> {
|
||||
let path = format!("assets/{}/{}", plugin, name);
|
||||
for pack in self.packs.iter().rev() {
|
||||
if let Some(val) = pack.open(&path) {
|
||||
|
@ -110,7 +118,7 @@ impl Manager {
|
|||
None
|
||||
}
|
||||
|
||||
pub fn open_all(&self, plugin: &str, name: &str) -> Vec<Box<io::Read>> {
|
||||
pub fn open_all(&self, plugin: &str, name: &str) -> Vec<Box<dyn io::Read>> {
|
||||
let mut ret = Vec::new();
|
||||
let path = format!("assets/{}/{}", plugin, name);
|
||||
for pack in self.packs.iter().rev() {
|
||||
|
@ -152,9 +160,12 @@ impl Manager {
|
|||
progress.tasks.retain(|v| v.progress < v.total);
|
||||
// Find out what we have to work with
|
||||
for task in &progress.tasks {
|
||||
if !mui.progress_ui.iter()
|
||||
if !mui
|
||||
.progress_ui
|
||||
.iter()
|
||||
.filter(|v| v.task_file == task.task_file)
|
||||
.any(|v| v.task_name == task.task_name) {
|
||||
.any(|v| v.task_name == task.task_name)
|
||||
{
|
||||
mui.num_tasks += 1;
|
||||
// Add a ui element for it
|
||||
let background = ui::ImageBuilder::new()
|
||||
|
@ -213,16 +224,22 @@ impl Manager {
|
|||
}
|
||||
let mut found = false;
|
||||
let mut prog = 1.0;
|
||||
for task in progress.tasks.iter()
|
||||
for task in progress
|
||||
.tasks
|
||||
.iter()
|
||||
.filter(|v| v.task_file == ui.task_file)
|
||||
.filter(|v| v.task_name == ui.task_name) {
|
||||
.filter(|v| v.task_name == ui.task_name)
|
||||
{
|
||||
found = true;
|
||||
prog = task.progress as f64 / task.total as f64;
|
||||
}
|
||||
let background = ui.background.borrow();
|
||||
let bar = ui.progress_bar.borrow();
|
||||
// Let the progress bar finish
|
||||
if !found && (background.y - ui.position).abs() < 0.7 * delta && (bar.width - 350.0).abs() < 1.0 * delta {
|
||||
if !found
|
||||
&& (background.y - ui.position).abs() < 0.7 * delta
|
||||
&& (bar.width - 350.0).abs() < 1.0 * delta
|
||||
{
|
||||
ui.closing = true;
|
||||
ui.position = -UI_HEIGHT;
|
||||
}
|
||||
|
@ -254,10 +271,11 @@ impl Manager {
|
|||
}
|
||||
|
||||
// Clean up dead elements
|
||||
mui.progress_ui.retain(|v| v.position >= -UI_HEIGHT || !v.closing);
|
||||
mui.progress_ui
|
||||
.retain(|v| v.position >= -UI_HEIGHT || !v.closing);
|
||||
}
|
||||
|
||||
fn add_pack(&mut self, pck: Box<Pack>) {
|
||||
fn add_pack(&mut self, pck: Box<dyn Pack>) {
|
||||
self.packs.push(pck);
|
||||
self.version += 1;
|
||||
}
|
||||
|
@ -265,7 +283,12 @@ impl Manager {
|
|||
fn load_vanilla(&mut self) {
|
||||
let loc = format!("./resources-{}", RESOURCES_VERSION);
|
||||
let location = path::Path::new(&loc);
|
||||
self.packs.insert(1, Box::new(DirPack { root: location.to_path_buf() }));
|
||||
self.packs.insert(
|
||||
1,
|
||||
Box::new(DirPack {
|
||||
root: location.to_path_buf(),
|
||||
}),
|
||||
);
|
||||
self.version += 1;
|
||||
}
|
||||
|
||||
|
@ -274,28 +297,40 @@ impl Manager {
|
|||
self.version += 1;
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn download_assets(&mut self) {
|
||||
let loc = format!("./index/{}.json", ASSET_VERSION);
|
||||
let location = path::Path::new(&loc).to_owned();
|
||||
let progress_info = self.vanilla_progress.clone();
|
||||
let (send, recv) = mpsc::channel();
|
||||
if fs::metadata(&location).is_ok(){
|
||||
if fs::metadata(&location).is_ok() {
|
||||
self.load_assets();
|
||||
} else {
|
||||
self.vanilla_assets_chan = Some(recv);
|
||||
}
|
||||
thread::spawn(move || {
|
||||
let client = reqwest::Client::new();
|
||||
if fs::metadata(&location).is_err(){
|
||||
let client = reqwest::blocking::Client::new();
|
||||
if fs::metadata(&location).is_err() {
|
||||
fs::create_dir_all(location.parent().unwrap()).unwrap();
|
||||
let res = client.get(ASSET_INDEX_URL)
|
||||
.send()
|
||||
.unwrap();
|
||||
let res = client.get(ASSET_INDEX_URL).send().unwrap();
|
||||
|
||||
let length = res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap().to_str().unwrap().parse::<u64>().unwrap();
|
||||
Self::add_task(&progress_info, "Downloading Asset Index", &*location.to_string_lossy(), length);
|
||||
let length = res
|
||||
.headers()
|
||||
.get(reqwest::header::CONTENT_LENGTH)
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.parse::<u64>()
|
||||
.unwrap();
|
||||
Self::add_task(
|
||||
&progress_info,
|
||||
"Downloading Asset Index",
|
||||
&*location.to_string_lossy(),
|
||||
length,
|
||||
);
|
||||
{
|
||||
let mut file = fs::File::create(format!("index-{}.tmp", ASSET_VERSION)).unwrap();
|
||||
let mut file =
|
||||
fs::File::create(format!("index-{}.tmp", ASSET_VERSION)).unwrap();
|
||||
let mut progress = ProgressRead {
|
||||
read: res,
|
||||
progress: &progress_info,
|
||||
|
@ -311,16 +346,25 @@ impl Manager {
|
|||
let index: serde_json::Value = serde_json::from_reader(&file).unwrap();
|
||||
let root_location = path::Path::new("./objects/");
|
||||
let objects = index.get("objects").and_then(|v| v.as_object()).unwrap();
|
||||
Self::add_task(&progress_info, "Downloading Assets", "./objects", objects.len() as u64);
|
||||
Self::add_task(
|
||||
&progress_info,
|
||||
"Downloading Assets",
|
||||
"./objects",
|
||||
objects.len() as u64,
|
||||
);
|
||||
for (k, v) in objects {
|
||||
let hash = v.get("hash").and_then(|v| v.as_str()).unwrap();
|
||||
let hash_path = format!("{}/{}", &hash[..2], hash);
|
||||
let location = root_location.join(&hash_path);
|
||||
if fs::metadata(&location).is_err(){
|
||||
if fs::metadata(&location).is_err() {
|
||||
fs::create_dir_all(location.parent().unwrap()).unwrap();
|
||||
let res = client.get(&format!("http://resources.download.minecraft.net/{}", hash_path))
|
||||
.send()
|
||||
.unwrap();
|
||||
let res = client
|
||||
.get(&format!(
|
||||
"http://resources.download.minecraft.net/{}",
|
||||
hash_path
|
||||
))
|
||||
.send()
|
||||
.unwrap();
|
||||
let length = v.get("size").and_then(|v| v.as_u64()).unwrap();
|
||||
Self::add_task(&progress_info, "Downloading Asset", k, length);
|
||||
let mut tmp_file = location.to_owned();
|
||||
|
@ -342,6 +386,7 @@ impl Manager {
|
|||
});
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn download_vanilla(&mut self) {
|
||||
let loc = format!("./resources-{}", RESOURCES_VERSION);
|
||||
let location = path::Path::new(&loc);
|
||||
|
@ -354,15 +399,25 @@ impl Manager {
|
|||
|
||||
let progress_info = self.vanilla_progress.clone();
|
||||
thread::spawn(move || {
|
||||
let client = reqwest::Client::new();
|
||||
let res = client.get(VANILLA_CLIENT_URL)
|
||||
.send()
|
||||
.unwrap();
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let res = client.get(VANILLA_CLIENT_URL).send().unwrap();
|
||||
let mut file = fs::File::create(format!("{}.tmp", RESOURCES_VERSION)).unwrap();
|
||||
|
||||
let length = res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap().to_str().unwrap().parse::<u64>().unwrap();
|
||||
let length = res
|
||||
.headers()
|
||||
.get(reqwest::header::CONTENT_LENGTH)
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.parse::<u64>()
|
||||
.unwrap();
|
||||
let task_file = format!("./resources-{}", RESOURCES_VERSION);
|
||||
Self::add_task(&progress_info, "Downloading Core Assets", &task_file, length);
|
||||
Self::add_task(
|
||||
&progress_info,
|
||||
"Downloading Core Assets",
|
||||
&task_file,
|
||||
length,
|
||||
);
|
||||
{
|
||||
let mut progress = ProgressRead {
|
||||
read: res,
|
||||
|
@ -378,7 +433,12 @@ impl Manager {
|
|||
let mut zip = zip::ZipArchive::new(file).unwrap();
|
||||
|
||||
let task_file = format!("./resources-{}", RESOURCES_VERSION);
|
||||
Self::add_task(&progress_info, "Unpacking Core Assets", &task_file, zip.len() as u64);
|
||||
Self::add_task(
|
||||
&progress_info,
|
||||
"Unpacking Core Assets",
|
||||
&task_file,
|
||||
zip.len() as u64,
|
||||
);
|
||||
|
||||
let loc = format!("./resources-{}", RESOURCES_VERSION);
|
||||
let location = path::Path::new(&loc);
|
||||
|
@ -414,9 +474,12 @@ impl Manager {
|
|||
|
||||
fn add_task_progress(progress: &Arc<Mutex<Progress>>, name: &str, file: &str, prog: u64) {
|
||||
let mut progress = progress.lock().unwrap();
|
||||
for task in progress.tasks.iter_mut()
|
||||
for task in progress
|
||||
.tasks
|
||||
.iter_mut()
|
||||
.filter(|v| v.task_file == file)
|
||||
.filter(|v| v.task_name == name) {
|
||||
.filter(|v| v.task_name == name)
|
||||
{
|
||||
task.progress += prog as u64;
|
||||
}
|
||||
}
|
||||
|
@ -427,7 +490,7 @@ struct DirPack {
|
|||
}
|
||||
|
||||
impl Pack for DirPack {
|
||||
fn open(&self, name: &str) -> Option<Box<io::Read>> {
|
||||
fn open(&self, name: &str) -> Option<Box<dyn io::Read>> {
|
||||
match fs::File::open(self.root.join(name)) {
|
||||
Ok(val) => Some(Box::new(val)),
|
||||
Err(_) => None,
|
||||
|
@ -438,7 +501,7 @@ impl Pack for DirPack {
|
|||
struct InternalPack;
|
||||
|
||||
impl Pack for InternalPack {
|
||||
fn open(&self, name: &str) -> Option<Box<io::Read>> {
|
||||
fn open(&self, name: &str) -> Option<Box<dyn io::Read>> {
|
||||
match internal::get_file(name) {
|
||||
Some(val) => Some(Box::new(io::Cursor::new(val))),
|
||||
None => None,
|
||||
|
@ -459,16 +522,17 @@ impl ObjectPack {
|
|||
let objects = index.get("objects").and_then(|v| v.as_object()).unwrap();
|
||||
let mut hash_objs = HashMap::with_hasher(BuildHasherDefault::default());
|
||||
for (k, v) in objects {
|
||||
hash_objs.insert(k.clone(), v.get("hash").and_then(|v| v.as_str()).unwrap().to_owned());
|
||||
}
|
||||
ObjectPack {
|
||||
objects: hash_objs,
|
||||
hash_objs.insert(
|
||||
k.clone(),
|
||||
v.get("hash").and_then(|v| v.as_str()).unwrap().to_owned(),
|
||||
);
|
||||
}
|
||||
ObjectPack { objects: hash_objs }
|
||||
}
|
||||
}
|
||||
|
||||
impl Pack for ObjectPack {
|
||||
fn open(&self, name: &str) -> Option<Box<io::Read>> {
|
||||
fn open(&self, name: &str) -> Option<Box<dyn io::Read>> {
|
||||
if !name.starts_with("assets/") {
|
||||
return None;
|
||||
}
|
||||
|
@ -494,7 +558,7 @@ struct ProgressRead<'a, T> {
|
|||
task_file: String,
|
||||
}
|
||||
|
||||
impl <'a, T: io::Read> io::Read for ProgressRead<'a, T> {
|
||||
impl<'a, T: io::Read> io::Read for ProgressRead<'a, T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let size = self.read.read(buf)?;
|
||||
Manager::add_task_progress(self.progress, &self.task_name, &self.task_file, size as u64);
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::ui;
|
||||
use crate::render;
|
||||
use crate::ui;
|
||||
|
||||
pub struct Connecting {
|
||||
elements: Option<UIElements>,
|
||||
|
@ -27,7 +27,6 @@ struct UIElements {
|
|||
_disclaimer: ui::TextRef,
|
||||
}
|
||||
|
||||
|
||||
impl Connecting {
|
||||
pub fn new(target: &str) -> Connecting {
|
||||
Connecting {
|
||||
|
@ -74,10 +73,12 @@ impl super::Screen for Connecting {
|
|||
self.elements = None
|
||||
}
|
||||
|
||||
fn tick(&mut self,
|
||||
_delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
_ui_container: &mut ui::Container) -> Option<Box<super::Screen>>{
|
||||
fn tick(
|
||||
&mut self,
|
||||
_delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
_ui_container: &mut ui::Container,
|
||||
) -> Option<Box<dyn super::Screen>> {
|
||||
let elements = self.elements.as_mut().unwrap();
|
||||
|
||||
elements.logo.tick(renderer);
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::fs;
|
||||
use std::collections::BTreeMap;
|
||||
use std_or_web::fs;
|
||||
|
||||
use crate::ui;
|
||||
use crate::render;
|
||||
use crate::ui;
|
||||
|
||||
use serde_json::{self, Value};
|
||||
|
||||
|
@ -60,7 +60,8 @@ impl EditServerEntry {
|
|||
};
|
||||
|
||||
{
|
||||
let servers = servers_info.as_object_mut()
|
||||
let servers = servers_info
|
||||
.as_object_mut()
|
||||
.unwrap()
|
||||
.get_mut("servers")
|
||||
.unwrap()
|
||||
|
@ -76,7 +77,6 @@ impl EditServerEntry {
|
|||
let mut out = fs::File::create("servers.json").unwrap();
|
||||
serde_json::to_writer_pretty(&mut out, &servers_info).unwrap();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl super::Screen for EditServerEntry {
|
||||
|
@ -131,7 +131,8 @@ impl super::Screen for EditServerEntry {
|
|||
&server_name.borrow().input,
|
||||
&server_address.borrow().input,
|
||||
);
|
||||
game.screen_sys.replace_screen(Box::new(super::ServerList::new(None)));
|
||||
game.screen_sys
|
||||
.replace_screen(Box::new(super::ServerList::new(None)));
|
||||
true
|
||||
});
|
||||
}
|
||||
|
@ -150,7 +151,8 @@ impl super::Screen for EditServerEntry {
|
|||
.attach(&mut *cancel);
|
||||
cancel.add_text(txt);
|
||||
cancel.add_click_func(|_, game| {
|
||||
game.screen_sys.replace_screen(Box::new(super::ServerList::new(None)));
|
||||
game.screen_sys
|
||||
.replace_screen(Box::new(super::ServerList::new(None)));
|
||||
true
|
||||
});
|
||||
}
|
||||
|
@ -169,11 +171,12 @@ impl super::Screen for EditServerEntry {
|
|||
self.elements = None
|
||||
}
|
||||
|
||||
fn tick(&mut self,
|
||||
_delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
_ui_container: &mut ui::Container) -> Option<Box<super::Screen>> {
|
||||
|
||||
fn tick(
|
||||
&mut self,
|
||||
_delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
_ui_container: &mut ui::Container,
|
||||
) -> Option<Box<dyn super::Screen>> {
|
||||
let elements = self.elements.as_mut().unwrap();
|
||||
elements.logo.tick(renderer);
|
||||
None
|
||||
|
|
|
@ -19,12 +19,12 @@ use std::thread;
|
|||
|
||||
use rand::{self, Rng};
|
||||
|
||||
use crate::ui;
|
||||
use crate::render;
|
||||
use crate::auth;
|
||||
use crate::console;
|
||||
use crate::protocol;
|
||||
use crate::protocol::mojang;
|
||||
use crate::auth;
|
||||
use crate::render;
|
||||
use crate::ui;
|
||||
|
||||
pub struct Login {
|
||||
elements: Option<UIElements>,
|
||||
|
@ -47,13 +47,16 @@ struct UIElements {
|
|||
profile: mojang::Profile,
|
||||
}
|
||||
|
||||
|
||||
impl Login {
|
||||
pub fn new(vars: Rc<console::Vars>) -> Login {
|
||||
Login { elements: None, vars: vars }
|
||||
Login {
|
||||
elements: None,
|
||||
vars: vars,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl super::Screen for Login {
|
||||
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) {
|
||||
let logo = ui::logo::Logo::new(renderer.resources.clone(), ui_container);
|
||||
|
@ -81,7 +84,6 @@ impl super::Screen for Login {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
// Login Error
|
||||
let login_error = ui::TextBuilder::new()
|
||||
.text("")
|
||||
|
@ -156,10 +158,12 @@ impl super::Screen for Login {
|
|||
self.elements = None
|
||||
}
|
||||
|
||||
fn tick(&mut self,
|
||||
_delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
_ui_container: &mut ui::Container) -> Option<Box<super::Screen>> {
|
||||
fn tick(
|
||||
&mut self,
|
||||
_delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
_ui_container: &mut ui::Container,
|
||||
) -> Option<Box<dyn super::Screen>> {
|
||||
let elements = self.elements.as_mut().unwrap();
|
||||
|
||||
if elements.try_login.get() && elements.login_res.is_none() {
|
||||
|
@ -170,10 +174,10 @@ impl super::Screen for Login {
|
|||
elements.login_btn_text.borrow_mut().text = "Logging in...".into();
|
||||
let mut client_token = self.vars.get(auth::AUTH_CLIENT_TOKEN).clone();
|
||||
if client_token.is_empty() {
|
||||
client_token = std::iter::repeat(()).map(|()| rand::thread_rng()
|
||||
.sample(&rand::distributions::Alphanumeric))
|
||||
.take(20)
|
||||
.collect();
|
||||
client_token = std::iter::repeat(())
|
||||
.map(|()| rand::thread_rng().sample(&rand::distributions::Alphanumeric))
|
||||
.take(20)
|
||||
.collect();
|
||||
self.vars.set(auth::AUTH_CLIENT_TOKEN, client_token);
|
||||
}
|
||||
let client_token = self.vars.get(auth::AUTH_CLIENT_TOKEN).clone();
|
||||
|
@ -185,7 +189,8 @@ impl super::Screen for Login {
|
|||
if refresh {
|
||||
tx.send(profile.refresh(&client_token)).unwrap();
|
||||
} else {
|
||||
tx.send(mojang::Profile::login(&username, &password, &client_token)).unwrap();
|
||||
tx.send(mojang::Profile::login(&username, &password, &client_token))
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -202,10 +207,10 @@ impl super::Screen for Login {
|
|||
self.vars.set(auth::AUTH_TOKEN, val.access_token.clone());
|
||||
elements.profile = val;
|
||||
return Some(Box::new(super::ServerList::new(None)));
|
||||
},
|
||||
}
|
||||
Err(err) => {
|
||||
elements.login_error.borrow_mut().text = format!("{}", err);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,31 +21,30 @@ pub mod connecting;
|
|||
pub mod edit_server;
|
||||
|
||||
pub mod settings_menu;
|
||||
pub use self::settings_menu::{SettingsMenu, VideoSettingsMenu, AudioSettingsMenu};
|
||||
pub use self::settings_menu::{AudioSettingsMenu, SettingsMenu, VideoSettingsMenu};
|
||||
|
||||
use crate::render;
|
||||
use crate::ui;
|
||||
|
||||
pub trait Screen {
|
||||
// Called once
|
||||
fn init(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
|
||||
}
|
||||
fn deinit(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
|
||||
}
|
||||
fn init(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {}
|
||||
fn deinit(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {}
|
||||
|
||||
// May be called multiple times
|
||||
fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container);
|
||||
fn on_deactive(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container);
|
||||
|
||||
// Called every frame the screen is active
|
||||
fn tick(&mut self,
|
||||
delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
ui_container: &mut ui::Container) -> Option<Box<Screen>>;
|
||||
fn tick(
|
||||
&mut self,
|
||||
delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
ui_container: &mut ui::Container,
|
||||
) -> Option<Box<dyn Screen>>;
|
||||
|
||||
// Events
|
||||
fn on_scroll(&mut self, _x: f64, _y: f64) {
|
||||
}
|
||||
fn on_scroll(&mut self, _x: f64, _y: f64) {}
|
||||
|
||||
fn is_closable(&self) -> bool {
|
||||
false
|
||||
|
@ -53,7 +52,7 @@ pub trait Screen {
|
|||
}
|
||||
|
||||
struct ScreenInfo {
|
||||
screen: Box<Screen>,
|
||||
screen: Box<dyn Screen>,
|
||||
init: bool,
|
||||
active: bool,
|
||||
}
|
||||
|
@ -65,9 +64,11 @@ pub struct ScreenSystem {
|
|||
}
|
||||
|
||||
impl ScreenSystem {
|
||||
pub fn new() -> ScreenSystem { Default::default() }
|
||||
pub fn new() -> ScreenSystem {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn add_screen(&mut self, screen: Box<Screen>) {
|
||||
pub fn add_screen(&mut self, screen: Box<dyn Screen>) {
|
||||
self.screens.push(ScreenInfo {
|
||||
screen,
|
||||
init: false,
|
||||
|
@ -81,7 +82,7 @@ impl ScreenSystem {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn replace_screen(&mut self, screen: Box<Screen>) {
|
||||
pub fn replace_screen(&mut self, screen: Box<dyn Screen>) {
|
||||
self.pop_screen();
|
||||
self.add_screen(screen);
|
||||
}
|
||||
|
@ -94,10 +95,12 @@ impl ScreenSystem {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn tick(&mut self,
|
||||
delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
ui_container: &mut ui::Container) {
|
||||
pub fn tick(
|
||||
&mut self,
|
||||
delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
ui_container: &mut ui::Container,
|
||||
) {
|
||||
for screen in &mut self.remove_queue {
|
||||
if screen.active {
|
||||
screen.screen.on_deactive(renderer, ui_container);
|
||||
|
|
|
@ -12,32 +12,30 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::fs;
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std_or_web::fs;
|
||||
|
||||
use crate::ui;
|
||||
use crate::render;
|
||||
use crate::format;
|
||||
use crate::format::{Component, TextComponent};
|
||||
use crate::protocol;
|
||||
use crate::render;
|
||||
use crate::ui;
|
||||
|
||||
use serde_json;
|
||||
use std::time::{Duration};
|
||||
use image;
|
||||
use base64;
|
||||
use image;
|
||||
use rand;
|
||||
use rand::Rng;
|
||||
use serde_json;
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct ServerList {
|
||||
elements: Option<UIElements>,
|
||||
disconnect_reason: Option<Component>,
|
||||
|
||||
needs_reload: Rc<RefCell<bool>>,
|
||||
server_protocol_versions: HashMap<String, i32>,
|
||||
}
|
||||
|
||||
struct UIElements {
|
||||
|
@ -70,7 +68,6 @@ struct Server {
|
|||
}
|
||||
|
||||
struct PingInfo {
|
||||
address: String,
|
||||
motd: format::Component,
|
||||
ping: Duration,
|
||||
exists: bool,
|
||||
|
@ -78,6 +75,7 @@ struct PingInfo {
|
|||
max: i32,
|
||||
protocol_version: i32,
|
||||
protocol_name: String,
|
||||
forge_mods: Vec<crate::protocol::forge::ForgeMod>,
|
||||
favicon: Option<image::DynamicImage>,
|
||||
}
|
||||
|
||||
|
@ -97,13 +95,14 @@ impl ServerList {
|
|||
elements: None,
|
||||
disconnect_reason,
|
||||
needs_reload: Rc::new(RefCell::new(false)),
|
||||
server_protocol_versions: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn reload_server_list(&mut self,
|
||||
renderer: &mut render::Renderer,
|
||||
ui_container: &mut ui::Container) {
|
||||
fn reload_server_list(
|
||||
&mut self,
|
||||
renderer: &mut render::Renderer,
|
||||
ui_container: &mut ui::Container,
|
||||
) {
|
||||
let elements = self.elements.as_mut().unwrap();
|
||||
*self.needs_reload.borrow_mut() = false;
|
||||
{
|
||||
|
@ -144,15 +143,12 @@ impl ServerList {
|
|||
let mut backr = back.borrow_mut();
|
||||
let address = address.clone();
|
||||
backr.add_hover_func(move |this, over, _| {
|
||||
this.colour.3 = if over {
|
||||
200
|
||||
} else {
|
||||
100
|
||||
};
|
||||
this.colour.3 = if over { 200 } else { 100 };
|
||||
false
|
||||
});
|
||||
backr.add_click_func(move |_, game| {
|
||||
game.screen_sys.replace_screen(Box::new(super::connecting::Connecting::new(&address)));
|
||||
game.screen_sys
|
||||
.replace_screen(Box::new(super::connecting::Connecting::new(&address)));
|
||||
game.connect_to(&address);
|
||||
true
|
||||
});
|
||||
|
@ -171,7 +167,6 @@ impl ServerList {
|
|||
.size(90.0, 90.0)
|
||||
.attach(&mut *back.borrow_mut());
|
||||
|
||||
|
||||
// Ping indicator
|
||||
let ping = ui::ImageBuilder::new()
|
||||
.texture("gui/icons")
|
||||
|
@ -235,9 +230,13 @@ impl ServerList {
|
|||
let sname = name.clone();
|
||||
let saddr = address.clone();
|
||||
btn.add_click_func(move |_, game| {
|
||||
game.screen_sys.replace_screen(Box::new(super::edit_server::EditServerEntry::new(
|
||||
Some((index, sname.clone(), saddr.clone()))
|
||||
)));
|
||||
game.screen_sys.replace_screen(Box::new(
|
||||
super::edit_server::EditServerEntry::new(Some((
|
||||
index,
|
||||
sname.clone(),
|
||||
saddr.clone(),
|
||||
))),
|
||||
));
|
||||
true
|
||||
})
|
||||
}
|
||||
|
@ -263,7 +262,9 @@ impl ServerList {
|
|||
|
||||
// Don't block the main thread whilst pinging the server
|
||||
thread::spawn(move || {
|
||||
match protocol::Conn::new(&address, protocol::SUPPORTED_PROTOCOLS[0]).and_then(|conn| conn.do_status()) {
|
||||
match protocol::Conn::new(&address, protocol::SUPPORTED_PROTOCOLS[0])
|
||||
.and_then(|conn| conn.do_status())
|
||||
{
|
||||
Ok(res) => {
|
||||
let mut desc = res.0.description;
|
||||
format::convert_legacy(&mut desc);
|
||||
|
@ -275,7 +276,6 @@ impl ServerList {
|
|||
None
|
||||
};
|
||||
drop(send.send(PingInfo {
|
||||
address,
|
||||
motd: desc,
|
||||
ping: res.1,
|
||||
exists: true,
|
||||
|
@ -283,6 +283,7 @@ impl ServerList {
|
|||
max: res.0.players.max,
|
||||
protocol_version: res.0.version.protocol,
|
||||
protocol_name: res.0.version.name,
|
||||
forge_mods: res.0.forge_mods,
|
||||
favicon,
|
||||
}));
|
||||
}
|
||||
|
@ -291,7 +292,6 @@ impl ServerList {
|
|||
let mut msg = TextComponent::new(&e);
|
||||
msg.modifier.color = Some(format::Color::Red);
|
||||
let _ = send.send(PingInfo {
|
||||
address,
|
||||
motd: Component::Text(msg),
|
||||
ping: Duration::new(99999, 0),
|
||||
exists: false,
|
||||
|
@ -299,6 +299,7 @@ impl ServerList {
|
|||
max: 0,
|
||||
protocol_version: 0,
|
||||
protocol_name: "".to_owned(),
|
||||
forge_mods: vec![],
|
||||
favicon: None,
|
||||
});
|
||||
}
|
||||
|
@ -348,9 +349,8 @@ impl super::Screen for ServerList {
|
|||
.attach(&mut *add);
|
||||
add.add_text(txt);
|
||||
add.add_click_func(move |_, game| {
|
||||
game.screen_sys.replace_screen(Box::new(super::edit_server::EditServerEntry::new(
|
||||
None
|
||||
)));
|
||||
game.screen_sys
|
||||
.replace_screen(Box::new(super::edit_server::EditServerEntry::new(None)));
|
||||
true
|
||||
})
|
||||
}
|
||||
|
@ -370,7 +370,8 @@ impl super::Screen for ServerList {
|
|||
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
|
||||
.attach(&mut *options);
|
||||
options.add_click_func(|_, game| {
|
||||
game.screen_sys.add_screen(Box::new(super::SettingsMenu::new(game.vars.clone(), false)));
|
||||
game.screen_sys
|
||||
.add_screen(Box::new(super::SettingsMenu::new(game.vars.clone(), false)));
|
||||
true
|
||||
});
|
||||
}
|
||||
|
@ -389,7 +390,10 @@ impl super::Screen for ServerList {
|
|||
let background = ui::ImageBuilder::new()
|
||||
.texture("steven:solid")
|
||||
.position(0.0, 3.0)
|
||||
.size(width.max(renderer.ui.size_of_string("Disconnected")) + 4.0, height + 4.0 + 16.0)
|
||||
.size(
|
||||
width.max(renderer.ui.size_of_string("Disconnected")) + 4.0,
|
||||
height + 4.0 + 16.0,
|
||||
)
|
||||
.colour((0, 0, 0, 100))
|
||||
.alignment(ui::VAttach::Top, ui::HAttach::Center)
|
||||
.draw_index(10)
|
||||
|
@ -438,10 +442,12 @@ impl super::Screen for ServerList {
|
|||
self.elements = None
|
||||
}
|
||||
|
||||
fn tick(&mut self,
|
||||
delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
ui_container: &mut ui::Container) -> Option<Box<super::Screen>> {
|
||||
fn tick(
|
||||
&mut self,
|
||||
delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
ui_container: &mut ui::Container,
|
||||
) -> Option<Box<dyn super::Screen>> {
|
||||
if *self.needs_reload.borrow() {
|
||||
self.reload_server_list(renderer, ui_container);
|
||||
}
|
||||
|
@ -471,20 +477,23 @@ impl super::Screen for ServerList {
|
|||
s.motd.borrow_mut().set_text(res.motd);
|
||||
// Selects the icon for the given ping range
|
||||
// TODO: switch to as_millis() experimental duration_as_u128 #50202 once available?
|
||||
let ping_ms = (res.ping.subsec_nanos() as f64)/1000000.0 + (res.ping.as_secs() as f64)*1000.0;
|
||||
let ping_ms = (res.ping.subsec_nanos() as f64) / 1000000.0
|
||||
+ (res.ping.as_secs() as f64) * 1000.0;
|
||||
let y = match ping_ms.round() as u64 {
|
||||
_x @ 0 ... 75 => 16.0 / 256.0,
|
||||
_x @ 76 ... 150 => 24.0 / 256.0,
|
||||
_x @ 151 ... 225 => 32.0 / 256.0,
|
||||
_x @ 226 ... 350 => 40.0 / 256.0,
|
||||
_x @ 351 ... 999 => 48.0 / 256.0,
|
||||
_x @ 0..=75 => 16.0 / 256.0,
|
||||
_x @ 76..=150 => 24.0 / 256.0,
|
||||
_x @ 151..=225 => 32.0 / 256.0,
|
||||
_x @ 226..=350 => 40.0 / 256.0,
|
||||
_x @ 351..=999 => 48.0 / 256.0,
|
||||
_ => 56.0 / 256.0,
|
||||
};
|
||||
s.ping.borrow_mut().texture_coords.1 = y;
|
||||
if res.exists {
|
||||
{
|
||||
let mut players = s.players.borrow_mut();
|
||||
let txt = if protocol::SUPPORTED_PROTOCOLS.contains(&res.protocol_version) {
|
||||
let txt = if protocol::SUPPORTED_PROTOCOLS
|
||||
.contains(&res.protocol_version)
|
||||
{
|
||||
players.colour.1 = 255;
|
||||
players.colour.2 = 255;
|
||||
format!("{}/{}", res.online, res.max)
|
||||
|
@ -494,28 +503,30 @@ impl super::Screen for ServerList {
|
|||
format!("Out of date {}/{}", res.online, res.max)
|
||||
};
|
||||
players.text = txt;
|
||||
|
||||
// TODO: store in memory instead of disk? but where?
|
||||
self.server_protocol_versions.insert(res.address, res.protocol_version);
|
||||
let mut out = fs::File::create("server_versions.json").unwrap();
|
||||
serde_json::to_writer_pretty(&mut out, &self.server_protocol_versions).unwrap();
|
||||
}
|
||||
let mut txt = TextComponent::new(&res.protocol_name);
|
||||
let sm =
|
||||
format!("{} mods + {}", res.forge_mods.len(), res.protocol_name);
|
||||
let st = if res.forge_mods.len() > 0 {
|
||||
&sm
|
||||
} else {
|
||||
&res.protocol_name
|
||||
};
|
||||
let mut txt = TextComponent::new(&st);
|
||||
txt.modifier.color = Some(format::Color::Yellow);
|
||||
let mut msg = Component::Text(txt);
|
||||
format::convert_legacy(&mut msg);
|
||||
s.version.borrow_mut().set_text(msg);
|
||||
}
|
||||
if let Some(favicon) = res.favicon {
|
||||
let name: String = std::iter::repeat(()).map(|()| rand::thread_rng()
|
||||
.sample(&rand::distributions::Alphanumeric))
|
||||
.take(30)
|
||||
.collect();
|
||||
let name: String = std::iter::repeat(())
|
||||
.map(|()| {
|
||||
rand::thread_rng().sample(&rand::distributions::Alphanumeric)
|
||||
})
|
||||
.take(30)
|
||||
.collect();
|
||||
let tex = renderer.get_textures_ref();
|
||||
s.icon_texture = Some(name.clone());
|
||||
let icon_tex = tex.write()
|
||||
.unwrap()
|
||||
.put_dynamic(&name, favicon);
|
||||
let icon_tex = tex.write().unwrap().put_dynamic(&name, favicon);
|
||||
s.icon.borrow_mut().texture = icon_tex.name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::console;
|
||||
use crate::render;
|
||||
use crate::ui;
|
||||
use crate::settings;
|
||||
use crate::ui;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -13,7 +13,7 @@ pub struct UIElements {
|
|||
pub struct SettingsMenu {
|
||||
_vars: Rc<console::Vars>,
|
||||
elements: Option<UIElements>,
|
||||
show_disconnect_button: bool
|
||||
show_disconnect_button: bool,
|
||||
}
|
||||
|
||||
impl SettingsMenu {
|
||||
|
@ -21,7 +21,7 @@ impl SettingsMenu {
|
|||
SettingsMenu {
|
||||
_vars: vars,
|
||||
elements: None,
|
||||
show_disconnect_button: show_disconnect_button
|
||||
show_disconnect_button: show_disconnect_button,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,8 @@ impl super::Screen for SettingsMenu {
|
|||
.attach(&mut *audio_settings);
|
||||
audio_settings.add_text(txt);
|
||||
audio_settings.add_click_func(|_, game| {
|
||||
game.screen_sys.add_screen(Box::new(AudioSettingsMenu::new(game.vars.clone())));
|
||||
game.screen_sys
|
||||
.add_screen(Box::new(AudioSettingsMenu::new(game.vars.clone())));
|
||||
true
|
||||
});
|
||||
}
|
||||
|
@ -70,7 +71,8 @@ impl super::Screen for SettingsMenu {
|
|||
.attach(&mut *video_settings);
|
||||
video_settings.add_text(txt);
|
||||
video_settings.add_click_func(|_, game| {
|
||||
game.screen_sys.add_screen(Box::new(VideoSettingsMenu::new(game.vars.clone())));
|
||||
game.screen_sys
|
||||
.add_screen(Box::new(VideoSettingsMenu::new(game.vars.clone())));
|
||||
true
|
||||
});
|
||||
}
|
||||
|
@ -142,7 +144,8 @@ impl super::Screen for SettingsMenu {
|
|||
disconnect_button.add_text(txt);
|
||||
disconnect_button.add_click_func(|_, game| {
|
||||
game.server.disconnect(None);
|
||||
game.screen_sys.replace_screen(Box::new(super::ServerList::new(None)));
|
||||
game.screen_sys
|
||||
.replace_screen(Box::new(super::ServerList::new(None)));
|
||||
true
|
||||
});
|
||||
}
|
||||
|
@ -153,14 +156,18 @@ impl super::Screen for SettingsMenu {
|
|||
background,
|
||||
_buttons: buttons,
|
||||
});
|
||||
|
||||
}
|
||||
fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
|
||||
self.elements = None;
|
||||
}
|
||||
|
||||
// Called every frame the screen is active
|
||||
fn tick(&mut self, _delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Option<Box<super::Screen>> {
|
||||
fn tick(
|
||||
&mut self,
|
||||
_delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
ui_container: &mut ui::Container,
|
||||
) -> Option<Box<dyn super::Screen>> {
|
||||
let elements = self.elements.as_mut().unwrap();
|
||||
{
|
||||
let mode = ui_container.mode;
|
||||
|
@ -178,9 +185,7 @@ impl super::Screen for SettingsMenu {
|
|||
}
|
||||
|
||||
// Events
|
||||
fn on_scroll(&mut self, _x: f64, _y: f64) {
|
||||
|
||||
}
|
||||
fn on_scroll(&mut self, _x: f64, _y: f64) {}
|
||||
|
||||
fn is_closable(&self) -> bool {
|
||||
true
|
||||
|
@ -227,11 +232,14 @@ impl super::Screen for VideoSettingsMenu {
|
|||
{
|
||||
let mut fov_setting = fov_setting.borrow_mut();
|
||||
let txt = ui::TextBuilder::new()
|
||||
.text(format!("FOV: {}", match r_fov {
|
||||
90 => "Normal".into(),
|
||||
110 => "Quake pro".into(),
|
||||
val => val.to_string(),
|
||||
}))
|
||||
.text(format!(
|
||||
"FOV: {}",
|
||||
match r_fov {
|
||||
90 => "Normal".into(),
|
||||
110 => "Quake pro".into(),
|
||||
val => val.to_string(),
|
||||
}
|
||||
))
|
||||
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
|
||||
.attach(&mut *fov_setting);
|
||||
fov_setting.add_text(txt);
|
||||
|
@ -246,14 +254,18 @@ impl super::Screen for VideoSettingsMenu {
|
|||
{
|
||||
let mut vsync_setting = vsync_setting.borrow_mut();
|
||||
let txt = ui::TextBuilder::new()
|
||||
.text(format!("VSync: {}", if r_vsync { "Enabled" } else { "Disabled" }))
|
||||
.text(format!(
|
||||
"VSync: {}",
|
||||
if r_vsync { "Enabled" } else { "Disabled" }
|
||||
))
|
||||
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
|
||||
.attach(&mut *vsync_setting);
|
||||
let txt_vsync = txt.clone();
|
||||
vsync_setting.add_text(txt);
|
||||
vsync_setting.add_click_func(move |_, game| {
|
||||
let r_vsync = !*game.vars.get(settings::R_VSYNC);
|
||||
txt_vsync.borrow_mut().text = format!("VSync: {}", if r_vsync { "Enabled" } else { "Disabled" });
|
||||
txt_vsync.borrow_mut().text =
|
||||
format!("VSync: {}", if r_vsync { "Enabled" } else { "Disabled" });
|
||||
game.vars.set(settings::R_VSYNC, r_vsync);
|
||||
true
|
||||
});
|
||||
|
@ -269,10 +281,13 @@ impl super::Screen for VideoSettingsMenu {
|
|||
{
|
||||
let mut fps_setting = fps_setting.borrow_mut();
|
||||
let txt = ui::TextBuilder::new()
|
||||
.text(format!("FPS cap: {}", match r_max_fps {
|
||||
0 => "Unlimited".into(),
|
||||
val => val.to_string(),
|
||||
}))
|
||||
.text(format!(
|
||||
"FPS cap: {}",
|
||||
match r_max_fps {
|
||||
0 => "Unlimited".into(),
|
||||
val => val.to_string(),
|
||||
}
|
||||
))
|
||||
.alignment(ui::VAttach::Middle, ui::HAttach::Center)
|
||||
.attach(&mut *fps_setting);
|
||||
fps_setting.add_text(txt);
|
||||
|
@ -302,14 +317,18 @@ impl super::Screen for VideoSettingsMenu {
|
|||
background,
|
||||
_buttons: buttons,
|
||||
});
|
||||
|
||||
}
|
||||
fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
|
||||
self.elements = None;
|
||||
}
|
||||
|
||||
// Called every frame the screen is active
|
||||
fn tick(&mut self, _delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Option<Box<super::Screen>> {
|
||||
fn tick(
|
||||
&mut self,
|
||||
_delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
ui_container: &mut ui::Container,
|
||||
) -> Option<Box<dyn super::Screen>> {
|
||||
let elements = self.elements.as_mut().unwrap();
|
||||
{
|
||||
let mode = ui_container.mode;
|
||||
|
@ -327,9 +346,7 @@ impl super::Screen for VideoSettingsMenu {
|
|||
}
|
||||
|
||||
// Events
|
||||
fn on_scroll(&mut self, _x: f64, _y: f64) {
|
||||
|
||||
}
|
||||
fn on_scroll(&mut self, _x: f64, _y: f64) {}
|
||||
|
||||
fn is_closable(&self) -> bool {
|
||||
true
|
||||
|
@ -338,14 +355,14 @@ impl super::Screen for VideoSettingsMenu {
|
|||
|
||||
pub struct AudioSettingsMenu {
|
||||
_vars: Rc<console::Vars>,
|
||||
elements: Option<UIElements>
|
||||
elements: Option<UIElements>,
|
||||
}
|
||||
|
||||
impl AudioSettingsMenu {
|
||||
pub fn new(vars: Rc<console::Vars>) -> AudioSettingsMenu {
|
||||
AudioSettingsMenu {
|
||||
_vars: vars,
|
||||
elements: None
|
||||
elements: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -387,14 +404,18 @@ impl super::Screen for AudioSettingsMenu {
|
|||
background,
|
||||
_buttons: buttons,
|
||||
});
|
||||
|
||||
}
|
||||
fn on_deactive(&mut self, _renderer: &mut render::Renderer, _ui_container: &mut ui::Container) {
|
||||
self.elements = None;
|
||||
}
|
||||
|
||||
// Called every frame the screen is active
|
||||
fn tick(&mut self, _delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Option<Box<super::Screen>> {
|
||||
fn tick(
|
||||
&mut self,
|
||||
_delta: f64,
|
||||
renderer: &mut render::Renderer,
|
||||
ui_container: &mut ui::Container,
|
||||
) -> Option<Box<dyn super::Screen>> {
|
||||
let elements = self.elements.as_mut().unwrap();
|
||||
{
|
||||
let mode = ui_container.mode;
|
||||
|
@ -412,9 +433,7 @@ impl super::Screen for AudioSettingsMenu {
|
|||
}
|
||||
|
||||
// Events
|
||||
fn on_scroll(&mut self, _x: f64, _y: f64) {
|
||||
|
||||
}
|
||||
fn on_scroll(&mut self, _x: f64, _y: f64) {}
|
||||
|
||||
fn is_closable(&self) -> bool {
|
||||
true
|
||||
|
|
1261
src/server/mod.rs
1261
src/server/mod.rs
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,6 @@
|
|||
|
||||
use crate::protocol::Serializable;
|
||||
use crate::protocol::packet::play::serverbound::PluginMessageServerbound;
|
||||
use crate::protocol::packet::play::serverbound::PluginMessageServerbound_i16;
|
||||
use crate::protocol::{Serializable, VarShort};
|
||||
|
||||
pub struct Brand {
|
||||
pub brand: String,
|
||||
|
@ -9,7 +8,7 @@ pub struct Brand {
|
|||
|
||||
impl Brand {
|
||||
pub fn as_message(self) -> PluginMessageServerbound {
|
||||
let protocol_version = unsafe { crate::protocol::CURRENT_PROTOCOL_VERSION };
|
||||
let protocol_version = crate::protocol::current_protocol_version();
|
||||
|
||||
let channel_name = if protocol_version >= 404 {
|
||||
"minecraft:brand"
|
||||
|
@ -31,8 +30,7 @@ impl Brand {
|
|||
Serializable::write_to(&self.brand, &mut data).unwrap();
|
||||
PluginMessageServerbound_i16 {
|
||||
channel: "MC|Brand".into(),
|
||||
data: crate::protocol::LenPrefixedBytes::<i16>::new(data),
|
||||
data: crate::protocol::LenPrefixedBytes::<VarShort>::new(data),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
use crate::render;
|
||||
use crate::render::model;
|
||||
use cgmath::{Vector3, Matrix4, Decomposed, Rotation3, Rad, Quaternion};
|
||||
use cgmath::{Decomposed, Matrix4, Quaternion, Rad, Rotation3, Vector3};
|
||||
|
||||
pub struct SunModel {
|
||||
sun: model::ModelKey,
|
||||
|
@ -12,7 +11,6 @@ pub struct SunModel {
|
|||
const SIZE: f32 = 50.0;
|
||||
|
||||
impl SunModel {
|
||||
|
||||
pub fn new(renderer: &mut render::Renderer) -> SunModel {
|
||||
SunModel {
|
||||
sun: SunModel::generate_sun(renderer),
|
||||
|
@ -71,26 +69,123 @@ impl SunModel {
|
|||
renderer.model.create_model(
|
||||
model::SUN,
|
||||
vec![vec![
|
||||
model::Vertex{x: 0.0, y: -SIZE, z: -SIZE, texture_x: 0.0, texture_y: 1.0, texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0},
|
||||
model::Vertex{x: 0.0, y: SIZE, z: -SIZE, texture_x: 0.0, texture_y: 0.0, texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0},
|
||||
model::Vertex{x: 0.0, y: -SIZE, z: SIZE, texture_x: 1.0, texture_y: 1.0, texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0},
|
||||
model::Vertex{x: 0.0, y: SIZE, z: SIZE, texture_x: 1.0, texture_y: 0.0, texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0}
|
||||
]]
|
||||
model::Vertex {
|
||||
x: 0.0,
|
||||
y: -SIZE,
|
||||
z: -SIZE,
|
||||
texture_x: 0.0,
|
||||
texture_y: 1.0,
|
||||
texture: tex.clone(),
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
a: 0,
|
||||
id: 0,
|
||||
},
|
||||
model::Vertex {
|
||||
x: 0.0,
|
||||
y: SIZE,
|
||||
z: -SIZE,
|
||||
texture_x: 0.0,
|
||||
texture_y: 0.0,
|
||||
texture: tex.clone(),
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
a: 0,
|
||||
id: 0,
|
||||
},
|
||||
model::Vertex {
|
||||
x: 0.0,
|
||||
y: -SIZE,
|
||||
z: SIZE,
|
||||
texture_x: 1.0,
|
||||
texture_y: 1.0,
|
||||
texture: tex.clone(),
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
a: 0,
|
||||
id: 0,
|
||||
},
|
||||
model::Vertex {
|
||||
x: 0.0,
|
||||
y: SIZE,
|
||||
z: SIZE,
|
||||
texture_x: 1.0,
|
||||
texture_y: 0.0,
|
||||
texture: tex.clone(),
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
a: 0,
|
||||
id: 0,
|
||||
},
|
||||
]],
|
||||
)
|
||||
}
|
||||
|
||||
pub fn generate_moon(renderer: &mut render::Renderer, phase: i32) -> model::ModelKey {
|
||||
let tex = render::Renderer::get_texture(renderer.get_textures_ref(), "environment/moon_phases");
|
||||
let tex =
|
||||
render::Renderer::get_texture(renderer.get_textures_ref(), "environment/moon_phases");
|
||||
let mpx = (phase % 4) as f64 * (1.0 / 4.0);
|
||||
let mpy = (phase / 4) as f64 * (1.0 / 2.0);
|
||||
renderer.model.create_model(
|
||||
model::SUN,
|
||||
vec![vec![
|
||||
model::Vertex{x: 0.0, y: -SIZE, z: -SIZE, texture_x: mpx, texture_y: mpy + (1.0 / 2.0), texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0},
|
||||
model::Vertex{x: 0.0, y: SIZE, z: -SIZE, texture_x: mpx, texture_y: mpy, texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0},
|
||||
model::Vertex{x: 0.0, y: -SIZE, z: SIZE, texture_x: mpx + (1.0 / 4.0), texture_y: mpy + (1.0 / 2.0), texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0},
|
||||
model::Vertex{x: 0.0, y: SIZE, z: SIZE, texture_x: mpx + (1.0 / 4.0), texture_y: mpy, texture: tex.clone(), r: 255, g: 255, b: 255, a: 0, id: 0}
|
||||
]]
|
||||
model::Vertex {
|
||||
x: 0.0,
|
||||
y: -SIZE,
|
||||
z: -SIZE,
|
||||
texture_x: mpx,
|
||||
texture_y: mpy + (1.0 / 2.0),
|
||||
texture: tex.clone(),
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
a: 0,
|
||||
id: 0,
|
||||
},
|
||||
model::Vertex {
|
||||
x: 0.0,
|
||||
y: SIZE,
|
||||
z: -SIZE,
|
||||
texture_x: mpx,
|
||||
texture_y: mpy,
|
||||
texture: tex.clone(),
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
a: 0,
|
||||
id: 0,
|
||||
},
|
||||
model::Vertex {
|
||||
x: 0.0,
|
||||
y: -SIZE,
|
||||
z: SIZE,
|
||||
texture_x: mpx + (1.0 / 4.0),
|
||||
texture_y: mpy + (1.0 / 2.0),
|
||||
texture: tex.clone(),
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
a: 0,
|
||||
id: 0,
|
||||
},
|
||||
model::Vertex {
|
||||
x: 0.0,
|
||||
y: SIZE,
|
||||
z: SIZE,
|
||||
texture_x: mpx + (1.0 / 4.0),
|
||||
texture_y: mpy,
|
||||
texture: tex.clone(),
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
a: 0,
|
||||
id: 0,
|
||||
},
|
||||
]],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
use crate::world;
|
||||
use crate::world::block;
|
||||
use crate::shared::{Position, Direction};
|
||||
use cgmath;
|
||||
use crate::render;
|
||||
use crate::render::model;
|
||||
use crate::shared::{Direction, Position};
|
||||
use crate::world;
|
||||
use crate::world::block;
|
||||
use cgmath;
|
||||
use collision::{self, Aabb};
|
||||
|
||||
pub struct Info {
|
||||
|
@ -17,13 +16,13 @@ impl Info {
|
|||
pub fn new() -> Info {
|
||||
Info {
|
||||
model: None,
|
||||
last_block: block::Air{},
|
||||
last_block: block::Air {},
|
||||
last_pos: Position::new(0, 0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self, renderer: &mut render::Renderer) {
|
||||
self.last_block = block::Air{};
|
||||
self.last_block = block::Air {};
|
||||
if let Some(model) = self.model.take() {
|
||||
renderer.model.remove_model(model);
|
||||
}
|
||||
|
@ -44,16 +43,27 @@ impl Info {
|
|||
let tex = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid");
|
||||
|
||||
for bound in bl.get_collision_boxes() {
|
||||
let bound = bound.add_v(cgmath::Vector3::new(pos.x as f64, pos.y as f64, pos.z as f64));
|
||||
let bound = bound.add_v(cgmath::Vector3::new(
|
||||
pos.x as f64,
|
||||
pos.y as f64,
|
||||
pos.z as f64,
|
||||
));
|
||||
for point in [
|
||||
(bound.min.x, bound.min.z),
|
||||
(bound.min.x, bound.max.z),
|
||||
(bound.max.x, bound.min.z),
|
||||
(bound.max.x, bound.max.z),
|
||||
].into_iter() {
|
||||
model::append_box(&mut parts,
|
||||
(point.0-LINE_SIZE) as f32, (bound.min.y-LINE_SIZE) as f32, (point.1-LINE_SIZE) as f32,
|
||||
(LINE_SIZE*2.0) as f32, ((bound.max.y-bound.min.y)+LINE_SIZE*2.0) as f32, (LINE_SIZE*2.0) as f32,
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
model::append_box(
|
||||
&mut parts,
|
||||
(point.0 - LINE_SIZE) as f32,
|
||||
(bound.min.y - LINE_SIZE) as f32,
|
||||
(point.1 - LINE_SIZE) as f32,
|
||||
(LINE_SIZE * 2.0) as f32,
|
||||
((bound.max.y - bound.min.y) + LINE_SIZE * 2.0) as f32,
|
||||
(LINE_SIZE * 2.0) as f32,
|
||||
[
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
|
@ -61,7 +71,8 @@ impl Info {
|
|||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
]);
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
for point in [
|
||||
|
@ -69,10 +80,17 @@ impl Info {
|
|||
(bound.min.x, bound.max.z, bound.max.x, bound.max.z),
|
||||
(bound.min.x, bound.min.z, bound.min.x, bound.max.z),
|
||||
(bound.max.x, bound.min.z, bound.max.x, bound.max.z),
|
||||
].into_iter() {
|
||||
model::append_box(&mut parts,
|
||||
(point.0-LINE_SIZE) as f32, (bound.min.y-LINE_SIZE) as f32, (point.1-LINE_SIZE) as f32,
|
||||
((point.2-point.0)+(LINE_SIZE*2.0)) as f32, (LINE_SIZE*2.0) as f32, ((point.3-point.1)+(LINE_SIZE*2.0)) as f32,
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
model::append_box(
|
||||
&mut parts,
|
||||
(point.0 - LINE_SIZE) as f32,
|
||||
(bound.min.y - LINE_SIZE) as f32,
|
||||
(point.1 - LINE_SIZE) as f32,
|
||||
((point.2 - point.0) + (LINE_SIZE * 2.0)) as f32,
|
||||
(LINE_SIZE * 2.0) as f32,
|
||||
((point.3 - point.1) + (LINE_SIZE * 2.0)) as f32,
|
||||
[
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
|
@ -80,10 +98,16 @@ impl Info {
|
|||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
]);
|
||||
model::append_box(&mut parts,
|
||||
(point.0-LINE_SIZE) as f32, (bound.max.y-LINE_SIZE) as f32, (point.1-LINE_SIZE) as f32,
|
||||
((point.2-point.0)+(LINE_SIZE*2.0)) as f32, (LINE_SIZE*2.0) as f32, ((point.3-point.1)+(LINE_SIZE*2.0)) as f32,
|
||||
],
|
||||
);
|
||||
model::append_box(
|
||||
&mut parts,
|
||||
(point.0 - LINE_SIZE) as f32,
|
||||
(bound.max.y - LINE_SIZE) as f32,
|
||||
(point.1 - LINE_SIZE) as f32,
|
||||
((point.2 - point.0) + (LINE_SIZE * 2.0)) as f32,
|
||||
(LINE_SIZE * 2.0) as f32,
|
||||
((point.3 - point.1) + (LINE_SIZE * 2.0)) as f32,
|
||||
[
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
|
@ -91,7 +115,8 @@ impl Info {
|
|||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
Some(tex.clone()),
|
||||
]);
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,7 +130,15 @@ impl Info {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn test_block(world: &world::World, pos: Position, s: cgmath::Vector3<f64>, d: cgmath::Vector3<f64>) -> (bool, Option<(Position, block::Block, Direction, cgmath::Vector3<f64>)>) {
|
||||
pub fn test_block(
|
||||
world: &world::World,
|
||||
pos: Position,
|
||||
s: cgmath::Vector3<f64>,
|
||||
d: cgmath::Vector3<f64>,
|
||||
) -> (
|
||||
bool,
|
||||
Option<(Position, block::Block, Direction, cgmath::Vector3<f64>)>,
|
||||
) {
|
||||
let block = world.get_block(pos);
|
||||
let posf = cgmath::Vector3::new(pos.x as f64, pos.y as f64, pos.z as f64);
|
||||
for bound in block.get_collision_boxes() {
|
||||
|
@ -137,7 +170,11 @@ fn find_face(bound: collision::Aabb3<f64>, hit: cgmath::Vector3<f64>) -> Directi
|
|||
}
|
||||
}
|
||||
|
||||
fn intersects_line(bound: collision::Aabb3<f64>, origin: cgmath::Vector3<f64>, dir: cgmath::Vector3<f64>) -> Option<cgmath::Vector3<f64>> {
|
||||
fn intersects_line(
|
||||
bound: collision::Aabb3<f64>,
|
||||
origin: cgmath::Vector3<f64>,
|
||||
dir: cgmath::Vector3<f64>,
|
||||
) -> Option<cgmath::Vector3<f64>> {
|
||||
const RIGHT: usize = 0;
|
||||
const LEFT: usize = 1;
|
||||
const MIDDLE: usize = 2;
|
||||
|
@ -145,7 +182,7 @@ fn intersects_line(bound: collision::Aabb3<f64>, origin: cgmath::Vector3<f64>, d
|
|||
let mut candidate_plane = [0.0, 0.0, 0.0];
|
||||
let mut max_t = [0.0, 0.0, 0.0];
|
||||
let mut inside = true;
|
||||
for i in 0 .. 3 {
|
||||
for i in 0..3 {
|
||||
if origin[i] < bound.min[i] {
|
||||
quadrant[i] = LEFT;
|
||||
candidate_plane[i] = bound.min[i];
|
||||
|
@ -162,13 +199,13 @@ fn intersects_line(bound: collision::Aabb3<f64>, origin: cgmath::Vector3<f64>, d
|
|||
return Some(origin);
|
||||
}
|
||||
|
||||
for i in 0 .. 3 {
|
||||
for i in 0..3 {
|
||||
if quadrant[i] != MIDDLE && dir[i] != 0.0 {
|
||||
max_t[i] = (candidate_plane[i] - origin[i]) / dir[i];
|
||||
}
|
||||
}
|
||||
let mut which_plane = 0;
|
||||
for i in 1 .. 3 {
|
||||
for i in 1..3 {
|
||||
if max_t[which_plane] < max_t[i] {
|
||||
which_plane = i;
|
||||
}
|
||||
|
@ -178,7 +215,7 @@ fn intersects_line(bound: collision::Aabb3<f64>, origin: cgmath::Vector3<f64>, d
|
|||
}
|
||||
|
||||
let mut coord = cgmath::Vector3::new(0.0, 0.0, 0.0);
|
||||
for i in 0 .. 3 {
|
||||
for i in 0..3 {
|
||||
if which_plane != i {
|
||||
coord[i] = origin[i] + max_t[which_plane] * dir[i];
|
||||
if coord[i] < bound.min[i] || coord[i] > bound.max[i] {
|
||||
|
@ -191,8 +228,16 @@ fn intersects_line(bound: collision::Aabb3<f64>, origin: cgmath::Vector3<f64>, d
|
|||
Some(coord)
|
||||
}
|
||||
|
||||
pub fn trace_ray<F, R>(world: &world::World, max: f64, s: cgmath::Vector3<f64>, d: cgmath::Vector3<f64>, collide_func: F) -> Option<R>
|
||||
where F: Fn(&world::World, Position, cgmath::Vector3<f64>, cgmath::Vector3<f64>,) -> (bool, Option<R>) {
|
||||
pub fn trace_ray<F, R>(
|
||||
world: &world::World,
|
||||
max: f64,
|
||||
s: cgmath::Vector3<f64>,
|
||||
d: cgmath::Vector3<f64>,
|
||||
collide_func: F,
|
||||
) -> Option<R>
|
||||
where
|
||||
F: Fn(&world::World, Position, cgmath::Vector3<f64>, cgmath::Vector3<f64>) -> (bool, Option<R>),
|
||||
{
|
||||
struct Gen {
|
||||
count: i32,
|
||||
base: f64,
|
||||
|
@ -208,11 +253,7 @@ pub fn trace_ray<F, R>(world: &world::World, max: f64, s: cgmath::Vector3<f64>,
|
|||
} else {
|
||||
0.0
|
||||
};
|
||||
Gen {
|
||||
count: 0,
|
||||
base,
|
||||
d,
|
||||
}
|
||||
Gen { count: 0, base, d }
|
||||
}
|
||||
|
||||
fn next(&mut self) -> f64 {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::console;
|
||||
use glutin::event::VirtualKeyCode;
|
||||
use std::marker::PhantomData;
|
||||
use glutin::VirtualKeyCode;
|
||||
// Might just rename this to settings.rs
|
||||
|
||||
pub const R_MAX_FPS: console::CVar<i64> = console::CVar {
|
||||
|
@ -40,24 +40,39 @@ pub const CL_MASTER_VOLUME: console::CVar<i64> = console::CVar {
|
|||
};
|
||||
|
||||
macro_rules! create_keybind {
|
||||
($keycode:ident, $name:expr, $description:expr) => (console::CVar {
|
||||
ty: PhantomData,
|
||||
name: $name,
|
||||
description: $description,
|
||||
mutable: true,
|
||||
serializable: true,
|
||||
default: &|| VirtualKeyCode::$keycode as i64
|
||||
})
|
||||
($keycode:ident, $name:expr, $description:expr) => {
|
||||
console::CVar {
|
||||
ty: PhantomData,
|
||||
name: $name,
|
||||
description: $description,
|
||||
mutable: true,
|
||||
serializable: true,
|
||||
default: &|| VirtualKeyCode::$keycode as i64,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub const CL_KEYBIND_FORWARD: console::CVar<i64> = create_keybind!(W, "cl_keybind_forward", "Keybinding for moving forward");
|
||||
pub const CL_KEYBIND_BACKWARD: console::CVar<i64> = create_keybind!(S, "cl_keybind_backward", "Keybinding for moving backward");
|
||||
pub const CL_KEYBIND_LEFT: console::CVar<i64> = create_keybind!(A, "cl_keybind_left", "Keybinding for moving the left");
|
||||
pub const CL_KEYBIND_RIGHT: console::CVar<i64> = create_keybind!(D, "cl_keybind_right", "Keybinding for moving to the right");
|
||||
pub const CL_KEYBIND_OPEN_INV: console::CVar<i64> = create_keybind!(E, "cl_keybind_open_inv", "Keybinding for opening the inventory");
|
||||
pub const CL_KEYBIND_SNEAK: console::CVar<i64> = create_keybind!(LShift, "cl_keybind_sneak", "Keybinding for sneaking");
|
||||
pub const CL_KEYBIND_SPRINT: console::CVar<i64> = create_keybind!(LControl, "cl_keybind_sprint", "Keybinding for sprinting");
|
||||
pub const CL_KEYBIND_JUMP: console::CVar<i64> = create_keybind!(Space, "cl_keybind_jump", "Keybinding for jumping");
|
||||
pub const CL_KEYBIND_FORWARD: console::CVar<i64> =
|
||||
create_keybind!(W, "cl_keybind_forward", "Keybinding for moving forward");
|
||||
pub const CL_KEYBIND_BACKWARD: console::CVar<i64> =
|
||||
create_keybind!(S, "cl_keybind_backward", "Keybinding for moving backward");
|
||||
pub const CL_KEYBIND_LEFT: console::CVar<i64> =
|
||||
create_keybind!(A, "cl_keybind_left", "Keybinding for moving the left");
|
||||
pub const CL_KEYBIND_RIGHT: console::CVar<i64> =
|
||||
create_keybind!(D, "cl_keybind_right", "Keybinding for moving to the right");
|
||||
pub const CL_KEYBIND_OPEN_INV: console::CVar<i64> = create_keybind!(
|
||||
E,
|
||||
"cl_keybind_open_inv",
|
||||
"Keybinding for opening the inventory"
|
||||
);
|
||||
pub const CL_KEYBIND_SNEAK: console::CVar<i64> =
|
||||
create_keybind!(LShift, "cl_keybind_sneak", "Keybinding for sneaking");
|
||||
pub const CL_KEYBIND_SPRINT: console::CVar<i64> =
|
||||
create_keybind!(LControl, "cl_keybind_sprint", "Keybinding for sprinting");
|
||||
pub const CL_KEYBIND_JUMP: console::CVar<i64> =
|
||||
create_keybind!(Space, "cl_keybind_jump", "Keybinding for jumping");
|
||||
|
||||
pub const DOUBLE_JUMP_MS: u32 = 100;
|
||||
|
||||
pub fn register_vars(vars: &mut console::Vars) {
|
||||
vars.register(R_MAX_FPS);
|
||||
|
@ -88,15 +103,22 @@ pub enum Stevenkey {
|
|||
|
||||
impl Stevenkey {
|
||||
pub fn values() -> Vec<Stevenkey> {
|
||||
vec!(Stevenkey::Forward, Stevenkey::Backward, Stevenkey::Left,
|
||||
Stevenkey::Right, Stevenkey::OpenInv, Stevenkey::Sneak,
|
||||
Stevenkey::Sprint, Stevenkey::Jump)
|
||||
vec![
|
||||
Stevenkey::Forward,
|
||||
Stevenkey::Backward,
|
||||
Stevenkey::Left,
|
||||
Stevenkey::Right,
|
||||
Stevenkey::OpenInv,
|
||||
Stevenkey::Sneak,
|
||||
Stevenkey::Sprint,
|
||||
Stevenkey::Jump,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn get_by_keycode(keycode: VirtualKeyCode, vars: &console::Vars) -> Option<Stevenkey> {
|
||||
for steven_key in Stevenkey::values() {
|
||||
if keycode as i64 == *vars.get(steven_key.get_cvar()) {
|
||||
return Some(steven_key)
|
||||
return Some(steven_key);
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -111,7 +133,7 @@ impl Stevenkey {
|
|||
Stevenkey::OpenInv => CL_KEYBIND_OPEN_INV,
|
||||
Stevenkey::Sneak => CL_KEYBIND_SNEAK,
|
||||
Stevenkey::Sprint => CL_KEYBIND_SPRINT,
|
||||
Stevenkey::Jump => CL_KEYBIND_JUMP
|
||||
Stevenkey::Jump => CL_KEYBIND_JUMP,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::f64::consts;
|
||||
use crate::ui;
|
||||
use crate::render;
|
||||
use crate::resources;
|
||||
use crate::ui;
|
||||
use rand::{self, seq::SliceRandom};
|
||||
use rand_pcg;
|
||||
use std::f64::consts;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use rand;
|
||||
use rand::Rng;
|
||||
|
||||
pub struct Logo {
|
||||
_shadow: ui::BatchRef,
|
||||
|
@ -20,9 +19,10 @@ pub struct Logo {
|
|||
}
|
||||
|
||||
impl Logo {
|
||||
pub fn new(resources: Arc<RwLock<resources::Manager>>,
|
||||
ui_container: &mut ui::Container)
|
||||
-> Logo {
|
||||
pub fn new(
|
||||
resources: Arc<RwLock<resources::Manager>>,
|
||||
ui_container: &mut ui::Container,
|
||||
) -> Logo {
|
||||
let logo_str = {
|
||||
let res = resources.read().unwrap();
|
||||
let mut logo = res.open("steven", "logo/logo.txt").unwrap();
|
||||
|
@ -66,14 +66,15 @@ impl Logo {
|
|||
.colour((0, 0, 0, 100))
|
||||
.attach(&mut *shadow_batch.borrow_mut());
|
||||
|
||||
|
||||
ui::ImageBuilder::new()
|
||||
.texture("minecraft:blocks/planks_oak")
|
||||
.position(x as f64, y as f64)
|
||||
.size(4.0, 8.0)
|
||||
.texture_coords((
|
||||
(x % 16) as f64 / 16.0, (y % 16) as f64 / 16.0,
|
||||
4.0 / 16.0, 8.0 / 16.0
|
||||
(x % 16) as f64 / 16.0,
|
||||
(y % 16) as f64 / 16.0,
|
||||
4.0 / 16.0,
|
||||
8.0 / 16.0,
|
||||
))
|
||||
.colour((r, g, b, 255))
|
||||
.attach(&mut *layer0.borrow_mut());
|
||||
|
@ -101,8 +102,9 @@ impl Logo {
|
|||
text_strings.push(line.to_owned().replace("\r", ""));
|
||||
}
|
||||
}
|
||||
let mut r: rand::XorShiftRng = rand::SeedableRng::from_seed([45, 0, 0, 0, 64, 0, 0, 0, 32, 0, 0, 0, 12, 0, 0, 0]);
|
||||
r.shuffle(&mut text_strings[..]);
|
||||
let mut r: rand_pcg::Pcg32 =
|
||||
rand::SeedableRng::from_seed([45, 0, 0, 0, 64, 0, 0, 0, 32, 0, 0, 0, 12, 0, 0, 0]);
|
||||
text_strings.shuffle(&mut r);
|
||||
}
|
||||
|
||||
let txt = ui::TextBuilder::new()
|
||||
|
@ -147,7 +149,7 @@ impl Logo {
|
|||
if self.text_base_scale > 1.0 {
|
||||
self.text_base_scale = 1.0;
|
||||
}
|
||||
text.x =(-width / 2.0) * self.text_base_scale;
|
||||
text.x = (-width / 2.0) * self.text_base_scale;
|
||||
self.text_orig_x = text.x;
|
||||
}
|
||||
|
||||
|
@ -160,6 +162,6 @@ impl Logo {
|
|||
text.scale_x = (0.7 + (offset / 3.0)) * self.text_base_scale;
|
||||
text.scale_y = (0.7 + (offset / 3.0)) * self.text_base_scale;
|
||||
let scale = text.scale_x;
|
||||
text.x =self.text_orig_x * scale * self.text_base_scale;
|
||||
text.x = self.text_orig_x * scale * self.text_base_scale;
|
||||
}
|
||||
}
|
||||
|
|
410
src/ui/mod.rs
410
src/ui/mod.rs
|
@ -14,17 +14,17 @@
|
|||
|
||||
pub mod logo;
|
||||
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use crate::render;
|
||||
use crate::format;
|
||||
use glutin::VirtualKeyCode;
|
||||
use clipboard::{ClipboardProvider, ClipboardContext};
|
||||
use crate::render;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use clipboard::{ClipboardContext, ClipboardProvider};
|
||||
use glutin::event::VirtualKeyCode;
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
const SCALED_WIDTH: f64 = 854.0;
|
||||
const SCALED_HEIGHT: f64 = 480.0;
|
||||
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum Mode {
|
||||
Scaled,
|
||||
|
@ -55,8 +55,10 @@ struct Region {
|
|||
|
||||
impl Region {
|
||||
fn intersects(&self, o: &Region) -> bool {
|
||||
!(self.x + self.w < o.x || self.x > o.x + o.w || self.y + self.h < o.y ||
|
||||
self.y > o.y + o.h)
|
||||
!(self.x + self.w < o.x
|
||||
|| self.x > o.x + o.w
|
||||
|| self.y + self.h < o.y
|
||||
|| self.y > o.y + o.h)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,8 +305,13 @@ impl Container {
|
|||
Mode::Unscaled(scale) => (scale, scale),
|
||||
};
|
||||
|
||||
if self.last_sw != sw || self.last_sh != sh || self.last_width != width ||
|
||||
self.last_height != height || self.version != renderer.ui.version || self.last_mode != self.mode {
|
||||
if self.last_sw != sw
|
||||
|| self.last_sh != sh
|
||||
|| self.last_width != width
|
||||
|| self.last_height != height
|
||||
|| self.version != renderer.ui.version
|
||||
|| self.last_mode != self.mode
|
||||
{
|
||||
self.last_sw = sw;
|
||||
self.last_sh = sh;
|
||||
self.last_width = width;
|
||||
|
@ -323,9 +330,12 @@ impl Container {
|
|||
|
||||
// If we don't have an element focused, focus one
|
||||
if !self.focusable_elements.is_empty()
|
||||
&& !self.focusable_elements.iter()
|
||||
.flat_map(|v| v.upgrade())
|
||||
.any(|v| v.is_focused()) {
|
||||
&& !self
|
||||
.focusable_elements
|
||||
.iter()
|
||||
.flat_map(|v| v.upgrade())
|
||||
.any(|v| v.is_focused())
|
||||
{
|
||||
self.cycle_focus()
|
||||
}
|
||||
|
||||
|
@ -379,13 +389,14 @@ impl Container {
|
|||
if self.focusable_elements.is_empty() {
|
||||
return;
|
||||
}
|
||||
let focusables = self.focusable_elements.iter()
|
||||
let focusables = self
|
||||
.focusable_elements
|
||||
.iter()
|
||||
.flat_map(|v| v.upgrade())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Find the last focused element if there is one
|
||||
let last_focus = focusables.iter()
|
||||
.position(|v| v.is_focused());
|
||||
let last_focus = focusables.iter().position(|v| v.is_focused());
|
||||
let next_focus = last_focus.map_or(0, |v| v + 1) % focusables.len();
|
||||
|
||||
// Clear the last focus
|
||||
|
@ -396,15 +407,20 @@ impl Container {
|
|||
focusables[next_focus].set_focused(true);
|
||||
}
|
||||
|
||||
pub fn key_press(&mut self, game: &mut crate::Game, key: VirtualKeyCode, down: bool, ctrl_pressed: bool) {
|
||||
pub fn key_press(
|
||||
&mut self,
|
||||
game: &mut crate::Game,
|
||||
key: VirtualKeyCode,
|
||||
down: bool,
|
||||
ctrl_pressed: bool,
|
||||
) {
|
||||
if key == VirtualKeyCode::Tab {
|
||||
if !down {
|
||||
self.cycle_focus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
for el in self.focusable_elements.iter()
|
||||
.flat_map(|v| v.upgrade()) {
|
||||
for el in self.focusable_elements.iter().flat_map(|v| v.upgrade()) {
|
||||
if el.is_focused() {
|
||||
el.key_press(game, key, down, ctrl_pressed);
|
||||
}
|
||||
|
@ -415,8 +431,7 @@ impl Container {
|
|||
if c < ' ' {
|
||||
return;
|
||||
}
|
||||
for el in self.focusable_elements.iter()
|
||||
.flat_map(|v| v.upgrade()) {
|
||||
for el in self.focusable_elements.iter().flat_map(|v| v.upgrade()) {
|
||||
if el.is_focused() {
|
||||
el.key_type(game, c);
|
||||
}
|
||||
|
@ -462,11 +477,27 @@ impl ElementHolder for Container {
|
|||
}
|
||||
|
||||
trait UIElement {
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8];
|
||||
fn draw(
|
||||
&mut self,
|
||||
renderer: &mut render::Renderer,
|
||||
r: &Region,
|
||||
sw: f64,
|
||||
sh: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
delta: f64,
|
||||
) -> &mut [u8];
|
||||
fn get_size(&self) -> (f64, f64);
|
||||
fn is_dirty(&self) -> bool;
|
||||
fn post_init(_: Rc<RefCell<Self>>) {}
|
||||
fn key_press(&mut self, _game: &mut crate::Game, _key: VirtualKeyCode, _down: bool, _ctrl_pressed: bool) {}
|
||||
fn key_press(
|
||||
&mut self,
|
||||
_game: &mut crate::Game,
|
||||
_key: VirtualKeyCode,
|
||||
_down: bool,
|
||||
_ctrl_pressed: bool,
|
||||
) {
|
||||
}
|
||||
fn key_type(&mut self, _game: &mut crate::Game, _c: char) {}
|
||||
fn tick(&mut self, renderer: &mut render::Renderer);
|
||||
}
|
||||
|
@ -499,9 +530,9 @@ macro_rules! element {
|
|||
data: Vec<u8>,
|
||||
needs_rebuild: bool,
|
||||
|
||||
hover_funcs: Vec<Box<Fn(&mut $name, bool, &mut crate::Game) -> bool>>,
|
||||
hover_funcs: Vec<Box<dyn Fn(&mut $name, bool, &mut crate::Game) -> bool>>,
|
||||
hover_state: bool,
|
||||
click_funcs: Vec<Box<Fn(&mut $name, &mut crate::Game) -> bool>>,
|
||||
click_funcs: Vec<Box<dyn Fn(&mut $name, &mut crate::Game) -> bool>>,
|
||||
|
||||
focused: bool,
|
||||
|
||||
|
@ -803,14 +834,29 @@ impl ImageBuilder {
|
|||
}
|
||||
|
||||
impl UIElement for Image {
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8] {
|
||||
fn draw(
|
||||
&mut self,
|
||||
renderer: &mut render::Renderer,
|
||||
r: &Region,
|
||||
sw: f64,
|
||||
sh: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
delta: f64,
|
||||
) -> &mut [u8] {
|
||||
if self.check_rebuild() {
|
||||
self.data.clear();
|
||||
let texture = render::Renderer::get_texture(renderer.get_textures_ref(), &self.texture);
|
||||
let mut element = render::ui::UIElement::new(
|
||||
&texture,
|
||||
r.x, r.y, r.w, r.h,
|
||||
self.texture_coords.0, self.texture_coords.1, self.texture_coords.2, self.texture_coords.3,
|
||||
r.x,
|
||||
r.y,
|
||||
r.w,
|
||||
r.h,
|
||||
self.texture_coords.0,
|
||||
self.texture_coords.1,
|
||||
self.texture_coords.2,
|
||||
self.texture_coords.3,
|
||||
);
|
||||
element.r = self.colour.0;
|
||||
element.g = self.colour.1;
|
||||
|
@ -861,7 +907,16 @@ impl BatchBuilder {
|
|||
}
|
||||
|
||||
impl UIElement for Batch {
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8] {
|
||||
fn draw(
|
||||
&mut self,
|
||||
renderer: &mut render::Renderer,
|
||||
r: &Region,
|
||||
sw: f64,
|
||||
sh: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
delta: f64,
|
||||
) -> &mut [u8] {
|
||||
if self.check_rebuild() {
|
||||
self.data.clear();
|
||||
self.super_draw(renderer, r, sw, sh, width, height, delta);
|
||||
|
@ -915,15 +970,29 @@ element! {
|
|||
}
|
||||
|
||||
impl UIElement for Text {
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8] {
|
||||
fn draw(
|
||||
&mut self,
|
||||
renderer: &mut render::Renderer,
|
||||
r: &Region,
|
||||
sw: f64,
|
||||
sh: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
delta: f64,
|
||||
) -> &mut [u8] {
|
||||
if self.check_rebuild() {
|
||||
self.data.clear();
|
||||
|
||||
let mut text = if self.rotation == 0.0 {
|
||||
renderer.ui.new_text_scaled(
|
||||
&self.text,
|
||||
r.x, r.y, sw * self.scale_x, sh * self.scale_y,
|
||||
self.colour.0, self.colour.1, self.colour.2,
|
||||
r.x,
|
||||
r.y,
|
||||
sw * self.scale_x,
|
||||
sh * self.scale_y,
|
||||
self.colour.0,
|
||||
self.colour.1,
|
||||
self.colour.2,
|
||||
)
|
||||
} else {
|
||||
let c = self.rotation.cos();
|
||||
|
@ -933,11 +1002,15 @@ impl UIElement for Text {
|
|||
let w = (tmpx * c - tmpy * s).abs();
|
||||
let h = (tmpy * c + tmpx * s).abs();
|
||||
renderer.ui.new_text_rotated(
|
||||
&self.text,
|
||||
r.x + w - (r.w / 2.0), r.y + h - (r.h / 2.0),
|
||||
sw * self.scale_x, sh * self.scale_y,
|
||||
self.rotation,
|
||||
self.colour.0, self.colour.1, self.colour.2,
|
||||
&self.text,
|
||||
r.x + w - (r.w / 2.0),
|
||||
r.y + h - (r.h / 2.0),
|
||||
sw * self.scale_x,
|
||||
sh * self.scale_y,
|
||||
self.rotation,
|
||||
self.colour.0,
|
||||
self.colour.1,
|
||||
self.colour.2,
|
||||
)
|
||||
};
|
||||
for e in &mut text.elements {
|
||||
|
@ -963,7 +1036,10 @@ impl UIElement for Text {
|
|||
}
|
||||
|
||||
fn get_size(&self) -> (f64, f64) {
|
||||
((self.width + 2.0) * self.scale_x, self.height * self.scale_y)
|
||||
(
|
||||
(self.width + 2.0) * self.scale_x,
|
||||
self.height * self.scale_y,
|
||||
)
|
||||
}
|
||||
|
||||
fn is_dirty(&self) -> bool {
|
||||
|
@ -975,8 +1051,6 @@ impl UIElement for Text {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
element! {
|
||||
ref FormattedRef
|
||||
pub struct Formatted {
|
||||
|
@ -1010,7 +1084,16 @@ element! {
|
|||
}
|
||||
|
||||
impl UIElement for Formatted {
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8] {
|
||||
fn draw(
|
||||
&mut self,
|
||||
renderer: &mut render::Renderer,
|
||||
r: &Region,
|
||||
sw: f64,
|
||||
sh: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
delta: f64,
|
||||
) -> &mut [u8] {
|
||||
if self.check_rebuild() {
|
||||
self.data.clear();
|
||||
|
||||
|
@ -1057,7 +1140,10 @@ impl UIElement for Formatted {
|
|||
}
|
||||
|
||||
fn get_size(&self) -> (f64, f64) {
|
||||
((self.width + 2.0) * self.scale_x, self.height * self.scale_y)
|
||||
(
|
||||
(self.width + 2.0) * self.scale_x,
|
||||
self.height * self.scale_y,
|
||||
)
|
||||
}
|
||||
|
||||
fn is_dirty(&self) -> bool {
|
||||
|
@ -1074,7 +1160,11 @@ impl Formatted {
|
|||
self.dirty = true;
|
||||
}
|
||||
|
||||
pub fn compute_size(renderer: &render::Renderer, text: &format::Component, max_width: f64) -> (f64, f64) {
|
||||
pub fn compute_size(
|
||||
renderer: &render::Renderer,
|
||||
text: &format::Component,
|
||||
max_width: f64,
|
||||
) -> (f64, f64) {
|
||||
let mut state = FormatState {
|
||||
lines: 0,
|
||||
width: 0.0,
|
||||
|
@ -1097,14 +1187,13 @@ struct FormatState<'a> {
|
|||
renderer: &'a render::Renderer,
|
||||
}
|
||||
|
||||
|
||||
impl <'a> ElementHolder for FormatState<'a> {
|
||||
impl<'a> ElementHolder for FormatState<'a> {
|
||||
fn add(&mut self, el: Element, _: bool) {
|
||||
self.text.push(el);
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a> FormatState<'a> {
|
||||
impl<'a> FormatState<'a> {
|
||||
fn build(&mut self, c: &format::Component, color: format::Color) {
|
||||
match *c {
|
||||
format::Component::Text(ref txt) => {
|
||||
|
@ -1196,46 +1285,156 @@ impl ButtonBuilder {
|
|||
}
|
||||
|
||||
impl UIElement for Button {
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8] {
|
||||
fn draw(
|
||||
&mut self,
|
||||
renderer: &mut render::Renderer,
|
||||
r: &Region,
|
||||
sw: f64,
|
||||
sh: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
delta: f64,
|
||||
) -> &mut [u8] {
|
||||
if self.check_rebuild() {
|
||||
self.data.clear();
|
||||
let offset = match (self.disabled, self.hovered) {
|
||||
(true, _) => 46.0,
|
||||
(false, true) => 86.0,
|
||||
(false, false) => 66.0,
|
||||
(true, _) => 46.0,
|
||||
(false, true) => 86.0,
|
||||
(false, false) => 66.0,
|
||||
};
|
||||
let texture = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/widgets")
|
||||
.relative(0.0, offset / 256.0, 200.0 / 256.0, 20.0 / 256.0);
|
||||
.relative(0.0, offset / 256.0, 200.0 / 256.0, 20.0 / 256.0);
|
||||
|
||||
self.data.extend(render::ui::UIElement::new(&texture, r.x, r.y, 4.0 * sw, 4.0 * sh, 0.0, 0.0, 2.0/200.0, 2.0/20.0).bytes(width, height));
|
||||
self.data.extend(render::ui::UIElement::new(&texture, r.x + r.w - 4.0 * sw, r.y, 4.0 * sw, 4.0 * sh, 198.0/200.0, 0.0, 2.0/200.0, 2.0/20.0).bytes(width, height));
|
||||
self.data.extend(render::ui::UIElement::new(&texture, r.x, r.y + r.h - 6.0 * sh, 4.0 * sw, 6.0 * sh, 0.0, 17.0/20.0, 2.0/200.0, 3.0/20.0).bytes(width, height));
|
||||
self.data.extend(render::ui::UIElement::new(&texture, r.x + r.w - 4.0 * sw, r.y + r.h - 6.0 * sh, 4.0 * sw, 6.0 * sh, 198.0/200.0, 17.0/20.0, 2.0/200.0, 3.0/20.0).bytes(width, height));
|
||||
|
||||
let w = ((r.w / sw)/2.0) - 4.0;
|
||||
self.data.extend(render::ui::UIElement::new(
|
||||
&texture.relative(2.0/200.0, 0.0, 196.0/200.0, 2.0/20.0),
|
||||
r.x+4.0*sw, r.y, r.w - 8.0 * sw, 4.0 * sh, 0.0, 0.0, w/196.0, 1.0).bytes(width, height)
|
||||
self.data.extend(
|
||||
render::ui::UIElement::new(
|
||||
&texture,
|
||||
r.x,
|
||||
r.y,
|
||||
4.0 * sw,
|
||||
4.0 * sh,
|
||||
0.0,
|
||||
0.0,
|
||||
2.0 / 200.0,
|
||||
2.0 / 20.0,
|
||||
)
|
||||
.bytes(width, height),
|
||||
);
|
||||
self.data.extend(render::ui::UIElement::new(
|
||||
&texture.relative(2.0/200.0, 17.0/20.0, 196.0/200.0, 3.0/20.0),
|
||||
r.x+4.0*sw, r.y+r.h-6.0*sh, r.w - 8.0 * sw, 6.0 * sh, 0.0, 0.0, w/196.0, 1.0).bytes(width, height)
|
||||
self.data.extend(
|
||||
render::ui::UIElement::new(
|
||||
&texture,
|
||||
r.x + r.w - 4.0 * sw,
|
||||
r.y,
|
||||
4.0 * sw,
|
||||
4.0 * sh,
|
||||
198.0 / 200.0,
|
||||
0.0,
|
||||
2.0 / 200.0,
|
||||
2.0 / 20.0,
|
||||
)
|
||||
.bytes(width, height),
|
||||
);
|
||||
self.data.extend(
|
||||
render::ui::UIElement::new(
|
||||
&texture,
|
||||
r.x,
|
||||
r.y + r.h - 6.0 * sh,
|
||||
4.0 * sw,
|
||||
6.0 * sh,
|
||||
0.0,
|
||||
17.0 / 20.0,
|
||||
2.0 / 200.0,
|
||||
3.0 / 20.0,
|
||||
)
|
||||
.bytes(width, height),
|
||||
);
|
||||
self.data.extend(
|
||||
render::ui::UIElement::new(
|
||||
&texture,
|
||||
r.x + r.w - 4.0 * sw,
|
||||
r.y + r.h - 6.0 * sh,
|
||||
4.0 * sw,
|
||||
6.0 * sh,
|
||||
198.0 / 200.0,
|
||||
17.0 / 20.0,
|
||||
2.0 / 200.0,
|
||||
3.0 / 20.0,
|
||||
)
|
||||
.bytes(width, height),
|
||||
);
|
||||
|
||||
let h = ((r.h / sh)/2.0) - 5.0;
|
||||
self.data.extend(render::ui::UIElement::new(
|
||||
&texture.relative(0.0/200.0, 2.0/20.0, 2.0/200.0, 15.0/20.0),
|
||||
r.x, r.y + 4.0*sh, 4.0 * sw, r.h - 10.0*sh, 0.0, 0.0, 1.0, h/16.0).bytes(width, height)
|
||||
let w = ((r.w / sw) / 2.0) - 4.0;
|
||||
self.data.extend(
|
||||
render::ui::UIElement::new(
|
||||
&texture.relative(2.0 / 200.0, 0.0, 196.0 / 200.0, 2.0 / 20.0),
|
||||
r.x + 4.0 * sw,
|
||||
r.y,
|
||||
r.w - 8.0 * sw,
|
||||
4.0 * sh,
|
||||
0.0,
|
||||
0.0,
|
||||
w / 196.0,
|
||||
1.0,
|
||||
)
|
||||
.bytes(width, height),
|
||||
);
|
||||
self.data.extend(render::ui::UIElement::new(
|
||||
&texture.relative(198.0/200.0, 2.0/20.0, 2.0/200.0, 15.0/20.0),
|
||||
r.x+r.w - 4.0 * sw, r.y + 4.0*sh, 4.0 * sw, r.h - 10.0*sh, 0.0, 0.0, 1.0, h/16.0).bytes(width, height)
|
||||
self.data.extend(
|
||||
render::ui::UIElement::new(
|
||||
&texture.relative(2.0 / 200.0, 17.0 / 20.0, 196.0 / 200.0, 3.0 / 20.0),
|
||||
r.x + 4.0 * sw,
|
||||
r.y + r.h - 6.0 * sh,
|
||||
r.w - 8.0 * sw,
|
||||
6.0 * sh,
|
||||
0.0,
|
||||
0.0,
|
||||
w / 196.0,
|
||||
1.0,
|
||||
)
|
||||
.bytes(width, height),
|
||||
);
|
||||
|
||||
let h = ((r.h / sh) / 2.0) - 5.0;
|
||||
self.data.extend(
|
||||
render::ui::UIElement::new(
|
||||
&texture.relative(0.0 / 200.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0),
|
||||
r.x,
|
||||
r.y + 4.0 * sh,
|
||||
4.0 * sw,
|
||||
r.h - 10.0 * sh,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
h / 16.0,
|
||||
)
|
||||
.bytes(width, height),
|
||||
);
|
||||
self.data.extend(
|
||||
render::ui::UIElement::new(
|
||||
&texture.relative(198.0 / 200.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0),
|
||||
r.x + r.w - 4.0 * sw,
|
||||
r.y + 4.0 * sh,
|
||||
4.0 * sw,
|
||||
r.h - 10.0 * sh,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
h / 16.0,
|
||||
)
|
||||
.bytes(width, height),
|
||||
);
|
||||
|
||||
self.data.extend(render::ui::UIElement::new(
|
||||
&texture.relative(2.0/200.0, 2.0/20.0, 196.0/200.0, 15.0/20.0),
|
||||
r.x+4.0*sw, r.y+4.0*sh, r.w - 8.0 * sw, r.h - 10.0 * sh, 0.0, 0.0, w/196.0, h/16.0).bytes(width, height)
|
||||
self.data.extend(
|
||||
render::ui::UIElement::new(
|
||||
&texture.relative(2.0 / 200.0, 2.0 / 20.0, 196.0 / 200.0, 15.0 / 20.0),
|
||||
r.x + 4.0 * sw,
|
||||
r.y + 4.0 * sh,
|
||||
r.w - 8.0 * sw,
|
||||
r.h - 10.0 * sh,
|
||||
0.0,
|
||||
0.0,
|
||||
w / 196.0,
|
||||
h / 16.0,
|
||||
)
|
||||
.bytes(width, height),
|
||||
);
|
||||
self.super_draw(renderer, r, sw, sh, width, height, delta);
|
||||
self.last_disabled = self.disabled;
|
||||
|
@ -1253,11 +1452,9 @@ impl UIElement for Button {
|
|||
}
|
||||
|
||||
fn is_dirty(&self) -> bool {
|
||||
self.last_disabled != self.disabled
|
||||
|| self.last_hovered != self.hovered
|
||||
self.last_disabled != self.disabled || self.last_hovered != self.hovered
|
||||
}
|
||||
|
||||
|
||||
fn post_init(s: Rc<RefCell<Self>>) {
|
||||
s.borrow_mut().add_hover_func(move |this, hover, _| {
|
||||
this.hovered = hover;
|
||||
|
@ -1286,7 +1483,7 @@ element! {
|
|||
priv text: Option<TextRef>,
|
||||
priv was_focused: bool,
|
||||
priv cursor_tick: f64,
|
||||
priv submit_funcs: Vec<Box<Fn(&mut TextBox, &mut crate::Game)>>,
|
||||
priv submit_funcs: Vec<Box<dyn Fn(&mut TextBox, &mut crate::Game)>>,
|
||||
}
|
||||
builder TextBoxBuilder {
|
||||
hardcode button = None,
|
||||
|
@ -1310,9 +1507,17 @@ impl TextBoxBuilder {
|
|||
}
|
||||
|
||||
impl UIElement for TextBox {
|
||||
fn key_press(&mut self, game: &mut crate::Game, key: VirtualKeyCode, down: bool, ctrl_pressed: bool) {
|
||||
fn key_press(
|
||||
&mut self,
|
||||
game: &mut crate::Game,
|
||||
key: VirtualKeyCode,
|
||||
down: bool,
|
||||
ctrl_pressed: bool,
|
||||
) {
|
||||
match (key, down) {
|
||||
(VirtualKeyCode::Back, _) => {self.input.pop();},
|
||||
(VirtualKeyCode::Back, _) => {
|
||||
self.input.pop();
|
||||
}
|
||||
(VirtualKeyCode::Return, false) => {
|
||||
use std::mem;
|
||||
let len = self.submit_funcs.len();
|
||||
|
@ -1321,17 +1526,19 @@ impl UIElement for TextBox {
|
|||
(func)(self, game);
|
||||
}
|
||||
self.submit_funcs.append(&mut temp);
|
||||
},
|
||||
}
|
||||
// TODO: wasm clipboard pasting, Clipboard API: https://www.w3.org/TR/clipboard-apis/
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
(VirtualKeyCode::V, true) => {
|
||||
if ctrl_pressed {
|
||||
let mut clipboard: ClipboardContext = ClipboardProvider::new().unwrap();
|
||||
match clipboard.get_contents() {
|
||||
Ok(text) => self.input.push_str(&text),
|
||||
Err(_) => ()
|
||||
Err(_) => (),
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1339,7 +1546,16 @@ impl UIElement for TextBox {
|
|||
self.input.push(c);
|
||||
}
|
||||
|
||||
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, sw: f64, sh: f64, width: f64, height: f64, delta: f64) -> &mut [u8] {
|
||||
fn draw(
|
||||
&mut self,
|
||||
renderer: &mut render::Renderer,
|
||||
r: &Region,
|
||||
sw: f64,
|
||||
sh: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
delta: f64,
|
||||
) -> &mut [u8] {
|
||||
if self.check_rebuild() {
|
||||
self.data.clear();
|
||||
self.cursor_tick += delta;
|
||||
|
@ -1378,17 +1594,21 @@ impl UIElement for TextBox {
|
|||
|
||||
fn post_init(s: Rc<RefCell<Self>>) {
|
||||
let mut textbox = s.borrow_mut();
|
||||
textbox.button = Some(ButtonBuilder::new()
|
||||
.position(0.0, 0.0)
|
||||
.size(textbox.width, textbox.height)
|
||||
.disabled(true)
|
||||
.attach(&mut *textbox));
|
||||
textbox.text = Some(TextBuilder::new()
|
||||
.text("")
|
||||
.position(5.0, 0.0)
|
||||
.draw_index(1)
|
||||
.alignment(VAttach::Middle, HAttach::Left)
|
||||
.attach(&mut *textbox));
|
||||
textbox.button = Some(
|
||||
ButtonBuilder::new()
|
||||
.position(0.0, 0.0)
|
||||
.size(textbox.width, textbox.height)
|
||||
.disabled(true)
|
||||
.attach(&mut *textbox),
|
||||
);
|
||||
textbox.text = Some(
|
||||
TextBuilder::new()
|
||||
.text("")
|
||||
.position(5.0, 0.0)
|
||||
.draw_index(1)
|
||||
.alignment(VAttach::Middle, HAttach::Left)
|
||||
.attach(&mut *textbox),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
use image::Rgba;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
|
@ -14,7 +13,7 @@ impl Biome {
|
|||
Biome {
|
||||
id,
|
||||
temperature: t,
|
||||
moisture: m*t,
|
||||
moisture: m * t,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,21 +22,19 @@ impl Biome {
|
|||
}
|
||||
|
||||
pub fn get_color_index(self) -> usize {
|
||||
let t = (self.temperature as f64 / 100f64) .min(1.0).max(0.0);
|
||||
let t = (self.temperature as f64 / 100f64).min(1.0).max(0.0);
|
||||
let m = (self.moisture as f64 / 100f64).min(1.0).max(0.0);
|
||||
(((1.0 - t) * 255.0) as usize) | ((((1.0 - (m*t)) * 255.0) as usize) << 8)
|
||||
(((1.0 - t) * 255.0) as usize) | ((((1.0 - (m * t)) * 255.0) as usize) << 8)
|
||||
}
|
||||
|
||||
pub fn process_color(self, col: Rgba<u8>) -> Rgba<u8> {
|
||||
if self.id == ROOFED_FOREST.id || self.id == ROOFED_FOREST_MOUNTAINS.id {
|
||||
Rgba {
|
||||
data: [
|
||||
((col.data[0] as u32 + 0x28) / 2) as u8,
|
||||
((col.data[1] as u32 + 0x34) / 2) as u8,
|
||||
((col.data[2] as u32 + 0x0A) / 2) as u8,
|
||||
255
|
||||
]
|
||||
}
|
||||
Rgba([
|
||||
((col.0[0] as u32 + 0x28) / 2) as u8,
|
||||
((col.0[1] as u32 + 0x34) / 2) as u8,
|
||||
((col.0[2] as u32 + 0x0A) / 2) as u8,
|
||||
255,
|
||||
])
|
||||
} else {
|
||||
col
|
||||
}
|
||||
|
|
575
src/world/mod.rs
575
src/world/mod.rs
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,3 @@
|
|||
|
||||
use crate::types::bit;
|
||||
use crate::types::hash::FNVHash;
|
||||
use crate::world::block;
|
||||
|
@ -14,15 +13,13 @@ pub struct BlockStorage {
|
|||
|
||||
impl BlockStorage {
|
||||
pub fn new(size: usize) -> BlockStorage {
|
||||
Self::new_default(size, block::Air{})
|
||||
Self::new_default(size, block::Air {})
|
||||
}
|
||||
|
||||
pub fn new_default(size: usize, def: block::Block) -> BlockStorage {
|
||||
let mut storage = BlockStorage {
|
||||
blocks: bit::Map::new(size, 4),
|
||||
block_map: vec![
|
||||
(def, size as u32)
|
||||
],
|
||||
block_map: vec![(def, size as u32)],
|
||||
rev_block_map: HashMap::with_hasher(BuildHasherDefault::default()),
|
||||
};
|
||||
storage.rev_block_map.insert(def, 0);
|
||||
|
@ -45,7 +42,8 @@ impl BlockStorage {
|
|||
let idx = *self.rev_block_map.get(&old).unwrap();
|
||||
let info = &mut self.block_map[idx];
|
||||
info.1 -= 1;
|
||||
if info.1 == 0 { // None left of this type
|
||||
if info.1 == 0 {
|
||||
// None left of this type
|
||||
self.rev_block_map.remove(&old);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "base-x"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "discard"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "localstoragefs"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stdweb 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "std_or_web"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"localstoragefs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stdweb-derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stdweb-internal-macros 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stdweb-internal-runtime 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-derive"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-internal-macros"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base-x 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-internal-runtime"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-macro 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-shared 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-macro-support 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-backend 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-shared 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum base-x 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1"
|
||||
"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum localstoragefs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba6cbee6bbe7e6ea61ad375952239a9678624f216a0f442ae04a90260e76cdf"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc"
|
||||
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
||||
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
|
||||
"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7"
|
||||
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
||||
"checksum stdweb 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
|
||||
"checksum stdweb-derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
|
||||
"checksum stdweb-internal-macros 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
|
||||
"checksum stdweb-internal-runtime 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
|
||||
"checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8"
|
||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
"checksum wasm-bindgen 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)" = "99de4b68939a880d530aed51289a7c7baee154e3ea8ac234b542c49da7134aaf"
|
||||
"checksum wasm-bindgen-backend 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)" = "b58e66a093a7b7571cb76409763c495b8741ac4319ac20acc2b798f6766d92ee"
|
||||
"checksum wasm-bindgen-macro 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)" = "a80f89daea7b0a67b11f6e9f911422ed039de9963dce00048a653b63d51194bf"
|
||||
"checksum wasm-bindgen-macro-support 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)" = "4f9dbc3734ad6cff6b76b75b7df98c06982becd0055f651465a08f769bca5c61"
|
||||
"checksum wasm-bindgen-shared 0.2.56 (registry+https://github.com/rust-lang/crates.io-index)" = "d907984f8506b3554eab48b8efff723e764ddbf76d4cd4a3fe4196bc00c49a70"
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "std_or_web"
|
||||
version = "0.0.1"
|
||||
authors = [ "iceiix <ice_ix@protonmail.ch>" ]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "0.1.10"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
localstoragefs = "0.1.0"
|
|
@ -0,0 +1,9 @@
|
|||
use cfg_if::cfg_if;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_arch = "wasm32")] {
|
||||
pub use localstoragefs::fs;
|
||||
} else {
|
||||
pub use std::fs;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
dist
|
|
@ -0,0 +1,37 @@
|
|||
# stevenarella-web
|
||||
|
||||
Web app for running Stevenarella as WebAssembly
|
||||
|
||||
Status: very incomplete. It does not currently compile, due to required modifications to adapt to the web,
|
||||
for progress see: [https://github.com/iceiix/stevenarella/issues/171](https://github.com/iceiix/stevenarella/issues/171).
|
||||
|
||||
## Building
|
||||
|
||||
To build for wasm32-unknown-unknown, run:
|
||||
|
||||
```sh
|
||||
cargo web start --target wasm32-unknown-unknown
|
||||
```
|
||||
|
||||
## Running
|
||||
|
||||
After building the Rust app, run the NodeJS web server as follows:
|
||||
|
||||
```sh
|
||||
cd pkg
|
||||
npm link
|
||||
cd ..
|
||||
cd www
|
||||
npm link stevenarella
|
||||
npm install
|
||||
npm start
|
||||
open http://localhost:8080/
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
Based on [rustwasm/create-wasm-app](https://github.com/rustwasm/create-wasm-app):
|
||||
|
||||
> An `npm init` template for kick starting a project that uses NPM packages
|
||||
> containing Rust-generated WebAssembly and bundles them with Webpack.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// A dependency graph that contains any wasm must all be imported
|
||||
// asynchronously. This `bootstrap.js` file does the single async import, so
|
||||
// that no one else needs to worry about it again.
|
||||
import("./index.js")
|
||||
.catch(e => console.error("Error importing `index.js`:", e));
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Stevenarella</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="./bootstrap.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,3 @@
|
|||
import * as wasm from "stevenarella";
|
||||
|
||||
wasm.main();
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "stevenarella-web",
|
||||
"version": "0.0.1",
|
||||
"description": "Multi-protocol Minecraft-compatible client, web-based version",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "webpack --config webpack.config.js",
|
||||
"start": "webpack-dev-server"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/iceiix/stevenarella.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "iceiix <ice_ix@protonmail.ch>",
|
||||
"license": "(MIT OR Apache-2.0)",
|
||||
"bugs": {
|
||||
"url": "https://github.com/iceiix/stevenarella/issues"
|
||||
},
|
||||
"homepage": "https://github.com/rustwasm/create-wasm-app#readme",
|
||||
"devDependencies": {
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: "./bootstrap.js",
|
||||
output: {
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
filename: "bootstrap.js",
|
||||
},
|
||||
mode: "development",
|
||||
plugins: [
|
||||
new CopyWebpackPlugin(['index.html'])
|
||||
],
|
||||
};
|
Loading…
Reference in New Issue