pull from upstream

Former-commit-id: 7907655bdc290e4790034d516d71839c3b45ec6c
This commit is contained in:
sxv20_ 2019-04-22 17:41:07 +01:00
commit 0e8a7ecda3
55 changed files with 1792 additions and 861 deletions

232
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,232 @@
#cache:
# paths:
# - target/
stages:
- build
- test
- deploy
- post-run
# our own git fetch command like https://gitlab.com/gitlab-org/gitlab-runner/blob/master/shells/abstract.go
# speeds up building because we skip the git clean and dont need any gitlab caches
variables:
GIT_STRATEGY: none
before_script:
- if [ -d .git ]; then
echo "is git dir";
else
git clone $CI_REPOSITORY_URL . ;
fi;
- rm -f .git/index.lock
- rm -f .git/shallow.lock
- rm -f .git/HEAD.lock
- rm -f .git/hocks/post-checkout
- git remote set-url origin $CI_REPOSITORY_URL
- git fetch origin --prune +refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/*
- git checkout -f -q $CI_COMMIT_SHA
- if [ ! -z "${SOURCE_PROJECT}" -a "${SOURCE_PROJECT}" != " " ]; then
echo "THIS SEEMS TO BE A MERGE PIPELINE FROM ${SOURCE_PROJECT}/${SOURCE_BRANCH}";
git pull "https://gitlab.com/${SOURCE_PROJECT}/veloren.git" "${SOURCE_BRANCH}";
fi;
- git submodule update --init --recursive
- git status
- if [ -d target ]; then
ls -la target;
fi;
# - git submodule update --init --recursive
clean-code:
stage: build
script:
- rustup component add rustfmt-preview
- cargo fmt --all -- --check
allow_failure: true
build-voxygen:
stage: build
script:
- (cd voxygen && cargo build)
build-server-cli:
stage: build
script:
- (cd server-cli && cargo build)
unittests:
stage: test
script:
- cargo test
#benchmarktests:
# stage: test
# script:
# - cargo bench
nightly-linux-debug:
stage: deploy
script:
- (cd voxygen && VELOREN_ASSETS=assets cargo build)
- (cd server-cli && VELOREN_ASSETS=assets cargo build)
- rm -r -f nightly
- mkdir nightly
- cp target/debug/veloren-server-cli nightly
- cp target/debug/veloren-voxygen nightly
- cp -r assets nightly/
- cp -r voxygen/shaders nightly/
- rm -f nightly-linux-debug.tar.bz2
- tar -cvjSf nightly-linux-debug.tar.bz2 nightly
when: always
artifacts:
paths:
- nightly-linux-debug.tar.bz2
expire_in: 1 week
only:
refs:
- master
nightly-windows-debug:
stage: deploy
script:
- (cd voxygen && VELOREN_ASSETS=assets cargo build --target=x86_64-pc-windows-gnu)
- (cd server-cli && VELOREN_ASSETS=assets cargo build --target=x86_64-pc-windows-gnu)
- rm -r -f nightly
- mkdir nightly
- cp target/x86_64-pc-windows-gnu/debug/veloren-server-cli.exe nightly
- cp target/x86_64-pc-windows-gnu/debug/veloren-voxygen.exe nightly
- cp -r assets nightly/
- cp -r voxygen/shaders nightly/
- rm -f nightly-windows-debug.zip
- zip -r nightly-windows-debug.zip nightly
artifacts:
paths:
- nightly-windows-debug.zip
expire_in: 1 week
only:
refs:
- master
nightly-linux-optimized:
stage: deploy
script:
- (cd voxygen && VELOREN_ASSETS=assets cargo build --release)
- (cd server-cli && VELOREN_ASSETS=assets cargo build --release)
- rm -r -f nightly
- mkdir nightly
- cp target/release/veloren-server-cli nightly
- cp target/release/veloren-voxygen nightly
- cp -r assets nightly/
- cp -r voxygen/shaders nightly/
- rm -f nightly-linux-optimized.tar.bz2
- tar -cvjSf nightly-linux-optimized.tar.bz2 nightly
when: manual
artifacts:
paths:
- nightly-linux-optimized.tar.bz2
expire_in: 2 days
only:
refs:
- master
nightly-windows-optimized:
stage: deploy
script:
- (cd voxygen && VELOREN_ASSETS=assets cargo build --release --target=x86_64-pc-windows-gnu)
- (cd server-cli && VELOREN_ASSETS=assets cargo build --release --target=x86_64-pc-windows-gnu)
- rm -r -f nightly
- mkdir nightly
- cp target/x86_64-pc-windows-gnu/release/veloren-server-cli.exe nightly
- cp target/x86_64-pc-windows-gnu/release/veloren-voxygen.exe nightly
- cp -r assets nightly/
- cp -r voxygen/shaders nightly/
- rm -f nightly-windows-optimized.zip
- zip -r nightly-windows-optimized.zip nightly
when: manual
artifacts:
paths:
- nightly-windows-optimized.zip
expire_in: 2 days
only:
refs:
- master
stable-linux-optimized:
stage: deploy
script:
- (cd voxygen && VELOREN_ASSETS=assets cargo build --release)
- (cd server-cli && VELOREN_ASSETS=assets cargo build --release)
- rm -r -f stable
- mkdir stable
- cp target/release/veloren-server-cli stable
- cp target/release/veloren-voxygen stable
- cp -r assets nightly/
- cp -r voxygen/shaders nightly/
- rm -f stable-linux-optimized.tar.bz2
- tar -cvjSf stable-linux-optimized.tar.bz2 stable
artifacts:
paths:
- stable-linux-optimized.tar.bz2
expire_in: 30d
only:
refs:
- /^v[0-9]+\.[0-9]+\.[0-9]+/
stable-windows-optimized:
stage: deploy
script:
- (cd voxygen && VELOREN_ASSETS=assets cargo build --release --target=x86_64-pc-windows-gnu)
- (cd server-cli && VELOREN_ASSETS=assets cargo build --release --target=x86_64-pc-windows-gnu)
- rm -r -f stable
- mkdir stable
- cp target/x86_64-pc-windows-gnu/release/veloren-server-cli.exe stable
- cp target/x86_64-pc-windows-gnu/release/veloren-voxygen.exe stable
- cp -r assets nightly/
- cp -r voxygen/shaders nightly/
- rm -f stable-windows-optimized.zip
- zip -r stable-windows-optimized.zip stable
artifacts:
paths:
- stable-windows-optimized.zip
expire_in: 30d
only:
refs:
- /^v[0-9]+\.[0-9]+\.[0-9]+/
# nightly-windows-release:
# stage: deploy
# script:
# - (cd voxygen && VELOREN_ASSETS=assets cargo build --release --target=x86_64-pc-windows-gnu)
# - (cd server-cli && VELOREN_ASSETS=assets cargo build --release --target=x86_64-pc-windows-gnu)
# - rm -r -f nightly
# - mkdir nightly
# - cp target/x86_64-pc-windows-gnu/debug/veloren-server-cli.exe nightly
# - cp target/x86_64-pc-windows-gnu/debug/veloren-voxygen.exe nightly
# - cp -r assets nightly/
# - cp -r voxygen/shaders nightly/
# - cp -r voxygen/fonts nightly/
# - rm -f nightly-windows-release.zip
# - zip -r nightly-windows-release.zip nightly
# artifacts:
# paths:
# - nightly-windows-release.zip
# expire_in: 1 week
# only:
# refs:
# - master
coverage:
stage: post-run
script:
- if cargo install --list | grep -i "cargo-tarpaulin"; then
echo "tarpaulin already installed";
else
RUSTFLAGS="--cfg procmacro2_semver_exempt" cargo install cargo-tarpaulin;
fi
- cargo tarpaulin --skip-clean --all || echo "There is a problem in tarpaulin which sometimes fails"
clippy:
stage: post-run
script:
- rustup component add clippy-preview --toolchain=nightly
- cargo clippy --all -- -D clippy || echo "This job is disabled, because we are not activly using it now, so we dont want to see yellow failed partly"
allow_failure: true

122
Cargo.lock generated
View File

@ -71,7 +71,7 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -219,7 +219,7 @@ source = "git+https://gitlab.com/veloren/conrod.git#93f02e61838b475ff190b3563a0f
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -401,7 +401,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -414,13 +414,13 @@ dependencies = [
[[package]]
name = "dot_vox"
version = "1.0.1"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -457,10 +457,37 @@ dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "euc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"vek 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "euclid"
version = "0.19.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "euclid_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure"
version = "0.1.5"
@ -477,7 +504,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -668,6 +695,14 @@ dependencies = [
"x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "guillotiere"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hibitset"
version = "0.5.4"
@ -862,14 +897,6 @@ dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "2.2.0"
@ -970,14 +997,6 @@ dependencies = [
"rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nom"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nom"
version = "4.2.3"
@ -1029,7 +1048,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1089,6 +1108,11 @@ dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "numtoa"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "objc"
version = "0.2.6"
@ -1471,7 +1495,7 @@ dependencies = [
[[package]]
name = "regex"
version = "1.1.5"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1604,7 +1628,7 @@ dependencies = [
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1615,7 +1639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1647,7 +1671,7 @@ dependencies = [
[[package]]
name = "shred"
version = "0.7.1"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1664,7 +1688,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1716,7 +1740,7 @@ dependencies = [
"nonzero_signed 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
"shred 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"shred 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"shred-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"shrev 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tuple_utils 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1725,7 +1749,7 @@ dependencies = [
[[package]]
name = "sphynx"
version = "0.1.0"
source = "git+https://gitlab.com/veloren/sphynx.git#b11c95047a1ab282cd790a3488a8b4f7923573e3"
source = "git+https://gitlab.com/veloren/sphynx.git#32cfe0602b7876784845a39d5118f5d63dca80ff"
dependencies = [
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1758,7 +1782,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.15.31"
version = "0.15.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1773,7 +1797,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1787,10 +1811,11 @@ dependencies = [
[[package]]
name = "termion"
version = "1.5.1"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1898,14 +1923,14 @@ name = "veloren-common"
version = "0.2.0"
dependencies = [
"bincode 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"dot_vox 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dot_vox 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
"shred 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"shred 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"specs 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)",
"sphynx 0.1.0 (git+https://gitlab.com/veloren/sphynx.git)",
"threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1942,13 +1967,16 @@ dependencies = [
"config 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"conrod_core 0.63.0 (git+https://gitlab.com/veloren/conrod.git)",
"conrod_winit 0.63.0 (git+https://gitlab.com/veloren/conrod.git)",
"dot_vox 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dot_vox 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx_device_gl 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx_window_glutin 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glsl-include 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"guillotiere 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1960,6 +1988,7 @@ dependencies = [
"vek 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
"veloren-client 0.2.0",
"veloren-common 0.2.0",
"veloren-server 0.2.0",
"winit 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -2208,12 +2237,15 @@ dependencies = [
"checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86"
"checksum derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6073e9676dbebdddeabaeb63e3b7cefd23c86f5c41d381ee1237cc77b1079898"
"checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a"
"checksum dot_vox 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa4d1fc391ef151fff024e8427d206af1adbef4281fcd875090f74697000441"
"checksum dot_vox 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11afd3251e588f2770226659b2a1d55ec2f8aaf2ca42bdcdbd01ff53b4a81e70"
"checksum downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b92dfd5c2f75260cbf750572f95d387e7ca0ba5e3fbe9e1a33f23025be020f"
"checksum draw_state 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "33cf9537e2d06891448799b96d5a8c8083e0e90522a7fdabe6ebf4f41d79d651"
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
"checksum euc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0151594c4feeeb99ff35ac1b467383a46fcb2705275615bed0a47f25ffe2ccf8"
"checksum euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7a4719a544a67ed3fc33784c2bd2c6581663dfe83b719a6ae05c6dabc3b51c73"
"checksum euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcb84c18ea5037a1c5a23039b4ff29403abce2e0d6b1daa11cf0bde2b30be15"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
@ -2237,6 +2269,7 @@ dependencies = [
"checksum gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "39bb69499005e11b7b7cc0af38404a1bc0f53d954bffa8adcdb6e8d5b14f75d5"
"checksum glsl-include 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "31c109a006ad24fd612da10d185b51000ef502155578f3634416f102f0d63b6c"
"checksum glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "535c6eda58adbb227604b2db10a022ffd6339d7ea3e970f338e7d98aeb24fcc3"
"checksum guillotiere 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e965c66630b3a0369feafb06d945f15a4f59aaecc209eb1c4a2b57bb48ee06"
"checksum hibitset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6527bc88f32e0d3926c7572874b2bf17a19b36978aacd0aacf75f7d27a5992d0"
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
"checksum image 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "545f000e8aa4e569e93f49c446987133452e0091c2494ac3efd3606aa3d309f2"
@ -2262,7 +2295,6 @@ dependencies = [
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
"checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
@ -2274,7 +2306,6 @@ dependencies = [
"checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum noise 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a3a34d4f8a31f95919b7ead9f5b60afb9bda0cae98b9219432ffaa6f00b0141"
"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
"checksum nonzero_signed 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "02783a0482333b0d3f5f5411b8fb60454a596696da041da0470ac9ef3e6e37d8"
"checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db"
@ -2288,6 +2319,7 @@ dependencies = [
"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 num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
"checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d"
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
"checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b"
@ -2330,7 +2362,7 @@ dependencies = [
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
"checksum regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "559008764a17de49a3146b234641644ed37d118d1ef641a0bb573d146edc6ce0"
"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
"checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
@ -2352,7 +2384,7 @@ dependencies = [
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
"checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5"
"checksum shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11"
"checksum shred 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c75ec29e8d2959ad96a1087fe4cadb926c6fc17cbae9812314fa8efe720aa2a"
"checksum shred 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6ea122e6133568144fcfb5888737d4ac776ebc959f989dd65b907136ac22bfed"
"checksum shred-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fcf34e5e5302d3024aba7afc291f6d1ca7573ed035d3c0796976ba3f10691a1"
"checksum shrev 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec60ed6f60a4b3cdc2ceacf57215db3408fbd8990f66a38686a31558cd9da482"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
@ -2364,10 +2396,10 @@ dependencies = [
"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
"checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba"
"checksum sum_type 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fcaf0ad86cfe6e1a9ccd145baa65fb1856a8a4b7cc1440b3a13f2b1f93a96fa"
"checksum syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b4cfac95805274c6afdb12d8f770fa2d27c045953e7b630a81801953699a9a"
"checksum syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)" = "846620ec526c1599c070eff393bfeeeb88a93afa2513fc3b49f1fea84cf7b0ed"
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
"checksum tiff 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4834f28a0330cb9f3f2c87d2649dca723cb33802e2bdcf18da32759fbec7ce"

@ -1 +1 @@
Subproject commit e3083ec8e8e634af8c9daed00ea82435da195979
Subproject commit 0a176c408946f081850132623a6730d9d2b1e7ed

View File

@ -26,7 +26,7 @@ use common::{
msg::{ClientMsg, ServerMsg},
};
const SERVER_TIMEOUT: f64 = 5.0; // Seconds
const SERVER_TIMEOUT: f64 = 20.0; // Seconds
pub enum Event {
Chat(String),
@ -167,9 +167,11 @@ impl Client {
_ => {},
}
// Update the server about the player's currently playing animation
if let Some(animation) = self.state.read_storage().get(self.player).cloned() {
self.postbox.send_message(ClientMsg::PlayerAnimation(animation));
// Update the server about the player's currently playing animation and the previous one
if let Some(animation_history) = self.state.read_storage::<comp::AnimationHistory>().get(self.player).cloned() {
if Some(animation_history.current) != animation_history.last {
self.postbox.send_message(ClientMsg::PlayerAnimation(animation_history));
}
}
// Request chunks from the server
@ -228,9 +230,9 @@ impl Client {
},
None => {},
},
ServerMsg::EntityAnimation { entity, animation } => match self.state.ecs().entity_from_uid(entity) {
ServerMsg::EntityAnimation { entity, animation_history } => match self.state.ecs().entity_from_uid(entity) {
Some(entity) => {
self.state.write_component(entity, animation);
self.state.write_component(entity, animation_history);
},
None => {},
},

View File

@ -10,7 +10,7 @@ sphynx = { git = "https://gitlab.com/veloren/sphynx.git", features = ["serde1"]
specs = { version = "0.14", features = ["serde"] }
shred = { version = "0.7", features = ["nightly"] }
vek = { version = "0.9", features = ["serde"] }
dot_vox = "1.0"
dot_vox = "4.0"
threadpool = "1.7"
mio = "0.6"
mio-extras = "2.0"

View File

@ -19,6 +19,12 @@ pub enum Gender {
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct AnimationHistory {
pub last: Option<Animation>,
pub current: Animation,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Animation {
Idle,
Run,
@ -55,6 +61,6 @@ impl Component for Character {
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
}
impl Component for Animation {
impl Component for AnimationHistory {
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
}

View File

@ -7,4 +7,5 @@ pub mod phys;
pub use agent::{Agent, Control};
pub use character::Character;
pub use player::Player;
pub use character::AnimationHistory;
pub use character::Animation;

View File

@ -11,7 +11,7 @@ pub enum ClientMsg {
Ping,
Pong,
Chat(String),
PlayerAnimation(comp::character::Animation),
PlayerAnimation(comp::character::AnimationHistory),
PlayerPhysics {
pos: comp::phys::Pos,
vel: comp::phys::Vel,

View File

@ -25,7 +25,7 @@ pub enum ServerMsg {
},
EntityAnimation {
entity: u64,
animation: comp::Animation,
animation_history: comp::AnimationHistory,
},
TerrainChunkUpdate {
key: Vec3<i32>,

View File

@ -97,41 +97,41 @@ impl State {
ecs.register_synced::<comp::Player>();
// Register unsynched (or synced by other means) components
ecs.internal_mut().register::<comp::phys::Pos>();
ecs.internal_mut().register::<comp::phys::Vel>();
ecs.internal_mut().register::<comp::phys::Dir>();
ecs.internal_mut().register::<comp::Animation>();
ecs.internal_mut().register::<comp::Agent>();
ecs.internal_mut().register::<comp::Control>();
ecs.register::<comp::phys::Pos>();
ecs.register::<comp::phys::Vel>();
ecs.register::<comp::phys::Dir>();
ecs.register::<comp::AnimationHistory>();
ecs.register::<comp::Agent>();
ecs.register::<comp::Control>();
// Register resources used by the ECS
ecs.internal_mut().add_resource(TimeOfDay(0.0));
ecs.internal_mut().add_resource(Time(0.0));
ecs.internal_mut().add_resource(DeltaTime(0.0));
ecs.internal_mut().add_resource(TerrainMap::new());
ecs.add_resource(TimeOfDay(0.0));
ecs.add_resource(Time(0.0));
ecs.add_resource(DeltaTime(0.0));
ecs.add_resource(TerrainMap::new());
}
/// Register a component with the state's ECS
pub fn with_component<T: Component>(mut self) -> Self
where <T as Component>::Storage: Default
{
self.ecs.internal_mut().register::<T>();
self.ecs.register::<T>();
self
}
/// Write a component attributed to a particular entity
pub fn write_component<C: Component>(&mut self, entity: EcsEntity, comp: C) {
let _ = self.ecs.internal_mut().write_storage().insert(entity, comp);
let _ = self.ecs.write_storage().insert(entity, comp);
}
/// Read a component attributed to a particular entity
pub fn read_component_cloned<C: Component + Clone>(&self, entity: EcsEntity) -> Option<C> {
self.ecs.internal().read_storage().get(entity).cloned()
self.ecs.read_storage().get(entity).cloned()
}
/// Get a read-only reference to the storage of a particular component type
pub fn read_storage<C: Component>(&self) -> EcsStorage<C, Fetch<EcsMaskedStorage<C>>> {
self.ecs.internal().read_storage::<C>()
self.ecs.read_storage::<C>()
}
/// Get a reference to the internal ECS world
@ -154,27 +154,25 @@ impl State {
///
/// Note that this should not be used for physics, animations or other such localised timings.
pub fn get_time_of_day(&self) -> f64 {
self.ecs.internal().read_resource::<TimeOfDay>().0
self.ecs.read_resource::<TimeOfDay>().0
}
/// Get the current in-game time.
///
/// Note that this does not correspond to the time of day.
pub fn get_time(&self) -> f64 {
self.ecs.internal().read_resource::<Time>().0
self.ecs.read_resource::<Time>().0
}
/// Get a reference to this state's terrain.
pub fn terrain(&self) -> Fetch<TerrainMap> {
self.ecs
.internal()
.read_resource::<TerrainMap>()
}
/// Insert the provided chunk into this state's terrain.
pub fn insert_chunk(&mut self, key: Vec3<i32>, chunk: TerrainChunk) {
if self.ecs
.internal_mut()
.write_resource::<TerrainMap>()
.insert(key, chunk)
.is_some()
@ -188,19 +186,19 @@ impl State {
/// Execute a single tick, simulating the game state by the given duration.
pub fn tick(&mut self, dt: Duration) {
// Change the time accordingly
self.ecs.internal_mut().write_resource::<TimeOfDay>().0 += dt.as_secs_f64() * DAY_CYCLE_FACTOR;
self.ecs.internal_mut().write_resource::<Time>().0 += dt.as_secs_f64();
self.ecs.write_resource::<TimeOfDay>().0 += dt.as_secs_f64() * DAY_CYCLE_FACTOR;
self.ecs.write_resource::<Time>().0 += dt.as_secs_f64();
// Run systems to update the world
self.ecs.internal_mut().write_resource::<DeltaTime>().0 = dt.as_secs_f64();
self.ecs.write_resource::<DeltaTime>().0 = dt.as_secs_f64();
// Create and run dispatcher for ecs systems
let mut dispatch_builder = DispatcherBuilder::new();
sys::add_local_systems(&mut dispatch_builder);
// This dispatches all the systems in parallel
dispatch_builder.build().dispatch(&self.ecs.internal_mut().res);
dispatch_builder.build().dispatch(&self.ecs.res);
self.ecs.internal_mut().maintain();
self.ecs.maintain();
}
/// Clean up the state after a tick

View File

@ -3,7 +3,7 @@ use specs::{Join, Read, ReadStorage, System, WriteStorage, Entities};
use vek::*;
// Crate
use crate::comp::{Control, Animation, phys::{Pos, Vel, Dir}};
use crate::comp::{Control, Animation, AnimationHistory, phys::{Pos, Vel, Dir}};
// Basic ECS AI agent system
pub struct Sys;
@ -13,7 +13,7 @@ impl<'a> System<'a> for Sys {
Entities<'a>,
WriteStorage<'a, Vel>,
WriteStorage<'a, Dir>,
WriteStorage<'a, Animation>,
WriteStorage<'a, AnimationHistory>,
ReadStorage<'a, Control>,
);
@ -23,12 +23,20 @@ impl<'a> System<'a> for Sys {
// Apply physics to the player: acceleration and non-linear decceleration
vel.0 += control.move_dir * 2.0 - vel.0.map(|e| e * e.abs() + e) * 0.03;
if control.move_dir.magnitude() > 0.01 {
dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
anims.insert(entity, Animation::Run);
} else {
anims.insert(entity, Animation::Idle);
}
let animation =
if control.move_dir.magnitude() > 0.01 {
dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
Animation::Run
} else {
Animation::Idle
};
let last_animation = anims.get_mut(entity).map(|h| h.current);
anims.insert(entity, AnimationHistory {
last: last_animation,
current: animation,
});
}
}
}

View File

@ -133,7 +133,7 @@ fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &Chat
let opt_alias = scan_fmt!(&args, action.arg_fmt, String);
match opt_alias {
Some(alias) => {
let ecs = server.state.ecs().internal();
let ecs = server.state.ecs();
let opt_player = (&ecs.entities(), &ecs.read_storage::<comp::player::Player>())
.join()
.find(|(_, player)| player.alias == alias)

View File

@ -15,6 +15,7 @@ use common::{
net::PostOffice,
state::{State, Uid},
terrain::TerrainChunk,
comp::character::Animation,
};
use specs::{
join::Join, saveload::MarkedBuilder, world::EntityBuilder as EcsEntityBuilder, Builder,
@ -25,7 +26,7 @@ use threadpool::ThreadPool;
use vek::*;
use world::World;
const CLIENT_TIMEOUT: f64 = 5.0; // Seconds
const CLIENT_TIMEOUT: f64 = 20.0; // Seconds
pub enum Event {
ClientConnected { entity: EcsEntity },
@ -53,7 +54,7 @@ impl Server {
let (chunk_tx, chunk_rx) = mpsc::channel();
let mut state = State::new();
state.ecs_mut().internal_mut().register::<comp::phys::ForceUpdate>();
state.ecs_mut().register::<comp::phys::ForceUpdate>();
let mut this = Self {
state,
@ -153,12 +154,11 @@ impl Server {
for (key, chunk) in self.chunk_rx.try_iter() {
// Send the chunk to all nearby players
for (entity, player, pos) in (
&self.state.ecs().internal().entities(),
&self.state.ecs().internal().read_storage::<comp::Player>(),
&self.state.ecs().entities(),
&self.state.ecs().read_storage::<comp::Player>(),
&self
.state
.ecs()
.internal()
.read_storage::<comp::phys::Pos>(),
)
.join()
@ -235,28 +235,7 @@ impl Server {
match client.state {
ClientState::Connecting => match msg {
ClientMsg::Connect { player, character } => {
// Write client components
state.write_component(entity, player);
state.write_component(entity, comp::phys::Pos(Vec3::zero()));
state.write_component(entity, comp::phys::Vel(Vec3::zero()));
state.write_component(entity, comp::phys::Dir(Vec3::unit_y()));
if let Some(character) = character {
state.write_component(entity, character);
}
state.write_component(entity, comp::phys::ForceUpdate);
client.state = ClientState::Connected;
// Return a handshake with the state of the current world
client.notify(ServerMsg::Handshake {
ecs_state: state.ecs().gen_state_package(),
player_entity: state
.ecs()
.uid_from_entity(entity)
.unwrap()
.into(),
});
Self::initialize_client(state, entity, client, player, character);
}
_ => disconnect = true,
},
@ -266,7 +245,7 @@ impl Server {
ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong),
ClientMsg::Pong => {}
ClientMsg::Chat(msg) => new_chat_msgs.push((entity, msg)),
ClientMsg::PlayerAnimation(animation) => state.write_component(entity, animation),
ClientMsg::PlayerAnimation(animation_history) => state.write_component(entity, animation_history),
ClientMsg::PlayerPhysics { pos, vel, dir } => {
state.write_component(entity, pos);
state.write_component(entity, vel);
@ -313,7 +292,6 @@ impl Server {
match self
.state
.ecs()
.internal()
.read_storage::<comp::Player>()
.get(entity)
{
@ -341,6 +319,63 @@ impl Server {
Ok(frontend_events)
}
/// Initialize a new client states with important information
fn initialize_client(
state: &mut State,
entity: specs::Entity,
client: &mut Client,
player: comp::Player,
character: Option<comp::Character>,
) {
// Save player metadata (for example the username)
state.write_component(entity, player);
// Give the player it's character if he wants one
// (Chat only clients don't need one for example)
if let Some(character) = character {
state.write_component(entity, character);
// Every character has to have these components
state.write_component(entity, comp::phys::Pos(Vec3::zero()));
state.write_component(entity, comp::phys::Vel(Vec3::zero()));
state.write_component(entity, comp::phys::Dir(Vec3::unit_y()));
// Make sure everything is accepted
state.write_component(entity, comp::phys::ForceUpdate);
// Set initial animation
state.write_component(entity, comp::AnimationHistory {
last: None,
current: Animation::Idle
});
}
client.state = ClientState::Connected;
// Return a handshake with the state of the current world
// (All components Sphynx tracks)
client.notify(ServerMsg::Handshake {
ecs_state: state.ecs().gen_state_package(),
player_entity: state
.ecs()
.uid_from_entity(entity)
.unwrap()
.into(),
});
// Sync logical information other players have authority over, not the server
for (other_entity, &uid, &animation_history) in (
&state.ecs().entities(),
&state.ecs().read_storage::<common::state::Uid>(),
&state.ecs().read_storage::<comp::AnimationHistory>(),
).join() {
// AnimationHistory
client.postbox.send_message(ServerMsg::EntityAnimation {
entity: uid.into(),
animation_history: animation_history,
});
}
}
/// Sync client states with the most up to date information
fn sync_clients(&mut self) {
// Sync 'logical' state using Sphynx
@ -348,12 +383,12 @@ impl Server {
// Sync 'physical' state
for (entity, &uid, &pos, &vel, &dir, force_update) in (
&self.state.ecs().internal().entities(),
&self.state.ecs().internal().read_storage::<Uid>(),
&self.state.ecs().internal().read_storage::<comp::phys::Pos>(),
&self.state.ecs().internal().read_storage::<comp::phys::Vel>(),
&self.state.ecs().internal().read_storage::<comp::phys::Dir>(),
self.state.ecs().internal().read_storage::<comp::phys::ForceUpdate>().maybe(),
&self.state.ecs().entities(),
&self.state.ecs().read_storage::<Uid>(),
&self.state.ecs().read_storage::<comp::phys::Pos>(),
&self.state.ecs().read_storage::<comp::phys::Vel>(),
&self.state.ecs().read_storage::<comp::phys::Dir>(),
self.state.ecs().read_storage::<comp::phys::ForceUpdate>().maybe(),
).join() {
let msg = ServerMsg::EntityPhysics {
entity: uid.into(),
@ -369,19 +404,32 @@ impl Server {
}
// Sync animation states
for (entity, &uid, &animation) in (
&self.state.ecs().internal().entities(),
&self.state.ecs().internal().read_storage::<Uid>(),
&self.state.ecs().internal().read_storage::<comp::Animation>(),
for (entity, &uid, &animation_history) in (
&self.state.ecs().entities(),
&self.state.ecs().read_storage::<Uid>(),
&self.state.ecs().read_storage::<comp::AnimationHistory>(),
).join() {
// Check if we need to sync
if Some(animation_history.current) == animation_history.last {
continue;
}
self.clients.notify_connected_except(entity, ServerMsg::EntityAnimation {
entity: uid.into(),
animation,
animation_history,
});
}
// Update animation last/current state
for (entity, mut animation_history) in (
&self.state.ecs().entities(),
&mut self.state.ecs().write_storage::<comp::AnimationHistory>()
).join() {
animation_history.last = Some(animation_history.current);
}
// Remove all force flags
self.state.ecs_mut().internal_mut().write_storage::<comp::phys::ForceUpdate>().clear();
self.state.ecs_mut().write_storage::<comp::phys::ForceUpdate>().clear();
}
pub fn generate_chunk(&mut self, key: Vec3<i32>) {

1
voxygen/.gitignore vendored
View File

@ -1,3 +1,4 @@
/target
**/*.rs.bk
Cargo.lock
settings.toml

