mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'zesterer/winit-20' into 'master'
Upgrade winit to 0.22.2 See merge request veloren/veloren!788
This commit is contained in:
commit
23e1378c78
@ -71,6 +71,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Animals are more effective in combat
|
||||
- Pathfinding is much smoother and pets are cleverer
|
||||
- Animals run/turn at different speeds
|
||||
- Updated windowing library (winit 0.19 -> 0.22)
|
||||
|
||||
### Removed
|
||||
|
||||
|
357
Cargo.lock
generated
357
Cargo.lock
generated
@ -63,6 +63,12 @@ version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407"
|
||||
|
||||
[[package]]
|
||||
name = "android_log-sys"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8052e2d8aabbb8d556d6abbcce2a22b9590996c5f849b9c7ce4544a2e3b984e"
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
@ -428,6 +434,17 @@ dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "calloop"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7aa2097be53a00de9e8fc349fea6d76221f398f5c4fa550d420669906962d160"
|
||||
dependencies = [
|
||||
"mio",
|
||||
"mio-extras",
|
||||
"nix 0.14.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.2.3"
|
||||
@ -463,11 +480,10 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "cgl"
|
||||
version = "0.2.3"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55e7ec0b74fe5897894cbc207092c577e87c52f8a59e8ca8d97ef37551f60a49"
|
||||
checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff"
|
||||
dependencies = [
|
||||
"gleam",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@ -530,14 +546,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.18.5"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1706996401131526e36b3b49f0c4d912639ce110996f3ca144d78946727bce54"
|
||||
checksum = "f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"block",
|
||||
"core-foundation",
|
||||
"core-graphics",
|
||||
"core-foundation 0.6.4",
|
||||
"core-graphics 0.17.3",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"objc",
|
||||
@ -545,14 +561,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.19.1"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400"
|
||||
checksum = "0c49e86fc36d5704151f5996b7b3795385f50ce09e3be0f47a0cfde869681cf8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"block",
|
||||
"core-foundation",
|
||||
"core-graphics",
|
||||
"core-foundation 0.7.0",
|
||||
"core-graphics 0.19.2",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"objc",
|
||||
@ -561,7 +577,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "conrod_core"
|
||||
version = "0.63.0"
|
||||
source = "git+https://gitlab.com/veloren/conrod.git?branch=pre-winit-20#46b374edc9537300e5278905ebd14dff45cfd927"
|
||||
source = "git+https://gitlab.com/veloren/conrod.git#1ab6eccf94b16a8977a3274b31d4dbfef9cf9a30"
|
||||
dependencies = [
|
||||
"conrod_derive",
|
||||
"copypasta",
|
||||
@ -576,7 +592,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "conrod_derive"
|
||||
version = "0.63.0"
|
||||
source = "git+https://gitlab.com/veloren/conrod.git?branch=pre-winit-20#46b374edc9537300e5278905ebd14dff45cfd927"
|
||||
source = "git+https://gitlab.com/veloren/conrod.git#1ab6eccf94b16a8977a3274b31d4dbfef9cf9a30"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
@ -586,7 +602,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "conrod_winit"
|
||||
version = "0.63.0"
|
||||
source = "git+https://gitlab.com/veloren/conrod.git?branch=pre-winit-20#46b374edc9537300e5278905ebd14dff45cfd927"
|
||||
source = "git+https://gitlab.com/veloren/conrod.git#1ab6eccf94b16a8977a3274b31d4dbfef9cf9a30"
|
||||
|
||||
[[package]]
|
||||
name = "const-random"
|
||||
@ -663,7 +679,7 @@ dependencies = [
|
||||
"objc-foundation",
|
||||
"objc_id",
|
||||
"smithay-clipboard",
|
||||
"wayland-client 0.23.6",
|
||||
"wayland-client",
|
||||
"x11-clipboard",
|
||||
]
|
||||
|
||||
@ -673,7 +689,17 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"core-foundation-sys 0.6.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
|
||||
dependencies = [
|
||||
"core-foundation-sys 0.7.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@ -683,6 +709,12 @@ version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics"
|
||||
version = "0.17.3"
|
||||
@ -690,11 +722,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-foundation 0.6.4",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics"
|
||||
version = "0.19.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation 0.7.0",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-video-sys"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"core-foundation-sys 0.7.0",
|
||||
"core-graphics 0.19.2",
|
||||
"libc",
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coreaudio-rs"
|
||||
version = "0.9.1"
|
||||
@ -721,7 +778,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b55d55d69f403f62a95bd3c04b431e0aedf5120c70f15d07a8edd234443dd59"
|
||||
dependencies = [
|
||||
"alsa-sys",
|
||||
"core-foundation-sys",
|
||||
"core-foundation-sys 0.6.2",
|
||||
"coreaudio-rs",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
@ -992,6 +1049,17 @@ dependencies = [
|
||||
"byteorder 1.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.18",
|
||||
"quote 1.0.7",
|
||||
"syn 1.0.33",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deunicode"
|
||||
version = "1.1.1"
|
||||
@ -1063,6 +1131,12 @@ version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04e93ca78226c51902d7aa8c12c988338aadd9e85ed9c6be8aaac39192ff3605"
|
||||
|
||||
[[package]]
|
||||
name = "dispatch"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
|
||||
|
||||
[[package]]
|
||||
name = "dlib"
|
||||
version = "0.4.2"
|
||||
@ -1505,17 +1579,6 @@ dependencies = [
|
||||
"gl_generator 0.14.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx_window_glutin"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "310ff66f08b5a55854b18fea2f48bdbb75c94458207ba574c9723be78e97a646"
|
||||
dependencies = [
|
||||
"gfx_core",
|
||||
"gfx_device_gl",
|
||||
"glutin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gilrs"
|
||||
version = "0.7.4"
|
||||
@ -1537,7 +1600,7 @@ version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43c758daf46af26d6872fe55507e3b2339779a160a06ad7a9b2a082f221209cd"
|
||||
dependencies = [
|
||||
"core-foundation",
|
||||
"core-foundation 0.6.4",
|
||||
"io-kit-sys",
|
||||
"libc",
|
||||
"libudev-sys",
|
||||
@ -1621,15 +1684,6 @@ dependencies = [
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gleam"
|
||||
version = "0.6.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cae10d7c99d0e77b4766e850a60898a17c1abaf01075531f1066f03dc7dc5fc5"
|
||||
dependencies = [
|
||||
"gl_generator 0.13.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib"
|
||||
version = "0.5.0"
|
||||
@ -1672,15 +1726,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "glutin"
|
||||
version = "0.21.2"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5371b35b309dace06be1b81b5f6adb1c9de578b7dbe1e74bf7e4ef762cf6febd"
|
||||
checksum = "9a9666c8fd9afd008f6559e2468c35e11aad1d110d525bb3b354e4138ec0e20f"
|
||||
dependencies = [
|
||||
"android_glue",
|
||||
"cgl",
|
||||
"cocoa 0.18.5",
|
||||
"core-foundation",
|
||||
"core-graphics",
|
||||
"cocoa 0.20.2",
|
||||
"core-foundation 0.7.0",
|
||||
"core-graphics 0.19.2",
|
||||
"glutin_egl_sys",
|
||||
"glutin_emscripten_sys",
|
||||
"glutin_gles2_sys",
|
||||
@ -1688,10 +1742,11 @@ dependencies = [
|
||||
"glutin_wgl_sys",
|
||||
"lazy_static",
|
||||
"libloading 0.5.2",
|
||||
"log",
|
||||
"objc",
|
||||
"osmesa-sys",
|
||||
"parking_lot 0.9.0",
|
||||
"wayland-client 0.21.13",
|
||||
"parking_lot 0.10.2",
|
||||
"wayland-client",
|
||||
"winapi 0.3.8",
|
||||
"winit",
|
||||
]
|
||||
@ -2048,7 +2103,7 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f21dcc74995dd4cd090b147e79789f8d65959cbfb5f0b118002db869ea3bd0a0"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"core-foundation-sys 0.6.2",
|
||||
"mach",
|
||||
]
|
||||
|
||||
@ -2076,6 +2131,12 @@ version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
||||
|
||||
[[package]]
|
||||
name = "jni-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.21"
|
||||
@ -2448,6 +2509,37 @@ dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95a356cafe20aee088789830bfea3a61336e84ded9e545e00d3869ce95dcb80c"
|
||||
dependencies = [
|
||||
"jni-sys",
|
||||
"ndk-sys",
|
||||
"num_enum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk-glue"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1730ee2e3de41c3321160a6da815f008c4006d71b095880ea50e17cf52332b8"
|
||||
dependencies = [
|
||||
"android_log-sys",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"ndk",
|
||||
"ndk-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b2820aca934aba5ed91c79acc72b6a44048ceacc5d36c035ed4e051f12d887d"
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.34"
|
||||
@ -2638,6 +2730,28 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca565a7df06f3d4b485494f25ba05da1435950f4dc263440eda7a6fa9b8e36e4"
|
||||
dependencies = [
|
||||
"derivative",
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2 1.0.18",
|
||||
"quote 1.0.7",
|
||||
"syn 1.0.33",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.7"
|
||||
@ -2682,6 +2796,17 @@ dependencies = [
|
||||
"byteorder 1.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "old_school_gfx_glutin_ext"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0557cea37cc48d238c938ded2873a6cc772704ee1eb01e832b43c2dd99624bc"
|
||||
dependencies = [
|
||||
"gfx_core",
|
||||
"gfx_device_gl",
|
||||
"glutin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.4.0"
|
||||
@ -2957,6 +3082,15 @@ version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
|
||||
dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "0.4.12"
|
||||
@ -3671,23 +3805,6 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
|
||||
|
||||
[[package]]
|
||||
name = "smithay-client-toolkit"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ccb8c57049b2a34d2cc2b203fa785020ba0129d31920ef0d317430adaf748fa"
|
||||
dependencies = [
|
||||
"andrew",
|
||||
"bitflags",
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
"memmap",
|
||||
"nix 0.14.1",
|
||||
"wayland-client 0.21.13",
|
||||
"wayland-commons 0.21.13",
|
||||
"wayland-protocols 0.21.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smithay-client-toolkit"
|
||||
version = "0.6.6"
|
||||
@ -3700,8 +3817,8 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"memmap",
|
||||
"nix 0.14.1",
|
||||
"wayland-client 0.23.6",
|
||||
"wayland-protocols 0.23.6",
|
||||
"wayland-client",
|
||||
"wayland-protocols",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3711,7 +3828,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "917e8ec7f535cd1a6cbf749c8866c24d67c548a80ac48c8e88a182eab5c07bd1"
|
||||
dependencies = [
|
||||
"nix 0.14.1",
|
||||
"smithay-client-toolkit 0.6.6",
|
||||
"smithay-client-toolkit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4506,13 +4623,12 @@ dependencies = [
|
||||
"crossbeam",
|
||||
"deunicode",
|
||||
"directories-next",
|
||||
"dispatch",
|
||||
"dispatch 0.1.4",
|
||||
"dot_vox",
|
||||
"euc",
|
||||
"failure",
|
||||
"gfx",
|
||||
"gfx_device_gl",
|
||||
"gfx_window_glutin",
|
||||
"gilrs",
|
||||
"git2",
|
||||
"glsl-include",
|
||||
@ -4522,6 +4638,7 @@ dependencies = [
|
||||
"image",
|
||||
"msgbox",
|
||||
"num 0.2.1",
|
||||
"old_school_gfx_glutin_ext",
|
||||
"rand 0.7.3",
|
||||
"rodio",
|
||||
"ron",
|
||||
@ -4706,21 +4823,6 @@ version = "0.2.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9ba19973a58daf4db6f352eda73dc0e289493cd29fb2632eb172085b6521acd"
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.21.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49963e5f9eeaf637bfcd1b9f0701c99fd5cd05225eb51035550d4272806f2713"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"downcast-rs",
|
||||
"libc",
|
||||
"nix 0.14.1",
|
||||
"wayland-commons 0.21.13",
|
||||
"wayland-scanner 0.21.13",
|
||||
"wayland-sys 0.21.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.23.6"
|
||||
@ -4728,22 +4830,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"calloop",
|
||||
"downcast-rs",
|
||||
"libc",
|
||||
"mio",
|
||||
"nix 0.14.1",
|
||||
"wayland-commons 0.23.6",
|
||||
"wayland-scanner 0.23.6",
|
||||
"wayland-sys 0.23.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-commons"
|
||||
version = "0.21.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c08896768b667e1df195d88a62a53a2d1351a1ed96188be79c196b35bb32ec"
|
||||
dependencies = [
|
||||
"nix 0.14.1",
|
||||
"wayland-sys 0.21.13",
|
||||
"wayland-commons",
|
||||
"wayland-scanner",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4753,20 +4847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb"
|
||||
dependencies = [
|
||||
"nix 0.14.1",
|
||||
"wayland-sys 0.23.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols"
|
||||
version = "0.21.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4afde2ea2a428eee6d7d2c8584fdbe8b82eee8b6c353e129a434cd6e07f42145"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wayland-client 0.21.13",
|
||||
"wayland-commons 0.21.13",
|
||||
"wayland-scanner 0.21.13",
|
||||
"wayland-sys 0.21.13",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4776,20 +4857,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wayland-client 0.23.6",
|
||||
"wayland-commons 0.23.6",
|
||||
"wayland-scanner 0.23.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-scanner"
|
||||
version = "0.21.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf3828c568714507315ee425a9529edc4a4aa9901409e373e9e0027e7622b79e"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
"xml-rs",
|
||||
"wayland-client",
|
||||
"wayland-commons",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4803,16 +4873,6 @@ dependencies = [
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-sys"
|
||||
version = "0.21.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520ab0fd578017a0ee2206623ba9ef4afe5e8f23ca7b42f6acfba2f4e66b1628"
|
||||
dependencies = [
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-sys"
|
||||
version = "0.23.6"
|
||||
@ -4897,26 +4957,31 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "winit"
|
||||
version = "0.19.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e96eb4bb472fa43e718e8fa4aef82f86cd9deac9483a1e1529230babdb394a8"
|
||||
version = "0.22.2"
|
||||
source = "git+https://github.com/Imberflur/winit.git?branch=macos-test#e98133adf2abbfc4368f6c069d0beb2b8b688b42"
|
||||
dependencies = [
|
||||
"android_glue",
|
||||
"backtrace",
|
||||
"bitflags",
|
||||
"cocoa 0.18.5",
|
||||
"core-foundation",
|
||||
"core-graphics",
|
||||
"cocoa 0.20.2",
|
||||
"core-foundation 0.7.0",
|
||||
"core-graphics 0.19.2",
|
||||
"core-video-sys",
|
||||
"dispatch 0.2.0",
|
||||
"instant",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"mio",
|
||||
"mio-extras",
|
||||
"ndk",
|
||||
"ndk-glue",
|
||||
"ndk-sys",
|
||||
"objc",
|
||||
"parking_lot 0.9.0",
|
||||
"parking_lot 0.10.2",
|
||||
"percent-encoding 2.1.0",
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"smithay-client-toolkit 0.4.6",
|
||||
"wayland-client 0.21.13",
|
||||
"smithay-client-toolkit",
|
||||
"wayland-client",
|
||||
"winapi 0.3.8",
|
||||
"x11-dl",
|
||||
]
|
||||
|
@ -72,3 +72,7 @@ debug = false
|
||||
[profile.releasedebuginfo]
|
||||
inherits = 'release'
|
||||
debug = 1
|
||||
|
||||
# cpal conflict fix isn't released yet
|
||||
[patch.crates-io]
|
||||
winit = { git = "https://github.com/Imberflur/winit.git", branch = "macos-test" }
|
||||
|
@ -249,15 +249,11 @@ impl State {
|
||||
|
||||
/// Removes every chunk of the terrain.
|
||||
pub fn clear_terrain(&mut self) {
|
||||
let keys = self
|
||||
.terrain_mut()
|
||||
.drain()
|
||||
.map(|(key, _)| key)
|
||||
.collect::<Vec<_>>();
|
||||
let removed_chunks = &mut self.ecs.write_resource::<TerrainChanges>().removed_chunks;
|
||||
|
||||
for key in keys {
|
||||
self.remove_chunk(key);
|
||||
}
|
||||
self.terrain_mut().drain().for_each(|(key, _)| {
|
||||
removed_chunks.insert(key);
|
||||
});
|
||||
}
|
||||
|
||||
/// Insert the provided chunk into this state's terrain.
|
||||
|
@ -25,11 +25,11 @@ anim = { package = "veloren-voxygen-anim", path = "src/anim", default-features =
|
||||
# Graphics
|
||||
gfx = "0.18.2"
|
||||
gfx_device_gl = { version = "0.16.2", optional = true }
|
||||
gfx_window_glutin = "0.31.0"
|
||||
glutin = "0.21.1"
|
||||
winit = { version = "0.19.4", features = ["serde"] }
|
||||
conrod_core = { git = "https://gitlab.com/veloren/conrod.git", branch = "pre-winit-20" }
|
||||
conrod_winit = { git = "https://gitlab.com/veloren/conrod.git", branch = "pre-winit-20" }
|
||||
old_school_gfx_glutin_ext = "0.24"
|
||||
glutin = "0.24.1"
|
||||
winit = { version = "0.22.2", features = ["serde"] }
|
||||
conrod_core = { git = "https://gitlab.com/veloren/conrod.git" }
|
||||
conrod_winit = { git = "https://gitlab.com/veloren/conrod.git" }
|
||||
euc = { git = "https://github.com/zesterer/euc.git" }
|
||||
|
||||
# ECS
|
||||
@ -87,7 +87,6 @@ winres = "0.1"
|
||||
criterion = "0.3"
|
||||
git2 = "0.13"
|
||||
world = { package = "veloren-world", path = "../world" }
|
||||
gfx_window_glutin = { version = "0.31.0", features = ["headless"] }
|
||||
|
||||
[[bench]]
|
||||
name = "meshing_benchmark"
|
||||
|
@ -1,9 +1,16 @@
|
||||
use common::comp;
|
||||
// TODO: Fix this example when we switch to actively maintained rendering
|
||||
// backend. Right now we would have to update `gfx_window_glutin` to work with
|
||||
// the latest version of glutin or we would need to add headless support to
|
||||
// `old_school_gfx_glutin_ext`.
|
||||
|
||||
fn main() {
|
||||
println!("Example temporarily disabled, see the TODO comment for details");
|
||||
}
|
||||
/*use common::comp;
|
||||
use gfx_window_glutin::init_headless;
|
||||
use vek::*;
|
||||
use veloren_voxygen::{render, scene::simple as scene};
|
||||
|
||||
#[allow(clippy::clone_on_copy)] // TODO: Pending review in #587
|
||||
fn main() {
|
||||
// Setup renderer
|
||||
let dim = (200u16, 300u16, 1, gfx::texture::AaMode::Single);
|
||||
@ -72,4 +79,4 @@ fn main() {
|
||||
// Get image
|
||||
let img = renderer.create_screenshot().unwrap();
|
||||
img.save("character.png").unwrap();
|
||||
}
|
||||
}*/
|
||||
|
Binary file not shown.
@ -465,17 +465,15 @@ impl Show {
|
||||
self.want_grab = true;
|
||||
|
||||
// Unpause the game if we are on singleplayer
|
||||
if let Some(singleplayer) = global_state.singleplayer.as_ref() {
|
||||
singleplayer.pause(false);
|
||||
};
|
||||
#[cfg(feature = "singleplayer")]
|
||||
global_state.unpause();
|
||||
} else {
|
||||
self.esc_menu = true;
|
||||
self.want_grab = false;
|
||||
|
||||
// Pause the game if we are on singleplayer
|
||||
if let Some(singleplayer) = global_state.singleplayer.as_ref() {
|
||||
singleplayer.pause(true);
|
||||
};
|
||||
#[cfg(feature = "singleplayer")]
|
||||
global_state.pause();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1721,9 +1719,8 @@ impl Hud {
|
||||
settings_window::Event::ChangeTab(tab) => self.show.open_setting_tab(tab),
|
||||
settings_window::Event::Close => {
|
||||
// Unpause the game if we are on singleplayer so that we can logout
|
||||
if let Some(singleplayer) = global_state.singleplayer.as_ref() {
|
||||
singleplayer.pause(false);
|
||||
};
|
||||
#[cfg(feature = "singleplayer")]
|
||||
global_state.unpause();
|
||||
|
||||
self.show.settings(false)
|
||||
},
|
||||
@ -1908,24 +1905,21 @@ impl Hud {
|
||||
self.force_ungrab = false;
|
||||
|
||||
// Unpause the game if we are on singleplayer
|
||||
if let Some(singleplayer) = global_state.singleplayer.as_ref() {
|
||||
singleplayer.pause(false);
|
||||
};
|
||||
#[cfg(feature = "singleplayer")]
|
||||
global_state.unpause();
|
||||
},
|
||||
Some(esc_menu::Event::Logout) => {
|
||||
// Unpause the game if we are on singleplayer so that we can logout
|
||||
if let Some(singleplayer) = global_state.singleplayer.as_ref() {
|
||||
singleplayer.pause(false);
|
||||
};
|
||||
#[cfg(feature = "singleplayer")]
|
||||
global_state.unpause();
|
||||
|
||||
events.push(Event::Logout);
|
||||
},
|
||||
Some(esc_menu::Event::Quit) => events.push(Event::Quit),
|
||||
Some(esc_menu::Event::CharacterSelection) => {
|
||||
// Unpause the game if we are on singleplayer so that we can logout
|
||||
if let Some(singleplayer) = global_state.singleplayer.as_ref() {
|
||||
singleplayer.pause(false);
|
||||
};
|
||||
#[cfg(feature = "singleplayer")]
|
||||
global_state.unpause();
|
||||
|
||||
events.push(Event::CharacterSelection)
|
||||
},
|
||||
|
@ -17,6 +17,7 @@ pub mod menu;
|
||||
pub mod mesh;
|
||||
pub mod profile;
|
||||
pub mod render;
|
||||
pub mod run;
|
||||
pub mod scene;
|
||||
pub mod session;
|
||||
pub mod settings;
|
||||
@ -27,10 +28,16 @@ pub mod window;
|
||||
// Reexports
|
||||
pub use crate::error::Error;
|
||||
|
||||
#[cfg(feature = "singleplayer")]
|
||||
use crate::singleplayer::Singleplayer;
|
||||
use crate::{
|
||||
audio::AudioFrontend, profile::Profile, settings::Settings, singleplayer::Singleplayer,
|
||||
window::Window,
|
||||
audio::AudioFrontend,
|
||||
profile::Profile,
|
||||
render::Renderer,
|
||||
settings::Settings,
|
||||
window::{Event, Window},
|
||||
};
|
||||
use common::{assets::watch, clock::Clock};
|
||||
|
||||
/// A type used to store state that is shared between all play states.
|
||||
pub struct GlobalState {
|
||||
@ -39,7 +46,11 @@ pub struct GlobalState {
|
||||
pub window: Window,
|
||||
pub audio: AudioFrontend,
|
||||
pub info_message: Option<String>,
|
||||
pub clock: Clock,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
pub singleplayer: Option<Singleplayer>,
|
||||
// TODO: redo this so that the watcher doesn't have to exist for reloading to occur
|
||||
pub localization_watcher: watch::ReloadIndicator,
|
||||
}
|
||||
|
||||
impl GlobalState {
|
||||
@ -51,8 +62,25 @@ impl GlobalState {
|
||||
}
|
||||
|
||||
pub fn maintain(&mut self, dt: f32) { self.audio.maintain(dt); }
|
||||
|
||||
#[cfg(feature = "singleplayer")]
|
||||
pub fn paused(&self) -> bool {
|
||||
self.singleplayer
|
||||
.as_ref()
|
||||
.map_or(false, Singleplayer::is_paused)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "singleplayer"))]
|
||||
pub fn paused(&self) -> bool { false }
|
||||
|
||||
#[cfg(feature = "singleplayer")]
|
||||
pub fn unpause(&self) { self.singleplayer.as_ref().map(|s| s.pause(false)); }
|
||||
|
||||
#[cfg(feature = "singleplayer")]
|
||||
pub fn pause(&self) { self.singleplayer.as_ref().map(|s| s.pause(true)); }
|
||||
}
|
||||
|
||||
// TODO: appears to be currently unused by playstates
|
||||
pub enum Direction {
|
||||
Forwards,
|
||||
Backwards,
|
||||
@ -61,6 +89,8 @@ pub enum Direction {
|
||||
/// States can either close (and revert to a previous state), push a new state
|
||||
/// on top of themselves, or switch to a totally different state.
|
||||
pub enum PlayStateResult {
|
||||
/// Keep running this play state.
|
||||
Continue,
|
||||
/// Pop all play states in reverse order and shut down the program.
|
||||
Shutdown,
|
||||
/// Close the current play state and pop it from the play state stack.
|
||||
@ -74,10 +104,15 @@ pub enum PlayStateResult {
|
||||
/// A trait representing a playable game state. This may be a menu, a game
|
||||
/// session, the title screen, etc.
|
||||
pub trait PlayState {
|
||||
/// Play the state until some change of state is required (i.e: a menu is
|
||||
/// opened or the game is closed).
|
||||
fn play(&mut self, direction: Direction, global_state: &mut GlobalState) -> PlayStateResult;
|
||||
/// Called when entering this play state from another
|
||||
fn enter(&mut self, global_state: &mut GlobalState, direction: Direction);
|
||||
|
||||
/// Tick the play state
|
||||
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult;
|
||||
|
||||
/// Get a descriptive name for this state type.
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
/// Draw the play state.
|
||||
fn render(&mut self, renderer: &mut Renderer, settings: &Settings);
|
||||
}
|
||||
|
@ -7,16 +7,19 @@ use veloren_voxygen::{
|
||||
audio::{self, AudioFrontend},
|
||||
i18n::{self, i18n_asset_key, VoxygenLocalization},
|
||||
logging,
|
||||
menu::main::MainMenuState,
|
||||
profile::Profile,
|
||||
run,
|
||||
settings::{AudioOutput, Settings},
|
||||
window::Window,
|
||||
Direction, GlobalState, PlayState, PlayStateResult,
|
||||
GlobalState,
|
||||
};
|
||||
|
||||
use common::assets::{load, load_expect};
|
||||
use std::{mem, panic};
|
||||
use tracing::{debug, error, warn};
|
||||
use common::{
|
||||
assets::{load_watched, watch},
|
||||
clock::Clock,
|
||||
};
|
||||
use std::panic;
|
||||
use tracing::{error, warn};
|
||||
|
||||
fn main() {
|
||||
#[cfg(feature = "tweak")]
|
||||
@ -26,57 +29,14 @@ fn main() {
|
||||
// Note: This won't log anything due to it being called before
|
||||
// `logging::init`. The issue is we need to read a setting to decide
|
||||
// whether we create a log file or not.
|
||||
let settings = Settings::load();
|
||||
|
||||
// Init logging and hold the guards.
|
||||
let _guards = logging::init(&settings);
|
||||
|
||||
// Save settings to add new fields or create the file if it is not already
|
||||
// there.
|
||||
let mut settings = Settings::load();
|
||||
// Save settings to add new fields or create the file if it is not already there
|
||||
if let Err(err) = settings.save_to_file() {
|
||||
panic!("Failed to save settings: {:?}", err);
|
||||
}
|
||||
|
||||
let mut audio = match settings.audio.output {
|
||||
AudioOutput::Off => None,
|
||||
AudioOutput::Automatic => audio::get_default_device(),
|
||||
AudioOutput::Device(ref dev) => Some(dev.clone()),
|
||||
}
|
||||
.map(|dev| AudioFrontend::new(dev, settings.audio.max_sfx_channels))
|
||||
.unwrap_or_else(AudioFrontend::no_audio);
|
||||
|
||||
audio.set_music_volume(settings.audio.music_volume);
|
||||
audio.set_sfx_volume(settings.audio.sfx_volume);
|
||||
|
||||
// Load the profile.
|
||||
let profile = Profile::load();
|
||||
|
||||
let mut global_state = GlobalState {
|
||||
audio,
|
||||
profile,
|
||||
window: Window::new(&settings).expect("Failed to create window!"),
|
||||
settings,
|
||||
info_message: None,
|
||||
singleplayer: None,
|
||||
};
|
||||
|
||||
// Try to load the localization and log missing entries
|
||||
let localized_strings = load::<VoxygenLocalization>(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
))
|
||||
.unwrap_or_else(|e| {
|
||||
let preferred_language = &global_state.settings.language.selected_language;
|
||||
warn!(
|
||||
?e,
|
||||
?preferred_language,
|
||||
"Impossible to load language: change to the default language (English) instead.",
|
||||
);
|
||||
global_state.settings.language.selected_language = i18n::REFERENCE_LANG.to_owned();
|
||||
load_expect::<VoxygenLocalization>(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
))
|
||||
});
|
||||
localized_strings.log_missing_entries();
|
||||
// Init logging and hold the guards.
|
||||
let _guards = logging::init(&settings);
|
||||
|
||||
// Set up panic handler to relay swish panic messages to the user
|
||||
let default_hook = panic::take_hook();
|
||||
@ -159,68 +119,56 @@ fn main() {
|
||||
#[cfg(feature = "hot-anim")]
|
||||
anim::init();
|
||||
|
||||
// Set up the initial play state.
|
||||
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(&mut global_state))];
|
||||
states.last().map(|current_state| {
|
||||
let current_state = current_state.name();
|
||||
debug!(?current_state, "Started game with state")
|
||||
});
|
||||
|
||||
// What's going on here?
|
||||
// ---------------------
|
||||
// The state system used by Voxygen allows for the easy development of
|
||||
// stack-based menus. For example, you may want a "title" state that can
|
||||
// push a "main menu" state on top of it, which can in turn push a
|
||||
// "settings" state or a "game session" state on top of it. The code below
|
||||
// manages the state transfer logic automatically so that we don't have to
|
||||
// re-engineer it for each menu we decide to add to the game.
|
||||
let mut direction = Direction::Forwards;
|
||||
while let Some(state_result) = states
|
||||
.last_mut()
|
||||
.map(|last| last.play(direction, &mut global_state))
|
||||
{
|
||||
// Implement state transfer logic.
|
||||
match state_result {
|
||||
PlayStateResult::Shutdown => {
|
||||
direction = Direction::Backwards;
|
||||
debug!("Shutting down all states...");
|
||||
while states.last().is_some() {
|
||||
states.pop().map(|old_state| {
|
||||
let old_state = old_state.name();
|
||||
debug!(?old_state, "Popped state");
|
||||
global_state.on_play_state_changed();
|
||||
});
|
||||
}
|
||||
},
|
||||
PlayStateResult::Pop => {
|
||||
direction = Direction::Backwards;
|
||||
states.pop().map(|old_state| {
|
||||
let old_state = old_state.name();
|
||||
debug!(?old_state, "Popped state");
|
||||
global_state.on_play_state_changed();
|
||||
});
|
||||
},
|
||||
PlayStateResult::Push(new_state) => {
|
||||
direction = Direction::Forwards;
|
||||
debug!("Pushed state '{}'.", new_state.name());
|
||||
states.push(new_state);
|
||||
global_state.on_play_state_changed();
|
||||
},
|
||||
PlayStateResult::Switch(mut new_state_box) => {
|
||||
direction = Direction::Forwards;
|
||||
states.last_mut().map(|old_state_box| {
|
||||
let old_state = old_state_box.name();
|
||||
let new_state = new_state_box.name();
|
||||
debug!(?old_state, ?new_state, "Switching to states",);
|
||||
mem::swap(old_state_box, &mut new_state_box);
|
||||
global_state.on_play_state_changed();
|
||||
});
|
||||
},
|
||||
}
|
||||
// Setup audio
|
||||
let mut audio = match settings.audio.output {
|
||||
AudioOutput::Off => None,
|
||||
AudioOutput::Automatic => audio::get_default_device(),
|
||||
AudioOutput::Device(ref dev) => Some(dev.clone()),
|
||||
}
|
||||
.map(|dev| AudioFrontend::new(dev, settings.audio.max_sfx_channels))
|
||||
.unwrap_or_else(AudioFrontend::no_audio);
|
||||
|
||||
// Save any unsaved changes to profile.
|
||||
global_state.profile.save_to_file_warn();
|
||||
// Save any unsaved changes to settings.
|
||||
global_state.settings.save_to_file_warn();
|
||||
audio.set_music_volume(settings.audio.music_volume);
|
||||
audio.set_sfx_volume(settings.audio.sfx_volume);
|
||||
|
||||
// Load the profile.
|
||||
let profile = Profile::load();
|
||||
|
||||
let mut localization_watcher = watch::ReloadIndicator::new();
|
||||
let localized_strings = load_watched::<VoxygenLocalization>(
|
||||
&i18n_asset_key(&settings.language.selected_language),
|
||||
&mut localization_watcher,
|
||||
)
|
||||
.unwrap_or_else(|error| {
|
||||
let selected_language = &settings.language.selected_language;
|
||||
warn!(
|
||||
?error,
|
||||
?selected_language,
|
||||
"Impossible to load language: change to the default language (English) instead.",
|
||||
);
|
||||
settings.language.selected_language = i18n::REFERENCE_LANG.to_owned();
|
||||
load_watched::<VoxygenLocalization>(
|
||||
&i18n_asset_key(&settings.language.selected_language),
|
||||
&mut localization_watcher,
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
localized_strings.log_missing_entries();
|
||||
|
||||
// Create window
|
||||
let (window, event_loop) = Window::new(&settings).expect("Failed to create window!");
|
||||
|
||||
let global_state = GlobalState {
|
||||
audio,
|
||||
profile,
|
||||
window,
|
||||
settings,
|
||||
clock: Clock::start(),
|
||||
info_message: None,
|
||||
#[cfg(feature = "singleplayer")]
|
||||
singleplayer: None,
|
||||
localization_watcher,
|
||||
};
|
||||
|
||||
run::run(global_state, event_loop);
|
||||
}
|
||||
|
@ -2,15 +2,17 @@ mod ui;
|
||||
|
||||
use crate::{
|
||||
i18n::{i18n_asset_key, VoxygenLocalization},
|
||||
render::Renderer,
|
||||
scene::simple::{self as scene, Scene},
|
||||
session::SessionState,
|
||||
settings::Settings,
|
||||
window::Event as WinEvent,
|
||||
Direction, GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::{assets, clock::Clock, comp, msg::ClientState, state::DeltaTime};
|
||||
use common::{assets, comp, msg::ClientState, state::DeltaTime};
|
||||
use specs::WorldExt;
|
||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use tracing::error;
|
||||
use ui::CharSelectionUi;
|
||||
|
||||
@ -32,20 +34,34 @@ impl CharSelectionState {
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_humanoid_body(&self) -> Option<comp::humanoid::Body> {
|
||||
self.char_selection_ui
|
||||
.get_character_list()
|
||||
.and_then(|data| {
|
||||
if let Some(character) = data.get(self.char_selection_ui.selected_character) {
|
||||
match character.body {
|
||||
comp::Body::Humanoid(body) => Some(body),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PlayState for CharSelectionState {
|
||||
fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult {
|
||||
// Set up an fps clock.
|
||||
let mut clock = Clock::start();
|
||||
|
||||
fn enter(&mut self, _: &mut GlobalState, _: Direction) {
|
||||
// Load the player's character list
|
||||
self.client.borrow_mut().load_character_list();
|
||||
}
|
||||
|
||||
let mut current_client_state = self.client.borrow().get_client_state();
|
||||
while let ClientState::Pending | ClientState::Registered = current_client_state {
|
||||
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<WinEvent>) -> PlayStateResult {
|
||||
let client_state = self.client.borrow().get_client_state();
|
||||
if let ClientState::Pending | ClientState::Registered = client_state {
|
||||
// Handle window events
|
||||
for event in global_state.window.fetch_events(&mut global_state.settings) {
|
||||
for event in events {
|
||||
if self.char_selection_ui.handle_event(event.clone()) {
|
||||
continue;
|
||||
}
|
||||
@ -60,8 +76,6 @@ impl PlayState for CharSelectionState {
|
||||
}
|
||||
}
|
||||
|
||||
global_state.window.renderer_mut().clear();
|
||||
|
||||
// Maintain the UI.
|
||||
let events = self
|
||||
.char_selection_ui
|
||||
@ -100,23 +114,7 @@ impl PlayState for CharSelectionState {
|
||||
}
|
||||
}
|
||||
|
||||
// Maintain global state.
|
||||
global_state.maintain(clock.get_last_delta().as_secs_f32());
|
||||
|
||||
let humanoid_body = self
|
||||
.char_selection_ui
|
||||
.get_character_list()
|
||||
.and_then(|data| {
|
||||
if let Some(character) = data.get(self.char_selection_ui.selected_character) {
|
||||
match character.body {
|
||||
comp::Body::Humanoid(body) => Some(body),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let humanoid_body = self.get_humanoid_body();
|
||||
let loadout = self.char_selection_ui.get_loadout();
|
||||
|
||||
// Maintain the scene.
|
||||
@ -141,17 +139,6 @@ impl PlayState for CharSelectionState {
|
||||
loadout.as_ref(),
|
||||
);
|
||||
}
|
||||
// Render the scene.
|
||||
self.scene.render(
|
||||
global_state.window.renderer_mut(),
|
||||
self.client.borrow().get_tick(),
|
||||
humanoid_body,
|
||||
loadout.as_ref(),
|
||||
);
|
||||
|
||||
// Draw the UI to the screen.
|
||||
self.char_selection_ui
|
||||
.render(global_state.window.renderer_mut(), self.scene.globals());
|
||||
|
||||
// Tick the client (currently only to keep the connection alive).
|
||||
let localized_strings = assets::load_expect::<VoxygenLocalization>(&i18n_asset_key(
|
||||
@ -160,7 +147,7 @@ impl PlayState for CharSelectionState {
|
||||
|
||||
match self.client.borrow_mut().tick(
|
||||
comp::ControllerInputs::default(),
|
||||
clock.get_last_delta(),
|
||||
global_state.clock.get_last_delta(),
|
||||
|_| {},
|
||||
) {
|
||||
Ok(events) => {
|
||||
@ -190,25 +177,33 @@ impl PlayState for CharSelectionState {
|
||||
},
|
||||
}
|
||||
|
||||
// TODO: make sure rendering is not relying on cleaned up stuff
|
||||
self.client.borrow_mut().cleanup();
|
||||
|
||||
// Finish the frame.
|
||||
global_state.window.renderer_mut().flush();
|
||||
global_state
|
||||
.window
|
||||
.swap_buffers()
|
||||
.expect("Failed to swap window buffers");
|
||||
|
||||
// Wait for the next tick.
|
||||
clock.tick(Duration::from_millis(
|
||||
1000 / (global_state.settings.graphics.max_fps as u64),
|
||||
));
|
||||
|
||||
current_client_state = self.client.borrow().get_client_state();
|
||||
PlayStateResult::Continue
|
||||
} else {
|
||||
error!("Client not in pending or registered state. Popping char selection play state");
|
||||
// TODO set global_state.info_message
|
||||
PlayStateResult::Pop
|
||||
}
|
||||
|
||||
PlayStateResult::Pop
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str { "Title" }
|
||||
|
||||
fn render(&mut self, renderer: &mut Renderer, _: &Settings) {
|
||||
let humanoid_body = self.get_humanoid_body();
|
||||
let loadout = self.char_selection_ui.get_loadout();
|
||||
|
||||
// Render the scene.
|
||||
self.scene.render(
|
||||
renderer,
|
||||
self.client.borrow().get_tick(),
|
||||
humanoid_body,
|
||||
loadout.as_ref(),
|
||||
);
|
||||
|
||||
// Draw the UI to the screen.
|
||||
self.char_selection_ui
|
||||
.render(renderer, self.scene.globals());
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,22 @@
|
||||
mod client_init;
|
||||
#[cfg(feature = "singleplayer")] mod ui;
|
||||
mod ui;
|
||||
|
||||
use super::char_selection::CharSelectionState;
|
||||
#[cfg(feature = "singleplayer")]
|
||||
use crate::singleplayer::Singleplayer;
|
||||
use crate::{
|
||||
singleplayer::Singleplayer, window::Event, Direction, GlobalState, PlayState, PlayStateResult,
|
||||
render::Renderer, settings::Settings, window::Event, Direction, GlobalState, PlayState,
|
||||
PlayStateResult,
|
||||
};
|
||||
use client_init::{ClientInit, Error as InitError, Msg as InitMsg};
|
||||
use common::{assets::load_expect, clock::Clock, comp};
|
||||
#[cfg(feature = "singleplayer")]
|
||||
use std::time::Duration;
|
||||
use common::{assets::load_expect, comp};
|
||||
use tracing::{error, warn};
|
||||
use ui::{Event as MainMenuEvent, MainMenuUi};
|
||||
|
||||
pub struct MainMenuState {
|
||||
main_menu_ui: MainMenuUi,
|
||||
// Used for client creation.
|
||||
client_init: Option<ClientInit>,
|
||||
}
|
||||
|
||||
impl MainMenuState {
|
||||
@ -21,6 +24,7 @@ impl MainMenuState {
|
||||
pub fn new(global_state: &mut GlobalState) -> Self {
|
||||
Self {
|
||||
main_menu_ui: MainMenuUi::new(global_state),
|
||||
client_init: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -28,237 +32,226 @@ impl MainMenuState {
|
||||
const DEFAULT_PORT: u16 = 14004;
|
||||
|
||||
impl PlayState for MainMenuState {
|
||||
#[allow(clippy::useless_format)] // TODO: Pending review in #587
|
||||
fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult {
|
||||
// Set up an fps clock.
|
||||
let mut clock = Clock::start();
|
||||
|
||||
// Used for client creation.
|
||||
let mut client_init: Option<ClientInit> = None;
|
||||
|
||||
fn enter(&mut self, global_state: &mut GlobalState, _: Direction) {
|
||||
// Kick off title music
|
||||
if global_state.settings.audio.output.is_enabled() && global_state.audio.music_enabled() {
|
||||
global_state.audio.play_title_music();
|
||||
}
|
||||
|
||||
// Reset singleplayer server if it was running already
|
||||
global_state.singleplayer = None;
|
||||
#[cfg(feature = "singleplayer")]
|
||||
{
|
||||
global_state.singleplayer = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult {
|
||||
let localized_strings = load_expect::<crate::i18n::VoxygenLocalization>(
|
||||
&crate::i18n::i18n_asset_key(&global_state.settings.language.selected_language),
|
||||
);
|
||||
|
||||
loop {
|
||||
// Handle window events.
|
||||
for event in global_state.window.fetch_events(&mut global_state.settings) {
|
||||
match event {
|
||||
Event::Close => return PlayStateResult::Shutdown,
|
||||
// Pass events to ui.
|
||||
Event::Ui(event) => {
|
||||
self.main_menu_ui.handle_event(event);
|
||||
},
|
||||
// Ignore all other events.
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
global_state.window.renderer_mut().clear();
|
||||
|
||||
// Poll client creation.
|
||||
match client_init.as_ref().and_then(|init| init.poll()) {
|
||||
Some(InitMsg::Done(Ok(mut client))) => {
|
||||
self.main_menu_ui.connected();
|
||||
// Register voxygen components / resources
|
||||
crate::ecs::init(client.state_mut().ecs_mut());
|
||||
return PlayStateResult::Push(Box::new(CharSelectionState::new(
|
||||
global_state,
|
||||
std::rc::Rc::new(std::cell::RefCell::new(client)),
|
||||
)));
|
||||
// Handle window events.
|
||||
for event in events {
|
||||
match event {
|
||||
Event::Close => return PlayStateResult::Shutdown,
|
||||
// Pass events to ui.
|
||||
Event::Ui(event) => {
|
||||
self.main_menu_ui.handle_event(event);
|
||||
},
|
||||
Some(InitMsg::Done(Err(e))) => {
|
||||
client_init = None;
|
||||
global_state.info_message = Some({
|
||||
let err = match e {
|
||||
InitError::BadAddress(_) | InitError::NoAddress => {
|
||||
localized_strings.get("main.login.server_not_found").into()
|
||||
// Ignore all other events.
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
// Poll client creation.
|
||||
match self.client_init.as_ref().and_then(|init| init.poll()) {
|
||||
Some(InitMsg::Done(Ok(mut client))) => {
|
||||
self.client_init = None;
|
||||
self.main_menu_ui.connected();
|
||||
// Register voxygen components / resources
|
||||
crate::ecs::init(client.state_mut().ecs_mut());
|
||||
return PlayStateResult::Push(Box::new(CharSelectionState::new(
|
||||
global_state,
|
||||
std::rc::Rc::new(std::cell::RefCell::new(client)),
|
||||
)));
|
||||
},
|
||||
Some(InitMsg::Done(Err(err))) => {
|
||||
self.client_init = None;
|
||||
global_state.info_message = Some({
|
||||
let err = match err {
|
||||
InitError::BadAddress(_) | InitError::NoAddress => {
|
||||
localized_strings.get("main.login.server_not_found").into()
|
||||
},
|
||||
InitError::ClientError(err) => match err {
|
||||
client::Error::AuthErr(e) => format!(
|
||||
"{}: {}",
|
||||
localized_strings.get("main.login.authentication_error"),
|
||||
e
|
||||
),
|
||||
client::Error::TooManyPlayers => {
|
||||
localized_strings.get("main.login.server_full").into()
|
||||
},
|
||||
InitError::ClientError(err) => match err {
|
||||
client::Error::AuthErr(e) => format!(
|
||||
client::Error::AuthServerNotTrusted => localized_strings
|
||||
.get("main.login.untrusted_auth_server")
|
||||
.into(),
|
||||
client::Error::ServerWentMad => localized_strings
|
||||
.get("main.login.outdated_client_or_server")
|
||||
.into(),
|
||||
client::Error::ServerTimeout => {
|
||||
localized_strings.get("main.login.timeout").into()
|
||||
},
|
||||
client::Error::ServerShutdown => {
|
||||
localized_strings.get("main.login.server_shut_down").into()
|
||||
},
|
||||
client::Error::AlreadyLoggedIn => {
|
||||
localized_strings.get("main.login.already_logged_in").into()
|
||||
},
|
||||
client::Error::NotOnWhitelist => {
|
||||
localized_strings.get("main.login.not_on_whitelist").into()
|
||||
},
|
||||
client::Error::InvalidCharacter => {
|
||||
localized_strings.get("main.login.invalid_character").into()
|
||||
},
|
||||
client::Error::NetworkErr(e) => format!(
|
||||
"{}: {:?}",
|
||||
localized_strings.get("main.login.network_error"),
|
||||
e
|
||||
),
|
||||
client::Error::ParticipantErr(e) => format!(
|
||||
"{}: {:?}",
|
||||
localized_strings.get("main.login.network_error"),
|
||||
e
|
||||
),
|
||||
client::Error::StreamErr(e) => format!(
|
||||
"{}: {:?}",
|
||||
localized_strings.get("main.login.network_error"),
|
||||
e
|
||||
),
|
||||
client::Error::Other(e) => {
|
||||
format!("{}: {}", localized_strings.get("common.error"), e)
|
||||
},
|
||||
client::Error::AuthClientError(e) => match e {
|
||||
client::AuthClientError::JsonError(e) => format!(
|
||||
"{}: {}",
|
||||
localized_strings.get("main.login.authentication_error"),
|
||||
localized_strings.get("common.fatal_error"),
|
||||
e
|
||||
),
|
||||
client::Error::TooManyPlayers => {
|
||||
localized_strings.get("main.login.server_full").into()
|
||||
},
|
||||
client::Error::AuthServerNotTrusted => localized_strings
|
||||
.get("main.login.untrusted_auth_server")
|
||||
.into(),
|
||||
client::Error::ServerWentMad => localized_strings
|
||||
.get("main.login.outdated_client_or_server")
|
||||
.into(),
|
||||
client::Error::ServerTimeout => {
|
||||
localized_strings.get("main.login.timeout").into()
|
||||
},
|
||||
client::Error::ServerShutdown => {
|
||||
localized_strings.get("main.login.server_shut_down").into()
|
||||
},
|
||||
client::Error::AlreadyLoggedIn => {
|
||||
localized_strings.get("main.login.already_logged_in").into()
|
||||
},
|
||||
client::Error::NotOnWhitelist => {
|
||||
localized_strings.get("main.login.not_on_whitelist").into()
|
||||
},
|
||||
client::Error::NetworkErr(e) => format!(
|
||||
"{}: {:?}",
|
||||
localized_strings.get("main.login.network_error"),
|
||||
e
|
||||
),
|
||||
client::Error::ParticipantErr(e) => format!(
|
||||
"{}: {:?}",
|
||||
localized_strings.get("main.login.network_error"),
|
||||
e
|
||||
),
|
||||
client::Error::StreamErr(e) => format!(
|
||||
"{}: {:?}",
|
||||
localized_strings.get("main.login.network_error"),
|
||||
e
|
||||
),
|
||||
client::Error::Other(e) => {
|
||||
format!("{}: {}", localized_strings.get("common.error"), e)
|
||||
},
|
||||
client::Error::AuthClientError(e) => match e {
|
||||
client::AuthClientError::JsonError(e) => format!(
|
||||
"{}: {}",
|
||||
localized_strings.get("common.fatal_error"),
|
||||
e
|
||||
),
|
||||
client::AuthClientError::RequestError() => format!(
|
||||
"{}",
|
||||
localized_strings.get("main.login.failed_sending_request")
|
||||
),
|
||||
client::AuthClientError::ServerError(_, e) => format!("{}", e),
|
||||
},
|
||||
client::Error::InvalidCharacter => {
|
||||
localized_strings.get("main.login.invalid_character").into()
|
||||
},
|
||||
// TODO: remove parentheses
|
||||
client::AuthClientError::RequestError() => localized_strings
|
||||
.get("main.login.failed_sending_request")
|
||||
.to_owned(),
|
||||
client::AuthClientError::ServerError(_, e) => e,
|
||||
},
|
||||
InitError::ClientCrashed => {
|
||||
localized_strings.get("main.login.client_crashed").into()
|
||||
},
|
||||
};
|
||||
// Log error for possible additional use later or incase that the error
|
||||
// displayed is cut of.
|
||||
error!("{}", err);
|
||||
err
|
||||
});
|
||||
},
|
||||
Some(InitMsg::IsAuthTrusted(auth_server)) => {
|
||||
if global_state
|
||||
.settings
|
||||
.networking
|
||||
.trusted_auth_servers
|
||||
.contains(&auth_server)
|
||||
{
|
||||
// Can't fail since we just polled it, it must be Some
|
||||
client_init.as_ref().unwrap().auth_trust(auth_server, true);
|
||||
} else {
|
||||
// Show warning that auth server is not trusted and prompt for approval
|
||||
self.main_menu_ui.auth_trust_prompt(auth_server);
|
||||
}
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
},
|
||||
InitError::ClientCrashed => {
|
||||
localized_strings.get("main.login.client_crashed").into()
|
||||
},
|
||||
};
|
||||
// Log error for possible additional use later or incase that the error
|
||||
// displayed is cut of.
|
||||
error!("{}", err);
|
||||
err
|
||||
});
|
||||
},
|
||||
Some(InitMsg::IsAuthTrusted(auth_server)) => {
|
||||
if global_state
|
||||
.settings
|
||||
.networking
|
||||
.trusted_auth_servers
|
||||
.contains(&auth_server)
|
||||
{
|
||||
// Can't fail since we just polled it, it must be Some
|
||||
self.client_init
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.auth_trust(auth_server, true);
|
||||
} else {
|
||||
// Show warning that auth server is not trusted and prompt for approval
|
||||
self.main_menu_ui.auth_trust_prompt(auth_server);
|
||||
}
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
|
||||
// Maintain global_state
|
||||
global_state.maintain(clock.get_last_delta().as_secs_f32());
|
||||
|
||||
// Maintain the UI.
|
||||
for event in self
|
||||
.main_menu_ui
|
||||
.maintain(global_state, clock.get_last_delta())
|
||||
{
|
||||
match event {
|
||||
MainMenuEvent::LoginAttempt {
|
||||
// Maintain the UI.
|
||||
for event in self
|
||||
.main_menu_ui
|
||||
.maintain(global_state, global_state.clock.get_last_delta())
|
||||
{
|
||||
match event {
|
||||
MainMenuEvent::LoginAttempt {
|
||||
username,
|
||||
password,
|
||||
server_address,
|
||||
} => {
|
||||
attempt_login(
|
||||
global_state,
|
||||
username,
|
||||
password,
|
||||
server_address,
|
||||
} => {
|
||||
attempt_login(
|
||||
global_state,
|
||||
username,
|
||||
password,
|
||||
server_address,
|
||||
DEFAULT_PORT,
|
||||
&mut client_init,
|
||||
);
|
||||
},
|
||||
MainMenuEvent::CancelLoginAttempt => {
|
||||
// client_init contains Some(ClientInit), which spawns a thread which
|
||||
// contains a TcpStream::connect() call This call is
|
||||
// blocking TODO fix when the network rework happens
|
||||
global_state.singleplayer = None;
|
||||
client_init = None;
|
||||
self.main_menu_ui.cancel_connection();
|
||||
},
|
||||
DEFAULT_PORT,
|
||||
&mut self.client_init,
|
||||
);
|
||||
},
|
||||
MainMenuEvent::CancelLoginAttempt => {
|
||||
// client_init contains Some(ClientInit), which spawns a thread which contains a
|
||||
// TcpStream::connect() call This call is blocking
|
||||
// TODO fix when the network rework happens
|
||||
#[cfg(feature = "singleplayer")]
|
||||
MainMenuEvent::StartSingleplayer => {
|
||||
let (singleplayer, server_settings) = Singleplayer::new(None); // TODO: Make client and server use the same thread pool
|
||||
{
|
||||
global_state.singleplayer = None;
|
||||
}
|
||||
self.client_init = None;
|
||||
self.main_menu_ui.cancel_connection();
|
||||
},
|
||||
#[cfg(feature = "singleplayer")]
|
||||
MainMenuEvent::StartSingleplayer => {
|
||||
let (singleplayer, server_settings) = Singleplayer::new(None); // TODO: Make client and server use the same thread pool
|
||||
|
||||
global_state.singleplayer = Some(singleplayer);
|
||||
global_state.singleplayer = Some(singleplayer);
|
||||
|
||||
attempt_login(
|
||||
global_state,
|
||||
"singleplayer".to_owned(),
|
||||
"".to_owned(),
|
||||
server_settings.gameserver_address.ip().to_string(),
|
||||
server_settings.gameserver_address.port(),
|
||||
&mut client_init,
|
||||
);
|
||||
},
|
||||
MainMenuEvent::Settings => {}, // TODO
|
||||
MainMenuEvent::Quit => return PlayStateResult::Shutdown,
|
||||
/*MainMenuEvent::DisclaimerClosed => {
|
||||
global_state.settings.show_disclaimer = false
|
||||
},*/
|
||||
MainMenuEvent::AuthServerTrust(auth_server, trust) => {
|
||||
if trust {
|
||||
global_state
|
||||
.settings
|
||||
.networking
|
||||
.trusted_auth_servers
|
||||
.insert(auth_server.clone());
|
||||
global_state.settings.save_to_file_warn();
|
||||
}
|
||||
client_init
|
||||
.as_ref()
|
||||
.map(|init| init.auth_trust(auth_server, trust));
|
||||
},
|
||||
}
|
||||
attempt_login(
|
||||
global_state,
|
||||
"singleplayer".to_owned(),
|
||||
"".to_owned(),
|
||||
server_settings.gameserver_address.ip().to_string(),
|
||||
server_settings.gameserver_address.port(),
|
||||
&mut self.client_init,
|
||||
);
|
||||
},
|
||||
MainMenuEvent::Settings => {}, // TODO
|
||||
MainMenuEvent::Quit => return PlayStateResult::Shutdown,
|
||||
/*MainMenuEvent::DisclaimerClosed => {
|
||||
global_state.settings.show_disclaimer = false
|
||||
},*/
|
||||
MainMenuEvent::AuthServerTrust(auth_server, trust) => {
|
||||
if trust {
|
||||
global_state
|
||||
.settings
|
||||
.networking
|
||||
.trusted_auth_servers
|
||||
.insert(auth_server.clone());
|
||||
global_state.settings.save_to_file_warn();
|
||||
}
|
||||
self.client_init
|
||||
.as_ref()
|
||||
.map(|init| init.auth_trust(auth_server, trust));
|
||||
},
|
||||
}
|
||||
|
||||
if let Some(info) = global_state.info_message.take() {
|
||||
self.main_menu_ui.show_info(info);
|
||||
}
|
||||
|
||||
// Draw the UI to the screen.
|
||||
self.main_menu_ui.render(global_state.window.renderer_mut());
|
||||
|
||||
// Finish the frame.
|
||||
global_state.window.renderer_mut().flush();
|
||||
global_state
|
||||
.window
|
||||
.swap_buffers()
|
||||
.expect("Failed to swap window buffers!");
|
||||
|
||||
// Wait for the next tick
|
||||
clock.tick(Duration::from_millis(
|
||||
1000 / (global_state.settings.graphics.max_fps as u64),
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(info) = global_state.info_message.take() {
|
||||
self.main_menu_ui.show_info(info);
|
||||
}
|
||||
|
||||
PlayStateResult::Continue
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str { "Title" }
|
||||
|
||||
fn render(&mut self, renderer: &mut Renderer, _: &Settings) {
|
||||
// Draw the UI to the screen.
|
||||
self.main_menu_ui.render(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
fn attempt_login(
|
||||
|
145
voxygen/src/run.rs
Normal file
145
voxygen/src/run.rs
Normal file
@ -0,0 +1,145 @@
|
||||
use crate::{
|
||||
menu::main::MainMenuState,
|
||||
ui,
|
||||
window::{Event, EventLoop},
|
||||
Direction, GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use std::{mem, time::Duration};
|
||||
use tracing::debug;
|
||||
|
||||
pub fn run(mut global_state: GlobalState, event_loop: EventLoop) {
|
||||
// Set up the initial play state.
|
||||
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(&mut global_state))];
|
||||
states.last_mut().map(|current_state| {
|
||||
current_state.enter(&mut global_state, Direction::Forwards);
|
||||
let current_state = current_state.name();
|
||||
debug!(?current_state, "Started game with state");
|
||||
});
|
||||
|
||||
// Used to ignore every other `MainEventsCleared`
|
||||
// This is a workaround for a bug on macos in which mouse motion events are only
|
||||
// reported every other cycle of the event loop
|
||||
// See: https://github.com/rust-windowing/winit/issues/1418
|
||||
let mut polled_twice = false;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
// Continously run loop since we handle sleeping
|
||||
*control_flow = winit::event_loop::ControlFlow::Poll;
|
||||
|
||||
// Get events for the ui.
|
||||
if let Some(event) = ui::Event::try_from(&event, global_state.window.window()) {
|
||||
global_state.window.send_event(Event::Ui(event));
|
||||
}
|
||||
|
||||
match event {
|
||||
winit::event::Event::MainEventsCleared => {
|
||||
if polled_twice {
|
||||
handle_main_events_cleared(&mut states, control_flow, &mut global_state);
|
||||
}
|
||||
polled_twice = !polled_twice;
|
||||
},
|
||||
winit::event::Event::WindowEvent { event, .. } => global_state
|
||||
.window
|
||||
.handle_window_event(event, &mut global_state.settings),
|
||||
winit::event::Event::DeviceEvent { event, .. } => {
|
||||
global_state.window.handle_device_event(event)
|
||||
},
|
||||
winit::event::Event::LoopDestroyed => {
|
||||
// Save any unsaved changes to settings and profile
|
||||
global_state.settings.save_to_file_warn();
|
||||
global_state.profile.save_to_file_warn();
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_main_events_cleared(
|
||||
states: &mut Vec<Box<dyn PlayState>>,
|
||||
control_flow: &mut winit::event_loop::ControlFlow,
|
||||
global_state: &mut GlobalState,
|
||||
) {
|
||||
// Run tick here
|
||||
|
||||
// What's going on here?
|
||||
// ---------------------
|
||||
// The state system used by Voxygen allows for the easy development of
|
||||
// stack-based menus. For example, you may want a "title" state
|
||||
// that can push a "main menu" state on top of it, which can in
|
||||
// turn push a "settings" state or a "game session" state on top of it.
|
||||
// The code below manages the state transfer logic automatically so that we
|
||||
// don't have to re-engineer it for each menu we decide to add
|
||||
// to the game.
|
||||
let mut exit = true;
|
||||
while let Some(state_result) = states.last_mut().map(|last| {
|
||||
let events = global_state.window.fetch_events();
|
||||
last.tick(global_state, events)
|
||||
}) {
|
||||
// Implement state transfer logic.
|
||||
match state_result {
|
||||
PlayStateResult::Continue => {
|
||||
// Wait for the next tick.
|
||||
global_state.clock.tick(Duration::from_millis(
|
||||
1000 / global_state.settings.graphics.max_fps as u64,
|
||||
));
|
||||
|
||||
// Maintain global state.
|
||||
global_state.maintain(global_state.clock.get_last_delta().as_secs_f32());
|
||||
|
||||
exit = false;
|
||||
break;
|
||||
},
|
||||
PlayStateResult::Shutdown => {
|
||||
debug!("Shutting down all states...");
|
||||
while states.last().is_some() {
|
||||
states.pop().map(|old_state| {
|
||||
debug!("Popped state '{}'.", old_state.name());
|
||||
global_state.on_play_state_changed();
|
||||
});
|
||||
}
|
||||
},
|
||||
PlayStateResult::Pop => {
|
||||
states.pop().map(|old_state| {
|
||||
debug!("Popped state '{}'.", old_state.name());
|
||||
global_state.on_play_state_changed();
|
||||
});
|
||||
states.last_mut().map(|new_state| {
|
||||
new_state.enter(global_state, Direction::Backwards);
|
||||
});
|
||||
},
|
||||
PlayStateResult::Push(mut new_state) => {
|
||||
new_state.enter(global_state, Direction::Forwards);
|
||||
debug!("Pushed state '{}'.", new_state.name());
|
||||
states.push(new_state);
|
||||
global_state.on_play_state_changed();
|
||||
},
|
||||
PlayStateResult::Switch(mut new_state) => {
|
||||
new_state.enter(global_state, Direction::Forwards);
|
||||
states.last_mut().map(|old_state| {
|
||||
debug!(
|
||||
"Switching to state '{}' from state '{}'.",
|
||||
new_state.name(),
|
||||
old_state.name()
|
||||
);
|
||||
mem::swap(old_state, &mut new_state);
|
||||
global_state.on_play_state_changed();
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if exit {
|
||||
*control_flow = winit::event_loop::ControlFlow::Exit;
|
||||
}
|
||||
|
||||
if let Some(last) = states.last_mut() {
|
||||
global_state.window.renderer_mut().clear();
|
||||
last.render(global_state.window.renderer_mut(), &global_state.settings);
|
||||
// Finish the frame.
|
||||
global_state.window.renderer_mut().flush();
|
||||
global_state
|
||||
.window
|
||||
.swap_buffers()
|
||||
.expect("Failed to swap window buffers!");
|
||||
}
|
||||
}
|
@ -5,15 +5,15 @@ use crate::{
|
||||
i18n::{i18n_asset_key, VoxygenLocalization},
|
||||
key_state::KeyState,
|
||||
menu::char_selection::CharSelectionState,
|
||||
render::Renderer,
|
||||
scene::{camera, Scene, SceneData},
|
||||
settings::{AudioOutput, ControlSettings},
|
||||
settings::{AudioOutput, ControlSettings, Settings},
|
||||
window::{AnalogGameInput, Event, GameInput},
|
||||
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::{
|
||||
assets::{load_expect, load_watched, watch},
|
||||
clock::Clock,
|
||||
assets::{load_expect, load_watched},
|
||||
comp,
|
||||
comp::{
|
||||
ChatMsg, ChatType, InventoryUpdateEvent, Pos, Vel, MAX_MOUNT_RANGE_SQR,
|
||||
@ -46,6 +46,12 @@ pub struct SessionState {
|
||||
inputs: comp::ControllerInputs,
|
||||
selected_block: Block,
|
||||
voxygen_i18n: std::sync::Arc<VoxygenLocalization>,
|
||||
walk_forward_dir: Vec2<f32>,
|
||||
walk_right_dir: Vec2<f32>,
|
||||
freefly_vel: Vec3<f32>,
|
||||
free_look: bool,
|
||||
auto_walk: bool,
|
||||
is_aiming: bool,
|
||||
}
|
||||
|
||||
/// Represents an active game session (i.e., the one being played).
|
||||
@ -59,14 +65,12 @@ impl SessionState {
|
||||
.camera_mut()
|
||||
.set_fov_deg(global_state.settings.graphics.fov);
|
||||
let hud = Hud::new(global_state, &client.borrow());
|
||||
{
|
||||
let mut client = client.borrow_mut();
|
||||
let my_entity = client.entity();
|
||||
client.state_mut().ecs_mut().insert(MyEntity(my_entity));
|
||||
}
|
||||
let voxygen_i18n = load_expect::<VoxygenLocalization>(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
));
|
||||
|
||||
let walk_forward_dir = scene.camera().forward_xy();
|
||||
let walk_right_dir = scene.camera().right_xy();
|
||||
Self {
|
||||
scene,
|
||||
client,
|
||||
@ -75,8 +79,20 @@ impl SessionState {
|
||||
hud,
|
||||
selected_block: Block::new(BlockKind::Normal, Rgb::broadcast(255)),
|
||||
voxygen_i18n,
|
||||
walk_forward_dir,
|
||||
walk_right_dir,
|
||||
freefly_vel: Vec3::zero(),
|
||||
free_look: false,
|
||||
auto_walk: false,
|
||||
is_aiming: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn stop_auto_walk(&mut self) {
|
||||
self.auto_walk = false;
|
||||
self.hud.auto_walk(false);
|
||||
self.key_state.auto_walk = false;
|
||||
}
|
||||
}
|
||||
|
||||
impl SessionState {
|
||||
@ -86,9 +102,6 @@ impl SessionState {
|
||||
|
||||
let mut client = self.client.borrow_mut();
|
||||
for event in client.tick(self.inputs.clone(), dt, crate::ecs::sys::add_local_systems)? {
|
||||
self.voxygen_i18n = load_expect::<VoxygenLocalization>(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
));
|
||||
match event {
|
||||
client::Event::Chat(m) => {
|
||||
self.hud.new_message(m);
|
||||
@ -153,12 +166,10 @@ impl SessionState {
|
||||
}
|
||||
|
||||
impl PlayState for SessionState {
|
||||
fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult {
|
||||
fn enter(&mut self, global_state: &mut GlobalState, _: Direction) {
|
||||
// Trap the cursor.
|
||||
global_state.window.grab_cursor(true);
|
||||
|
||||
// Set up an fps clock.
|
||||
let mut clock = Clock::start();
|
||||
self.client.borrow_mut().clear_terrain();
|
||||
|
||||
// Send startup commands to the server
|
||||
@ -167,30 +178,28 @@ impl PlayState for SessionState {
|
||||
self.client.borrow_mut().send_chat(cmd.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keep a watcher on the language
|
||||
let mut localization_watcher = watch::ReloadIndicator::new();
|
||||
let mut localized_strings = load_watched::<VoxygenLocalization>(
|
||||
&i18n_asset_key(&global_state.settings.language.selected_language),
|
||||
&mut localization_watcher,
|
||||
)
|
||||
.unwrap();
|
||||
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult {
|
||||
self.voxygen_i18n = load_expect::<VoxygenLocalization>(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
));
|
||||
|
||||
let mut walk_forward_dir = self.scene.camera().forward_xy();
|
||||
let mut walk_right_dir = self.scene.camera().right_xy();
|
||||
let mut freefly_vel = Vec3::zero();
|
||||
let mut free_look = false;
|
||||
let mut auto_walk = false;
|
||||
// TODO: can this be a method on the session or are there borrowcheck issues?
|
||||
|
||||
fn stop_auto_walk(auto_walk: &mut bool, key_state: &mut KeyState, hud: &mut Hud) {
|
||||
*auto_walk = false;
|
||||
hud.auto_walk(false);
|
||||
key_state.auto_walk = false;
|
||||
}
|
||||
|
||||
// Game loop
|
||||
let mut current_client_state = self.client.borrow().get_client_state();
|
||||
while let ClientState::Pending | ClientState::Character = current_client_state {
|
||||
let client_state = self.client.borrow().get_client_state();
|
||||
if let ClientState::Pending | ClientState::Character = client_state {
|
||||
// Update MyEntity
|
||||
// Note: Alternatively, the client could emit an event when the entity changes
|
||||
// which may or may not be more elegant
|
||||
{
|
||||
let my_entity = self.client.borrow().entity();
|
||||
self.client
|
||||
.borrow_mut()
|
||||
.state_mut()
|
||||
.ecs_mut()
|
||||
.insert(MyEntity(my_entity));
|
||||
}
|
||||
// Compute camera data
|
||||
self.scene
|
||||
.camera_mut()
|
||||
@ -229,6 +238,7 @@ impl PlayState for SessionState {
|
||||
},
|
||||
)
|
||||
};
|
||||
self.is_aiming = is_aiming;
|
||||
|
||||
let cam_dir: Vec3<f32> = Vec3::from(view_mat.inverted() * -Vec4::unit_z());
|
||||
|
||||
@ -278,7 +288,7 @@ impl PlayState for SessionState {
|
||||
}));
|
||||
|
||||
// Handle window events.
|
||||
for event in global_state.window.fetch_events(&mut global_state.settings) {
|
||||
for event in events {
|
||||
// Pass all events to the ui first.
|
||||
if self.hud.handle_event(event.clone(), global_state) {
|
||||
continue;
|
||||
@ -331,7 +341,7 @@ impl PlayState for SessionState {
|
||||
Event::InputUpdate(GameInput::Respawn, state)
|
||||
if state != self.key_state.respawn =>
|
||||
{
|
||||
stop_auto_walk(&mut auto_walk, &mut self.key_state, &mut self.hud);
|
||||
self.stop_auto_walk();
|
||||
self.key_state.respawn = state;
|
||||
if state {
|
||||
self.client.borrow_mut().respawn();
|
||||
@ -348,7 +358,7 @@ impl PlayState for SessionState {
|
||||
{
|
||||
self.key_state.toggle_sit = state;
|
||||
if state {
|
||||
stop_auto_walk(&mut auto_walk, &mut self.key_state, &mut self.hud);
|
||||
self.stop_auto_walk();
|
||||
self.client.borrow_mut().toggle_sit();
|
||||
}
|
||||
}
|
||||
@ -357,31 +367,31 @@ impl PlayState for SessionState {
|
||||
{
|
||||
self.key_state.toggle_dance = state;
|
||||
if state {
|
||||
stop_auto_walk(&mut auto_walk, &mut self.key_state, &mut self.hud);
|
||||
self.stop_auto_walk();
|
||||
self.client.borrow_mut().toggle_dance();
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::MoveForward, state) => {
|
||||
if state && global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||
stop_auto_walk(&mut auto_walk, &mut self.key_state, &mut self.hud);
|
||||
self.stop_auto_walk();
|
||||
}
|
||||
self.key_state.up = state
|
||||
},
|
||||
Event::InputUpdate(GameInput::MoveBack, state) => {
|
||||
if state && global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||
stop_auto_walk(&mut auto_walk, &mut self.key_state, &mut self.hud);
|
||||
self.stop_auto_walk();
|
||||
}
|
||||
self.key_state.down = state
|
||||
},
|
||||
Event::InputUpdate(GameInput::MoveLeft, state) => {
|
||||
if state && global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||
stop_auto_walk(&mut auto_walk, &mut self.key_state, &mut self.hud);
|
||||
self.stop_auto_walk();
|
||||
}
|
||||
self.key_state.left = state
|
||||
},
|
||||
Event::InputUpdate(GameInput::MoveRight, state) => {
|
||||
if state && global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||
stop_auto_walk(&mut auto_walk, &mut self.key_state, &mut self.hud);
|
||||
self.stop_auto_walk();
|
||||
}
|
||||
self.key_state.right = state
|
||||
},
|
||||
@ -509,12 +519,12 @@ impl PlayState for SessionState {
|
||||
Event::InputUpdate(GameInput::FreeLook, state) => {
|
||||
match (global_state.settings.gameplay.free_look_behavior, state) {
|
||||
(PressBehavior::Toggle, true) => {
|
||||
free_look = !free_look;
|
||||
self.hud.free_look(free_look);
|
||||
self.free_look = !self.free_look;
|
||||
self.hud.free_look(self.free_look);
|
||||
},
|
||||
(PressBehavior::Hold, state) => {
|
||||
free_look = state;
|
||||
self.hud.free_look(free_look);
|
||||
self.free_look = state;
|
||||
self.hud.free_look(self.free_look);
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
@ -522,14 +532,14 @@ impl PlayState for SessionState {
|
||||
Event::InputUpdate(GameInput::AutoWalk, state) => {
|
||||
match (global_state.settings.gameplay.auto_walk_behavior, state) {
|
||||
(PressBehavior::Toggle, true) => {
|
||||
auto_walk = !auto_walk;
|
||||
self.key_state.auto_walk = auto_walk;
|
||||
self.hud.auto_walk(auto_walk);
|
||||
self.auto_walk = !self.auto_walk;
|
||||
self.key_state.auto_walk = self.auto_walk;
|
||||
self.hud.auto_walk(self.auto_walk);
|
||||
},
|
||||
(PressBehavior::Hold, state) => {
|
||||
auto_walk = state;
|
||||
self.key_state.auto_walk = auto_walk;
|
||||
self.hud.auto_walk(auto_walk);
|
||||
self.auto_walk = state;
|
||||
self.key_state.auto_walk = self.auto_walk;
|
||||
self.hud.auto_walk(self.auto_walk);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
@ -567,9 +577,9 @@ impl PlayState for SessionState {
|
||||
}
|
||||
}
|
||||
|
||||
if !free_look {
|
||||
walk_forward_dir = self.scene.camera().forward_xy();
|
||||
walk_right_dir = self.scene.camera().right_xy();
|
||||
if !self.free_look {
|
||||
self.walk_forward_dir = self.scene.camera().forward_xy();
|
||||
self.walk_right_dir = self.scene.camera().right_xy();
|
||||
self.inputs.look_dir = Dir::from_unnormalized(cam_dir + aim_dir_offset).unwrap();
|
||||
}
|
||||
|
||||
@ -581,8 +591,9 @@ impl PlayState for SessionState {
|
||||
camera::CameraMode::FirstPerson | camera::CameraMode::ThirdPerson => {
|
||||
// Move the player character based on their walking direction.
|
||||
// This could be different from the camera direction if free look is enabled.
|
||||
self.inputs.move_dir = walk_right_dir * axis_right + walk_forward_dir * axis_up;
|
||||
freefly_vel = Vec3::zero();
|
||||
self.inputs.move_dir =
|
||||
self.walk_right_dir * axis_right + self.walk_forward_dir * axis_up;
|
||||
self.freefly_vel = Vec3::zero();
|
||||
},
|
||||
|
||||
camera::CameraMode::Freefly => {
|
||||
@ -596,27 +607,27 @@ impl PlayState for SessionState {
|
||||
let right = self.scene.camera().right();
|
||||
let dir = right * axis_right + forward * axis_up;
|
||||
|
||||
let dt = clock.get_last_delta().as_secs_f32();
|
||||
if freefly_vel.magnitude_squared() > 0.01 {
|
||||
let new_vel =
|
||||
freefly_vel - freefly_vel.normalized() * (FREEFLY_DAMPING * dt);
|
||||
if freefly_vel.dot(new_vel) > 0.0 {
|
||||
freefly_vel = new_vel;
|
||||
let dt = global_state.clock.get_last_delta().as_secs_f32();
|
||||
if self.freefly_vel.magnitude_squared() > 0.01 {
|
||||
let new_vel = self.freefly_vel
|
||||
- self.freefly_vel.normalized() * (FREEFLY_DAMPING * dt);
|
||||
if self.freefly_vel.dot(new_vel) > 0.0 {
|
||||
self.freefly_vel = new_vel;
|
||||
} else {
|
||||
freefly_vel = Vec3::zero();
|
||||
self.freefly_vel = Vec3::zero();
|
||||
}
|
||||
}
|
||||
if dir.magnitude_squared() > 0.01 {
|
||||
freefly_vel += dir * (FREEFLY_ACCEL * dt);
|
||||
if freefly_vel.magnitude() > FREEFLY_MAX_SPEED {
|
||||
freefly_vel = freefly_vel.normalized() * FREEFLY_MAX_SPEED;
|
||||
self.freefly_vel += dir * (FREEFLY_ACCEL * dt);
|
||||
if self.freefly_vel.magnitude() > FREEFLY_MAX_SPEED {
|
||||
self.freefly_vel = self.freefly_vel.normalized() * FREEFLY_MAX_SPEED;
|
||||
}
|
||||
}
|
||||
|
||||
let pos = self.scene.camera().get_focus_pos();
|
||||
self.scene
|
||||
.camera_mut()
|
||||
.set_focus_pos(pos + freefly_vel * dt);
|
||||
.set_focus_pos(pos + self.freefly_vel * dt);
|
||||
|
||||
// Do not apply any movement to the player character
|
||||
self.inputs.move_dir = Vec2::zero();
|
||||
@ -626,16 +637,14 @@ impl PlayState for SessionState {
|
||||
self.inputs.climb = self.key_state.climb();
|
||||
|
||||
// Runs if either in a multiplayer server or the singleplayer server is unpaused
|
||||
if global_state.singleplayer.is_none()
|
||||
|| !global_state.singleplayer.as_ref().unwrap().is_paused()
|
||||
{
|
||||
if !global_state.paused() {
|
||||
// Perform an in-game tick.
|
||||
match self.tick(clock.get_avg_delta(), global_state) {
|
||||
match self.tick(global_state.clock.get_avg_delta(), global_state) {
|
||||
Ok(TickAction::Continue) => {}, // Do nothing
|
||||
Ok(TickAction::Disconnect) => return PlayStateResult::Pop, // Go to main menu
|
||||
Err(err) => {
|
||||
global_state.info_message =
|
||||
Some(localized_strings.get("common.connection_lost").to_owned());
|
||||
Some(self.voxygen_i18n.get("common.connection_lost").to_owned());
|
||||
error!("[session] Failed to tick the scene: {:?}", err);
|
||||
|
||||
return PlayStateResult::Pop;
|
||||
@ -643,19 +652,17 @@ impl PlayState for SessionState {
|
||||
}
|
||||
}
|
||||
|
||||
// Maintain global state.
|
||||
global_state.maintain(clock.get_last_delta().as_secs_f32());
|
||||
|
||||
// Recompute dependents just in case some input modified the camera
|
||||
self.scene
|
||||
.camera_mut()
|
||||
.compute_dependents(&*self.client.borrow().state().terrain());
|
||||
|
||||
// Extract HUD events ensuring the client borrow gets dropped.
|
||||
let mut hud_events = self.hud.maintain(
|
||||
&self.client.borrow(),
|
||||
global_state,
|
||||
DebugInfo {
|
||||
tps: clock.get_tps(),
|
||||
tps: global_state.clock.get_tps(),
|
||||
ping_ms: self.client.borrow().get_ping_ms_rolling_avg(),
|
||||
coordinates: self
|
||||
.client
|
||||
@ -687,7 +694,7 @@ impl PlayState for SessionState {
|
||||
num_figures_visible: self.scene.figure_mgr().figure_count_visible() as u32,
|
||||
},
|
||||
&self.scene.camera(),
|
||||
clock.get_last_delta(),
|
||||
global_state.clock.get_last_delta(),
|
||||
HudInfo {
|
||||
is_aiming,
|
||||
is_first_person: matches!(
|
||||
@ -698,8 +705,8 @@ impl PlayState for SessionState {
|
||||
);
|
||||
|
||||
// Look for changes in the localization files
|
||||
if localization_watcher.reloaded() {
|
||||
hud_events.push(HudEvent::ChangeLanguage(localized_strings.metadata.clone()));
|
||||
if global_state.localization_watcher.reloaded() {
|
||||
hud_events.push(HudEvent::ChangeLanguage(self.voxygen_i18n.metadata.clone()));
|
||||
}
|
||||
|
||||
// Maintain the UI.
|
||||
@ -916,13 +923,13 @@ impl PlayState for SessionState {
|
||||
HudEvent::ChangeLanguage(new_language) => {
|
||||
global_state.settings.language.selected_language =
|
||||
new_language.language_identifier;
|
||||
localized_strings = load_watched::<VoxygenLocalization>(
|
||||
self.voxygen_i18n = load_watched::<VoxygenLocalization>(
|
||||
&i18n_asset_key(&global_state.settings.language.selected_language),
|
||||
&mut localization_watcher,
|
||||
&mut global_state.localization_watcher,
|
||||
)
|
||||
.unwrap();
|
||||
localized_strings.log_missing_entries();
|
||||
self.hud.update_language(localized_strings.clone());
|
||||
self.voxygen_i18n.log_missing_entries();
|
||||
self.hud.update_language(self.voxygen_i18n.clone());
|
||||
},
|
||||
HudEvent::ToggleFullscreen => {
|
||||
global_state
|
||||
@ -978,59 +985,62 @@ impl PlayState for SessionState {
|
||||
};
|
||||
|
||||
// Runs if either in a multiplayer server or the singleplayer server is unpaused
|
||||
if global_state.singleplayer.is_none()
|
||||
|| !global_state.singleplayer.as_ref().unwrap().is_paused()
|
||||
{
|
||||
if !global_state.paused() {
|
||||
self.scene.maintain(
|
||||
global_state.window.renderer_mut(),
|
||||
&mut global_state.audio,
|
||||
&scene_data,
|
||||
);
|
||||
}
|
||||
|
||||
let renderer = global_state.window.renderer_mut();
|
||||
// Clear the screen
|
||||
renderer.clear();
|
||||
// Render the screen using the global renderer
|
||||
self.scene.render(
|
||||
renderer,
|
||||
client.state(),
|
||||
client.entity(),
|
||||
client.get_tick(),
|
||||
&scene_data,
|
||||
);
|
||||
// Draw the UI to the screen
|
||||
self.hud.render(renderer, self.scene.globals());
|
||||
// Finish the frame
|
||||
renderer.flush();
|
||||
}
|
||||
|
||||
// Display the frame on the window.
|
||||
global_state
|
||||
.window
|
||||
.swap_buffers()
|
||||
.expect("Failed to swap window buffers!");
|
||||
|
||||
// Wait for the next tick.
|
||||
clock.tick(Duration::from_millis(
|
||||
1000 / global_state.settings.graphics.max_fps as u64,
|
||||
));
|
||||
|
||||
// Clean things up after the tick.
|
||||
self.cleanup();
|
||||
|
||||
current_client_state = self.client.borrow().get_client_state();
|
||||
}
|
||||
|
||||
if let ClientState::Registered = current_client_state {
|
||||
return PlayStateResult::Switch(Box::new(CharSelectionState::new(
|
||||
PlayStateResult::Continue
|
||||
} else if let ClientState::Registered = client_state {
|
||||
PlayStateResult::Switch(Box::new(CharSelectionState::new(
|
||||
global_state,
|
||||
self.client.clone(),
|
||||
)));
|
||||
)))
|
||||
} else {
|
||||
error!("Client not in the expected state, exiting session play state");
|
||||
PlayStateResult::Pop
|
||||
}
|
||||
|
||||
PlayStateResult::Pop
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str { "Session" }
|
||||
|
||||
/// Render the session to the screen.
|
||||
///
|
||||
/// This method should be called once per frame.
|
||||
fn render(&mut self, renderer: &mut Renderer, settings: &Settings) {
|
||||
// Render the screen using the global renderer
|
||||
{
|
||||
let client = self.client.borrow();
|
||||
|
||||
let scene_data = SceneData {
|
||||
state: client.state(),
|
||||
player_entity: client.entity(),
|
||||
loaded_distance: client.loaded_distance(),
|
||||
view_distance: client.view_distance().unwrap_or(1),
|
||||
tick: client.get_tick(),
|
||||
thread_pool: client.thread_pool(),
|
||||
gamma: settings.graphics.gamma,
|
||||
mouse_smoothing: settings.gameplay.smooth_pan_enable,
|
||||
sprite_render_distance: settings.graphics.sprite_render_distance as f32,
|
||||
figure_lod_render_distance: settings.graphics.figure_lod_render_distance as f32,
|
||||
is_aiming: self.is_aiming,
|
||||
};
|
||||
self.scene.render(
|
||||
renderer,
|
||||
client.state(),
|
||||
client.entity(),
|
||||
client.get_tick(),
|
||||
&scene_data,
|
||||
);
|
||||
}
|
||||
// Draw the UI to the screen
|
||||
self.hud.render(renderer, self.scene.globals());
|
||||
}
|
||||
}
|
||||
|
@ -6,11 +6,11 @@ use crate::{
|
||||
window::{GameInput, KeyMouse},
|
||||
};
|
||||
use directories_next::{ProjectDirs, UserDirs};
|
||||
use glutin::{MouseButton, VirtualKeyCode};
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::{fs, io::prelude::*, path::PathBuf};
|
||||
use tracing::warn;
|
||||
use winit::event::{MouseButton, VirtualKeyCode};
|
||||
|
||||
// ControlSetting-like struct used by Serde, to handle not serializing/building
|
||||
// post-deserializing the inverse_keybindings hashmap
|
||||
|
@ -1,26 +1,30 @@
|
||||
use conrod_core::{event::Input, input::Button};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Event(pub Input);
|
||||
impl Event {
|
||||
pub fn try_from(
|
||||
event: glutin::Event,
|
||||
window: &glutin::ContextWrapper<glutin::PossiblyCurrent, winit::Window>,
|
||||
event: &winit::event::Event<()>,
|
||||
window: &glutin::ContextWrapper<glutin::PossiblyCurrent, winit::window::Window>,
|
||||
) -> Option<Self> {
|
||||
use conrod_winit::*;
|
||||
// A wrapper around the winit window that allows us to implement the trait
|
||||
// necessary for enabling the winit <-> conrod conversion functions.
|
||||
struct WindowRef<'a>(&'a winit::Window);
|
||||
struct WindowRef<'a>(&'a winit::window::Window);
|
||||
|
||||
// Implement the `WinitWindow` trait for `WindowRef` to allow for generating
|
||||
// compatible conversion functions.
|
||||
impl<'a> conrod_winit::WinitWindow for WindowRef<'a> {
|
||||
fn get_inner_size(&self) -> Option<(u32, u32)> {
|
||||
winit::Window::get_inner_size(&self.0).map(Into::into)
|
||||
Some(
|
||||
winit::window::Window::inner_size(&self.0)
|
||||
.to_logical::<u32>(self.hidpi_factor())
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
fn hidpi_factor(&self) -> f32 { winit::Window::get_hidpi_factor(&self.0) as _ }
|
||||
fn hidpi_factor(&self) -> f64 { winit::window::Window::scale_factor(&self.0) }
|
||||
}
|
||||
convert_event!(event, &WindowRef(window.window())).map(Self)
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ pub enum ScaleMode {
|
||||
pub struct Scale {
|
||||
mode: ScaleMode,
|
||||
// Current dpi factor
|
||||
dpi_factor: f64,
|
||||
scale_factor: f64,
|
||||
// Current logical window size
|
||||
window_dims: Vec2<f64>,
|
||||
}
|
||||
@ -27,10 +27,10 @@ pub struct Scale {
|
||||
impl Scale {
|
||||
pub fn new(window: &Window, mode: ScaleMode) -> Self {
|
||||
let window_dims = window.logical_size();
|
||||
let dpi_factor = window.renderer().get_resolution().x as f64 / window_dims.x;
|
||||
let scale_factor = window.renderer().get_resolution().x as f64 / window_dims.x;
|
||||
Scale {
|
||||
mode,
|
||||
dpi_factor,
|
||||
scale_factor,
|
||||
window_dims,
|
||||
}
|
||||
}
|
||||
@ -54,7 +54,7 @@ impl Scale {
|
||||
// coordinates.
|
||||
pub fn scale_factor_logical(&self) -> f64 {
|
||||
match self.mode {
|
||||
ScaleMode::Absolute(scale) => scale / self.dpi_factor,
|
||||
ScaleMode::Absolute(scale) => scale / self.scale_factor,
|
||||
ScaleMode::DpiFactor => 1.0,
|
||||
ScaleMode::RelativeToWindow(dims) => {
|
||||
(self.window_dims.x / dims.x).min(self.window_dims.y / dims.y)
|
||||
@ -64,11 +64,11 @@ impl Scale {
|
||||
|
||||
// Calculate factor to transform between physical coordinates and our scaled
|
||||
// coordinates.
|
||||
pub fn scale_factor_physical(&self) -> f64 { self.scale_factor_logical() * self.dpi_factor }
|
||||
pub fn scale_factor_physical(&self) -> f64 { self.scale_factor_logical() * self.scale_factor }
|
||||
|
||||
// Updates internal window size (and/or dpi_factor).
|
||||
// Updates internal window size (and/or scale_factor).
|
||||
pub fn window_resized(&mut self, new_dims: Vec2<f64>, renderer: &Renderer) {
|
||||
self.dpi_factor = renderer.get_resolution().x as f64 / new_dims.x;
|
||||
self.scale_factor = renderer.get_resolution().x as f64 / new_dims.x;
|
||||
self.window_dims = new_dims;
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,10 @@ use crate::{
|
||||
settings::{ControlSettings, Settings},
|
||||
ui, Error,
|
||||
};
|
||||
use crossbeam::channel;
|
||||
use gilrs::{EventType, Gilrs};
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use crossbeam::channel;
|
||||
use old_school_gfx_glutin_ext::{ContextBuilderExt, WindowInitExt, WindowUpdateExt};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use tracing::{error, info, warn};
|
||||
@ -241,7 +241,7 @@ pub enum AnalogGameInput {
|
||||
}
|
||||
|
||||
/// Represents an incoming event from the window.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Event {
|
||||
/// The window has been requested to close.
|
||||
Close,
|
||||
@ -280,19 +280,20 @@ pub enum Event {
|
||||
ScreenshotMessage(String),
|
||||
}
|
||||
|
||||
pub type MouseButton = winit::MouseButton;
|
||||
pub type PressState = winit::ElementState;
|
||||
pub type MouseButton = winit::event::MouseButton;
|
||||
pub type PressState = winit::event::ElementState;
|
||||
pub type EventLoop = winit::event_loop::EventLoop<()>;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub enum KeyMouse {
|
||||
Key(glutin::VirtualKeyCode),
|
||||
Mouse(glutin::MouseButton),
|
||||
Key(winit::event::VirtualKeyCode),
|
||||
Mouse(winit::event::MouseButton),
|
||||
}
|
||||
|
||||
impl fmt::Display for KeyMouse {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use self::KeyMouse::*;
|
||||
use glutin::{MouseButton, VirtualKeyCode::*};
|
||||
use winit::event::{MouseButton, VirtualKeyCode::*};
|
||||
write!(f, "{}", match self {
|
||||
Key(Key1) => "1",
|
||||
Key(Key2) => "2",
|
||||
@ -466,23 +467,23 @@ impl fmt::Display for KeyMouse {
|
||||
}
|
||||
|
||||
pub struct Window {
|
||||
events_loop: glutin::EventsLoop,
|
||||
renderer: Renderer,
|
||||
window: glutin::ContextWrapper<glutin::PossiblyCurrent, winit::Window>,
|
||||
window: glutin::ContextWrapper<glutin::PossiblyCurrent, winit::window::Window>,
|
||||
cursor_grabbed: bool,
|
||||
pub pan_sensitivity: u32,
|
||||
pub zoom_sensitivity: u32,
|
||||
pub zoom_inversion: bool,
|
||||
pub mouse_y_inversion: bool,
|
||||
fullscreen: bool,
|
||||
modifiers: winit::event::ModifiersState,
|
||||
needs_refresh_resize: bool,
|
||||
keypress_map: HashMap<GameInput, glutin::ElementState>,
|
||||
keypress_map: HashMap<GameInput, winit::event::ElementState>,
|
||||
pub remapping_keybindings: Option<GameInput>,
|
||||
supplement_events: Vec<Event>,
|
||||
events: Vec<Event>,
|
||||
focused: bool,
|
||||
gilrs: Option<Gilrs>,
|
||||
controller_settings: ControllerSettings,
|
||||
cursor_position: winit::dpi::LogicalPosition,
|
||||
cursor_position: winit::dpi::PhysicalPosition<f64>,
|
||||
mouse_emulation_vec: Vec2<f32>,
|
||||
// Currently used to send and receive screenshot result messages
|
||||
message_sender: channel::Sender<String>,
|
||||
@ -490,30 +491,32 @@ pub struct Window {
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub fn new(settings: &Settings) -> Result<Window, Error> {
|
||||
let events_loop = glutin::EventsLoop::new();
|
||||
pub fn new(settings: &Settings) -> Result<(Window, EventLoop), Error> {
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
let size = settings.graphics.window_size;
|
||||
|
||||
let win_builder = glutin::WindowBuilder::new()
|
||||
let win_builder = winit::window::WindowBuilder::new()
|
||||
.with_title("Veloren")
|
||||
.with_dimensions(glutin::dpi::LogicalSize::new(
|
||||
size[0] as f64,
|
||||
size[1] as f64,
|
||||
))
|
||||
.with_inner_size(winit::dpi::LogicalSize::new(size[0] as f64, size[1] as f64))
|
||||
.with_maximized(true);
|
||||
|
||||
let ctx_builder = glutin::ContextBuilder::new()
|
||||
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
|
||||
.with_vsync(false);
|
||||
// Avoid cpal / winit OleInitialize conflict
|
||||
// See: https://github.com/rust-windowing/winit/pull/1524
|
||||
#[cfg(target_os = "windows")]
|
||||
let win_builder = winit::platform::windows::WindowBuilderExtWindows::with_drag_and_drop(
|
||||
win_builder,
|
||||
false,
|
||||
);
|
||||
|
||||
let (window, device, factory, win_color_view, win_depth_view) =
|
||||
gfx_window_glutin::init::<WinColorFmt, WinDepthFmt>(
|
||||
win_builder,
|
||||
ctx_builder,
|
||||
&events_loop,
|
||||
)
|
||||
.map_err(|err| Error::BackendError(Box::new(err)))?;
|
||||
glutin::ContextBuilder::new()
|
||||
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
|
||||
.with_vsync(false)
|
||||
.with_gfx_color_depth::<WinColorFmt, WinDepthFmt>()
|
||||
.build_windowed(win_builder, &event_loop)
|
||||
.map_err(|err| Error::BackendError(Box::new(err)))?
|
||||
.init_gfx::<WinColorFmt, WinDepthFmt>();
|
||||
|
||||
let vendor = device.get_info().platform_name.vendor;
|
||||
let renderer = device.get_info().platform_name.renderer;
|
||||
@ -559,7 +562,6 @@ impl Window {
|
||||
) = channel::unbounded::<String>();
|
||||
|
||||
let mut this = Self {
|
||||
events_loop,
|
||||
renderer: Renderer::new(
|
||||
device,
|
||||
factory,
|
||||
@ -576,14 +578,15 @@ impl Window {
|
||||
zoom_inversion: settings.gameplay.zoom_inversion,
|
||||
mouse_y_inversion: settings.gameplay.mouse_y_inversion,
|
||||
fullscreen: false,
|
||||
modifiers: Default::default(),
|
||||
needs_refresh_resize: false,
|
||||
keypress_map,
|
||||
remapping_keybindings: None,
|
||||
supplement_events: vec![],
|
||||
events: Vec::new(),
|
||||
focused: true,
|
||||
gilrs,
|
||||
controller_settings,
|
||||
cursor_position: winit::dpi::LogicalPosition::new(0.0, 0.0),
|
||||
cursor_position: winit::dpi::PhysicalPosition::new(0.0, 0.0),
|
||||
mouse_emulation_vec: Vec2::zero(),
|
||||
// Currently used to send and receive screenshot result messages
|
||||
message_sender,
|
||||
@ -592,195 +595,30 @@ impl Window {
|
||||
|
||||
this.fullscreen(settings.graphics.fullscreen);
|
||||
|
||||
Ok(this)
|
||||
Ok((this, event_loop))
|
||||
}
|
||||
|
||||
pub fn window(
|
||||
&self,
|
||||
) -> &glutin::ContextWrapper<glutin::PossiblyCurrent, winit::window::Window> {
|
||||
&self.window
|
||||
}
|
||||
|
||||
pub fn renderer(&self) -> &Renderer { &self.renderer }
|
||||
|
||||
pub fn renderer_mut(&mut self) -> &mut Renderer { &mut self.renderer }
|
||||
|
||||
#[allow(clippy::match_bool)] // TODO: Pending review in #587
|
||||
pub fn fetch_events(&mut self, settings: &mut Settings) -> Vec<Event> {
|
||||
let mut events = vec![];
|
||||
events.append(&mut self.supplement_events);
|
||||
pub fn fetch_events(&mut self) -> Vec<Event> {
|
||||
// Refresh ui size (used when changing playstates)
|
||||
if self.needs_refresh_resize {
|
||||
events.push(Event::Ui(ui::Event::new_resize(self.logical_size())));
|
||||
self.events
|
||||
.push(Event::Ui(ui::Event::new_resize(self.logical_size())));
|
||||
self.needs_refresh_resize = false;
|
||||
}
|
||||
|
||||
// Receive any messages sent through the message channel
|
||||
self.message_receiver
|
||||
.try_iter()
|
||||
.for_each(|message| events.push(Event::ScreenshotMessage(message)));
|
||||
|
||||
// Copy data that is needed by the events closure to avoid lifetime errors.
|
||||
// TODO: Remove this if/when the compiler permits it.
|
||||
let cursor_grabbed = self.cursor_grabbed;
|
||||
let renderer = &mut self.renderer;
|
||||
let window = &mut self.window;
|
||||
let remapping_keybindings = &mut self.remapping_keybindings;
|
||||
let focused = &mut self.focused;
|
||||
let controls = &mut settings.controls;
|
||||
let keypress_map = &mut self.keypress_map;
|
||||
let pan_sensitivity = self.pan_sensitivity;
|
||||
let zoom_sensitivity = self.zoom_sensitivity;
|
||||
let zoom_inversion = match self.zoom_inversion {
|
||||
true => -1.0,
|
||||
false => 1.0,
|
||||
};
|
||||
let mouse_y_inversion = match self.mouse_y_inversion {
|
||||
true => -1.0,
|
||||
false => 1.0,
|
||||
};
|
||||
let mut toggle_fullscreen = false;
|
||||
let mut take_screenshot = false;
|
||||
let mut cursor_position = None;
|
||||
|
||||
self.events_loop.poll_events(|event| {
|
||||
// Get events for ui.
|
||||
if let Some(event) = ui::Event::try_from(event.clone(), window) {
|
||||
events.push(Event::Ui(event));
|
||||
}
|
||||
|
||||
match event {
|
||||
glutin::Event::WindowEvent { event, .. } => match event {
|
||||
glutin::WindowEvent::CloseRequested => events.push(Event::Close),
|
||||
glutin::WindowEvent::Resized(glutin::dpi::LogicalSize { width, height }) => {
|
||||
let (mut color_view, mut depth_view) = renderer.win_views_mut();
|
||||
gfx_window_glutin::update_views(window, &mut color_view, &mut depth_view);
|
||||
renderer.on_resize().unwrap();
|
||||
events.push(Event::Resize(Vec2::new(width as u32, height as u32)));
|
||||
},
|
||||
glutin::WindowEvent::Moved(glutin::dpi::LogicalPosition { x, y }) => {
|
||||
events.push(Event::Moved(Vec2::new(x as u32, y as u32)))
|
||||
},
|
||||
glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)),
|
||||
glutin::WindowEvent::MouseInput { button, state, .. } => {
|
||||
if let (true, Some(game_inputs)) = (
|
||||
cursor_grabbed,
|
||||
Window::map_input(
|
||||
KeyMouse::Mouse(button),
|
||||
controls,
|
||||
remapping_keybindings,
|
||||
),
|
||||
) {
|
||||
for game_input in game_inputs {
|
||||
events.push(Event::InputUpdate(
|
||||
*game_input,
|
||||
state == glutin::ElementState::Pressed,
|
||||
));
|
||||
}
|
||||
}
|
||||
events.push(Event::MouseButton(button, state));
|
||||
},
|
||||
glutin::WindowEvent::KeyboardInput { input, .. } => {
|
||||
if let Some(key) = input.virtual_keycode {
|
||||
if let Some(game_inputs) = Window::map_input(
|
||||
KeyMouse::Key(key),
|
||||
controls,
|
||||
remapping_keybindings,
|
||||
) {
|
||||
for game_input in game_inputs {
|
||||
match game_input {
|
||||
GameInput::Fullscreen => {
|
||||
if input.state == glutin::ElementState::Pressed
|
||||
&& !Self::is_pressed(
|
||||
keypress_map,
|
||||
GameInput::Fullscreen,
|
||||
)
|
||||
{
|
||||
toggle_fullscreen = !toggle_fullscreen;
|
||||
}
|
||||
Self::set_pressed(
|
||||
keypress_map,
|
||||
GameInput::Fullscreen,
|
||||
input.state,
|
||||
);
|
||||
},
|
||||
GameInput::Screenshot => {
|
||||
take_screenshot = input.state
|
||||
== glutin::ElementState::Pressed
|
||||
&& !Self::is_pressed(
|
||||
keypress_map,
|
||||
GameInput::Screenshot,
|
||||
);
|
||||
Self::set_pressed(
|
||||
keypress_map,
|
||||
GameInput::Screenshot,
|
||||
input.state,
|
||||
);
|
||||
},
|
||||
_ => events.push(Event::InputUpdate(
|
||||
*game_input,
|
||||
input.state == glutin::ElementState::Pressed,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
glutin::WindowEvent::Focused(state) => {
|
||||
*focused = state;
|
||||
events.push(Event::Focused(state));
|
||||
},
|
||||
glutin::WindowEvent::CursorMoved { position, .. } => {
|
||||
cursor_position = Some(position);
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
glutin::Event::DeviceEvent { event, .. } => match event {
|
||||
glutin::DeviceEvent::MouseMotion {
|
||||
delta: (dx, dy), ..
|
||||
} if *focused => {
|
||||
let delta = Vec2::new(
|
||||
dx as f32 * (pan_sensitivity as f32 / 100.0),
|
||||
dy as f32 * (pan_sensitivity as f32 * mouse_y_inversion / 100.0),
|
||||
);
|
||||
|
||||
if cursor_grabbed {
|
||||
events.push(Event::CursorPan(delta));
|
||||
} else {
|
||||
events.push(Event::CursorMove(delta));
|
||||
}
|
||||
},
|
||||
glutin::DeviceEvent::MouseWheel { delta, .. } if cursor_grabbed && *focused => {
|
||||
events.push(Event::Zoom({
|
||||
// Since scrolling apparently acts different depending on platform
|
||||
#[cfg(target_os = "windows")]
|
||||
const PLATFORM_FACTOR: f32 = -4.0;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
const PLATFORM_FACTOR: f32 = 1.0;
|
||||
|
||||
let y = match delta {
|
||||
glutin::MouseScrollDelta::LineDelta(_x, y) => y,
|
||||
// TODO: Check to see if there is a better way to find the "line
|
||||
// height" than just hardcoding 16.0 pixels. Alternately we could
|
||||
// get rid of this and have the user set zoom sensitivity, since
|
||||
// it's unlikely people would expect a configuration file to work
|
||||
// across operating systems.
|
||||
glutin::MouseScrollDelta::PixelDelta(pos) => (pos.y / 16.0) as f32,
|
||||
};
|
||||
y * (zoom_sensitivity as f32 / 100.0) * zoom_inversion * PLATFORM_FACTOR
|
||||
}))
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(pos) = cursor_position {
|
||||
self.cursor_position = pos;
|
||||
}
|
||||
|
||||
if take_screenshot {
|
||||
self.take_screenshot(&settings);
|
||||
}
|
||||
|
||||
if toggle_fullscreen {
|
||||
self.toggle_fullscreen(settings);
|
||||
for message in self.message_receiver.try_iter() {
|
||||
self.events.push(Event::ScreenshotMessage(message))
|
||||
}
|
||||
|
||||
if let Some(gilrs) = &mut self.gilrs {
|
||||
@ -808,7 +646,7 @@ impl Window {
|
||||
| EventType::ButtonRepeated(button, code) => {
|
||||
handle_buttons(
|
||||
&self.controller_settings,
|
||||
&mut events,
|
||||
&mut self.events,
|
||||
&Button::from((button, code)),
|
||||
true,
|
||||
);
|
||||
@ -816,7 +654,7 @@ impl Window {
|
||||
EventType::ButtonReleased(button, code) => {
|
||||
handle_buttons(
|
||||
&self.controller_settings,
|
||||
&mut events,
|
||||
&mut self.events,
|
||||
&Button::from((button, code)),
|
||||
false,
|
||||
);
|
||||
@ -843,13 +681,14 @@ impl Window {
|
||||
},
|
||||
|
||||
EventType::AxisChanged(axis, value, code) => {
|
||||
let value = match self
|
||||
let value = if self
|
||||
.controller_settings
|
||||
.inverted_axes
|
||||
.contains(&Axis::from((axis, code)))
|
||||
{
|
||||
true => value * -1.0,
|
||||
false => value,
|
||||
-value
|
||||
} else {
|
||||
value
|
||||
};
|
||||
|
||||
let value = self
|
||||
@ -865,17 +704,17 @@ impl Window {
|
||||
for action in actions {
|
||||
match *action {
|
||||
AxisGameAction::MovementX => {
|
||||
events.push(Event::AnalogGameInput(
|
||||
self.events.push(Event::AnalogGameInput(
|
||||
AnalogGameInput::MovementX(value),
|
||||
));
|
||||
},
|
||||
AxisGameAction::MovementY => {
|
||||
events.push(Event::AnalogGameInput(
|
||||
self.events.push(Event::AnalogGameInput(
|
||||
AnalogGameInput::MovementY(value),
|
||||
));
|
||||
},
|
||||
AxisGameAction::CameraX => {
|
||||
events.push(Event::AnalogGameInput(
|
||||
self.events.push(Event::AnalogGameInput(
|
||||
AnalogGameInput::CameraX(
|
||||
value
|
||||
* self.controller_settings.pan_sensitivity
|
||||
@ -885,7 +724,7 @@ impl Window {
|
||||
));
|
||||
},
|
||||
AxisGameAction::CameraY => {
|
||||
events.push(Event::AnalogGameInput(
|
||||
self.events.push(Event::AnalogGameInput(
|
||||
AnalogGameInput::CameraY(
|
||||
value
|
||||
* self.controller_settings.pan_sensitivity
|
||||
@ -906,22 +745,22 @@ impl Window {
|
||||
for action in actions {
|
||||
match *action {
|
||||
AxisMenuAction::MoveX => {
|
||||
events.push(Event::AnalogMenuInput(
|
||||
self.events.push(Event::AnalogMenuInput(
|
||||
AnalogMenuInput::MoveX(value),
|
||||
));
|
||||
},
|
||||
AxisMenuAction::MoveY => {
|
||||
events.push(Event::AnalogMenuInput(
|
||||
self.events.push(Event::AnalogMenuInput(
|
||||
AnalogMenuInput::MoveY(value),
|
||||
));
|
||||
},
|
||||
AxisMenuAction::ScrollX => {
|
||||
events.push(Event::AnalogMenuInput(
|
||||
self.events.push(Event::AnalogMenuInput(
|
||||
AnalogMenuInput::ScrollX(value),
|
||||
));
|
||||
},
|
||||
AxisMenuAction::ScrollY => {
|
||||
events.push(Event::AnalogMenuInput(
|
||||
self.events.push(Event::AnalogMenuInput(
|
||||
AnalogMenuInput::ScrollY(value),
|
||||
));
|
||||
},
|
||||
@ -936,6 +775,7 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
let mut events = std::mem::take(&mut self.events);
|
||||
// Mouse emulation for the menus, to be removed when a proper menu navigation
|
||||
// system is available
|
||||
if !self.cursor_grabbed {
|
||||
@ -952,46 +792,231 @@ impl Window {
|
||||
self.mouse_emulation_vec.y = d * -1.0;
|
||||
None
|
||||
},
|
||||
_ => {
|
||||
let event = Event::AnalogMenuInput(input);
|
||||
Some(event)
|
||||
},
|
||||
},
|
||||
Event::MenuInput(input, state) => match input {
|
||||
MenuInput::Apply => Some(match state {
|
||||
true => Event::Ui(ui::Event(conrod_core::event::Input::Press(
|
||||
conrod_core::input::Button::Mouse(
|
||||
conrod_core::input::state::mouse::Button::Left,
|
||||
),
|
||||
))),
|
||||
false => Event::Ui(ui::Event(conrod_core::event::Input::Release(
|
||||
conrod_core::input::Button::Mouse(
|
||||
conrod_core::input::state::mouse::Button::Left,
|
||||
),
|
||||
))),
|
||||
}),
|
||||
_ => Some(event),
|
||||
input => Some(Event::AnalogMenuInput(input)),
|
||||
},
|
||||
Event::MenuInput(MenuInput::Apply, state) => Some(match state {
|
||||
true => Event::Ui(ui::Event(conrod_core::event::Input::Press(
|
||||
conrod_core::input::Button::Mouse(
|
||||
conrod_core::input::state::mouse::Button::Left,
|
||||
),
|
||||
))),
|
||||
false => Event::Ui(ui::Event(conrod_core::event::Input::Release(
|
||||
conrod_core::input::Button::Mouse(
|
||||
conrod_core::input::state::mouse::Button::Left,
|
||||
),
|
||||
))),
|
||||
}),
|
||||
_ => Some(event),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let sensitivity = self.controller_settings.mouse_emulation_sensitivity;
|
||||
if self.mouse_emulation_vec != Vec2::zero() {
|
||||
self.offset_cursor(self.mouse_emulation_vec * sensitivity as f32)
|
||||
.unwrap_or(());
|
||||
}
|
||||
// TODO: make this independent of framerate
|
||||
// TODO: consider multiplying by scale factor
|
||||
self.offset_cursor(self.mouse_emulation_vec * sensitivity as f32);
|
||||
}
|
||||
|
||||
events
|
||||
}
|
||||
|
||||
pub fn handle_device_event(&mut self, event: winit::event::DeviceEvent) {
|
||||
use winit::event::DeviceEvent;
|
||||
|
||||
let mouse_y_inversion = match self.mouse_y_inversion {
|
||||
true => -1.0,
|
||||
false => 1.0,
|
||||
};
|
||||
|
||||
match event {
|
||||
DeviceEvent::MouseMotion {
|
||||
delta: (dx, dy), ..
|
||||
} if self.focused => {
|
||||
let delta = Vec2::new(
|
||||
dx as f32 * (self.pan_sensitivity as f32 / 100.0),
|
||||
dy as f32 * (self.pan_sensitivity as f32 * mouse_y_inversion / 100.0),
|
||||
);
|
||||
|
||||
if self.cursor_grabbed {
|
||||
self.events.push(Event::CursorPan(delta));
|
||||
} else {
|
||||
self.events.push(Event::CursorMove(delta));
|
||||
}
|
||||
},
|
||||
DeviceEvent::MouseWheel { delta, .. } if self.cursor_grabbed && self.focused => {
|
||||
self.events.push(Event::Zoom({
|
||||
// Since scrolling apparently acts different depending on platform
|
||||
#[cfg(target_os = "windows")]
|
||||
const PLATFORM_FACTOR: f32 = -4.0;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
const PLATFORM_FACTOR: f32 = 1.0;
|
||||
|
||||
let y = match delta {
|
||||
winit::event::MouseScrollDelta::LineDelta(_x, y) => y,
|
||||
// TODO: Check to see if there is a better way to find the "line
|
||||
// height" than just hardcoding 16.0 pixels. Alternately we could
|
||||
// get rid of this and have the user set zoom sensitivity, since
|
||||
// it's unlikely people would expect a configuration file to work
|
||||
// across operating systems.
|
||||
winit::event::MouseScrollDelta::PixelDelta(pos) => (pos.y / 16.0) as f32,
|
||||
};
|
||||
y * (self.zoom_sensitivity as f32 / 100.0)
|
||||
* if self.zoom_inversion { -1.0 } else { 1.0 }
|
||||
* PLATFORM_FACTOR
|
||||
}))
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_window_event(
|
||||
&mut self,
|
||||
event: winit::event::WindowEvent,
|
||||
settings: &mut Settings,
|
||||
) {
|
||||
use winit::event::WindowEvent;
|
||||
|
||||
let controls = &mut settings.controls;
|
||||
// TODO: these used to be used to deduplicate events which they no longer do
|
||||
// this needs to be handled elsewhere
|
||||
let mut toggle_fullscreen = false;
|
||||
let mut take_screenshot = false;
|
||||
|
||||
match event {
|
||||
WindowEvent::CloseRequested => self.events.push(Event::Close),
|
||||
WindowEvent::Resized(winit::dpi::PhysicalSize { width, height }) => {
|
||||
let (mut color_view, mut depth_view) = self.renderer.win_views_mut();
|
||||
self.window.update_gfx(&mut color_view, &mut depth_view);
|
||||
self.renderer.on_resize().unwrap();
|
||||
// TODO: update users of this event with the fact that it is now the physical
|
||||
// size
|
||||
self.events
|
||||
.push(Event::Resize(Vec2::new(width as u32, height as u32)));
|
||||
},
|
||||
WindowEvent::ReceivedCharacter(c) => self.events.push(Event::Char(c)),
|
||||
WindowEvent::MouseInput { button, state, .. } => {
|
||||
if let (true, Some(game_inputs)) =
|
||||
// Mouse input not mapped to input if it is not grabbed
|
||||
(
|
||||
self.cursor_grabbed,
|
||||
Window::map_input(
|
||||
KeyMouse::Mouse(button),
|
||||
controls,
|
||||
&mut self.remapping_keybindings,
|
||||
),
|
||||
) {
|
||||
for game_input in game_inputs {
|
||||
self.events.push(Event::InputUpdate(
|
||||
*game_input,
|
||||
state == winit::event::ElementState::Pressed,
|
||||
));
|
||||
}
|
||||
}
|
||||
self.events.push(Event::MouseButton(button, state));
|
||||
},
|
||||
WindowEvent::ModifiersChanged(modifiers) => self.modifiers = modifiers,
|
||||
WindowEvent::KeyboardInput {
|
||||
input,
|
||||
is_synthetic,
|
||||
..
|
||||
} => {
|
||||
// Ignore synthetic tab presses so that we don't get tabs when alt-tabbing back
|
||||
// into the window
|
||||
if matches!(
|
||||
input.virtual_keycode,
|
||||
Some(winit::event::VirtualKeyCode::Tab)
|
||||
) && is_synthetic
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Ignore Alt-F4 so we don't try to do anything heavy like take a screenshot
|
||||
// when the window is about to close
|
||||
if matches!(input, winit::event::KeyboardInput {
|
||||
state: winit::event::ElementState::Pressed,
|
||||
virtual_keycode: Some(winit::event::VirtualKeyCode::F4),
|
||||
..
|
||||
}) && self.modifiers.alt()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(key) = input.virtual_keycode {
|
||||
if let Some(game_inputs) = Window::map_input(
|
||||
KeyMouse::Key(key),
|
||||
controls,
|
||||
&mut self.remapping_keybindings,
|
||||
) {
|
||||
for game_input in game_inputs {
|
||||
match game_input {
|
||||
GameInput::Fullscreen => {
|
||||
if input.state == winit::event::ElementState::Pressed
|
||||
&& !Self::is_pressed(
|
||||
&mut self.keypress_map,
|
||||
GameInput::Fullscreen,
|
||||
)
|
||||
{
|
||||
toggle_fullscreen = !toggle_fullscreen;
|
||||
}
|
||||
Self::set_pressed(
|
||||
&mut self.keypress_map,
|
||||
GameInput::Fullscreen,
|
||||
input.state,
|
||||
);
|
||||
},
|
||||
GameInput::Screenshot => {
|
||||
take_screenshot = input.state
|
||||
== winit::event::ElementState::Pressed
|
||||
&& !Self::is_pressed(
|
||||
&mut self.keypress_map,
|
||||
GameInput::Screenshot,
|
||||
);
|
||||
Self::set_pressed(
|
||||
&mut self.keypress_map,
|
||||
GameInput::Screenshot,
|
||||
input.state,
|
||||
);
|
||||
},
|
||||
_ => self.events.push(Event::InputUpdate(
|
||||
*game_input,
|
||||
input.state == winit::event::ElementState::Pressed,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
WindowEvent::Focused(state) => {
|
||||
self.focused = state;
|
||||
self.events.push(Event::Focused(state));
|
||||
},
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
self.cursor_position = position;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
if take_screenshot {
|
||||
self.take_screenshot(&settings);
|
||||
}
|
||||
|
||||
if toggle_fullscreen {
|
||||
self.toggle_fullscreen(settings);
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves cursor by an offset
|
||||
pub fn offset_cursor(&self, d: Vec2<f32>) -> Result<(), String> {
|
||||
self.window
|
||||
.window()
|
||||
.set_cursor_position(winit::dpi::LogicalPosition::new(
|
||||
d.x as f64 + self.cursor_position.x,
|
||||
d.y as f64 + self.cursor_position.y,
|
||||
))
|
||||
pub fn offset_cursor(&self, d: Vec2<f32>) {
|
||||
if d != Vec2::zero() {
|
||||
if let Err(err) =
|
||||
self.window
|
||||
.window()
|
||||
.set_cursor_position(winit::dpi::LogicalPosition::new(
|
||||
d.x as f64 + self.cursor_position.x,
|
||||
d.y as f64 + self.cursor_position.y,
|
||||
))
|
||||
{
|
||||
error!("Error setting cursor position: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_buffers(&self) -> Result<(), Error> {
|
||||
@ -1004,8 +1029,8 @@ impl Window {
|
||||
|
||||
pub fn grab_cursor(&mut self, grab: bool) {
|
||||
self.cursor_grabbed = grab;
|
||||
self.window.window().hide_cursor(grab);
|
||||
let _ = self.window.window().grab_cursor(grab);
|
||||
self.window.window().set_cursor_visible(!grab);
|
||||
let _ = self.window.window().set_cursor_grab(grab);
|
||||
}
|
||||
|
||||
pub fn toggle_fullscreen(&mut self, settings: &mut Settings) {
|
||||
@ -1020,7 +1045,13 @@ impl Window {
|
||||
let window = self.window.window();
|
||||
self.fullscreen = fullscreen;
|
||||
if fullscreen {
|
||||
window.set_fullscreen(Some(window.get_current_monitor()));
|
||||
window.set_fullscreen(Some(winit::window::Fullscreen::Exclusive(
|
||||
window
|
||||
.current_monitor()
|
||||
.video_modes()
|
||||
.max_by_key(|mode| mode.size().width)
|
||||
.expect("No video modes available!!"),
|
||||
)));
|
||||
} else {
|
||||
window.set_fullscreen(None);
|
||||
}
|
||||
@ -1033,8 +1064,8 @@ impl Window {
|
||||
let (w, h) = self
|
||||
.window
|
||||
.window()
|
||||
.get_inner_size()
|
||||
.unwrap_or(glutin::dpi::LogicalSize::new(0.0, 0.0))
|
||||
.inner_size()
|
||||
.to_logical::<f64>(self.window.window().scale_factor())
|
||||
.into();
|
||||
Vec2::new(w, h)
|
||||
}
|
||||
@ -1048,7 +1079,7 @@ impl Window {
|
||||
));
|
||||
}
|
||||
|
||||
pub fn send_supplement_event(&mut self, event: Event) { self.supplement_events.push(event) }
|
||||
pub fn send_event(&mut self, event: Event) { self.events.push(event) }
|
||||
|
||||
pub fn take_screenshot(&mut self, settings: &Settings) {
|
||||
match self.renderer.create_screenshot() {
|
||||
@ -1086,15 +1117,20 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_pressed(map: &mut HashMap<GameInput, glutin::ElementState>, input: GameInput) -> bool {
|
||||
*(map.entry(input).or_insert(glutin::ElementState::Released))
|
||||
== glutin::ElementState::Pressed
|
||||
fn is_pressed(
|
||||
map: &mut HashMap<GameInput, winit::event::ElementState>,
|
||||
input: GameInput,
|
||||
) -> bool {
|
||||
*(map
|
||||
.entry(input)
|
||||
.or_insert(winit::event::ElementState::Released))
|
||||
== winit::event::ElementState::Pressed
|
||||
}
|
||||
|
||||
fn set_pressed(
|
||||
map: &mut HashMap<GameInput, glutin::ElementState>,
|
||||
map: &mut HashMap<GameInput, winit::event::ElementState>,
|
||||
input: GameInput,
|
||||
state: glutin::ElementState,
|
||||
state: winit::event::ElementState,
|
||||
) {
|
||||
map.insert(input, state);
|
||||
}
|
||||
@ -1109,6 +1145,7 @@ impl Window {
|
||||
remapping: &mut Option<GameInput>,
|
||||
) -> Option<impl Iterator<Item = &'a GameInput>> {
|
||||
match *remapping {
|
||||
// TODO: save settings
|
||||
Some(game_input) => {
|
||||
controls.modify_binding(game_input, key_mouse);
|
||||
*remapping = None;
|
||||
|
Loading…
Reference in New Issue
Block a user