mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added Controller support
This commit is contained in:
parent
5598fe7166
commit
8838682f0b
@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- weapon control system
|
||||
- Game pauses when in singleplayer and pause menu
|
||||
- Added authentication system (to play on the official server register on https://account.veloren.net)
|
||||
- Added gamepad/controller support
|
||||
|
||||
### Changed
|
||||
|
||||
|
249
Cargo.lock
generated
249
Cargo.lock
generated
@ -160,7 +160,7 @@ source = "git+https://gitlab.com/veloren/auth.git?rev=65571ade0d954a0e0bd995fdb3
|
||||
dependencies = [
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"uuid",
|
||||
"uuid 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -174,7 +174,7 @@ dependencies = [
|
||||
"reqwest",
|
||||
"rust-argon2 0.6.1",
|
||||
"serde_json",
|
||||
"uuid",
|
||||
"uuid 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -203,14 +203,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "backtrace-sys"
|
||||
version = "0.1.33"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e17b52e737c40a7d75abca20b29a19a0eb7ba9fc72c5a72dd282a0a3c2c0dc35"
|
||||
checksum = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base-x"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.9.3"
|
||||
@ -248,15 +254,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.51.1"
|
||||
version = "0.53.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebd71393f1ec0509b553aa012b9b58e81dadbdff7130bd3b8cba576e69b32f75"
|
||||
checksum = "6bb26d6a69a335b8cb0e7c7e9775cd5666611dc50a37177c3f2cedcfc040e8c8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"cfg-if",
|
||||
"clang-sys",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"peeking_take_while",
|
||||
"proc-macro2 1.0.9",
|
||||
"quote 1.0.3",
|
||||
@ -360,15 +367,6 @@ version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1"
|
||||
|
||||
[[package]]
|
||||
name = "c2-chacha"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "c_vec"
|
||||
version = "1.3.3"
|
||||
@ -419,11 +417,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.3.6"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fce5b5fb86b0c57c20c834c1b412fd09c77c8a59b9473f86272709e78874cd1d"
|
||||
checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
|
||||
dependencies = [
|
||||
"nom",
|
||||
"nom 5.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -471,9 +469,9 @@ checksum = "498d20a7aaf62625b9bf26e637cf7736417cde1d0c99f1d04d1170229a85cf87"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "0.28.1"
|
||||
version = "0.29.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81de550971c976f176130da4b2978d3b524eaa0fd9ac31f3ceb5ae1231fb4853"
|
||||
checksum = "f92986241798376849e1a007827041fed9bb36195822c2049d18e174420e0534"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
@ -614,9 +612,9 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "copypasta"
|
||||
version = "0.6.2"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1fcbfb17a41091ba8bad1233d0178fda058968a71998dde3f11189f0b4aa9da"
|
||||
checksum = "865e9675691e2a7dfc806b16ef2dd5dd536e26ea9b8046519767d79be03aeb6a"
|
||||
dependencies = [
|
||||
"clipboard-win",
|
||||
"objc",
|
||||
@ -683,9 +681,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "coreaudio-sys"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8f5954c1c7ccb55340443e8b29fca24013545a5e7d72c1ca7db4fc02b982ce"
|
||||
checksum = "e81f1c165c33ffab90a03077ac3b03462b34d5947145dfa48102e063d581502c"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
]
|
||||
@ -703,7 +701,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"num-traits 0.2.11",
|
||||
"stdweb",
|
||||
"stdweb 0.1.3",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
@ -917,9 +915,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "942ca430eef7a3806595a6737bc388bf51adb888d3fc0dd1b50f1c170167ee3a"
|
||||
checksum = "3c6d883546668a3e2011b6a716a7330b82eabb0151b138217f632c8243e17135"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
@ -965,6 +963,12 @@ dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "discard"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||
|
||||
[[package]]
|
||||
name = "dispatch"
|
||||
version = "0.1.4"
|
||||
@ -989,7 +993,7 @@ dependencies = [
|
||||
"byteorder 1.3.4",
|
||||
"lazy_static",
|
||||
"log 0.4.8",
|
||||
"nom",
|
||||
"nom 4.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1400,6 +1404,40 @@ dependencies = [
|
||||
"lzw",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gilrs"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "122bb249f904e5f4ac73fc514b9b2ce6cce3af511f5df00ffc8000e47de6b290"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"gilrs-core",
|
||||
"log 0.4.8",
|
||||
"serde",
|
||||
"stdweb 0.4.20",
|
||||
"uuid 0.8.1",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gilrs-core"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bdd4ea2d919ecb594362fa26b0f172729b9ee9b95e407fbad95e0a49cadc143"
|
||||
dependencies = [
|
||||
"core-foundation 0.6.4",
|
||||
"io-kit-sys",
|
||||
"libc",
|
||||
"libudev-sys",
|
||||
"log 0.4.8",
|
||||
"nix 0.15.0",
|
||||
"rusty-xinput",
|
||||
"stdweb 0.4.20",
|
||||
"uuid 0.8.1",
|
||||
"vec_map",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gio"
|
||||
version = "0.4.1"
|
||||
@ -1882,6 +1920,16 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c346c299e3fe8ef94dc10c2c0253d858a69aac1245157a3bf4125915d528caf"
|
||||
|
||||
[[package]]
|
||||
name = "io-kit-sys"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f21dcc74995dd4cd090b147e79789f8d65959cbfb5f0b118002db869ea3bd0a0"
|
||||
dependencies = [
|
||||
"core-foundation-sys 0.6.2",
|
||||
"mach",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.4"
|
||||
@ -2017,6 +2065,16 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libudev-sys"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.0.25"
|
||||
@ -2087,6 +2145,15 @@ version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
|
||||
|
||||
[[package]]
|
||||
name = "mach"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
@ -2287,6 +2354,19 @@ dependencies = [
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.14"
|
||||
@ -2312,6 +2392,16 @@ dependencies = [
|
||||
"version_check 0.1.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "5.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b471253da97532da4b61552249c521e01e736071f71c1a4f7ebbfbf0a06aad6"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"version_check 0.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "5.0.0-pre.2"
|
||||
@ -2977,7 +3067,7 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
"rand_chacha 0.2.1",
|
||||
"rand_chacha 0.2.2",
|
||||
"rand_core 0.5.1",
|
||||
"rand_hc 0.2.0",
|
||||
"rand_pcg 0.2.1",
|
||||
@ -2995,11 +3085,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"c2-chacha",
|
||||
"ppv-lite86",
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
@ -3403,6 +3493,17 @@ dependencies = [
|
||||
"stb_truetype",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusty-xinput"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2aa654bc32eb9ca14cce1a084abc9dfe43949a4547c35269a094c39272db3bb"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log 0.4.8",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.2"
|
||||
@ -3660,7 +3761,7 @@ dependencies = [
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
"memmap",
|
||||
"nix",
|
||||
"nix 0.14.1",
|
||||
"wayland-client 0.21.13",
|
||||
"wayland-commons 0.21.13",
|
||||
"wayland-protocols 0.21.13",
|
||||
@ -3677,18 +3778,18 @@ dependencies = [
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
"memmap",
|
||||
"nix",
|
||||
"nix 0.14.1",
|
||||
"wayland-client 0.23.6",
|
||||
"wayland-protocols 0.23.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smithay-clipboard"
|
||||
version = "0.3.7"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a59486e68b5596f664deedf01c46297f4af60379adae20175357a814d40f69e"
|
||||
checksum = "917e8ec7f535cd1a6cbf749c8866c24d67c548a80ac48c8e88a182eab5c07bd1"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"nix 0.14.1",
|
||||
"smithay-client-toolkit 0.6.6",
|
||||
]
|
||||
|
||||
@ -3751,6 +3852,57 @@ version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e"
|
||||
|
||||
[[package]]
|
||||
name = "stdweb"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
|
||||
dependencies = [
|
||||
"discard",
|
||||
"rustc_version",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"stdweb-derive",
|
||||
"stdweb-internal-macros",
|
||||
"stdweb-internal-runtime",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-derive"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.9",
|
||||
"quote 1.0.3",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 1.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-internal-macros"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
|
||||
dependencies = [
|
||||
"base-x",
|
||||
"proc-macro2 1.0.9",
|
||||
"quote 1.0.3",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"sha1",
|
||||
"syn 1.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-internal-runtime"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
|
||||
|
||||
[[package]]
|
||||
name = "sum_type"
|
||||
version = "0.2.0"
|
||||
@ -4090,6 +4242,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
|
||||
|
||||
[[package]]
|
||||
name = "uvth"
|
||||
version = "3.1.1"
|
||||
@ -4107,6 +4265,12 @@ version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
|
||||
[[package]]
|
||||
name = "vek"
|
||||
version = "0.9.12"
|
||||
@ -4239,6 +4403,7 @@ dependencies = [
|
||||
"gfx",
|
||||
"gfx_device_gl",
|
||||
"gfx_window_glutin",
|
||||
"gilrs",
|
||||
"git2",
|
||||
"glsl-include",
|
||||
"glutin",
|
||||
@ -4285,7 +4450,7 @@ dependencies = [
|
||||
"packed_simd",
|
||||
"pretty_env_logger",
|
||||
"rand 0.7.3",
|
||||
"rand_chacha 0.2.1",
|
||||
"rand_chacha 0.2.2",
|
||||
"rayon",
|
||||
"ron",
|
||||
"roots",
|
||||
@ -4417,7 +4582,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"downcast-rs",
|
||||
"libc",
|
||||
"nix",
|
||||
"nix 0.14.1",
|
||||
"wayland-commons 0.21.13",
|
||||
"wayland-scanner 0.21.13",
|
||||
"wayland-sys 0.21.13",
|
||||
@ -4432,7 +4597,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"downcast-rs",
|
||||
"libc",
|
||||
"nix",
|
||||
"nix 0.14.1",
|
||||
"wayland-commons 0.23.6",
|
||||
"wayland-scanner 0.23.6",
|
||||
"wayland-sys 0.23.6",
|
||||
@ -4444,7 +4609,7 @@ version = "0.21.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c08896768b667e1df195d88a62a53a2d1351a1ed96188be79c196b35bb32ec"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"nix 0.14.1",
|
||||
"wayland-sys 0.21.13",
|
||||
]
|
||||
|
||||
@ -4454,7 +4619,7 @@ version = "0.23.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"nix 0.14.1",
|
||||
"wayland-sys 0.23.6",
|
||||
]
|
||||
|
||||
|
@ -35,6 +35,9 @@ specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git" }
|
||||
# Mathematics
|
||||
vek = { version = "0.9.9", features = ["serde"] }
|
||||
|
||||
# Controller
|
||||
gilrs = { version = "0.7", features = ["serde"] }
|
||||
|
||||
# Singleplayer
|
||||
server = { package = "veloren-server", path = "../server", optional = true }
|
||||
|
||||
|
329
voxygen/src/controller.rs
Normal file
329
voxygen/src/controller.rs
Normal file
@ -0,0 +1,329 @@
|
||||
//! Module containing controller-specific abstractions allowing complex
|
||||
//! keybindings
|
||||
|
||||
use crate::window::{GameInput, MenuInput};
|
||||
use gilrs::{ev::Code as GilCode, Axis as GilAxis, Button as GilButton};
|
||||
use hashbrown::HashMap;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
/// Contains all controller related settings and keymaps
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ControllerSettings {
|
||||
pub game_button_map: HashMap<Button, Vec<GameInput>>,
|
||||
pub menu_button_map: HashMap<Button, Vec<MenuInput>>,
|
||||
pub game_analog_button_map: HashMap<AnalogButton, Vec<AnalogButtonGameAction>>,
|
||||
pub menu_analog_button_map: HashMap<AnalogButton, Vec<AnalogButtonMenuAction>>,
|
||||
pub game_axis_map: HashMap<Axis, Vec<AxisGameAction>>,
|
||||
pub menu_axis_map: HashMap<Axis, Vec<AxisMenuAction>>,
|
||||
pub pan_sensitivity: u32,
|
||||
pub axis_deadzones: HashMap<Axis, f32>,
|
||||
pub button_deadzones: HashMap<AnalogButton, f32>,
|
||||
pub mouse_emulation_sensitivity: u32,
|
||||
pub inverted_axes: Vec<Axis>,
|
||||
}
|
||||
|
||||
impl ControllerSettings {
|
||||
pub fn apply_axis_deadzone(&self, k: &Axis, input: f32) -> f32 {
|
||||
let threshold = *self.axis_deadzones.get(k).unwrap_or(&0.2);
|
||||
|
||||
// This could be one comparison per handled event faster if threshold was
|
||||
// guaranteed to fall into <0, 1) range
|
||||
let input_abs = input.abs();
|
||||
if input_abs <= threshold || threshold >= 1.0 {
|
||||
0.0
|
||||
} else if threshold <= 0.0 {
|
||||
input
|
||||
} else {
|
||||
(input_abs - threshold) / (1.0 - threshold) * input.signum()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_button_deadzone(&self, k: &AnalogButton, input: f32) -> f32 {
|
||||
let threshold = *self.button_deadzones.get(k).unwrap_or(&0.2);
|
||||
|
||||
// This could be one comparison per handled event faster if threshold was
|
||||
// guaranteed to fall into <0, 1) range
|
||||
if input <= threshold || threshold >= 1.0 {
|
||||
0.0
|
||||
} else if threshold <= 0.0 {
|
||||
input
|
||||
} else {
|
||||
(input - threshold) / (1.0 - threshold)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&crate::settings::GamepadSettings> for ControllerSettings {
|
||||
fn from(settings: &crate::settings::GamepadSettings) -> Self {
|
||||
Self {
|
||||
game_button_map: {
|
||||
let mut map: HashMap<_, Vec<_>> = HashMap::new();
|
||||
map.entry(settings.game_buttons.primary)
|
||||
.or_default()
|
||||
.push(GameInput::Primary);
|
||||
map.entry(settings.game_buttons.secondary)
|
||||
.or_default()
|
||||
.push(GameInput::Secondary);
|
||||
map.entry(settings.game_buttons.toggle_cursor)
|
||||
.or_default()
|
||||
.push(GameInput::ToggleCursor);
|
||||
map.entry(settings.game_buttons.escape)
|
||||
.or_default()
|
||||
.push(GameInput::Escape);
|
||||
map.entry(settings.game_buttons.enter)
|
||||
.or_default()
|
||||
.push(GameInput::Enter);
|
||||
map.entry(settings.game_buttons.command)
|
||||
.or_default()
|
||||
.push(GameInput::Command);
|
||||
map.entry(settings.game_buttons.move_forward)
|
||||
.or_default()
|
||||
.push(GameInput::MoveForward);
|
||||
map.entry(settings.game_buttons.move_left)
|
||||
.or_default()
|
||||
.push(GameInput::MoveLeft);
|
||||
map.entry(settings.game_buttons.move_back)
|
||||
.or_default()
|
||||
.push(GameInput::MoveBack);
|
||||
map.entry(settings.game_buttons.move_right)
|
||||
.or_default()
|
||||
.push(GameInput::MoveRight);
|
||||
map.entry(settings.game_buttons.jump)
|
||||
.or_default()
|
||||
.push(GameInput::Jump);
|
||||
map.entry(settings.game_buttons.sit)
|
||||
.or_default()
|
||||
.push(GameInput::Sit);
|
||||
map.entry(settings.game_buttons.glide)
|
||||
.or_default()
|
||||
.push(GameInput::Glide);
|
||||
map.entry(settings.game_buttons.climb)
|
||||
.or_default()
|
||||
.push(GameInput::Climb);
|
||||
map.entry(settings.game_buttons.climb_down)
|
||||
.or_default()
|
||||
.push(GameInput::ClimbDown);
|
||||
map.entry(settings.game_buttons.wall_leap)
|
||||
.or_default()
|
||||
.push(GameInput::WallLeap);
|
||||
map.entry(settings.game_buttons.mount)
|
||||
.or_default()
|
||||
.push(GameInput::Mount);
|
||||
map.entry(settings.game_buttons.map)
|
||||
.or_default()
|
||||
.push(GameInput::Map);
|
||||
map.entry(settings.game_buttons.bag)
|
||||
.or_default()
|
||||
.push(GameInput::Bag);
|
||||
map.entry(settings.game_buttons.quest_log)
|
||||
.or_default()
|
||||
.push(GameInput::QuestLog);
|
||||
map.entry(settings.game_buttons.character_window)
|
||||
.or_default()
|
||||
.push(GameInput::CharacterWindow);
|
||||
map.entry(settings.game_buttons.social)
|
||||
.or_default()
|
||||
.push(GameInput::Social);
|
||||
map.entry(settings.game_buttons.spellbook)
|
||||
.or_default()
|
||||
.push(GameInput::Spellbook);
|
||||
map.entry(settings.game_buttons.settings)
|
||||
.or_default()
|
||||
.push(GameInput::Settings);
|
||||
map.entry(settings.game_buttons.help)
|
||||
.or_default()
|
||||
.push(GameInput::Help);
|
||||
map.entry(settings.game_buttons.toggle_interface)
|
||||
.or_default()
|
||||
.push(GameInput::ToggleInterface);
|
||||
map.entry(settings.game_buttons.toggle_debug)
|
||||
.or_default()
|
||||
.push(GameInput::ToggleDebug);
|
||||
map.entry(settings.game_buttons.fullscreen)
|
||||
.or_default()
|
||||
.push(GameInput::Fullscreen);
|
||||
map.entry(settings.game_buttons.screenshot)
|
||||
.or_default()
|
||||
.push(GameInput::Screenshot);
|
||||
map.entry(settings.game_buttons.toggle_ingame_ui)
|
||||
.or_default()
|
||||
.push(GameInput::ToggleIngameUi);
|
||||
map.entry(settings.game_buttons.roll)
|
||||
.or_default()
|
||||
.push(GameInput::Roll);
|
||||
map.entry(settings.game_buttons.respawn)
|
||||
.or_default()
|
||||
.push(GameInput::Respawn);
|
||||
map.entry(settings.game_buttons.interact)
|
||||
.or_default()
|
||||
.push(GameInput::Interact);
|
||||
map.entry(settings.game_buttons.toggle_wield)
|
||||
.or_default()
|
||||
.push(GameInput::ToggleWield);
|
||||
map.entry(settings.game_buttons.charge)
|
||||
.or_default()
|
||||
.push(GameInput::Charge);
|
||||
map
|
||||
},
|
||||
menu_button_map: {
|
||||
let mut map: HashMap<_, Vec<_>> = HashMap::new();
|
||||
map.entry(settings.menu_buttons.up)
|
||||
.or_default()
|
||||
.push(MenuInput::Up);
|
||||
map.entry(settings.menu_buttons.down)
|
||||
.or_default()
|
||||
.push(MenuInput::Down);
|
||||
map.entry(settings.menu_buttons.left)
|
||||
.or_default()
|
||||
.push(MenuInput::Left);
|
||||
map.entry(settings.menu_buttons.right)
|
||||
.or_default()
|
||||
.push(MenuInput::Right);
|
||||
map.entry(settings.menu_buttons.scroll_up)
|
||||
.or_default()
|
||||
.push(MenuInput::ScrollUp);
|
||||
map.entry(settings.menu_buttons.scroll_down)
|
||||
.or_default()
|
||||
.push(MenuInput::ScrollDown);
|
||||
map.entry(settings.menu_buttons.scroll_left)
|
||||
.or_default()
|
||||
.push(MenuInput::ScrollLeft);
|
||||
map.entry(settings.menu_buttons.scroll_right)
|
||||
.or_default()
|
||||
.push(MenuInput::ScrollRight);
|
||||
map.entry(settings.menu_buttons.home)
|
||||
.or_default()
|
||||
.push(MenuInput::Home);
|
||||
map.entry(settings.menu_buttons.end)
|
||||
.or_default()
|
||||
.push(MenuInput::End);
|
||||
map.entry(settings.menu_buttons.apply)
|
||||
.or_default()
|
||||
.push(MenuInput::Apply);
|
||||
map.entry(settings.menu_buttons.back)
|
||||
.or_default()
|
||||
.push(MenuInput::Back);
|
||||
map.entry(settings.menu_buttons.exit)
|
||||
.or_default()
|
||||
.push(MenuInput::Exit);
|
||||
map
|
||||
},
|
||||
game_analog_button_map: HashMap::new(),
|
||||
menu_analog_button_map: HashMap::new(),
|
||||
game_axis_map: {
|
||||
let mut map: HashMap<_, Vec<_>> = HashMap::new();
|
||||
map.entry(settings.game_axis.movement_x)
|
||||
.or_default()
|
||||
.push(AxisGameAction::MovementX);
|
||||
map.entry(settings.game_axis.movement_y)
|
||||
.or_default()
|
||||
.push(AxisGameAction::MovementY);
|
||||
map.entry(settings.game_axis.camera_x)
|
||||
.or_default()
|
||||
.push(AxisGameAction::CameraX);
|
||||
map.entry(settings.game_axis.camera_y)
|
||||
.or_default()
|
||||
.push(AxisGameAction::CameraY);
|
||||
map
|
||||
},
|
||||
menu_axis_map: {
|
||||
let mut map: HashMap<_, Vec<_>> = HashMap::new();
|
||||
map.entry(settings.menu_axis.move_x)
|
||||
.or_default()
|
||||
.push(AxisMenuAction::MoveX);
|
||||
map.entry(settings.menu_axis.move_y)
|
||||
.or_default()
|
||||
.push(AxisMenuAction::MoveY);
|
||||
map.entry(settings.menu_axis.scroll_x)
|
||||
.or_default()
|
||||
.push(AxisMenuAction::ScrollX);
|
||||
map.entry(settings.menu_axis.scroll_y)
|
||||
.or_default()
|
||||
.push(AxisMenuAction::ScrollY);
|
||||
map
|
||||
},
|
||||
pan_sensitivity: settings.pan_sensitivity,
|
||||
axis_deadzones: settings.axis_deadzones.clone(),
|
||||
button_deadzones: settings.button_deadzones.clone(),
|
||||
mouse_emulation_sensitivity: settings.mouse_emulation_sensitivity,
|
||||
inverted_axes: settings.inverted_axes.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// All the menu actions you can bind to an Axis
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub enum AxisMenuAction {
|
||||
MoveX,
|
||||
MoveY,
|
||||
ScrollX,
|
||||
ScrollY,
|
||||
}
|
||||
|
||||
/// All the game actions you can bind to an Axis
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub enum AxisGameAction {
|
||||
MovementX,
|
||||
MovementY,
|
||||
CameraX,
|
||||
CameraY,
|
||||
}
|
||||
|
||||
/// All the menu actions you can bind to an analog button
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub enum AnalogButtonMenuAction {}
|
||||
|
||||
/// All the game actions you can bind to an analog button
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub enum AnalogButtonGameAction {}
|
||||
|
||||
/// Button::Simple(GilButton::Unknown) is invalid and equal to mapping an action
|
||||
/// to nothing
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub enum Button {
|
||||
Simple(GilButton),
|
||||
EventCode(u32),
|
||||
}
|
||||
|
||||
/// AnalogButton::Simple(GilButton::Unknown) is invalid and equal to mapping an
|
||||
/// action to nothing
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub enum AnalogButton {
|
||||
Simple(GilButton),
|
||||
EventCode(u32),
|
||||
}
|
||||
|
||||
/// Axis::Simple(GilAxis::Unknown) is invalid and equal to mapping an action to
|
||||
/// nothing
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub enum Axis {
|
||||
Simple(GilAxis),
|
||||
EventCode(u32),
|
||||
}
|
||||
|
||||
impl From<(GilAxis, GilCode)> for Axis {
|
||||
fn from((axis, code): (GilAxis, GilCode)) -> Self {
|
||||
match axis {
|
||||
GilAxis::Unknown => Self::EventCode(code.into_u32()),
|
||||
_ => Self::Simple(axis),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(GilButton, GilCode)> for Button {
|
||||
fn from((button, code): (GilButton, GilCode)) -> Self {
|
||||
match button {
|
||||
GilButton::Unknown => Self::EventCode(code.into_u32()),
|
||||
_ => Self::Simple(button),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(GilButton, GilCode)> for AnalogButton {
|
||||
fn from((button, code): (GilButton, GilCode)) -> Self {
|
||||
match button {
|
||||
GilButton::Unknown => Self::EventCode(code.into_u32()),
|
||||
_ => Self::Simple(button),
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ pub struct KeyState {
|
||||
pub left: bool,
|
||||
pub up: bool,
|
||||
pub down: bool,
|
||||
pub analog_matrix: Vec2<f32>,
|
||||
}
|
||||
|
||||
impl KeyState {
|
||||
@ -14,16 +15,21 @@ impl KeyState {
|
||||
left: false,
|
||||
up: false,
|
||||
down: false,
|
||||
analog_matrix: Vec2::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dir_vec(&self) -> Vec2<f32> {
|
||||
let dir = Vec2::<f32>::new(
|
||||
if self.right { 1.0 } else { 0.0 } + if self.left { -1.0 } else { 0.0 },
|
||||
if self.up { 1.0 } else { 0.0 } + if self.down { -1.0 } else { 0.0 },
|
||||
);
|
||||
let dir = if self.analog_matrix == Vec2::zero() {
|
||||
Vec2::<f32>::new(
|
||||
if self.right { 1.0 } else { 0.0 } + if self.left { -1.0 } else { 0.0 },
|
||||
if self.up { 1.0 } else { 0.0 } + if self.down { -1.0 } else { 0.0 },
|
||||
)
|
||||
} else {
|
||||
self.analog_matrix
|
||||
};
|
||||
|
||||
if dir.magnitude_squared() == 0.0 {
|
||||
if dir.magnitude_squared() <= 1.0 {
|
||||
dir
|
||||
} else {
|
||||
dir.normalized()
|
||||
|
@ -6,6 +6,7 @@
|
||||
pub mod ui;
|
||||
pub mod anim;
|
||||
pub mod audio;
|
||||
pub mod controller;
|
||||
mod ecs;
|
||||
pub mod error;
|
||||
pub mod hud;
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
create_pp_mesh, create_skybox_mesh, Consts, Globals, Light, Model, PostProcessLocals,
|
||||
PostProcessPipeline, Renderer, Shadow, SkyboxLocals, SkyboxPipeline,
|
||||
},
|
||||
window::Event,
|
||||
window::{AnalogGameInput, Event},
|
||||
};
|
||||
use common::{
|
||||
comp,
|
||||
@ -50,6 +50,7 @@ pub struct Scene {
|
||||
lights: Consts<Light>,
|
||||
shadows: Consts<Shadow>,
|
||||
camera: Camera,
|
||||
camera_input_state: Vec2<f32>,
|
||||
|
||||
skybox: Skybox,
|
||||
postprocess: PostProcess,
|
||||
@ -85,6 +86,7 @@ impl Scene {
|
||||
.create_consts(&[Shadow::default(); MAX_SHADOW_COUNT])
|
||||
.unwrap(),
|
||||
camera: Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson),
|
||||
camera_input_state: Vec2::zero(),
|
||||
|
||||
skybox: Skybox {
|
||||
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
|
||||
@ -146,6 +148,17 @@ impl Scene {
|
||||
.zoom_switch(delta * (0.05 + self.camera.get_distance() * 0.01));
|
||||
true
|
||||
},
|
||||
Event::AnalogGameInput(input) => match input {
|
||||
AnalogGameInput::CameraX(d) => {
|
||||
self.camera_input_state.x = d;
|
||||
true
|
||||
},
|
||||
AnalogGameInput::CameraY(d) => {
|
||||
self.camera_input_state.y = d;
|
||||
true
|
||||
},
|
||||
_ => false,
|
||||
},
|
||||
// All other events are unhandled
|
||||
_ => false,
|
||||
}
|
||||
@ -185,6 +198,12 @@ impl Scene {
|
||||
_ => 1_f32,
|
||||
};
|
||||
|
||||
// Add the analog input to camera
|
||||
self.camera
|
||||
.rotate_by(Vec3::from([self.camera_input_state.x, 0.0, 0.0]));
|
||||
self.camera
|
||||
.rotate_by(Vec3::from([0.0, self.camera_input_state.y, 0.0]));
|
||||
|
||||
// Alter camera position to match player.
|
||||
let tilt = self.camera.get_orientation().y;
|
||||
let dist = self.camera.get_distance();
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
key_state::KeyState,
|
||||
render::Renderer,
|
||||
scene::{camera, Scene, SceneData},
|
||||
window::{Event, GameInput},
|
||||
window::{AnalogGameInput, Event, GameInput},
|
||||
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use client::{self, Client, Event::Chat};
|
||||
@ -365,6 +365,17 @@ impl PlayState for SessionState {
|
||||
Event::InputUpdate(GameInput::Charge, state) => {
|
||||
self.inputs.charge.set_state(state);
|
||||
},
|
||||
Event::AnalogGameInput(input) => match input {
|
||||
AnalogGameInput::MovementX(v) => {
|
||||
self.key_state.analog_matrix.x = v;
|
||||
},
|
||||
AnalogGameInput::MovementY(v) => {
|
||||
self.key_state.analog_matrix.y = v;
|
||||
},
|
||||
other => {
|
||||
self.scene.handle_input_event(Event::AnalogGameInput(other));
|
||||
},
|
||||
},
|
||||
|
||||
// Pass all other events to the scene
|
||||
event => {
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
};
|
||||
use directories::{ProjectDirs, UserDirs};
|
||||
use glutin::{MouseButton, VirtualKeyCode};
|
||||
use hashbrown::HashSet;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use log::warn;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::{fs, io::prelude::*, path::PathBuf};
|
||||
@ -105,6 +105,225 @@ impl Default for ControlSettings {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GamepadSettings {
|
||||
pub game_buttons: con_settings::GameButtons,
|
||||
pub menu_buttons: con_settings::MenuButtons,
|
||||
pub game_axis: con_settings::GameAxis,
|
||||
pub menu_axis: con_settings::MenuAxis,
|
||||
pub game_analog_buttons: con_settings::GameAnalogButton,
|
||||
pub menu_analog_buttons: con_settings::MenuAnalogButton,
|
||||
pub pan_sensitivity: u32,
|
||||
pub pan_invert_y: bool,
|
||||
pub axis_deadzones: HashMap<crate::controller::Axis, f32>,
|
||||
pub button_deadzones: HashMap<crate::controller::AnalogButton, f32>,
|
||||
pub mouse_emulation_sensitivity: u32,
|
||||
pub inverted_axes: Vec<crate::controller::Axis>,
|
||||
}
|
||||
|
||||
impl Default for GamepadSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
game_buttons: con_settings::GameButtons::default(),
|
||||
menu_buttons: con_settings::MenuButtons::default(),
|
||||
game_axis: con_settings::GameAxis::default(),
|
||||
menu_axis: con_settings::MenuAxis::default(),
|
||||
game_analog_buttons: con_settings::GameAnalogButton::default(),
|
||||
menu_analog_buttons: con_settings::MenuAnalogButton::default(),
|
||||
pan_sensitivity: 10,
|
||||
pan_invert_y: false,
|
||||
axis_deadzones: HashMap::new(),
|
||||
button_deadzones: HashMap::new(),
|
||||
mouse_emulation_sensitivity: 12,
|
||||
inverted_axes: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod con_settings {
|
||||
use crate::controller::*;
|
||||
use gilrs::{Axis as GilAxis, Button as GilButton};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GameButtons {
|
||||
pub primary: Button,
|
||||
pub secondary: Button,
|
||||
pub toggle_cursor: Button,
|
||||
pub escape: Button,
|
||||
pub enter: Button,
|
||||
pub command: Button,
|
||||
pub move_forward: Button,
|
||||
pub move_left: Button,
|
||||
pub move_back: Button,
|
||||
pub move_right: Button,
|
||||
pub jump: Button,
|
||||
pub sit: Button,
|
||||
pub glide: Button,
|
||||
pub climb: Button,
|
||||
pub climb_down: Button,
|
||||
pub wall_leap: Button,
|
||||
pub mount: Button,
|
||||
pub map: Button,
|
||||
pub bag: Button,
|
||||
pub quest_log: Button,
|
||||
pub character_window: Button,
|
||||
pub social: Button,
|
||||
pub spellbook: Button,
|
||||
pub settings: Button,
|
||||
pub help: Button,
|
||||
pub toggle_interface: Button,
|
||||
pub toggle_debug: Button,
|
||||
pub fullscreen: Button,
|
||||
pub screenshot: Button,
|
||||
pub toggle_ingame_ui: Button,
|
||||
pub roll: Button,
|
||||
pub respawn: Button,
|
||||
pub interact: Button,
|
||||
pub toggle_wield: Button,
|
||||
pub charge: Button,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct MenuButtons {
|
||||
pub up: Button,
|
||||
pub down: Button,
|
||||
pub left: Button,
|
||||
pub right: Button,
|
||||
pub scroll_up: Button,
|
||||
pub scroll_down: Button,
|
||||
pub scroll_left: Button,
|
||||
pub scroll_right: Button,
|
||||
pub home: Button,
|
||||
pub end: Button,
|
||||
pub apply: Button,
|
||||
pub back: Button,
|
||||
pub exit: Button,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GameAxis {
|
||||
pub movement_x: Axis,
|
||||
pub movement_y: Axis,
|
||||
pub camera_x: Axis,
|
||||
pub camera_y: Axis,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct MenuAxis {
|
||||
pub move_x: Axis,
|
||||
pub move_y: Axis,
|
||||
pub scroll_x: Axis,
|
||||
pub scroll_y: Axis,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct GameAnalogButton {}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct MenuAnalogButton {}
|
||||
|
||||
impl Default for GameButtons {
|
||||
fn default() -> Self {
|
||||
// binding to unknown = getting skipped from processing
|
||||
Self {
|
||||
primary: Button::Simple(GilButton::RightTrigger2),
|
||||
secondary: Button::Simple(GilButton::LeftTrigger2),
|
||||
toggle_cursor: Button::Simple(GilButton::Select),
|
||||
escape: Button::Simple(GilButton::Mode),
|
||||
enter: Button::Simple(GilButton::Unknown),
|
||||
command: Button::Simple(GilButton::Unknown),
|
||||
move_forward: Button::Simple(GilButton::Unknown),
|
||||
move_left: Button::Simple(GilButton::Unknown),
|
||||
move_back: Button::Simple(GilButton::Unknown),
|
||||
move_right: Button::Simple(GilButton::Unknown),
|
||||
jump: Button::Simple(GilButton::South),
|
||||
sit: Button::Simple(GilButton::West),
|
||||
glide: Button::Simple(GilButton::LeftTrigger),
|
||||
climb: Button::Simple(GilButton::South),
|
||||
climb_down: Button::Simple(GilButton::Unknown),
|
||||
wall_leap: Button::Simple(GilButton::Unknown),
|
||||
mount: Button::Simple(GilButton::North),
|
||||
map: Button::Simple(GilButton::DPadRight),
|
||||
bag: Button::Simple(GilButton::DPadDown),
|
||||
quest_log: Button::Simple(GilButton::Unknown),
|
||||
character_window: Button::Simple(GilButton::Unknown),
|
||||
social: Button::Simple(GilButton::Unknown),
|
||||
spellbook: Button::Simple(GilButton::Unknown),
|
||||
settings: Button::Simple(GilButton::Unknown),
|
||||
help: Button::Simple(GilButton::Unknown),
|
||||
toggle_interface: Button::Simple(GilButton::Unknown),
|
||||
toggle_debug: Button::Simple(GilButton::Unknown),
|
||||
fullscreen: Button::Simple(GilButton::Unknown),
|
||||
screenshot: Button::Simple(GilButton::DPadUp),
|
||||
toggle_ingame_ui: Button::Simple(GilButton::Unknown),
|
||||
roll: Button::Simple(GilButton::RightTrigger),
|
||||
respawn: Button::Simple(GilButton::RightTrigger2),
|
||||
interact: Button::Simple(GilButton::LeftTrigger2),
|
||||
toggle_wield: Button::Simple(GilButton::DPadLeft),
|
||||
charge: Button::Simple(GilButton::Unknown),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MenuButtons {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
up: Button::Simple(GilButton::Unknown),
|
||||
down: Button::Simple(GilButton::Unknown),
|
||||
left: Button::Simple(GilButton::Unknown),
|
||||
right: Button::Simple(GilButton::Unknown),
|
||||
scroll_up: Button::Simple(GilButton::Unknown),
|
||||
scroll_down: Button::Simple(GilButton::Unknown),
|
||||
scroll_left: Button::Simple(GilButton::Unknown),
|
||||
scroll_right: Button::Simple(GilButton::Unknown),
|
||||
home: Button::Simple(GilButton::DPadUp),
|
||||
end: Button::Simple(GilButton::DPadDown),
|
||||
apply: Button::Simple(GilButton::South),
|
||||
back: Button::Simple(GilButton::East),
|
||||
exit: Button::Simple(GilButton::Mode),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GameAxis {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
movement_x: Axis::Simple(GilAxis::LeftStickX),
|
||||
movement_y: Axis::Simple(GilAxis::LeftStickY),
|
||||
camera_x: Axis::Simple(GilAxis::RightStickX),
|
||||
camera_y: Axis::Simple(GilAxis::RightStickY),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MenuAxis {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
move_x: Axis::Simple(GilAxis::RightStickX),
|
||||
move_y: Axis::Simple(GilAxis::RightStickY),
|
||||
scroll_x: Axis::Simple(GilAxis::LeftStickX),
|
||||
scroll_y: Axis::Simple(GilAxis::LeftStickY),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GameAnalogButton {
|
||||
fn default() -> Self { Self {} }
|
||||
}
|
||||
|
||||
impl Default for MenuAnalogButton {
|
||||
fn default() -> Self { Self {} }
|
||||
}
|
||||
}
|
||||
|
||||
/// `GameplaySettings` contains sensitivity and gameplay options.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
@ -298,6 +517,7 @@ pub struct Settings {
|
||||
pub logon_commands: Vec<String>,
|
||||
pub language: LanguageSettings,
|
||||
pub screenshots_path: PathBuf,
|
||||
pub controller: GamepadSettings,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
@ -329,6 +549,7 @@ impl Default for Settings {
|
||||
logon_commands: Vec::new(),
|
||||
language: LanguageSettings::default(),
|
||||
screenshots_path,
|
||||
controller: GamepadSettings::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -634,8 +634,8 @@ impl Ui {
|
||||
mesh.push_quad(create_ui_quad(
|
||||
gl_aabr(rect),
|
||||
Aabr {
|
||||
min: Vec2::new(0.0, 0.0),
|
||||
max: Vec2::new(0.0, 0.0),
|
||||
min: Vec2::zero(),
|
||||
max: Vec2::zero(),
|
||||
},
|
||||
color,
|
||||
UiMode::Geometry,
|
||||
|
@ -1,15 +1,17 @@
|
||||
use crate::{
|
||||
controller::*,
|
||||
render::{Renderer, WinColorFmt, WinDepthFmt},
|
||||
settings::Settings,
|
||||
ui, Error,
|
||||
};
|
||||
use gilrs::{EventType, Gilrs};
|
||||
use hashbrown::HashMap;
|
||||
use log::{error, warn};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use vek::*;
|
||||
|
||||
/// Represents a key that the game recognises after keyboard mapping.
|
||||
/// Represents a key that the game recognises after input mapping.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub enum GameInput {
|
||||
Primary,
|
||||
@ -49,6 +51,40 @@ pub enum GameInput {
|
||||
Charge,
|
||||
}
|
||||
|
||||
/// Represents a key that the game menus recognise after input mapping
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub enum MenuInput {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
ScrollUp,
|
||||
ScrollDown,
|
||||
ScrollLeft,
|
||||
ScrollRight,
|
||||
Home,
|
||||
End,
|
||||
Apply,
|
||||
Back,
|
||||
Exit,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
pub enum AnalogMenuInput {
|
||||
MoveX(f32),
|
||||
MoveY(f32),
|
||||
ScrollX(f32),
|
||||
ScrollY(f32),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
pub enum AnalogGameInput {
|
||||
MovementX(f32),
|
||||
MovementY(f32),
|
||||
CameraX(f32),
|
||||
CameraY(f32),
|
||||
}
|
||||
|
||||
/// Represents an incoming event from the window.
|
||||
#[derive(Clone)]
|
||||
pub enum Event {
|
||||
@ -76,6 +112,13 @@ pub enum Event {
|
||||
SettingsChanged,
|
||||
/// The window is (un)focused
|
||||
Focused(bool),
|
||||
/// A key that the game recognises for menu navigation has been pressed or
|
||||
/// released
|
||||
MenuInput(MenuInput, bool),
|
||||
/// Update of the analog inputs recognized by the menus
|
||||
AnalogMenuInput(AnalogMenuInput),
|
||||
/// Update of the analog inputs recognized by the game
|
||||
AnalogGameInput(AnalogGameInput),
|
||||
}
|
||||
|
||||
pub type MouseButton = winit::MouseButton;
|
||||
@ -277,6 +320,10 @@ pub struct Window {
|
||||
keypress_map: HashMap<GameInput, glutin::ElementState>,
|
||||
supplement_events: Vec<Event>,
|
||||
focused: bool,
|
||||
gilrs: Option<Gilrs>,
|
||||
controller_settings: ControllerSettings,
|
||||
cursor_position: winit::dpi::LogicalPosition,
|
||||
mouse_emulation_vec: Vec2<f32>,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
@ -414,6 +461,30 @@ impl Window {
|
||||
|
||||
let keypress_map = HashMap::new();
|
||||
|
||||
let gilrs = match Gilrs::new() {
|
||||
Ok(gilrs) => Some(gilrs),
|
||||
Err(gilrs::Error::NotImplemented(_dummy)) => {
|
||||
warn!("Controller input is unsupported on this platform.");
|
||||
None
|
||||
},
|
||||
Err(gilrs::Error::InvalidAxisToBtn) => {
|
||||
error!(
|
||||
"Invalid AxisToBtn controller mapping. Falling back to no controller support."
|
||||
);
|
||||
None
|
||||
},
|
||||
Err(gilrs::Error::Other(err)) => {
|
||||
error!(
|
||||
"Platform-specific error when creating a Gilrs instance: `{}`. Falling back \
|
||||
to no controller support.",
|
||||
err
|
||||
);
|
||||
None
|
||||
},
|
||||
};
|
||||
|
||||
let controller_settings = ControllerSettings::from(&settings.controller);
|
||||
|
||||
let mut this = Self {
|
||||
events_loop,
|
||||
renderer: Renderer::new(
|
||||
@ -437,6 +508,10 @@ impl Window {
|
||||
keypress_map,
|
||||
supplement_events: vec![],
|
||||
focused: true,
|
||||
gilrs,
|
||||
controller_settings,
|
||||
cursor_position: winit::dpi::LogicalPosition::new(0.0, 0.0),
|
||||
mouse_emulation_vec: Vec2::zero(),
|
||||
};
|
||||
|
||||
this.fullscreen(settings.graphics.fullscreen);
|
||||
@ -477,6 +552,7 @@ impl Window {
|
||||
};
|
||||
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.
|
||||
@ -556,6 +632,9 @@ impl Window {
|
||||
*focused = state;
|
||||
events.push(Event::Focused(state));
|
||||
},
|
||||
glutin::WindowEvent::CursorMoved { position, .. } => {
|
||||
cursor_position = Some(position);
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
glutin::Event::DeviceEvent { event, .. } => match event {
|
||||
@ -593,6 +672,10 @@ impl Window {
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(pos) = cursor_position {
|
||||
self.cursor_position = pos;
|
||||
}
|
||||
|
||||
if take_screenshot {
|
||||
self.take_screenshot(&settings);
|
||||
}
|
||||
@ -601,9 +684,217 @@ impl Window {
|
||||
self.toggle_fullscreen(settings);
|
||||
}
|
||||
|
||||
if let Some(gilrs) = &mut self.gilrs {
|
||||
while let Some(event) = gilrs.next_event() {
|
||||
fn handle_buttons(
|
||||
settings: &ControllerSettings,
|
||||
events: &mut Vec<Event>,
|
||||
button: &Button,
|
||||
is_pressed: bool,
|
||||
) {
|
||||
if let Some(evs) = settings.game_button_map.get(button) {
|
||||
for ev in evs {
|
||||
events.push(Event::InputUpdate(*ev, is_pressed));
|
||||
}
|
||||
}
|
||||
if let Some(evs) = settings.menu_button_map.get(button) {
|
||||
for ev in evs {
|
||||
events.push(Event::MenuInput(*ev, is_pressed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match event.event {
|
||||
EventType::ButtonPressed(button, code)
|
||||
| EventType::ButtonRepeated(button, code) => {
|
||||
handle_buttons(
|
||||
&self.controller_settings,
|
||||
&mut events,
|
||||
&Button::from((button, code)),
|
||||
true,
|
||||
);
|
||||
},
|
||||
EventType::ButtonReleased(button, code) => {
|
||||
handle_buttons(
|
||||
&self.controller_settings,
|
||||
&mut events,
|
||||
&Button::from((button, code)),
|
||||
false,
|
||||
);
|
||||
},
|
||||
EventType::ButtonChanged(button, _value, code) => {
|
||||
if let Some(actions) = self
|
||||
.controller_settings
|
||||
.game_analog_button_map
|
||||
.get(&AnalogButton::from((button, code)))
|
||||
{
|
||||
for action in actions {
|
||||
match *action {}
|
||||
}
|
||||
}
|
||||
if let Some(actions) = self
|
||||
.controller_settings
|
||||
.menu_analog_button_map
|
||||
.get(&AnalogButton::from((button, code)))
|
||||
{
|
||||
for action in actions {
|
||||
match *action {}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
EventType::AxisChanged(axis, value, code) => {
|
||||
let value = match self
|
||||
.controller_settings
|
||||
.inverted_axes
|
||||
.contains(&Axis::from((axis, code)))
|
||||
{
|
||||
true => value * -1.0,
|
||||
false => value,
|
||||
};
|
||||
|
||||
let value = self
|
||||
.controller_settings
|
||||
.apply_axis_deadzone(&Axis::from((axis, code)), value);
|
||||
|
||||
if self.cursor_grabbed {
|
||||
if let Some(actions) = self
|
||||
.controller_settings
|
||||
.game_axis_map
|
||||
.get(&Axis::from((axis, code)))
|
||||
{
|
||||
for action in actions {
|
||||
match *action {
|
||||
AxisGameAction::MovementX => {
|
||||
events.push(Event::AnalogGameInput(
|
||||
AnalogGameInput::MovementX(value),
|
||||
));
|
||||
},
|
||||
AxisGameAction::MovementY => {
|
||||
events.push(Event::AnalogGameInput(
|
||||
AnalogGameInput::MovementY(value),
|
||||
));
|
||||
},
|
||||
AxisGameAction::CameraX => {
|
||||
events.push(Event::AnalogGameInput(
|
||||
AnalogGameInput::CameraX(
|
||||
value
|
||||
* self.controller_settings.pan_sensitivity
|
||||
as f32
|
||||
/ 100.0,
|
||||
),
|
||||
));
|
||||
},
|
||||
AxisGameAction::CameraY => {
|
||||
events.push(Event::AnalogGameInput(
|
||||
AnalogGameInput::CameraY(
|
||||
value
|
||||
* self.controller_settings.pan_sensitivity
|
||||
as f32
|
||||
/ 100.0,
|
||||
),
|
||||
));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(actions) = self
|
||||
.controller_settings
|
||||
.menu_axis_map
|
||||
.get(&Axis::from((axis, code)))
|
||||
{
|
||||
// TODO: possibly add sensitivity settings when this is used
|
||||
for action in actions {
|
||||
match *action {
|
||||
AxisMenuAction::MoveX => {
|
||||
events.push(Event::AnalogMenuInput(
|
||||
AnalogMenuInput::MoveX(value),
|
||||
));
|
||||
},
|
||||
AxisMenuAction::MoveY => {
|
||||
events.push(Event::AnalogMenuInput(
|
||||
AnalogMenuInput::MoveY(value),
|
||||
));
|
||||
},
|
||||
AxisMenuAction::ScrollX => {
|
||||
events.push(Event::AnalogMenuInput(
|
||||
AnalogMenuInput::ScrollX(value),
|
||||
));
|
||||
},
|
||||
AxisMenuAction::ScrollY => {
|
||||
events.push(Event::AnalogMenuInput(
|
||||
AnalogMenuInput::ScrollY(value),
|
||||
));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
EventType::Connected => {},
|
||||
EventType::Disconnected => {},
|
||||
EventType::Dropped => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse emulation for the menus, to be removed when a proper menu navigation
|
||||
// system is available
|
||||
if !self.cursor_grabbed {
|
||||
events = events
|
||||
.into_iter()
|
||||
.filter_map(|event| match event {
|
||||
Event::AnalogMenuInput(input) => match input {
|
||||
AnalogMenuInput::MoveX(d) => {
|
||||
self.mouse_emulation_vec.x = d;
|
||||
None
|
||||
},
|
||||
AnalogMenuInput::MoveY(d) => {
|
||||
// This just has to be inverted for some reason
|
||||
self.mouse_emulation_vec.y = d * -1.0;
|
||||
None
|
||||
},
|
||||
_ => {
|
||||
let event = Event::AnalogMenuInput(input);
|
||||
Some(event)
|
||||
},
|
||||
},
|
||||
Event::MenuInput(input, state) => match input {
|
||||
MenuInput::Apply => Some(match state {
|
||||
true => Event::Ui(ui::Event(conrod_core::event::Input::Press(
|
||||
conrod_core::input::Button::Mouse(
|
||||
conrod_core::input::state::mouse::Button::Left,
|
||||
),
|
||||
))),
|
||||
false => Event::Ui(ui::Event(conrod_core::event::Input::Release(
|
||||
conrod_core::input::Button::Mouse(
|
||||
conrod_core::input::state::mouse::Button::Left,
|
||||
),
|
||||
))),
|
||||
}),
|
||||
_ => Some(event),
|
||||
},
|
||||
_ => Some(event),
|
||||
})
|
||||
.collect();
|
||||
let sensitivity = self.controller_settings.mouse_emulation_sensitivity;
|
||||
if self.mouse_emulation_vec != Vec2::zero() {
|
||||
self.offset_cursor(self.mouse_emulation_vec * sensitivity as f32)
|
||||
.unwrap_or(());
|
||||
}
|
||||
}
|
||||
events
|
||||
}
|
||||
|
||||
/// Moves cursor by an offset
|
||||
pub fn offset_cursor(&self, d: Vec2<f32>) -> Result<(), String> {
|
||||
self.window
|
||||
.window()
|
||||
.set_cursor_position(winit::dpi::LogicalPosition::new(
|
||||
d.x as f64 + self.cursor_position.x,
|
||||
d.y as f64 + self.cursor_position.y,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn swap_buffers(&self) -> Result<(), Error> {
|
||||
self.window
|
||||
.swap_buffers()
|
||||
|
Loading…
Reference in New Issue
Block a user