View File

@ -12,6 +12,7 @@ default = ["gl"]
[dependencies]
common = { package = "veloren-common", path = "../common" }
client = { package = "veloren-client", path = "../client" }
server = { package = "veloren-server", path = "../server" }
# Graphics
gfx = "0.17"
@ -21,6 +22,7 @@ glutin = "0.19"
winit = {version = "0.18", features = ["serde"]}
conrod_core = { git = "https://gitlab.com/veloren/conrod.git" }
conrod_winit = { git = "https://gitlab.com/veloren/conrod.git" }
euc = "0.2"
# ECS
specs = "0.14"
@ -34,9 +36,11 @@ failure = "0.1"
lazy_static = "1.1"
log = "0.4"
pretty_env_logger = "0.3"
dot_vox = "1.0"
dot_vox = "4.0"
image = "0.21"
config = "0.9"
serde = "1.0"
serde_derive = "1.0"
toml = "0.4"
guillotiere = "0.4"
fnv = "1.0"

View File

@ -8,6 +8,7 @@ use vek::*;
use super::{
CharacterSkeleton,
super::Animation,
SCALE,
};
pub struct IdleAnimation;
@ -22,28 +23,39 @@ impl Animation for IdleAnimation {
time: f64,
) -> Self::Skeleton {
let mut next = (*skeleton).clone();
next.head.offset = Vec3::unit_z() * 13.0 / 11.0;
next.head.ori = Quaternion::rotation_z(0.0);
next.chest.offset = Vec3::unit_z() * 9.0 / 11.0;
next.chest.ori = Quaternion::rotation_z(0.0);
let wave = (time as f32 * 12.0).sin();
let wavecos = (time as f32 * 12.0).cos();
let wave_slow = (time as f32 * 6.0 + PI).sin();
let wavecos_slow = (time as f32 * 6.0 + PI).cos();
let waveultra_slow = (time as f32 * 1.0 + PI).sin();
let waveultracos_slow = (time as f32 * 1.0 + PI).cos();
let wave_dip = (wave_slow.abs() - 0.5).abs();
next.belt.offset = Vec3::unit_z() * 7.0 / 11.0;
next.belt.ori = Quaternion::rotation_z(0.0);
next.head.offset = Vec3::new(0.0, 0.0, 12.0 + waveultra_slow * 0.4) / SCALE;
next.head.ori = Quaternion::rotation_y(waveultra_slow * 0.05);
next.shorts.offset = Vec3::unit_z() * 4.0 / 11.0;
next.shorts.ori = Quaternion::rotation_z(0.0);
next.chest.offset = Vec3::new(0.0, 0.0, 8.0 + waveultra_slow * 0.4) / SCALE;
next.chest.ori = Quaternion::rotation_y(0.0);
next.l_hand.offset = Vec3::new(-8.0, 0.0, 9.0) / 11.0;
next.r_hand.offset = Vec3::new(8.0, 0.0, 9.0 ) / 11.0;
next.belt.offset = Vec3::new(0.0, 0.0, 6.0 + waveultra_slow * 0.4) / SCALE;
next.belt.ori = Quaternion::rotation_y(0.0);
next.l_foot.offset = Vec3::new(-3.5, 0.0, 3.0) / 11.0;
next.l_foot.ori = Quaternion::rotation_x(0.0);
next.r_foot.offset = Vec3::new(3.5, 0.0, 3.0) / 11.0;
next.r_foot.ori = Quaternion::rotation_x(0.0);
next.shorts.offset = Vec3::new(0.0, 0.0, 3.0 + waveultra_slow * 0.4) / SCALE;
next.shorts.ori = Quaternion::rotation_y(0.0);
next.back.offset = Vec3::new(-9.0, 5.0, 18.0);
next.back.ori = Quaternion::rotation_y(2.5);
next.l_hand.offset = Vec3::new(0.0 + waveultracos_slow * 0.3, 7.5, 11.0 + waveultra_slow * 1.1) / SCALE;
next.l_hand.ori = Quaternion::rotation_y(0.0 + waveultra_slow * 0.06);
next.r_hand.offset = Vec3::new(0.0 + waveultracos_slow * 0.3 , - 7.5, 11.0 + waveultra_slow * 1.1) / SCALE;
next.r_hand.ori = Quaternion::rotation_y(0.0 + waveultra_slow * 0.06);
next.l_foot.offset = Vec3::new(2.5, 3.4, 6.0) / SCALE;
next.l_foot.ori = Quaternion::rotation_y(0.04 + waveultra_slow * 0.04);
next.r_foot.offset = Vec3::new(2.5, -3.4, 6.0) / SCALE;
next.r_foot.ori = Quaternion::rotation_y(0.04 + waveultra_slow * 0.04);
next.back.offset = Vec3::new(-6.5, 16.0, 15.0);
next.back.ori = Quaternion::rotation_x(2.5);
next.back.scale = Vec3::one();
next

View File

@ -14,6 +14,8 @@ use super::{
Bone,
};
const SCALE: f32 = 11.0;
#[derive(Clone)]
pub struct CharacterSkeleton {
head: Bone,

View File

@ -8,6 +8,7 @@ use vek::*;
use super::{
CharacterSkeleton,
super::Animation,
SCALE
};
pub struct RunAnimation;
@ -22,34 +23,40 @@ impl Animation for RunAnimation {
) -> Self::Skeleton {
let mut next = (*skeleton).clone();
let wave = (time as f32 * 12.0).sin();
let wave_slow = (time as f32 * 6.0 + PI).sin();
let wave = (time as f32 * 14.0).sin();
let fuzzwave = (time as f32 * 12.0).sin();
let wavecos = (time as f32 * 14.0).cos();
let wave_slow = (time as f32 * 8.0 + PI).sin();
let wavecos_slow = (time as f32 * 8.0 + PI).cos();
let wave_dip = (wave_slow.abs() - 0.5).abs();
next.head.offset = Vec3::unit_z() * 13.0 / 11.0;
next.head.ori = Quaternion::rotation_z(wave * 0.3);
next.head.offset = Vec3::unit_z() * (12.0 + fuzzwave *1.0)/ SCALE;
next.chest.offset = Vec3::unit_z() * 9.0 / 11.0;
next.chest.offset = Vec3::unit_z() * (8.0 + fuzzwave * 0.8) / SCALE;
next.chest.ori = Quaternion::rotation_z(wave * 0.3);
next.belt.offset = Vec3::unit_z() * 7.0 / 11.0;
next.belt.ori = Quaternion::rotation_z(wave * 0.2);
next.belt.offset = Vec3::unit_z() * (6.0 + fuzzwave * 0.8) / SCALE;
next.belt.ori = Quaternion::rotation_z(wave * 0.3);
next.shorts.offset = Vec3::unit_z() * 4.0 / 11.0;
next.shorts.ori = Quaternion::rotation_z(wave * 0.1);
next.shorts.offset = Vec3::unit_z() * (3.0 + fuzzwave * 0.8) / SCALE;
next.shorts.ori = Quaternion::rotation_z(wave * 0.2);
next.l_hand.offset = Vec3::new(-6.0 - wave_dip * 6.0, wave * 5.0, 11.0 - wave_dip * 6.0) / 11.0;
next.r_hand.offset = Vec3::new(6.0 + wave_dip * 6.0, -wave * 5.0, 11.0 - wave_dip * 6.0) / 11.0;
next.l_hand.offset = Vec3::new(0.0 - wavecos * 1.0, 7.5, 11.0 - wave * 1.0) / SCALE;
next.l_hand.ori = Quaternion::rotation_y(wave * -1.8);
next.r_hand.offset = Vec3::new(0.0 + wavecos * 1.0, -7.5, 11.0 + wave * 1.0) / SCALE;
next.r_hand.ori = Quaternion::rotation_y(wave * 1.8);
next.l_foot.offset = Vec3::new(-3.5, 1.0 - wave * 8.0, 3.5 - wave_dip * 4.0) / 11.0;
next.l_foot.ori = Quaternion::rotation_x(-wave + 1.0);
next.r_foot.offset = Vec3::new(3.5, 1.0 + wave * 8.0, 3.5 - wave_dip * 4.0) / 11.0;
next.r_foot.ori = Quaternion::rotation_x(wave + 1.0);
next.l_foot.offset = Vec3::new(2.5 - wavecos * 4.0, 3.4, 6.0 + wave * 2.9) / SCALE;
next.l_foot.ori = Quaternion::rotation_y(wave * -1.0);
next.r_foot.offset = Vec3::new(2.5 + wavecos * 4.0, -3.4, 6.0 - wave * 2.9) / SCALE;
next.back.offset = Vec3::new(-9.0, 5.0, 18.0);
next.back.ori = Quaternion::rotation_y(2.5);
next.r_foot.ori = Quaternion::rotation_y(wave * 1.0);
next.back.offset = Vec3::new(-6.0, 16.0, 15.0);
next.back.ori = Quaternion::rotation_x(2.5);
next.back.scale = Vec3::one();
next
}
}

View File

@ -83,34 +83,42 @@ impl Chat {
self.new_messages = false;
}
// Only show if it has the keyboard captured
// Chat input with rectangle as background
let text_edit = TextEdit::new(&self.input)
.w(460.0)
.restrict_to_height(false)
.line_spacing(2.0)
.font_size(15)
.font_id(font);
let y = match text_edit.get_y_dimension(ui_widgets) {
Dimension::Absolute(y) => y + 6.0,
_ => 0.0,
};
Rectangle::fill([470.0, y])
.rgba(0.0, 0.0, 0.0, 0.8)
.bottom_left_with_margins_on(ui_widgets.window, 10.0, 10.0)
.w(470.0)
.set(self.ids.input_bg, ui_widgets);
if let Some(str) = text_edit
.top_left_with_margins_on(self.ids.input_bg, 1.0, 1.0)
.set(self.ids.input, ui_widgets)
{
self.input = str.to_string();
self.input.retain(|c| c != '\n');
let keyboard_captured = ui_widgets.global_input().current.widget_capturing_keyboard.map_or(false, |id| id == self.ids.input);
if keyboard_captured {
let text_edit = TextEdit::new(&self.input)
.w(460.0)
.restrict_to_height(false)
.line_spacing(2.0)
.font_size(15)
.font_id(font);
let y = match text_edit.get_y_dimension(ui_widgets) {
Dimension::Absolute(y) => y + 6.0,
_ => 0.0,
};
Rectangle::fill([470.0, y])
.rgba(0.0, 0.0, 0.0, 0.8)
.bottom_left_with_margins_on(ui_widgets.window, 10.0, 10.0)
.w(470.0)
.set(self.ids.input_bg, ui_widgets);
if let Some(str) = text_edit
.top_left_with_margins_on(self.ids.input_bg, 1.0, 1.0)
.set(self.ids.input, ui_widgets)
{
self.input = str.to_string();
self.input.retain(|c| c != '\n');
}
}
// Message box
Rectangle::fill([470.0, 174.0])
.rgba(0.0, 0.0, 0.0, 0.4)
.up_from(self.ids.input_bg, 0.0)
.and(|r| if keyboard_captured {
r.up_from(self.ids.input_bg, 0.0)
} else {
r.bottom_left_with_margins_on(ui_widgets.window, 10.0, 10.0)
})
.set(self.ids.message_box_bg, ui_widgets);
let (mut items, _) = List::flow_down(self.messages.len() + 1)
.top_left_of(self.ids.message_box_bg)
@ -154,13 +162,13 @@ impl Chat {
}
}
// If enter is pressed send the current message
// If enter is pressed and the input box is not empty send the current message
if ui_widgets
.widget_input(self.ids.input)
.presses()
.key()
.any(|key_press| match key_press.key {
Key::Return => true,
Key::Return if !self.input.is_empty() => true,
_ => false,
})
{

File diff suppressed because it is too large Load Diff

View File

@ -13,12 +13,14 @@ pub mod session;
pub mod ui;
pub mod window;
pub mod settings;
pub mod singleplayer;
// Reexports
pub use crate::error::Error;
// Standard
use std::mem;
use std::thread;
// Library
use log;
@ -28,13 +30,18 @@ use pretty_env_logger;
use crate::{
menu::main::MainMenuState,
window::Window,
settings::Settings
settings::Settings,
singleplayer::Singleplayer,
};
/// The URL of the default public server that Voxygen will connect to
const DEFAULT_PUBLIC_SERVER: &'static str = "server.veloren.net";
/// A type used to store state that is shared between all play states
pub struct GlobalState {
settings: Settings,
window: Window,
singleplayer: Option<Singleplayer>,
}
impl GlobalState {
@ -88,6 +95,7 @@ fn main() {
let mut global_state = GlobalState {
settings,
window,
singleplayer: None,
};
// Set up the initial play state

View File

@ -45,7 +45,10 @@ impl PlayState for CharSelectionState {
// Handle window events
for event in global_state.window.fetch_events() {
match event {
Event::Close => return PlayStateResult::Shutdown,
Event::Close => {
global_state.singleplayer = None;
return PlayStateResult::Shutdown;
},
// Pass events to ui
Event::Ui(event) => {
self.char_selection_ui.handle_event(event);
@ -60,8 +63,11 @@ impl PlayState for CharSelectionState {
// Maintain the UI
for event in self.char_selection_ui.maintain(global_state.window.renderer_mut()) {
match event {
ui::Event::Logout => return PlayStateResult::Pop,
ui::Event::Play => return PlayStateResult::Push(
ui::Event::Logout => {
global_state.singleplayer = None;
return PlayStateResult::Pop;
},
ui::Event::Play => return PlayStateResult::Switch(
Box::new(SessionState::new(&mut global_state.window, self.client.clone()))
),
}

View File

@ -235,7 +235,7 @@ impl Imgs {
.as_slice(),
)
.unwrap();
ui.new_image(renderer, &image).unwrap()
ui.new_graphic(ui::Graphic::Image(image))
};
Imgs {
v_logo: load("element/v_logo.png"),
@ -377,20 +377,16 @@ impl CharSelectionUi {
// Load images
let imgs = Imgs::new(&mut ui, window.renderer_mut());
// Load fonts
let font_opensans = ui.new_font(
conrod_core::text::font::from_file(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../assets/voxygen/font/OpenSans-Regular.ttf"
))
.unwrap(),
);
let font_metamorph = ui.new_font(
conrod_core::text::font::from_file(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../assets/voxygen/font/Metamorphous-Regular.ttf"
))
.unwrap(),
);
let load_font = |filename, ui: &mut Ui| {
let fullpath: String = ["/voxygen/font", filename].concat();
ui.new_font(conrod_core::text::Font::from_bytes(
assets::load(fullpath.as_str())
.expect("Error loading file")
).unwrap())
};
let font_opensans = load_font("/OpenSans-Regular.ttf", &mut ui);
let font_metamorph = load_font("/Metamorphous-Regular.ttf", &mut ui);
Self {
ui,
imgs,
@ -411,6 +407,7 @@ impl CharSelectionUi {
fn update_layout(&mut self) -> Vec<Event> {
let mut events = Vec::new();
let ref mut ui_widgets = self.ui.set_widgets();
let version = env!("CARGO_PKG_VERSION");
// Character Selection /////////////////
// Supposed functionality:
@ -475,7 +472,7 @@ impl CharSelectionUi {
Button::image(self.imgs.v_logo)
.w_h(346.0, 111.0)
.top_left_with_margins_on(self.ids.bg_selection, 30.0, 40.0)
.label("Alpha 0.1")
.label(version)
.label_rgba(1.0, 1.0, 1.0, 1.0)
.label_font_size(10)
.label_y(conrod_core::position::Relative::Scalar(-40.0))

View File

@ -22,10 +22,10 @@ pub struct ClientInit {
impl ClientInit {
pub fn new(
connection_args: (String, u16, bool),
client_args: (comp::Player, Option<comp::Character>, Option<comp::Animation>, u64),
client_args: (comp::Player, Option<comp::Character>, u64),
) -> Self {
let (server_address, default_port, prefer_ipv6) = connection_args;
let (player, character, animation, view_distance) = client_args;
let (player, character, view_distance) = client_args;
let (tx, rx) = channel();

View File

@ -5,6 +5,7 @@ use super::char_selection::CharSelectionState;
use crate::{
window::{Event, Window},
GlobalState, PlayState, PlayStateResult,
singleplayer::Singleplayer,
};
use client_init::{ClientInit, Error as InitError};
use common::{clock::Clock, comp};
@ -60,7 +61,7 @@ impl PlayState for MainMenuState {
global_state.window.renderer_mut().clear(BG_COLOR);
// Poll client creation
match client_init.as_ref().and_then(|init| init.poll()) {
match client_init.as_ref().and_then(|init| init.poll()) {
Some(Ok(client)) => {
self.main_menu_ui.connected();
return PlayStateResult::Push(Box::new(CharSelectionState::new(
@ -70,11 +71,14 @@ impl PlayState for MainMenuState {
}
Some(Err(err)) => {
client_init = None;
self.main_menu_ui.login_error(match err {
InitError::BadAddress(_) | InitError::NoAddress => "No such host is known",
InitError::ConnectionFailed(_) => "Could not connect to address",
}.to_string());
},
self.main_menu_ui.login_error(
match err {
InitError::BadAddress(_) | InitError::NoAddress => "Server not found",
InitError::ConnectionFailed(_) => "Connection failed",
}
.to_string(),
);
}
None => {}
}
@ -95,11 +99,13 @@ impl PlayState for MainMenuState {
(
comp::Player::new(username.clone()),
Some(comp::Character::test()),
Some(comp::Animation::Idle),
300,
),
)));
}
},
MainMenuEvent::StartSingleplayer => {
global_state.singleplayer = Some(Singleplayer::new());
},
MainMenuEvent::Quit => return PlayStateResult::Shutdown,
}
}

View File

@ -2,9 +2,14 @@ use crate::{
render::Renderer,
ui::{self, ScaleMode, Ui},
window::Window,
DEFAULT_PUBLIC_SERVER,
};
use common::{
assets,
figure::Segment,
};
use common::assets;
use conrod_core::{
color,
color::TRANSPARENT,
image::Id as ImgId,
position::{Dimension, Relative},
@ -36,6 +41,9 @@ widget_ids! {
servers_button,
settings_button,
quit_button,
// Error
error_frame,
button_ok,
}
}
@ -52,11 +60,15 @@ struct Imgs {
button: ImgId,
button_hover: ImgId,
button_press: ImgId,
error_frame: ImgId,
button_dark: ImgId,
button_dark_hover: ImgId,
button_dark_press: ImgId,
}
impl Imgs {
fn new(ui: &mut Ui, renderer: &mut Renderer) -> Imgs {
// TODO: update paths
let mut load = |filename| {
let load_img = |filename, ui: &mut Ui| {
let fullpath: String = ["/voxygen/", filename].concat();
let image = image::load_from_memory(
assets::load(fullpath.as_str())
@ -64,24 +76,41 @@ impl Imgs {
.as_slice(),
)
.unwrap();
ui.new_image(renderer, &image).unwrap()
ui.new_graphic(ui::Graphic::Image(image))
};
let load_vox = |filename, ui: &mut Ui| {
let fullpath: String = ["/voxygen/", filename].concat();
let dot_vox = dot_vox::load_bytes(
assets::load(fullpath.as_str())
.expect("Error loading file")
.as_slice(),
)
.unwrap();
ui.new_graphic(ui::Graphic::Voxel(Segment::from(dot_vox)))
};
Imgs {
bg: load("background/bg_main.png"),
v_logo: load("element/v_logo.png"),
bg: load_img("background/bg_main.png", ui),
v_logo: load_img("element/v_logo.png", ui),
// Input fields
input_bg: load("element/misc_backgrounds/textbox.png"),
input_bg: load_img("element/misc_backgrounds/textbox.png", ui),
// Login button
login_button: load("element/buttons/button_login.png"),
login_button_hover: load("element/buttons/button_login_hover.png"),
login_button_press: load("element/buttons/button_login_press.png"),
login_button: load_img("element/buttons/button_login.png", ui),
login_button_hover: load_img("element/buttons/button_login_hover.png", ui),
login_button_press: load_img("element/buttons/button_login_press.png", ui),
// Servers, settings, and quit buttons
button: load("element/buttons/button.png"),
button_hover: load("element/buttons/button_hover.png"),
button_press: load("element/buttons/button_press.png"),
//button: load_vox("element/buttons/button.vox", ui),
button: load_img("element/buttons/button.png", ui),
button_hover: load_img("element/buttons/button_hover.png", ui),
button_press: load_img("element/buttons/button_press.png", ui),
//Error
error_frame: load_img("element/frames/window_2.png", ui),
button_dark: load_img("element/buttons/button_dark.png", ui),
button_dark_hover: load_img("element/buttons/button_dark_hover.png", ui),
button_dark_press: load_img("element/buttons/button_dark_press.png", ui),
}
}
}
@ -91,6 +120,7 @@ pub enum Event {
username: String,
server_address: String,
},
StartSingleplayer,
Quit,
}
@ -116,20 +146,16 @@ impl MainMenuUi {
// Load images
let imgs = Imgs::new(&mut ui, window.renderer_mut());
// Load fonts
let font_opensans = ui.new_font(
conrod_core::text::font::from_file(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../assets/voxygen/font/OpenSans-Regular.ttf"
))
.unwrap(),
);
let font_metamorph = ui.new_font(
conrod_core::text::font::from_file(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../assets/voxygen/font/Metamorphous-Regular.ttf"
))
.unwrap(),
);
let load_font = |filename, ui: &mut Ui| {
let fullpath: String = ["/voxygen/font", filename].concat();
ui.new_font(conrod_core::text::Font::from_bytes(
assets::load(fullpath.as_str())
.expect("Error loading file")
).unwrap())
};
let font_opensans = load_font("/OpenSans-Regular.ttf", &mut ui);
let font_metamorph = load_font("/Metamorphous-Regular.ttf", &mut ui);
Self {
ui,
imgs,
@ -137,7 +163,7 @@ impl MainMenuUi {
font_metamorph,
font_opensans,
username: "Username".to_string(),
server_address: "veloren.mac94.de".to_string(),
server_address: DEFAULT_PUBLIC_SERVER.to_string(),
login_error: None,
connecting: None,
}
@ -146,6 +172,7 @@ impl MainMenuUi {
fn update_layout(&mut self) -> Vec<Event> {
let mut events = Vec::new();
let ref mut ui_widgets = self.ui.set_widgets();
let version = env!("CARGO_PKG_VERSION");
// Background image, Veloren logo, Alpha-Version Label
Image::new(self.imgs.bg)
.middle_of(ui_widgets.window)
@ -153,7 +180,7 @@ impl MainMenuUi {
Button::image(self.imgs.v_logo)
.w_h(346.0, 111.0)
.top_left_with_margins(30.0, 40.0)
.label("Alpha 0.1")
.label(version)
.label_rgba(1.0, 1.0, 1.0, 1.0)
.label_font_size(10)
.label_y(Relative::Scalar(-40.0))
@ -172,6 +199,20 @@ impl MainMenuUi {
});
};
}
//Singleplayer
//Used when the singleplayer button is pressed
macro_rules! singleplayer {
() => {
self.login_error = None;
events.push(Event::StartSingleplayer);
events.push(Event::LoginAttempt {
username: "singleplayer".to_string(),
server_address: "localhost".to_string(),
});
};
}
const TEXT_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0);
// Username
// TODO: get a lower resolution and cleaner input_bg.png
@ -203,20 +244,34 @@ impl MainMenuUi {
// Login error
if let Some(msg) = &self.login_error {
let text = Text::new(&msg)
.rgba(0.5, 0.0, 0.0, 1.0)
.rgba(1.0, 1.0, 1.0, 1.0)
.font_size(30)
.font_id(self.font_opensans);
let x = match text.get_x_dimension(ui_widgets) {
Dimension::Absolute(x) => x + 10.0,
_ => 0.0,
};
Rectangle::fill([x, 40.0])
.rgba(0.2, 0.3, 0.3, 0.7)
Rectangle::fill_with([400.0, 100.0], color::TRANSPARENT)
.rgba(0.1, 0.1, 0.1, 1.0)
.parent(ui_widgets.window)
.up_from(self.ids.username_bg, 35.0)
.mid_top_with_margin_on(self.ids.username_bg, -35.0)
.set(self.ids.login_error_bg, ui_widgets);
text.middle_of(self.ids.login_error_bg)
Image::new(self.imgs.error_frame)
.w_h(400.0, 100.0)
.middle_of(self.ids.login_error_bg)
.set(self.ids.error_frame, ui_widgets);
text.mid_top_with_margin_on(self.ids.error_frame, 10.0)
.set(self.ids.login_error, ui_widgets);
if Button::image(self.imgs.button_dark)
.w_h(100.0, 30.0)
.mid_bottom_with_margin_on(self.ids.login_error_bg, 5.0)
.hover_image(self.imgs.button_dark_hover)
.press_image(self.imgs.button_dark_press)
.label_y(Relative::Scalar(2.0))
.label("Okay")
.label_font_size(10)
.label_color(TEXT_COLOR)
.set(self.ids.button_ok, ui_widgets)
.was_clicked()
{
self.login_error = None
};
}
// Server address
Image::new(self.imgs.input_bg)
@ -290,12 +345,13 @@ impl MainMenuUi {
.align_middle_x_of(self.ids.address_bg)
.label("Singleplayer")
.label_color(TEXT_COLOR)
.label_font_size(26)
.label_font_size(24)
.label_y(Relative::Scalar(5.0))
.label_x(Relative::Scalar(2.0))
.set(self.ids.singleplayer_button, ui_widgets)
.was_clicked()
{
singleplayer!();
login!();
}
// Quit

View File

@ -65,13 +65,13 @@ impl Mode {
}
}
pub fn create_quad(rect: Aabr<f32>, uv_rect: Aabr<f32>, color: [f32; 4], mode: Mode) -> Quad<UiPipeline> {
pub fn create_quad(rect: Aabr<f32>, uv_rect: Aabr<f32>, color: Rgba<f32>, mode: Mode) -> Quad<UiPipeline> {
let mode_val = mode.value();
let v = |pos, uv| {
Vertex {
pos,
uv,
color,
color: color.into_array(),
mode: mode_val,
}
};
@ -90,13 +90,13 @@ pub fn create_quad(rect: Aabr<f32>, uv_rect: Aabr<f32>, color: [f32; 4], mode: M
)
}
pub fn create_tri(tri: [[f32; 2]; 3], uv_tri: [[f32; 2]; 3], color: [f32; 4], mode: Mode) -> Tri<UiPipeline> {
pub fn create_tri(tri: [[f32; 2]; 3], uv_tri: [[f32; 2]; 3], color: Rgba<f32>, mode: Mode) -> Tri<UiPipeline> {
let mode_val = mode.value();
let v = |pos, uv| {
Vertex {
pos,
uv,
color,
color: color.into_array(),
mode: mode_val,
}
};

View File

@ -81,7 +81,7 @@ impl<P: Pipeline> Texture<P> {
tex,
srv,
sampler: factory.create_sampler(gfx::texture::SamplerInfo::new(
gfx::texture::FilterMethod::Bilinear,
gfx::texture::FilterMethod::Scale,
gfx::texture::WrapMode::Clamp,
)),
_phantom: PhantomData,

View File

@ -8,7 +8,8 @@ use client::Client;
use common::{
comp,
figure::Segment,
msg
msg,
assets,
};
use crate::{
Error,
@ -43,19 +44,25 @@ impl Figures {
pub fn new(renderer: &mut Renderer) -> Self {
// TODO: Make a proper asset loading system
fn load_segment(filename: &'static str) -> Segment {
Segment::from(dot_vox::load(&(concat!(env!("CARGO_MANIFEST_DIR"), "/../assets/voxygen/voxel/").to_string() + filename)).unwrap())
let fullpath: String = ["/voxygen/voxel/", filename].concat();
Segment::from(dot_vox::load_bytes(
assets::load(fullpath.as_str())
.expect("Error loading file")
.as_slice(),
).unwrap())
}
let bone_meshes = [
Some(load_segment("head.vox").generate_mesh(Vec3::new(-7.0, -6.5, -6.0))),
Some(load_segment("chest.vox").generate_mesh(Vec3::new(-6.0, -3.0, 0.0))),
Some(load_segment("belt.vox").generate_mesh(Vec3::new(-5.0, -3.0, 0.0))),
Some(load_segment("pants.vox").generate_mesh(Vec3::new(-5.0, -3.0, 0.0))),
Some(load_segment("hand.vox").generate_mesh(Vec3::new(-2.0, -2.0, -1.0))),
Some(load_segment("hand.vox").generate_mesh(Vec3::new(-2.0, -2.0, -1.0))),
Some(load_segment("foot.vox").generate_mesh(Vec3::new(-2.5, -3.0, -2.0))),
Some(load_segment("foot.vox").generate_mesh(Vec3::new(-2.5, -3.0, -2.0))),
Some(load_segment("sword.vox").generate_mesh(Vec3::new(-6.5, -1.0, 0.0))),
Some(load_segment("head.vox").generate_mesh(Vec3::new(-3.5, -7.0, -6.0))),
Some(load_segment("chest.vox").generate_mesh(Vec3::new(-3.0, -6.0, 0.0))),
Some(load_segment("belt.vox").generate_mesh(Vec3::new(-3.0, -5.0, 0.0))),
Some(load_segment("pants.vox").generate_mesh(Vec3::new(-3.0, -5.0, 0.0))),
Some(load_segment("hand.vox").generate_mesh(Vec3::new(0.0, -2.0, -6.0))),
Some(load_segment("hand.vox").generate_mesh(Vec3::new(0.0, -2.0, -6.0))),
Some(load_segment("foot.vox").generate_mesh(Vec3::new(-4.0, -2.5, -6.0))),
Some(load_segment("foot.vox").generate_mesh(Vec3::new(-4.0, -2.5, -6.0))),
Some(load_segment("sword.vox").generate_mesh(Vec3::new(0.0, -0.0, 0.0))),
None,
None,
None,
@ -82,19 +89,19 @@ impl Figures {
pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) {
let time = client.state().get_time();
let ecs = client.state_mut().ecs_mut().internal_mut();
for (entity, pos, dir, character, animation) in (
let ecs = client.state_mut().ecs_mut();
for (entity, pos, dir, character, animation_history) in (
&ecs.entities(),
&ecs.read_storage::<comp::phys::Pos>(),
&ecs.read_storage::<comp::phys::Dir>(),
&ecs.read_storage::<comp::Character>(),
&ecs.read_storage::<comp::Animation>(),
&ecs.read_storage::<comp::AnimationHistory>(),
).join() {
let state = self.states
.entry(entity)
.or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
let target_skeleton = match animation {
let target_skeleton = match animation_history.current {
comp::character::Animation::Idle => IdleAnimation::update_skeleton(&mut state.skeleton, time),
comp::character::Animation::Run => RunAnimation::update_skeleton(&mut state.skeleton, time),
};
@ -138,7 +145,7 @@ impl<S: Skeleton> FigureState<S> {
let mat =
Mat4::<f32>::identity() *
Mat4::translation_3d(pos) *
Mat4::rotation_z(dir.y.atan2(dir.x) + f32::consts::PI / 2.0);
Mat4::rotation_z(dir.y.atan2(dir.x));// + f32//::consts)::PI / 2.0);
let locals = FigureLocals::new(mat);
renderer.update_consts(&mut self.locals, &[locals]).unwrap();

View File

@ -111,7 +111,6 @@ impl Scene {
let player_pos = client
.state()
.ecs()
.internal()
.read_storage::<comp::phys::Pos>()
.get(client.player())
.map(|pos| pos.0)

View File

@ -120,19 +120,20 @@ impl PlayState for SessionState {
// Handle window events
for event in global_state.window.fetch_events() {
// Pass all events to the ui first
if self.hud.handle_event(event.clone()) {
// Pass all events to the ui first
if self.hud.handle_event(event.clone(), global_state) {
continue;
}
let _handled = match event {
Event::Close => return PlayStateResult::Shutdown,
Event::Close => {
global_state.singleplayer = None;
return PlayStateResult::Shutdown;
},
// Toggle cursor grabbing
Event::KeyDown(Key::ToggleCursor) => {
global_state
.window
.grab_cursor(!global_state.window.is_cursor_grabbed());
self.hud
.update_grab(global_state.window.is_cursor_grabbed());
}
// Movement Key Pressed
Event::KeyDown(Key::MoveForward) => self.key_state.up = true,
@ -166,7 +167,10 @@ impl PlayState for SessionState {
self.client.borrow_mut().send_chat(msg);
},
HudEvent::Logout => return PlayStateResult::Pop,
HudEvent::Quit => return PlayStateResult::Shutdown,
HudEvent::Quit => {
global_state.singleplayer = None;
return PlayStateResult::Shutdown;
},
}
}

View File

@ -34,7 +34,7 @@ pub struct ControlSettings {
pub spellbook: VirtualKeyCode,
pub settings: VirtualKeyCode,
pub help: VirtualKeyCode,
pub interface: VirtualKeyCode,
pub toggle_interface: VirtualKeyCode,
}
impl Default for Settings {
@ -56,7 +56,7 @@ impl Default for Settings {
spellbook: VirtualKeyCode::P,
settings: VirtualKeyCode::N,
help: VirtualKeyCode::F1,
interface: VirtualKeyCode::F2,
toggle_interface: VirtualKeyCode::F2,
},
}
}

View File

@ -0,0 +1,81 @@
use std::time::Duration;
use log::info;
use server::{Input, Event, Server};
use common::clock::Clock;
use std::{
thread,
thread::JoinHandle
};
use std::sync::mpsc::{
channel, Receiver, Sender, TryRecvError,
};
const TPS: u64 = 30;
enum Msg {
Stop,
}
/// Used to start and stop the background thread running the server
/// when in singleplayer mode.
pub struct Singleplayer {
server_thread: JoinHandle<()>,
sender: Sender<Msg>,
}
impl Singleplayer {
pub fn new() -> Self {
let (sender, reciever) = channel();
let thread = thread::spawn(move || {
run_server(reciever);
});
Singleplayer {
server_thread: thread,
sender,
}
}
}
impl Drop for Singleplayer {
fn drop(&mut self) {
self.sender.send(Msg::Stop);
}
}
fn run_server(rec: Receiver<Msg>) {
info!("Starting server-cli...");
// Set up an fps clock
let mut clock = Clock::new();
// Create server
let mut server = Server::new()
.expect("Failed to create server instance");
loop {
let events = server.tick(Input::default(), clock.get_last_delta())
.expect("Failed to tick server");
for event in events {
match event {
Event::ClientConnected { entity } => info!("Client connected!"),
Event::ClientDisconnected { entity } => info!("Client disconnected!"),
Event::Chat { entity, msg } => info!("[Client] {}", msg),
}
}
// Clean up the server after a tick
server.cleanup();
match rec.try_recv() {
Ok(msg) => break,
Err(err) => match err {
TryRecvError::Empty => (),
TryRecvError::Disconnected => break,
},
}
// Wait for the next tick
clock.tick(Duration::from_millis(1000 / TPS));
}
}

View File

@ -0,0 +1,115 @@
use common::figure::Segment;
use fnv::FnvHashMap;
use guillotiere::{size2, Allocation, AtlasAllocator};
use image::DynamicImage;
use vek::*;
pub enum Graphic {
Image(DynamicImage),
Voxel(Segment),
Blank,
}
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
pub struct Id(u32);
type Parameters = (Id, Vec2<u16>, Aabr<u64>);
pub struct GraphicCache {
atlas: AtlasAllocator,
graphic_map: FnvHashMap<Id, Graphic>,
rect_map: FnvHashMap<Parameters, Aabr<u16>>,
next_id: u32,
}
impl GraphicCache {
pub fn new(size: Vec2<u16>) -> Self {
Self {
atlas: AtlasAllocator::new(size2(i32::from(size.x), i32::from(size.y))),
graphic_map: FnvHashMap::default(),
rect_map: FnvHashMap::default(),
next_id: 0,
}
}
pub fn new_graphic(&mut self, graphic: Graphic) -> Id {
let id = self.next_id;
self.next_id = id.wrapping_add(1);
let id = Id(id);
self.graphic_map.insert(id, graphic);
id
}
pub fn get_graphic(&self, id: Id) -> Option<&Graphic> {
self.graphic_map.get(&id)
}
pub fn clear_cache(&mut self, new_size: Vec2<u16>) {
self.rect_map.clear();
self.atlas = AtlasAllocator::new(size2(i32::from(new_size.x), i32::from(new_size.y)));
}
pub fn cache_res<F>(
&mut self,
graphic_id: Id,
dims: Vec2<u16>,
source: Aabr<f64>,
mut cacher: F,
) -> Option<Aabr<u16>>
where
F: FnMut(Aabr<u16>, Vec<[u8; 4]>),
{
match self
.rect_map
.get(&(graphic_id, dims, source.map(|e| e.to_bits()))) //<-------- TODO: Replace this with rounded representation of source
{
Some(aabr) => Some(*aabr),
None => match self.graphic_map.get(&graphic_id) {
Some(graphic) => {
// Allocate rectangle
let aabr = match self
.atlas
.allocate(size2(i32::from(dims.x), i32::from(dims.y)))
{
Some(Allocation { id, rectangle }) => {
let (min, max) = (rectangle.min, rectangle.max);
Aabr {
min: Vec2::new(min.x as u16, min.y as u16),
max: Vec2::new(max.x as u16, max.y as u16),
}
}
// Out of room
// TODO: make more room by 1. expanding cache size, 2. removing unused allocations, 3. rearranging rectangles
None => return None,
};
// Render image
// TODO: use source
let data = match graphic {
Graphic::Image(ref image) => image
.resize_exact(
u32::from(aabr.size().w),
u32::from(aabr.size().h),
image::FilterType::Nearest,
)
.to_rgba()
.pixels()
.map(|p| p.data)
.collect::<Vec<[u8; 4]>>(),
Graphic::Voxel(segment) => {
super::renderer::draw_vox(&segment, aabr.size().into())
}
Graphic::Blank => return None,
};
// Draw to allocated area
cacher(aabr, data);
// Insert area into map for retrieval
self.rect_map
.insert((graphic_id, dims, source.map(|e| e.to_bits())), aabr);
// Return area
Some(aabr)
}
None => None,
},
}
}
}

View File

@ -0,0 +1,4 @@
mod graphic;
mod renderer;
pub use graphic::{Graphic, GraphicCache, Id};

View File

@ -0,0 +1,218 @@
use super::super::{linear_to_srgb, srgb_to_linear};
use common::{
figure::Segment,
vol::{ReadVol, SizedVol, Vox},
};
use euc::{buffer::Buffer2d, rasterizer, Pipeline};
use vek::*;
struct Voxel {
mvp: Mat4<f32>,
}
#[derive(Copy, Clone)]
struct Vert {
pos: Vec3<f32>,
col: Rgb<f32>,
norm: Vec3<f32>,
ao_level: u8,
}
impl Vert {
fn new(pos: Vec3<f32>, col: Rgb<f32>, norm: Vec3<f32>, ao_level: u8) -> Self {
Vert {
pos,
col,
norm,
ao_level,
}
}
}
impl<'a> Pipeline for Voxel {
type Vertex = Vert;
type VsOut = Rgba<f32>;
type Pixel = [u8; 4];
#[inline(always)]
fn vert(
&self,
Vert {
pos,
col,
norm,
ao_level,
}: &Self::Vertex,
) -> ([f32; 3], Self::VsOut) {
let light = Rgba::from_opaque(Rgb::from(*ao_level as f32 / 4.0 + 0.25));
let color = light * srgb_to_linear(Rgba::from_opaque(*col));
let position = Vec3::from(self.mvp * Vec4::from_point(*pos)).into_array();
(position, color)
}
#[inline(always)]
fn frag(&self, color: &Self::VsOut) -> Self::Pixel {
linear_to_srgb(*color)
.map(|e| (e * 255.0) as u8)
.into_array()
}
}
pub fn draw_vox(segment: &Segment, output_size: Vec2<u16>) -> Vec<[u8; 4]> {
let dims = output_size.map(|e| e as usize).into_array();
let mut color = Buffer2d::new(dims, [0; 4]);
let mut depth = Buffer2d::new(dims, 1.0);
let (w, h, d) = segment.get_size().map(|e| e as f32).into_tuple();
let mvp = Mat4::<f32>::orthographic_rh_no(FrustumPlanes {
left: -1.0,
right: 1.0,
bottom: -1.0,
top: 1.0,
near: 0.0,
far: 1.0,
}) * Mat4::rotation_x(-std::f32::consts::PI / 2.0)
* Mat4::scaling_3d([2.0 / w, 2.0 / h, 2.0 / d])
* Mat4::translation_3d([-w / 2.0, -h / 2.0, -d / 2.0]);
Voxel { mvp }.draw::<rasterizer::Triangles<_>, _>(
&generate_mesh(segment, Vec3::from(0.0)),
&mut color,
&mut depth,
);
// TODO: remove this clone
color.as_ref().to_vec()
}
fn ao_level(side1: bool, corner: bool, side2: bool) -> u8 {
if side1 && side2 {
0
} else {
3 - [side1, corner, side2].iter().filter(|e| **e).count() as u8
}
}
// TODO: generalize meshing code....
fn create_quad(
origin: Vec3<f32>,
unit_x: Vec3<f32>,
unit_y: Vec3<f32>,
norm: Vec3<f32>,
col: Rgb<f32>,
occluders: [bool; 8],
) -> [Vert; 6] {
let a_ao = ao_level(occluders[0], occluders[1], occluders[2]);
let b_ao = ao_level(occluders[2], occluders[3], occluders[4]);
let c_ao = ao_level(occluders[4], occluders[5], occluders[6]);
let d_ao = ao_level(occluders[6], occluders[7], occluders[0]);
let a = Vert::new(origin, col, norm, a_ao);
let b = Vert::new(origin + unit_x, col, norm, b_ao);
let c = Vert::new(origin + unit_x + unit_y, col, norm, c_ao);
let d = Vert::new(origin + unit_y, col, norm, d_ao);
// Flip to fix anisotropy
let (a, b, c, d) = if a_ao + c_ao > b_ao + d_ao {
(d, a, b, c)
} else {
(a, b, c, d)
};
[
a, b, c, // Tri 1
c, d, a, // Tri 2
]
}
fn generate_mesh(segment: &Segment, offs: Vec3<f32>) -> Vec<Vert> {
let mut vertices = Vec::new();
for pos in segment.iter_positions() {
if let Some(col) = segment.get(pos).ok().and_then(|vox| vox.get_color()) {
let col = col.map(|e| e as f32 / 255.0);
let is_empty = |pos| segment.get(pos).map(|v| v.is_empty()).unwrap_or(true);
let occluders = |unit_x, unit_y, dir| {
// would be nice to generate unit_x and unit_y from a given direction
[
!is_empty(pos + dir - unit_x),
!is_empty(pos + dir - unit_x - unit_y),
!is_empty(pos + dir - unit_y),
!is_empty(pos + dir + unit_x - unit_y),
!is_empty(pos + dir + unit_x),
!is_empty(pos + dir + unit_x + unit_y),
!is_empty(pos + dir + unit_y),
!is_empty(pos + dir - unit_x + unit_y),
]
};
// -x
if is_empty(pos - Vec3::unit_x()) {
vertices.extend_from_slice(&create_quad(
offs + pos.map(|e| e as f32) + Vec3::unit_y(),
-Vec3::unit_y(),
Vec3::unit_z(),
-Vec3::unit_x(),
col,
occluders(-Vec3::unit_y(), Vec3::unit_z(), -Vec3::unit_x()),
));
}
// +x
if is_empty(pos + Vec3::unit_x()) {
vertices.extend_from_slice(&create_quad(
offs + pos.map(|e| e as f32) + Vec3::unit_x(),
Vec3::unit_y(),
Vec3::unit_z(),
Vec3::unit_x(),
col,
occluders(Vec3::unit_y(), Vec3::unit_z(), Vec3::unit_x()),
));
}
// -y
if is_empty(pos - Vec3::unit_y()) {
vertices.extend_from_slice(&create_quad(
offs + pos.map(|e| e as f32),
Vec3::unit_x(),
Vec3::unit_z(),
-Vec3::unit_y(),
col,
occluders(Vec3::unit_x(), Vec3::unit_z(), -Vec3::unit_y()),
));
}
// +y
if is_empty(pos + Vec3::unit_y()) {
vertices.extend_from_slice(&create_quad(
offs + pos.map(|e| e as f32) + Vec3::unit_y(),
Vec3::unit_z(),
Vec3::unit_x(),
Vec3::unit_y(),
col,
occluders(Vec3::unit_z(), Vec3::unit_x(), Vec3::unit_y()),
));
}
// -z
if is_empty(pos - Vec3::unit_z()) {
vertices.extend_from_slice(&create_quad(
offs + pos.map(|e| e as f32),
Vec3::unit_y(),
Vec3::unit_x(),
-Vec3::unit_z(),
col,
occluders(Vec3::unit_y(), Vec3::unit_x(), -Vec3::unit_z()),
));
}
// +z
if is_empty(pos + Vec3::unit_z()) {
vertices.extend_from_slice(&create_quad(
offs + pos.map(|e| e as f32) + Vec3::unit_z(),
Vec3::unit_x(),
Vec3::unit_y(),
Vec3::unit_z(),
col,
occluders(Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z()),
));
}
}
}
vertices
}

View File

@ -1,8 +1,15 @@
mod widgets;
mod graphic;
mod util;
pub use widgets::toggle_button::ToggleButton;
pub use graphic::Graphic;
pub(self) use util::{srgb_to_linear, linear_to_srgb};
use image::DynamicImage;
use graphic::{
GraphicCache,
Id as GraphicId,
};
use conrod_core::{
Ui as CrUi,
UiBuilder,
@ -16,7 +23,7 @@ use conrod_core::{
widget::{Id as WidgId, id::Generator},
render::Primitive,
event::Input,
input::{touch::Touch, Widget, Motion, Button, MouseButton},
input::{touch::Touch, Widget, Motion, Button},
};
use vek::*;
use crate::{
@ -81,9 +88,10 @@ impl Event {
}
pub struct Cache {
blank_texture: Texture<UiPipeline>,
glyph_cache: GlyphCache<'static>,
glyph_cache_tex: Texture<UiPipeline>,
graphic_cache: graphic::GraphicCache,
graphic_cache_tex: Texture<UiPipeline>,
}
// TODO: Should functions be returning UiError instead of Error?
@ -93,23 +101,31 @@ impl Cache {
const SCALE_TOLERANCE: f32 = 0.1;
const POSITION_TOLERANCE: f32 = 0.1;
let graphic_cache_dims = Vec2::new(w * 4, h * 4);
Ok(Self {
blank_texture: renderer.create_texture(&DynamicImage::new_rgba8(1, 1))?,
glyph_cache: GlyphCache::builder()
.dimensions(w as u32, h as u32)
.scale_tolerance(SCALE_TOLERANCE)
.position_tolerance(POSITION_TOLERANCE)
.build(),
glyph_cache_tex: renderer.create_dynamic_texture((w, h).into())?,
graphic_cache: GraphicCache::new(graphic_cache_dims),
graphic_cache_tex: renderer.create_dynamic_texture(graphic_cache_dims)?,
})
}
pub fn blank_texture(&self) -> &Texture<UiPipeline> { &self.blank_texture }
pub fn glyph_cache_tex(&self) -> &Texture<UiPipeline> { &self.glyph_cache_tex }
pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture<UiPipeline>) { (&mut self.glyph_cache, &self.glyph_cache_tex) }
pub fn graphic_cache_tex(&self) -> &Texture<UiPipeline> { &self.graphic_cache_tex }
pub fn graphic_cache_mut_and_tex(&mut self) -> (&mut GraphicCache, &Texture<UiPipeline>) { (&mut self.graphic_cache, &self.graphic_cache_tex) }
pub fn new_graphic(&mut self, graphic: Graphic) -> GraphicId { self.graphic_cache.new_graphic(graphic) }
pub fn clear_graphic_cache(&mut self, renderer: &mut Renderer, new_size: Vec2<u16>) {
self.graphic_cache.clear_cache(new_size);
self.graphic_cache_tex = renderer.create_dynamic_texture(new_size).unwrap();
}
}
enum DrawKind {
Image(ImgId),
Image,
// Text and non-textured geometry
Plain,
}
@ -121,9 +137,9 @@ enum DrawCommand {
Scissor(Aabr<u16>),
}
impl DrawCommand {
fn image(model: Model<UiPipeline>, img_id: ImgId) -> DrawCommand {
fn image(model: Model<UiPipeline>) -> DrawCommand {
DrawCommand::Draw {
kind: DrawKind::Image(img_id),
kind: DrawKind::Image,
model,
}
}
@ -198,7 +214,7 @@ impl Scale {
pub struct Ui {
ui: CrUi,
image_map: Map<Texture<UiPipeline>>,
image_map: Map<GraphicId>,
cache: Cache,
// Draw commands for the next render
draw_commands: Vec<DrawCommand>,
@ -230,8 +246,8 @@ impl Ui {
self.ui.handle_event(Input::Resize(w, h));
}
pub fn new_image(&mut self, renderer: &mut Renderer, image: &DynamicImage) -> Result<ImgId, Error> {
Ok(self.image_map.insert(renderer.create_texture(image)?))
pub fn new_graphic(&mut self, graphic: Graphic) -> ImgId {
self.image_map.insert(self.cache.new_graphic(graphic))
}
pub fn new_font(&mut self, font: Font) -> FontId {
@ -246,7 +262,7 @@ impl Ui {
self.ui.set_widgets()
}
// Accepts option so widget can be unfocused
// Accepts Option so widget can be unfocused
pub fn focus_widget(&mut self, id: Option<WidgId>) {
self.ui.keyboard_capture(match id {
Some(id) => id,
@ -259,7 +275,7 @@ impl Ui {
self.ui.global_input().current.widget_capturing_keyboard
}
// Get whether the a widget besides the window is capturing the mouse
// Get whether a widget besides the window is capturing the mouse
pub fn no_widget_capturing_mouse(&self) -> bool {
self.ui.global_input().current.widget_capturing_mouse.filter(|id| id != &self.ui.window ).is_none()
}
@ -305,7 +321,14 @@ impl Ui {
self.draw_commands.clear();
let mut mesh = Mesh::new();
let mut current_img = None;
// TODO: this could be removed entirely if the draw call just used both textures
// however this allows for flexibility if we want to interleave other draw calls later
enum State {
Image,
Plain,
};
let mut current_state = State::Plain;
let window_scizzor = default_scissor(renderer);
let mut current_scizzor = window_scizzor;
@ -314,9 +337,10 @@ impl Ui {
// `Plain` state.
macro_rules! switch_to_plain_state {
() => {
if let Some(image_id) = current_img.take() {
self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap(), image_id));
if let State::Image = current_state {
self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap()));
mesh.clear();
current_state = State::Plain;
}
};
}
@ -324,7 +348,7 @@ impl Ui {
let p_scale_factor = self.scale.scale_factor_physical();
while let Some(prim) = primitives.next() {
let Primitive {kind, scizzor, id, rect} = prim;
let Primitive {kind, scizzor, id: _id, rect} = prim;
// Check for a change in the scizzor
let new_scizzor = {
@ -348,12 +372,12 @@ impl Ui {
};
if new_scizzor != current_scizzor {
// Finish the current command
match current_img.take() {
None =>
self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap())),
Some(image_id) =>
self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap(), image_id)),
}
self.draw_commands.push(match current_state {
State::Plain =>
DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
State::Image =>
DrawCommand::image(renderer.create_model(&mesh).unwrap()),
});
mesh.clear();
// Update the scizzor and produce a command.
@ -375,52 +399,64 @@ impl Ui {
use conrod_core::render::PrimitiveKind;
match kind {
PrimitiveKind::Image { image_id, color, source_rect } => {
let graphic_id = self.image_map.get(&image_id).expect("Image does not exist in image map");
let (graphic_cache, cache_tex) = self.cache.graphic_cache_mut_and_tex();
// Switch to the `Image` state for this image if we're not in it already.
let new_image_id = image_id;
match current_img {
// If we're already in the drawing mode for this image, we're done.
Some(image_id) if image_id == new_image_id => (),
// If we were in the `Plain` drawing state, switch to Image drawing state.
None => {
self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap()));
mesh.clear();
current_img = Some(new_image_id);
}
// If we were drawing a different image, switch state to draw *this* image.
Some(image_id) => {
self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap(), image_id));
mesh.clear();
current_img = Some(new_image_id);
}
match graphic_cache.get_graphic(*graphic_id) {
Some(Graphic::Blank) | None => continue,
_ => {}
}
let color = srgb_to_linear(color.unwrap_or(conrod_core::color::WHITE).to_fsa());
// Switch to the `Image` state for this image if we're not in it already.
if let State::Plain = current_state {
self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap()));
mesh.clear();
current_state = State::Image;
}
// Transform the source rectangle into uv coordinates
let (image_w, image_h) = self.image_map
.get(&image_id)
.expect("Image does not exist in image map")
.get_dimensions()
.map(|e| e as f64)
.into_tuple();
let (uv_l, uv_r, uv_t, uv_b) = match source_rect {
Some(src_rect) => {
let (l, r, b, t) = src_rect.l_r_b_t();
((l / image_w) as f32,
(r / image_w) as f32,
(b / image_h) as f32,
(t / image_h) as f32)
let color = srgb_to_linear(color.unwrap_or(conrod_core::color::WHITE).to_fsa().into());
let resolution = Vec2::new(
(rect.w() * p_scale_factor) as u16,
(rect.h() * p_scale_factor) as u16,
);
// Transform the source rectangle into uv coordinate
// TODO: make sure this is right
let source_aabr = {
let (uv_l, uv_r, uv_b, uv_t) = (0.0, 1.0, 0.0, 1.0);/*match source_rect {
Some(src_rect) => {
let (l, r, b, t) = src_rect.l_r_b_t();
((l / image_w) as f32,
(r / image_w) as f32,
(b / image_h) as f32,
(t / image_h) as f32)
}
None => (0.0, 1.0, 0.0, 1.0),
};*/
Aabr {
min: Vec2::new(uv_l, uv_b),
max: Vec2::new(uv_r, uv_t),
}
None => (0.0, 1.0, 0.0, 1.0),
};
let uv = Aabr {
min: Vec2::new(uv_l, uv_b),
max: Vec2::new(uv_r, uv_t),
let (cache_w, cache_h) = cache_tex.get_dimensions().map(|e| e as f32).into_tuple();
// Cache graphic at particular resolution
let uv_aabr = match graphic_cache.cache_res(*graphic_id, resolution, source_aabr, |aabr, data| {
let offset = aabr.min.into_array();
let size = aabr.size().into_array();
renderer.update_texture(cache_tex, offset, size, &data);
}) {
Some(aabr) => Aabr {
min: Vec2::new(aabr.min.x as f32 / cache_w, aabr.max.y as f32 / cache_h),
max: Vec2::new(aabr.max.x as f32 / cache_w, aabr.min.y as f32 / cache_h),
},
None => continue,
};
mesh.push_quad(create_ui_quad(
gl_aabr(rect),
uv,
uv_aabr,
color,
UiMode::Image,
));
@ -449,7 +485,7 @@ impl Ui {
renderer.update_texture(cache_tex, offset, size, &new_data);
}).unwrap();
let color = srgb_to_linear(color.to_fsa());
let color = srgb_to_linear(color.to_fsa().into());
for g in positioned_glyphs {
if let Ok(Some((uv_rect, screen_rect))) = glyph_cache.rect_for(font_id.index(), g) {
@ -477,7 +513,7 @@ impl Ui {
}
}
PrimitiveKind::Rectangle { color } => {
let color = srgb_to_linear(color.to_fsa());
let color = srgb_to_linear(color.to_fsa().into());
// Don't draw a transparent rectangle
if color[3] == 0.0 {
continue;
@ -497,7 +533,7 @@ impl Ui {
}
PrimitiveKind::TrianglesSingleColor { color, triangles } => {
// Don't draw transparent triangle or switch state if there are actually no triangles
let color: [f32; 4] = srgb_to_linear(color.into());
let color = srgb_to_linear(Rgba::from(Into::<[f32; 4]>::into(color)));
if triangles.is_empty() || color[3] == 0.0 {
continue;
}
@ -529,24 +565,27 @@ impl Ui {
}
_ => {}
// TODO: Add these
//PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);}
// TODO: Add this
//PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);}
// Other uneeded for now
//PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);}
}
}
// Enter the final command
match current_img {
None =>
self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap())),
Some(image_id) =>
self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap(), image_id)),
}
self.draw_commands.push(match current_state {
State::Plain =>
DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
State::Image =>
DrawCommand::image(renderer.create_model(&mesh).unwrap()),
});
// Handle window resizing
if let Some(new_dims) = self.window_resized.take() {
self.scale.window_resized(new_dims, renderer);
let (w, h) = self.scale.scaled_window_size().into_tuple();
self.ui.handle_event(Input::Resize(w, h));
self.cache.clear_graphic_cache(renderer, renderer.get_resolution().map(|e| e * 4));
// TODO: probably need to resize glyph cache, see conrod's gfx backend for reference
}
}
}
@ -560,8 +599,8 @@ impl Ui {
}
DrawCommand::Draw { kind, model } => {
let tex = match kind {
DrawKind::Image(image_id) => {
self.image_map.get(&image_id).expect("Image does not exist in image map")
DrawKind::Image => {
self.cache.graphic_cache_tex()
}
DrawKind::Plain => {
self.cache.glyph_cache_tex()
@ -580,16 +619,4 @@ fn default_scissor(renderer: &mut Renderer) -> Aabr<u16> {
min: Vec2 { x: 0, y: 0 },
max: Vec2 { x: screen_w, y: screen_h }
}
}
fn srgb_to_linear(color: [f32; 4]) -> [f32; 4] {
fn linearize(comp: f32) -> f32 {
if comp <= 0.04045 {
comp / 12.92
} else {
((comp + 0.055) / 1.055).powf(2.4)
}
}
[linearize(color[0]), linearize(color[1]), linearize(color[2]), color[3]]
}
}

36
voxygen/src/ui/util.rs Normal file
View File

@ -0,0 +1,36 @@
use vek::*;
#[inline(always)]
pub fn srgb_to_linear(c: Rgba<f32>) -> Rgba<f32> {
#[inline(always)]
fn to_linear(x: f32) -> f32 {
if x <= 0.04045 {
x / 12.92
} else {
((x + 0.055) / 1.055).powf(2.4)
}
}
Rgba {
r: to_linear(c.r),
g: to_linear(c.g),
b: to_linear(c.b),
a: c.a,
}
}
#[inline(always)]
pub fn linear_to_srgb(c: Rgba<f32>) -> Rgba<f32> {
#[inline(always)]
fn to_srgb(x: f32) -> f32 {
if x <= 0.0031308 {
x * 12.92
} else {
x.powf(1.0 / 2.4) * 1.055 - 0.055
}
}
Rgba {
r: to_srgb(c.r),
g: to_srgb(c.g),
b: to_srgb(c.b),
a: c.a,
}
}

View File

@ -51,7 +51,7 @@ impl Window {
key_map.insert(settings.controls.spellbook, Key::Spellbook);
key_map.insert(settings.controls.settings, Key::Settings);
key_map.insert(settings.controls.help, Key::Help);
key_map.insert(settings.controls.interface, Key::Interface);
key_map.insert(settings.controls.toggle_interface, Key::ToggleInterface);
let tmp = Ok(Self {
events_loop,
@ -180,7 +180,7 @@ pub enum Key {
Social,
Spellbook,
Settings,
Interface,
ToggleInterface,
Help,
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.