Merge branch 'zesterer/winit-20' into 'master'

Upgrade winit to 0.22.2

See merge request veloren/veloren!788
This commit is contained in:
Imbris
2020-07-18 03:26:59 +00:00
18 changed files with 1195 additions and 962 deletions

View File

@ -71,6 +71,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Animals are more effective in combat - Animals are more effective in combat
- Pathfinding is much smoother and pets are cleverer - Pathfinding is much smoother and pets are cleverer
- Animals run/turn at different speeds - Animals run/turn at different speeds
- Updated windowing library (winit 0.19 -> 0.22)
### Removed ### Removed

357
Cargo.lock generated
View File

@ -63,6 +63,12 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407"
[[package]]
name = "android_log-sys"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8052e2d8aabbb8d556d6abbcce2a22b9590996c5f849b9c7ce4544a2e3b984e"
[[package]] [[package]]
name = "ansi_term" name = "ansi_term"
version = "0.11.0" version = "0.11.0"
@ -428,6 +434,17 @@ dependencies = [
"winapi 0.3.8", "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]] [[package]]
name = "cast" name = "cast"
version = "0.2.3" version = "0.2.3"
@ -463,11 +480,10 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]] [[package]]
name = "cgl" name = "cgl"
version = "0.2.3" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55e7ec0b74fe5897894cbc207092c577e87c52f8a59e8ca8d97ef37551f60a49" checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff"
dependencies = [ dependencies = [
"gleam",
"libc", "libc",
] ]
@ -530,14 +546,14 @@ dependencies = [
[[package]] [[package]]
name = "cocoa" name = "cocoa"
version = "0.18.5" version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1706996401131526e36b3b49f0c4d912639ce110996f3ca144d78946727bce54" checksum = "f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"block", "block",
"core-foundation", "core-foundation 0.6.4",
"core-graphics", "core-graphics 0.17.3",
"foreign-types", "foreign-types",
"libc", "libc",
"objc", "objc",
@ -545,14 +561,14 @@ dependencies = [
[[package]] [[package]]
name = "cocoa" name = "cocoa"
version = "0.19.1" version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400" checksum = "0c49e86fc36d5704151f5996b7b3795385f50ce09e3be0f47a0cfde869681cf8"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"block", "block",
"core-foundation", "core-foundation 0.7.0",
"core-graphics", "core-graphics 0.19.2",
"foreign-types", "foreign-types",
"libc", "libc",
"objc", "objc",
@ -561,7 +577,7 @@ dependencies = [
[[package]] [[package]]
name = "conrod_core" name = "conrod_core"
version = "0.63.0" 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 = [ dependencies = [
"conrod_derive", "conrod_derive",
"copypasta", "copypasta",
@ -576,7 +592,7 @@ dependencies = [
[[package]] [[package]]
name = "conrod_derive" name = "conrod_derive"
version = "0.63.0" 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 = [ dependencies = [
"proc-macro2 0.4.30", "proc-macro2 0.4.30",
"quote 0.6.13", "quote 0.6.13",
@ -586,7 +602,7 @@ dependencies = [
[[package]] [[package]]
name = "conrod_winit" name = "conrod_winit"
version = "0.63.0" 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]] [[package]]
name = "const-random" name = "const-random"
@ -663,7 +679,7 @@ dependencies = [
"objc-foundation", "objc-foundation",
"objc_id", "objc_id",
"smithay-clipboard", "smithay-clipboard",
"wayland-client 0.23.6", "wayland-client",
"x11-clipboard", "x11-clipboard",
] ]
@ -673,7 +689,17 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" checksum = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
dependencies = [ 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", "libc",
] ]
@ -683,6 +709,12 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
[[package]]
name = "core-foundation-sys"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
[[package]] [[package]]
name = "core-graphics" name = "core-graphics"
version = "0.17.3" version = "0.17.3"
@ -690,11 +722,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" checksum = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"core-foundation", "core-foundation 0.6.4",
"foreign-types", "foreign-types",
"libc", "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]] [[package]]
name = "coreaudio-rs" name = "coreaudio-rs"
version = "0.9.1" version = "0.9.1"
@ -721,7 +778,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b55d55d69f403f62a95bd3c04b431e0aedf5120c70f15d07a8edd234443dd59" checksum = "6b55d55d69f403f62a95bd3c04b431e0aedf5120c70f15d07a8edd234443dd59"
dependencies = [ dependencies = [
"alsa-sys", "alsa-sys",
"core-foundation-sys", "core-foundation-sys 0.6.2",
"coreaudio-rs", "coreaudio-rs",
"lazy_static", "lazy_static",
"libc", "libc",
@ -992,6 +1049,17 @@ dependencies = [
"byteorder 1.3.4", "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]] [[package]]
name = "deunicode" name = "deunicode"
version = "1.1.1" version = "1.1.1"
@ -1063,6 +1131,12 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04e93ca78226c51902d7aa8c12c988338aadd9e85ed9c6be8aaac39192ff3605" checksum = "04e93ca78226c51902d7aa8c12c988338aadd9e85ed9c6be8aaac39192ff3605"
[[package]]
name = "dispatch"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]] [[package]]
name = "dlib" name = "dlib"
version = "0.4.2" version = "0.4.2"
@ -1505,17 +1579,6 @@ dependencies = [
"gl_generator 0.14.0", "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]] [[package]]
name = "gilrs" name = "gilrs"
version = "0.7.4" version = "0.7.4"
@ -1537,7 +1600,7 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43c758daf46af26d6872fe55507e3b2339779a160a06ad7a9b2a082f221209cd" checksum = "43c758daf46af26d6872fe55507e3b2339779a160a06ad7a9b2a082f221209cd"
dependencies = [ dependencies = [
"core-foundation", "core-foundation 0.6.4",
"io-kit-sys", "io-kit-sys",
"libc", "libc",
"libudev-sys", "libudev-sys",
@ -1621,15 +1684,6 @@ dependencies = [
"xml-rs", "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]] [[package]]
name = "glib" name = "glib"
version = "0.5.0" version = "0.5.0"
@ -1672,15 +1726,15 @@ dependencies = [
[[package]] [[package]]
name = "glutin" name = "glutin"
version = "0.21.2" version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5371b35b309dace06be1b81b5f6adb1c9de578b7dbe1e74bf7e4ef762cf6febd" checksum = "9a9666c8fd9afd008f6559e2468c35e11aad1d110d525bb3b354e4138ec0e20f"
dependencies = [ dependencies = [
"android_glue", "android_glue",
"cgl", "cgl",
"cocoa 0.18.5", "cocoa 0.20.2",
"core-foundation", "core-foundation 0.7.0",
"core-graphics", "core-graphics 0.19.2",
"glutin_egl_sys", "glutin_egl_sys",
"glutin_emscripten_sys", "glutin_emscripten_sys",
"glutin_gles2_sys", "glutin_gles2_sys",
@ -1688,10 +1742,11 @@ dependencies = [
"glutin_wgl_sys", "glutin_wgl_sys",
"lazy_static", "lazy_static",
"libloading 0.5.2", "libloading 0.5.2",
"log",
"objc", "objc",
"osmesa-sys", "osmesa-sys",
"parking_lot 0.9.0", "parking_lot 0.10.2",
"wayland-client 0.21.13", "wayland-client",
"winapi 0.3.8", "winapi 0.3.8",
"winit", "winit",
] ]
@ -2048,7 +2103,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f21dcc74995dd4cd090b147e79789f8d65959cbfb5f0b118002db869ea3bd0a0" checksum = "f21dcc74995dd4cd090b147e79789f8d65959cbfb5f0b118002db869ea3bd0a0"
dependencies = [ dependencies = [
"core-foundation-sys", "core-foundation-sys 0.6.2",
"mach", "mach",
] ]
@ -2076,6 +2131,12 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
[[package]]
name = "jni-sys"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]] [[package]]
name = "jobserver" name = "jobserver"
version = "0.1.21" version = "0.1.21"
@ -2448,6 +2509,37 @@ dependencies = [
"winapi 0.3.8", "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]] [[package]]
name = "net2" name = "net2"
version = "0.2.34" version = "0.2.34"
@ -2638,6 +2730,28 @@ dependencies = [
"libc", "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]] [[package]]
name = "objc" name = "objc"
version = "0.2.7" version = "0.2.7"
@ -2682,6 +2796,17 @@ dependencies = [
"byteorder 1.3.4", "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]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.4.0" version = "1.4.0"
@ -2957,6 +3082,15 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" 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]] [[package]]
name = "proc-macro-error" name = "proc-macro-error"
version = "0.4.12" version = "0.4.12"
@ -3671,23 +3805,6 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" 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]] [[package]]
name = "smithay-client-toolkit" name = "smithay-client-toolkit"
version = "0.6.6" version = "0.6.6"
@ -3700,8 +3817,8 @@ dependencies = [
"lazy_static", "lazy_static",
"memmap", "memmap",
"nix 0.14.1", "nix 0.14.1",
"wayland-client 0.23.6", "wayland-client",
"wayland-protocols 0.23.6", "wayland-protocols",
] ]
[[package]] [[package]]
@ -3711,7 +3828,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "917e8ec7f535cd1a6cbf749c8866c24d67c548a80ac48c8e88a182eab5c07bd1" checksum = "917e8ec7f535cd1a6cbf749c8866c24d67c548a80ac48c8e88a182eab5c07bd1"
dependencies = [ dependencies = [
"nix 0.14.1", "nix 0.14.1",
"smithay-client-toolkit 0.6.6", "smithay-client-toolkit",
] ]
[[package]] [[package]]
@ -4506,13 +4623,12 @@ dependencies = [
"crossbeam", "crossbeam",
"deunicode", "deunicode",
"directories-next", "directories-next",
"dispatch", "dispatch 0.1.4",
"dot_vox", "dot_vox",
"euc", "euc",
"failure", "failure",
"gfx", "gfx",
"gfx_device_gl", "gfx_device_gl",
"gfx_window_glutin",
"gilrs", "gilrs",
"git2", "git2",
"glsl-include", "glsl-include",
@ -4522,6 +4638,7 @@ dependencies = [
"image", "image",
"msgbox", "msgbox",
"num 0.2.1", "num 0.2.1",
"old_school_gfx_glutin_ext",
"rand 0.7.3", "rand 0.7.3",
"rodio", "rodio",
"ron", "ron",
@ -4706,21 +4823,6 @@ version = "0.2.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9ba19973a58daf4db6f352eda73dc0e289493cd29fb2632eb172085b6521acd" 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]] [[package]]
name = "wayland-client" name = "wayland-client"
version = "0.23.6" version = "0.23.6"
@ -4728,22 +4830,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda" checksum = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"calloop",
"downcast-rs", "downcast-rs",
"libc", "libc",
"mio",
"nix 0.14.1", "nix 0.14.1",
"wayland-commons 0.23.6", "wayland-commons",
"wayland-scanner 0.23.6", "wayland-scanner",
"wayland-sys 0.23.6", "wayland-sys",
]
[[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",
] ]
[[package]] [[package]]
@ -4753,20 +4847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb" checksum = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb"
dependencies = [ dependencies = [
"nix 0.14.1", "nix 0.14.1",
"wayland-sys 0.23.6", "wayland-sys",
]
[[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",
] ]
[[package]] [[package]]
@ -4776,20 +4857,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9" checksum = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"wayland-client 0.23.6", "wayland-client",
"wayland-commons 0.23.6", "wayland-commons",
"wayland-scanner 0.23.6", "wayland-scanner",
]
[[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",
] ]
[[package]] [[package]]
@ -4803,16 +4873,6 @@ dependencies = [
"xml-rs", "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]] [[package]]
name = "wayland-sys" name = "wayland-sys"
version = "0.23.6" version = "0.23.6"
@ -4897,26 +4957,31 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "winit" name = "winit"
version = "0.19.5" version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/Imberflur/winit.git?branch=macos-test#e98133adf2abbfc4368f6c069d0beb2b8b688b42"
checksum = "1e96eb4bb472fa43e718e8fa4aef82f86cd9deac9483a1e1529230babdb394a8"
dependencies = [ dependencies = [
"android_glue",
"backtrace",
"bitflags", "bitflags",
"cocoa 0.18.5", "cocoa 0.20.2",
"core-foundation", "core-foundation 0.7.0",
"core-graphics", "core-graphics 0.19.2",
"core-video-sys",
"dispatch 0.2.0",
"instant",
"lazy_static", "lazy_static",
"libc", "libc",
"log", "log",
"mio",
"mio-extras",
"ndk",
"ndk-glue",
"ndk-sys",
"objc", "objc",
"parking_lot 0.9.0", "parking_lot 0.10.2",
"percent-encoding 2.1.0", "percent-encoding 2.1.0",
"raw-window-handle", "raw-window-handle",
"serde", "serde",
"smithay-client-toolkit 0.4.6", "smithay-client-toolkit",
"wayland-client 0.21.13", "wayland-client",
"winapi 0.3.8", "winapi 0.3.8",
"x11-dl", "x11-dl",
] ]

View File

@ -72,3 +72,7 @@ debug = false
[profile.releasedebuginfo] [profile.releasedebuginfo]
inherits = 'release' inherits = 'release'
debug = 1 debug = 1
# cpal conflict fix isn't released yet
[patch.crates-io]
winit = { git = "https://github.com/Imberflur/winit.git", branch = "macos-test" }

View File

@ -249,15 +249,11 @@ impl State {
/// Removes every chunk of the terrain. /// Removes every chunk of the terrain.
pub fn clear_terrain(&mut self) { pub fn clear_terrain(&mut self) {
let keys = self let removed_chunks = &mut self.ecs.write_resource::<TerrainChanges>().removed_chunks;
.terrain_mut()
.drain()
.map(|(key, _)| key)
.collect::<Vec<_>>();
for key in keys { self.terrain_mut().drain().for_each(|(key, _)| {
self.remove_chunk(key); removed_chunks.insert(key);
} });
} }
/// Insert the provided chunk into this state's terrain. /// Insert the provided chunk into this state's terrain.

View File

@ -25,11 +25,11 @@ anim = { package = "veloren-voxygen-anim", path = "src/anim", default-features =
# Graphics # Graphics
gfx = "0.18.2" gfx = "0.18.2"
gfx_device_gl = { version = "0.16.2", optional = true } gfx_device_gl = { version = "0.16.2", optional = true }
gfx_window_glutin = "0.31.0" old_school_gfx_glutin_ext = "0.24"
glutin = "0.21.1" glutin = "0.24.1"
winit = { version = "0.19.4", features = ["serde"] } winit = { version = "0.22.2", features = ["serde"] }
conrod_core = { git = "https://gitlab.com/veloren/conrod.git", branch = "pre-winit-20" } conrod_core = { git = "https://gitlab.com/veloren/conrod.git" }
conrod_winit = { git = "https://gitlab.com/veloren/conrod.git", branch = "pre-winit-20" } conrod_winit = { git = "https://gitlab.com/veloren/conrod.git" }
euc = { git = "https://github.com/zesterer/euc.git" } euc = { git = "https://github.com/zesterer/euc.git" }
# ECS # ECS
@ -87,7 +87,6 @@ winres = "0.1"
criterion = "0.3" criterion = "0.3"
git2 = "0.13" git2 = "0.13"
world = { package = "veloren-world", path = "../world" } world = { package = "veloren-world", path = "../world" }
gfx_window_glutin = { version = "0.31.0", features = ["headless"] }
[[bench]] [[bench]]
name = "meshing_benchmark" name = "meshing_benchmark"

View File

@ -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 gfx_window_glutin::init_headless;
use vek::*; use vek::*;
use veloren_voxygen::{render, scene::simple as scene}; use veloren_voxygen::{render, scene::simple as scene};
#[allow(clippy::clone_on_copy)] // TODO: Pending review in #587
fn main() { fn main() {
// Setup renderer // Setup renderer
let dim = (200u16, 300u16, 1, gfx::texture::AaMode::Single); let dim = (200u16, 300u16, 1, gfx::texture::AaMode::Single);
@ -72,4 +79,4 @@ fn main() {
// Get image // Get image
let img = renderer.create_screenshot().unwrap(); let img = renderer.create_screenshot().unwrap();
img.save("character.png").unwrap(); img.save("character.png").unwrap();
} }*/

View File

@ -465,17 +465,15 @@ impl Show {
self.want_grab = true; self.want_grab = true;
// Unpause the game if we are on singleplayer // Unpause the game if we are on singleplayer
if let Some(singleplayer) = global_state.singleplayer.as_ref() { #[cfg(feature = "singleplayer")]
singleplayer.pause(false); global_state.unpause();
};
} else { } else {
self.esc_menu = true; self.esc_menu = true;
self.want_grab = false; self.want_grab = false;
// Pause the game if we are on singleplayer // Pause the game if we are on singleplayer
if let Some(singleplayer) = global_state.singleplayer.as_ref() { #[cfg(feature = "singleplayer")]
singleplayer.pause(true); global_state.pause();
};
} }
} }
@ -1721,9 +1719,8 @@ impl Hud {
settings_window::Event::ChangeTab(tab) => self.show.open_setting_tab(tab), settings_window::Event::ChangeTab(tab) => self.show.open_setting_tab(tab),
settings_window::Event::Close => { settings_window::Event::Close => {
// Unpause the game if we are on singleplayer so that we can logout // Unpause the game if we are on singleplayer so that we can logout
if let Some(singleplayer) = global_state.singleplayer.as_ref() { #[cfg(feature = "singleplayer")]
singleplayer.pause(false); global_state.unpause();
};
self.show.settings(false) self.show.settings(false)
}, },
@ -1908,24 +1905,21 @@ impl Hud {
self.force_ungrab = false; self.force_ungrab = false;
// Unpause the game if we are on singleplayer // Unpause the game if we are on singleplayer
if let Some(singleplayer) = global_state.singleplayer.as_ref() { #[cfg(feature = "singleplayer")]
singleplayer.pause(false); global_state.unpause();
};
}, },
Some(esc_menu::Event::Logout) => { Some(esc_menu::Event::Logout) => {
// Unpause the game if we are on singleplayer so that we can logout // Unpause the game if we are on singleplayer so that we can logout
if let Some(singleplayer) = global_state.singleplayer.as_ref() { #[cfg(feature = "singleplayer")]
singleplayer.pause(false); global_state.unpause();
};
events.push(Event::Logout); events.push(Event::Logout);
}, },
Some(esc_menu::Event::Quit) => events.push(Event::Quit), Some(esc_menu::Event::Quit) => events.push(Event::Quit),
Some(esc_menu::Event::CharacterSelection) => { Some(esc_menu::Event::CharacterSelection) => {
// Unpause the game if we are on singleplayer so that we can logout // Unpause the game if we are on singleplayer so that we can logout
if let Some(singleplayer) = global_state.singleplayer.as_ref() { #[cfg(feature = "singleplayer")]
singleplayer.pause(false); global_state.unpause();
};
events.push(Event::CharacterSelection) events.push(Event::CharacterSelection)
}, },

View File

@ -17,6 +17,7 @@ pub mod menu;
pub mod mesh; pub mod mesh;
pub mod profile; pub mod profile;
pub mod render; pub mod render;
pub mod run;
pub mod scene; pub mod scene;
pub mod session; pub mod session;
pub mod settings; pub mod settings;
@ -27,10 +28,16 @@ pub mod window;
// Reexports // Reexports
pub use crate::error::Error; pub use crate::error::Error;
#[cfg(feature = "singleplayer")]
use crate::singleplayer::Singleplayer;
use crate::{ use crate::{
audio::AudioFrontend, profile::Profile, settings::Settings, singleplayer::Singleplayer, audio::AudioFrontend,
window::Window, 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. /// A type used to store state that is shared between all play states.
pub struct GlobalState { pub struct GlobalState {
@ -39,7 +46,11 @@ pub struct GlobalState {
pub window: Window, pub window: Window,
pub audio: AudioFrontend, pub audio: AudioFrontend,
pub info_message: Option<String>, pub info_message: Option<String>,
pub clock: Clock,
#[cfg(feature = "singleplayer")]
pub singleplayer: Option<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 { impl GlobalState {
@ -51,8 +62,25 @@ impl GlobalState {
} }
pub fn maintain(&mut self, dt: f32) { self.audio.maintain(dt); } 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 { pub enum Direction {
Forwards, Forwards,
Backwards, Backwards,
@ -61,6 +89,8 @@ pub enum Direction {
/// States can either close (and revert to a previous state), push a new state /// 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. /// on top of themselves, or switch to a totally different state.
pub enum PlayStateResult { pub enum PlayStateResult {
/// Keep running this play state.
Continue,
/// Pop all play states in reverse order and shut down the program. /// Pop all play states in reverse order and shut down the program.
Shutdown, Shutdown,
/// Close the current play state and pop it from the play state stack. /// 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 /// A trait representing a playable game state. This may be a menu, a game
/// session, the title screen, etc. /// session, the title screen, etc.
pub trait PlayState { pub trait PlayState {
/// Play the state until some change of state is required (i.e: a menu is /// Called when entering this play state from another
/// opened or the game is closed). fn enter(&mut self, global_state: &mut GlobalState, direction: Direction);
fn play(&mut self, direction: Direction, global_state: &mut GlobalState) -> PlayStateResult;
/// Tick the play state
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult;
/// Get a descriptive name for this state type. /// Get a descriptive name for this state type.
fn name(&self) -> &'static str; fn name(&self) -> &'static str;
/// Draw the play state.
fn render(&mut self, renderer: &mut Renderer, settings: &Settings);
} }

View File

@ -7,16 +7,19 @@ use veloren_voxygen::{
audio::{self, AudioFrontend}, audio::{self, AudioFrontend},
i18n::{self, i18n_asset_key, VoxygenLocalization}, i18n::{self, i18n_asset_key, VoxygenLocalization},
logging, logging,
menu::main::MainMenuState,
profile::Profile, profile::Profile,
run,
settings::{AudioOutput, Settings}, settings::{AudioOutput, Settings},
window::Window, window::Window,
Direction, GlobalState, PlayState, PlayStateResult, GlobalState,
}; };
use common::assets::{load, load_expect}; use common::{
use std::{mem, panic}; assets::{load_watched, watch},
use tracing::{debug, error, warn}; clock::Clock,
};
use std::panic;
use tracing::{error, warn};
fn main() { fn main() {
#[cfg(feature = "tweak")] #[cfg(feature = "tweak")]
@ -26,57 +29,14 @@ fn main() {
// Note: This won't log anything due to it being called before // 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 // `logging::init`. The issue is we need to read a setting to decide
// whether we create a log file or not. // whether we create a log file or not.
let settings = Settings::load(); let mut settings = Settings::load();
// Save settings to add new fields or create the file if it is not already there
// 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.
if let Err(err) = settings.save_to_file() { if let Err(err) = settings.save_to_file() {
panic!("Failed to save settings: {:?}", err); panic!("Failed to save settings: {:?}", err);
} }
let mut audio = match settings.audio.output { // Init logging and hold the guards.
AudioOutput::Off => None, let _guards = logging::init(&settings);
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();
// Set up panic handler to relay swish panic messages to the user // Set up panic handler to relay swish panic messages to the user
let default_hook = panic::take_hook(); let default_hook = panic::take_hook();
@ -159,68 +119,56 @@ fn main() {
#[cfg(feature = "hot-anim")] #[cfg(feature = "hot-anim")]
anim::init(); anim::init();
// Set up the initial play state. // Setup audio
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(&mut global_state))]; let mut audio = match settings.audio.output {
states.last().map(|current_state| { AudioOutput::Off => None,
let current_state = current_state.name(); AudioOutput::Automatic => audio::get_default_device(),
debug!(?current_state, "Started game with state") AudioOutput::Device(ref dev) => Some(dev.clone()),
}); }
.map(|dev| AudioFrontend::new(dev, settings.audio.max_sfx_channels))
.unwrap_or_else(AudioFrontend::no_audio);
// What's going on here? audio.set_music_volume(settings.audio.music_volume);
// --------------------- audio.set_sfx_volume(settings.audio.sfx_volume);
// 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();
});
},
}
}
// Save any unsaved changes to profile. // Load the profile.
global_state.profile.save_to_file_warn(); let profile = Profile::load();
// Save any unsaved changes to settings.
global_state.settings.save_to_file_warn(); 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);
} }

View File

@ -2,15 +2,17 @@ mod ui;
use crate::{ use crate::{
i18n::{i18n_asset_key, VoxygenLocalization}, i18n::{i18n_asset_key, VoxygenLocalization},
render::Renderer,
scene::simple::{self as scene, Scene}, scene::simple::{self as scene, Scene},
session::SessionState, session::SessionState,
settings::Settings,
window::Event as WinEvent, window::Event as WinEvent,
Direction, GlobalState, PlayState, PlayStateResult, Direction, GlobalState, PlayState, PlayStateResult,
}; };
use client::{self, Client}; 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 specs::WorldExt;
use std::{cell::RefCell, rc::Rc, time::Duration}; use std::{cell::RefCell, rc::Rc};
use tracing::error; use tracing::error;
use ui::CharSelectionUi; 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 { impl PlayState for CharSelectionState {
fn play(&mut self, _: Direction, global_state: &mut GlobalState) -> PlayStateResult { fn enter(&mut self, _: &mut GlobalState, _: Direction) {
// Set up an fps clock.
let mut clock = Clock::start();
// Load the player's character list // Load the player's character list
self.client.borrow_mut().load_character_list(); self.client.borrow_mut().load_character_list();
}
let mut current_client_state = self.client.borrow().get_client_state(); fn tick(&mut self, global_state: &mut GlobalState, events: Vec<WinEvent>) -> PlayStateResult {
while let ClientState::Pending | ClientState::Registered = current_client_state { let client_state = self.client.borrow().get_client_state();
if let ClientState::Pending | ClientState::Registered = client_state {
// Handle window events // 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()) { if self.char_selection_ui.handle_event(event.clone()) {
continue; continue;
} }
@ -60,8 +76,6 @@ impl PlayState for CharSelectionState {
} }
} }
global_state.window.renderer_mut().clear();
// Maintain the UI. // Maintain the UI.
let events = self let events = self
.char_selection_ui .char_selection_ui
@ -100,23 +114,7 @@ impl PlayState for CharSelectionState {
} }
} }
// Maintain global state. let humanoid_body = self.get_humanoid_body();
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 loadout = self.char_selection_ui.get_loadout(); let loadout = self.char_selection_ui.get_loadout();
// Maintain the scene. // Maintain the scene.
@ -141,17 +139,6 @@ impl PlayState for CharSelectionState {
loadout.as_ref(), 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). // Tick the client (currently only to keep the connection alive).
let localized_strings = assets::load_expect::<VoxygenLocalization>(&i18n_asset_key( let localized_strings = assets::load_expect::<VoxygenLocalization>(&i18n_asset_key(
@ -160,7 +147,7 @@ impl PlayState for CharSelectionState {
match self.client.borrow_mut().tick( match self.client.borrow_mut().tick(
comp::ControllerInputs::default(), comp::ControllerInputs::default(),
clock.get_last_delta(), global_state.clock.get_last_delta(),
|_| {}, |_| {},
) { ) {
Ok(events) => { 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(); self.client.borrow_mut().cleanup();
// Finish the frame. PlayStateResult::Continue
global_state.window.renderer_mut().flush(); } else {
global_state error!("Client not in pending or registered state. Popping char selection play state");
.window // TODO set global_state.info_message
.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::Pop PlayStateResult::Pop
} }
}
fn name(&self) -> &'static str { "Title" } 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());
}
} }

View File

@ -1,19 +1,22 @@
mod client_init; mod client_init;
#[cfg(feature = "singleplayer")] mod ui; mod ui;
use super::char_selection::CharSelectionState; use super::char_selection::CharSelectionState;
#[cfg(feature = "singleplayer")]
use crate::singleplayer::Singleplayer;
use crate::{ 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 client_init::{ClientInit, Error as InitError, Msg as InitMsg};
use common::{assets::load_expect, clock::Clock, comp}; use common::{assets::load_expect, comp};
#[cfg(feature = "singleplayer")]
use std::time::Duration;
use tracing::{error, warn}; use tracing::{error, warn};
use ui::{Event as MainMenuEvent, MainMenuUi}; use ui::{Event as MainMenuEvent, MainMenuUi};
pub struct MainMenuState { pub struct MainMenuState {
main_menu_ui: MainMenuUi, main_menu_ui: MainMenuUi,
// Used for client creation.
client_init: Option<ClientInit>,
} }
impl MainMenuState { impl MainMenuState {
@ -21,6 +24,7 @@ impl MainMenuState {
pub fn new(global_state: &mut GlobalState) -> Self { pub fn new(global_state: &mut GlobalState) -> Self {
Self { Self {
main_menu_ui: MainMenuUi::new(global_state), main_menu_ui: MainMenuUi::new(global_state),
client_init: None,
} }
} }
} }
@ -28,29 +32,26 @@ impl MainMenuState {
const DEFAULT_PORT: u16 = 14004; const DEFAULT_PORT: u16 = 14004;
impl PlayState for MainMenuState { impl PlayState for MainMenuState {
#[allow(clippy::useless_format)] // TODO: Pending review in #587 fn enter(&mut self, global_state: &mut GlobalState, _: Direction) {
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;
// Kick off title music // Kick off title music
if global_state.settings.audio.output.is_enabled() && global_state.audio.music_enabled() { if global_state.settings.audio.output.is_enabled() && global_state.audio.music_enabled() {
global_state.audio.play_title_music(); global_state.audio.play_title_music();
} }
// Reset singleplayer server if it was running already // Reset singleplayer server if it was running already
#[cfg(feature = "singleplayer")]
{
global_state.singleplayer = None; global_state.singleplayer = None;
}
}
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult {
let localized_strings = load_expect::<crate::i18n::VoxygenLocalization>( let localized_strings = load_expect::<crate::i18n::VoxygenLocalization>(
&crate::i18n::i18n_asset_key(&global_state.settings.language.selected_language), &crate::i18n::i18n_asset_key(&global_state.settings.language.selected_language),
); );
loop {
// Handle window events. // Handle window events.
for event in global_state.window.fetch_events(&mut global_state.settings) { for event in events {
match event { match event {
Event::Close => return PlayStateResult::Shutdown, Event::Close => return PlayStateResult::Shutdown,
// Pass events to ui. // Pass events to ui.
@ -61,12 +62,10 @@ impl PlayState for MainMenuState {
_ => {}, _ => {},
} }
} }
global_state.window.renderer_mut().clear();
// Poll client creation. // Poll client creation.
match client_init.as_ref().and_then(|init| init.poll()) { match self.client_init.as_ref().and_then(|init| init.poll()) {
Some(InitMsg::Done(Ok(mut client))) => { Some(InitMsg::Done(Ok(mut client))) => {
self.client_init = None;
self.main_menu_ui.connected(); self.main_menu_ui.connected();
// Register voxygen components / resources // Register voxygen components / resources
crate::ecs::init(client.state_mut().ecs_mut()); crate::ecs::init(client.state_mut().ecs_mut());
@ -75,10 +74,10 @@ impl PlayState for MainMenuState {
std::rc::Rc::new(std::cell::RefCell::new(client)), std::rc::Rc::new(std::cell::RefCell::new(client)),
))); )));
}, },
Some(InitMsg::Done(Err(e))) => { Some(InitMsg::Done(Err(err))) => {
client_init = None; self.client_init = None;
global_state.info_message = Some({ global_state.info_message = Some({
let err = match e { let err = match err {
InitError::BadAddress(_) | InitError::NoAddress => { InitError::BadAddress(_) | InitError::NoAddress => {
localized_strings.get("main.login.server_not_found").into() localized_strings.get("main.login.server_not_found").into()
}, },
@ -109,6 +108,9 @@ impl PlayState for MainMenuState {
client::Error::NotOnWhitelist => { client::Error::NotOnWhitelist => {
localized_strings.get("main.login.not_on_whitelist").into() 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!( client::Error::NetworkErr(e) => format!(
"{}: {:?}", "{}: {:?}",
localized_strings.get("main.login.network_error"), localized_strings.get("main.login.network_error"),
@ -133,14 +135,11 @@ impl PlayState for MainMenuState {
localized_strings.get("common.fatal_error"), localized_strings.get("common.fatal_error"),
e e
), ),
client::AuthClientError::RequestError() => format!( // TODO: remove parentheses
"{}", client::AuthClientError::RequestError() => localized_strings
localized_strings.get("main.login.failed_sending_request") .get("main.login.failed_sending_request")
), .to_owned(),
client::AuthClientError::ServerError(_, e) => format!("{}", e), client::AuthClientError::ServerError(_, e) => e,
},
client::Error::InvalidCharacter => {
localized_strings.get("main.login.invalid_character").into()
}, },
}, },
InitError::ClientCrashed => { InitError::ClientCrashed => {
@ -161,7 +160,10 @@ impl PlayState for MainMenuState {
.contains(&auth_server) .contains(&auth_server)
{ {
// Can't fail since we just polled it, it must be Some // Can't fail since we just polled it, it must be Some
client_init.as_ref().unwrap().auth_trust(auth_server, true); self.client_init
.as_ref()
.unwrap()
.auth_trust(auth_server, true);
} else { } else {
// Show warning that auth server is not trusted and prompt for approval // Show warning that auth server is not trusted and prompt for approval
self.main_menu_ui.auth_trust_prompt(auth_server); self.main_menu_ui.auth_trust_prompt(auth_server);
@ -170,13 +172,10 @@ impl PlayState for MainMenuState {
None => {}, None => {},
} }
// Maintain global_state
global_state.maintain(clock.get_last_delta().as_secs_f32());
// Maintain the UI. // Maintain the UI.
for event in self for event in self
.main_menu_ui .main_menu_ui
.maintain(global_state, clock.get_last_delta()) .maintain(global_state, global_state.clock.get_last_delta())
{ {
match event { match event {
MainMenuEvent::LoginAttempt { MainMenuEvent::LoginAttempt {
@ -190,15 +189,18 @@ impl PlayState for MainMenuState {
password, password,
server_address, server_address,
DEFAULT_PORT, DEFAULT_PORT,
&mut client_init, &mut self.client_init,
); );
}, },
MainMenuEvent::CancelLoginAttempt => { MainMenuEvent::CancelLoginAttempt => {
// client_init contains Some(ClientInit), which spawns a thread which // client_init contains Some(ClientInit), which spawns a thread which contains a
// contains a TcpStream::connect() call This call is // TcpStream::connect() call This call is blocking
// blocking TODO fix when the network rework happens // TODO fix when the network rework happens
#[cfg(feature = "singleplayer")]
{
global_state.singleplayer = None; global_state.singleplayer = None;
client_init = None; }
self.client_init = None;
self.main_menu_ui.cancel_connection(); self.main_menu_ui.cancel_connection();
}, },
#[cfg(feature = "singleplayer")] #[cfg(feature = "singleplayer")]
@ -213,7 +215,7 @@ impl PlayState for MainMenuState {
"".to_owned(), "".to_owned(),
server_settings.gameserver_address.ip().to_string(), server_settings.gameserver_address.ip().to_string(),
server_settings.gameserver_address.port(), server_settings.gameserver_address.port(),
&mut client_init, &mut self.client_init,
); );
}, },
MainMenuEvent::Settings => {}, // TODO MainMenuEvent::Settings => {}, // TODO
@ -230,7 +232,7 @@ impl PlayState for MainMenuState {
.insert(auth_server.clone()); .insert(auth_server.clone());
global_state.settings.save_to_file_warn(); global_state.settings.save_to_file_warn();
} }
client_init self.client_init
.as_ref() .as_ref()
.map(|init| init.auth_trust(auth_server, trust)); .map(|init| init.auth_trust(auth_server, trust));
}, },
@ -241,24 +243,15 @@ impl PlayState for MainMenuState {
self.main_menu_ui.show_info(info); self.main_menu_ui.show_info(info);
} }
// Draw the UI to the screen. PlayStateResult::Continue
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),
));
}
} }
fn name(&self) -> &'static str { "Title" } 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( fn attempt_login(

145
voxygen/src/run.rs Normal file
View 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!");
}
}

View File

@ -5,15 +5,15 @@ use crate::{
i18n::{i18n_asset_key, VoxygenLocalization}, i18n::{i18n_asset_key, VoxygenLocalization},
key_state::KeyState, key_state::KeyState,
menu::char_selection::CharSelectionState, menu::char_selection::CharSelectionState,
render::Renderer,
scene::{camera, Scene, SceneData}, scene::{camera, Scene, SceneData},
settings::{AudioOutput, ControlSettings}, settings::{AudioOutput, ControlSettings, Settings},
window::{AnalogGameInput, Event, GameInput}, window::{AnalogGameInput, Event, GameInput},
Direction, Error, GlobalState, PlayState, PlayStateResult, Direction, Error, GlobalState, PlayState, PlayStateResult,
}; };
use client::{self, Client}; use client::{self, Client};
use common::{ use common::{
assets::{load_expect, load_watched, watch}, assets::{load_expect, load_watched},
clock::Clock,
comp, comp,
comp::{ comp::{
ChatMsg, ChatType, InventoryUpdateEvent, Pos, Vel, MAX_MOUNT_RANGE_SQR, ChatMsg, ChatType, InventoryUpdateEvent, Pos, Vel, MAX_MOUNT_RANGE_SQR,
@ -46,6 +46,12 @@ pub struct SessionState {
inputs: comp::ControllerInputs, inputs: comp::ControllerInputs,
selected_block: Block, selected_block: Block,
voxygen_i18n: std::sync::Arc<VoxygenLocalization>, 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). /// Represents an active game session (i.e., the one being played).
@ -59,14 +65,12 @@ impl SessionState {
.camera_mut() .camera_mut()
.set_fov_deg(global_state.settings.graphics.fov); .set_fov_deg(global_state.settings.graphics.fov);
let hud = Hud::new(global_state, &client.borrow()); 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( let voxygen_i18n = load_expect::<VoxygenLocalization>(&i18n_asset_key(
&global_state.settings.language.selected_language, &global_state.settings.language.selected_language,
)); ));
let walk_forward_dir = scene.camera().forward_xy();
let walk_right_dir = scene.camera().right_xy();
Self { Self {
scene, scene,
client, client,
@ -75,8 +79,20 @@ impl SessionState {
hud, hud,
selected_block: Block::new(BlockKind::Normal, Rgb::broadcast(255)), selected_block: Block::new(BlockKind::Normal, Rgb::broadcast(255)),
voxygen_i18n, 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 { impl SessionState {
@ -86,9 +102,6 @@ impl SessionState {
let mut client = self.client.borrow_mut(); let mut client = self.client.borrow_mut();
for event in client.tick(self.inputs.clone(), dt, crate::ecs::sys::add_local_systems)? { 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 { match event {
client::Event::Chat(m) => { client::Event::Chat(m) => {
self.hud.new_message(m); self.hud.new_message(m);
@ -153,12 +166,10 @@ impl SessionState {
} }
impl PlayState for 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. // Trap the cursor.
global_state.window.grab_cursor(true); global_state.window.grab_cursor(true);
// Set up an fps clock.
let mut clock = Clock::start();
self.client.borrow_mut().clear_terrain(); self.client.borrow_mut().clear_terrain();
// Send startup commands to the server // Send startup commands to the server
@ -167,30 +178,28 @@ impl PlayState for SessionState {
self.client.borrow_mut().send_chat(cmd.to_string()); 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();
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;
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 fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult {
let mut current_client_state = self.client.borrow().get_client_state(); self.voxygen_i18n = load_expect::<VoxygenLocalization>(&i18n_asset_key(
while let ClientState::Pending | ClientState::Character = current_client_state { &global_state.settings.language.selected_language,
));
// TODO: can this be a method on the session or are there borrowcheck issues?
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 // Compute camera data
self.scene self.scene
.camera_mut() .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()); let cam_dir: Vec3<f32> = Vec3::from(view_mat.inverted() * -Vec4::unit_z());
@ -278,7 +288,7 @@ impl PlayState for SessionState {
})); }));
// Handle window events. // 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. // Pass all events to the ui first.
if self.hud.handle_event(event.clone(), global_state) { if self.hud.handle_event(event.clone(), global_state) {
continue; continue;
@ -331,7 +341,7 @@ impl PlayState for SessionState {
Event::InputUpdate(GameInput::Respawn, state) Event::InputUpdate(GameInput::Respawn, state)
if state != self.key_state.respawn => 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; self.key_state.respawn = state;
if state { if state {
self.client.borrow_mut().respawn(); self.client.borrow_mut().respawn();
@ -348,7 +358,7 @@ impl PlayState for SessionState {
{ {
self.key_state.toggle_sit = state; self.key_state.toggle_sit = state;
if 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(); self.client.borrow_mut().toggle_sit();
} }
} }
@ -357,31 +367,31 @@ impl PlayState for SessionState {
{ {
self.key_state.toggle_dance = state; self.key_state.toggle_dance = state;
if 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(); self.client.borrow_mut().toggle_dance();
} }
} }
Event::InputUpdate(GameInput::MoveForward, state) => { Event::InputUpdate(GameInput::MoveForward, state) => {
if state && global_state.settings.gameplay.stop_auto_walk_on_input { 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 self.key_state.up = state
}, },
Event::InputUpdate(GameInput::MoveBack, state) => { Event::InputUpdate(GameInput::MoveBack, state) => {
if state && global_state.settings.gameplay.stop_auto_walk_on_input { 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 self.key_state.down = state
}, },
Event::InputUpdate(GameInput::MoveLeft, state) => { Event::InputUpdate(GameInput::MoveLeft, state) => {
if state && global_state.settings.gameplay.stop_auto_walk_on_input { 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 self.key_state.left = state
}, },
Event::InputUpdate(GameInput::MoveRight, state) => { Event::InputUpdate(GameInput::MoveRight, state) => {
if state && global_state.settings.gameplay.stop_auto_walk_on_input { 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 self.key_state.right = state
}, },
@ -509,12 +519,12 @@ impl PlayState for SessionState {
Event::InputUpdate(GameInput::FreeLook, state) => { Event::InputUpdate(GameInput::FreeLook, state) => {
match (global_state.settings.gameplay.free_look_behavior, state) { match (global_state.settings.gameplay.free_look_behavior, state) {
(PressBehavior::Toggle, true) => { (PressBehavior::Toggle, true) => {
free_look = !free_look; self.free_look = !self.free_look;
self.hud.free_look(free_look); self.hud.free_look(self.free_look);
}, },
(PressBehavior::Hold, state) => { (PressBehavior::Hold, state) => {
free_look = state; self.free_look = state;
self.hud.free_look(free_look); self.hud.free_look(self.free_look);
}, },
_ => {}, _ => {},
}; };
@ -522,14 +532,14 @@ impl PlayState for SessionState {
Event::InputUpdate(GameInput::AutoWalk, state) => { Event::InputUpdate(GameInput::AutoWalk, state) => {
match (global_state.settings.gameplay.auto_walk_behavior, state) { match (global_state.settings.gameplay.auto_walk_behavior, state) {
(PressBehavior::Toggle, true) => { (PressBehavior::Toggle, true) => {
auto_walk = !auto_walk; self.auto_walk = !self.auto_walk;
self.key_state.auto_walk = auto_walk; self.key_state.auto_walk = self.auto_walk;
self.hud.auto_walk(auto_walk); self.hud.auto_walk(self.auto_walk);
}, },
(PressBehavior::Hold, state) => { (PressBehavior::Hold, state) => {
auto_walk = state; self.auto_walk = state;
self.key_state.auto_walk = auto_walk; self.key_state.auto_walk = self.auto_walk;
self.hud.auto_walk(auto_walk); self.hud.auto_walk(self.auto_walk);
}, },
_ => {}, _ => {},
} }
@ -567,9 +577,9 @@ impl PlayState for SessionState {
} }
} }
if !free_look { if !self.free_look {
walk_forward_dir = self.scene.camera().forward_xy(); self.walk_forward_dir = self.scene.camera().forward_xy();
walk_right_dir = self.scene.camera().right_xy(); self.walk_right_dir = self.scene.camera().right_xy();
self.inputs.look_dir = Dir::from_unnormalized(cam_dir + aim_dir_offset).unwrap(); 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 => { camera::CameraMode::FirstPerson | camera::CameraMode::ThirdPerson => {
// Move the player character based on their walking direction. // Move the player character based on their walking direction.
// This could be different from the camera direction if free look is enabled. // 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; self.inputs.move_dir =
freefly_vel = Vec3::zero(); self.walk_right_dir * axis_right + self.walk_forward_dir * axis_up;
self.freefly_vel = Vec3::zero();
}, },
camera::CameraMode::Freefly => { camera::CameraMode::Freefly => {
@ -596,27 +607,27 @@ impl PlayState for SessionState {
let right = self.scene.camera().right(); let right = self.scene.camera().right();
let dir = right * axis_right + forward * axis_up; let dir = right * axis_right + forward * axis_up;
let dt = clock.get_last_delta().as_secs_f32(); let dt = global_state.clock.get_last_delta().as_secs_f32();
if freefly_vel.magnitude_squared() > 0.01 { if self.freefly_vel.magnitude_squared() > 0.01 {
let new_vel = let new_vel = self.freefly_vel
freefly_vel - freefly_vel.normalized() * (FREEFLY_DAMPING * dt); - self.freefly_vel.normalized() * (FREEFLY_DAMPING * dt);
if freefly_vel.dot(new_vel) > 0.0 { if self.freefly_vel.dot(new_vel) > 0.0 {
freefly_vel = new_vel; self.freefly_vel = new_vel;
} else { } else {
freefly_vel = Vec3::zero(); self.freefly_vel = Vec3::zero();
} }
} }
if dir.magnitude_squared() > 0.01 { if dir.magnitude_squared() > 0.01 {
freefly_vel += dir * (FREEFLY_ACCEL * dt); self.freefly_vel += dir * (FREEFLY_ACCEL * dt);
if freefly_vel.magnitude() > FREEFLY_MAX_SPEED { if self.freefly_vel.magnitude() > FREEFLY_MAX_SPEED {
freefly_vel = freefly_vel.normalized() * FREEFLY_MAX_SPEED; self.freefly_vel = self.freefly_vel.normalized() * FREEFLY_MAX_SPEED;
} }
} }
let pos = self.scene.camera().get_focus_pos(); let pos = self.scene.camera().get_focus_pos();
self.scene self.scene
.camera_mut() .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 // Do not apply any movement to the player character
self.inputs.move_dir = Vec2::zero(); self.inputs.move_dir = Vec2::zero();
@ -626,16 +637,14 @@ impl PlayState for SessionState {
self.inputs.climb = self.key_state.climb(); self.inputs.climb = self.key_state.climb();
// Runs if either in a multiplayer server or the singleplayer server is unpaused // Runs if either in a multiplayer server or the singleplayer server is unpaused
if global_state.singleplayer.is_none() if !global_state.paused() {
|| !global_state.singleplayer.as_ref().unwrap().is_paused()
{
// Perform an in-game tick. // 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::Continue) => {}, // Do nothing
Ok(TickAction::Disconnect) => return PlayStateResult::Pop, // Go to main menu Ok(TickAction::Disconnect) => return PlayStateResult::Pop, // Go to main menu
Err(err) => { Err(err) => {
global_state.info_message = 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); error!("[session] Failed to tick the scene: {:?}", err);
return PlayStateResult::Pop; 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 // Recompute dependents just in case some input modified the camera
self.scene self.scene
.camera_mut() .camera_mut()
.compute_dependents(&*self.client.borrow().state().terrain()); .compute_dependents(&*self.client.borrow().state().terrain());
// Extract HUD events ensuring the client borrow gets dropped. // Extract HUD events ensuring the client borrow gets dropped.
let mut hud_events = self.hud.maintain( let mut hud_events = self.hud.maintain(
&self.client.borrow(), &self.client.borrow(),
global_state, global_state,
DebugInfo { DebugInfo {
tps: clock.get_tps(), tps: global_state.clock.get_tps(),
ping_ms: self.client.borrow().get_ping_ms_rolling_avg(), ping_ms: self.client.borrow().get_ping_ms_rolling_avg(),
coordinates: self coordinates: self
.client .client
@ -687,7 +694,7 @@ impl PlayState for SessionState {
num_figures_visible: self.scene.figure_mgr().figure_count_visible() as u32, num_figures_visible: self.scene.figure_mgr().figure_count_visible() as u32,
}, },
&self.scene.camera(), &self.scene.camera(),
clock.get_last_delta(), global_state.clock.get_last_delta(),
HudInfo { HudInfo {
is_aiming, is_aiming,
is_first_person: matches!( is_first_person: matches!(
@ -698,8 +705,8 @@ impl PlayState for SessionState {
); );
// Look for changes in the localization files // Look for changes in the localization files
if localization_watcher.reloaded() { if global_state.localization_watcher.reloaded() {
hud_events.push(HudEvent::ChangeLanguage(localized_strings.metadata.clone())); hud_events.push(HudEvent::ChangeLanguage(self.voxygen_i18n.metadata.clone()));
} }
// Maintain the UI. // Maintain the UI.
@ -916,13 +923,13 @@ impl PlayState for SessionState {
HudEvent::ChangeLanguage(new_language) => { HudEvent::ChangeLanguage(new_language) => {
global_state.settings.language.selected_language = global_state.settings.language.selected_language =
new_language.language_identifier; new_language.language_identifier;
localized_strings = load_watched::<VoxygenLocalization>( self.voxygen_i18n = load_watched::<VoxygenLocalization>(
&i18n_asset_key(&global_state.settings.language.selected_language), &i18n_asset_key(&global_state.settings.language.selected_language),
&mut localization_watcher, &mut global_state.localization_watcher,
) )
.unwrap(); .unwrap();
localized_strings.log_missing_entries(); self.voxygen_i18n.log_missing_entries();
self.hud.update_language(localized_strings.clone()); self.hud.update_language(self.voxygen_i18n.clone());
}, },
HudEvent::ToggleFullscreen => { HudEvent::ToggleFullscreen => {
global_state global_state
@ -978,20 +985,53 @@ impl PlayState for SessionState {
}; };
// Runs if either in a multiplayer server or the singleplayer server is unpaused // Runs if either in a multiplayer server or the singleplayer server is unpaused
if global_state.singleplayer.is_none() if !global_state.paused() {
|| !global_state.singleplayer.as_ref().unwrap().is_paused()
{
self.scene.maintain( self.scene.maintain(
global_state.window.renderer_mut(), global_state.window.renderer_mut(),
&mut global_state.audio, &mut global_state.audio,
&scene_data, &scene_data,
); );
} }
}
let renderer = global_state.window.renderer_mut(); // Clean things up after the tick.
// Clear the screen self.cleanup();
renderer.clear();
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
}
}
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 // 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( self.scene.render(
renderer, renderer,
client.state(), client.state(),
@ -999,38 +1039,8 @@ impl PlayState for SessionState {
client.get_tick(), client.get_tick(),
&scene_data, &scene_data,
); );
}
// Draw the UI to the screen // Draw the UI to the screen
self.hud.render(renderer, self.scene.globals()); 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(
global_state,
self.client.clone(),
)));
}
PlayStateResult::Pop
}
fn name(&self) -> &'static str { "Session" }
} }

View File

@ -6,11 +6,11 @@ use crate::{
window::{GameInput, KeyMouse}, window::{GameInput, KeyMouse},
}; };
use directories_next::{ProjectDirs, UserDirs}; use directories_next::{ProjectDirs, UserDirs};
use glutin::{MouseButton, VirtualKeyCode};
use hashbrown::{HashMap, HashSet}; use hashbrown::{HashMap, HashSet};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::{fs, io::prelude::*, path::PathBuf}; use std::{fs, io::prelude::*, path::PathBuf};
use tracing::warn; use tracing::warn;
use winit::event::{MouseButton, VirtualKeyCode};
// ControlSetting-like struct used by Serde, to handle not serializing/building // ControlSetting-like struct used by Serde, to handle not serializing/building
// post-deserializing the inverse_keybindings hashmap // post-deserializing the inverse_keybindings hashmap

View File

@ -1,26 +1,30 @@
use conrod_core::{event::Input, input::Button}; use conrod_core::{event::Input, input::Button};
use vek::*; use vek::*;
#[derive(Clone)] #[derive(Clone, Debug)]
pub struct Event(pub Input); pub struct Event(pub Input);
impl Event { impl Event {
pub fn try_from( pub fn try_from(
event: glutin::Event, event: &winit::event::Event<()>,
window: &glutin::ContextWrapper<glutin::PossiblyCurrent, winit::Window>, window: &glutin::ContextWrapper<glutin::PossiblyCurrent, winit::window::Window>,
) -> Option<Self> { ) -> Option<Self> {
use conrod_winit::*; use conrod_winit::*;
// A wrapper around the winit window that allows us to implement the trait // A wrapper around the winit window that allows us to implement the trait
// necessary for enabling the winit <-> conrod conversion functions. // 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 // Implement the `WinitWindow` trait for `WindowRef` to allow for generating
// compatible conversion functions. // compatible conversion functions.
impl<'a> conrod_winit::WinitWindow for WindowRef<'a> { impl<'a> conrod_winit::WinitWindow for WindowRef<'a> {
fn get_inner_size(&self) -> Option<(u32, u32)> { 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) convert_event!(event, &WindowRef(window.window())).map(Self)
} }

View File

@ -19,7 +19,7 @@ pub enum ScaleMode {
pub struct Scale { pub struct Scale {
mode: ScaleMode, mode: ScaleMode,
// Current dpi factor // Current dpi factor
dpi_factor: f64, scale_factor: f64,
// Current logical window size // Current logical window size
window_dims: Vec2<f64>, window_dims: Vec2<f64>,
} }
@ -27,10 +27,10 @@ pub struct Scale {
impl Scale { impl Scale {
pub fn new(window: &Window, mode: ScaleMode) -> Self { pub fn new(window: &Window, mode: ScaleMode) -> Self {
let window_dims = window.logical_size(); 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 { Scale {
mode, mode,
dpi_factor, scale_factor,
window_dims, window_dims,
} }
} }
@ -54,7 +54,7 @@ impl Scale {
// coordinates. // coordinates.
pub fn scale_factor_logical(&self) -> f64 { pub fn scale_factor_logical(&self) -> f64 {
match self.mode { match self.mode {
ScaleMode::Absolute(scale) => scale / self.dpi_factor, ScaleMode::Absolute(scale) => scale / self.scale_factor,
ScaleMode::DpiFactor => 1.0, ScaleMode::DpiFactor => 1.0,
ScaleMode::RelativeToWindow(dims) => { ScaleMode::RelativeToWindow(dims) => {
(self.window_dims.x / dims.x).min(self.window_dims.y / dims.y) (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 // Calculate factor to transform between physical coordinates and our scaled
// coordinates. // 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) { 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; self.window_dims = new_dims;
} }

View File

@ -4,10 +4,10 @@ use crate::{
settings::{ControlSettings, Settings}, settings::{ControlSettings, Settings},
ui, Error, ui, Error,
}; };
use crossbeam::channel;
use gilrs::{EventType, Gilrs}; use gilrs::{EventType, Gilrs};
use hashbrown::HashMap; use hashbrown::HashMap;
use old_school_gfx_glutin_ext::{ContextBuilderExt, WindowInitExt, WindowUpdateExt};
use crossbeam::channel;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::fmt; use std::fmt;
use tracing::{error, info, warn}; use tracing::{error, info, warn};
@ -241,7 +241,7 @@ pub enum AnalogGameInput {
} }
/// Represents an incoming event from the window. /// Represents an incoming event from the window.
#[derive(Clone)] #[derive(Clone, Debug)]
pub enum Event { pub enum Event {
/// The window has been requested to close. /// The window has been requested to close.
Close, Close,
@ -280,19 +280,20 @@ pub enum Event {
ScreenshotMessage(String), ScreenshotMessage(String),
} }
pub type MouseButton = winit::MouseButton; pub type MouseButton = winit::event::MouseButton;
pub type PressState = winit::ElementState; pub type PressState = winit::event::ElementState;
pub type EventLoop = winit::event_loop::EventLoop<()>;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub enum KeyMouse { pub enum KeyMouse {
Key(glutin::VirtualKeyCode), Key(winit::event::VirtualKeyCode),
Mouse(glutin::MouseButton), Mouse(winit::event::MouseButton),
} }
impl fmt::Display for KeyMouse { impl fmt::Display for KeyMouse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::KeyMouse::*; use self::KeyMouse::*;
use glutin::{MouseButton, VirtualKeyCode::*}; use winit::event::{MouseButton, VirtualKeyCode::*};
write!(f, "{}", match self { write!(f, "{}", match self {
Key(Key1) => "1", Key(Key1) => "1",
Key(Key2) => "2", Key(Key2) => "2",
@ -466,23 +467,23 @@ impl fmt::Display for KeyMouse {
} }
pub struct Window { pub struct Window {
events_loop: glutin::EventsLoop,
renderer: Renderer, renderer: Renderer,
window: glutin::ContextWrapper<glutin::PossiblyCurrent, winit::Window>, window: glutin::ContextWrapper<glutin::PossiblyCurrent, winit::window::Window>,
cursor_grabbed: bool, cursor_grabbed: bool,
pub pan_sensitivity: u32, pub pan_sensitivity: u32,
pub zoom_sensitivity: u32, pub zoom_sensitivity: u32,
pub zoom_inversion: bool, pub zoom_inversion: bool,
pub mouse_y_inversion: bool, pub mouse_y_inversion: bool,
fullscreen: bool, fullscreen: bool,
modifiers: winit::event::ModifiersState,
needs_refresh_resize: bool, needs_refresh_resize: bool,
keypress_map: HashMap<GameInput, glutin::ElementState>, keypress_map: HashMap<GameInput, winit::event::ElementState>,
pub remapping_keybindings: Option<GameInput>, pub remapping_keybindings: Option<GameInput>,
supplement_events: Vec<Event>, events: Vec<Event>,
focused: bool, focused: bool,
gilrs: Option<Gilrs>, gilrs: Option<Gilrs>,
controller_settings: ControllerSettings, controller_settings: ControllerSettings,
cursor_position: winit::dpi::LogicalPosition, cursor_position: winit::dpi::PhysicalPosition<f64>,
mouse_emulation_vec: Vec2<f32>, mouse_emulation_vec: Vec2<f32>,
// Currently used to send and receive screenshot result messages // Currently used to send and receive screenshot result messages
message_sender: channel::Sender<String>, message_sender: channel::Sender<String>,
@ -490,30 +491,32 @@ pub struct Window {
} }
impl Window { impl Window {
pub fn new(settings: &Settings) -> Result<Window, Error> { pub fn new(settings: &Settings) -> Result<(Window, EventLoop), Error> {
let events_loop = glutin::EventsLoop::new(); let event_loop = EventLoop::new();
let size = settings.graphics.window_size; let size = settings.graphics.window_size;
let win_builder = glutin::WindowBuilder::new() let win_builder = winit::window::WindowBuilder::new()
.with_title("Veloren") .with_title("Veloren")
.with_dimensions(glutin::dpi::LogicalSize::new( .with_inner_size(winit::dpi::LogicalSize::new(size[0] as f64, size[1] as f64))
size[0] as f64,
size[1] as f64,
))
.with_maximized(true); .with_maximized(true);
let ctx_builder = glutin::ContextBuilder::new() // Avoid cpal / winit OleInitialize conflict
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2))) // See: https://github.com/rust-windowing/winit/pull/1524
.with_vsync(false); #[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) = let (window, device, factory, win_color_view, win_depth_view) =
gfx_window_glutin::init::<WinColorFmt, WinDepthFmt>( glutin::ContextBuilder::new()
win_builder, .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
ctx_builder, .with_vsync(false)
&events_loop, .with_gfx_color_depth::<WinColorFmt, WinDepthFmt>()
) .build_windowed(win_builder, &event_loop)
.map_err(|err| Error::BackendError(Box::new(err)))?; .map_err(|err| Error::BackendError(Box::new(err)))?
.init_gfx::<WinColorFmt, WinDepthFmt>();
let vendor = device.get_info().platform_name.vendor; let vendor = device.get_info().platform_name.vendor;
let renderer = device.get_info().platform_name.renderer; let renderer = device.get_info().platform_name.renderer;
@ -559,7 +562,6 @@ impl Window {
) = channel::unbounded::<String>(); ) = channel::unbounded::<String>();
let mut this = Self { let mut this = Self {
events_loop,
renderer: Renderer::new( renderer: Renderer::new(
device, device,
factory, factory,
@ -576,14 +578,15 @@ impl Window {
zoom_inversion: settings.gameplay.zoom_inversion, zoom_inversion: settings.gameplay.zoom_inversion,
mouse_y_inversion: settings.gameplay.mouse_y_inversion, mouse_y_inversion: settings.gameplay.mouse_y_inversion,
fullscreen: false, fullscreen: false,
modifiers: Default::default(),
needs_refresh_resize: false, needs_refresh_resize: false,
keypress_map, keypress_map,
remapping_keybindings: None, remapping_keybindings: None,
supplement_events: vec![], events: Vec::new(),
focused: true, focused: true,
gilrs, gilrs,
controller_settings, 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(), mouse_emulation_vec: Vec2::zero(),
// Currently used to send and receive screenshot result messages // Currently used to send and receive screenshot result messages
message_sender, message_sender,
@ -592,195 +595,30 @@ impl Window {
this.fullscreen(settings.graphics.fullscreen); 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(&self) -> &Renderer { &self.renderer }
pub fn renderer_mut(&mut self) -> &mut Renderer { &mut 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) -> Vec<Event> {
pub fn fetch_events(&mut self, settings: &mut Settings) -> Vec<Event> {
let mut events = vec![];
events.append(&mut self.supplement_events);
// Refresh ui size (used when changing playstates) // Refresh ui size (used when changing playstates)
if self.needs_refresh_resize { 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; self.needs_refresh_resize = false;
} }
// Receive any messages sent through the message channel // Receive any messages sent through the message channel
self.message_receiver for message in self.message_receiver.try_iter() {
.try_iter() self.events.push(Event::ScreenshotMessage(message))
.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);
} }
if let Some(gilrs) = &mut self.gilrs { if let Some(gilrs) = &mut self.gilrs {
@ -808,7 +646,7 @@ impl Window {
| EventType::ButtonRepeated(button, code) => { | EventType::ButtonRepeated(button, code) => {
handle_buttons( handle_buttons(
&self.controller_settings, &self.controller_settings,
&mut events, &mut self.events,
&Button::from((button, code)), &Button::from((button, code)),
true, true,
); );
@ -816,7 +654,7 @@ impl Window {
EventType::ButtonReleased(button, code) => { EventType::ButtonReleased(button, code) => {
handle_buttons( handle_buttons(
&self.controller_settings, &self.controller_settings,
&mut events, &mut self.events,
&Button::from((button, code)), &Button::from((button, code)),
false, false,
); );
@ -843,13 +681,14 @@ impl Window {
}, },
EventType::AxisChanged(axis, value, code) => { EventType::AxisChanged(axis, value, code) => {
let value = match self let value = if self
.controller_settings .controller_settings
.inverted_axes .inverted_axes
.contains(&Axis::from((axis, code))) .contains(&Axis::from((axis, code)))
{ {
true => value * -1.0, -value
false => value, } else {
value
}; };
let value = self let value = self
@ -865,17 +704,17 @@ impl Window {
for action in actions { for action in actions {
match *action { match *action {
AxisGameAction::MovementX => { AxisGameAction::MovementX => {
events.push(Event::AnalogGameInput( self.events.push(Event::AnalogGameInput(
AnalogGameInput::MovementX(value), AnalogGameInput::MovementX(value),
)); ));
}, },
AxisGameAction::MovementY => { AxisGameAction::MovementY => {
events.push(Event::AnalogGameInput( self.events.push(Event::AnalogGameInput(
AnalogGameInput::MovementY(value), AnalogGameInput::MovementY(value),
)); ));
}, },
AxisGameAction::CameraX => { AxisGameAction::CameraX => {
events.push(Event::AnalogGameInput( self.events.push(Event::AnalogGameInput(
AnalogGameInput::CameraX( AnalogGameInput::CameraX(
value value
* self.controller_settings.pan_sensitivity * self.controller_settings.pan_sensitivity
@ -885,7 +724,7 @@ impl Window {
)); ));
}, },
AxisGameAction::CameraY => { AxisGameAction::CameraY => {
events.push(Event::AnalogGameInput( self.events.push(Event::AnalogGameInput(
AnalogGameInput::CameraY( AnalogGameInput::CameraY(
value value
* self.controller_settings.pan_sensitivity * self.controller_settings.pan_sensitivity
@ -906,22 +745,22 @@ impl Window {
for action in actions { for action in actions {
match *action { match *action {
AxisMenuAction::MoveX => { AxisMenuAction::MoveX => {
events.push(Event::AnalogMenuInput( self.events.push(Event::AnalogMenuInput(
AnalogMenuInput::MoveX(value), AnalogMenuInput::MoveX(value),
)); ));
}, },
AxisMenuAction::MoveY => { AxisMenuAction::MoveY => {
events.push(Event::AnalogMenuInput( self.events.push(Event::AnalogMenuInput(
AnalogMenuInput::MoveY(value), AnalogMenuInput::MoveY(value),
)); ));
}, },
AxisMenuAction::ScrollX => { AxisMenuAction::ScrollX => {
events.push(Event::AnalogMenuInput( self.events.push(Event::AnalogMenuInput(
AnalogMenuInput::ScrollX(value), AnalogMenuInput::ScrollX(value),
)); ));
}, },
AxisMenuAction::ScrollY => { AxisMenuAction::ScrollY => {
events.push(Event::AnalogMenuInput( self.events.push(Event::AnalogMenuInput(
AnalogMenuInput::ScrollY(value), 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 // Mouse emulation for the menus, to be removed when a proper menu navigation
// system is available // system is available
if !self.cursor_grabbed { if !self.cursor_grabbed {
@ -952,13 +792,9 @@ impl Window {
self.mouse_emulation_vec.y = d * -1.0; self.mouse_emulation_vec.y = d * -1.0;
None None
}, },
_ => { input => Some(Event::AnalogMenuInput(input)),
let event = Event::AnalogMenuInput(input);
Some(event)
}, },
}, Event::MenuInput(MenuInput::Apply, state) => Some(match state {
Event::MenuInput(input, state) => match input {
MenuInput::Apply => Some(match state {
true => Event::Ui(ui::Event(conrod_core::event::Input::Press( true => Event::Ui(ui::Event(conrod_core::event::Input::Press(
conrod_core::input::Button::Mouse( conrod_core::input::Button::Mouse(
conrod_core::input::state::mouse::Button::Left, conrod_core::input::state::mouse::Button::Left,
@ -971,27 +807,216 @@ impl Window {
))), ))),
}), }),
_ => Some(event), _ => Some(event),
},
_ => Some(event),
}) })
.collect(); .collect();
let sensitivity = self.controller_settings.mouse_emulation_sensitivity; let sensitivity = self.controller_settings.mouse_emulation_sensitivity;
if self.mouse_emulation_vec != Vec2::zero() { // TODO: make this independent of framerate
self.offset_cursor(self.mouse_emulation_vec * sensitivity as f32) // TODO: consider multiplying by scale factor
.unwrap_or(()); self.offset_cursor(self.mouse_emulation_vec * sensitivity as f32);
}
} }
events 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 /// Moves cursor by an offset
pub fn offset_cursor(&self, d: Vec2<f32>) -> Result<(), String> { pub fn offset_cursor(&self, d: Vec2<f32>) {
if d != Vec2::zero() {
if let Err(err) =
self.window self.window
.window() .window()
.set_cursor_position(winit::dpi::LogicalPosition::new( .set_cursor_position(winit::dpi::LogicalPosition::new(
d.x as f64 + self.cursor_position.x, d.x as f64 + self.cursor_position.x,
d.y as f64 + self.cursor_position.y, d.y as f64 + self.cursor_position.y,
)) ))
{
error!("Error setting cursor position: {:?}", err);
}
}
} }
pub fn swap_buffers(&self) -> Result<(), Error> { pub fn swap_buffers(&self) -> Result<(), Error> {
@ -1004,8 +1029,8 @@ impl Window {
pub fn grab_cursor(&mut self, grab: bool) { pub fn grab_cursor(&mut self, grab: bool) {
self.cursor_grabbed = grab; self.cursor_grabbed = grab;
self.window.window().hide_cursor(grab); self.window.window().set_cursor_visible(!grab);
let _ = self.window.window().grab_cursor(grab); let _ = self.window.window().set_cursor_grab(grab);
} }
pub fn toggle_fullscreen(&mut self, settings: &mut Settings) { pub fn toggle_fullscreen(&mut self, settings: &mut Settings) {
@ -1020,7 +1045,13 @@ impl Window {
let window = self.window.window(); let window = self.window.window();
self.fullscreen = fullscreen; self.fullscreen = fullscreen;
if 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 { } else {
window.set_fullscreen(None); window.set_fullscreen(None);
} }
@ -1033,8 +1064,8 @@ impl Window {
let (w, h) = self let (w, h) = self
.window .window
.window() .window()
.get_inner_size() .inner_size()
.unwrap_or(glutin::dpi::LogicalSize::new(0.0, 0.0)) .to_logical::<f64>(self.window.window().scale_factor())
.into(); .into();
Vec2::new(w, h) 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) { pub fn take_screenshot(&mut self, settings: &Settings) {
match self.renderer.create_screenshot() { match self.renderer.create_screenshot() {
@ -1086,15 +1117,20 @@ impl Window {
} }
} }
fn is_pressed(map: &mut HashMap<GameInput, glutin::ElementState>, input: GameInput) -> bool { fn is_pressed(
*(map.entry(input).or_insert(glutin::ElementState::Released)) map: &mut HashMap<GameInput, winit::event::ElementState>,
== glutin::ElementState::Pressed input: GameInput,
) -> bool {
*(map
.entry(input)
.or_insert(winit::event::ElementState::Released))
== winit::event::ElementState::Pressed
} }
fn set_pressed( fn set_pressed(
map: &mut HashMap<GameInput, glutin::ElementState>, map: &mut HashMap<GameInput, winit::event::ElementState>,
input: GameInput, input: GameInput,
state: glutin::ElementState, state: winit::event::ElementState,
) { ) {
map.insert(input, state); map.insert(input, state);
} }
@ -1109,6 +1145,7 @@ impl Window {
remapping: &mut Option<GameInput>, remapping: &mut Option<GameInput>,
) -> Option<impl Iterator<Item = &'a GameInput>> { ) -> Option<impl Iterator<Item = &'a GameInput>> {
match *remapping { match *remapping {
// TODO: save settings
Some(game_input) => { Some(game_input) => {
controls.modify_binding(game_input, key_mouse); controls.modify_binding(game_input, key_mouse);
*remapping = None; *remapping = None;