From a87186860ec602c19f0d11528bef2d5123bc7e48 Mon Sep 17 00:00:00 2001 From: Lizzy Fleckenstein Date: Tue, 28 Feb 2023 18:14:06 +0100 Subject: [PATCH] Basic map rendering --- Cargo.lock | 1970 +++++++++++++++++++- Cargo.toml | 19 +- assets/ascii-art.txt | 6 + assets/shaders/map.wgsl | 34 + assets/textures/air.png | Bin 0 -> 225 bytes assets/textures/aux1_btn.png | Bin 0 -> 1652 bytes assets/textures/blank.png | Bin 0 -> 95 bytes assets/textures/bubble.png | Bin 0 -> 142 bytes assets/textures/bubble_gone.png | Bin 0 -> 68 bytes assets/textures/camera_btn.png | Bin 0 -> 1859 bytes assets/textures/cdb_add.png | Bin 0 -> 147 bytes assets/textures/cdb_clear.png | Bin 0 -> 150 bytes assets/textures/cdb_downloading.png | Bin 0 -> 201 bytes assets/textures/cdb_queued.png | Bin 0 -> 210 bytes assets/textures/cdb_update.png | Bin 0 -> 173 bytes assets/textures/cdb_viewonline.png | Bin 0 -> 191 bytes assets/textures/chat_btn.png | Bin 0 -> 873 bytes assets/textures/chat_hide_btn.png | Bin 0 -> 1089 bytes assets/textures/chat_show_btn.png | Bin 0 -> 1082 bytes assets/textures/checkbox_16.png | Bin 0 -> 288 bytes assets/textures/checkbox_16_white.png | Bin 0 -> 173 bytes assets/textures/checkbox_32.png | Bin 0 -> 436 bytes assets/textures/checkbox_64.png | Bin 0 -> 766 bytes assets/textures/clear.png | Bin 0 -> 708 bytes assets/textures/crack_anylength.png | Bin 0 -> 255 bytes assets/textures/debug_btn.png | Bin 0 -> 2484 bytes assets/textures/down.png | Bin 0 -> 1690 bytes assets/textures/drop_btn.png | Bin 0 -> 1269 bytes assets/textures/end_icon.png | Bin 0 -> 908 bytes assets/textures/error_icon_orange.png | Bin 0 -> 133 bytes assets/textures/error_icon_red.png | Bin 0 -> 133 bytes assets/textures/error_screenshot.png | Bin 0 -> 971 bytes assets/textures/fast_btn.png | Bin 0 -> 1212 bytes assets/textures/fly_btn.png | Bin 0 -> 1559 bytes assets/textures/gear_icon.png | Bin 0 -> 1858 bytes assets/textures/halo.png | Bin 0 -> 144 bytes assets/textures/heart.png | Bin 0 -> 255 bytes assets/textures/heart_gone.png | Bin 0 -> 68 bytes assets/textures/ignore.png | Bin 0 -> 234 bytes assets/textures/inventory_btn.png | Bin 0 -> 331 bytes assets/textures/joystick_bg.png | Bin 0 -> 12481 bytes assets/textures/joystick_center.png | Bin 0 -> 2574 bytes assets/textures/joystick_off.png | Bin 0 -> 14363 bytes assets/textures/jump_btn.png | Bin 0 -> 1710 bytes assets/textures/loading_screenshot.png | Bin 0 -> 580 bytes assets/textures/logo.png | Bin 0 -> 12188 bytes assets/textures/menu_bg.png | Bin 0 -> 124 bytes assets/textures/menu_header.png | Bin 0 -> 1628 bytes assets/textures/minimap_btn.png | Bin 0 -> 1220 bytes assets/textures/minimap_mask_round.png | Bin 0 -> 1858 bytes assets/textures/minimap_mask_square.png | Bin 0 -> 420 bytes assets/textures/minimap_overlay_round.png | Bin 0 -> 22044 bytes assets/textures/minimap_overlay_square.png | Bin 0 -> 1686 bytes assets/textures/next_icon.png | Bin 0 -> 714 bytes assets/textures/no_screenshot.png | Bin 0 -> 2043 bytes assets/textures/no_texture.png | Bin 0 -> 281 bytes assets/textures/no_texture_airlike.png | Bin 0 -> 178 bytes assets/textures/noclip_btn.png | Bin 0 -> 1236 bytes assets/textures/object_marker_red.png | Bin 0 -> 449 bytes assets/textures/player.png | Bin 0 -> 142 bytes assets/textures/player_back.png | Bin 0 -> 153 bytes assets/textures/player_marker.png | Bin 0 -> 2166 bytes assets/textures/plus.png | Bin 0 -> 763 bytes assets/textures/prev_icon.png | Bin 0 -> 714 bytes assets/textures/progress_bar.png | Bin 0 -> 413 bytes assets/textures/progress_bar_bg.png | Bin 0 -> 354 bytes assets/textures/rangeview_btn.png | Bin 0 -> 2423 bytes assets/textures/rare_controls.png | Bin 0 -> 227 bytes assets/textures/refresh.png | Bin 0 -> 3660 bytes assets/textures/search.png | Bin 0 -> 1908 bytes assets/textures/server_favorite.png | Bin 0 -> 916 bytes assets/textures/server_favorite_delete.png | Bin 0 -> 748 bytes assets/textures/server_flags_creative.png | Bin 0 -> 273 bytes assets/textures/server_flags_damage.png | Bin 0 -> 713 bytes assets/textures/server_flags_pvp.png | Bin 0 -> 1048 bytes assets/textures/server_incompatible.png | Bin 0 -> 385 bytes assets/textures/server_ping_1.png | Bin 0 -> 251 bytes assets/textures/server_ping_2.png | Bin 0 -> 244 bytes assets/textures/server_ping_3.png | Bin 0 -> 245 bytes assets/textures/server_ping_4.png | Bin 0 -> 213 bytes assets/textures/server_public.png | Bin 0 -> 492 bytes assets/textures/smoke_puff.png | Bin 0 -> 202 bytes assets/textures/start_icon.png | Bin 0 -> 912 bytes assets/textures/sunrisebg.png | Bin 0 -> 4435 bytes assets/textures/unknown_item.png | Bin 0 -> 292 bytes assets/textures/unknown_node.png | Bin 0 -> 193 bytes assets/textures/unknown_object.png | Bin 0 -> 254 bytes assets/textures/wieldhand.png | Bin 0 -> 126 bytes assets/textures/zoom.png | Bin 0 -> 1320 bytes src/gfx.rs | 141 ++ src/gfx/map.rs | 447 +++++ src/gfx/media.rs | 42 + src/gfx/state.rs | 233 +++ src/gfx/util.rs | 63 + src/main.rs | 154 +- src/net.rs | 252 +++ 96 files changed, 3159 insertions(+), 202 deletions(-) create mode 100644 assets/ascii-art.txt create mode 100644 assets/shaders/map.wgsl create mode 100644 assets/textures/air.png create mode 100644 assets/textures/aux1_btn.png create mode 100644 assets/textures/blank.png create mode 100644 assets/textures/bubble.png create mode 100644 assets/textures/bubble_gone.png create mode 100644 assets/textures/camera_btn.png create mode 100644 assets/textures/cdb_add.png create mode 100644 assets/textures/cdb_clear.png create mode 100644 assets/textures/cdb_downloading.png create mode 100644 assets/textures/cdb_queued.png create mode 100644 assets/textures/cdb_update.png create mode 100644 assets/textures/cdb_viewonline.png create mode 100644 assets/textures/chat_btn.png create mode 100644 assets/textures/chat_hide_btn.png create mode 100644 assets/textures/chat_show_btn.png create mode 100644 assets/textures/checkbox_16.png create mode 100644 assets/textures/checkbox_16_white.png create mode 100644 assets/textures/checkbox_32.png create mode 100644 assets/textures/checkbox_64.png create mode 100644 assets/textures/clear.png create mode 100644 assets/textures/crack_anylength.png create mode 100644 assets/textures/debug_btn.png create mode 100644 assets/textures/down.png create mode 100644 assets/textures/drop_btn.png create mode 100644 assets/textures/end_icon.png create mode 100644 assets/textures/error_icon_orange.png create mode 100644 assets/textures/error_icon_red.png create mode 100644 assets/textures/error_screenshot.png create mode 100644 assets/textures/fast_btn.png create mode 100644 assets/textures/fly_btn.png create mode 100644 assets/textures/gear_icon.png create mode 100644 assets/textures/halo.png create mode 100644 assets/textures/heart.png create mode 100644 assets/textures/heart_gone.png create mode 100644 assets/textures/ignore.png create mode 100644 assets/textures/inventory_btn.png create mode 100644 assets/textures/joystick_bg.png create mode 100644 assets/textures/joystick_center.png create mode 100644 assets/textures/joystick_off.png create mode 100644 assets/textures/jump_btn.png create mode 100644 assets/textures/loading_screenshot.png create mode 100644 assets/textures/logo.png create mode 100644 assets/textures/menu_bg.png create mode 100644 assets/textures/menu_header.png create mode 100644 assets/textures/minimap_btn.png create mode 100644 assets/textures/minimap_mask_round.png create mode 100644 assets/textures/minimap_mask_square.png create mode 100644 assets/textures/minimap_overlay_round.png create mode 100644 assets/textures/minimap_overlay_square.png create mode 100644 assets/textures/next_icon.png create mode 100644 assets/textures/no_screenshot.png create mode 100644 assets/textures/no_texture.png create mode 100644 assets/textures/no_texture_airlike.png create mode 100644 assets/textures/noclip_btn.png create mode 100644 assets/textures/object_marker_red.png create mode 100644 assets/textures/player.png create mode 100644 assets/textures/player_back.png create mode 100644 assets/textures/player_marker.png create mode 100644 assets/textures/plus.png create mode 100644 assets/textures/prev_icon.png create mode 100644 assets/textures/progress_bar.png create mode 100644 assets/textures/progress_bar_bg.png create mode 100644 assets/textures/rangeview_btn.png create mode 100644 assets/textures/rare_controls.png create mode 100644 assets/textures/refresh.png create mode 100644 assets/textures/search.png create mode 100644 assets/textures/server_favorite.png create mode 100644 assets/textures/server_favorite_delete.png create mode 100644 assets/textures/server_flags_creative.png create mode 100644 assets/textures/server_flags_damage.png create mode 100644 assets/textures/server_flags_pvp.png create mode 100644 assets/textures/server_incompatible.png create mode 100644 assets/textures/server_ping_1.png create mode 100644 assets/textures/server_ping_2.png create mode 100644 assets/textures/server_ping_3.png create mode 100644 assets/textures/server_ping_4.png create mode 100644 assets/textures/server_public.png create mode 100644 assets/textures/smoke_puff.png create mode 100644 assets/textures/start_icon.png create mode 100644 assets/textures/sunrisebg.png create mode 100644 assets/textures/unknown_item.png create mode 100644 assets/textures/unknown_node.png create mode 100644 assets/textures/unknown_object.png create mode 100644 assets/textures/wieldhand.png create mode 100644 assets/textures/zoom.png create mode 100644 src/gfx.rs create mode 100644 src/gfx/map.rs create mode 100644 src/gfx/media.rs create mode 100644 src/gfx/state.rs create mode 100644 src/gfx/util.rs create mode 100644 src/net.rs diff --git a/Cargo.lock b/Cargo.lock index 43e621c..907a375 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,111 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ab_glyph" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe21446ad43aa56417a767f3e2f3d7c4ca522904de1dd640529a76e9c5c3b33c" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "android-activity" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c77a0045eda8b888c76ea473c2b0515ba6f471d318f8927c5c72240937035a6" +dependencies = [ + "android-properties", + "bitflags", + "cc", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "approx" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "ash" +version = "0.37.2+1.3.238" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28bf19c1f0a470be5fbf7522a308a05df06610252c5bcf5143e1b23f629a9a03" +dependencies = [ + "libloading", +] + [[package]] name = "async-recursion" version = "1.0.2" @@ -30,12 +129,63 @@ dependencies = [ "syn", ] +[[package]] +name = "autocfg" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.1.0", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "block-buffer" version = "0.10.3" @@ -45,12 +195,70 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-sys" +version = "0.1.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "block2" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" +dependencies = [ + "block-sys", + "objc2-encode", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "bytemuck" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aca418a974d83d40a0c1f0c5cba6ff4bc28d8df099109ca459a2118d40b6322" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "calloop" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a59225be45a478d772ce015d9743e49e92798ece9e34eda9a6aa2a6a7f40192" +dependencies = [ + "log", + "nix 0.25.1", + "slotmap", + "thiserror", + "vec_map", +] + [[package]] name = "cc" version = "1.0.79" @@ -66,6 +274,69 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cgmath" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "283944cdecc44bf0b8dd010ec9af888d3b4f142844fdbe026c20ef68148d6fe7" +dependencies = [ + "approx", + "num-traits", + "rand 0.6.5", + "serde", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "collision" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107f6be76c2269a9c8d89e707a66122bd3086f987fa508133a5f774e8ac4ced" +dependencies = [ + "approx", + "bit-set", + "cgmath", + "num", + "rand 0.6.5", + "smallvec 0.6.14", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "com-rs" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf43edc576402991846b093a7ca18a3477e0ef9c588cde84964b5d3e43016642" + [[package]] name = "convert_case" version = "0.6.0" @@ -75,6 +346,47 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types", + "libc", +] + [[package]] name = "cpufeatures" version = "0.2.5" @@ -103,6 +415,23 @@ dependencies = [ "typenum", ] +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "d3d12" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f0de2f5a8e7bd4a9eec0e3c781992a4ce1724f68aec7d7a3715344de8b39da" +dependencies = [ + "bitflags", + "libloading", + "winapi", +] + [[package]] name = "darling" version = "0.14.3" @@ -160,10 +489,25 @@ dependencies = [ ] [[package]] -name = "drop_bomb" -version = "0.1.5" +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" +dependencies = [ + "libloading", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "enumset" @@ -184,6 +528,15 @@ dependencies = [ "syn", ] +[[package]] +name = "euclid" +version = "0.22.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b52c2ef4a78da0ba68fbe1fd920627411096d2ac478f7f4c9f3a54ba6705bade" +dependencies = [ + "num-traits", +] + [[package]] name = "flate2" version = "1.0.25" @@ -202,89 +555,390 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "generic-array" -version = "0.14.6" +name = "foreign-types" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "typenum", - "version_check", + "foreign-types-shared", ] [[package]] -name = "getrandom" -version = "0.2.8" +name = "foreign-types-shared" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "fps-camera" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60c7ada020a020615930e1faeb0a4106b1d327bad75498ae06a1ea9063b1e9b3" dependencies = [ - "cfg-if", - "libc", - "wasi", + "bitflags", + "piston3d-cam", + "vecmath", ] [[package]] -name = "hashbrown" -version = "0.12.3" +name = "fuchsia-cprng" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] -name = "hermit-abi" -version = "0.2.6" +name = "futures" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" dependencies = [ - "libc", + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", ] [[package]] -name = "hydra" -version = "0.1.0" +name = "futures-channel" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ - "mt_net", - "rand", - "sha2", - "srp", - "tokio", + "futures-core", + "futures-sink", ] [[package]] -name = "ident_case" -version = "1.0.1" +name = "futures-core" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] -name = "indexmap" -version = "1.9.2" +name = "futures-executor" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" dependencies = [ - "autocfg", - "hashbrown", + "futures-core", + "futures-task", + "futures-util", ] [[package]] -name = "jobserver" -version = "0.1.25" +name = "futures-io" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" + +[[package]] +name = "futures-macro" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ - "libc", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "futures-sink" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] -name = "libc" -version = "0.2.139" +name = "futures-task" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" + +[[package]] +name = "futures-util" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" + +[[package]] +name = "glow" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8edf6019dff2d92ad27c1e3ff82ad50a0aea5b01370353cc928bfdc33e95925c" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gpu-alloc" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc59e5f710e310e76e6707f86c561dd646f69a8876da9131703b2f717de818d" +dependencies = [ + "bitflags", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5" +dependencies = [ + "bitflags", +] + +[[package]] +name = "gpu-allocator" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce95f9e2e11c2c6fadfce42b5af60005db06576f231f5c92550fdded43c423e8" +dependencies = [ + "backtrace", + "log", + "thiserror", + "winapi", + "windows", +] + +[[package]] +name = "gpu-descriptor" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a" +dependencies = [ + "bitflags", + "gpu-descriptor-types", + "hashbrown", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126" +dependencies = [ + "bitflags", +] + +[[package]] +name = "guillotiere" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782" +dependencies = [ + "euclid", + "svg_fmt", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hassle-rs" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90601c6189668c7345fc53842cb3f3a3d872203d523be1b3cb44a36a3e62fb85" +dependencies = [ + "bitflags", + "com-rs", + "libc", + "libloading", + "thiserror", + "widestring", + "winapi", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "image" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "jpeg-decoder", + "num-rational 0.4.1", + "num-traits", + "png", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg 1.1.0", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "khronos-egl" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" +dependencies = [ + "libc", + "libloading", + "pkg-config", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lerp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b19ac50d419bff1a024a8eb8034bfbee6c1cf8fa3472502f6bd3def327b09e4c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "libc" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "libz-sys" version = "1.1.8" @@ -296,6 +950,16 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg 1.1.0", + "scopeguard", +] + [[package]] name = "log" version = "0.4.17" @@ -305,12 +969,65 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memmap2" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af2c65375e552a67fe3829ca63e8a7c27a378a62824594f43b2851d682b5ec2" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg 1.1.0", +] + +[[package]] +name = "metal" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de11355d1f6781482d027a3b4d4de7825dcedb197bf573e0596d00008402d060" +dependencies = [ + "bitflags", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.6.2" @@ -332,11 +1049,36 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "mt_client" +version = "0.1.0" +dependencies = [ + "bytemuck", + "cgmath", + "fps-camera", + "futures", + "guillotiere", + "image", + "lerp", + "mt_net", + "rand 0.8.5", + "rust-embed", + "sha2", + "srp", + "threadpool", + "tokio", + "wgpu", + "winit", +] + [[package]] name = "mt_net" version = "0.1.0" -source = "git+https://github.com/minetest-rust/mt_net#c545faea8fddd6bd4707dd7e67c83bf7ddd297cb" +source = "git+https://github.com/minetest-rust/mt_net#85d55e42119ea80cd1cd9e9e34c05ea7d07b3a88" dependencies = [ + "async-trait", + "cgmath", + "collision", "delegate", "enumset", "mt_rudp", @@ -347,13 +1089,11 @@ dependencies = [ [[package]] name = "mt_rudp" version = "0.1.0" -source = "git+https://github.com/minetest-rust/mt_rudp#88ff69e7a8e90a4fa3929fa173ed93e99b60f37c" +source = "git+https://github.com/minetest-rust/mt_rudp#feb966ec55874037a8371acb018cd739a42efd4f" dependencies = [ "async-recursion", "async-trait", "byteorder", - "delegate", - "drop_bomb", "num_enum", "thiserror", "tokio", @@ -362,9 +1102,11 @@ dependencies = [ [[package]] name = "mt_ser" version = "0.1.0" -source = "git+https://github.com/minetest-rust/mt_ser#3561472c60acfeda2dadb477a1da4afd287ab30a" +source = "git+https://github.com/minetest-rust/mt_ser#5baa62aea9af9ba7cc74823d07250fe772518abc" dependencies = [ "byteorder", + "cgmath", + "collision", "enumset", "flate2", "mt_ser_derive", @@ -376,7 +1118,7 @@ dependencies = [ [[package]] name = "mt_ser_derive" version = "0.1.0" -source = "git+https://github.com/minetest-rust/mt_ser#3561472c60acfeda2dadb477a1da4afd287ab30a" +source = "git+https://github.com/minetest-rust/mt_ser#5baa62aea9af9ba7cc74823d07250fe772518abc" dependencies = [ "convert_case", "darling", @@ -386,32 +1128,188 @@ dependencies = [ ] [[package]] -name = "nom8" -version = "0.2.0" +name = "naga" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eafe22a23b797c9bc227c6c896419b26b5bb88fa903417a3adaed08778850d5" +dependencies = [ + "bit-set", + "bitflags", + "codespan-reporting", + "hexf-parse", + "indexmap", + "log", + "num-traits", + "rustc-hash", + "spirv", + "termcolor", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "ndk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.4.1+23.1.7779620" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg 1.1.0", + "bitflags", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nom8" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" +dependencies = [ + "memchr", +] + +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint 0.2.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational 0.2.4", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg 1.1.0", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg 1.1.0", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg 1.1.0", + "num-traits", + "serde", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg 1.1.0", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" dependencies = [ - "memchr", + "autocfg 1.1.0", + "num-integer", + "num-traits", ] [[package]] -name = "num-bigint" -version = "0.4.3" +name = "num-rational" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" dependencies = [ - "autocfg", + "autocfg 1.1.0", + "num-bigint 0.2.6", "num-integer", "num-traits", + "serde", ] [[package]] -name = "num-integer" -version = "0.1.45" +name = "num-rational" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ - "autocfg", + "autocfg 1.1.0", + "num-integer", "num-traits", ] @@ -421,7 +1319,7 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ - "autocfg", + "autocfg 1.1.0", ] [[package]] @@ -436,18 +1334,18 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d829733185c1ca374f17e52b762f24f535ec625d2cc1f070e34c8a9068f341b" +checksum = "3e0072973714303aa6e3631c7e8e777970cf4bdd25dc4932e41031027b8bcc4e" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e" +checksum = "0629cbd6b897944899b1f10496d9c4a7ac5878d45fd61bc22e9e79bfbbc29597" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -455,30 +1353,168 @@ dependencies = [ "syn", ] +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc-sys" +version = "0.2.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" + +[[package]] +name = "objc2" +version = "0.3.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe31e5425d3d0b89a15982c024392815da40689aceb34bad364d58732bcfd649" +dependencies = [ + "block2", + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "2.0.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "object" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "orbclient" +version = "0.3.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba683f1641c11041c59d5d93689187abcab3c1349dc6d9d70c550c9f9360802f" +dependencies = [ + "cfg-if", + "redox_syscall 0.2.16", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e25e9fb15717794fae58ab55c26e044103aad13186fbb625893f9a3bbcc24228" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "smallvec 1.10.0", + "windows-sys 0.45.0", +] + [[package]] name = "paste" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + [[package]] name = "pin-project-lite" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piston-float" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b058c3a640efd4bcf63266512e4bb03187192c1b29edd38b16d5a014613e3199" + +[[package]] +name = "piston3d-cam" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6153024c02c4d09e3193ce0eb63abc585fda3389de375bbd41f059b91f2c520a" +dependencies = [ + "quaternion", + "vecmath", +] + [[package]] name = "pkg-config" version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "png" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" +dependencies = [ + "bitflags", + "crc32fast", + "flate2", + "miniz_oxide", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -504,6 +1540,21 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74605f360ce573babfe43964cbe520294dcb081afbf8c108fc6e23036b4da2df" + +[[package]] +name = "quaternion" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5598168e2776e6000e53955f69d238183160199a2c43375e3aa0f74bd34e675" +dependencies = [ + "vecmath", +] + [[package]] name = "quote" version = "1.0.23" @@ -513,34 +1564,288 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.8", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "libc", - "rand_chacha", - "rand_core", + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "range-alloc" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" + +[[package]] +name = "raw-window-handle" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" +dependencies = [ + "cty", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb02a9aee8e8c7ad8d86890f1e16b49e0bbbffc9961ff3788c31d57c98bcbf03" +dependencies = [ + "bitflags", +] + +[[package]] +name = "renderdoc-sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157" + +[[package]] +name = "rust-embed" +version = "6.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "283ffe2f866869428c92e0d61c2f35dfb4355293cdfdc48f49e895c15f1333d1" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "6.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31ab23d42d71fb9be1b643fe6765d292c5e14d46912d13f3ae2815ca048ea04d" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "7.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1669d81dfabd1b5f8e2856b8bbe146c6192b0ba22162edc738ac0a5de18f054" +dependencies = [ + "sha2", + "walkdir", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sctk-adwaita" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc56402866c717f54e48b122eb93c69f709bc5a6359c403598992fd92f017931" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "serde" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" dependencies = [ - "ppv-lite86", - "rand_core", + "serde_derive", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "serde_derive" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ - "getrandom", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -563,6 +1868,58 @@ dependencies = [ "libc", ] +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg 1.1.0", +] + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" +dependencies = [ + "maybe-uninit", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "smithay-client-toolkit" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454" +dependencies = [ + "bitflags", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2", + "nix 0.24.3", + "pkg-config", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + [[package]] name = "socket2" version = "0.4.7" @@ -573,6 +1930,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "spirv" +version = "0.2.0+1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" +dependencies = [ + "bitflags", + "num-traits", +] + [[package]] name = "srp" version = "0.6.0" @@ -581,10 +1948,22 @@ dependencies = [ "digest", "generic-array", "lazy_static", - "num-bigint", + "num-bigint 0.4.3", "subtle", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strict-num" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df65f20698aeed245efdde3628a6b559ea1239bbb871af1b6e3b58c413b2bd1" + [[package]] name = "strsim" version = "0.10.0" @@ -597,6 +1976,12 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +[[package]] +name = "svg_fmt" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb1df15f412ee2e9dfc1c504260fa695c1c3f10fe9f4a6ee2d2184d7d6450e2" + [[package]] name = "syn" version = "1.0.107" @@ -608,6 +1993,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.38" @@ -628,13 +2022,47 @@ dependencies = [ "syn", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tiny-skia" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfef3412c6975196fdfac41ef232f910be2bb37b9dd3313a49a1a6bc815a5bdb" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "png", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b5edac058fc98f51c935daea4d805b695b38e2f151241cad125ade2a2ac20d" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + [[package]] name = "tokio" version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" dependencies = [ - "autocfg", + "autocfg 1.1.0", "libc", "mio", "num_cpus", @@ -673,6 +2101,12 @@ dependencies = [ "toml_datetime", ] +[[package]] +name = "ttf-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633" + [[package]] name = "typenum" version = "1.16.0" @@ -691,24 +2125,317 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "vecmath" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bdd6034ee9c1e5e12485f3e4120e12777f6c81cf43bf9a73bff98ed2b479afe" +dependencies = [ + "piston-float", +] + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "wayland-client" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" +dependencies = [ + "bitflags", + "downcast-rs", + "libc", + "nix 0.24.3", + "scoped-tls", + "wayland-commons", + "wayland-scanner", + "wayland-sys", +] + +[[package]] +name = "wayland-commons" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" +dependencies = [ + "nix 0.24.3", + "once_cell", + "smallvec 1.10.0", + "wayland-sys", +] + +[[package]] +name = "wayland-cursor" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" +dependencies = [ + "nix 0.24.3", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" +dependencies = [ + "bitflags", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" +dependencies = [ + "dlib", + "lazy_static", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wgpu" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d745a1b6d91d85c33defbb29f0eee0450e1d2614d987e14bf6baf26009d132d7" +dependencies = [ + "arrayvec", + "cfg-if", + "js-sys", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec 1.10.0", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7131408d940e335792645a98f03639573b0480e9e2e7cddbbab74f7c6d9f3fff" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags", + "codespan-reporting", + "fxhash", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec 1.10.0", + "thiserror", + "web-sys", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a7816f00690eca4540579ad861ee9b646d938b467ce83caa5ffb8b1d8180f6" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags", + "block", + "core-graphics-types", + "d3d12", + "foreign-types", + "fxhash", + "glow", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "hassle-rs", + "js-sys", + "khronos-egl", + "libc", + "libloading", + "log", + "metal", + "naga", + "objc", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "smallvec 1.10.0", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a321d5436275e62be2d1ebb87991486fb3a561823656beb5410571500972cc65" +dependencies = [ + "bitflags", + "js-sys", + "web-sys", +] + +[[package]] +name = "widestring" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" + [[package]] name = "winapi" version = "0.3.9" @@ -725,12 +2452,30 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.42.0" @@ -812,6 +2557,67 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[package]] +name = "winit" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4755d4ba0e3d30fc7beef2095e246b1e6a6fad0717608bcb87a2df4b003bcf" +dependencies = [ + "android-activity", + "bitflags", + "cfg_aliases", + "core-foundation", + "core-graphics", + "dispatch", + "instant", + "libc", + "log", + "mio", + "ndk", + "objc2", + "once_cell", + "orbclient", + "percent-encoding", + "raw-window-handle", + "redox_syscall 0.3.4", + "sctk-adwaita", + "smithay-client-toolkit", + "wasm-bindgen", + "wayland-client", + "wayland-commons", + "wayland-protocols", + "wayland-scanner", + "web-sys", + "windows-sys 0.45.0", + "x11-dl", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "xcursor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +dependencies = [ + "nom", +] + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" + [[package]] name = "zstd" version = "0.12.3+zstd.1.5.2" diff --git a/Cargo.toml b/Cargo.toml index d14cb17..6b38982 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,22 @@ [package] -name = "hydra" +name = "mt_client" version = "0.1.0" edition = "2021" [dependencies] -mt_net = { git = "https://github.com/minetest-rust/mt_net", version = "0.1.0", features = ["conn", "client"] } +bytemuck = { version = "1.13.0", features = ["derive"] } +cgmath = "0.17.0" +fps-camera = "0.1.2" +futures = { version = "0.3.26" } +guillotiere = "0.6.2" +image = { version = "0.24.5", features = ["jpeg", "png", "bmp", "tga"], default-features = false } +lerp = "0.4.0" +mt_net = { git = "https://github.com/minetest-rust/mt_net", features = ["conn", "client"] } rand = "0.8.5" +rust-embed = "6.4.2" sha2 = "0.10.6" -srp = { git = "https://github.com/minetest-rust/PAKEs.git", version = "0.6.0" } -tokio = { version = "1.25.0", features = ["rt", "rt-multi-thread"] } +srp = { git = "https://github.com/minetest-rust/PAKEs.git" } +threadpool = "1.8.1" +tokio = { version = "1.25.0", features = ["rt", "rt-multi-thread", "signal"] } +wgpu = "0.15.1" +winit = "0.28.1" diff --git a/assets/ascii-art.txt b/assets/ascii-art.txt new file mode 100644 index 0000000..51c82fb --- /dev/null +++ b/assets/ascii-art.txt @@ -0,0 +1,6 @@ + _ _ _ _ + ___| |__ _ __ ___| | _| |_ ___ ___| |_ +/ __| '_ \| '__/ _ \ |/ / __/ _ \/ __| __| +\__ \ | | | | | __/ <| || __/\__ \ |_ +|___/_| |_|_| \___|_|\_\\__\___||___/\__| + diff --git a/assets/shaders/map.wgsl b/assets/shaders/map.wgsl new file mode 100644 index 0000000..f6919a9 --- /dev/null +++ b/assets/shaders/map.wgsl @@ -0,0 +1,34 @@ +// Vertex shader + +struct VertexInput { + @location(0) pos: vec3, + @location(1) tex_coords: vec2, +} + +struct VertexOutput { + @builtin(position) pos: vec4, + @location(0) tex_coords: vec2, +} + +@group(1) @binding(0) var view_proj: mat4x4; +@group(2) @binding(0) var model: mat4x4; + +@vertex +fn vs_main( + in: VertexInput, +) -> VertexOutput { + var out: VertexOutput; + out.pos = view_proj * model * vec4(in.pos, 1.0); + out.tex_coords = in.tex_coords; + return out; +} + +// Fragment shader + +@group(0) @binding(0) var atlas_texture: texture_2d; +@group(0) @binding(1) var atlas_sampler: sampler; + +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4 { + return textureSample(atlas_texture, atlas_sampler, in.tex_coords); +} diff --git a/assets/textures/air.png b/assets/textures/air.png new file mode 100644 index 0000000000000000000000000000000000000000..e2c487214455f4b747aa431837f2348fc5ef12c0 GIT binary patch literal 225 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^PC< zb~5}loW1onP=vF_qD8!Q)5>euu zpPQSSR|4cRFzi{kX(o{J^mK6yu{fRl;@;2C_RInkyn|T|v;`bhnYHVIy}*U@tp6u6 z?Bbq~xhTf9$8C?^fiwnY%|_QAMh!iM;|y!oDIDc?R#6qo7n*6p@L|t`&Jf8)6_DYc Lu6{1-oD!M)b+J)ola;L7rzm92o(cOo3RU8X@HrL_lT>4Wuo~}D7^r0izX+QY) z@zC9n<=Www5wMS&3jpsQmd92legF@p-Ei6tkb{Mq3qUX0Ck_B+75T36goY;#A@Aa> z<^#}yKBSv%zoQQS9*yQ~fBLFPvADUTMi+>?uWCVY>d6huC04~x@HCgwR{~d0X z<3TsbKwFIwld-;%AuBiRu~JYsdqir@Q*$@#gc2tq05m8)Y~I7!Q#LS%FgnZsw{7fO zYm?-bg@`V+`aMdz$OLtpLzD_-`I2Y9SC?8ig&RtYF?uQy0NBFI2BB}!GLUD}OsRp- zYm8aHXv;C8P`^hfqKN2DvmnElQDk>j8MQVQddlsCpfN0v2mt=HJnk^qSF#4%xjqsb zi^T~5t>WjDC+nG2`F>$8(Kk%vtzF=LG86UTWxYMMgX#9cdn491pOVlS)A_X zWh}}u{(fRnfPW_^O2d0Gti?)P*{Ww^gZKc*AG$5{1pMy6Y393q>rY|cgaBY!GUQfV z6I(`G==TAo2E3=@27p%aW6G7SUOCcWF6ti?%K9yAn3xX0RXJ;XnqE*Alcs7py`U@8 zFfnVa0IGNb{#wootpDu9gb*f)Q5ke{#BQ!=n_nn(XxlhARsgbnH=g%BfykBg_K5W- z2Vi>{?%Kg^tXSD9-W?GtJbn{10BK~mn0dMS7)7l=K>*_A6qgILzpET!A6uybZe#KI z0icC{n=VNNQR`0(0OlrBzJx}J&ZyGfCUp5^G{!EE9e})q<-#;v(WbK!y$s<*Lz7FF zilS`LTlR=<7*_OrsYvIIWrsWKMfc0HO7#1S{VMD{cpS zPA~w>?j5} z=s|efY+6(1y`Xe>VWQIwPlc}>Js-U;VLckivUYR_0P0x(zR^4Z3*U<>o&fV={;;rL zd;sF-X#F%vY5H4!Rq2s;z(%-^HFE*3t-|yb+46`TDCm@;J8>dTz_s)%v&NskZaP(? zKxq9&i9cAGCol?uC%C&}7t0IAjj%AQSDk^G(Rz4TtUnQLzu2#~yMHYV_ zyO!%0FJ literal 0 HcmV?d00001 diff --git a/assets/textures/bubble_gone.png b/assets/textures/bubble_gone.png new file mode 100644 index 0000000000000000000000000000000000000000..240ca4f8d4edca6d5905acf71bdd9f88d4bd3127 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kP61+gajamnSrtAhou#e O#o+1c=d#Wzp$Py;d<%g9 literal 0 HcmV?d00001 diff --git a/assets/textures/camera_btn.png b/assets/textures/camera_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..9327dc4a679e88a7cf15880fc926dda25a4e19a0 GIT binary patch literal 1859 zcmZ{ljXM*F1IIUcH#4)%)XMu?MpNg>%V?OFt%YsG+zH!ooXh)5bZE3i!(uVXZea~k zUdjo-%iCrs^sYNa=B2L4=q}3L{qzUi^L)PF@AG{Afp2k8fS<1RUTpvXpiA(_Q+BuD zYcy4NJN{@hZg*7Dya>UXnj!Cfze=rSe_9#^j> zkd>9?5P$lIG)8oCj6+gtT_vM$}VFF9i=sL}u8?)~qlbV0G-7}Ut|zmEBD^aO++ z?ZuREvV~6Xhu2`=o;mNrl^pYou$PN@hPH}@tM&Zt*%KNOci%_@U-%bY-{Lx9iN+B$ zP0ST|QP0^-$J(`CD1_;nOW=f89l^Ejo16EpaFePpr|J#&)C4deUpft9!l+>bIc1gK z@#*R}GV1N57M~2)rq!m4<6H=bqY)Kt&)AMAvxgqzP1MQn#TUx@aYzOF=P0UF_0ECY zOKSBaCGA(vzN(+3|Ms>X!yX`k(J1OA0~79)XMZZNz>p5n_rs6)8*bc)rF2PaQhMZY1m%LG< zmMUBlc>Wi5;!}pDucJ}IVK!B#2-%dw+;q*eej{1-)jPQUt#8#IDb_Nr-WKx5rB8`; zw|s@uM!du#dv8PV%B8`|t;=b3R}5Cq7~hkOO`qY@vGo=`buWXdE8l!M!_G`leVz

I2q=#=03=IdiSIP zF|54;BHY8}!B<^CMQ^Sn(SruBZzO<0)WKvI*7 zS<0QtZsO6-ZRAwuO)_Y0Agm3hJkZfyVXDK9ZY867+x4cf;(ZfJ)V1n`bses;tq

q!N zsg_#+p%L}pUC83)bXdt zsP!M`CyL@B3nyv3!j4l2EJ;K9+Q-Wx+)l@r0UKih+>{`y>pD~zIZ?9D@fBY!Cb6+$ z(!6jRH5^-uMzWO^tu_N)q_;Rn;kC{MD=w6_4%9y=IG*qNuvDcx1=_d2bKVX)5hHEO zF1ZXQ4R;YwF49{o)hvBv)P$2fC2wJEJffciW#crTGPz{cuigvn=h_ zqlw>BH81cU(B|`RSE~IuL$WV* z8)woSH59heXf2_^$KcOOlRQ0Ju$`mTSjk_BuR)o9HI{aVZHAE|kp_0<^I#6%puC_vEZxp(+ettJZsr8IQkVA*W;JV$_dCK|C!7KVkkk5wwzW z>`rz7PqHkHC|bvF!#$sx%QcXj8Aj8E=E&_9KlQHSd95S956YX1l)1I%4V?jUoAm(11Q^+SQe-E3=>81?EQ^>xiH3_Slys4j?mQq{9f)v&CC6nr!L<Ev-?~+u3<>fMmhS q|M8FiKQ>~|V_o+4kG#frVTP$m0*-x0uSx?AVDNPHb6Mw<&;$S-YA!PX literal 0 HcmV?d00001 diff --git a/assets/textures/cdb_clear.png b/assets/textures/cdb_clear.png new file mode 100644 index 0000000000000000000000000000000000000000..d5df4a067f5e207257eecef0fffd4f98cdf88984 GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^3Lq@N0wg;h=h*-_(J z_(MZPU%!2gOoPmsCrMqh8^7H8|NlwSuOr7dus=DX8oK%UrR*7Pf`^w!NlBC*Si$Tj xYoH)>u3+61;WK$w!4@ewplLUl7&N|CO}ullg(ETw3ETp)z4*}Q$iB}B>zE{ literal 0 HcmV?d00001 diff --git a/assets/textures/cdb_queued.png b/assets/textures/cdb_queued.png new file mode 100644 index 0000000000000000000000000000000000000000..6972f7fb8328503589abfdb65cec902640e5f816 GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@o&cW^S0Mf6%)`lH5~`<4|e%426_ z0Qrn1L4Lsu4$p3+0XhDjE{-7;w~`YUNEjTF@ RIDtkpc)I$ztaD0e0sxzGGnoJY literal 0 HcmV?d00001 diff --git a/assets/textures/cdb_viewonline.png b/assets/textures/cdb_viewonline.png new file mode 100644 index 0000000000000000000000000000000000000000..ae2a146b855715506dcaacd5ec0fb55713762df2 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv{s5m4S0Eh~9NbheWx?dW>-Vm$ z-@z#j6k;q1@(X5gcy=QV$cgiGaSW-rm7E|E(%|Xo$v9PiNr%#+6&g7jDlJPKJOXY6 z1Ozf}ZgpxuS3das?*KDHmN@U5yct51fi^LCy85}Sb4q9e08d;#XaE2J literal 0 HcmV?d00001 diff --git a/assets/textures/chat_btn.png b/assets/textures/chat_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..be4477d3e5dacd8c54ce1a679bbcab34684e1930 GIT binary patch literal 873 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H0wgodS2_SGreY`05Dt#eH*O$7&H|6fVg?50 zjUdeUwfU_lP*AeOHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#_B$IXpfN8zT^vIy zZoQpj?=dw{qTPR1TZBZDgo*@*tJxNgtt?MPTJjnnw6-l+D7D(tDKm>xF)OR9BdSSb zdYhB>B890ZHZ3^gBG7W;U-qlZYTy4}TKMo!=jZBo75abfeJ-%PU;eKA{&h>m76B&? z81bL&F3%^u57`smg-pBetWy;f@y|1Fw`!P1@`czUFE9h6Jyf zJlh!kX5C@6O48XscmA>-Z^z5}Gu~A4wZ;95+c!&SU67zjy==J8zw&RbJ@?P53)gpl zJ-EMd>Ky~qnq|5nU&_*azSx?%+-zR8Bm32i)bNfQV#|ErC}%B>ZOy7k$eNkh{{F<; zJ?0brZ;E`iTQaSE*}Q&}-#yt6rgm04)_$?RXf<#4tb3b|#$Q>{DYe|NbF+u?<7Mjt zU;SbEI(r7^tVx!=W`>DbufGc$$A}sFdIzx=?Kb8A%_$kpIb*Tu&ig7+Gox4LpV{7E zI9=i1>&Xn96G%iS+z-sY!+PMS3@gt}d*yFW)fa@kxaR4_7@FE^vhSP5ub@x|*6XKU zRlU^L2xN^h3BCJGa_WL6C*S=y9-FV*zChuVXrpke-J!$(l!b#FPJUUZS8U>wqr~;% zN%@kvMEO>r^ece_m7EBuDAU5?sb2t$cD+0pJ%>KtPVe{CGksp z`%KNxos6rJ-X7Y^$Rd)LoB3dC<$upT&(0d$XHsscayzqIIj65yJ?xW_OKP1dkIyNfM37Z?~nn^63dD`LUroi(gSW=l_PX;`|o?^q>AhqZ<7 zu7=b;>*<>tF6)_}*?huS&;Har*LkItPMrr^+Lm*{5*#q;9r=G={+E?h&@w@WiNK7( N;OXk;vd$@?2>{tKc_sh= literal 0 HcmV?d00001 diff --git a/assets/textures/chat_hide_btn.png b/assets/textures/chat_hide_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..92a8ece4780911a2c01f8df81e4b1f5bf8123c7f GIT binary patch literal 1089 zcmV-H1it%;P)MzCV_|S* zE^l&Yo9;Xs000BPNkl96hBS`Bt8JV#I~5@ z1He$+@y!8186$XS=x+q&CgYpB1#ktXRdy-<1(?^UJMqt=W)pzz_&un?hRSZlKaNFW zJY)7DXghv4ei7rFPW2;i1BT-#1#JkJ`v*wSQ}IPz4%D$Ev$Qgc8B)>RJ%Q%15j^vIbH}gIIqbWANp3FGx!Q1cl0O)(c?F9gx@Ao|bp!f3z=K<*c zy2Eh*`af=Qvk=N$^<^!r+y;=N=nV-#u9`m_06C{Tp#V_s_4y5;fL@>50H#+2P)M)O zZ2-Xah5!oc^|=UOl#HNax9qV2pe)6yI2FGYGumI?qS6ckEAd-!C*k!*pV6ua?0nFU z8^rCQPOFN0t2m`G{l-CI(9ZfQPHF9G6{m!55d@Z3apE*tyIR8;VL}N6R+lm2B>oV; zi^7yp#)$1zoH!~i-n=I4Xw|AuWq*N`{Q~M&?ZQ{$cgx-Qh3*$nzv@2BlXLExUAvm$ z$uE`Aiu(oBuelquUf*hT|R)^y&JOmfg z0ALGV5Wlx(S1(%b^J5d95x-gN2{e8h0IbJj;y1s1`Cc&bmjgf>28iEhbOjt=27op^ zB7Wa-IOzBk0M_6>@%w=zfyXBRrf`q={X}>0@uepe}#HU0b;i`yJwDZhju~;k?i^XEGSS%Kc#bU8oEM@%z>JFo>37Chu00000NkvXX Hu0mjf?1k!# literal 0 HcmV?d00001 diff --git a/assets/textures/chat_show_btn.png b/assets/textures/chat_show_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..b260d252347d0d5c157b19a8e30d0dfa2defeab2 GIT binary patch literal 1082 zcmV-A1jYM_P)MzCV_|S* zE^l&Yo9;Xs000BINklD1Bg^eARmJ&dN(F83lj0MtIXiOv)CdR~& zSQrb4F~(?OX@y!46FU=1{{w3i{{SiY{yaFo?hbDcIJmo?4IDS`?j4I^XBPJNOf_WL zx%b(*nRjP*PJ|Fb2qAGJQOSy&uF)bJ{RFXMA`TlGuW|q&9^ab)GK&wJN)}9+*uT@ zc6$#KM!k$)o8jNVmeKqi{#yU$Z(zo#mvGls_%~5dS3l=u@XIR&MclR#{xxKcX46=6 zHvX?+R`rS-QHS4-jL~EUt4^oDWu%SzDmtSKztz`V#(5U7ci0ps2^|&YWT^a8y9P(71#f( z^x)avgt~vet_DXwRTJ-mQJ;-Qz`=KI2lMJ0ZieQc;VyNT7mi_a^NI>({wWTKDcv9vT3ZMWApa2Ts zG{{Vl0w{n2D1ZVeAO-@;zUA=3kru=EOGTY;rNMu0#&10!?1PbxrU_272P5qP$DNc^ z__RG5qW}t^fMg5E`(AcSm;hh`+o7hx&LiIE2Tg-rO^&lFV8m!{0;MJ|N*)S#V z<>ncrFy!k6E)`TTX4I>AF3}Pz1yziyzr2y?2~aTUNWrLjUG9t6AyC1t_3+13o8K+& zCJz`6y<^=R>!FAuHj!d}=s{X`Tv5hqaD*;M!M*TO=i3pCEOE9j)0s>hRS#( zk{kg^3}3B6n=1fMM3O5Y`UQ_z3#j6SNRkD-7D=*zw<1Xv@IfTW0tO{%7|$X2?- zG7x6;t5)LxG9*h}BT9nv(@M${i&7cN%ggmL^RkPR6AM!H@{7`Ezq647Dw^x*;uvDl zdv&5C-ysDNR`wUN3aXhN`G*en+ID8{dd$a^cVxvvv0cT}S}OPaZ`_|ObNpn~?u@nR z3>USz71volm%NeG6E|;4you?G6VW{v+XeF48TUUq%;s*?pd)_Y{I(Wz$E~!fLEptB z6Ff9MHB*1~dTN$3p0M2g{N}8nPl_#D&6eF*8GWPnr}BdIXLlRcPgv->E~%&Rn8bD6 bc~2P&8agD_+1z&rI+VfF)z4*}Q$iB}tx#!I literal 0 HcmV?d00001 diff --git a/assets/textures/checkbox_16_white.png b/assets/textures/checkbox_16_white.png new file mode 100644 index 0000000000000000000000000000000000000000..0cf0f3e659a6f4de4e7e871dfd14250cb5cc1302 GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa4)6(a1=3HSK7IcD`HL4Xo`3<6 z3jtGds#XD|IZA^3f*Ir#ln&gz|4>e<-x?@p>FMGa!Z9;B;Q*rxkAg|Ei(!l6tw0{p z4D$m@2VU@q3gnu%tO$7R@!F$F_ literal 0 HcmV?d00001 diff --git a/assets/textures/checkbox_32.png b/assets/textures/checkbox_32.png new file mode 100644 index 0000000000000000000000000000000000000000..f5ff59a3a0be6a992d2b2b8b60326cf01bfbd12e GIT binary patch literal 436 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmSQK*5Dp-y;YjHK@;M7UB8!3a z8xUr!)F|8wWJs2{MwA5SrEaj? z(fW3Zq2Cb$0ayFJU=`J%W0UxqRLvLNWaWxlbwZ@$bil#dJJwFOJeJ*Du;E7E+|o_H zb>ga@s!#RUZ%94urKqIZQn6oT&(xqO&84DFdwTDSW*@M8&VSfA`OUU!11YIGHDPQ^`}mS0^4%CJ>24B9Tbs%t&@W7fB)_WuE6h zxWEXBh};!LQ58i|iO5e{BFsFUm=6*WDYGp5SpPyPb)BZ^YpwM|(?RDF;7GovEy6hj zXq2ycF2d9Uw93~sMVNAc&hj;!v48AXRv%t zRaL+DgV{MJZ}h(G57}%{h57P+XOdi4y;8Y&M4&YoK!VTa> z9>NUZO&-Dv;8h;N3gBHH!U-^nJcJQoGo?RED0k=8`MG?j;L z0TL0p&GY;_b|M%*&+p{FU?>mmD?;^UdNZ5N-n1<-cVIu>&;fRr{bwx5!}9?Kt+V$T zuP-)U^M^DA7`)Ejcf78+kcZO&jMmwQjMs)Mc{mPWyv{y!ye3@A!~X%Sth1YpcZh3w z_!q$1I=kt3HM?7#wRig__Va+JYvp}O)AYlWc|uV4`8M`10j>38nx*BqCCZNXhu0IgZ9fe^n(Ci9{yH9|36VDV}Z;x&QzG07*qoM6N<$f+F}-%>V!Z literal 0 HcmV?d00001 diff --git a/assets/textures/clear.png b/assets/textures/clear.png new file mode 100644 index 0000000000000000000000000000000000000000..9244264adcf8a710ff13a2d684f148f997f1522f GIT binary patch literal 708 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrVCwdCaSW-r_4ck|p0J|`+k@?8 z)4T38Ghetp_qK?~6E??3JeK}D7|j>(if@>5FNQ(xtQ%9xq#I|>oJ-rk-tWo9fB*MH zp5A261T+u{c%448b?emavpj!@3x2dSE|*=GYrgL7A+xn2b!l~{&a|J|bNs}_tEEWpk`5!2*`a}1RyVnJUKYCsTDmAJZ691N{Rw#iPDykKZKfD4SDBXYZavSfp zt(M8LUICfU&F8YHzp0s=(DY%oUz2h9J|Q20x{sb8K$MJ(p@+4@qz<4 z!kg0dK3Eysi%9);Rd;NiTfc_o`reublauX^hYkL8bi5ZVT=BywU-{9yDV`H%&hFSD z{eSy3XBU}c*&BW+C(O>xi5IGCE-m?*7^bhf!nSDs-Ve5G964XH7nBIy_{nX@*CKED zC9J9A$E62L@3|g1-|-{rXX!rIBX13O=8G=aFLdP6;d1{6XTq5t?lu(JC&Y2TP@!hB z!wW0ribzTW? zv>WHHXDQnUw9_l$Ihb?k|95ulYSoBmH}=bWKa)PledlLA%OVzTzIe`-^(=?Nn=}vK z|5|oXdfI~7>hssAan;KT<|{qg^yu`QKY#yx%+Ejmf9+EvCB5Qf=OwiwTl#JLZgovQ z!0-C6bfNb@zk-X!W`9H8=%_c!chCE&^5PxeZU@em`wuKW9OwuSX$khe@MP~-NmYTm zX3qx;1G)7Yj~~m(^N&w8r?2p_d#V`5`bmzdPwkAe zpvj{|&$K|HdEe%pRQz0!G=I*)Unh8t_${6a%6_ap_442guKs5dp8fI@W&X~-p1gnR tY#WJB3qAxqRowT;(ZZ|P@u4IC1?lV48SBK1&Psy3;pyt?1cVtfDq literal 0 HcmV?d00001 diff --git a/assets/textures/debug_btn.png b/assets/textures/debug_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..ab210a6a48d9183c705a39519379d69a76627ff8 GIT binary patch literal 2484 zcmZuzX*3%M7uC*8JJptr;nmL}IH(gj#}1 ziLFF!oo|L{DIvB>qSO+MHg-BK+A;s|vjNJyNux3fhb z>Hq%akKZ57P!s0QM{+#&n!WpvKYDyb{A-?yvctwoNPO4yFOTh}iS3U}U>y8roLgj2 zT!LQ=ULqkOK|eHt5F6kZh1ZXa38t@Ef{qpq?QO5R-#sS&<6hKc`aOw_$ZN;HPbXeu zMeND_Lg!LvisNeuV%9{7d9O{&+udp(Pu3WL6^~nH@6{!C)bDY5ig#|6pu4;vnd=?` zNnLG~^*Lo(6_ryeY9h$bdBb_j{g;RHsalr(c7x|ihqW^Q0~93&q=hT{>J>6ghDSMB zX$2AkWYV%5=!^j}55cS&#ehKJ-UL>{v{D)o?co*nX(&YGwuiEKpBEykU2Um>UOFLt z{!V50hXyrHxWO7xZdstsnk-yV6;a5k{ZYoU4am$}fzv>pYKO3B@12JyS*?6B^a@tL zX^19cy>tpVmTdWFKijU(L)NP7TB|(0L_utd!0y<*0)eqzY60n*cZ>%@(7{9$&`^z3 zP9a6KPhSl+tROQEdry$Oo+GW4na>u~yzX}@stk{ht1N^-)xS{TvSgggn(*1q zVB)vx!3HC{OP(MzW}~ea%dLX8FoAL;eH9%8p2hH=F0Zo2RRUrHH`kZwenqtfwwXGz zdR_0YKGy(EAGO+?v}lHzX$nk-I!E{DN<#;%^Bt47tIK(_(|)CE#x>7*UdC*~Xm{c# zxI9&$x0&ST)a0Yzppz|~M%-H!B+VH0Yu<2|^?T_2VpM%eP(|1UV`RmJI=(hp(xe~E zg>#z0aH@A;#yj&`cUfgqPx67gnNE?}#IFd1ufc%nQ-HiqL^CqUY3WN?+#3(wUs`4p z)Hp6$ioxzivBZS1{A_Ifw&FTJobmSEPxpFk?s}H6V2MJpbtrjn)v8ua>P=J7oe^B? z_B~;kVwguTNl~5i7v?p4*4yUOBYe?fv(cA~w|FByvpZ2*m)NDforMsK$F&z&AtDc8 z=et^sBH$dpJVyUSsnq0(c=9-9RMoJ0>)HrD17=z5H8!3>sJc^#3QlXk}OP$1QHZJ3#e6wFJ_!HtpR;3j1w())(zT{MW+lUlhoF~qBJx?{5 z{QPY5W#HW%h*qLk0R{IE=i<+%OeS%e;LX%}M=}gGMBPO1Two04htmx!JRKW-+39_@ zF9xpq2v=7_M8{6zE#(gTh0WdI?#gk0{u0t~S*S;4Rku%k8fx)mYcak7BGSS>AscAA z!k||O?cHWFsA*Uc?6$D6SGexiQ*jx%CV9@u$f-Lk&03**NuCd~T)%GTFitC`;LK{;J^xtniv=+C^9OA{dNs zI-Z(BXU1DgJs|=Kx3I3p2-GfQ%b7TQj7v-g4CaO3*vTu$48TmxUHqGs*+u?wEin&< zMq!G|hr_hTulG`i5e+Z?P~|^1Gcn&(_-ZQH%sBxGLZ-yNGzojl8(jH8B)=N+8}_TY zRL@U_jYC$v-@SwL>pyOCR-m(EWqRvhf|N33`t}(szV)tJRD2&I+w^*YH@j2y1V|IJ z!lh>*W|RV&*6Lj4za!7So+2>zKvt1A7dgAk%BSjYT{a^ya=o~_?hJTotG3$2Rw8!u%^@FLkN{nu>tVU~N$u_S# z*WiKy#)!7zgsP9l?e^ezf1T!D;g+^fOLqm5Pxufv9+bP@bR2yj1^UPyig1#8%44|N z6-SWN3AN6Mxs6!h{!r`nVX@I$Fwhxp_=>jHwnj>IB;sXv!IY@>s>C2#t@^=~HF07< z&63I4=aN$2Tsd9EN@&Xq391{~YMbciIkvBRX@xTxS@y4LKK1i!SD$-bhR>|~Dskn-^rR?{+Kd5swh;0=GofDzFMINBW zy(agrCVEk-WBss|_6bg;Gf+i=2#k$FX&sWozjnx?i z0X_@*He2}fyuq=e#Q@wHsUQ@gWr}=Jpl8$RqmVvq&;E<$!QDI?dF$zb@V=kB95|qE zGRZ^o-us%vtad&&Pa>HNw)}3aQg7Jxt9#~j4O+w5YXrn#HL{M$gm7y8AFS)VaC5a zh-O|z?k7V9FZxxLt-$GA&#)XJDj1o0x{k*`k$?C+*R>|OC#j>2PXcc?d$mJMtR?e< zm4S4}hu0Q;jqStQaO)n5is{JoB&+4{$X^9m#Ir}g`^5Lxz|w<^PhOc!_p+XwT*FG#dzVh#q-V{Wpi6(464d8gtt7?RuYqoRsXZGI9 zonH^n$En+g_m_eVD&)k2K!ye#m vx-KdSdGBZbuGxaPIils^{{`gCw_|pLS{f_KE0>ObED3w~4cq!_w;%iikL1-n literal 0 HcmV?d00001 diff --git a/assets/textures/down.png b/assets/textures/down.png new file mode 100644 index 0000000000000000000000000000000000000000..c290d3a453d28d394d9798f803b22caca57e48c2 GIT binary patch literal 1690 zcmbV`X;{(=7RLW_amgk1W`oOh8S7R$YFe24l!+FWs31`)1{G*$)y#$#1*oXNrALh$_pXWU9d4K0T=Q%e+P)7`O z&2<3)FhCwfpaDQ*v(*4}pqr*nC&)Gpl5`jurlW(M3-|`NP>-HU0s!qZ-%7(h?ZMb4 zG^6>Sq+t@y)9A#DB!Et*J6(v6O*%`YlAIDQMswue<^Z5&hD7*=rHsnPkrXV+^yMGJ z=n4V)pN;OsT9-3%E-3dfOeZ`yQ8(aw*Y3NToE)r>Wgu;&=tK+^5^DXqTAz%VrWI8$ z0%xKB*w*LYnR_zjeGD{vVo_bPQk?L0quF(;XfdN@vFJ<2d=nPC`P82gBM_b0JoNl@ z-BmpKRpnBWAnM-X^<9FfB)qWQUmP~ELrhMzU=Ydj2Sk=Ep>o2COouVBVPk$Z?=>GD z68MBsVGP&J7^?$l*Z@!lU<5!80ScXt!fAzMDxp^dFdutQSFLmZJNlo!{}(>&1I|8q z8M@{(ZfFxX;5~}@I4bH7C>3VOMrz^J*9+Q1OPAYrQv+kM$7<|DRN=K?zI8eT2YXlI zUX~4a5VQ9V9sQYKpGaC{sKEI$ww1-o3pY?CE9P|YHUz!a+Ma|NBLq5AmWc7SL ze}H0OYB*13dt@#r$FMHg#&G+3=WXWSjO6%vmt9A3D}Kb2R5J~~Jf4(JI6H-w<7j`) za~-C&MZrPZt-dc}2F^4dU7neiHEqscVq9?!`$AWFw#xTje8ZZx6fc6Oo}{onhhsa! zx*LQ*i^bcKm5XI#}Mh{3<0VJ>c%^daUmegYBa=96z5F32&O$~bMqOQITkHA1o8~52C}SjKhh+#nwVkX%<9h3$uh}tRmv&Y zi~O&X$73TF{U_JGf@Ujka90pR+tWlVU>s}&ao^J9*(EHq@?gXouVx|+-k`-+O%Rd%ZX`C%Ns%YNz2>z*@gXhSr(jr!q&}F`b7UMpKRPmIi!oj}R(Bi!<|FbLC3uP~n;itZiNgjvS3t`-50qQ? zQayJfet{bDF!+q)9gh#C*%nlm_0Kzq83>+YdzU}j1J98)~tyg*7`d+K$WZBlgJbP?+j?q)$K#z{->o{<{(5;1nJp26E z2{&}3BgRm2rMw67!)JY4h&plb{ed91TkCC}Q0jV15iSgx?};9Rk4@lBQg4=KZu?Qc zZGru0-!a+8-%Yp)b$$ek5*j?ddm+}!xZ!rN;fdtSo&%wMHnxPT*Zy@k*V2!rRzR5E zehqI|bqjjypQUQvwl=O3N%}Y}!jcI@QXi@(X*y?bO#Q0Fzn(7G5|t%&hNyAX_XX=O zYp5ApeX~#VC|AtX@liR&IOtqDwa#v7QhqLfKhsG0d(9*I#|Q0%HqeJ=v!MgO@K%X! z7;iMh=_$z$>G^|Oe9wFRA;aiW78d>ni5rcQJD|2C1+F@j+%VpgWFGAH!mGLvr9=7h z6f<-1*PCooB>7WiV(U*G`nwdDT)0Jv*@RR(F>iXYz&n8S{3hel;P9QC;~V1#1Zc3q zmSE{d%HRLVD6-P9Cw{}~#=&l8?~YBFr^1gr|HLVw*ezY*!;V11m6!i5o9x~b9m&dS z)R053w%QaMopif1ht>vj_d`0ng3LZM{|+5oL*YKP6YmE?%~ey#u?>B0ku>W=yO_tk zxC?gefWdleIw3HV%(b=4A(S+OmK`FO?|?rig%TEX>V`#XDn$A10MZ|Ys5?x!{vX=2 B{#XD2 literal 0 HcmV?d00001 diff --git a/assets/textures/drop_btn.png b/assets/textures/drop_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..4403ce67b8e2aa2f6505f45d26f427ac720ea793 GIT binary patch literal 1269 zcmVMzCV_|S* zE^l&Yo9;Xs000DZNkl1dQGG>}wC;kLAtEKBa6+$dT?WH;JkCu$0GHFsSKQ``CU zFzf6&=iZt98{T`)?{l7Z*}1dd&%Nj0?_AFl1VIo4K@bE%5ClOG1VNY;tRYQ5{iIpr zV)Ps;IY%`3q8BJQqJfnp`ANI$!*p?!L!99^O~bDoVJ$KHqbHSSr-o@ow^IYFX*T+L zo^}qGjjp!Cw39c+hGterDgHX;-=9hJN*W5Ri;jSda`*CNXB_@^%aT{Fl!=ajUFiHp zC+QhQPji+r<0`wNBcK7m2v8u;DN<8LPw_rO+6VyG0BDGsfDF%&Wkic|ll}_h!5e(b zKSuO-d4$HO3WyUYPCZ|8LyI-S84eit{WO;hRh?|5hH9##E+9^v4eVz?d$7mJae^dC z-lm^hT4xz#4@;;nH46k3+ZI0HPwhTm=eqXuMc!nY65TQZ#r6VU8C{~NqK!v=(XA8^ zC(e2f@bg5MC@{#5iQevvfMV+cptVAD%LQ}-&>{jvfC$iAJ-wW#mv&C`4zF_3Edlie zGt4Kv#Ht9CN9HKtYbtY*_jsJU+!avdcV1($TV24<-(*-~>mc|GmyLZwFxS}40(+;y zS{`B(rQJW zpDV?)?Pb63kfxyJ&I?$;KJ939jL+E3`e_TO;c4SUA;-S*%N=55H3d(EVbPf`-?TzoAUzkZm0=BabSTlr>Em@amIT!DET3wc`q;z$GyImc^7(JVxJ6n{N_)7+ zCT8(JwB9~MYIZAo?$uTW;e6SO7;8Ds)xa&yRgTZ?br=pRS342rf=LzIXjLBh8?>^G zsySbGDL0iNH_SC7&+|MMv6m4>*vq1MyJlPHJHh`fRjnqaTokZWnQJ;c7n#^M09qH|8*D}v4+(NJKN!RM165g=Va20=j(1VIo4K@bE% f5ClOG1i{aL0Y~DMOhWOm00000NkvXXu0mjf^{Fz> literal 0 HcmV?d00001 diff --git a/assets/textures/end_icon.png b/assets/textures/end_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4fb4d52a0d19f421424b43478cb3e4d0d710c1b4 GIT binary patch literal 908 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&T@COFaRt)v+_m00B2eMo~fS z6%98wG_dVX>eM~<`(J;`ie-1?efP~wF;1@*E6$rSg>~l~1&$^ds-LJY(zBy&%Fd^~ zn3QQ-1v~2V~&XQF^2y@CeMev#WyyvReX;rPq$!~zSrCWaF^+S~FO&M5*zmikdj6r+9Bezj-8^Y(^i}9L zduMX=+P&N-D=@CL=yx~*LQmNoEdx^2uj iVhWGiCWRvp*sFI2JN@~Y_#T-07(8A5T-G@yGywq89R<$- literal 0 HcmV?d00001 diff --git a/assets/textures/error_icon_orange.png b/assets/textures/error_icon_orange.png new file mode 100644 index 0000000000000000000000000000000000000000..1f1586f2137a17481272ab3e644ac04a0d0d38c7 GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;TYyi9E0F%*!SG_~{6rv&u_VYZ zn8D%MjWi%f*VDx@ghMttF(DywO?qNc!q58$4lO#s^rVQR!Gn=c?5Nm;1gTe~DWM4f3?U^4 literal 0 HcmV?d00001 diff --git a/assets/textures/error_icon_red.png b/assets/textures/error_icon_red.png new file mode 100644 index 0000000000000000000000000000000000000000..1f5bafbf442ffe6ac29f374f378a56983cecf6a0 GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;TYyi9E0F%rz##p<7bL=1666=m z;PC858jz#w>Eal|A)B0-kdU}0J+Ua^=luhR79C)EQpC~V!N@0eRBXZm<_O1RWseDs aj0|%(u<>&pI!m0irp><8b@Q$Qj90G|+7ApIYRAb^44lthOnP>7`@$S)X37xB(0>jKh@ zN#5=*OljOTDGUtEMxHK?Ar-gY-VN-VZ6MP6@WffBSCNdnPBE=|$(Hft@A^!+V-nIl zJNtV3Z_CAX9+@70knyp`_S*roC%!a$;3gKCGST%K>l*p}?KkaQU0T-EcYMw6`K;AC z!4)ipNu-)Rzq2OY@_CH@wBXI}Vk0+Cd%A1WoJn6_oS9XsbA9Ggt0|Qw>6t~6f4yHv zmX|hFXRcZGFy!t6i!f1d>4i37cc=Gna;jWoHBIlZ^hT}yt3qY(b%dV0)KZ}y_O`Wm z(Gly7S&{35ryMsj3XNymmlG(rn)P)k&;I&XXR1OUSAXAZ{n}>weeJuE&v(}7Fuc~8 ze*ZgT!rZ67?tNuHWOeT8_lV{M+2@}&)+I%_@0=E4&huL1x)Ar#Q_s0J2CS)BC%}E| z)YGWsgAqGpvUOy#=WBPhCciCq-Po`ucb$dUgso>qk2`I;6yvF*qJ4Jik)}i`E))Rj>sW0+1x7DT;+c!nCKYOrMaGaJ8dlXZsb8v&px1HZM zP7{5$H{#)j!gaN47R9`c{O+qG;%#>P?vbdgOsTd`Ycf@)>1?z+mZY0JjVJQ8rI>cj zwqr@H#vd((w57JYCAlvC)047vam}Z>9WqaYr^#<#6r&JU#JVwNikts3$8dp@U&Cf- z-hIv#H&<^X(7J}}pA@H^c$d<0U;WmZ9+rRWZrzt&W-Ro>l4JJli4Es(v`D{H5wEE` zou*!JVRNHm*eq__@~qFo77u1V(+HcyZKI#h|7`aLf5S-;g?ev{<*QBZv(`Fo>lA(3 zWaq!7{c`h(66wT9uld3Tw8=$bmk^4jt#Isd*zex5aN%?F=1U%Q{x>G-bs6mwN4bj_of zt@1y+ubsZWN$*#wqw4Eb_me_4aY>0h%{r7NvrRBN@1NML4PAEacOyQtzF)|=`puTN zM`x|C5dOO6(0Y~wcQSYP>TEip)Qw5}njiV+yy&KNiIOuP%`e?@XW6OA2?5s{q`^u3 c{^4ItJEtZIC8?=C0A?iyPgg&ebxsLQ0FPF|+5i9m literal 0 HcmV?d00001 diff --git a/assets/textures/fast_btn.png b/assets/textures/fast_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..aeb4d3c0cf4e00105c7f2a5331b2ce1e93ee1ceb GIT binary patch literal 1212 zcmV;t1Vj6YP)MzCV_|S* zE^l&Yo9;Xs000C#NklX1Kw+Z*&^L*}q?>Rd=-|s#5InR0SwJbpp1VIo4K@bE%5ClOG1VIo4K@bE%5WEB_ z6z~qa*~ZI^@cwk?;*PzV@xnCG${heYY3EZ0c-w$wyp{B|hV_J%qvg|TGb+MK9x!F` z58{eqtwh*tiUIG@seD}8nP5inyQ+y7w|UnD1BP==8!}ItV8BFLv<93r!GMPyR>03@ z#DErU40zv+U0@xzlm@ghIaopmFo8Utj_U{y{qdb%uksy0s(%ulBGz((h+-*!&q{LdwZD@>mBNB@|78V3$!88F zlu*o6h9{HQurwhgMi_0G1QiKuV4qnAq_Cy8wFS>te_YODAk8)dzVd1H$MsBRCj5s2 z%Pgp|8PH&w0TW|BhV1!RdW2~f?6$3e*Gw~@z-GWNmTB;t&4OIh3@Eo5P-dC|BW-DM znRySv7jgSQ*gONq##9L^EfXP=)f{5G$G-^{1VIo4K@bE%5ClOG1VIo4K@bE%5ClOG aJitF*@!e9Z=#iEH0000TP)MzCV_|S* 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 iX~LC;KxVdXMuvwq3$j{ToF@)oKa)K{6 zgHqdy-QJBIir?RvDli3=pJQ6NVzZci7-kP61+gajamnSrtAhou#e O#o+1c=d#Wzp$Py;d<%g9 literal 0 HcmV?d00001 diff --git a/assets/textures/ignore.png b/assets/textures/ignore.png new file mode 100644 index 0000000000000000000000000000000000000000..a73d2222da54fb2b4a1bb6ec97f9124f9cbfcb33 GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|jKx9jP7LeL$-D$|*pj^6T^PC< zb~5}loW1onP=vFeuu zpPQSSR|4cRFzi{kX(o^g@^ogRTRdI;T-G@yGywq0tw}fl literal 0 HcmV?d00001 diff --git a/assets/textures/inventory_btn.png b/assets/textures/inventory_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..278ce39c73b9dd35ef8cb7118d3670253a2d1346 GIT binary patch literal 331 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H0wgodS2_SGreY`05Dt#eH*O$7&H|6fVg?50 zjUdeUwfU_lP*AeOHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#_B$IXprTWrE{-7; zx8B~^$lGGT<8blJl)tZ2xK{NzCWhh e%LjJYpChbF7Z$W+)cSq{@jYGrT-G@yGywqKG;VDG literal 0 HcmV?d00001 diff --git a/assets/textures/joystick_bg.png b/assets/textures/joystick_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..406193998ec07b38d6cc9f55b00bffaacacead72 GIT binary patch literal 12481 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 literal 0 HcmV?d00001 diff --git a/assets/textures/joystick_center.png b/assets/textures/joystick_center.png new file mode 100644 index 0000000000000000000000000000000000000000..1e4754d2491299095c20a00f4d12167d6f87ab48 GIT binary patch literal 2574 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 E0n`C2NdN!< literal 0 HcmV?d00001 diff --git a/assets/textures/jump_btn.png b/assets/textures/jump_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..d21b4a9f8623197e0af9fd2601cdf7cb31a545a3 GIT binary patch literal 1710 zcmbW1dsNZ~6vuy7)6C3Ft#oe3Xr}4ZRRdF*k|Ih8=7ZrQQRL^mDQ1lD znI;}E1s^4%a?mzY!-|uDVL5f?6AiIMTof|Es+evhQ={B2f z005XG1L2_nV6agd09&_gK$97#+`y(3Uu5{!t(Z56Poi;BU}Opa82$7q4UUq_MmI$3 zRR4(7FygsXQhf4RfJ7p>;x6G+&cr93btNXBuULZG0Dz$j5`HZF$}8nqbfP83cHr%c zP+opqtIK$c@AeUsenAAvO6u4jZTEc$6RNq&$YpoCy45w${JIsvo*yj40gZ z)Y`RbSipC3^6x8%(5@WAZ+WtmLrND{9$C@7!IMa{dc7)j_UZfTdkvd54*Q(=TitfD zYC+};D(Rbc8@|c<1{r1}2?gEas!4cX{pt;J{_!7g^}vep5I@iA`8ppRf6=*0+_41m z#i6sg$)0z8S>T!n`Qe_@30Btq5jLcj-ad_O4CoOpkX9AjYj59CyDO~e3;r?iX-Ubt z*D81La^RYU@Hs7(ZGdW|Tq_T->_zF*w1FW?tWnAKm9}PVPW`U+a5NbHJxA@1XB_P8 zwSnlyT)`H@Ns$=cI1z)v&|fTKdt>#Sfc(U*qUvS>YeGF5rBP+NN*7sciP#^^ zHC{UB)v|phVGHsy2O*KFP5od}s^Qa!(p4#ArlgvAiEcuD9 z>rXq7`Y7Fn@)wv^6EIgE((8_%KX%`O^lt9rLv^O@Fx^Tw?yRQ1rA(c=ZyBp?mOHSH ztn6i_R~VK1$XybgsMGSjL^7WYvHG^m}0co+ zUhJBM65tf^(HyMwuo>2rJlN(&Y&kj;^!No`GHCtSKk?TtOGz~)(@lK8MuRt2vTlFJ z4I;XqmZAI94ih#t*Cq`gk2F^HrAs-speK=BI}-)JNmNomt5a7^BTNP|$RIoe*(JMD z=EccvWBV{S+vBX~3wB>GG^6Kw%f3omi|&lv_3l|yy%FpZL;MKzaC9t$^wKjPw0|)r z4>D=Lu+%hU#(D1Z#C!-cqrAGTpNpj26e4LChXe;>n=5fr|JP@#G}(4#IMqHLI zVlLH+k{j8fWVNB`I~&!!3JEk4@#sL%8iMRwKNo;n{kU5xW!oMhC{@8^T|IuRPWNri z&Pk4_9q1=yF99d&;l-1tv-U}p3fP~Z<5mUCEOU;PH=&(NU&;R()R%jq$+TfCyyz9K z;Uyz7aL88bPZp0{BF9TA216U(J{s<}ToQ^1b!mrYpf?UOtR_nL^isPrxPukq2!1^^ z;kNaZC*jcgqo^2SlmOROY=5gZfXwSRE%D~0^YwQ%Hjs;K8)VG`=^NpWW@A}MY6|tR zBz7o2`oPVO%*Q;)y9n@{eaorL0(cfvQ1mi<`Ces(wW8R5f%ocEQcD)i?2Cs?%v2HO zZhDy6wm5;@-B}v4X$3rwH<(5iGyj>>efx7r=#=9+(-QasW^fYt|8O<2YbKvYpU%i( zU*G5PU*DlUFzSU&$GIi|vXfv&NWuax@KHY(*MV9@KL0%8uN?>ouCO#SAqdqpz+B{E zXz=mPv{&WNr@-LguNGd@=NtEr7#;td_q*YNIj(OqUCFa<>&pI!m0iqGuuL;P2`Ho<;1l8sr2i8E*4cVl0+sTV1o;IsFmUiH`xn(Mdi3*m z)w<3Upg3cax4R2ZDq&qQccs^ z+M;GHzPWIzVnzl}R+n4*wFPSrZTh|N)iODbzUBqXC)>RL#{95$LiLxf1yjAkf^*k| z8_DPZ!5Ya8)BHBgeC%c!QGCSe)Z>`HZ3&5ZfbTgi`QBD!U>bYv+SALf*)`Ys^76l3 z-fY(O{-x>huTIO~Y`(IlYI{tyP0#DO^WSV2-dxswaLeOZ`DfWt*PP0Ce7Czd`|um{ z$(yFNXLrZ#v0iNFd+L_lTHUCP>so6(Pg(I)e^1&g@kv+nwbmQk{;ysqzAss`d&76D zYpWIQCvBQ{_}=k|^{s!t<6^i!WKlSCE$@S_=`4bzE zz_VGVKSF1(bP0l+XkK?6D7` literal 0 HcmV?d00001 diff --git a/assets/textures/logo.png b/assets/textures/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..48793678f178139f0713f0a4aada1e9736b78654 GIT binary patch literal 12188 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 literal 0 HcmV?d00001 diff --git a/assets/textures/minimap_mask_round.png b/assets/textures/minimap_mask_round.png new file mode 100644 index 0000000000000000000000000000000000000000..a0c6b2ddf99230cae173264a2f9fd11fc0b05382 GIT binary patch literal 1858 zcmY*aYgkiP7Cragya-7M5@HC52|@*AG@vN7Nb{m97!5BC3K$R-#urkC0#y@20*DGh zMHqZEP}F={F@tSos*)Q%bpisW>gf0wxl{u_o76!-C12)hJ3r>vUVE)|e(kmQ*&|=E zgihsB0RZ%6OQk6Qz&L~fjNoMtJFWmP9`faB33%1(^=`NOwQFX`2TO6vic|nf4i3Zs zKpI&l6{VGCzdU5wO5igI1C`8$GsPIRJCpL{JpbY2PZL!U7w#xFD>rg7iZ%%ULf@`x zR*79fpHX6-Hx9tLuR<@{C-P2>9_%c0k>kt$rrrN$xTlvraeK&lOvYgJ&2HkCjNNt4 z9}l^<+tsbj-R15Y{@&%Ka9^&>^W&A5ldGTwQ&kzH3fIv3MvLXW2oFc)JRw-`gg{`gCJb)i=EHf%&?z}LE+dHv|?q2-+4%Ja%;&G}He-4+W$=aZ!2mO6P?yBAJOW| z-4iPtn%(i{>^DHO+Q`+UAA$|FMS4YZrL`wu0eghkDIhoKVrwG$MR_?4uIHD`jE~YG zc6O2T82eE}WkyXvznEbV%V~NX*LFpH!4D-_EfHyqjeN2Y$G0sJW1yaIh>R(6zG9zd zvJgK_E(QfkcwhbqkGp^0B8cE@BDq^=GHm;EpCtR#;F$Nxx z6?=oP?n|PR7w5GYxq<`?It^tI0M>tRVveAmrFg+Lr<+C?zKM|+| zvx!}F!-b+Z+3{+KhUI>EvEBaUZ6w|)0m4B6N$`Jg(tLofRDE{`*VOJC&%iiR1v!Vj z>B`SX{nhUDS77{ciF=m?jQ_RXee=(NOmMEtWT2|AUYaijs?92N2o(U8cOPI7F~=+} zFgI=nQ`>%moc>(0X>Uq2+Tl5}Xrbfg%dDe=j*g*s>a%*=+PKL;pYC3rqjUJd&L8Ck zNk5Eb&+ops-|^$)2d>H8lFP#lj;^t_@vh^y&bGXHfZu}k=HKo)E{(4>yB>XMe!J`X z#C3jRPNe+f2(O}A6k#DO%^*JG!;;3HTqS;!Y9Xp9QowhDt3n;mb5A9-vtDP0OZVY4 zJBWOq8T<63g*}aoOfo!GBwH#?PU)1#HtVdGK928>-%ZWBK1+lYk6@9&^N)<$mH(5j zSt8AC;a)w}dA`${a=zp7r$P=wO@`Piz0MS9(GiFJ$uK zv7$wXIaN6ZUn8NZ>WV9@uxZ{yY+!$Uuvc#@RABOKQ;T4h;(#!OAXl;*1x#vxNNG6b z=^EKN&M!i!k`Rjd2N5D9dD_F9`)4eqH+Yv!n2ZnqzWcj#y|Ug0&NANBdC zvLqv>Lq)8+g+h$CxT7@&CKn7-Ndy|V%^;DmXbCAsz=~V$mF{daw8B)1y)Gg-G+zCZRme(B476E6*zcs732(l{}+W?UhZU9S&EIoVc*D;~IS+a|%tVO(# z3+*!SQ`D{TxSe6VITLI`vhZZ}8j`xA?AePXPOhexc|08|wx23UMsk$f-re^isHv1S zOeXM6vc25JmbX`Y;+Q3DB(+?s2MIyD7bgGUnALXN>-`e+mzi?d+o7_P->v*+;zbzH zynZqC52@IBE?%ZJsU#j1Z?7)r-JQ6V(&x5&l~T_RzWurS!~X}CC9IHkh?ScE0zakt AwEzGB literal 0 HcmV?d00001 diff --git a/assets/textures/minimap_mask_square.png b/assets/textures/minimap_mask_square.png new file mode 100644 index 0000000000000000000000000000000000000000..160b6faff6e0f74537143c86b49155551f0e2a23 GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0y~yU;;9k7?_xWRHv9tCXnI@@Ck7R(i0|3_zwo>^?x4& z@|jD5{DOh>ud*Ze7#J8`JY5_^D&mqNOb;YnVdT+vW*156wE{91^Cd(`awU}aWim84 zGBl)~OKXz;&$PpljeTuX+Ime!#>OAN8R-KW%dHg#4KQG~PH;H5g4s>h;1vUVTO-?I a1_tkhGa7M{@w0)!%HZkh=d#Wzp$P!v{z$9< literal 0 HcmV?d00001 diff --git a/assets/textures/minimap_overlay_round.png b/assets/textures/minimap_overlay_round.png new file mode 100644 index 0000000000000000000000000000000000000000..16e3c41c730d785aaaa83e7fb5bd5d68922cf828 GIT binary patch literal 22044 zcmbTec|6oz96$PszsNTK8zOA#}vFoZ(3iiwOpC5$CzD%DenM#%2TAXy{C zV5UvUh%6xng%HMWFxx%T^V?qcb?+bdD(O4lvwY6ye9mWm9}mu2nMzA3NI?)JjWs)E z13_@`UpOSO0sL4B?OF#vHn>@so`M9zKRFEriQp5-Yi3S2AZX(@;WrFQ%a8{jiU(mW zPm2$WN^OPdljOa8AxH_ro;qO{`hA+&ACSQg7I50ujcyDl{H1d4S@EK>)%FjM+*MD{ z;00&38>TMZf`18^C1POCInwQDOfEVHlNJN5_-n2VF6Z4@*^dzwH3%lxRqxAw_CEPa zrsdo_~N06Q+v+Jc*d$*CY##t-hE(F|t`BIA- zGLz=tRJN9j;5|Q#4XB?t@kR-X*(~M_>`Uj8I^=k+_|pCn6)4=GyvL_10g1gH6&0m~ zCI6(;F<#mVZQLqOykIrH202-P=1ms1u5+$f#+m0;BzQRGUOa5NRg5GGDSfIDTeE^k zkdgLfJuzexsk?8z((?D=?X@dC*T3@$i0cJ{8Xirs>?&9$2D}~WOhkH{rCD_bRa`u5 zO^w*s^7pLnIi+Ke8AQ6YYm_Q6eZt16Lz#d+?5!=Bozox=A_S`+1)dzDU{n>oM%4Y` z@ekhq1{;f_s(TyTSlUeQ{~x^@B~}zSEo5#8NwoXB@&|YPk(ruNOAjla$Q_Zh;G@@? zt*;tRS-9h+v7IcVgWk?Ik$06Ee4dqm9VJm9B^Xq#)2oUlUvaYkj!Br^U#?1i$TCV0 zd=F$xi`NNhxKo6Lth2@%-ZL1?F_tvyLPFOkYr){@XYJ<$6Y{+?{|usgXc!&7bRbB6 zx&^OW{zhrY5?AwWnMBn?b}tZ3P*X==^Hx8ijSgaI+%e7N9wM)&gjVUSC-aBAfMJh~ zWOMRoygh^1sw3FziyPNG9I#AyoiUslkeSC!Y7Eb_aax_UCYl>VXJL>k z_lnlAg&LLfPwF1?&LvXn465>-zbfYz_lZHp^eI=zaU|{6B$H_%HI3iFY}oJpmcdHv zqu6^@Txdn}I?=o#a?t$G)7XymfW}%!*e7Bnwu8o>qVZjs8T?8O_4~3Wi#?MGsYy)3 z;-mwwT&UHjE;p#XeV8PIvRFi3#@gWUizVi_sOTVepX^(^*z3>E9yo)2(d|>EF9!$o ztzgzG2=zg)He0=68lwE zQDhjPFyzfabW4S~#N{JRp}3@Nd}ZuAd^K9Yek?yiN=>qtT5;XuLz7y;Cl`jfGOs5% z3=ZJ&%km>Kb`K;8wVM`j=jZ2bBAn2cojmep3k6hV zF4-z*>s&w0NPp9c4#Bn8OnBY`j>w1UNn%oFrR_`XEp3j5Og{}yKj5cyO#T{sAslyN%rEzO)@~W7RG2|5 zcCeH}&IDM9ZqT=s7~uU&xsIY{tBUyAi<@l_&V^}jtMK!yvTdXybSrsUP0HA$!y_fOJY>274u)m_P>NfAC`^Snsn-+XG2z;vQR`>W`f|+$B zsXOc-7Ml+4%QD~m&0NY@;{F09;Ap_`w6?NW3@a|5aWsL$ynGqzdOuVYIh1|Pwr5FxjzOWgy4Y+heB)>$Am%w1b7 zi7p%(R82;TW$qXCaoM>inEh?Mv#$GA98zRtWF#1S@BtJq76G-}7VxHe%2KA5*RSP% zJ^BRM{MaP-`g_Ksd$K$3G*aH-LzJ41jk(==r8UM&)G6zKtXxz^-48pd)te za(W#+W$!NF^ZG_dDb`k2fq_%G)_Gj_?(f+N_C?)wl(p*U;g;Ik+Wr~I6J+H5RzC(a zzK-+2KA6sAQzO)s<^3#!qg=fEjSKZl2*>~6YhhywKm{6-}8$P6+X`nxOU)DL` zHQPP5#=&4r2Apq3Yil>+cqsi~tkj819o&hDiLUnc_V)t=1DV|~M95avsz5ey4WBU* zm%lI(*g9W)50iI~5@9EX5rZ;T9E@fV*V!l64i*ngVuzS1qCEMLkxNmZT^E-GcMx1m zhXY}qxdOdXgGIK>zCP3qLn)#vU&@c11H$X=fw5sSJsEy)nKbQ6%|a=X6tr?`IK}R{ zof z1v%h;bOOC&@)x8AO-#|zM~@x_R_+J4E2uQFGpf;mcG$Z*IFP(F7Ou(zyS%0F<~xoW}AauUiHQ-TaEJMYJt zxQ9nYWt{@s+dlHxvyT_0KKD`H+I&5YQf9I4e7}Hq3>AT#yc#=i!fy&qNi+(1t)Bo+ zhKYF6Eq8o~eTS1y&soIuD>Yen?f`?o-T1Xjq1{!vm=E`tBmon`S6NO=z2@W^|4YXbGdqdCEaF;b6z74=u=>9Ek9E(bVlCn<3t}LOK-Smto zD2T+4c&9}#jr^i%clVI3w-f2b>$~U(d zufAu-2RX|nXlJmuWdyOyzN!kD-%KBB7BXdAm2W?sJ-PG>ef;>vh^dmAikiW2^@aU4 z{7GU}B9Ws%?BOb~aOrgAFQlm3Z+Z?7;y13ZPnF&8aU~k2rluYw*vdJs1l!p1mHt{6 z#lT5fo49KS#|k+-?kQX6y{jsQPlEcHWkoYrfvMAs`SA07qN?@LnE*Fb8p|ib&QIuek$?2_FiaMHvQ)^-TVP5HS+Leb!yyw+5C?m zKkfu>NK?;tGpN10P;hsr%Yif2*0brUsbPnsubFf#k{e%I4ZF@qxpqhsXkVqc@DQtF@ei zSogKMj=;tv`B(9stVW;VogPs*+akF7vgE6+urb49c-?R2q6;&Rs=oESNM&w~yR8Jn z)JR9MvPKIYf-|i&nNKDDViA#ZBK;{6uhvEF3ngw|>e!`I6nt|1g|lg{k{KkyRrH;^ z!LCcSOz+!65Ogui()y}2TCQ$cy_IP#3M571$4!3K%@eI#-j2o93CY80MrHK3@a`J_ zTeJauateulYPrDn60{Kp{2<}^e#n3#pm5VobJ=L zu3M#}=zGmXUxnx5OnczKa3*S7&VuuMFijK-wcjb=8~=Mvx20kuxiQy+$@6Vp9FO0g z_eQ2S?*UyQ?sgGNroF-&hRsgvlYRk1LKAOniF;RR2PZS?4zSbvQnXiLRE}Y8!?|`w zUEPjPh`D8Pg21pFcudp7A7|q91`k|usxGrH+H)!7w;-9ajn(M-gaa!+E8RO>Mekbh z!NktjQPJ`W3Td^W^KL%)dO`w(E3zx^*m_p6tNhQ<|fnY|48ok$pcfA+e7KPzYiWZoYiACKP|^C6%~o~Al^o^~la*wNwX5*^c z^`M|2#||t(5E46|#5Er-&f2>(<1w)D=uOJ?nx&$^G>6OuXe;cCGZ}f38X3{&M>LI# z0!}d-gawQ|ixh>M*I~WW>_VR^=iR$@^*J0)$+qZR%Ajogopa)B>mW&nG5t>V?amKw z*VB+BQCyp^>-6Gib7H4YGS?MVIs3eCf{@c`LR(u~3)8;}^Siz^!7i=NTekktq>sdp zOpTU7V7$1uKb$a#-%HBm89N6KA&f&mF!;tD>;+BA9j5j=4_D8s+FBuqLat{P~PL>;GQfaihYRHsob?wxkUSpO@I z<1`+vYn;`qWHY9Fl%t1I`>LEvRy<1V(@X4&CdXP*)_y|msM3qITY)~F)fsm7=eyS$2ZZ*|LK$u@N|8 zH{K9)**q5iap7sT7GXCr|=3SFK1@k4&Z`_JNiMdn06o zxdm3WCY?F-cq!_oV?A~&Sfk=?0lRft4(s_UC@)~DQ4ooxX;ltc)U~=HASz{R`Rk)* zu5nWQyQvL7Sp_Q6HD$6Pz_hMpQ3Qc(wivn8p2Czm$G@@(}xWz*gvzIJn%HT$$r z@U$bVm;5 zc50qeGVt<31w6K50F77e+ITZ{XOa|VNKAmj>oOwIB*Tl+6R$LJ_8pd3JFti0Lux3# z#cd+rwsuy$yg&x)yCjxjzxc+}`Jg1uf&S~K6z)dF_ijAbL5j~{i}Y4T@fWi><{UVq zIOkUs=>#^9+n+-*=eti!<-pq``lfwQ{4iaP-CW9&t5b4=>w)c8{~nUTX*Lo{D>R2W z`JcC;X@Ut;wE0lzNSrrTPciNuBh9n( zSMIs4?{Y_SZrZgoE!J2Nn1&p*2)v4n5CR$6O7fTC&$LG6<4?Byv?3A&mJ+vyWuQI# zVXRVF<0oB?E1Pa@K^Zix=KJj@lcYCjyW9p2IAc|W{;Q#_LP(pd6@M#=50xLBtx;sk zVT1x<`-av%{n3gDh2CQ`ld_a?c;XLMNt8O7Am1j__W1w&%y#7WHctTS87!{kMft0I`P3&9SU z(j?L87D2-r{>wi~k{G==H0P52PRSrcX&Y84`33>4YfGAu-@C_VA)8y(9ZJtoBbp+D z_}}NY-pq3@x%cwrOY;U7^cMGB20y$eR{u1hcJPJh z_LvWoZZAVSnLCH#yXytn!Gs&^E!YB}MF_+`W}7{*IJvpGrwIjuI8of=hP7Ymcf%Wu zb{ikvr%;z2YoyCwT~irEWnI1Z0U>oWinG|_;hGX{YbXq}GYH|{~s zqy&9oxLA=#^FS77eeTD*cL9xS_{(Lgun0q#W5>Maq#TN~5vy6tIfqgow_Z+94q`IV z|7f}BpjOsJFfuAIr{u`T9>UlF(;P35 zKjL7+Pq#)0{^g!~f+Al{?<>HPZ*Fz3H#~N%*#%Jd7QT<=1=w1YchYM4A*Vcg+Q z$i7af7Z> zs5y~eX0V)(gZ)L_K7WHRn*-awya#SiwU`aekuTXX^9+HCpt+O{)kShvG=PwWlO2k> z{k*)qfT#1peB{N&*j~uU<;_AZDbcg$GS`sNliz*%`{2so^mRL#196^3g9R#G#eg;2mPEqgw8c5yc0u)$E6u+Pp}h zh@)joH*elNNL=oA7}va1cM1siC5m&&I&hzEO8kf-BN687acP!A5!DB;>FtLu>G6c4 zg)|g^)hy@JnaNQ5k~rk3Bbjq>PM!KfG9e!g(Zju@20Y}TG(H4n<{Z36P=U00Fi79T zc9>-b6@znpVEr}3mv)}WBbIpmW1=d-|YXkI_M3y3DFjIr*rqGKWEy~fe z7U3#w-#4h#QcTH4!EC|+k9Ja`ryxJyYh8q7Sh~DKzkBy?8nr+Z!q&7-cOtPy53~leGBPrhS4AM?+J~5(ogn+%x!Zh7o7h^U^?!~kAO(KF=|kzy+#sK{pI(R{Vi6zY ziQ_DUkoV|o!*sZi6CPR~VYb7w1H9ZZ9>j_|JgY;Mb-&4)ANeSfqUpLH)_b_cLJ&4b zQ<|(zO6Hl>r6HS3`fCE(ToxW^^2!+6^BaR@wl2cvLnNz25|}H@n!bmS-9r3ggfe)kXd=Qn1e@?0ZDZ^m zMZ6v=@D9HdL4+`-C-O@WpawZbF8zh2i;OwISdHqSts2aW$w}|Kq1CkWqy+KsWPb~r zOXWyoY4KW73hp=Q4QMDQ#q%%C<@#0N5$4i(GXd(nE}3>vVW`rPJm3$LRMO%@t ztnk=F0rk9<{;0JD4>gGSo3hmQ2?#-q^|L*38xGT?%sO8Uv^c;TGN7lFx6{+p|4=IN zD;?%}L=$iz`mZTnB50rWcL1t2^MTf*`nk6o4f|!~!&g64o9Eda-Y(^iU#X{NyZZMd z_5qZ*l9{k%iFGBgUkVdI+`0Sc>1N0NMB;P%k!%VNWO-~BzX)DYcs?tK zx>O>ulL)B%(sxr42dY$pHt@`lk^3w=JIN+4H|IZO`AJNF5XD{pMRU~HO8~j1m3oSn zj)lfoM!pL38oNlyihhrzB2v1KRqko52TF0H@^OUmQH1;P>%f2f*JVIDVQDxRSwm1s=#siC=62>ccLKZ0xN~a%@h36qct-$ zZm^%F?g?URp%jztKD+yZifu}lB{uC(ReR}klDgrxg76Y}Iex@7>yjmva|lZeVrzoT zU6&~$66h$%&pPLG861@13QkJYAbDERbEjRzCerWGv&58&~;5f3>ojZ3xF~#Q3r`D#@x5!rJ>n5@Db|4EF zCCu_=7Q?5#;O+W6Pp6PxCJm1tNAA(BBztj1prvzixQ2Teth;h_8Ft+nlxgZa&yzCG zKw0{{@sX|jSXpK-sGO77?9@J;`Emq=k#T@I%WRZV9(cSYj^fzv{pft21cCq%0ETPY z!9p}(UYUFl+4Y(i5V62)$20*Gg>WoXZf9Jr<-{gG5?eVXhck`pOiJc!pn2(iuZ8*A zoU@KKGAcKb8UaDJ3!6|&RwCikxl4)$mQd!ipy14)% zxr~!L9z1x^hr|N+AltqWKD`>4<8KYU=zb9w7bgt@^?l0G8}Tb-YIZR2r`|ApG63VK zuceMmvpiKmynFb)JP0;l-CSE3yOaq9RW02YZjqiHEd2Vh_UiqR2Cy{KRce^B!{Xn+ zh?4Tq5Xtbo*u>Zvrau`f2ezub=LOVIzuSwt6-ox@apj_1PD+Z1zXiN}aMJZpZ)4$W z1F!&VK`a<8r08n0h`*s z&Aax3lVMKYjMX1!38}Y(*_Xn1Coky`&^wKf2JzOH4>32t?v^6~xQ0qo=&24TtSZCr zDOd+djozt#yLI|?YUXt|V8mzprpb~ske{2|U(FSM2bw}bAt1f)1YsO#`y8nR2Uu4| zbWB(4Gsly5D8RX9wx;MQ(FG+V>bj@nc(5VEF5iJxpO|Mc@MOgm| zTNrI-e9bjI#uEXRBsn_MQ-vAKP7gbt(MGKQ$ujM_i5r|R*)2Ih7R`xV(rgN~>Tm+J zyuvH^bFKH4ZvueA6f0g>_9&zA^#SkbE`{)}3XO>E?)Bp=*R;Njw4Mi?x6~ze&de2Q%T8T^_;)oOC`A92fRwSx4Wx$eSJn+d4wA0@CZ z#;F3%tdM=GeuJ9mG7<}l{=qYJx1923;=iRk1@+6{F6Fp7$6wEp>jAXcx(UPTU|%7i6E_ZyspSqb9nn8cbw(v z9;*Rn%~@2VJICDGT+69#y}DtbSc?9zmFPAv13^>vuy0PAUa7Q_(jP;`J=~ANNx!Xh zx#e)3aV=@E>|?MA%9?dY91`mYv;+O~%b@F8XC;2DhiHo!`NG?S7qgK&1Q1l-Rjnst zWDCbEg8u0aV(q%R;Jp~>7aD?e3#H04TS;v|t8v94`Y-32UG0oV{wAp5d)tJfwDa)A z1N*TRLySich0U|Ds;wk)lUuCmNeOYFg!OJp&uRQ8&Mg(dk_bRm_rGzA6Y=zyvTq+C zv7135RN7BFIY1lcs3EXWNDN{yW&ZgyTCG&h`7~H-@qtMa6@jYMGJL0l=^aK~ty&;n zW8b4%W9zJiG&6x3Yb9wlfwI5mWaO@REf5jiC+}E5^gr<>#UY`oWC1gBfWb;K&-(~sG;IM4YQGCM9XubNd`TTj z(QfSPfi8;>pO=0XfJEA#2APLw8+y&eNDE;77XmEGV0D(z0f7iqE?vE@pcJ%r|6i^Q zL|^Ic@FiVUhn|2jdyOuHNVi+UF>45jA7;HH-(yB%$mfJ3T9gD!~O+m1DTqISiGS%(nYfvsZDCA*nJwUAyKn6UP+BQ1hqo=>waYAXT95~Ky z$sQc{*q9Mw*uvRF?MwpFN=G4XeRLEFf-{n3$lUOo1BKP)1| z83a^*g!NcJ@_?uuJ-^>aagM6}IIyv#!I$16B;WlI$f@2|!3y29T=Js_^JoYPIios4 zB0mc55HH8W%bR%U5h9p_whUIw5^?n1)DE(wpDO(5j2*LrR)$+_Fv?vxpnrAKQJj;1 zB&5}3kHFM*zzmDe;T@OxLkyp_hIfWdfY4r}889--|CJ1`Ta?5B!-luvmtnAk&A0pVvlgWfY` z#@GT7C8@m^Ha76>HX@P>apF@dVb@Y9bz^5zdE1r0KErYh3X!slr!GD+xt z{|m|`fs4Od3lw0WTe2RM*5~D7bp+M2Fzsf9C9k)p>$&q4VGwC%Y%K8Deyok=cBw_Y zed3c^>R2M=s|z(?ujP8(ZfDo;2TU#7AY^l(&>`bF-K0hWY zdtu|PS0?+0Z6z^9up@|l&tFGif!#52ad|4CdQJ#Ocfxte0AWZPobbL=xP4sDCqV38B7);?OB}vh=@q`Q1lVK z2oxGB^dTWqYvcwUVi65!wC^3AUW?^#sXutbd4oS_L4NL zq1$OakOxY=Iv#$ndXw9l1g;3y?(9L5yvEa?{bA^CqyJ+epDCkRr_;*ab;w zpOANDrKYfxS;vkDdt^`Hw;wT!1=N)*2BDhlhaIS+`1g0;WMrXqisAJI(~tb6L6fb36_*?atec(st0h@cATYXBEDMi=%C zxo=eiGYVUv?Cu3L(^>74y7a)>ftx#^3&MpGGp~v~u^$ro({}xgUO(h8v*fu^34|2| zBmN}cN9!-egyeKK>taAQ2~t%C0vmCgx)=ypPc61Dx~tJ* zPW}wAwOauM7j^`tZmytPc@o54qrY0y^IB3gZNZXqOwSjcPtVTQ#40=vIw0`;%6#`w z5|ftCY8{E3y6}(I=25}oOMnLp2behW1eh_$vjJGvWF)rs?15NweLOxlOofiDP5p3u zP(1@pY+T+Wjn%h(PuhowCJCHt(3e ztU*x2){2df2j@3V_H8Uh5|#cX5o!?>zzCWpc1ECY!w7&a{$eSk-^+|%KR$Y&>y6z; z&KDOK_x&L(*J`x*Xf;V<*#nV(mx;cneAB!VXL1L){2+chd*G=KmG3_1vx^E*jQ(Cl|dL@)K z%wAZ07A8P&gd>$_Z1y$19%jX*>jgA@h~T-soFG3-%Oe7zZTSo-i&}Sf#qTkwj&euz z3&qXgazp4I{Z+Bv4dDFDPK9n94wr=fyxGR|g8^+-E-jR{?#UhW`th<|j6PvI;?$Lm zIjP+j-1#TSe>xJUf;Qp`?OqH~31z$5|FjWY2-t{A%TEMKvB<)Q1#|RQ#AQK8q(FCp z7Xo(EXXCKYX-GMI$ysBv?6vd}kiroI`md(sDEw*mkL>SoFT91px@h5cKE`ZSjW_OjrrDU<>dMDRbye3x(;e}gq5D2b3_tuI-Q(k8Az(fJbRh~~*h4m)TA|Q>l zgTd%gfZbFBoY;P3R$k+Q2?m(;CMjtWr@OewU@J71OTv=7fDc%o+Ku#JU1hoK z5KgufTcrRkZlR}9){xlWGy6#DDv&;rU+?LZoagO)gZ<42QV_05Yf2mX#*9>Ma*Wr) z3!CkSw1rGS=zBw(l+PRrfG%pma)fj>mjBp5m)rJVx5%~*=(QVM>CYHp!Utz~xz9eF z#J>l;-!nFUlxMfKwkCOtib6P!A;8iD;D$}?bs81%MG><2oddhpEsCo$!4UMY9t6Z@ z3OF#vBP~|SDFg)a zW6ycO2ilz87ll&C+NesCiuOY@alq{d&SY2phOjmEI<29iTtBgy$*FGMTvmZQs}%W5W!c63Igyu+>6uuUQy9cw7b2ue}lL{z3JC^ z3pRqteTk0ZJ{9VKaI*roK&$BiC~T(LzZSTnU^yUyBMnyWVhfyAy*kB#GLG+yb9+(dQFJ)a2Bh?_IMV-! z*HjO?HV(8`h;Ih8dD@oP`}_G719&(eKt}(h3J|}1$@-0gSqi+I0z9(WU$j+Y{yRAW z2+l@gMSv{}b_x9<1~f9_Naaa<$nja2{3paB6^93Pr>m-L!5$R|IJWUjUL(M0rzdXT zB@SdJqF9T+Q>C?*^E#CY6kEKhsj06oQ$TnEnJoZ*0dKQbegwQrS#oUklwJ(QfmIKt z#S4Pj2eE8sWc}F#3`;93{8Zc+!MQYkadB}YmK;0Y1N|Y$5`+~kBLKKH)C%C|cf@6O zys}!Ojfj%2V}Pyg%8wHSUx49u1Ch^sSvW#GbQe@Zo4{G=jY>D<_xOwD1Dw$EQ|Zdn7U9BczK$S*ZP{CJ6B2mQ9IbeB(tn7)DB;#VY_7#ueEY zh5UGX*Nu$iwEDf|&ay7&jt~{G5T*J$U4CTGpHXdmlLaRwM#!un6u;(QQ4+Y41XZ^t zCkgayV8g;u{L7QZ1Ry%y+5_JB-9Mx*2srTHn?p5u;Eg@>8r*}zZS)UbBj!qy-s^y7 z7rZT61d3Mwy=n0aTN5~`L75jtVrx0TAYMCbvnGUpoChtxp|A9V6s851y!%PenG0w6 z#AH#7vp`{3n4AtdZrS+*pg}W*HgGC~uOhcWT>QSu9vS8T(m#ES1p!J0^1UQtriRrY zWdSJWMTsBn%Tqnx8^F$Hb_#lX9o6q;#c5>)vrm2>T@X~-Lp#b~jA;vC@IYp!d%=~^ z%XpODw~K(@YW(~kJO)q{+v1db9^?>^ndd8E*Bt+6j%U`XMbMT8nc18nUoo=(p}LoJ1X%Ozu_c<5B25F0gbOxk=hpN|VnEvEe(Q7wr3?hY@7S|Lh#YWP zu6L?H04fIn$Z;)pK7(>7fZx9a^n;!VD@H2|poIZw`kWX9U0V;x;h>_lO`_275^ZTITTjs4>NmhBrE>BC)#t_NDtRC(ti+NBbSu%ReTN9y-bH`1pF2cA za&2LfR<&x{ag5*^wVn-e3Ag<`@D2S4nOS+jh$bVdjV-|fJ4*4 z>WBH>Xr9IT@upBiEcrg!M~Ge9tG6suE=DYrD}u=Q_ilhm-!5<$yCww=wDt3KsRe=( z5HQ*S8N4B!xLkf;&n51NF#UNUWPPYY6eAoO_o0(kcaeKzY2vFTnit>!rwhliKgyf! z`kC!-0sR@){y1;;{m<-~GZ0cZ(p=XhQFVvF52V&++>~B`liL6WEd7A)zXY4Oq9qGX z8{GvAwg$R@6r>#sPg}x zvh4=J>qFl}ad~POi60xWo#cw+is4or0L_%A(E>{4rb5LpTyvuV&q57M`RIA=3SR|9 zRhm48^3CKIFnQmsGWazHFh?6Pv(6S%YlS%JeWJL`!tw*n0k?|@_ol0L8Kb0CEFg{7_-$t^R8~)#=mkCz3d3a7)Dcl5^ z`D97D2@ZpJ;p+hiPGXRAM-=t}rH-P>~*S z0HRuzC)IQHrfY85kHu%>VolWMC~YNP<2w zZUzQcfW*_WJ;siHB-}AsP^rk^_c*Wbo2;gw>o`J)+;1U-*pDzb^ioub_}Ec6s7`p; zq_wpQ$^j0%agWUQtXFEz@Pavr`h2W%*TB0-CtrNp#ia zFZ%%(6zqv%X||#u{1_}p8Hj7kdfj~4rH+^~mWcu!T${)SC>@$tJLuK>_N0%i9)CGV z4D-8Dx&413Z!UskR(+~y$+f6^<-Y6}?79_AhrfIip5W;;r7N1&_kjC>ChLBDi*fHq zaAI-lU-C;jXaE$4Fi!h$_=v1-<1#K zM;Id?It8N2!^?Y!T(?_spG)>04CdZ&pkkv9q(& zFl>ExQVLTfRc?H8SO}?U5>7v5ojdh}&uloqPE(#_Hw>)y=t+{0wEtcIUSRyT#RBj{ zVG%?S*n^s%6F}~2x;CBx0e-0cicl5&26wh3eq4#2e+x>@DC)jRng3Z%&ujpI=I=!X zf+#a+haz0X5|o85b##wWVa^UP{7N7hsc8txI>H(!8vrU*lqG=&qAdz8(_FcF_3CRo zwah?v3S-&>WiZYXXJ|aO^Ht{wj4V49!3C9MyVG${ZSyCQJGO^qciO!&@hzR$|Pk=xz5nN%XU02NAeH5Wvt z0!P-TDh-r5TDzu}FE}M%(y5er@1+FcP`A(A-$x{uj;jiafL#ROqL3j#fDSAHNdr6M ztd=B8`jjRUh)6Qm{LBBwT$2w|0##I}DUVq*+gy@53OYGkPPcqM?Ec+j=#-A)f3!_nW z@>S~04Fali7gn!zxmpG_JuX^b1b6_ z;x%t6QIergUOpNXf$cb`Gs{c*7^fN1-ykSG11-c}4MWqh>ZLazNba%l_W}eU8#E_3 zeg(^Oq)rB$B4g8pxICk4Y=W_b1IXdb($;?$E%KsfX};T_s%4RA*~V*ZHe(vxJxR#N zKuW8G?@OM4PfY|I|?c_IJZF;l5YFb zPWO5r{2zoad*sE?GLpKy&(apy#=H5nhI25l{BUhCICQFW2q^r8*m%&Xx8G~MKSq+| zC0yJduJ?LBRg(1TRz4lT!NIlfF93(Wg$#0!v%>(ZacDBBVQ{Ht=Qaqt5VKP=KhMTH z-%(@GWu*C5fl8!92fH;E34)^&bKveKmD~uhfF%pj|A*}LZG1!2RDq^+#H_{<(~;ya z38ElTDaFUHFuA4UKN-pXITyh$*q{0G>+l zS%lZhO*C#%hhfR(2PB~NVN#Ft(g>@pcqdnd*W==|e&KLmOtuPIu-3*45Ud0!l6O>S zr0Z4M*_^Nu0)}n)C4YG*oIU}y_uF4ss5L05u@ku zLi9DYmh+F}c2TH-cdxPO8R9lt67vyDqE-s$HPwrW8dP0Pgo@Kd{}7_ON}x{MAGU^< zy8$$x5;Q>@ZhMB_I;R0+;{Zptt&!3&DM3+ujPwTYe_&^GD zIARvu{0aa8hi{s!tnoi?vjEezf8?ln+CES33qY1V zYdABZP98csUg~@1tc0=@&2!u=OJ(h0Y6CQkB;`W;TVpQ?CssbU4R<}nXVdiS4lHzz zzx*V%yPkb6*&{kl3o|5hu_L@5uf{;tnsu4|57Hu?5`n~>EE9SoU+IDRyL}fX6ShMHXQ!imoP}O*&QDOVRm8S zM(5*HFS_40mN;j}rKa;FaH}(;I0Pn%PFZ1Uih+v z>7b&O<7nK?o80i-AAKz>ESkC8dRV)NMs)8^Mq3-Tu(0s?#lsG>Lp0**^3R z7nd4&dZ7ZCz{rIWqba+oKm!Gzo^wa z#%dxrV0=K3P`~x#eCE+dJ-`+3WDiDI&suswduM{{ul=|kF`1Y049xiA#?`}?wlh*- zI}go%zU;{b8uRZ>?_86UlfQu)Vj>p^^TOG0b{lZ-GyJs;4KH<oK-IDWzswY9dzhg(gPg<@n&OhTlAVNWE_pdPBL^hzthB{~L<< zD7w8@E~gPve($o06!L=Y+vK_d7eJIR@(We)uF*n)JDXtZoDhVU8vXyn)|&*B9ez4y83oW#Vm)ITGy z!R2TBR=-{Jy3{c8829K8f3_G@j>Ot+l{Jnv2F3od_>czL>`gSO47v#)CN{8#bkbYz zn&kc)P6HFM-fgq{z8ji*!schB@>H80TBnbG_rw`MyGS~(Z1IXJFmg}E4O-Z2Pm(k^ z75FaVFGlLM;NajufB%^WtS7Y8OqD+GtD6}N_r;rn0wit2waTwv#lW;R0Zei}AqC8F zXdCYS<~`;B#eK2R?)M4Vu2v1PVKV@xhkd^wntNRF$mU^)bP{jBICy_;!y8a%3iALa zn<}@gsi|rG;rh+D$Jh^3Gga4QAWt)+q?rG!hHH;!di~?yna!PH$)(t`5Gk5V&RjM{ zIdY3GO1ZBKM~;?VkBjo#Ddw=4(G ziL@YxjIOFot)o&zM5d`~HmYg1VtDw=_4pwz=rD42-LNH1?XjL@a0Fv4KJTJm#29rH;ol7wxK^vUpTwSMI}T}$|s4(B(Nim$^^f8$~A<`7SOB@xnF zQPe!6G9$GDr9iOh?_ZxdxVfD<@$0V-ZV#8DCP-s`csxG#*EJT&-5x#?AWA@vN0`r9 zs0LeUB$|A;l$B6s48p_~esAFpF^M8A%%ebVG}+HwMyRK%xY+A@Qw7x%EW7Mz?n2lGz2IacW^4tIfbDTKsKz~S*)J9A` z5kw5g^qv;qYJD@gL(*Y$p`s^9tg!A_hGq?hpBGtdeEp??%jKSv|MnwD5N)AL*r2;Zt3 z^^f5A!73V4i=1l0AAnj05?i(Dzn!$IjAV>!D0?x+(CmWcsTwXFrT9^vG5U20;MHPE z9hn?UHmWQSuPqF#Vr$clA1WFSF)B+u^u|A(^B?eafkXyReG4)41oC_#WkyZBm`_3} zImckwdGgz_kr6SAYRcaL^}v4X7yJZ!7H1vhz%%OjrHbY(?|^dkALozgWR48cm2ets zQhS)vWUHnAAV153QKL9mewtA-f;sayHT^bWYTtj8e@`UNOa+}0vn^#C={1hTa7@6P zCO>8^NY(wm#N6kh3qY}d=kDHw%9CF7NWru}+GwM?mtjPyzU{Xxpb0nKAth^iyowGLd?_X9J$VOz%IR`gqyA0|AW{D!uRu zC-uzDZ4OVoCD$lPqQW50^Ii+%aA)}jIL5q2K}Zbe3;K6%;-tME@4=;qRaK&@Oy;D= zW`X^oWEX~)FQaH?HK>taJ@rD22IExU+Ss&z(eRQxEflc687*}S4}7Iz;rD}hFu>|l zPa13SKvwq09*8oP)e{@^>86NmW48~RUyl#Wxh36bZcPt8osLqy&cN&kBqjt=2{+DjGduEZoW%SvAo)_3Q^MVEzBSr+_5lj}VougPQSHx=M_v?tP$_zVZ_ znr0~ls&M2TDHzbDiu4?KO)|eIFX5?eCNOMj_`<)Q6-Ok7q=s^#D^KTxbac5moqVEr zi1T`J3lzgX0{g%tuU@6#kpqQsV-FseA% z{fGc=0CR7}bDP_i%UN&WjilKfG{~?31RFm5T6{-%~B%mkP%z9-ogM9^t(o@L34A>0z zs27K85uds3bLGWDt=?%W-sn0pRh(bo9!EBWY;pdJS&=$4ZzNH(1a-z>FeQLK@-#brZ%?~Rv_lP`u}8#&MUa{B-C_V@R{1Qnm#(&DL~^8w2YikbDy z@D9(|*lAD#bNrdp+Ss_?)>Nc-U~F^I&syZa*5pJthuJ!Vz6s~Rq3o`<&A`{4?*0H} zsE$`xSF1puqUEZoFEv$3_tm2uJGraCD7G9i%S<|IA>bw=`2whyc0<0jsE`hnc9FF) zeUwdLh!;l?qdUQ>IuhPWpfYb24w8$4wuE#H` zsZ)k8(nZCqFlQ|I9?(U|C?46aeqqUp&KOmA_qIrvOvA>&3mfBQoFS5{B0DsT!?)C$ z*j(>i>c4x?Y8ytbu_TdjFMb?EkWe}st{bjr}5dTLdhwbHW4|T2UZJAPlb+NH~ zWoZ{hHrxC@S^&`z_@)H%x9&%)n5T=@248JGbTvqlTw1N>7x=m7{R5KEm|zCpC}bUU z;`#WjJe`Z>sf;SBWVolj;PH+o@?V+fWWh=5aS`h4BE^rGb7+Beblok41X#L~$O zl8*)d7ktxKR@2?1AU^7j+xJ!uC0>Sa-IJqhrWf2+!}5zw#mwB?Fus2#V7* zZyxLs2xbA|-DtZY+g(x4QC?t!K%9vd4vytItb5){X5;;o00Y>aPN+b%xA<~*rD*d%z*JjLTxE}m zsZjsF+}_OX|Ak_L4DnA^jNWCs=cQ5x0*5lz>SUDIfBFYwHRQm%Nvq}ym>WB_p_Rdu zfX(U8%p#%g_Z{~kY7A3fPB}uQ;ji0*}~vE@xtjXNuOoK*XZ9UAeNWcXYac06p0@(Iv>l?96dit4czj)u6hcF!xEfdLQD*2!+&9LN0LEHlxq!1BbuK-f9BAJ zV0bDw7yBZ+PQeRpN7ttm%;G*q3rMaETFg5{2+)2)&@p@hI=lk)vokS zIj$D^%6^StkLI>wMv|sU_MvL_{S#>e+P0GP$2qcxBJ24(GPd*g=ja`gPxoD2NwzE4 z!G2U$^j1VAvXXW0Qu)*oP3YtfzTR`LZ12h=X+dW-9$>cKHk_dRl zl(v+ZRqfGeL4kB}zk^nIIq<+gg210o(zd31k=UX-rO;ya{+W>Z&S+fofXmRJxZ z5mWIO73b5?K6l91whDLS{c#K4z>V*Gklq)HRq%GFO5bre+UXtBeQeTh4-$1IqB@rOaurk)j**<>^GYY%65!&S4PProS$(H_TyIb!8M6{`e1o&mN$XNvJ#|` z%qc(z0$-7>9;{wTm;z_S+8igfGS2ck-)PW@)gwF2tSWf_By3@5DE!;wY6B`3L}QTp zxl$p{ihkiPii9U`?c^SgO|>k5C3mlXvCl?WLf45F`>xxZrAau_V3?6bLPyxzCH*S!k#l{&Xg%r`uqDkJ3A*&o(zHOidhFQAQ>X9VyZ`Xf<0ns^K7ID)?c1+kzkU1l`}dzefB*dp z_~Td3z`!!k)5S5Q;?~>i8;c&h3AkQ7SkgS@)Na2Q|NlD~f6SYzQdITeh|=DoHyP)8 zMeJow8rN=@tIdwuFzf23r}HMVthsKObP(}S1TPRqXX z_Sd!IZkt$!h>uKH<}dGfGjZm9#)uD0f9@zpZ@Z`bY3bI(D%@MQev`Yn{aekK{#iUa zK{oe){bwxLva4T;Md#y}^e>m6Pyhd%b;kGocJDT?*?i>l{`vcB?=`SDd@S61b;CKP z)H!V;B%j#sQ8dh5@!8DWL)j1{yf# z!v9!1l`kDNrYE@mf9}{<%X&fCXdnM;od6e?I@S%YZ>9%ci(D{o`HPS9xj$6x>_2S9 zz2)h@Pd@}J7;e;8uVhN#WDqQTw?D37ZR+~W*{-k7Z$D78>4WQz3xXAYrskeo^)YYq zQ>oC;8J4Tv{(4mFgoj?us0_KgUh-SSI?Fs$?ex8|-|xKH7;}8b{_A&?&I>XgXku9P kDmh1Y*Z2RfvrS*;i_D!~u``&XkO2rhUHx3vIVCg!03F&7(f|Me literal 0 HcmV?d00001 diff --git a/assets/textures/next_icon.png b/assets/textures/next_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..03f960917cfa90b54f94ae60cba0ce82d202f2e8 GIT binary patch literal 714 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&%?a=caRt)<2P>GYa3KZgKI4)g zzhDMtHg-;KNohF+MI{wg6H_yDOKV%d(8#FhnAo_aoc!*d-Z@K_u2{Kh?bU0y?%aL& z^vB=z>l^1WFfgw2ba4!+xb=3{>#!yVkygPaMw?g9lA5a8db73Rd;RtcN{urghG)OO z8uh!n@$*{a*)tzDJm*ww5pd!F694<+_P-BivfE#=`c8;DfIV zgchiN3~!ivWG_ReXcp5Pm20dTwiz4-RTo4QzAR8}sF%9U^z^dCeFa_~#x0GS4EHAL zFx^nO#j?P23ztH1f;fYe1xtZv3Fm=HFGL(vFX}R!a%^Wfw!oWV(hU?3>Ay%Jba$k&wc+rgO&yHcFP|xpX`}pvzz-aJOCXg+m$V0XjpE-I%t6|TK==D!egbQ~weEWJqDs^s4+rX|0A7uv3@Q*~G!U%P4H)%A8!7hk<+nelZy)0JOK z8Mf~;kIY^1b#M3Yr*k6jTieJN*C%{9JmEKYJ0zTef&FiWe!+)lk9JOaG#41@44$rj JF6*2UngEY&hi?D? literal 0 HcmV?d00001 diff --git a/assets/textures/no_screenshot.png b/assets/textures/no_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..14df091a24ef9c3ed15e28688c9b08296a324d7f GIT binary patch literal 2043 zcmb`I`B&138ixU;T+(d0kTqtLPGgGN;$W$vl#U~ssR@16FoeW~aLFCRl&+RbF1g=K znarI8ZX#l4;#z8X%5crC3^Ei$bHT0KoH_SDm~)=BX!q!mxv|mf9~yUWn_P0*FfQp^MYIgz*ef@4 z=xE{&@Y(9fg#4N2A_vjc=6j#&-vw?eC0BgZ{aFhk-2FF@{|n+D3uzMT+J}a2j3syF z#DPXN2Tq*EQ-9uoC%;S&$Y{ejyL(c`^z#U3?o_^AT+Ogboo_kJemCgas1KO8j@7UE znH3rX)^8K*-tbE`q0&GAyB1W(h|uQ3Sl_K-9*iYK-bI~y45wJ=7SMOCvCQ|1WBWt@ zz6yW3ke2r8OV)EzB|_Mk;S2XOB#TizWhoNot8=9bwVUMy+Ep7Vv4NVF{r^Wj$qcIv$if3T%-)Q~sLewh)yEA1g$yZaA*-EQ7`#j)z z>Dw;AFz9={r~)>LqfSB04&2veK!+66+WL@MPSOZumg)tK&t0}GL20T_!_8UMnal+b z=fDw=OF(}+Ol!U{hBcPa1~I5)-^Q|RrsUUr(|09ol#h)ZvcI|6!72N3V}-vK1yNgq z{o1}17`607Op!kJT0bt`*$ye1yNYd4t~p44A`*gGO^=nJyfd#Q+^dT*K)uF7HCyKx zBX$hA84TtPq%|CVG{XDA8#rqf*JsvF&>&d4n}tB}sN$PoqUzPwS7sm(@pq9AFk^cpATDOiU@^DTxu+kLrg`*YHR z6EXkV$>$EudV35mSs+HXUX&HL5XC8+qw|F08D&p9v+TwuF$XxH1K^JzGuaJ@F%0bd5t>gM?ly>4lBe=@) zgjIQRx7-9PRr01Lb#G&KCrdLQjR``gbE^g@+=6vubVq-658iMbs$8?*=_5Gu8d#PS zlhzNsLkR-{9s|AjN6eHdpL#;Nst~i*55Ms4^AY#>2|SA1l|zu+@;DAVK&Lg!yfg&Q z&`lB(Ec0`CD|3fR&QI((gVV>@`=u1IW~1fhaxPl-I!yqz$Y<~q&vO>!>$iV89PAgp z1WcS3%E@$Bm4;8Jkg_G8G$fB3I+`^+d${HFD@B(vF1@2%9bB<`To{$b=#Cv%DCgpJ zJ1a>L#X8EBd69+`o8HiAR!SSGbHE|4;EPG81f~Q zg~-gdHb}lRwU2!8WW-1<{%9WR#JuX1Al&_S{Kbsk^?jUFVI7K4F?Wl2;6VvzcV-FY znJ4Q-Rc~=fR+~A}z<-Z=j?OETe&wS#JM|Jt1?L%GuQuX-yjIPhpq(RwnIXaH+GwbV zRBiF7|B_$@ug&*nE$SA9t)7Fhe>*n?@|G7=I~X6bDB8`N>ms}gi$0lF9-*>aPrp{C z*YYNb5}Wt_CIm*d(X0~R*Nj;*LUBL#8WU|L1j-=c8L%7HaiR$5_33OQh? zf)Mj7YyWh<=XYq$76DN~@5Zb%ux<2|YE2a{G528vNwBexvSNwN_GC7E#H*Z=M4@@j zV>;bQ_Q03HM`(%Wqf+TIJeIrXPoO(FIp0ZFld<$OqID-O)D^RES7bXsv&7klkUEaY!%10Bg0Z4|W^(9EA%CACbN?1=VKX6^qTD zBd&FrN;K7TC#(XvMMolg8o#z}#sF*XW`_ZDzuHac;1ELEnUskCrSzVM`OC4lv|>}) z_=B1Dm=Y72ECK56HjUI3`K#3(?3`_D&k`8_11q}ZMF0Q* literal 0 HcmV?d00001 diff --git a/assets/textures/no_texture.png b/assets/textures/no_texture.png new file mode 100644 index 0000000000000000000000000000000000000000..681b810820fc21ad7269147beddbcc419e0daf46 GIT binary patch literal 281 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|Y)RhkE|14;~Xv*;X`O+`b-bgbfeS0-coAET; zzMw#_XBo^<>rPjOEPQ$^sBogkzcU6u?)~UwTRY9FVFs&Y!9};@TKl%1i0%Dcl5HCH zcit7X*7WK3{D1DAq%B$@@bmQ!wQr?6Ue;|gc)Z}Q37`1snQw3YY}aL#+#JF)i|rn} XXw|Dr-?)>3E@tp_^>bP0l+XkK)@y7& literal 0 HcmV?d00001 diff --git a/assets/textures/no_texture_airlike.png b/assets/textures/no_texture_airlike.png new file mode 100644 index 0000000000000000000000000000000000000000..634ee8ca552b07a2b0bc7ecdc1848a480175a18d GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`m7Xq+Ar*{sC$aJ!FyJ}z>A$$Y ziJG@KD|_m7*4uAta_96tZl18^Z{qXgHB#yR4(m!b3OF&d&S{>hKRdx8K>R&px(#!~ zffVN*)lDX*2N(>wuJ_GkZK^V5aA^3+`Qw*K5|_7xi*(0th1?{8yI$Km8~HCrZtdM| b=~G@PGsEDqVDx&RBN#kg{an^LB{Ts5xq&{0 literal 0 HcmV?d00001 diff --git a/assets/textures/noclip_btn.png b/assets/textures/noclip_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..5d7372de561f4cbf7da7e4c220c8b5ea3f08566d GIT binary patch literal 1236 zcmV;_1S|WAP)MzCV_|S* zE^l&Yo9;Xs000D2Nkl`0xXBGpvPC@s1#}Q%3V;Y9+R0Z* zKrur^HN#beARAQ?u#N#@h7o&;2dW5YAZ(hnjImn{0e@QNZFkiW5VjOBs)B$l8v$X} z-++)B0(vb4{HBJ0BaB;o0Q()sAMPa^R}iJ2%6*pG5YZ90?5_e=N17hVTi}{ z648V=$oJHfiw_?qjOY|Z8Rk7r<9E>mM7hIe7YSfF&5YQr(2R4106qfr5}K9}BSbfa zy6`7w?g_Hq6#`gB^Yrw_o(LDn!ABLB`JGNKvP;+SDn>PTeB%NE zB|{H!-SGmbG3nOkqLdy1#hJw<998? zA12TH0`A)ke@!YBNLX)v^poj*0mC-WzsB<=GAy-O8oj4LjSwen(x0847r>`BuYdAO zAe<$DS2;H4bhm?2*9u?-o51LF2&0=C4qtPt_QVGQweu=I&^as;7Ax5oR`hfYb?hY|Rn@MvjO;3`HFW|74Q~@t? za2`GV5MS`RWsOiS*GyN3H@GDac#U^C#BIh*#`ZsG#Lr7}7D+Xlj18@>%LI9Y)f7-f z5k+K@&dYIBiS6Nup(m(P>%2gnp+oE^Tde~VrwyOMQMCm4>C_1blBL#}p{<%aLVyO< z4o#ggY>E5T5|D4G8Lm+6+@OB%@TzJ83U&QJm>ktkj_S*&>Qoc(rB1+Q)dXbg%A%DM z;NyZuz+UwPK?HbMz%K+GaQ(Ab0+jz9p%3`X yAy+|)AP9mW2!bF8f*=TjAP9mW2!bF8vv~%sMbtcIH^y0 zLf5PY#dIfEl&C((!XB|6HvqH((b%h@HEX}jF zXD2P=j6QaA%Cd~jk!;Hark}C;w8#Cxy0teLcX+w*^&d$Nya`<${15xmVCA(y_IRm@)C#nH6^yatDMsHJ{9 z_E`2ww9Vo?`|{=hsjEHOUEew6zKJb76g)vb%1QKH@;1{`(^)lLSMSQ&f9&m5wV!FR n+YaB?zZ}?+ULW=Rg-i{T>XMS@?763OK_Ths>gTe~DWM4f0VlGz literal 0 HcmV?d00001 diff --git a/assets/textures/player.png b/assets/textures/player.png new file mode 100644 index 0000000000000000000000000000000000000000..6d61c4342f39fd8da8330e97117c68a3709483fd GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<5!3HFyJAa%3QlXwMjv*C{Z>MhLa!}-9{{8ab z&TEibqWl!w& rU}f~-R;g-O%k1_*>%@MOhihZx0?vo`Z!=Z~TEO7x>gTe~DWM4fSl%(n literal 0 HcmV?d00001 diff --git a/assets/textures/player_back.png b/assets/textures/player_back.png new file mode 100644 index 0000000000000000000000000000000000000000..a84a066f9aedb4425db17ce1572217da3525708b GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<5$P6SE-Lv|E6k~CayA#8@b22Z19JTFVdQ&MBb@06hRMfdBvi literal 0 HcmV?d00001 diff --git a/assets/textures/player_marker.png b/assets/textures/player_marker.png new file mode 100644 index 0000000000000000000000000000000000000000..f2cc2c6f0f4c543f2ed5537df60cd2b6f7600aef GIT binary patch literal 2166 zcmeHH3sX}^6h65j5Q7x)F(O!Wup*iQK^y}#+(TdhD5 z(AMf0Xdpv1emte^!{+i6aaIhAUJ5};ci3EL*bYE=i7~?J3KQitHOW0 zD37;`^{sM>%l53X1tHHyUcrP_8tBs$&-|jGn*dn$UKNC zFILXIE7+4YG+laBXhXI5I6im>I>H9n__MPTad6lKre2x1uTOzMvk!DjCd0`Lw%;CG z(W9_QmdO2_Q#&!TkrSJ0W{Cz<$rEN}C$^1^fNYY%U+))#qFleD)`@Q5#NGkXyI*5^ zr|f4zn1>f!xT(f6%oCa7f8K7U;(cZ}K-(B1%Oe$v2i5nBCi{bQIgV7}4^-jpowHOA zgBC5}MeqXrJ(mOL2(|g*eWsICXwvsv-;@;dV9gHnykzn~EvA&R*`ZxY;`3tN^Q}6a zPUz+)k4GE1jJY6-y1Z<#)qh=4q3}ws)k?)G+RWm=UdSm=c0P8r%UOaPnZ;VT44j3y&URk zK{Qx1GS1sTEOE}KC((f)$HE7U%C)cs@Ol?F(lL>aBakQys>5CmU{kHHSxhi}ryE!P zWh95!;^p{K8YGRX4cKGqgks>^@`m7USbb~3ocX|)7OWw-pEIbIaMugG-AKRxn^T$V zd2qI~VZioAHL2B*w67_y_ZTXz21|i60Cx{fnlZjBP#^^bx2>aP$^-1B(DC@vJ+g~6 zBfxiaAHmHp$0-|?1-?lZ~s(dgXhy0Ymr8ao~(IREb6`3ib9fz3ciznnh%-80{GrM?^R&77_jwEzGl$#~qB5u@uC5Y^t0dqG0Iug* zZkUzo-j-bzh3{ULUx%u?0W8+3Ej6JwOH!>+oRv@ymt)INDKywFe@m+ul21oeuNS}y z4H=<-ocSMBd3&2$%nw<_J@~f4I<5ERVcKFc zO29|up>-P1JmsKCA2V3*KuPZ}nny|R(`Td~&~N*msIe?7X(NBJNlqyjE7Xlm+gfR$ zGA$-L%`v9!Z+5%6d6Q3#HBHIdfq~wpXgzj0jSp4Xh)gQ+nX;O-rD@IyDBEvzocHg^ zA&}LE(fEI6xDSrznqxAFg~M2VCh51{>1V0r%KO`zip zOM?7@85kIum|57^Id}!d#3iKU^h{m7e0&3AYnv9W+qh}-)?KGAK79K8#mje}zW@07 z>(AeR(ZzioKur%kT^vIyZoQp(a$1vtfNQXeqiYC@jKmQ}_YjMJ|BsgjG{${niz|;V zf2b5$a9;3poR^|RTOt%aJMYM~gW(`6hn_9?o!DB^DR^UfjIwr=RQCC?DW}}byoXF5)-(JUT2$Zmp_!vz|5@vAa%^Z| i;6@=5km5)FBkRHo#qO#MF(tr+!rGYa3KZgKI4)g zzhDMtHg-;KNohF+MI{wg6H_yDOKV%d(8#FhnAo_aoc!*d-Z@K_u2{Kh?bU0y?%aL& z^vB=z>l^1WFfgw2ba4!+h2fp@jEXndkl|BBm;>X_F59XHMb?Fw|+eOao*brhySGfD=1I0e!9+J=h^%6 z`nkvFJXL?09k?&%=DD3(Ha?%vZxUi|dHnj#;x$JYzJ9Kcs}D_T`1Ld0wYXNXVZP7j zXFt6e%f9O~-+1HCwc+l3fdzm6s4}em+sRP%ouB>7dwE`oJN6P6D*v-EJp7>+UH)F4 zDH-X{n`+nvZ>-!lqzOggE_}0#p@tvJXqOP9fKvC^;hRgp1 z8XhF9yD!fqF!%oc%Vg4}8*OVmQOZ za$tuG$AY*=UseWi8!()=_bUFnn}O-YeO3{N-7XRi+g)TFHoGV|>~&Fb*y*C-u+>G! zVWW#d!VVXcgbgkh3--I%EZFYC=n$^J_=3ZQA-9odfvN!08uP~^rr14u|qB)@t8l{ePt*`xOGA4b4PXYh3O Kb6Mw<&;$S*k&Lqd literal 0 HcmV?d00001 diff --git a/assets/textures/progress_bar.png b/assets/textures/progress_bar.png new file mode 100644 index 0000000000000000000000000000000000000000..e80367191644d95c36f28921bdd6b82c1f6ec421 GIT binary patch literal 413 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K53^>?;i(P=vF< zBeIx*fj<$18CTdZ&jbpxmw5WRvOi?z6z7s%{Uog#Xq1+xi(^Q|t+#g!vkoOlG(7y{ z`ax)^#)}76TmwEZ>}^jLJO7B)rfosBqbs{QJG*0y6~{WiT{~2oG#pLNe$JWbBmd;- zewO-9O=it#4G;N#EbUjKy+l-Mqya?^qZ(7&saP9SU2c zmX>~QTOap1#b<*5?SD2Fj6kPxFccJil|4{p>=|=?_1grW2O#AN3=Z$+GP2Lp`J^-9 RAt=}xJYD@<);T3K0RW6PjtT$( literal 0 HcmV?d00001 diff --git a/assets/textures/progress_bar_bg.png b/assets/textures/progress_bar_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..4e30ae889deb94fd1db1b65c03f2bf95ae33b5be GIT binary patch literal 354 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 literal 0 HcmV?d00001 diff --git a/assets/textures/rare_controls.png b/assets/textures/rare_controls.png new file mode 100644 index 0000000000000000000000000000000000000000..953d9e06d6c3dc7f5078f0c656ee249ee123cd25 GIT binary patch literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^4nW+%!2%=&JC;8LQcT58o*^6@p>Nzkf}8~&k;M!Q z%o{cVkBaA{ u6m2$`5Cg*oQSV7AC&PFUA_>~lO4f0@?Niq~E%W;pNZixa&t;ucLK6V-l0N_d literal 0 HcmV?d00001 diff --git a/assets/textures/refresh.png b/assets/textures/refresh.png new file mode 100644 index 0000000000000000000000000000000000000000..7193677b43bea725df64fc6c84de9546787c1ffd GIT binary patch literal 3660 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 DZQC6y literal 0 HcmV?d00001 diff --git a/assets/textures/search.png b/assets/textures/search.png new file mode 100644 index 0000000000000000000000000000000000000000..aace8044ac235bcf5935ed8a72c4cb136746a916 GIT binary patch literal 1908 zcmZ`)do;r*hEgWpDPBKS7mN|uQ4@RU{bU;RZBGG9cM4QZ&YGw2;badcT z8^0=@n`5_k4cg)jkHrR_ZUs6C)#;ru{p*MnFzSSy14BnK9k99qvx%(Q|Ku6*tVeE= z;j}fOm}70k#m=-1{B|WKep=e`sqE6mH$a&vhfe)BT5{~=GqH7W4FDtAPF6XfUJMg0 zG)SRiFgWX|#Hdo<6h%bjftQL_(g^a6TBkuGS!%-M3?v2!!-LD$RV3F+$;z#Y3Lq&# z_lXLz)euUtSfqnLL7jl2b-JcIw!dO0JQC!^>f882mU~^SkXzr`0xD$%3+f2q+OnxW z1#r9If&|iNnfe3`b*4|E043HiVCS~J?2$Nf98bhA$TsSxMtQ>bU0iB`d;--0U8=Ry zJ$(nF6is0}714=%paq!4^8&7*G-=qVnCc)Uq1GXZTEy1xasEqQke2{%ythu6(G*D6 zDF?-+D!Ue41yd=tX`8nuzFuMdv3v8p=sx4(#)k(VUp+7uXc=E9WXOjk_@2pQs9(A3 z%Fe+(gW#yEwq~Ezh<5oM;;RAsmL}jVtqyDg;3RO6+(ZS+wa!eGy%Xv)cY8sdSn&;K z=Ps^SBI2ddjn|*vyW-*bv2?_ZIuz7pOr~qbsWd5m^(%dw z+V538xQ3H(-4_xppDzC3sA8pkh`&sY6Nru)^Z(SD+qXv7TA(SYSIuP68ayyP+H0?< zaowVMuFU-jk-0cLhl6vgDyMeXaRacK-*^{WOw9U|9&j|Vd<#9+JeGf*Iy5>ye)R3f z!qwGPGPOQQ{6H;&(Wc;AI2huTl){mQQt=*;F&g!IJS<08ZLf>0u+ENg7s343c&1m7mb$YSA$oW=Ou(;WVMAGQ+9 zU{v(RH~IzT(6ZnE)c?h#57hs2bs8di1zc28QeyD_;W>7ZU(8N^yT}Ash708loHCa&7K!Wixy30l1~_H zt%s71ttI{vsu(~*IL^WdO-8p|;mo$+Ut=}jyoU52j>@^LpIy;y;Aknl_Rb!tje;t0 z4`ZQ&Pd~ODxH|QAh4G_8Ov>8b6FKrNMcniQ{aQW-sL+^9m+j?+iW)Y8u-@$4+ZyKqr5_OPwunRDLxq8ZX8<(~$=F88q9F&sb0`#Qm~!Ma?^gL*o;c9xJrXIg(l#>Bs<*5P z_Oorurv`1CY#wa(+`Gd3dpUO9?{|2zxdX|~OX;BN^lt;g?q=M*AyZzwcOF=an-aR$ zWvqD9Pja5@lpfUFh3giFZ@YlBpa8ns&|&HPv69cekehvTx1-3K!uJ{pthx&pQMU_X zz_OYBuTku;iCT@2eL`2sndtrXyaIV!7w1Pc;qV4`&`*DVI@)O3>nZp58l2 zh86Z3I>$`!bGRg_`o{BU|3AaXW{t-BrPl3lJI0##E>?4JbBElN!tO>W;jyUC9TP&C zcdY$f=J{hbR^H#JQa?PKHouPy0s)EE-W+MDc;Xz%zs`T$`R%Yt?QXQVAN^tty#4`5(6Lbv2~siR@4 z@`h)pegmd;G66wTd;1v6$`5#mabMDZA>){oRw~(J+i2oaY0;7FQaR<-xTRoy>!JU5 oz)Hy+PJ7*y{67!tO!d0_mw-1lpr~N2?{5lnuywWJ5y{E_0lF-AYXATM literal 0 HcmV?d00001 diff --git a/assets/textures/server_favorite.png b/assets/textures/server_favorite.png new file mode 100644 index 0000000000000000000000000000000000000000..6a3fc5efe7ce3a9ffa0f2e0a800afdace65285c4 GIT binary patch literal 916 zcmV;F18e+=P)Ky5;j10^mHOxQ-`a%p0KmH*s0SF)_1|+})G695v z1~9NPXE6ANGPrrGS(%G4*n;HEL>L&{r5G5#{Xysf2p|*#z?wm>_`#seq^=ymAb5{~ z(MFjyN|!l>4JenV0W|wRiVg;V0Ac}?e}P(mG6*sJW)Nol$sqWji6NQAQk|cH;UNQq zm?DFdlZwxxuQ#Ji`5CT#`o!@5?;nQO3>*yKK=uIy5DUY9U;s%8>of4kaxgOg;$z`v z=V26;WM@+S1(XJc6vHD1wG?B11#O|FA6~xu!u*!;^WXPhKC#_-`uE?z|MdU?#Pan! z!&at$?17yA#_UY&Pk|b~0`Y60-j6`Pfb0N9jmTvNHh&%lF$OUn1_mCUe=BcGPTRw9 za?fjq`v3vN__m&b;mKnLTUiyB1p+}LN(`dFVEGC3C?j(4{DTm$iQ&(2~h3>gSMOm<6L<^ZgVCXR&d&Y15hNsV`X@@;p4ZCRX-O@ zd&E!=H1Z8d3Lt=({sCRc2}%Pj3|H?z_+Rzw^4C8MpMEefeEbf`2B2QX3n zK#EF$0Ad0q-G4wM|NRB4v19>x{TWc;>OY3hyZx$w literal 0 HcmV?d00001 diff --git a/assets/textures/server_favorite_delete.png b/assets/textures/server_favorite_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..e35c6aaf05f7ee2f176f98d57441a1c3885170b7 GIT binary patch literal 748 zcmVxFe<%$Yj8k0%#L?^QAE|7fM+{2(~)|aZ(E2|Np(d%xPWWFe{8pKW7?{UxrK1a zmV2gXTHUjf-v9u=l6leq0H|qPxsZ0(tBb;)fXbtUzK3whfpF8OhyMTo-nNtJ00930 z0MVX+=>Py}008L;2cln9=mrI2004sk0E7Slpa1}^006cC0J(o^!k2o+gK)>FgUpY2 z%(9Emhjh=qlF*xf)R%qLn10ozh1SfR*r$ivtBTvLjN7=C+_I0}-m2fYk>9zJ;lh~W zz?SC8o#)P<=@=2|9~J2$7wIG!=_MNM*{AHPx#O>|ODQvd-00|g2Y6crjDA0Q(tD=;xLI6XZ;LP<+h zSz26NU2SuBeU6oupP;0tsjhSRK^Y!@n`TF|$`}_U<{{Fw5 zCYt~N0MSWAK~xwSRl#Q?LSYyN;5%g%GLlVY%icSyVcl;YE6N_(l&$gG9i8*VbpcS& z^ftgyv^lAOs`EZGbS||OQ0V$val+uBEUUTfdp8Vub(A%xva^ll)_edxBNOwK7p6Wg zd{d*t^=MxD&RkKR`IAm(E(a=s>apbK3FV1zuTgIaH1@%p#3AL83+;u-sR`cSMJNv} zfUf2EHh#TF*&uWsr)NjI`#Y2n@y9e2JLqp}o!O@N2~FwZxVsoA>s)7eS^=imH*DK9Z19?OM0000^VCxB+P>HCKL)kWY+1DS&4*8KKYb4FnECGW*XkJy9Sa*@ ze_nbDXbNjdkY6xE%>HLT9lr~P00k;NT^vIy;!^vsa~(F|alLzFmR#i9|Npa0ITnWS z@0#bP0l+XkKx@UXz literal 0 HcmV?d00001 diff --git a/assets/textures/server_flags_damage.png b/assets/textures/server_flags_damage.png new file mode 100644 index 0000000000000000000000000000000000000000..3f0bf0daf5c1d43bf4d1e16b3eda18d87b8be7cb GIT binary patch literal 713 zcmV;)0yh1LP)c)Km-8-Af{bsl069r%$ zFb1>+UC=0vM7S+H4=kXIaZVGeVy*JM|E^HdciDJTurLNOL83dHqH?#0exB zK{kRce@R-UB)f4OqTPJh1+;N4Aa6q{AB7>kFLF~C2I~e7VWbCBb z)&s3KMPI3ZhFW{mS@w=F1}snkWm$LM>za-rt*xshHJhXS>Y~=)h)t+kru=E9DhC5w zoe~xG7)5;v@*J`;IY}`|#yzdCovy0S0mD-W)*WXx6C$_1Z*3G>+l;IY18W7gm3S%YeiG!EpZ%SD*)=pHurEqc}X8LOR6BQf(|Nj600I9IOvbDUbtgyPj z$E>ry&(+{QLrbTvxVgT@xx2udoS)Oy+PAvGpr)^w8G)7993frD&qZpzEes;#od%h7dqeV3b}!N$zb(bdY!&O$^&hlq&~ z5)Z?~$Ed5WyT8S%uCu|y#Q*>R|Ns9@O-+%KlmGw!0002Kzrnk_zNxIQtgf=Kv9!Fr zz5oCKXlQ2u006MDv8k)AD=RM9+1akHufoB^RZds2vbL+Nuu(`-!@;PnVFfoy0xvXsA5}UYin%w_WDv7N1c|Qo}HZl005+BRr>3dV(alOEMMV=opP#FRg@dlHt(}vdUmHYL7CuiF zMJF02larK{m6kg(JWm%!R2Dv997dXrnyag)P*72HR&*dBL2O2AbWm}7czje;Rh5&K zu&}Say|A%#md#w*4n76uwooU zTO35j&DsvBF^~WN0GV`BPE!B{EX4yTea6^)r33*21E9*L?~?@rj_;Z$)Aff5f%w`f zAI$o9ZT{OH7|Z_oR7L&$+!6s0$^QNG)d~aw0s#!W{QCU-!w3Q*_W2|NQ@J|G%`>`M z0s$ws?68#Vvo8Swxc=V`$H)c&DGZaZ+9jp5G@vt||0u0kb z2T`7t7XbkQ0R#!GhF%A7$|Xtw008JoL_t&-83lkbNJ0SsMDL+PgG(ergAEN5&AA3e zAQC!SIjIna3Q>WY24$4y52^+gLkK4mX;PsC9cs0?$knEDYzqxcroWkQNs?s7JZ9?A z;^tS91t{2jOkc)p{*m=ZOl(G?5M!2;Of@jH4<~c^At56opTM;395u(j|@t5+o`v;wFM1*2ztmJ}4dP)F0sF)Ck&a`5*p=IEkZwLKHDC za=O%jtuYpQ$9KPT-hKBx;6I8&xEu_o5A(J?Wwq)8fC>QE?RI#28nf4%CyLAEISgZr z(`k3z==U9Zo@BS{#)>PI8Al^Y%lfHY1aJ;?&Or zWx0Ig;gCYTE^s`mlv2Vl1bp99*6WwMw_i9x|J~Hlb}#IUEKom6E@5CNrm|Nv6|N;Ic$j&0@9sP&S+QBm-r?f2EWM fgkd&`eW<Eak-aXNX+h7Ab|SPTpUINBC4 zo;r2v|J12d{~!LLBNFj%zJ~aM+Z}un9$P0SNC<42C?YP9%5k~#vHt)07XLok?^NV0 zKgjw2^?ykT35hA|H72JpC?BqO9ydI9W7y@PKf}~(?`fc$7(8A5T-G@yGywn{!BX1* literal 0 HcmV?d00001 diff --git a/assets/textures/server_ping_2.png b/assets/textures/server_ping_2.png new file mode 100644 index 0000000000000000000000000000000000000000..8dca0be0d0a62de2046535079a018fb611b21388 GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE({hRn3dtu2NdBf@Q5sC zVBi)8VMc~ob0mO*>?NMQuIvw)m;?+Nb1HK!fI^L)E{-7 zsZ*!^Pn|mT|KT4xA`$=QYlttn-N6^(v2|jC#2kx%pZ<3~*8eY@t>q^^=fnPg^BWr* z9e;Ki{fkhz>NZEO;pT}03ND)%domhZ4#n?!BB9L8%-r0%)FRBT8%SPZeV-s?@#Ff! h8eb8+#|_Wj7^06Fy0*SB+5mJ6gQu&X%Q~loCIIN+Rm=bY literal 0 HcmV?d00001 diff --git a/assets/textures/server_ping_3.png b/assets/textures/server_ping_3.png new file mode 100644 index 0000000000000000000000000000000000000000..c2cab017e10b3b6babfafe953cf663b7066cfa46 GIT binary patch literal 245 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)3BisC9v-11Q2-;1OBO zz`!jG!i)^F=12eq*-JcqUD+QpF$ox`FVDZ(0u*ZUba4!^IDK{UUe3b~JZ|$3`A#^- zoWXflB+e-A=srfKc?W&NCd`&u@}d8b=&@IJELHrRoii^6@k_mKV-C3*dNtdRw}4-A zO6Er+-F?^jrKi-DG1R{P$ak(IvDvHT`A5-zs_&#+I-{ANeAh{@tmtJ**je0=vh%l8 jO_uVEbjAs%_ZPCRZ85nRx&ML#&@~L6u6{1-oD!M<0YFnr literal 0 HcmV?d00001 diff --git a/assets/textures/server_ping_4.png b/assets/textures/server_ping_4.png new file mode 100644 index 0000000000000000000000000000000000000000..03b4b5b83cf3c9dabc49234a31ec827a21bc02c2 GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkEFdh=kcmmafO&R~Z75JE$pCP8H}kFA2s zxjVKBMq4GcBuOZAo=-{CJeQED$v0hL>UoO?I|Ug&H0fq8I(UC4&^887S3j3^P6c#H5WF&~;`|^V2tXiU#NGRa%j6XzR0MXT!n)lTND#sgSe=0M6n9RkQc*B$e?fo| zyKtX^luR)ef@G>&-0du8ZpXPE(rKBn#u+Q_Sn$k(XI9*?##uTolm7by-cQOmELgDM zi4_l7i02flF=-rUA)d41fdx-2SkP!W_@kK=B@2|r>fu$HIp-V)iWVt2rR&fSkovEVk;@H3bySTP$8Q3%0DtS+HZlC2KR8#a3Qy^-|-K z1-tgVO{bg0vBp^@)t8U@^DPN(y3)E5_8`GcGAYkU<7X0^I~Lr2`1<|br?4ikxc(b~ zS6tIo#mS^RW5KQSieDU%lcMl~c+mTr2LZVkL{b#({bNI*$o-yRulF?%v?1_{qP>4~ zEU}fa`9BH&ZlWEV*sgB#_kx{QyEx^6SG(|nT|*q}bh=48ixjt{C|F~C+5@Y-_7=%G z=V-JXkk~qtN?EMV0*0qnnF53aYa0DH&I65>gX1t&ZJ4TY7OGyDdd*#=(@jERa~8Wl i#98c~#O4Rh9sCB{Tao+q-1zta00004>ti^@+=>QiQE7$hEQ`G3RY@DXvHh=$u6+S=Ge zd|6pp|9|XU+`ubsmaui^1PiVPOaAGbFCN{bP0l+XkK@H9k* literal 0 HcmV?d00001 diff --git a/assets/textures/start_icon.png b/assets/textures/start_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3830fb3ae493b622db421f8470b74dc910a0ece4 GIT binary patch literal 912 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrU=H_maSW-r^>*%A?<1p4;3%lS0OC(wTvj`;bVP3N&-(9g~wc7QWt^3aQXCDyTz&VFm{Xk~$YmEar zzLAV&4a^DRKlo~5%96dV1~%Muf5P`cs$#O#XE}?kq`8$ZOKYC+H7 zxMadN!JU@hp9%ao~+_CD$9~_5*Rpo~5r}%<$R&cz$s3HY1b$9aFa2 z;^*sB%j$)?Gd`1^_&Zbg9`iQizCUY9MG`g&T6!pNx_-opYeR&9behyp*H;=1jsA>0 zHCzb~f*F|SGg*8RJuq=SL*Cb2ItN06+j{P&%ctCWCAuTpnD+pTK{u17F(v2B#wa1Y4zVB})oSbc!|L7_Br{9~3C3LR^i z`7c-9|Ml#8R6|$O4YygW@5&ec+$y@@(B$o3RUFda&3tox$Inofjk`xeBU3zhA;o=5X5op2&l;u*+8eg(_UT{qLP&_&?on+4a`7FR$?w z9Q@HK8Gq?s{n@Ykotat$+zgKiAM-!E!_Quh>3j^A)h2EZ#W}|%`WsJA;Z(bxF7c*` z!Cd8sL20e(_U7xcvkSAzg(RGIbQ#L|vL5n2CCf2)snlw&fc}{YvxJ2Hc<%o%xKA=f zn^TXQ^>A>)lyfRpf)3e#D;uN_8Y~H)U&HRYzcK$n;WH~PgLH#8%dab3e)oXq2UpFh z7+_TJv`xP2cxH=r#{vBZ#XuzikMABdeZ0IPY$JDIgB8o+E~XVsS2QKU1RO*c spE_op{M#U|*b+GTbq7A+A^nqmqFmf#8}S8Jz?{b5>FVdQ&MBb@08B=O*Z=?k literal 0 HcmV?d00001 diff --git a/assets/textures/sunrisebg.png b/assets/textures/sunrisebg.png new file mode 100644 index 0000000000000000000000000000000000000000..33523178853a27665f9661748dc31ea5163993ab GIT binary patch literal 4435 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 Z`hPl-frM`Bn{@yH002ovPDHLkV1iz{aytM3 literal 0 HcmV?d00001 diff --git a/assets/textures/unknown_item.png b/assets/textures/unknown_item.png new file mode 100644 index 0000000000000000000000000000000000000000..c8cf616a710463e4b8694bb94718180259387564 GIT binary patch literal 292 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!cYsfbtGZK`1_)(qI_GG*=4iR) zYP;rZyX9%S15v(?2M`tLdKMb`ml+0D7zb4v2UnT|SDA!VnFd#zhE|(}*4V@}+s3x; zdA#maq3ukdu~R%<977}|SsNI`m<>5xj?Z1w#GA1ATK)gYzf@x1Z`=B8j;Hsx$6xQJ zDk(kBy!fZdHSohPfoBFBNt<`3Xtb$ha;?t3xpBGn+cnc_pBC>s$9KDLLWBLJWeazw zcJ*>H2`^+T%Bb?#^>j^fn){QIrMiDko?o{vHF{D}1LHl097FT(6KpDiwtQ%1u9C>p i$vkU0d0TPXOL^9xyjk-qZoLM&kHOQ`&t;ucLK6UmVQ^Cb literal 0 HcmV?d00001 diff --git a/assets/textures/unknown_node.png b/assets/textures/unknown_node.png new file mode 100644 index 0000000000000000000000000000000000000000..cb59ff4677a745d8e9b5c4f4ccd9a357e3f4db0c GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJe}GSjtFESshof1Tzei_n!T*Ma zODsoofl|4iE{-7;w^VyNc^M3O4*mEx|L3E5K^UwRkD_o2J;q1ci;S(pS>UpU(Y5C=Lm+@ZhV=WL$@vyd* pJlM=VIhJY1ifAV9(wOK2c2XOdlz4w6w*f6?@O1TaS?83{1OVH!MqU5_ literal 0 HcmV?d00001 diff --git a/assets/textures/unknown_object.png b/assets/textures/unknown_object.png new file mode 100644 index 0000000000000000000000000000000000000000..c0166c31f8ff34468d52ff0accbb6bd592261e6c GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyLIFM@u0YzH!MuT?;XlLw|6Bh2 z|NlRBjSbW49#KZGqeFMzCV_|S* zE^l&Yo9;Xs000E1Nkl8TYOl;SgsP=?=IZ8{;@eOY>lnnik5dC?Ux$LGT zO}wl2f`Qc1y!DJFLoqOfd0e1*v(z5Yhu>(@l6y0PWdQp$5icBQ{ZxiV~*@wB9>KUvAVHKvcbd_Dm<`Sl2B@BJI zfax9Cg-MtWlcoe>I;MTH3ze8ADxt`r2Gc{b2YqS6tA;cs7{!?8$R50o=~E>feQCsN zyX?W2nDUhb{ESy4-DL}^@H$OMNkB2C(Xs<6T*a$QNx`F-rpgZFVtQXmK{lq(Wd}xJ z8mA=T6ke-j2gYD}N=d?Ayvk(sGAl7cLn@LDK4(1~k!eXXQm7^Z2m1qbmurlepRrZKVwD=_6L z30Q+y6TM{%CS#hVgrf%ycvZ=Bv#Z z&UGTyGg9`UCv`+BR-14i4K(Kh1+ov5i1ra7wGst1(30~!EZY#GjA+a0qE=uWjl^<> z2V@(vIZU*J6v`L6vWS~I%@Em!A=DAAi4yuME~GG?TH;g7AlZgOF4LT=EM%x+BAY23 z!jBW=$~KJR0xj9YY(|kK17QX+g)*+-Up05jHsn)FY{%HdYDy_(ExWlwTO6UEY(syx zaO)f-N46oAPq@LYa)92l5BY52R@uYtvJYY2-~j$z;S0*~XBRzWBf`8)1x>`OhB@R& zr13re?4-MF#XS^L$u(lBri5om(ZA@-di>c!7uk#~o@P1=*~l)AaE4>-XDg+AND;Y; zLM9vVr;^(gBxJG)f6B>FkdQ?M{`^F`f`n|g;?Ek=6(nS{4S!aWsvw~oJMgEJR0Rol zum^vZ5>}AVlPdfvA*3MTPWIu?0tE}b*pEN+6)g1QF#gO_u+X31@ux_^!T^rqM}>lh zT#ggJ3Iz{&oFraF3L^5TAs+J-R1Bh)o0+d5<9_}mmd_M)4CM?hSwcv`$1u*(oW+FH zG4LQ~iS!j=bsQ9O5w8`bsAJ&~F7lt1q^jd#1b^_4Wpq-, + net_events: mpsc::UnboundedSender, +) { + let window = winit::window::WindowBuilder::new() + .build(&event_loop) + .unwrap(); + + window + .set_cursor_grab(CursorGrabMode::Locked) + .or_else(|_e| window.set_cursor_grab(CursorGrabMode::Confined)) + .unwrap(); + + window.set_cursor_visible(false); + + let mut state = state::State::new(&window).await; + let mut map = None; + let mut media = media::MediaMgr::new(); + + let mut nodedefs = None; + + let mut last_frame = Instant::now(); + + event_loop.run_return(move |event, _, flow| match event { + MainEventsCleared => window.request_redraw(), + RedrawRequested(id) if id == window.id() => { + let now = Instant::now(); + let dt = now - last_frame; + last_frame = now; + + state.update(dt); + net_events + .send(NetEvent::PlayerPos( + state.camera.position.into(), + Rad(state.camera.yaw).into(), + Rad(state.camera.pitch).into(), + )) + .ok(); + + use wgpu::SurfaceError::*; + match state.render(&map) { + Ok(_) => {} + Err(Lost) => state.configure_surface(), + Err(OutOfMemory) => *flow = ExitWithCode(0), + Err(err) => eprintln!("gfx error: {err:?}"), + } + } + WindowEvent { + ref event, + window_id: id, + } if id == window.id() => match event { + CloseRequested => *flow = ExitWithCode(0), + Resized(size) => state.resize(*size), + ScaleFactorChanged { new_inner_size, .. } => state.resize(**new_inner_size), + KeyboardInput { + input: + winit::event::KeyboardInput { + virtual_keycode: Some(key), + state: key_state, + .. + }, + .. + } => { + use fps_camera::Actions; + use winit::event::{ElementState::*, VirtualKeyCode as Key}; + + let actions = match key { + Key::W => Actions::MOVE_FORWARD, + Key::A => Actions::STRAFE_LEFT, + Key::S => Actions::MOVE_BACKWARD, + Key::D => Actions::STRAFE_RIGHT, + Key::Space => Actions::FLY_UP, + Key::LShift => Actions::FLY_DOWN, + _ => Actions::empty(), + }; + + match key_state { + Pressed => state.camera.enable_actions(actions), + Released => state.camera.disable_action(actions), + } + } + _ => {} + }, + DeviceEvent { + event: MouseMotion { delta }, + .. + } => { + state.camera.update_mouse(delta.0 as f32, delta.1 as f32); + window + .set_cursor_position(winit::dpi::PhysicalPosition::new( + state.config.width / 2, + state.config.height / 2, + )) + .ok(); + } + UserEvent(event) => match event { + Close => *flow = ExitWithCode(0), + NodeDefs(defs) => nodedefs = Some(defs), + MapBlock(pos, blk) => { + if let Some(map) = map.as_mut() { + map.add_block(&mut state, pos, blk); + } + } + Media(files, finished) => { + media.add_server_media(files); + + if finished { + map = Some(map::MapRender::new( + &mut state, + &media, + nodedefs.take().unwrap_or_default(), + )); + + net_events.send(NetEvent::Ready).ok(); + } + } + PlayerPos(pos, pitch, yaw) => { + state.camera.position = pos.into(); + state.camera.pitch = Rad::::from(pitch).0; + state.camera.yaw = Rad::::from(yaw).0; + } + }, + _ => {} + }); +} diff --git a/src/gfx/map.rs b/src/gfx/map.rs new file mode 100644 index 0000000..d95a4d2 --- /dev/null +++ b/src/gfx/map.rs @@ -0,0 +1,447 @@ +use super::{media::MediaMgr, state::State, util::MatrixUniform}; +use cgmath::{prelude::*, Matrix4, Point3, Vector3}; +use mt_net::{MapBlock, NodeDef}; +use rand::Rng; +use std::{collections::HashMap, ops::Range}; +use wgpu::util::DeviceExt; + +pub struct MapRender { + pipeline: wgpu::RenderPipeline, + textures: HashMap; 2]>, + nodes: HashMap, + atlas: wgpu::BindGroup, + model: wgpu::BindGroupLayout, + blocks: HashMap<[i16; 3], BlockMesh>, +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] +struct Vertex { + pos: [f32; 3], + tex_coords: [f32; 2], +} + +impl Vertex { + const ATTRIBS: [wgpu::VertexAttribute; 2] = + wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x2]; + + fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { + wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &Self::ATTRIBS, + } + } +} + +struct BlockMesh { + vertex_buffer: wgpu::Buffer, + num_vertices: u32, + model: MatrixUniform, +} + +impl MapRender { + pub fn render<'a>(&'a self, state: &'a State, pass: &mut wgpu::RenderPass<'a>) { + pass.set_pipeline(&self.pipeline); + pass.set_bind_group(0, &self.atlas, &[]); + pass.set_bind_group(1, &state.camera_uniform.bind_group, &[]); + + for mesh in self.blocks.values() { + pass.set_bind_group(2, &mesh.model.bind_group, &[]); + pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); + pass.draw(0..mesh.num_vertices, 0..1); + } + } + + pub fn add_block(&mut self, state: &mut State, pos: Point3, block: Box) { + let mut vertices = Vec::with_capacity(10000); + for (index, content) in block.param_0.iter().enumerate() { + let def = match self.nodes.get(content) { + Some(x) => x, + None => continue, + }; + + use lerp::Lerp; + use mt_net::DrawType; + use std::array::from_fn as array; + + match def.draw_type { + DrawType::Cube => { + let pos: [i16; 3] = array(|i| ((index >> (4 * i)) & 0xf) as i16); + for (f, face) in CUBE.iter().enumerate() { + let dir = FACE_DIR[f]; + let npos: [i16; 3] = array(|i| dir[i] + pos[i]); + if npos.iter().all(|x| (0..16).contains(x)) { + let nindex = npos[0] | (npos[1] << 4) | (npos[2] << 8); + + if let Some(ndef) = self.nodes.get(&block.param_0[nindex as usize]) { + if ndef.draw_type == DrawType::Cube { + continue; + } + } + } + + let tile = &def.tiles[f]; + let rect = self.textures.get(&tile.texture).unwrap(); + + for vertex in face.iter() { + /*println!( + "{:?} {:?} {:?} {:?}", + (vertex.1[0], vertex.1[1]), + (rect[0].start, rect[1].start), + (rect[0].end, rect[1].end), + ( + vertex.1[0].lerp(rect[0].start, rect[0].end), + vertex.1[1].lerp(rect[1].start, rect[1].end) + ) + );*/ + vertices.push(Vertex { + pos: array(|i| pos[i] as f32 - 8.5 + vertex.0[i]), + tex_coords: array(|i| rect[i].start.lerp(rect[i].end, vertex.1[i])), + }) + } + } + } + DrawType::None => {} + _ => { + // TODO + } + } + } + + self.blocks.insert( + pos.into(), + BlockMesh { + vertex_buffer: state + .device + .create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("mapblock.vertex_buffer"), + contents: bytemuck::cast_slice(&vertices), + usage: wgpu::BufferUsages::VERTEX, + }), + num_vertices: vertices.len() as u32, + model: MatrixUniform::new( + &state.device, + &self.model, + Matrix4::from_translation( + pos.cast::().unwrap().to_vec() * 16.0 + Vector3::new(8.5, 8.5, 8.5), + ), + "mapblock", + false, + ), + }, + ); + } + + pub fn new(state: &mut State, media: &MediaMgr, nodes: HashMap) -> Self { + let mut rng = rand::thread_rng(); + let mut atlas_map = HashMap::new(); + let mut atlas_alloc = guillotiere::SimpleAtlasAllocator::new(guillotiere::size2(1, 1)); + + for node in nodes.values() { + let tiles = node + .tiles + .iter() + .chain(node.overlay_tiles.iter()) + .chain(node.special_tiles.iter()); + + let load_texture = |texture: &str| { + let payload = media + .get(texture) + .ok_or_else(|| format!("texture not found: {texture}"))?; + + image::load_from_memory(payload) + .or_else(|_| { + image::load_from_memory_with_format(payload, image::ImageFormat::Tga) + }) + .map_err(|e| format!("failed to load texture {texture}: {e}")) + .map(|x| image::imageops::flip_vertical(&x)) + }; + + let mut make_texture = |texture: &str| { + texture + .split('^') + .map(|part| match load_texture(part) { + Ok(v) => v, + Err(e) => { + if !texture.is_empty() && !texture.contains('[') { + eprintln!("{e}"); + } + + let mut img = image::RgbImage::new(1, 1); + rng.fill(&mut img.get_pixel_mut(0, 0).0); + + image::DynamicImage::from(img).to_rgba8() + } + }) + .reduce(|mut base, top| { + image::imageops::overlay(&mut base, &top, 0, 0); + base + }) + .unwrap() + }; + + for tile in tiles { + atlas_map.entry(tile.texture.clone()).or_insert_with(|| { + let img = make_texture(&tile.texture); + + let dimensions = img.dimensions(); + let size = guillotiere::size2(dimensions.0 as i32, dimensions.1 as i32); + + loop { + match atlas_alloc.allocate(size) { + None => { + let mut atlas_size = atlas_alloc.size(); + atlas_size.width *= 2; + atlas_size.height *= 2; + atlas_alloc.grow(atlas_size); + } + Some(v) => return (img, v), + } + } + }); + } + } + + let atlas_size = atlas_alloc.size(); + let mut atlas = image::RgbaImage::new(atlas_size.width as u32, atlas_size.height as u32); + + let textures = atlas_map + .into_iter() + .map(|(name, (img, rect))| { + let w = atlas_size.width as f32; + let h = atlas_size.height as f32; + + let x = (rect.min.x as f32 / w)..(rect.max.x as f32 / w); + let y = (rect.min.y as f32 / h)..(rect.max.y as f32 / h); + + use image::GenericImage; + atlas + .copy_from(&img, rect.min.x as u32, rect.min.y as u32) + .unwrap(); + + (name, [x, y]) + }) + .collect(); + + let size = wgpu::Extent3d { + width: atlas_size.width as u32, + height: atlas_size.height as u32, + depth_or_array_layers: 1, + }; + + let atlas_texture = state.device.create_texture(&wgpu::TextureDescriptor { + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + label: Some("tile_atlas"), + view_formats: &[], + }); + + state.queue.write_texture( + wgpu::ImageCopyTexture { + texture: &atlas_texture, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }, + &atlas, + wgpu::ImageDataLayout { + offset: 0, + bytes_per_row: std::num::NonZeroU32::new(4 * atlas_size.width as u32), + rows_per_image: std::num::NonZeroU32::new(atlas_size.height as u32), + }, + size, + ); + + let atlas_view = atlas_texture.create_view(&wgpu::TextureViewDescriptor::default()); + + let atlas_sampler = state.device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + // "We've got you surrounded, stop using Nearest filter" + // - "I hate bilinear filtering I hate bilinear filtering I hate bilinear filtering" + mag_filter: wgpu::FilterMode::Nearest, + min_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }); + + let atlas_bind_group_layout = + state + .device + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + multisampled: false, + view_dimension: wgpu::TextureViewDimension::D2, + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + label: Some("atlas.bind_group_layout"), + }); + + let atlas_bind_group = state.device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &atlas_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&atlas_view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&atlas_sampler), + }, + ], + label: Some("atlas.bind_group"), + }); + + let model_bind_group_layout = MatrixUniform::layout(&state.device, "mapblock"); + + let shader = state + .device + .create_shader_module(wgpu::include_wgsl!("../../assets/shaders/map.wgsl")); + + let pipeline_layout = + state + .device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[ + &atlas_bind_group_layout, + &model_bind_group_layout, + &state.camera_bind_group_layout, + ], + push_constant_ranges: &[], + }); + + let pipeline = state + .device + .create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: None, + layout: Some(&pipeline_layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + buffers: &[Vertex::desc()], + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + targets: &[Some(wgpu::ColorTargetState { + format: state.config.format, + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: Some(wgpu::Face::Back), + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + }, + depth_stencil: Some(wgpu::DepthStencilState { + format: wgpu::TextureFormat::Depth32Float, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + }), + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + multiview: None, + }); + + Self { + pipeline, + nodes, + textures, + atlas: atlas_bind_group, + model: model_bind_group_layout, + blocks: HashMap::new(), + } + } +} + +#[rustfmt::skip] +const CUBE: [[([f32; 3], [f32; 2]); 6]; 6] = [ + [ + ([-0.5, 0.5, -0.5], [ 0.0, 1.0]), + ([ 0.5, 0.5, 0.5], [ 1.0, 0.0]), + ([ 0.5, 0.5, -0.5], [ 1.0, 1.0]), + ([ 0.5, 0.5, 0.5], [ 1.0, 0.0]), + ([-0.5, 0.5, -0.5], [ 0.0, 1.0]), + ([-0.5, 0.5, 0.5], [ 0.0, 0.0]), + ], + [ + ([-0.5, -0.5, -0.5], [ 0.0, 1.0]), + ([ 0.5, -0.5, -0.5], [ 1.0, 1.0]), + ([ 0.5, -0.5, 0.5], [ 1.0, 0.0]), + ([ 0.5, -0.5, 0.5], [ 1.0, 0.0]), + ([-0.5, -0.5, 0.5], [ 0.0, 0.0]), + ([-0.5, -0.5, -0.5], [ 0.0, 1.0]), + ], + [ + ([ 0.5, 0.5, 0.5], [ 1.0, 1.0]), + ([ 0.5, -0.5, -0.5], [ 0.0, 0.0]), + ([ 0.5, 0.5, -0.5], [ 0.0, 1.0]), + ([ 0.5, -0.5, -0.5], [ 0.0, 0.0]), + ([ 0.5, 0.5, 0.5], [ 1.0, 1.0]), + ([ 0.5, -0.5, 0.5], [ 1.0, 0.0]), + ], + [ + ([-0.5, 0.5, 0.5], [ 1.0, 1.0]), + ([-0.5, 0.5, -0.5], [ 0.0, 1.0]), + ([-0.5, -0.5, -0.5], [ 0.0, 0.0]), + ([-0.5, -0.5, -0.5], [ 0.0, 0.0]), + ([-0.5, -0.5, 0.5], [ 1.0, 0.0]), + ([-0.5, 0.5, 0.5], [ 1.0, 1.0]), + ], + [ + ([-0.5, -0.5, 0.5], [ 0.0, 0.0]), + ([ 0.5, -0.5, 0.5], [ 1.0, 0.0]), + ([ 0.5, 0.5, 0.5], [ 1.0, 1.0]), + ([ 0.5, 0.5, 0.5], [ 1.0, 1.0]), + ([-0.5, 0.5, 0.5], [ 0.0, 1.0]), + ([-0.5, -0.5, 0.5], [ 0.0, 0.0]), + ], + [ + ([-0.5, -0.5, -0.5], [ 0.0, 0.0]), + ([ 0.5, 0.5, -0.5], [ 1.0, 1.0]), + ([ 0.5, -0.5, -0.5], [ 1.0, 0.0]), + ([ 0.5, 0.5, -0.5], [ 1.0, 1.0]), + ([-0.5, -0.5, -0.5], [ 0.0, 0.0]), + ([-0.5, 0.5, -0.5], [ 0.0, 1.0]), + ], +]; + +#[rustfmt::skip] +const FACE_DIR: [[i16; 3]; 6] = [ + [ 0, 1, 0], + [ 0, -1, 0], + [ 1, 0, 0], + [-1, 0, 0], + [ 0, 0, 1], + [ 0, 0, -1], +]; diff --git a/src/gfx/media.rs b/src/gfx/media.rs new file mode 100644 index 0000000..ac5d158 --- /dev/null +++ b/src/gfx/media.rs @@ -0,0 +1,42 @@ +use std::collections::HashMap; + +#[derive(rust_embed::RustEmbed)] +#[folder = "assets/textures"] +pub struct BaseFolder; // copied from github.com/minetest/minetest + +pub struct MediaMgr { + packs: Vec>>, + srv_idx: usize, +} + +impl MediaMgr { + pub fn new() -> Self { + Self { + packs: [ + BaseFolder::iter() + .map(|file| { + ( + file.to_string(), + BaseFolder::get(&file).unwrap().data.into_owned(), + ) + }) + .collect(), + HashMap::new(), + ] + .into(), + srv_idx: 1, + } + } + + pub fn add_server_media(&mut self, files: HashMap>) { + self.packs[self.srv_idx].extend(files.into_iter()); + } + + pub fn get(&self, file: &str) -> Option<&[u8]> { + self.packs + .iter() + .rev() + .find_map(|pack| pack.get(file)) + .map(Vec::as_slice) + } +} diff --git a/src/gfx/state.rs b/src/gfx/state.rs new file mode 100644 index 0000000..9d1cfd1 --- /dev/null +++ b/src/gfx/state.rs @@ -0,0 +1,233 @@ +use super::util::MatrixUniform; +use cgmath::{prelude::*, Deg, Matrix4, Rad}; +use fps_camera::{FirstPerson, FirstPersonSettings}; +use std::time::Duration; + +pub struct State { + pub surface: wgpu::Surface, + pub device: wgpu::Device, + pub queue: wgpu::Queue, + pub config: wgpu::SurfaceConfiguration, + pub fov: Rad, + pub view: Matrix4, + pub proj: Matrix4, + pub camera: FirstPerson, + pub camera_uniform: MatrixUniform, + pub camera_bind_group_layout: wgpu::BindGroupLayout, + pub depth_texture: wgpu::Texture, + pub depth_view: wgpu::TextureView, + pub depth_sampler: wgpu::Sampler, +} + +impl State { + pub async fn new(window: &winit::window::Window) -> Self { + let size = window.inner_size(); + + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: wgpu::Backends::all(), + dx12_shader_compiler: Default::default(), + }); + + let surface = unsafe { instance.create_surface(window) }.unwrap(); + + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::default(), + compatible_surface: Some(&surface), + force_fallback_adapter: false, + }) + .await + .unwrap(); + + let (device, queue) = adapter + .request_device( + &wgpu::DeviceDescriptor { + features: wgpu::Features::empty(), + limits: Default::default(), + label: None, + }, + None, + ) + .await + .unwrap(); + + let surface_caps = surface.get_capabilities(&adapter); + let surface_format = surface_caps + .formats + .iter() + .copied() + .find(|f| f.describe().srgb) + .unwrap_or(surface_caps.formats[0]); + + let config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: surface_format, + width: size.width, + height: size.height, + present_mode: surface_caps.present_modes[0], + alpha_mode: surface_caps.alpha_modes[0], + view_formats: vec![], + }; + + let (depth_texture, depth_view, depth_sampler) = + Self::create_depth_texture(&config, &device); + + let camera = FirstPerson::new( + [0.0, 0.0, 0.0], + FirstPersonSettings { + speed_horizontal: 10.0, + speed_vertical: 10.0, + mouse_sensitivity_horizontal: 1.0, + mouse_sensitivity_vertical: 1.0, + }, + ); + + let camera_bind_group_layout = MatrixUniform::layout(&device, "camera"); + + let camera_uniform = MatrixUniform::new( + &device, + &camera_bind_group_layout, + Matrix4::identity(), + "camera", + true, + ); + + let mut state = Self { + surface, + device, + queue, + config, + fov: Deg(90.0).into(), + proj: Matrix4::identity(), + view: Matrix4::identity(), + camera, + camera_uniform, + camera_bind_group_layout, + depth_texture, + depth_view, + depth_sampler, + }; + + state.resize(size); + + state + } + + pub fn create_depth_texture( + config: &wgpu::SurfaceConfiguration, + device: &wgpu::Device, + ) -> (wgpu::Texture, wgpu::TextureView, wgpu::Sampler) { + let depth_size = wgpu::Extent3d { + width: config.width, + height: config.height, + depth_or_array_layers: 1, + }; + let depth_descriptor = wgpu::TextureDescriptor { + label: Some("depth texture"), + size: depth_size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Depth32Float, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT // 3. + | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }; + let depth_texture = device.create_texture(&depth_descriptor); + + let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default()); + let depth_sampler = device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Nearest, + compare: Some(wgpu::CompareFunction::LessEqual), + lod_min_clamp: 0.0, + lod_max_clamp: 100.0, + ..Default::default() + }); + + (depth_texture, depth_view, depth_sampler) + } + + pub fn resize(&mut self, size: winit::dpi::PhysicalSize) { + if size.width > 0 && size.height > 0 { + self.config.width = size.width; + self.config.height = size.height; + self.configure_surface(); + self.update_projection(); + (self.depth_texture, self.depth_view, self.depth_sampler) = + Self::create_depth_texture(&self.config, &self.device); + } + } + + pub fn configure_surface(&mut self) { + self.surface.configure(&self.device, &self.config); + } + + pub fn update_projection(&mut self) { + self.proj = cgmath::perspective( + self.fov, + self.config.width as f32 / self.config.height as f32, + 0.1, + 100000.0, + ); + } + + pub fn update(&mut self, dt: Duration) { + let cam = self.camera.camera(dt.as_secs_f32()); + self.camera.position = cam.position; + self.view = Matrix4::from(cam.orthogonal()); + + self.camera_uniform.set(&self.queue, self.proj * self.view); + } + + pub fn render(&self, map: &Option) -> Result<(), wgpu::SurfaceError> { + let output = self.surface.get_current_texture()?; + let view = output + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + + let mut encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + { + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0x87 as f64 / 255.0, + g: 0xCE as f64 / 255.0, + b: 0xEB as f64 / 255.0, + a: 1.0, + }), + store: true, + }, + })], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &self.depth_view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: true, + }), + stencil_ops: None, + }), + }); + + if let Some(map) = map.as_ref() { + map.render(self, &mut render_pass); + } + } + + self.queue.submit(std::iter::once(encoder.finish())); + output.present(); + + Ok(()) + } +} diff --git a/src/gfx/util.rs b/src/gfx/util.rs new file mode 100644 index 0000000..f93accd --- /dev/null +++ b/src/gfx/util.rs @@ -0,0 +1,63 @@ +use cgmath::Matrix4; +use wgpu::util::DeviceExt; + +pub struct MatrixUniform { + buffer: wgpu::Buffer, + pub bind_group: wgpu::BindGroup, +} + +impl MatrixUniform { + pub fn new( + device: &wgpu::Device, + bind_group_layout: &wgpu::BindGroupLayout, + init: Matrix4, + name: &str, + writable: bool, + ) -> Self { + let uniform: [[f32; 4]; 4] = init.into(); + + let mut usage = wgpu::BufferUsages::UNIFORM; + + if writable { + usage |= wgpu::BufferUsages::COPY_DST; + } + + let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some(&format!("{name}.buffer")), + contents: bytemuck::cast_slice(&[uniform]), + usage, + }); + + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: buffer.as_entire_binding(), + }], + label: Some(&format!("{name}.bind_group")), + }); + + Self { buffer, bind_group } + } + + pub fn layout(device: &wgpu::Device, name: &str) -> wgpu::BindGroupLayout { + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + label: Some(&format!("{name}.bind_group_layout")), + }) + } + + pub fn set(&self, queue: &wgpu::Queue, to: Matrix4) { + let uniform: [[f32; 4]; 4] = to.into(); + queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&[uniform])); + } +} diff --git a/src/main.rs b/src/main.rs index 5b8817e..f517ee2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,124 +1,46 @@ -use mt_net::{MtReceiver, MtSender, RemoteSrv, ToCltPkt, ToSrvPkt}; -use rand::RngCore; -use sha2::Sha256; -use srp::{client::SrpClient, groups::G_2048}; -use std::time::Duration; -use tokio::sync::oneshot; - -async fn handle(tx: MtSender, rx: &mut MtReceiver) { - let mut username = "hydra".to_string(); - let password = "password"; - - let (init_tx, mut init_rx) = oneshot::channel(); - - { - let tx = tx.clone(); - let pkt = ToSrvPkt::Init { - serialize_version: 29, - min_proto_version: 40, - max_proto_version: 40, - player_name: username.clone(), - send_full_item_meta: false, - }; - - tokio::spawn(async move { - let mut interval = tokio::time::interval(Duration::from_millis(100)); - while tokio::select! { - _ = &mut init_rx => false, - _ = interval.tick() => true, - } { - tx.send(&pkt).await.unwrap() - } - }); - } - - let mut init_tx = Some(init_tx); - let mut auth = None; - - while let Some(res) = rx.recv().await { - match res { - Ok(pkt) => { - use ToCltPkt::*; - - match pkt { - Hello { - auth_methods, - username: name, - .. - } => { - use mt_net::AuthMethod; - - if let Some(chan) = init_tx.take() { - chan.send(()).unwrap(); - - let client = SrpClient::::new(&G_2048); - - let mut rand_bytes = vec![0; 32]; - rand::thread_rng().fill_bytes(&mut rand_bytes); - - username = name; +mod gfx; +mod net; + +use cgmath::{Deg, Point3}; +use std::collections::HashMap; +use tokio::sync::mpsc; + +#[derive(Debug, Clone)] +pub enum GfxEvent { + Close, + Media(HashMap>, bool), + NodeDefs(HashMap), + MapBlock(Point3, Box), + PlayerPos(Point3, Deg, Deg), +} - if auth_methods.contains(AuthMethod::FirstSrp) { - let verifier = client.compute_verifier( - username.to_lowercase().as_bytes(), - password.as_bytes(), - &rand_bytes, - ); +#[derive(Debug, Clone)] +pub enum NetEvent { + PlayerPos(Point3, Deg, Deg), + Ready, +} - tx.send(&ToSrvPkt::FirstSrp { - salt: rand_bytes, - verifier, - empty_passwd: password.is_empty(), - }) - .await - .unwrap(); - } else if auth_methods.contains(AuthMethod::Srp) { - let a = client.compute_public_ephemeral(&rand_bytes); - auth = Some((rand_bytes, client)); +fn main() { + println!(include_str!("../assets/ascii-art.txt")); + println!("Early WIP. Expext breakage. Trans rights <3"); - tx.send(&ToSrvPkt::SrpBytesA { a, no_sha1: true }) - .await - .unwrap(); - } else { - panic!("unsupported auth methods: {auth_methods:?}"); - } - } - } - SrpBytesSaltB { salt, b } => { - if let Some((a, client)) = auth.take() { - let m = client - .process_reply( - &a, - username.to_lowercase().as_bytes(), - password.as_bytes(), - &salt, - &b, - ) - .unwrap() - .proof() - .into(); + let (net_tx, net_rx) = mpsc::unbounded_channel(); + let event_loop = winit::event_loop::EventLoopBuilder::::with_user_event().build(); + let event_loop_proxy = event_loop.create_proxy(); - tx.send(&ToSrvPkt::SrpBytesM { m }).await.unwrap(); - } - } - x => println!("{x:?}"), - } - } - Err(err) => eprintln!("{err}"), - } - } -} + let runtime = tokio::runtime::Builder::new_multi_thread() + .enable_io() + .enable_time() + .thread_name("network") + .build() + .unwrap(); -#[tokio::main] -async fn main() { - let (tx, mut rx) = mt_net::connect("localhost:30000").await.unwrap(); + let net_thread = runtime.spawn(net::run(event_loop_proxy, net_rx)); - tokio::select! { - _ = tokio::signal::ctrl_c() => println!("canceled"), - _ = handle(tx, &mut rx) => { - println!("disconnected"); - } - } + // graphics code is pseudo async: the winit event loop is blocking + // so we can't really use async capabilities + futures::executor::block_on(gfx::run(event_loop, net_tx)); - rx.close().await; + // wait for net to finish + runtime.block_on(net_thread).unwrap(); } diff --git a/src/net.rs b/src/net.rs new file mode 100644 index 0000000..323fe06 --- /dev/null +++ b/src/net.rs @@ -0,0 +1,252 @@ +use crate::{GfxEvent, NetEvent}; +use cgmath::{Deg, Point3, Vector3}; +use futures::future::OptionFuture; +use mt_net::{CltSender, ReceiverExt, SenderExt, ToCltPkt, ToSrvPkt}; +use rand::RngCore; +use sha2::Sha256; +use srp::{client::SrpClient, groups::G_2048}; +use std::{future::Future, time::Duration}; +use tokio::{ + sync::mpsc, + time::{interval, Instant, Interval}, +}; +use winit::event_loop::EventLoopProxy; + +enum AuthState { + Init(Interval), + Verify(Vec, SrpClient<'static, Sha256>), + Done, +} + +struct Conn { + tx: CltSender, + auth: AuthState, + send_pos_iv: Option, + username: String, + password: String, + pos: Point3, + pitch: Deg, + yaw: Deg, + events: EventLoopProxy, +} + +fn maybe_tick(iv: Option<&mut Interval>) -> OptionFuture + '_> { + OptionFuture::from(iv.map(Interval::tick)) +} + +pub(crate) async fn run( + evt_out: EventLoopProxy, + mut evt_in: mpsc::UnboundedReceiver, +) { + let (tx, mut rx, worker) = mt_net::connect("localhost:30000").await.unwrap(); + + let mut conn = Conn { + tx, + auth: AuthState::Init(interval(Duration::from_millis(100))), + send_pos_iv: None, + username: "shrek".into(), // shrek is love, shrek is life <3 + password: "boobies".into(), + pos: Point3::new(0.0, 0.0, 0.0), + pitch: Deg(0.0), + yaw: Deg(0.0), + events: evt_out, + }; + + let init_pkt = ToSrvPkt::Init { + serialize_version: 29, + proto_version: 40..=40, + player_name: conn.username.clone(), + send_full_item_meta: false, + }; + + let worker_thread = tokio::spawn(worker.run()); + + loop { + tokio::select! { + pkt = rx.recv() => match pkt { + None => break, + Some(Err(e)) => eprintln!("{e}"), + Some(Ok(v)) => conn.handle_pkt(v).await, + }, + Some(_) = maybe_tick(match &mut conn.auth { + AuthState::Init(iv) => Some(iv), + _ => None, + }) => { + conn.tx.send(&init_pkt).await.unwrap(); + } + Some(_) = maybe_tick(conn.send_pos_iv.as_mut()) => { + conn.tx + .send(&ToSrvPkt::PlayerPos(mt_net::PlayerPos { + pos: conn.pos, + vel: Vector3::new(0.0, 0.0, 0.0), + pitch: conn.pitch, + yaw: conn.yaw, + keys: mt_net::enumset::EnumSet::empty(), + fov: Deg(90.0).into(), + wanted_range: 12, + })) + .await + .unwrap(); + } + evt = evt_in.recv() => { + match evt { + Some(NetEvent::PlayerPos(pos, yaw, pitch)) => { + conn.pos = pos; + conn.yaw = yaw; + conn.pitch = pitch; + }, + Some(NetEvent::Ready) => { + conn.tx + .send(&ToSrvPkt::CltReady { + major: 0, + minor: 1, + patch: 0, + reserved: 0, + version: format!("Minetest Rust {}", env!("CARGO_PKG_VERSION")), + formspec: 4, + }) + .await + .unwrap(); + } + None => conn.tx.close(), + } + } + _ = tokio::signal::ctrl_c() => { + conn.tx.close(); + } + } + } + + conn.events.send_event(GfxEvent::Close).ok(); // TODO: make sure to send this on panic + worker_thread.await.unwrap(); +} + +impl Conn { + async fn handle_pkt(&mut self, pkt: ToCltPkt) { + use ToCltPkt::*; + + match pkt { + Hello { + auth_methods, + username: name, + .. + } => { + use mt_net::AuthMethod; + + if !matches!(self.auth, AuthState::Init(_)) { + return; + } + + let srp = SrpClient::::new(&G_2048); + + let mut rand_bytes = vec![0; 32]; + rand::thread_rng().fill_bytes(&mut rand_bytes); + + if self.username != name { + panic!("username changed"); + } + + if auth_methods.contains(AuthMethod::FirstSrp) { + let verifier = srp.compute_verifier( + self.username.to_lowercase().as_bytes(), + self.password.as_bytes(), + &rand_bytes, + ); + + self.tx + .send(&ToSrvPkt::FirstSrp { + salt: rand_bytes, + verifier, + empty_passwd: self.password.is_empty(), + }) + .await + .unwrap(); + + self.auth = AuthState::Done; + } else if auth_methods.contains(AuthMethod::Srp) { + let a = srp.compute_public_ephemeral(&rand_bytes); + + self.tx + .send(&ToSrvPkt::SrpBytesA { a, no_sha1: true }) + .await + .unwrap(); + + self.auth = AuthState::Verify(rand_bytes, srp); + } else { + panic!("unsupported auth methods: {auth_methods:?}"); + } + } + SrpBytesSaltB { salt, b } => { + if let AuthState::Verify(a, srp) = &self.auth { + let m = srp + .process_reply( + a, + self.username.to_lowercase().as_bytes(), + self.password.as_bytes(), + &salt, + &b, + ) + .unwrap() + .proof() + .into(); + + self.tx.send(&ToSrvPkt::SrpBytesM { m }).await.unwrap(); + + self.auth = AuthState::Done; + } + } + NodeDefs(defs) => { + self.events.send_event(GfxEvent::NodeDefs(defs.0)).ok(); + } + Kick(reason) => { + println!("kicked: {reason}"); + } + AcceptAuth { player_pos, .. } => { + self.tx + .send(&ToSrvPkt::Init2 { + lang: "en_US".into(), // localization is unironically overrated + }) + .await + .unwrap(); + + self.pos = player_pos; + self.send_pos_iv = Some(interval(Duration::from_millis(100))); + } + MovePlayer { pos, pitch, yaw } => { + self.pos = pos; + self.pitch = pitch; + self.yaw = yaw; + + self.events + .send_event(GfxEvent::PlayerPos(self.pos, self.pitch, self.yaw)) + .ok(); + } + BlockData { pos, block } => { + self.events.send_event(GfxEvent::MapBlock(pos, block)).ok(); + self.tx + .send(&ToSrvPkt::GotBlocks { + blocks: Vec::from([pos]), + }) + .await + .unwrap(); + } + AnnounceMedia { files, .. } => { + self.tx + .send(&ToSrvPkt::RequestMedia { + filenames: files.into_keys().collect(), // TODO: cache + }) + .await + .ok(); + } + Media { files, n, i } => { + self.events + .send_event(GfxEvent::Media(files, i + 1 == n)) + .ok(); + } + ChatMsg { text, .. } => { + println!("{text}"); + } + _ => {} + } + } +} -- 2.44.0