Merge branch 'master' into 1.13_assets

This commit is contained in:
ice_iix 2020-06-21 12:51:13 -07:00
commit c0c940a4c2
105 changed files with 15824 additions and 4496 deletions

20
.build.yml Normal file
View File

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

5
.gitignore vendored
View File

@ -1,6 +1,11 @@
# Rust
target/
**/*.rs.bk
.rust/
working/
*.log
pkg
# IntelliJ
.idea

View File

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

2774
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

363
blocks/Cargo.lock generated
View File

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

View File

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

View File

@ -1,4 +1,3 @@
pub struct Material {
pub renderable: bool,
pub should_cull_against: bool,

52
gl/Cargo.lock generated
View File

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

View File

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

View File

@ -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();
}

28
protocol/Cargo.toml Normal file
View File

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

View File

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

View File

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

11
protocol/src/lib.rs Normal file
View File

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

View File

@ -1,5 +1,3 @@
#[doc(hidden)]
#[macro_export]
macro_rules! create_ids {

View File

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

View File

@ -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!(),
}
}
}

View File

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

View File

@ -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()?;

View File

@ -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!()
}
}

View File

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

View File

@ -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!(
}
}
);

View File

@ -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!(
}
}
);

View File

@ -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!(
}
}
);

View File

@ -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!(
}
}
);

View File

@ -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!(
}
}
);

View File

@ -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!(
}
}
);

View File

@ -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!(
}
}
);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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!(
}
}
);

View File

@ -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!(
}
}
);

View File

@ -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!(
}
}
);

View File

@ -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!(
}
}
);

View File

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

View File

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

View File

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

View File

@ -1,5 +1,3 @@
use std::hash::Hasher;
pub struct FNVHash(u64);

View File

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

View File

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

View File

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

4
resources/Cargo.lock generated
View File

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

View File

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

View File

@ -1,2 +1 @@
include!(concat!(env!("OUT_DIR"), "/resources.rs"));

4
shared/Cargo.lock generated
View File

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

View File

@ -1,10 +1,9 @@
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Axis {
Y,
Z,
X,
None
None,
}
impl Axis {

View File

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

View File

@ -1,4 +1,3 @@
pub mod axis;
pub use self::axis::Axis;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,
);
}
}

View File

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

View File

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

View File

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

View File

@ -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"),
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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) => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
},
}
}
}
}

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -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,
},
]],
)
}
}

View File

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

View File

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

View File

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

View File

@ -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),
);
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

276
std_or_web/Cargo.lock generated Normal file
View File

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

11
std_or_web/Cargo.toml Normal file
View File

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

9
std_or_web/src/lib.rs Normal file
View File

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

2
www/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
dist

37
www/README.md Normal file
View File

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

5
www/bootstrap.js vendored Normal file
View File

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

10
www/index.html Normal file
View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Stevenarella</title>
</head>
<body>
<script src="./bootstrap.js"></script>
</body>
</html>

3
www/index.js Normal file
View File

@ -0,0 +1,3 @@
import * as wasm from "stevenarella";
wasm.main();

5405
www/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

27
www/package.json Normal file
View File

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

14
www/webpack.config.js Normal file
View File

@ -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'])
],
};