diff --git a/.gitignore b/.gitignore index ea8c4bf..e7a5685 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ /target +*.db3 +/.vscode +config.toml \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ef9c507..1cb3eac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "ab_glyph" -version = "0.2.29" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -18,98 +18,6 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" -[[package]] -name = "accesskit" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d3b8f9bae46a948369bc4a03e815d4ed6d616bd00de4051133a5019dc31c5a" - -[[package]] -name = "accesskit_atspi_common" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c5dd55e6e94949498698daf4d48fb5659e824d7abec0d394089656ceaf99d4f" -dependencies = [ - "accesskit", - "accesskit_consumer", - "atspi-common", - "serde", - "thiserror 1.0.69", - "zvariant", -] - -[[package]] -name = "accesskit_consumer" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47983a1084940ba9a39c077a8c63e55c619388be5476ac04c804cfbd1e63459" -dependencies = [ - "accesskit", - "hashbrown", - "immutable-chunkmap", -] - -[[package]] -name = "accesskit_macos" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7329821f3bd1101e03a7d2e03bd339e3ac0dc64c70b4c9f9ae1949e3ba8dece1" -dependencies = [ - "accesskit", - "accesskit_consumer", - "hashbrown", - "objc2 0.5.2", - "objc2-app-kit 0.2.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "accesskit_unix" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcee751cc20d88678c33edaf9c07e8b693cd02819fe89053776f5313492273f5" -dependencies = [ - "accesskit", - "accesskit_atspi_common", - "async-channel", - "async-executor", - "async-task", - "atspi", - "futures-lite", - "futures-util", - "serde", - "zbus", -] - -[[package]] -name = "accesskit_windows" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24fcd5d23d70670992b823e735e859374d694a3d12bfd8dd32bd3bd8bedb5d81" -dependencies = [ - "accesskit", - "accesskit_consumer", - "hashbrown", - "paste", - "static_assertions", - "windows 0.58.0", - "windows-core 0.58.0", -] - -[[package]] -name = "accesskit_winit" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6a48dad5530b6deb9fc7a52cc6c3bf72cdd9eb8157ac9d32d69f2427a5e879" -dependencies = [ - "accesskit", - "accesskit_macos", - "accesskit_unix", - "accesskit_windows", - "raw-window-handle", - "winit", -] - [[package]] name = "adler2" version = "2.0.0" @@ -118,15 +26,14 @@ checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.2.15", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -145,7 +52,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.9.0", + "bitflags 2.10.0", "cc", "cesu8", "jni", @@ -154,9 +61,9 @@ dependencies = [ "log", "ndk", "ndk-context", - "ndk-sys 0.6.0+11769913", + "ndk-sys", "num_enum", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -165,262 +72,32 @@ 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 = "arboard" -version = "3.5.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1df21f715862ede32a0c525ce2ca4d52626bb0007f8c18b87a384503ac33e70" +checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" dependencies = [ "clipboard-win", "image", "log", - "objc2 0.6.0", - "objc2-app-kit 0.3.0", + "objc2 0.6.3", + "objc2-app-kit 0.3.2", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", "parking_lot", "percent-encoding", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "x11rb", ] -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "as-raw-xcb-connection" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" - -[[package]] -name = "ash" -version = "0.38.0+1.3.281" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" -dependencies = [ - "libloading", -] - -[[package]] -name = "async-broadcast" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" -dependencies = [ - "event-listener", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-channel" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-fs" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" -dependencies = [ - "async-lock", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-io" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" -dependencies = [ - "async-lock", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix 0.38.44", - "slab", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-process" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" -dependencies = [ - "async-channel", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "rustix 0.38.44", - "tracing", -] - -[[package]] -name = "async-recursion" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "async-signal" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 0.38.44", - "signal-hook-registry", - "slab", - "windows-sys 0.59.0", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "async-trait" -version = "0.1.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atspi" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be534b16650e35237bb1ed189ba2aab86ce65e88cc84c66f4935ba38575cecbf" -dependencies = [ - "atspi-common", - "atspi-connection", - "atspi-proxies", -] - -[[package]] -name = "atspi-common" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1909ed2dc01d0a17505d89311d192518507e8a056a48148e3598fef5e7bb6ba7" -dependencies = [ - "enumflags2", - "serde", - "static_assertions", - "zbus", - "zbus-lockstep", - "zbus-lockstep-macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "atspi-connection" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "430c5960624a4baaa511c9c0fcc2218e3b58f5dbcc47e6190cafee344b873333" -dependencies = [ - "atspi-common", - "atspi-proxies", - "futures-lite", - "zbus", -] - -[[package]] -name = "atspi-proxies" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e6c5de3e524cf967569722446bcd458d5032348554d9a17d7d72b041ab7496" -dependencies = [ - "atspi-common", - "serde", - "zbus", - "zvariant", -] - [[package]] name = "autocfg" version = "1.4.0" @@ -428,19 +105,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] -name = "bit-set" -version = "0.8.0" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" @@ -450,27 +118,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" -dependencies = [ - "serde", -] - -[[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.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "block2" @@ -481,19 +131,6 @@ dependencies = [ "objc2 0.5.2", ] -[[package]] -name = "blocking" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" -dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite", - "piper", -] - [[package]] name = "bumpalo" version = "3.17.0" @@ -502,18 +139,18 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytemuck" -version = "1.22.0" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.9.3" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", @@ -538,12 +175,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "log", "polling", "rustix 0.38.44", "slab", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -598,23 +235,13 @@ dependencies = [ [[package]] name = "clipboard-win" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" dependencies = [ "error-code", ] -[[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 = "combine" version = "4.6.7" @@ -676,7 +303,7 @@ dependencies = [ "bitflags 1.3.2", "core-foundation 0.9.4", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "libc", ] @@ -691,15 +318,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - [[package]] name = "crc32fast" version = "1.4.2" @@ -715,38 +333,28 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - [[package]] name = "cursor-icon" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - [[package]] name = "dispatch" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.10.0", + "objc2 0.6.3", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -790,9 +398,9 @@ checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" [[package]] name = "ecolor" -version = "0.31.1" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc4feb366740ded31a004a0e4452fbf84e80ef432ecf8314c485210229672fd1" +checksum = "71ddb8ac7643d1dba1bb02110e804406dd459a838efcb14011ced10556711a8e" dependencies = [ "bytemuck", "emath", @@ -800,15 +408,14 @@ dependencies = [ [[package]] name = "eframe" -version = "0.31.1" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0dfe0859f3fb1bc6424c57d41e10e9093fe938f426b691e42272c2f336d915c" +checksum = "457481173e6db5ca9fa2be93a58df8f4c7be639587aeb4853b526c6cf87db4e6" dependencies = [ "ahash", "bytemuck", "document-features", "egui", - "egui-wgpu", "egui-winit", "egui_glow", "glow", @@ -829,74 +436,68 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "web-time", - "winapi", - "windows-sys 0.59.0", + "windows-sys 0.61.2", "winit", ] [[package]] name = "egui" -version = "0.31.1" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd34cec49ab55d85ebf70139cb1ccd29c977ef6b6ba4fe85489d6877ee9ef3" +checksum = "6a9b567d356674e9a5121ed3fedfb0a7c31e059fe71f6972b691bcd0bfc284e3" dependencies = [ - "accesskit", "ahash", - "bitflags 2.9.0", + "bitflags 2.10.0", "emath", "epaint", "log", "nohash-hasher", "profiling", + "smallvec", + "unicode-segmentation", ] [[package]] -name = "egui-wgpu" -version = "0.31.1" +name = "egui-winit" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d319dfef570f699b6e9114e235e862a2ddcf75f0d1a061de9e1328d92146d820" +checksum = "ec6687e5bb551702f4ad10ac428bab12acf9d53047ebb1082d4a0ed8c6251a29" dependencies = [ - "ahash", + "arboard", "bytemuck", - "document-features", "egui", - "epaint", "log", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-ui-kit", "profiling", - "thiserror 1.0.69", - "type-map", + "raw-window-handle", + "smithay-clipboard", "web-time", - "wgpu", + "webbrowser", "winit", ] [[package]] -name = "egui-winit" -version = "0.31.1" +name = "egui_extras" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9dfbb78fe4eb9c3a39ad528b90ee5915c252e77bbab9d4ebc576541ab67e13" +checksum = "d01d34e845f01c62e3fded726961092e70417d66570c499b9817ab24674ca4ed" dependencies = [ - "accesskit_winit", "ahash", - "arboard", - "bytemuck", "egui", + "enum-map", "log", + "mime_guess2", "profiling", - "raw-window-handle", - "smithay-clipboard", - "web-time", - "webbrowser", - "winit", ] [[package]] name = "egui_glow" -version = "0.31.1" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "910906e3f042ea6d2378ec12a6fd07698e14ddae68aed2d819ffe944a73aab9e" +checksum = "6420863ea1d90e750f75075231a260030ad8a9f30a7cef82cdc966492dc4c4eb" dependencies = [ - "ahash", "bytemuck", "egui", "glow", @@ -905,39 +506,46 @@ dependencies = [ "profiling", "wasm-bindgen", "web-sys", - "winit", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "emath" -version = "0.31.1" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b" +checksum = "491bdf728bf25ddd9ad60d4cf1c48588fa82c013a2440b91aa7fc43e34a07c32" dependencies = [ "bytemuck", ] [[package]] -name = "endi" -version = "1.1.0" +name = "encoding_rs" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] [[package]] -name = "enumflags2" -version = "0.7.11" +name = "enum-map" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" dependencies = [ - "enumflags2_derive", - "serde", + "enum-map-derive", ] [[package]] -name = "enumflags2_derive" -version = "0.7.11" +name = "enum-map-derive" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", @@ -959,9 +567,9 @@ dependencies = [ [[package]] name = "epaint" -version = "0.31.1" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fcc0f5a7c613afd2dee5e4b30c3e6acafb8ad6f0edb06068811f708a67c562" +checksum = "009d0dd3c2163823a0abdb899451ecbc78798dec545ee91b43aff1fa790bab62" dependencies = [ "ab_glyph", "ahash", @@ -977,9 +585,9 @@ dependencies = [ [[package]] name = "epaint_default_fonts" -version = "0.31.1" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7e7a64c02cf7a5b51e745a9e45f60660a286f151c238b9d397b3e923f5082f" +checksum = "5c4fbe202b6578d3d56428fa185cdf114a05e49da05f477b3c7f0fbb221f1862" [[package]] name = "equivalent" @@ -1004,25 +612,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" [[package]] -name = "event-listener" -version = "5.4.0" +name = "fallible-iterator" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] -name = "event-listener-strategy" -version = "0.5.4" +name = "fallible-streaming-iterator" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener", - "pin-project-lite", -] +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fastrand" @@ -1049,12 +648,27 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "foldhash" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -1062,7 +676,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared", + "foreign-types-shared 0.3.1", ] [[package]] @@ -1076,6 +690,12 @@ dependencies = [ "syn", ] +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -1092,40 +712,26 @@ dependencies = [ ] [[package]] -name = "futures-core" +name = "futures-channel" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] [[package]] -name = "futures-io" +name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-lite" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] -name = "futures-macro" +name = "futures-io" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-sink" @@ -1147,7 +753,6 @@ checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-io", - "futures-macro", "futures-sink", "futures-task", "memchr", @@ -1156,16 +761,6 @@ dependencies = [ "slab", ] -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "gethostname" version = "0.4.3" @@ -1178,13 +773,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] @@ -1224,27 +819,24 @@ dependencies = [ [[package]] name = "glutin" -version = "0.32.2" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03642b8b0cce622392deb0ee3e88511f75df2daac806102597905c3ea1974848" +checksum = "12124de845cacfebedff80e877bb37b5b75c34c5a4c89e47e1cdd67fb6041325" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "cfg_aliases", "cgl", - "core-foundation 0.9.4", - "dispatch", + "dispatch2", "glutin_egl_sys", - "glutin_glx_sys", "glutin_wgl_sys", "libloading", - "objc2 0.5.2", - "objc2-app-kit 0.2.2", - "objc2-foundation 0.2.2", + "objc2 0.6.3", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", "once_cell", "raw-window-handle", - "wayland-sys", "windows-sys 0.52.0", - "x11-dl", ] [[package]] @@ -1270,116 +862,193 @@ dependencies = [ ] [[package]] -name = "glutin_glx_sys" +name = "glutin_wgl_sys" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7bb2938045a88b612499fbcba375a77198e01306f52272e692f8c1f3751185" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" dependencies = [ "gl_generator", - "x11-dl", ] [[package]] -name = "glutin_wgl_sys" -version = "0.6.1" +name = "h2" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ - "gl_generator", + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] -name = "gpu-alloc" -version = "0.6.0" +name = "hashbrown" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "bitflags 2.9.0", - "gpu-alloc-types", + "foldhash", ] [[package]] -name = "gpu-alloc-types" -version = "0.3.0" +name = "hashbrown" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" -dependencies = [ - "bitflags 2.9.0", -] +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] -name = "gpu-descriptor" -version = "0.3.1" +name = "hashlink" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "bitflags 2.9.0", - "gpu-descriptor-types", - "hashbrown", + "hashbrown 0.15.5", ] [[package]] -name = "gpu-descriptor-types" -version = "0.2.0" +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hermit-abi" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ - "bitflags 2.9.0", + "bytes", + "itoa", ] [[package]] -name = "hashbrown" -version = "0.15.2" +name = "http-body" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "foldhash", + "bytes", + "http", ] [[package]] -name = "heck" -version = "0.5.0" +name = "http-body-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] [[package]] -name = "hermit-abi" -version = "0.4.0" +name = "httparse" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "hermit-abi" -version = "0.5.0" +name = "humantime" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" [[package]] -name = "hex" -version = "0.4.3" +name = "hyper" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] [[package]] -name = "hexf-parse" -version = "0.2.1" +name = "hyper-rustls" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] [[package]] -name = "home" -version = "0.5.11" +name = "hyper-tls" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ - "windows-sys 0.59.0", + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", ] [[package]] -name = "humantime" -version = "2.2.0" +name = "hyper-util" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" +checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] [[package]] name = "icu_collections" @@ -1534,22 +1203,29 @@ dependencies = [ ] [[package]] -name = "immutable-chunkmap" -version = "2.0.6" +name = "indexmap" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f97096f508d54f8f8ab8957862eee2ccd628847b6217af1a335e1c44dee578" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ - "arrayvec", + "equivalent", + "hashbrown 0.16.0", ] [[package]] -name = "indexmap" -version = "2.8.0" +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ - "equivalent", - "hashbrown", + "memchr", + "serde", ] [[package]] @@ -1563,6 +1239,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -1580,7 +1265,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror 1.0.69", + "thiserror", "walkdir", "windows-sys 0.45.0", ] @@ -1617,17 +1302,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "khronos-egl" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" -dependencies = [ - "libc", - "libloading", - "pkg-config", -] - [[package]] name = "khronos_api" version = "3.1.0" @@ -1636,9 +1310,9 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libloading" @@ -1656,11 +1330,22 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "libc", "redox_syscall 0.5.10", ] +[[package]] +name = "libsqlite3-sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -1669,9 +1354,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" @@ -1687,28 +1372,18 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" @@ -1735,18 +1410,21 @@ dependencies = [ ] [[package]] -name = "metal" -version = "0.31.0" +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" +checksum = "1706dc14a2e140dec0a7a07109d9a3d5890b81e85bd6c60b906b249a77adf0ca" dependencies = [ - "bitflags 2.9.0", - "block", - "core-graphics-types", - "foreign-types", - "log", - "objc", - "paste", + "mime", + "phf", + "phf_shared", + "unicase", ] [[package]] @@ -1760,25 +1438,31 @@ dependencies = [ ] [[package]] -name = "naga" -version = "24.0.0" +name = "mio" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ - "arrayvec", - "bit-set", - "bitflags 2.9.0", - "cfg_aliases", - "codespan-reporting", - "hexf-parse", - "indexmap", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", "log", - "rustc-hash", - "spirv", - "strum", - "termcolor", - "thiserror 2.0.12", - "unicode-xid", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", ] [[package]] @@ -1787,13 +1471,13 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "jni-sys", "log", - "ndk-sys 0.6.0+11769913", + "ndk-sys", "num_enum", "raw-window-handle", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -1802,15 +1486,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" -[[package]] -name = "ndk-sys" -version = "0.5.0+25.2.9519653" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" -dependencies = [ - "jni-sys", -] - [[package]] name = "ndk-sys" version = "0.6.0+11769913" @@ -1820,19 +1495,6 @@ dependencies = [ "jni-sys", ] -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags 2.9.0", - "cfg-if", - "cfg_aliases", - "libc", - "memoffset", -] - [[package]] name = "nohash-hasher" version = "0.2.0" @@ -1869,15 +1531,6 @@ dependencies = [ "syn", ] -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - [[package]] name = "objc-sys" version = "0.3.5" @@ -1896,9 +1549,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" dependencies = [ "objc2-encode", ] @@ -1909,7 +1562,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "block2", "libc", "objc2 0.5.2", @@ -1921,14 +1574,15 @@ dependencies = [ [[package]] name = "objc2-app-kit" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", + "bitflags 2.10.0", + "objc2 0.6.3", + "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", ] [[package]] @@ -1937,7 +1591,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "block2", "objc2 0.5.2", "objc2-core-location", @@ -1961,7 +1615,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -1969,22 +1623,24 @@ dependencies = [ [[package]] name = "objc2-core-foundation" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", + "bitflags 2.10.0", + "dispatch2", + "objc2 0.6.3", ] [[package]] name = "objc2-core-graphics" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", + "bitflags 2.10.0", + "dispatch2", + "objc2 0.6.3", "objc2-core-foundation", "objc2-io-surface", ] @@ -2025,7 +1681,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "block2", "dispatch", "libc", @@ -2034,23 +1690,23 @@ dependencies = [ [[package]] name = "objc2-foundation" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", + "bitflags 2.10.0", + "objc2 0.6.3", "objc2-core-foundation", ] [[package]] name = "objc2-io-surface" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", + "bitflags 2.10.0", + "objc2 0.6.3", "objc2-core-foundation", ] @@ -2072,7 +1728,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2084,7 +1740,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2107,7 +1763,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "block2", "objc2 0.5.2", "objc2-cloud-kit", @@ -2139,7 +1795,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "block2", "objc2 0.5.2", "objc2-core-location", @@ -2153,31 +1809,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] -name = "orbclient" -version = "0.3.48" +name = "openssl" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "libredox", + "bitflags 2.10.0", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", ] [[package]] -name = "ordered-float" -version = "4.6.0" +name = "openssl-macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "num-traits", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "ordered-stream" -version = "0.2.0" +name = "openssl-probe" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ - "futures-core", - "pin-project-lite", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "orbclient" +version = "0.3.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" +dependencies = [ + "libredox", ] [[package]] @@ -2189,17 +1870,11 @@ dependencies = [ "ttf-parser", ] -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -2207,36 +1882,74 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall 0.5.10", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "payload" version = "0.1.0" dependencies = [ "common", - "windows 0.60.0", + "windows", ] [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", + "unicase", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", + "unicase", +] [[package]] name = "pin-project" @@ -2270,17 +1983,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - [[package]] name = "pkg-config" version = "0.3.32" @@ -2315,15 +2017,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy 0.8.24", -] - [[package]] name = "pretty_env_logger" version = "0.5.0" @@ -2354,19 +2047,9 @@ dependencies = [ [[package]] name = "profiling" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" - -[[package]] -name = "quick-xml" -version = "0.30.0" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" -dependencies = [ - "memchr", - "serde", -] +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" [[package]] name = "quick-xml" @@ -2398,18 +2081,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[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", ] @@ -2418,9 +2089,6 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.15", -] [[package]] name = "raw-window-handle" @@ -2443,7 +2111,7 @@ version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", ] [[package]] @@ -2476,16 +2144,74 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] -name = "renderdoc-sys" -version = "1.1.0" +name = "reqwest" +version = "0.12.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] [[package]] -name = "rustc-hash" -version = "1.1.0" +name = "ring" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rusqlite" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" +dependencies = [ + "bitflags 2.10.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] [[package]] name = "rustix" @@ -2493,7 +2219,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -2502,15 +2228,48 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "errno", "libc", - "linux-raw-sys 0.9.3", - "windows-sys 0.59.0", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] @@ -2534,6 +2293,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -2547,32 +2315,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "sctk-adwaita" -version = "0.10.1" +name = "security-framework" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "ab_glyph", - "log", - "memmap2", - "smithay-client-toolkit", - "tiny-skia", + "bitflags 2.10.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", ] +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -2592,25 +2386,24 @@ dependencies = [ ] [[package]] -name = "serde_repr" -version = "0.1.20" +name = "serde_spanned" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ - "proc-macro2", - "quote", - "syn", + "serde_core", ] [[package]] -name = "sha1" -version = "0.10.6" +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ - "cfg-if", - "cpufeatures", - "digest", + "form_urlencoded", + "itoa", + "ryu", + "serde", ] [[package]] @@ -2619,21 +2412,18 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - [[package]] name = "simd-adler32" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -2654,9 +2444,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smithay-client-toolkit" @@ -2664,7 +2454,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "calloop", "calloop-wayland-source", "cursor-icon", @@ -2672,7 +2462,7 @@ dependencies = [ "log", "memmap2", "rustix 0.38.44", - "thiserror 1.0.69", + "thiserror", "wayland-backend", "wayland-client", "wayland-csd-frame", @@ -2704,12 +2494,13 @@ dependencies = [ ] [[package]] -name = "spirv" -version = "0.3.0+sdk-1.3.268.0" +name = "socket2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ - "bitflags 2.9.0", + "libc", + "windows-sys 0.60.2", ] [[package]] @@ -2725,42 +2516,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -name = "strict-num" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" - -[[package]] -name = "strum" -version = "0.26.3" +name = "subtle" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros", -] +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] -name = "strum_macros" -version = "0.26.4" +name = "syn" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ - "heck", "proc-macro2", "quote", - "rustversion", - "syn", + "unicode-ident", ] [[package]] -name = "syn" -version = "2.0.100" +name = "sync_wrapper" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "futures-core", ] [[package]] @@ -2774,17 +2552,38 @@ dependencies = [ "syn", ] +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.10.0", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" -version = "3.19.1" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", "getrandom 0.3.2", "once_cell", - "rustix 1.0.5", - "windows-sys 0.59.0", + "rustix 1.1.2", + "windows-sys 0.61.2", ] [[package]] @@ -2802,16 +2601,7 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl", ] [[package]] @@ -2825,17 +2615,6 @@ dependencies = [ "syn", ] -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tiff" version = "0.9.1" @@ -2848,38 +2627,75 @@ dependencies = [ ] [[package]] -name = "tiny-skia" -version = "0.11.4" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "arrayref", - "arrayvec", - "bytemuck", - "cfg-if", - "log", - "tiny-skia-path", + "displaydoc", + "zerovec", ] [[package]] -name = "tiny-skia-path" -version = "0.11.4" +name = "tokio" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "arrayref", - "bytemuck", - "strict-num", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", ] [[package]] -name = "tinystr" -version = "0.7.6" +name = "tokio-native-tls" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ - "displaydoc", - "zerovec", + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime 0.7.3", + "toml_parser", + "toml_writer", + "winnow", ] [[package]] @@ -2888,6 +2704,15 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.22.24" @@ -2895,73 +2720,107 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap", - "toml_datetime", + "toml_datetime 0.6.8", "winnow", ] [[package]] -name = "tracing" -version = "0.1.41" +name = "toml_parser" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", + "winnow", ] [[package]] -name = "tracing-attributes" -version = "0.1.28" +name = "toml_writer" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ - "proc-macro2", - "quote", - "syn", + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", ] [[package]] -name = "tracing-core" -version = "0.1.33" +name = "tower-http" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" dependencies = [ - "once_cell", + "bitflags 2.10.0", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", ] [[package]] -name = "ttf-parser" -version = "0.25.1" +name = "tower-layer" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] -name = "type-map" -version = "0.5.0" +name = "tower-service" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" -dependencies = [ - "rustc-hash", -] +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] -name = "typenum" -version = "1.18.0" +name = "tracing" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] [[package]] -name = "uds_windows" -version = "1.1.0" +name = "tracing-core" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ - "memoffset", - "tempfile", - "winapi", + "once_cell", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -2975,16 +2834,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "unicode-xid" -version = "0.2.6" +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" @@ -3009,6 +2862,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -3025,11 +2884,20 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -3113,13 +2981,13 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" +checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35" dependencies = [ "cc", "downcast-rs", - "rustix 0.38.44", + "rustix 1.1.2", "scoped-tls", "smallvec", "wayland-sys", @@ -3127,12 +2995,12 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.8" +version = "0.31.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" +checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" dependencies = [ - "bitflags 2.9.0", - "rustix 0.38.44", + "bitflags 2.10.0", + "rustix 1.1.2", "wayland-backend", "wayland-scanner", ] @@ -3143,7 +3011,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "cursor-icon", "wayland-backend", ] @@ -3161,26 +3029,13 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc" -dependencies = [ - "bitflags 2.9.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols-plasma" -version = "0.3.6" +version = "0.32.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccaacc76703fefd6763022ac565b590fcade92202492381c95b2edfdf7d46b3" +checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "wayland-backend", "wayland-client", - "wayland-protocols", "wayland-scanner", ] @@ -3190,7 +3045,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248a02e6f595aad796561fa82d25601bd2c8c3b145b1c7453fc8f94c1a58f8b2" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -3199,20 +3054,20 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.6" +version = "0.31.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" +checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3" dependencies = [ "proc-macro2", - "quick-xml 0.37.4", + "quick-xml", "quote", ] [[package]] name = "wayland-sys" -version = "0.31.6" +version = "0.31.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" +checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142" dependencies = [ "dlib", "log", @@ -3224,163 +3079,43 @@ dependencies = [ name = "web-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webbrowser" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5df295f8451142f1856b1bd86a606dfe9587d439bc036e319c827700dbd555e" -dependencies = [ - "core-foundation 0.10.0", - "home", - "jni", - "log", - "ndk-context", - "objc2 0.6.0", - "objc2-foundation 0.3.0", - "url", - "web-sys", -] - -[[package]] -name = "weezl" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" - -[[package]] -name = "wgpu" -version = "24.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35904fb00ba2d2e0a4d002fcbbb6e1b89b574d272a50e5fc95f6e81cf281c245" -dependencies = [ - "arrayvec", - "bitflags 2.9.0", - "cfg_aliases", - "document-features", - "js-sys", - "log", - "parking_lot", - "profiling", - "raw-window-handle", - "smallvec", - "static_assertions", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "wgpu-core", - "wgpu-hal", - "wgpu-types", -] - -[[package]] -name = "wgpu-core" -version = "24.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c25545d479b47d3f0a8e373aceb2060b67c6eb841b24ac8c32348151c7a0c" -dependencies = [ - "arrayvec", - "bit-vec", - "bitflags 2.9.0", - "cfg_aliases", - "document-features", - "indexmap", - "log", - "naga", - "once_cell", - "parking_lot", - "profiling", - "raw-window-handle", - "rustc-hash", - "smallvec", - "thiserror 2.0.12", - "wgpu-hal", - "wgpu-types", -] - -[[package]] -name = "wgpu-hal" -version = "24.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259" -dependencies = [ - "android_system_properties", - "arrayvec", - "ash", - "bitflags 2.9.0", - "bytemuck", - "cfg_aliases", - "core-graphics-types", - "glow", - "glutin_wgl_sys", - "gpu-alloc", - "gpu-descriptor", - "js-sys", - "khronos-egl", - "libc", - "libloading", - "log", - "metal", - "naga", - "ndk-sys 0.5.0+25.2.9519653", - "objc", - "once_cell", - "ordered-float", - "parking_lot", - "profiling", - "raw-window-handle", - "renderdoc-sys", - "rustc-hash", - "smallvec", - "thiserror 2.0.12", +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", "wasm-bindgen", - "web-sys", - "wgpu-types", - "windows 0.58.0", ] [[package]] -name = "wgpu-types" -version = "24.0.0" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ - "bitflags 2.9.0", "js-sys", - "log", - "web-sys", + "wasm-bindgen", ] [[package]] -name = "winapi" -version = "0.3.9" +name = "webbrowser" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "00f1243ef785213e3a32fa0396093424a3a6ea566f9948497e5a2309261a4c97" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "core-foundation 0.10.0", + "jni", + "log", + "ndk-context", + "objc2 0.6.3", + "objc2-foundation 0.3.2", + "url", + "web-sys", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "weezl" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" [[package]] name = "winapi-util" @@ -3391,22 +3126,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[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.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.60.0" @@ -3414,9 +3133,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529" dependencies = [ "windows-collections", - "windows-core 0.60.1", + "windows-core", "windows-future", - "windows-link", + "windows-link 0.1.1", "windows-numerics", ] @@ -3426,20 +3145,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5467f79cc1ba3f52ebb2ed41dbb459b8e7db636cc3429458d9a852e15bc24dec" dependencies = [ - "windows-core 0.60.1", -] - -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", + "windows-core", ] [[package]] @@ -3448,9 +3154,9 @@ version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247" dependencies = [ - "windows-implement 0.59.0", - "windows-interface 0.59.1", - "windows-link", + "windows-implement", + "windows-interface", + "windows-link 0.1.1", "windows-result 0.3.2", "windows-strings 0.3.1", ] @@ -3461,19 +3167,8 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a787db4595e7eb80239b74ce8babfb1363d8e343ab072f2ffe901400c03349f0" dependencies = [ - "windows-core 0.60.1", - "windows-link", -] - -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "windows-core", + "windows-link 0.1.1", ] [[package]] @@ -3487,17 +3182,6 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-interface" version = "0.59.1" @@ -3515,23 +3199,31 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-numerics" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "005dea54e2f6499f2cee279b8f703b3cf3b5734a2d8d21867c8f44003182eeed" dependencies = [ - "windows-core 0.60.1", - "windows-link", + "windows-core", + "windows-link 0.1.1", ] [[package]] -name = "windows-result" -version = "0.2.0" +name = "windows-registry" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-targets 0.52.6", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", ] [[package]] @@ -3540,17 +3232,16 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" dependencies = [ - "windows-link", + "windows-link 0.1.1", ] [[package]] -name = "windows-strings" -version = "0.1.0" +name = "windows-result" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -3559,7 +3250,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" dependencies = [ - "windows-link", + "windows-link 0.1.1", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", ] [[package]] @@ -3589,6 +3289,24 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -3628,13 +3346,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -3653,6 +3388,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -3671,6 +3412,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -3689,12 +3436,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -3713,6 +3472,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -3731,6 +3496,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -3749,6 +3520,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -3767,18 +3544,22 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winit" -version = "0.30.9" +version = "0.30.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a809eacf18c8eca8b6635091543f02a5a06ddf3dad846398795460e6e0ae3cc0" +checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732" dependencies = [ - "ahash", "android-activity", "atomic-waker", - "bitflags 2.9.0", + "bitflags 2.10.0", "block2", - "bytemuck", "calloop", "cfg_aliases", "concurrent-queue", @@ -3788,53 +3569,53 @@ dependencies = [ "dpi", "js-sys", "libc", - "memmap2", "ndk", "objc2 0.5.2", "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", "objc2-ui-kit", "orbclient", - "percent-encoding", "pin-project", "raw-window-handle", "redox_syscall 0.4.1", "rustix 0.38.44", - "sctk-adwaita", - "smithay-client-toolkit", "smol_str", "tracing", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-protocols-plasma", "web-sys", "web-time", "windows-sys 0.52.0", - "x11-dl", - "x11rb", "xkbcommon-dl", ] [[package]] name = "winnow" -version = "0.7.4" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] +[[package]] +name = "winresource" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1ef04dd590e94ff7431a8eda99d5ca659e688d60e930bd0a330062acea4608f" +dependencies = [ + "toml", + "version_check", +] + [[package]] name = "wit-bindgen-rt" version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", ] [[package]] @@ -3849,28 +3630,13 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" -[[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 = "x11rb" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ - "as-raw-xcb-connection", "gethostname", - "libc", - "libloading", - "once_cell", "rustix 0.38.44", "x11rb-protocol", ] @@ -3887,23 +3653,13 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" -[[package]] -name = "xdg-home" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "xkbcommon-dl" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.10.0", "dlib", "log", "once_cell", @@ -3918,9 +3674,9 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.25" +version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" [[package]] name = "yoke" @@ -3946,139 +3702,20 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zbus" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" -dependencies = [ - "async-broadcast", - "async-executor", - "async-fs", - "async-io", - "async-lock", - "async-process", - "async-recursion", - "async-task", - "async-trait", - "blocking", - "enumflags2", - "event-listener", - "futures-core", - "futures-sink", - "futures-util", - "hex", - "nix", - "ordered-stream", - "rand", - "serde", - "serde_repr", - "sha1", - "static_assertions", - "tracing", - "uds_windows", - "windows-sys 0.52.0", - "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus-lockstep" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca2c5dceb099bddaade154055c926bb8ae507a18756ba1d8963fd7b51d8ed1d" -dependencies = [ - "zbus_xml", - "zvariant", -] - -[[package]] -name = "zbus-lockstep-macros" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709ab20fc57cb22af85be7b360239563209258430bccf38d8b979c5a2ae3ecce" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "zbus-lockstep", - "zbus_xml", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", - "zvariant_utils", -] - -[[package]] -name = "zbus_names" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" -dependencies = [ - "serde", - "static_assertions", - "zvariant", -] - -[[package]] -name = "zbus_xml" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3f374552b954f6abb4bd6ce979e6c9b38fb9d0cd7cc68a7d796e70c9f3a233" -dependencies = [ - "quick-xml 0.30.0", - "serde", - "static_assertions", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive 0.7.35", -] - [[package]] name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive 0.8.24", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ - "proc-macro2", - "quote", - "syn", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", @@ -4106,18 +3743,32 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + [[package]] name = "zerosplitter" -version = "0.1.4" +version = "0.4.1" dependencies = [ "bytemuck", "common", "eframe", + "egui", + "egui_extras", + "itertools", "log", "pretty_env_logger", + "reqwest", + "rusqlite", + "semver", "serde", "serde_json", - "windows 0.60.0", + "toml", + "windows", + "winresource", ] [[package]] @@ -4141,40 +3792,3 @@ dependencies = [ "quote", "syn", ] - -[[package]] -name = "zvariant" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" -dependencies = [ - "endi", - "enumflags2", - "serde", - "static_assertions", - "zvariant_derive", -] - -[[package]] -name = "zvariant_derive" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", - "zvariant_utils", -] - -[[package]] -name = "zvariant_utils" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/README.md b/README.md index 0eee087..625c765 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,52 @@ # ZeroSplitter -Automatic split-tracker for ZeroRanger. Very alpha. Does not yet support White Vanilla. +Automatic split-tracker for ZeroRanger. Very beta. +Supports Green Orange and White Vanilla. + +[DOWNLOAD](https://github.com/lily-and-doll/ZeroSplitter/releases) + +Image of the Zerosplitter main interface with all columns turned on + + + +# How to use +Extract the zip and run `zerosplitter.exe`. The program will detect Zeroranger and start reading data automatically. +You can start playing and your scores will automatically show up in ZeroSplitter. If you restart your run and your score +doesn't show up as the correct split, just go back to the main menu and launch from there. + +Continues should be tracked properly in Green Orange but not White Vanilla. + +Co-op should work, but has not been tested. If you find co-op to work, let me know. + +# Your Data +Your data is stored in the `sqlite.db3` next to the .exe. You can manually insert, delete, or modify any data in the database if you like. +When updating the program, just put the new `zerosplitter.exe` and `payload.dll` in the same folder as your old `sqlite.db3` and `config.toml` files. +The database file will automatically be updated and will not be able to be used with older versions of the program. + +If you want to move the program to another folder, just copy all the files in the folder. + +# Categories +A "category" is a set of splits and personal bests to run against. ZeroSplitter will try to detect which mode +you are playing and not overwrite scores from one mode with another - but don't push your luck: have the right +category selected before you take off. + +Press the plus button to add a new category. + +Currently the only way to delete categories is by manually dropping them from the database, but you can rename them. + +# Options +The gear button in the top right opens up the options menu. + +## Columns +Use the check boxes to turn columns of data on and off on the main screen. You can pick between a variety of different displays for your score, as well as some +additional statistics like rank. You can have as many or as few columns enabled at once as you like. Hover over some of the column selectors for more details +on what they mean. + +The config file lets you set the default columns that will be selected when you launch the program. + +## Import +You can import previously recorded runs by putting a category name and a list of scores into the two boxes. +Seperate each score with a comma and space like shown in the hint. + +# How to build from source +Just run `cargo run --release` in the top level of the repository, next to this `README.md`. `build.sh` will zip `zerosplitter.exe` +and `payload.dll` for you, but you don't need to do this. diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..8303d50 --- /dev/null +++ b/TODO.txt @@ -0,0 +1,14 @@ +Add deleting categories +Rework the pop up menus +Add log file and remove terminal window +Make it more clear that importing uses relative scores or make it accept either +Fix the reset stage/full reset split detection + +Extract functionality from UI + Pull UI state (comparisons, toggles) into single top-level child struct + Ui modifies state via self access/reads from state + no DB calls in UI - all data accessed via get-or-insert cache in UI state struct + +RunData {SplitData} struct + Get all run/split data through a central channel that gets all data + Pare down data as needed later \ No newline at end of file diff --git a/common/Cargo.toml b/common/Cargo.toml index ebb7a7f..eabea06 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -5,4 +5,4 @@ edition = "2024" [dependencies.bytemuck] version = "1" -features = ["derive"] \ No newline at end of file +features = ["derive", "min_const_generics"] \ No newline at end of file diff --git a/common/src/lib.rs b/common/src/lib.rs index d461236..a3a377d 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -3,7 +3,7 @@ use std::io::{self, Read}; use bytemuck::{Pod, Zeroable}; #[derive(Debug, Default, Clone, Copy, Zeroable, Pod)] -#[repr(C)] +#[repr(C, packed(2))] pub struct FrameData { pub score_p1: i32, pub score_p2: i32, @@ -11,6 +11,16 @@ pub struct FrameData { pub game_loop: u8, pub checkpoint: u8, pub difficulty: i8, + pub realm: u8, + pub checkpoint_sub: u8, + pub timer_wave: u32, + pub multiplier_one: u32, + pub dynamic_rank: f32, + pub pattern_rank: f32, + pub stage_current: u8, + pub timer_wave_frames: u8, + pub timer_wave_hotframes: u32, + pub timer_wave_bonus: u32, } impl FrameData { diff --git a/payload/src/lib.rs b/payload/src/lib.rs index e6a80b0..a2d9e9c 100644 --- a/payload/src/lib.rs +++ b/payload/src/lib.rs @@ -100,6 +100,16 @@ fn get_frame_data() -> FrameData { let stage_p1 = read_var(c"stage_one").unwrap().value as u8; let stage_p2 = read_var(c"stage_two").unwrap().value as u8; let stage = stage_p1.max(stage_p2); + let realm = read_var(c"realm").unwrap().value as u8; + let checkpoint_sub = read_var(c"checkpoint_sub").unwrap().value as u8; + let timer_wave = read_var(c"timer_wave").unwrap().value as u32; + let multiplier_one = read_var(c"multiplier_one").unwrap().value as u32; + let pattern_rank = read_var(c"pattern_rank").unwrap().value as f32; + let dynamic_rank = read_var(c"dynamic_rank").unwrap().value as f32; + let stage_current = read_var(c"stage_current").unwrap().value as u8; + let timer_wave_frames = read_var(c"timer_wave_frames").unwrap().value as u8; + let timer_wave_hotframes = read_var(c"timer_wave_hotframes").unwrap().value as u32; + let timer_wave_bonus = read_var(c"timer_wave_bonus").unwrap().value as u32; FrameData { score_p1: score_p1 as i32, score_p2: score_p2 as i32, @@ -107,6 +117,16 @@ fn get_frame_data() -> FrameData { game_loop, checkpoint, difficulty, + realm, + checkpoint_sub, + timer_wave, + multiplier_one, + pattern_rank, + dynamic_rank, + stage_current, + timer_wave_frames, + timer_wave_hotframes, + timer_wave_bonus, } } diff --git a/splitter/Cargo.toml b/splitter/Cargo.toml index a106acd..dd3c0b3 100644 --- a/splitter/Cargo.toml +++ b/splitter/Cargo.toml @@ -1,16 +1,27 @@ [package] name = "zerosplitter" -version = "0.1.4" +version = "0.4.1" edition = "2024" [dependencies] bytemuck = "1" common = {path = "../common"} -eframe = "0.31" pretty_env_logger = "0.5" log = "0.4" serde = {version = "1.0", features = ["derive"]} serde_json = "1.0" +rusqlite = { version = "0.37.0", features = ["bundled"] } +toml = "0.9.8" +reqwest = { version = "0.12.24", features = ["blocking", "json"] } +semver = "1.0.27" +egui_extras = "0.33.3" +egui = "0.33.3" +itertools = "0.14.0" + +[dependencies.eframe] +version = "0.33.3" +default-features = false +features = ["default_fonts", "glow"] [dependencies.windows] version = "0.60" @@ -22,3 +33,6 @@ features = [ "Win32_System_Memory", "Win32_Security" ] + +[build-dependencies] +winresource = "0.1.27" diff --git a/splitter/assets/config_sections/check_for_updates.toml b/splitter/assets/config_sections/check_for_updates.toml new file mode 100644 index 0000000..f29d5b0 --- /dev/null +++ b/splitter/assets/config_sections/check_for_updates.toml @@ -0,0 +1,4 @@ +# Checks for updates on launch. If an update is avaliable, a link will +# be in the Options menu. +check_for_updates = true + diff --git a/splitter/assets/config_sections/decoration_button.toml b/splitter/assets/config_sections/decoration_button.toml new file mode 100644 index 0000000..5ffc263 --- /dev/null +++ b/splitter/assets/config_sections/decoration_button.toml @@ -0,0 +1,9 @@ +# Adds a toggle in the top bar that turns off window decorations, e.g. +# the title bar and side bars. When the decorations are hidden, you +# can move the window by dragging it anywhere but cannot resize it +# manually. +# Known issue: right clicking the window when decorations are hidden +# makes dragging no longer work. Turn them back on and drag the +# title bar to fix it. +decoration_button = false + diff --git a/splitter/assets/config_sections/default_columns.toml b/splitter/assets/config_sections/default_columns.toml new file mode 100644 index 0000000..6d9d545 --- /dev/null +++ b/splitter/assets/config_sections/default_columns.toml @@ -0,0 +1,3 @@ +# Selects which columns are on by default. The columns are numbered from 0 up in the order they +# are shown in the options menu e.g. names = 0, best = 1, diff = 5, score = 9. +default_columns = [0, 1, 5, 9] \ No newline at end of file diff --git a/splitter/assets/config_sections/heading.toml b/splitter/assets/config_sections/heading.toml new file mode 100644 index 0000000..fe2be02 --- /dev/null +++ b/splitter/assets/config_sections/heading.toml @@ -0,0 +1,4 @@ +# Configuration for ZeroSplitter. Edit this file to change the settings +# (If you're unfamiliar with the format, this is a TOML file) +# https://en.wikipedia.org/wiki/TOML + diff --git a/splitter/assets/config_sections/min_col.toml b/splitter/assets/config_sections/min_col.toml new file mode 100644 index 0000000..f6b88f8 --- /dev/null +++ b/splitter/assets/config_sections/min_col.toml @@ -0,0 +1,5 @@ +# Minimum width of each column in the main UI +# Columns will expand automatically as they are filled with data, but you can give them extra breathing room if you want +# A very small number may cause columns to frequently get wider as your run progresses +minimum_column_width = 50.0 + diff --git a/splitter/assets/config_sections/zoom_level.toml b/splitter/assets/config_sections/zoom_level.toml new file mode 100644 index 0000000..93c6137 --- /dev/null +++ b/splitter/assets/config_sections/zoom_level.toml @@ -0,0 +1,4 @@ +# Scale factor for the entire UI. 2.0 = twice as large as normal. +# The program is 300x300 in GO mode and 300x650 at 1.0 zoom, for reference +zoom_level = 1.0 + diff --git a/splitter/assets/icon.ico b/splitter/assets/icon.ico new file mode 100644 index 0000000..04e9ae7 Binary files /dev/null and b/splitter/assets/icon.ico differ diff --git a/splitter/build.rs b/splitter/build.rs new file mode 100644 index 0000000..b6f0c0c --- /dev/null +++ b/splitter/build.rs @@ -0,0 +1,13 @@ +use std::{env, io}; + +use winresource::WindowsResource; + +fn main() -> io::Result<()> { + if env::var_os("CARGO_CFG_WINDOWS").is_some() { + WindowsResource::new() + // This path can be absolute, or relative to your crate root. + .set_icon("assets/icon.ico") + .compile()?; + } + Ok(()) +} diff --git a/splitter/sql/best_splits.sql b/splitter/sql/best_splits.sql new file mode 100644 index 0000000..d0c879b --- /dev/null +++ b/splitter/sql/best_splits.sql @@ -0,0 +1,7 @@ +SELECT max(score) +FROM (SELECT split_num, score, mode +FROM splits +INNER JOIN runs +INNER JOIN categories +ON splits.run_id = runs.id AND runs.category = categories.id +WHERE categories.id = ?1) GROUP BY split_num \ No newline at end of file diff --git a/splitter/sql/import_run.sql b/splitter/sql/import_run.sql new file mode 100644 index 0000000..7a3620a --- /dev/null +++ b/splitter/sql/import_run.sql @@ -0,0 +1 @@ +INSERT INTO runs (category, imported) VALUES (?1, true) \ No newline at end of file diff --git a/splitter/sql/import_split.sql b/splitter/sql/import_split.sql new file mode 100644 index 0000000..3107628 --- /dev/null +++ b/splitter/sql/import_split.sql @@ -0,0 +1 @@ +INSERT INTO splits (split_num, score, run_id) VALUES (?1, ?2, ?3) \ No newline at end of file diff --git a/splitter/sql/paces_at_split_n.sql b/splitter/sql/paces_at_split_n.sql new file mode 100644 index 0000000..54416ca --- /dev/null +++ b/splitter/sql/paces_at_split_n.sql @@ -0,0 +1,7 @@ +SELECT +sum(CASE WHEN split_num <= ?2 THEN score ELSE 0 END) AS pace, +sum(score) as total +FROM splits JOIN runs ON splits.run_id = runs.id +WHERE category = ?1 +GROUP BY run_id +ORDER BY pace DESC \ No newline at end of file diff --git a/splitter/sql/pass_rate.sql b/splitter/sql/pass_rate.sql new file mode 100644 index 0000000..8fbb23d --- /dev/null +++ b/splitter/sql/pass_rate.sql @@ -0,0 +1,8 @@ +SELECT +split_num, +count(case when final = false then 1 end) as pass_count, +count(case when final = false or final=true then 1 end) as run_count, +count(case when final = false then 1 end) * 100.0 / count(case when final = false or final=true then 1 end) as percentage +FROM splits INNER JOIN runs ON runs.id = splits.run_id +WHERE score > 0 and runs.category = 3 +GROUP BY split_num \ No newline at end of file diff --git a/splitter/sql/pb_splits.sql b/splitter/sql/pb_splits.sql new file mode 100644 index 0000000..bb83682 --- /dev/null +++ b/splitter/sql/pb_splits.sql @@ -0,0 +1,13 @@ +SELECT score, hits, splits.run_id, mode +FROM (SELECT max(score_total), run_id, mode +FROM (SELECT sum(score) as score_total, * +FROM (SELECT score, run_id, mode +FROM splits +INNER JOIN runs +INNER JOIN categories +ON splits.run_id = runs.id AND runs.category = categories.id +WHERE categories.id = ?1) +GROUP BY run_id +ORDER BY score_total DESC)) AS sub +INNER JOIN splits +ON splits.run_id = sub.run_id \ No newline at end of file diff --git a/splitter/sql/run_data_by_id.sql b/splitter/sql/run_data_by_id.sql new file mode 100644 index 0000000..d80c285 --- /dev/null +++ b/splitter/sql/run_data_by_id.sql @@ -0,0 +1,4 @@ +SELECT score, datetime +FROM splits INNER JOIN runs +ON splits.run_id = runs.id +WHERE run_id = ?1 AND category = ?2 \ No newline at end of file diff --git a/splitter/sql/runs_by_score_total.sql b/splitter/sql/runs_by_score_total.sql new file mode 100644 index 0000000..4c692c8 --- /dev/null +++ b/splitter/sql/runs_by_score_total.sql @@ -0,0 +1,6 @@ +SELECT sum(score) as total_score, run_id, runs.datetime +FROM splits INNER JOIN runs +ON splits.run_id = runs.id +WHERE category = ?1 +GROUP BY run_id +ORDER BY total_score DESC \ No newline at end of file diff --git a/splitter/src/app.rs b/splitter/src/app.rs new file mode 100644 index 0000000..1dbc634 --- /dev/null +++ b/splitter/src/app.rs @@ -0,0 +1,555 @@ +use std::{fmt::Display, ops::Add}; + +use eframe::{ + App, Frame, + egui::{Align, CentralPanel, Color32, ComboBox, Context, Id, Layout, Sense, Ui}, +}; +use egui::TopBottomPanel; +use egui_extras::{Column, TableBuilder}; +use itertools::Itertools; + +use crate::{ + Gamemode, Run, ZeroError, ZeroSplitter, + config::CONFIG, + run::SplitData, + theme::{DARK_GREEN, DARK_ORANGE, DARKER_GREEN, DARKER_ORANGE, GREEN, LIGHT_ORANGE}, + ui::{category_maker_dialog, confirm_dialog}, + vanilla_descriptive_split_names, vanilla_split_names, +}; + +pub struct Options { + pub names: bool, + pub relative_score: bool, + pub show_gold_split: bool, + pub decorations: bool, + pub show_options_menu: bool, + pub columns_order: Vec, +} + +impl Default for Options { + fn default() -> Self { + Self { + names: false, + relative_score: true, + show_gold_split: true, + decorations: true, + show_options_menu: false, + columns_order: vec![0, 1, 5, 9], + } + } +} + +impl App for ZeroSplitter { + fn update(&mut self, ctx: &Context, _frame: &mut Frame) { + while let Ok(data) = self.data_source.try_recv() { + self.update_frame(data); + } + + // Detect gamemode change persist between frames + let prev_mode_id = Id::new("prev_mode"); + let cur_mode = self.categories.current().mode; + if let Some(prev_mode) = ctx.data(|data| data.get_temp::(prev_mode_id)) + && prev_mode != cur_mode + { + let zoom_level = CONFIG.get().unwrap().zoom_level; + let min_size = match self.categories.current().mode { + Gamemode::GreenOrange => eframe::egui::Vec2 { x: 300.0, y: 300.0 }, + Gamemode::WhiteVanilla => eframe::egui::Vec2 { x: 300.0, y: 650.0 }, + Gamemode::BlackOnion => todo!(), + }; + let size = ctx.used_size(); + ctx.send_viewport_cmd(eframe::egui::ViewportCommand::InnerSize(size)); + self.reset(); + } + + ctx.data_mut(|data| data.insert_temp(prev_mode_id, cur_mode)); + + CentralPanel::default().show(ctx, |ui| { + if !self.options.decorations + && ui + .interact(ui.max_rect(), Id::new("window_drag"), Sense::drag()) + .dragged() + { + ctx.send_viewport_cmd(eframe::egui::ViewportCommand::StartDrag); + } + + if self.options.show_options_menu { + self.options_menu(ctx); + }; + + ui.with_layout(Layout::top_down_justified(Align::Min), |ui| { + ui.horizontal_top(|ui| { + ui.with_layout(Layout::right_to_left(Align::Min), |ui| { + if ui.button("âš™").clicked() { + self.options.show_options_menu = true; + } + }); + }); + ui.horizontal(|ui| { + if CONFIG.get().unwrap().decoration_button { + let deco_toggle = ui + .toggle_value(&mut self.options.decorations, "DECOR") + .on_hover_text("Toggle the decoration (title bar...)"); + if deco_toggle.changed() && self.options.decorations { + ctx.send_viewport_cmd(eframe::egui::ViewportCommand::Decorations(true)); + } else if deco_toggle.changed() { + ctx.send_viewport_cmd(eframe::egui::ViewportCommand::Decorations(false)); + } + } + }); + ui.horizontal(|ui| { + ui.label("Category: "); + { + let len = self.categories.len(); + let mut cat_idx = self.categories.current; + ComboBox::from_label("") + .show_index(ui, &mut cat_idx, len, |i| &self.categories.index(i).unwrap().name); + if self.categories.current != cat_idx { + self.end_run(); + self.categories.set_current(cat_idx, &self.db).unwrap(); + } + } + + if ui.small_button("+").clicked() { + self.waiting_for_category = true; + } + /*if ui.button("Delete").clicked() { + self.waiting_for_confirm = true; + }*/ + if ui.button("Rename").clicked() { + self.waiting_for_rename = true; + } + }); + + TopBottomPanel::bottom("footer") + .show_separator_line(false) + .show(ctx, |ui| { + ui.label(format!( + "Personal Best: {}", + self.db.get_pb_run(&self.categories).map_or(0, |r| r.1) + )); + ui.label(format!( + "Sum of Best: {}", + self.db.get_gold_splits(&self.categories).map_or(0, |s| s.iter().sum()) + )); + }); + + if let Ok(data) = self.calculate_synthetic_data() { + self.display_splits( + ui, + self.run.splits().unwrap(), + self.run.current_split().unwrap_or_default(), + data, + self.categories.current().mode, + ); + } else { + ui.centered_and_justified(|ui| { + ui.style_mut().interaction.selectable_labels = false; + ui.label("Waiting for a run to start...") + }); + }; + }); + }); + + if self.waiting_for_category { + if let Ok(new_category) = self.dialog_rx.try_recv() { + if let Some(data) = new_category { + self.categories.push(data.textbox, data.mode, &self.db).unwrap(); + } + self.waiting_for_category = false; + } else { + category_maker_dialog(ctx, self.dialog_tx.clone(), "Enter new category name", true); + } + } + + if self.waiting_for_rename { + if let Ok(rename_category) = self.dialog_rx.try_recv() { + if let Some(data) = rename_category { + self.categories.rename_current(&self.db, data.textbox).unwrap(); + } + self.waiting_for_rename = false; + } else { + category_maker_dialog(ctx, self.dialog_tx.clone(), "Enter new name for category", false); + } + } + + if self.waiting_for_confirm { + if let Ok(Some(confirmation)) = self.dialog_rx.try_recv() { + if confirmation.textbox == "Deleted" { + self.categories.delete_current(&self.db).unwrap(); + } + self.waiting_for_confirm = false; + } else { + confirm_dialog( + ctx, + self.dialog_tx.clone(), + format!( + "Are you sure you want to delete category {}?", + self.categories.current().name + ), + ); + } + } + + let size = ctx.used_size(); + ctx.send_viewport_cmd(eframe::egui::ViewportCommand::InnerSize(size)); + } + + fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) { + if let Run::Active { .. } = self.run { + self.save_splits(); + } + } +} + +#[derive(Clone, Copy)] +struct SyntheticData { + gold_split: i32, + pb_split: i32, + summed_score: i32, + summed_gold_split: i32, + summed_pb_split: i32, +} + +impl ZeroSplitter { + fn calculate_synthetic_data(&self) -> Result, ZeroError> { + let raw_splits = self.run.scores()?; + + let summed_score = running_total(raw_splits); + + let gold_splits = self.categories.get_golds().clone(); + let summed_gold_splits = running_total(gold_splits.clone()); + + let pb_splits = self.categories.get_comparison().clone(); + let summed_pb_splits = running_total(pb_splits.clone()); + + // Every iterator needs to be at least the length of the run; having extra should be OK + Ok(itertools::multizip(( + summed_score.into_iter().pad_using(26, |_| 0), + gold_splits.into_iter().pad_using(26, |_| 0), + summed_gold_splits.into_iter().pad_using(26, |_| 0), + pb_splits.into_iter().pad_using(26, |_| 0), + summed_pb_splits.into_iter().pad_using(26, |_| 0), + )) + .map( + |(summed_score, gold_split, summed_gold_split, pb_split, summed_pb_split)| SyntheticData { + gold_split, + pb_split, + summed_score, + summed_gold_split, + summed_pb_split, + }, + ) + .collect()) + } + + /// Display data recieved from params. Only use the self reference for options/config if possible + fn display_splits( + &self, + ui: &mut Ui, + run_data: Vec, + current_split: usize, + synthetic_data: Vec, + current_mode: Gamemode, + ) { + ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend); + + let min_col = CONFIG.get().unwrap().min_col; + + TableBuilder::new(ui) + .columns(Column::auto().at_least(min_col), self.options.columns_order.len()) + .cell_layout(Layout::right_to_left(Align::Min)) + .scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysHidden) + .header(20.0, |mut row| { + let headings = [ + "names", + "best", + "sum best", + "PB", + "sum PB", + "diff", + "sum diff", + "best diff", + "sum best diff", + "score", + "sum score", + "P rank", + "D rank", + "mult", + "bonus", + "time", + "frames", + "cold", + "drops", + ]; + + for idx in self.options.columns_order.iter() { + row.col(|ui| { + ui.label(headings[*idx]); + }); + } + }) + .body(|body| { + body.rows(20.0, run_data.len(), |mut row| { + let n = row.index(); + let this_current = run_data[n]; + let this_synthetic = synthetic_data[n]; + + // translate split number to stage/loop for GO + let stage_n = (n & 3) + 1; + let loop_n = (n >> 2) + 1; + + let names_col = Box::new(|ui: &mut Ui| { + match current_mode { + Gamemode::GreenOrange => ui.label(format!("{loop_n}-{stage_n}")), + Gamemode::WhiteVanilla => { + if self.options.names { + ui.label(vanilla_descriptive_split_names(n)) + } else { + ui.label(vanilla_split_names(n)) + } + } + Gamemode::BlackOnion => todo!(), + }; + }); + + let gold_col = Box::new(|ui: &mut Ui| { + if this_synthetic.gold_split > 0 { + ui.colored_label(GREEN, this_synthetic.gold_split.to_string()); + } + }); + + let summed_gold_col = Box::new(|ui: &mut Ui| { + if this_synthetic.summed_gold_split > 0 { + ui.colored_label(GREEN, this_synthetic.summed_gold_split.to_string()); + } + }); + + let pb_col = Box::new(|ui: &mut Ui| { + if this_synthetic.gold_split > 0 { + ui.colored_label(GREEN, this_synthetic.pb_split.to_string()); + } + }); + + let summed_pb_col = Box::new(|ui: &mut Ui| { + if this_synthetic.gold_split > 0 { + ui.colored_label(GREEN, this_synthetic.summed_pb_split.to_string()); + } + }); + + let diff_col = Box::new(|ui: &mut Ui| { + if n < current_split { + // past split, we should show a diff + let diff = this_current.score - this_synthetic.pb_split; + let diff_color = if diff > 0 { + LIGHT_ORANGE + } else if diff == 0 { + Color32::WHITE + } else { + DARK_GREEN + }; + ui.colored_label(diff_color, format!("{diff:+}")); + } + }); + + let summed_diff_col = Box::new(|ui: &mut Ui| { + if n < current_split { + // past split, we should show a diff + let summed_diff = this_synthetic.summed_score - this_synthetic.summed_pb_split; + let diff = this_current.score - this_synthetic.pb_split; + let diff_color = if summed_diff > 0 { + if diff >= 0 { LIGHT_ORANGE } else { DARK_ORANGE } + } else if summed_diff == 0 { + Color32::WHITE + } else { + if diff >= 0 { DARK_GREEN } else { DARKER_GREEN } + }; + ui.colored_label(diff_color, format!("{summed_diff:+}")); //TODO: re-add subcolors + } + }); + + let gold_diff_col = Box::new(|ui: &mut Ui| { + if n < current_split { + // past split, we should show a diff + let diff = this_current.score - this_synthetic.gold_split; + let diff_color = if diff > 0 { + LIGHT_ORANGE + } else if diff == 0 { + Color32::WHITE + } else { + DARK_GREEN + }; + ui.colored_label(diff_color, format!("{diff:+}")); + } + }); + + let summed_gold_diff_col = Box::new(|ui: &mut Ui| { + if n < current_split { + // past split, we should show a diff + let summed_diff = this_synthetic.summed_score - this_synthetic.summed_gold_split; + let diff = this_current.score - this_synthetic.gold_split; + let diff_color = if summed_diff > 0 { + if diff >= 0 { LIGHT_ORANGE } else { DARK_ORANGE } + } else if summed_diff == 0 { + Color32::WHITE + } else { + if diff >= 0 { DARK_GREEN } else { DARKER_GREEN } + }; + ui.colored_label(diff_color, format!("{summed_diff:+}")); //TODO: re-add subcolors + } + }); + + let scores_col = Box::new(|ui: &mut Ui| { + ui.horizontal(|ui| { + ui.with_layout(Layout::right_to_left(Align::Min), |ui| { + // Only write splits up to the current split + if n <= current_split { + // Set color of split (rightmost number) + let split_color = if current_split == n && self.split_delay.is_none() { + Color32::WHITE + } else if this_current.score >= this_synthetic.gold_split { + DARKER_ORANGE + } else { + DARK_ORANGE + }; + + ui.colored_label(split_color, this_current.score.to_string()); + } else { + ui.colored_label(DARK_GREEN, "--"); + } + }); + }); + }); + + let summed_scores_col = Box::new(|ui: &mut Ui| { + ui.horizontal(|ui| { + ui.with_layout(Layout::right_to_left(Align::Min), |ui| { + // Only write splits up to the current split + if n <= current_split { + let split_color = if current_split == n && self.split_delay.is_none() { + Color32::WHITE + } else if this_synthetic.summed_score >= this_synthetic.summed_gold_split { + DARKER_ORANGE + } else { + DARK_ORANGE + }; + + ui.colored_label(split_color, this_synthetic.summed_score.to_string()); + } else { + ui.colored_label(DARK_GREEN, "--"); + } + }); + }); + }); + + let prank_col = Box::new(|ui: &mut Ui| { + if this_current.pattern_rank > 0.0 { + ui.colored_label(GREEN, format!("{}", this_current.pattern_rank)); + } else { + ui.colored_label(DARK_GREEN, "--"); + } + }); + + let drank_col = Box::new(|ui: &mut Ui| { + if this_current.dynamic_rank > 0.0 { + ui.colored_label(GREEN, format!("{:.4}", this_current.dynamic_rank)); + } else { + ui.colored_label(DARK_GREEN, "--"); + } + }); + + let timebonus_col = Box::new(|ui: &mut Ui| { + if this_current.time_bonus > 0 { + ui.colored_label(GREEN, format!("{}", this_current.time_bonus)); + } else { + ui.colored_label(DARK_GREEN, "--"); + } + }); + + let time_col = Box::new(|ui: &mut Ui| { + if this_current.time_frames > 0 { + ui.colored_label(GREEN, format!("{:.2}", this_current.time_frames as f64 / 60.0)); + } else { + ui.colored_label(DARK_GREEN, "--"); + } + }); + + let time_frames_col = Box::new(|ui: &mut Ui| { + if this_current.time_frames > 0 { + ui.colored_label(GREEN, format!("{}", this_current.time_frames)); + } else { + ui.colored_label(DARK_GREEN, "--"); + } + }); + + let coldframes_col = Box::new(|ui: &mut Ui| { + if this_current.coldframes > 0 { + ui.colored_label(GREEN, format!("{}", this_current.coldframes)); + } else { + ui.colored_label(DARK_GREEN, "--"); + } + }); + + let mult_drops_col = Box::new(|ui: &mut Ui| { + if this_current.mult_drops > 0 { + ui.colored_label(GREEN, format!("{}", this_current.mult_drops)); + } else { + ui.colored_label(DARK_GREEN, "--"); + } + }); + + let mult_col = simple_col(this_current.mult); + + let mut columns: Vec> = vec![ + names_col, + gold_col, + summed_gold_col, + pb_col, + summed_pb_col, + diff_col, + summed_diff_col, + gold_diff_col, + summed_gold_diff_col, + scores_col, + summed_scores_col, + prank_col, + drank_col, + mult_col, + timebonus_col, + time_col, + time_frames_col, + coldframes_col, + mult_drops_col, + ]; + + for idx in self.options.columns_order.iter() { + row.col(columns.get_mut(*idx).unwrap()); + } + }); + }); + } +} + +fn running_total(mut input: Vec) -> Vec +where + T: Add + Copy + Default, +{ + for i in 0..input.len() { + input[i] = input[i] + i.checked_sub(1).map_or(T::default(), |j| input[j]) + } + + input +} + +fn simple_col(value: T) -> Box +where + T: Display + PartialOrd + Default + Copy, +{ + Box::new(move |ui: &mut Ui| { + if value > T::default() { + ui.colored_label(GREEN, format!("{}", value)); + } else { + ui.colored_label(DARK_GREEN, "--"); + } + }) +} diff --git a/splitter/src/config.rs b/splitter/src/config.rs new file mode 100644 index 0000000..1cf5965 --- /dev/null +++ b/splitter/src/config.rs @@ -0,0 +1,239 @@ +use std::{ + fs::{File, OpenOptions, read_to_string}, + io::{Read, Write}, + sync::OnceLock, +}; + +use crate::{VERSION, ZeroSplitter, theme::DARK_GREEN}; + +use eframe::egui::{Context, Id, RichText, Separator, TextEdit, ViewportBuilder, ViewportId}; +use toml::{Table, Value, value::Array}; + +use crate::{ZeroError, theme::GREEN, update::check_for_updates}; + +pub static CONFIG: OnceLock = OnceLock::new(); + +const CONFIG_PATH: &'static str = "config.toml"; + +pub fn load_config() -> Result<(), ZeroError> { + let config_str = match read_to_string(CONFIG_PATH) { + Ok(s) => s, + Err(e) => match e.kind() { + std::io::ErrorKind::NotFound => create_config()?, + _ => return Err(ZeroError::IOError(e)), + }, + }; + let table = config_str.parse::()?; + + let mut writer = OpenOptions::new().append(true).open(CONFIG_PATH)?; + + let config = Config { + zoom_level: match table.get("zoom_level") { + Some(Value::Float(f)) => *f as f32, + None => { + writer.write_all(include_bytes!("../assets/config_sections/zoom_level.toml"))?; + 1.0 + } + _ => return Err(ZeroError::ConfigError("zoom_level".to_owned())), + }, + decoration_button: match table.get("decoration_button") { + Some(Value::Boolean(b)) => *b, + None => { + writer.write_all(include_bytes!("../assets/config_sections/decoration_button.toml"))?; + false + } + _ => return Err(ZeroError::ConfigError("decoration_button".to_owned())), + }, + check_for_updates: match table.get("check_for_updates") { + Some(Value::Boolean(b)) => *b, + None => { + writer.write_all(include_bytes!("../assets/config_sections/check_for_updates.toml"))?; + true + } + _ => return Err(ZeroError::ConfigError("check_for_updates".to_owned())), + }, + min_col: match table.get("minimum_column_width") { + Some(Value::Float(f)) => *f as f32, + None => { + writer.write_all(include_bytes!("../assets/config_sections/min_col.toml"))?; + 50.0 + } + _ => return Err(ZeroError::ConfigError("min_col".to_owned())), + }, + default_columns: match table.get("default_columns") { + Some(Value::Array(a)) => a + .into_iter() + .filter_map(|v| { + if let Value::Integer(i) = v { + Some(*i as usize) + } else { + None + } + }) + .collect(), + None => { + writer.write_all(include_bytes!("../assets/config_sections/default_columns.toml"))?; + Vec::from([0, 1, 5, 9]) + } + _ => return Err(ZeroError::ConfigError("min_col".to_owned())), + }, + }; + + CONFIG.set(config).map_err(|_| ZeroError::StaticAlreadyInit)?; + Ok(()) +} + +fn create_config() -> Result { + let mut file = File::create_new(CONFIG_PATH)?; + file.write_all(include_bytes!("../assets/config_sections/heading.toml"))?; + let mut ret = String::new(); + file.read_to_string(&mut ret)?; + + Ok(ret) +} + +pub struct Config { + pub zoom_level: f32, + pub decoration_button: bool, + pub check_for_updates: bool, + pub min_col: f32, + pub default_columns: Vec, +} + +impl ZeroSplitter { + pub fn options_menu(&mut self, ctx: &Context) -> () { + ctx.show_viewport_immediate( + ViewportId::from_hash_of("options_menu_viewport"), + ViewportBuilder::default().with_title("Options"), + |ctx, _| { + eframe::egui::CentralPanel::default().show(ctx, |ui| { + if CONFIG.get().unwrap().check_for_updates { + // UPDATER + ui.horizontal(|ui| { + ui.label(RichText::new("Updater").color(GREEN).heading()); + ui.add(Separator::default().horizontal()) + }); + ui.horizontal(|ui| { + let update_label_id = Id::new("update_label"); + if ui.button("Check for updates").clicked() { + ctx.data_mut(|data| { + data.insert_temp( + update_label_id, + match check_for_updates() { + Ok(Some(url)) => format!("Update avaliable - {url}"), + Ok(None) => format!("Up to date - {VERSION}"), + Err(e) => format!("Failed to check for update - {e:?}"), + }, + ) + }); + } + ui.label( + ctx.data(|data| data.get_temp::(update_label_id)) + .unwrap_or_default(), + ); + }); + }; + // EXTRA COLUMNS + ui.horizontal(|ui| { + ui.label(RichText::new("Column Selector").color(GREEN).heading()); + ui.add(Separator::default().horizontal()) + }); + + ui.colored_label(DARK_GREEN, "Hover each column checkbox for descriptions"); + + let mut col_checks = vec![false; 19]; + for col in self.options.columns_order.iter() { + col_checks[*col] = true + } + + // TODO: don't do this + ui.checkbox(col_checks.get_mut(0).unwrap(), "names"); + ui.checkbox(col_checks.get_mut(1).unwrap(), "best") + .on_hover_text("Your best score for each split"); + ui.checkbox(col_checks.get_mut(2).unwrap(), "summed best") + .on_hover_text("Your best ever total score at this split"); + ui.checkbox(col_checks.get_mut(3).unwrap(), "PB") + .on_hover_text("The score you got in each split of your PB"); + ui.checkbox(col_checks.get_mut(4).unwrap(), "summed PB") + .on_hover_text("The total score you had at each split of your PB"); + ui.checkbox(col_checks.get_mut(5).unwrap(), "diff").on_hover_text( + "The difference between your split score and the score for this split in your PB", + ); + ui.checkbox(col_checks.get_mut(6).unwrap(), "summed diff") + .on_hover_text( + "The difference between your total score and the total score at this split in your PB", + ); + ui.checkbox(col_checks.get_mut(7).unwrap(), "best diff").on_hover_text( + "The difference between your split score and your best ever score for this split", + ); + ui.checkbox(col_checks.get_mut(8).unwrap(), "summed best diff") + .on_hover_text( + "The difference between your total score and your best ever total score at this split", + ); + ui.checkbox(col_checks.get_mut(9).unwrap(), "score"); + ui.checkbox(col_checks.get_mut(10).unwrap(), "summed score"); + ui.checkbox(col_checks.get_mut(11).unwrap(), "pattern rank"); + ui.checkbox(col_checks.get_mut(12).unwrap(), "dynamic rank"); + ui.checkbox(col_checks.get_mut(13).unwrap(), "mult (WV)"); + ui.checkbox(col_checks.get_mut(14).unwrap(), "time bonus (WV)"); + ui.checkbox(col_checks.get_mut(15).unwrap(), "time (WV)"); + ui.checkbox(col_checks.get_mut(16).unwrap(), "time (frames) (WV)"); + ui.checkbox(col_checks.get_mut(17).unwrap(), "coldframes (WV)") + .on_hover_text( + "The number of frames the time bonus countdown was paused due to killing all enemies", + ); + ui.checkbox(col_checks.get_mut(18).unwrap(), "mult drops (GO)"); + + self.options.columns_order = col_checks + .iter() + .enumerate() + .filter_map(|(i, b)| b.then_some(i)) + .collect(); + + // IMPORTER + ui.horizontal(|ui| { + ui.label(RichText::new("Importer").color(GREEN).heading()); + ui.add(Separator::default().horizontal()) + }); + // Category name + let category_name_id = ui.label("Category name").id; + let mut category_name = ctx + .data(|data| data.get_temp::(category_name_id)) + .unwrap_or_default(); + ui.add(TextEdit::singleline(&mut category_name)); + ctx.data_mut(|data| data.insert_temp(category_name_id, category_name.clone())); + + // Split data + let splits_data_id = ui.label("Split scores").id; + let mut run_string = ctx + .data(|data| data.get_temp::(splits_data_id)) + .unwrap_or_default(); + ui.add(TextEdit::multiline(&mut run_string).hint_text("111, 222, 333, 444, 555, 666, 777, 888")); + ctx.data_mut(|data| data.insert_temp(splits_data_id, run_string.clone())); + + if ui.button("IMPORT").clicked() { + let splits = run_string + .split(", ") + .map(|s| s.parse().unwrap_or_default()) + .collect::>(); + match self.db.import_run(splits.clone(), &category_name) { + Ok(_) => { + println!( + "Successfully imported run with {} splits and total score {}", + splits.len(), + splits.iter().sum::() + ); + run_string.clear(); + } + Err(err) => println!("Import failed: {err}"), + }; + }; + }); + + if ctx.input(|i| i.viewport().close_requested()) { + self.options.show_options_menu = false + }; + }, + ); + } +} diff --git a/splitter/src/database.rs b/splitter/src/database.rs new file mode 100644 index 0000000..0303057 --- /dev/null +++ b/splitter/src/database.rs @@ -0,0 +1,407 @@ +use std::sync::Arc; + +use log::error; +use rusqlite::{ + Connection, Result, ToSql, params, + types::{FromSql, ValueRef}, +}; + +use crate::{Category, CategoryManager, Gamemode, Run}; + +#[derive(Clone)] +pub struct Database { + conn: Arc, +} + +macro_rules! transaction { + ($conn:expr, $inner:expr) => {{ + $conn.execute("BEGIN TRANSACTION", ())?; + + match (|| { + { + $inner + } + + Ok::<(), rusqlite::Error>(()) + })() { + Ok(_) => { + $conn.execute("COMMIT", ())?; + Ok(()) + } + Err(err) => { + $conn.execute("ROLLBACK", ())?; + Err(err) + } + } + }}; +} + +const CURRENT_SCHEMA_VERSION: i32 = 5; + +impl Database { + pub fn init() -> Result { + let database = Database { + #[cfg(not(test))] + conn: Arc::new(Connection::open("./sqlite.db3")?), + #[cfg(test)] + conn: Arc::new(Connection::open_in_memory()?), + }; + + // create tables if they don't exist + if !database.conn.table_exists(Some("main"), "categories")? { + if let Err(err) = database.create_tables0() { + error!("Error creating tables: {}", err) + }; + database.insert_new_category("default".to_owned(), Gamemode::GreenOrange)?; + } + // check version of schema (0 if they were just created) + let schema_version = database + .conn + .query_one("PRAGMA user_version", (), |row| row.get::<_, i32>(0)) + .unwrap(); + + // migrate schema version if necessary + if schema_version < CURRENT_SCHEMA_VERSION { + database.migrate(schema_version) + } else if schema_version > CURRENT_SCHEMA_VERSION { + panic!( + "Schema version beyond program version!\n Schema version {schema_version}, program version {CURRENT_SCHEMA_VERSION}" + ) + } + + Ok(database) + } + pub fn create_tables0(&self) -> Result<()> { + self.conn.execute("BEGIN TRANSACTION", ())?; + + match (|| { + self.conn.pragma_update(Some("main"), "user_version", 0)?; + self.conn.execute( + " + CREATE TABLE IF NOT EXISTS categories ( + id INTEGER PRIMARY KEY, + name TEXT UNIQUE NOT NULL, + mode INTEGER NOT NULL + ) + ", + (), + )?; + + self.conn.execute( + " + CREATE TABLE IF NOT EXISTS runs ( + id INTEGER PRIMARY KEY, + category INTEGER NOT NULL REFERENCES categories(id) ON DELETE CASCADE + ) + ", + (), + )?; + + self.conn.execute( + " + CREATE TABLE IF NOT EXISTS splits ( + id INTEGER PRIMARY KEY, + split_num INTEGER NOT NULL, + score INTEGER NOT NULL, + hits INTEGER, + mult INTEGER, + run_id INTEGER NOT NULL REFERENCES runs(id) ON DELETE CASCADE + ) + ", + (), + )?; + + Ok::<(), rusqlite::Error>(()) + })() { + Ok(_) => { + self.conn.execute("COMMIT", ())?; + Ok(()) + } + Err(err) => { + self.conn.execute("ROLLBACK", ())?; + Err(err) + } + } + } + + pub fn insert_new_category(&self, name: String, mode: Gamemode) -> Result { + self.conn + .execute("INSERT INTO categories VALUES(NULL, ?1, ?2)", params![name, mode])?; + + Ok(self.conn.last_insert_rowid()) + } + + pub fn delete_category(&self, category: Category) -> Result { + self.conn + .execute("DELETE FROM categories WHERE id = ?1", params![category.id]) + } + + pub fn rename_category(&self, category: &Category, new_name: String) -> Result { + self.conn.execute( + "UPDATE categories SET name='?1' WHERE id=?2", + params![new_name, category.id], + ) + } + pub fn get_categories(&self) -> Result> { + let mut statement = self.conn.prepare("SELECT name, mode, id FROM categories")?; + let rows = statement.query_map((), |row| { + Ok(( + row.get::<_, String>(0)?, + row.get::<_, Gamemode>(1)?, + row.get::<_, i64>(2)?, + )) + })?; + let categories = rows + .map(|r| r.unwrap()) + .map(|(name, mode, id)| Category { id, mode, name }) + .collect::>(); + Ok(categories) + } + + pub fn insert_run(&self, category: &CategoryManager, run: &Run) -> Result<()> { + let category = category.current(); + self.conn.execute("BEGIN TRANSACTION", ())?; + + match (|| { + let mut stmt = self.conn.prepare("SELECT id FROM categories WHERE name = ?1")?; + let res = stmt.query_one(params![category.name], |row| row.get::(0))?; + + self.conn.execute( + "INSERT INTO runs (id, category, datetime, imported) VALUES(NULL, ?1, datetime('now'), false)", + params![res], + )?; + + let run_id = self.conn.last_insert_rowid(); + + for (num, &split) in run.splits().unwrap().iter().take_while(|&&s| s.score > 0).enumerate() { + let final_split = num == run.current_split().unwrap(); + self.conn.execute( + "INSERT INTO splits (id, split_num, score, hits, mult, run_id, final, pattern_rank, dynamic_rank, time_frames, time_bonus, time_coldframes) VALUES(NULL, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)", + params![num, split.score, 0, split.mult, run_id, final_split, split.pattern_rank, split.dynamic_rank, split.time_frames, split.time_bonus, split.coldframes], + )?; + } + + Ok::<(), rusqlite::Error>(()) + })() { + Ok(_) => { + self.conn.execute("COMMIT", ())?; + println!("Committing run with score {} to database", run.score().unwrap()); + Ok(()) + } + Err(err) => { + self.conn.execute("ROLLBACK", ())?; + Err(err) + } + } + } + + pub fn get_pb_run(&self, category: &CategoryManager) -> Result<(Vec, i32, Gamemode)> { + let category = category.current(); + let mut statement = self.conn.prepare(include_str!("../sql/pb_splits.sql"))?; + let rows = statement.query_map(params![category.id], |row| { + Ok(( + row.get::(0)?, //score + row.get::>(1)?, //mult + row.get::(2)?, //run_id + row.get::(3)?, + )) + })?; + let splits: Vec<(i32, Option, i32, Gamemode)> = rows.map(|r| r.unwrap()).collect(); + + if splits.len() > 0 { + let scores: Vec = splits.iter().map(|s| s.0).collect(); + let _hits: Vec = splits.iter().map(|s| s.1.unwrap_or(0)).collect(); + let _run_id = splits[0].2; + let mode = splits[0].3; + + let total = scores.iter().sum(); + + Ok((scores, total, mode)) + } else { + Err(rusqlite::Error::QueryReturnedNoRows) + } + } + + /// Get the highest core of each split for the category + pub fn get_gold_splits(&self, category: &CategoryManager) -> Result> { + let mut statement = self.conn.prepare(include_str!("../sql/best_splits.sql"))?; + statement + .query_map(params![category.current().id], |rows| rows.get(0))? + .collect::>>() + .map(|v| { + if v.len() > 0 { + Ok(v) + } else { + Err(rusqlite::Error::QueryReturnedNoRows) + } + })? + } + + fn migrate(&self, schema_version: i32) { + println!("Migrating database from {schema_version} to {CURRENT_SCHEMA_VERSION}"); + + self.conn.execute("BEGIN TRANSACTION", ()).unwrap(); + + let mut current_schema = schema_version; + + match (|| { + while current_schema < CURRENT_SCHEMA_VERSION { + match current_schema { + 0 => { + self.migrate0to1()?; + current_schema = 1 + } + 1 => { + self.migrate1to2()?; + current_schema = 2 + } + 2 => { + self.migrate2to3()?; + current_schema = 3 + } + 3 => { + self.migrate3to4()?; + current_schema = 4 + } + 4 => { + self.migrate4to5()?; + current_schema = 5 + } + _ => Err(rusqlite::Error::InvalidQuery)?, + }; + } + Ok::<(), rusqlite::Error>(()) + })() { + Ok(_) => { + self.conn.execute("COMMIT", ()).unwrap(); + println!("Migration successful") + } + Err(err) => { + self.conn.execute("ROLLBACK", ()).unwrap(); + panic!("Migration failed! {err}") + } + } + } + + fn migrate0to1(&self) -> Result { + println!("Migrating schema 0 to 1..."); + self.conn.pragma_update(Some("main"), "user_version", 1)?; + self.conn.execute("ALTER TABLE splits ADD COLUMN final BOOLEAN", ()) + } + + fn migrate1to2(&self) -> Result { + println!("Migrating schema 1 to 2..."); + self.conn.pragma_update(Some("main"), "user_version", 2)?; + self.conn.execute("ALTER TABLE runs ADD COLUMN datetime INTEGER", ()) + } + + fn migrate2to3(&self) -> Result<()> { + println!("Migrating schema 2 to 3..."); + self.conn.pragma_update(Some("main"), "user_version", 3)?; + self.conn.execute_batch( + "ALTER TABLE splits ADD COLUMN pattern_rank REAL; + ALTER TABLE splits ADD COLUMN dynamic_rank REAL;", + ) + } + + fn migrate3to4(&self) -> Result { + println!("Migrating schema 3 to 4..."); + self.conn.pragma_update(Some("main"), "user_version", 4)?; + self.conn.execute("ALTER TABLE runs ADD COLUMN imported BOOLEAN", ()) + } + + fn migrate4to5(&self) -> Result<()> { + println!("Migrating schema 4 to 5..."); + self.conn.pragma_update(Some("main"), "user_version", 5)?; + self.conn.execute_batch( + "ALTER TABLE splits ADD COLUMN time_frames INTEGER; + ALTER TABLE splits ADD COLUMN time_bonus INTEGER; + ALTER TABLE splits ADD COLUMN time_coldframes INTEGER;", + ) + } + + pub fn import_run(&self, splits: Vec, category_name: &String) -> Result<()> { + transaction!(self.conn, { + let category_id = + self.conn + .query_one("SELECT id FROM categories WHERE name=?1", params![category_name], |r| { + r.get::<_, i32>(0) + })?; + self.conn + .execute( + "INSERT INTO runs (category, imported) VALUES (?1, true)", + params![category_id], + ) + .unwrap(); + let last = self.conn.last_insert_rowid(); + for (idx, score) in splits.iter().enumerate() { + self.conn + .execute( + "INSERT INTO splits (split_num, score, run_id) VALUES (?1, ?2, ?3)", + params![idx as i32, score, last], + ) + .unwrap(); + } + }) + } +} + +impl ToSql for Gamemode { + fn to_sql(&self) -> Result> { + match self { + Gamemode::GreenOrange => Ok(0u8.into()), + Gamemode::WhiteVanilla => Ok(1u8.into()), + Gamemode::BlackOnion => Ok(2u8.into()), + } + } +} + +impl FromSql for Gamemode { + fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult { + match value { + ValueRef::Integer(0) => Ok(Self::GreenOrange), + ValueRef::Integer(1) => Ok(Self::WhiteVanilla), + ValueRef::Integer(2) => Ok(Self::BlackOnion), + ValueRef::Integer(i) => Err(rusqlite::types::FromSqlError::OutOfRange(i)), + _ => Err(rusqlite::types::FromSqlError::InvalidType), + } + } +} + +#[cfg(test)] +#[allow(dead_code, unused)] +mod tests { + use std::sync::Arc; + + use rusqlite::Connection; + + use rusqlite::Result; + + use crate::Gamemode; + use crate::{ + Category, + database::{self, Database}, + }; + + #[test] + fn import_and_get_pb() -> Result<()> { + let db = Database::init()?; + + println!("Importing run..."); + db.import_run(vec![10, 20, 30, 40], &"default".to_string())?; + + let mut categories = crate::CategoryManager { + categories: vec![], + current: 0, + comparison_cache: vec![], + golds_cache: vec![], + }; + categories.load(&db); + + println!("Getting PB..."); + let pb = db.get_pb_run(&categories)?; + + assert!(pb.0 == vec![10, 20, 30, 40]); + Ok(()) + } +} diff --git a/splitter/src/main.rs b/splitter/src/main.rs index ee05796..b018615 100644 --- a/splitter/src/main.rs +++ b/splitter/src/main.rs @@ -1,6 +1,5 @@ use std::{ env, - fs::{self, File}, net::UdpSocket, sync::{ OnceLock, @@ -12,34 +11,44 @@ use std::{ use common::FrameData; use eframe::{ - App, Frame, NativeOptions, - egui::{ - Align, CentralPanel, Color32, ComboBox, Context, IconData, Id, Key, Layout, Sides, ThemePreference, - ViewportBuilder, ViewportId, - }, + NativeOptions, + egui::{Context, IconData, ThemePreference, ViewportBuilder}, }; -use log::{error, warn}; +use log::{debug, error}; use serde::{Deserialize, Serialize}; +use crate::{app::Options, config::CONFIG, database::Database, run::Run, theme::zeroranger_visuals}; + +mod app; +mod config; +mod database; mod hook; +mod run; mod system; +mod theme; mod ui; +mod update; -const DARK_GREEN: Color32 = Color32::from_rgb(0, 0x4f, 0x4d); -const GREEN: Color32 = Color32::from_rgb(0, 0x94, 0x79); -const LIGHT_ORANGE: Color32 = Color32::from_rgb(0xff, 0xc0, 0x73); -const DARK_ORANGE: Color32 = Color32::from_rgb(0xff, 0x80, 0); +const VERSION: &str = env!("CARGO_PKG_VERSION"); static EGUI_CTX: OnceLock = OnceLock::new(); fn main() { + config::load_config().unwrap(); + let zoom_level = CONFIG.get().unwrap().zoom_level; + #[cfg(debug_assertions)] + unsafe { + env::set_var("RUST_BACKTRACE", "1"); + } + pretty_env_logger::init(); let options = NativeOptions { viewport: ViewportBuilder::default() - .with_inner_size([300., 300.]) + .with_inner_size([300.0 * zoom_level, 300.0 * zoom_level]) .with_icon(IconData::default()) .with_title("ZeroSplitter"), + ..Default::default() }; @@ -53,6 +62,8 @@ fn main() { Box::new(|c| { let _ = EGUI_CTX.set(c.egui_ctx.clone()); c.egui_ctx.set_theme(ThemePreference::Dark); + c.egui_ctx.set_visuals(zeroranger_visuals()); + c.egui_ctx.set_zoom_factor(CONFIG.get().unwrap().zoom_level); Ok(Box::new(ZeroSplitter::load(rx))) }), ) @@ -80,386 +91,468 @@ fn ipc_thread(channel: Sender) { } struct ZeroSplitter { - categories: Vec, - current_category: usize, + categories: CategoryManager, data_source: Receiver, last_frame: FrameData, - current_run: Run, - current_split: Option, - current_split_score_offset: i32, + run: Run, waiting_for_category: bool, waiting_for_rename: bool, waiting_for_confirm: bool, - dialog_rx: Receiver, - dialog_tx: Sender, - comparison: Category, + dialog_rx: Receiver>, + dialog_tx: Sender>, + split_delay: Option, + start_delay: Option, + db: Database, + options: Options, } impl ZeroSplitter { - fn new(data_source: Receiver) -> Self { + fn new(data_source: Receiver, db: Database) -> Self { let (tx, rx) = mpsc::channel(); - let mut default_categories = Vec::new(); - default_categories.push(Category::new("Type-C".to_string())); - default_categories.push(Category::new("Type-B".to_string())); - Self { - categories: default_categories, + let mut zerosplitter = Self { + categories: CategoryManager::init(), data_source, - last_frame: Default::default(), - current_category: 0, - current_run: Default::default(), - current_split: None, - current_split_score_offset: 0, + last_frame: FrameData::default(), + run: Run::Inactive, dialog_rx: rx, dialog_tx: tx, waiting_for_category: false, waiting_for_rename: false, waiting_for_confirm: false, - comparison: Category::new("".to_string()), - } + split_delay: None, + start_delay: None, + db, + options: Default::default(), + }; + + zerosplitter.categories.load(&zerosplitter.db).unwrap(); + zerosplitter.options.columns_order = CONFIG.get().unwrap().default_columns.clone(); + + zerosplitter } fn load(data_source: Receiver) -> Self { - let data_path = env::current_exe() - .expect("Could not get program directory") - .with_file_name("zs_data.json"); - - match fs::exists(&data_path) { - Ok(true) => (), - Ok(false) => return Self::new(data_source), - Err(e) => { - warn!("Could not tell if data file exists: {}", e); - return Self::new(data_source); - } - } + let db = Database::init().unwrap(); - match File::open(&data_path) { - Ok(file) => { - let data: Vec = serde_json::from_reader(file).expect("Loading data"); - if data.is_empty() { - Self::new(data_source) - } else { - Self { - current_category: 0, - categories: data, - ..Self::new(data_source) - } - } - } - Err(e) => panic!("Could not open extant data file at {:?}: {}", &data_path, e), - } + Self::new(data_source, db.clone()) } fn save_splits(&mut self) { - self.categories[self.current_category].update_from_run(&self.current_run); - - let data_path = env::current_exe() - .expect("Could not get program directory") - .with_file_name("zs_data.json"); - let file = match File::create(&data_path) { - Ok(file) => file, - Err(err) => { - error!("Could not save: Could not open data file {:?}: {}", &data_path, err); - return; - } - }; + if self.run.is_active() && self.run.scores().unwrap()[0] > 0 { + debug!("Saving splits"); - if let Err(err) = serde_json::to_writer_pretty(file, &self.categories) { - error!("Error writing save: {}", err); + if let Err(err) = self.db.insert_run(&self.categories, &self.run) { + error!("Error writing run to database: {err}"); + } } } fn update_frame(&mut self, frame: FrameData) { - // WV not yet implemented, idk if it'll crash or not + if self.run.is_active() && frame.is_menu() { + self.end_run(); + } + // Difficulty is ZR-speak for gamemode if frame.difficulty == 0 { - // Reset if we just left the menu or returned to 1-1 - if frame.stage != self.last_frame.stage && (self.last_frame.is_menu() || frame.is_first_stage()) { - self.reset(); - } - - if !frame.is_menu() { - let frame_split = (frame.stage - 1 - frame.game_loop) as usize; - - if frame_split >= 8 { - // TLB or credits - return; - } + self.update_greenorange(frame); + } else if frame.difficulty == -1 { + self.update_whitevanilla(frame); + } else if frame.difficulty == 1 { + // Black Onion placeholder + } + self.last_frame = frame; + } - // Split if necessary - if frame.stage != self.last_frame.stage { - self.current_split = Some(frame_split); - self.current_split_score_offset = self.last_frame.total_score(); - self.save_splits(); - } + fn update_greenorange(&mut self, frame: FrameData) { + // Skip update if current category isn't Green Orange or if on menu + if self.categories.current().mode != Gamemode::GreenOrange || frame.is_menu() { + return; + } - // If our score got reset by a continue, fix the score offset. - if self.current_split_score_offset > frame.total_score() { - self.current_split_score_offset = 0; - } + let frame_split = frame + .stage + .checked_sub(1) + .unwrap_or(0) + .checked_sub(frame.game_loop) + .unwrap_or(0) as usize; + + // Reset if we just left the menu or returned to 1-1 + if frame.stage != self.last_frame.stage && (self.last_frame.is_menu() || frame.is_first_stage()) { + self.reset(); + self.run.start(frame); + self.run.set_split(frame_split).unwrap(); + self.categories.refresh_caches(&self.db).unwrap(); + } - // Update run and split scores - self.current_run.score = frame.total_score(); - let split_score = frame.total_score() - self.current_split_score_offset; - self.current_run.splits[frame_split] = split_score; - } else { - // End the run if we're back on the menu - self.end_run(); + if !frame.is_menu() && self.run.is_active() { + if frame_split >= 8 { + // TLB or credits + return; } - } - self.last_frame = frame; - } + // check for mult halving, second conditional is for odd multiplier + if frame.multiplier_one + 10 == (self.last_frame.multiplier_one + 10) / 2 + || frame.multiplier_one + 9 == (self.last_frame.multiplier_one + 10) / 2 + { + dbg!(frame.multiplier_one, self.last_frame.multiplier_one); + self.run.bump_mult_drops(); + } - fn reset(&mut self) { - self.end_run(); - self.current_run = Default::default(); - self.comparison = self.categories[self.current_category].clone(); - } + // Split if necessary + if (frame_split > self.run.current_split().unwrap()) && !self.last_frame.is_menu() { + self.run.split().unwrap(); + } - fn end_run(&mut self) { - self.save_splits(); - self.current_split = None; + // Update run and split scores + self.run.update(frame).unwrap(); + } else { + // End the run if we're back on the menu + // TODO make certain this is unreachable? + self.end_run(); + } } -} -impl App for ZeroSplitter { - fn update(&mut self, ctx: &Context, _frame: &mut Frame) { - while let Ok(data) = self.data_source.try_recv() { - self.update_frame(data); + fn update_whitevanilla(&mut self, frame: FrameData) { + let last_frame = self.last_frame; + // Skip update if current category isn't White Vanilla or if on menu + if self.categories.current().mode != Gamemode::WhiteVanilla || frame.is_menu() { + return; } - CentralPanel::default().show(ctx, |ui| { - ui.with_layout(Layout::top_down_justified(Align::Min), |ui| { - ui.horizontal(|ui| { - ui.label("Category: "); - ComboBox::from_label("").show_index(ui, &mut self.current_category, self.categories.len(), |i| { - &self.categories[i].name - }); - if ui.small_button("+").clicked() { - self.waiting_for_category = true; - } - /*if ui.button("Delete").clicked() { - self.waiting_for_confirm = true; - }*/ - if ui.button("Rename").clicked() { - self.waiting_for_rename = true; - } - }); - - let cur_category = &self.categories[self.current_category]; - - for (i, split) in self.current_run.splits.iter().enumerate() { - let stage_n = (i & 3) + 1; - let loop_n = (i >> 2) + 1; - let best = cur_category.best_splits[i]; - let stored_best = self.comparison.personal_best.splits[i]; - let pb = self.comparison.personal_best.splits[i]; - - Sides::new().show( - ui, - |left| { - left.label(format!("{}-{}", loop_n, stage_n)); - - if best > 0 { - left.colored_label(GREEN, best.to_string()); - } - }, - |right| { - if *split != 0 || self.current_split == Some(i) { - let split_color = if self.current_split == Some(i) { - Color32::WHITE - } else { - DARK_ORANGE - }; - - right.colored_label(split_color, split.to_string()); - - if self.current_split != Some(i) { - // past split, we should show a diff - let diff = *split - pb; - let diff_color = if *split > stored_best { - LIGHT_ORANGE - } else if diff >= 0 { - Color32::WHITE - } else { - DARK_GREEN - }; - - if diff > 0 { - right.colored_label(diff_color, format!("+{}", diff)); - } else { - right.colored_label(diff_color, diff.to_string()); - } - } - } else { - right.colored_label(DARK_GREEN, "--"); - } - }, - ); - } + // Reset if we returned to 1-1 + if frame.total_score() == 0 && last_frame.total_score() > 0 || last_frame.is_menu() { + self.reset(); + self.start_delay = Some(1); + } - ui.label(format!("Personal Best: {}", cur_category.personal_best.score)); - ui.label(format!( - "Sum of Best: {}", - cur_category.best_splits.into_iter().sum::() - )) - }); - }); - - if self.waiting_for_category { - if let Ok(new_category) = self.dialog_rx.try_recv() { - if !new_category.is_empty() { - self.categories.push(Category::new(new_category)); - self.current_category = self.categories.len() - 1; - self.save_splits(); - } - self.waiting_for_category = false; + // Start run the frame after reset + if let Some(start_delay) = self.start_delay { + if start_delay >= 1 { + self.start_delay = Some(start_delay - 1) } else { - entry_dialog(ctx, self.dialog_tx.clone(), "Enter new category name"); + self.run.start(frame); + self.run + .set_split(match frame.stage { + 1 => 0, + 2 => 5, + 3 => 12, + 4 => 19, + _ => panic!("Stage out of bounds! {}", frame.stage), + }) + .unwrap(); + self.categories.refresh_caches(&self.db).unwrap(); + self.start_delay = None; + return; } } - if self.waiting_for_rename { - if let Ok(new_name) = self.dialog_rx.try_recv() { - if !new_name.is_empty() { - self.categories[self.current_category].name = new_name; - self.save_splits(); + // Run in progress + if !frame.is_menu() && !(self.run == Run::Inactive) { + // Operate within the 20-frame inconsistent window between splits + // ~Frame 18: time bonus score applied + if let Some(split_delay) = self.split_delay { + self.split_delay = Some(split_delay + 1); + // wait after the timer reset to get time bonus + if split_delay == 20 { + self.run.split().unwrap(); + } else if split_delay == 60 { + self.run.store_mult(frame).unwrap(); + self.split_delay = None } - self.waiting_for_rename = false; } else { - entry_dialog(ctx, self.dialog_tx.clone(), "Enter new name for category"); + self.run.store_time(last_frame).unwrap(); } - } - if self.waiting_for_confirm { - if let Ok(confirmation) = self.dialog_rx.try_recv() { - if confirmation == "Deleted" { - self.categories.remove(self.current_category); - self.current_category = self.current_category.saturating_sub(1); - } - self.waiting_for_confirm = false; - } else { - confirm_dialog( - ctx, - self.dialog_tx.clone(), - format!( - "Are you sure you want to delete category {}?", - self.categories[self.current_category].name - ), - ); + // Split if necessary; score requirement prevents spurious splits after a reset + if frame.timer_wave == 0 && self.last_frame.timer_wave != 0 && frame.total_score() > 0 { + self.split_delay = Some(0); } + + // Update run and split scores + self.run.update(frame).unwrap(); + } else if frame.is_menu() { + // End the run if we're back on the menu + // TODO make certain this is unreachable? + self.end_run(); } } - fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) { + fn reset(&mut self) { self.save_splits(); + self.run.reset(); } -} -fn entry_dialog(ctx: &Context, tx: Sender, msg: &'static str) { - let vp_builder = ViewportBuilder::default() - .with_title("ZeroSplitter") - .with_active(true) - .with_resizable(false) - .with_minimize_button(false) - .with_maximize_button(false) - .with_inner_size([200., 100.]); - - ctx.show_viewport_deferred(ViewportId::from_hash_of("entry dialog"), vp_builder, move |ctx, _| { - if ctx.input(|input| input.viewport().close_requested()) { - let _ = tx.send("".to_string()); - request_repaint(); - return; - } - - let text_id = Id::new("edit text"); - let mut edit_str = ctx.data_mut(|data| data.get_temp_mut_or_insert_with(text_id, || String::new()).clone()); + fn end_run(&mut self) { + self.save_splits(); + self.run.end(); + } +} - CentralPanel::default().show(ctx, |ui| { - ui.vertical_centered_justified(|ui| { - ui.label(msg); - if ui.text_edit_singleline(&mut edit_str).lost_focus() && ui.input(|i| i.key_pressed(Key::Enter)) { - let _ = tx.send(edit_str.clone()); - request_repaint(); - } - }); - }); +#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)] +pub enum Gamemode { + GreenOrange, + WhiteVanilla, + BlackOnion, +} - ctx.data_mut(|data| { - data.insert_temp(text_id, edit_str); - }); - }); +impl Gamemode { + fn splits(&self) -> usize { + match self { + Gamemode::GreenOrange => 8, + Gamemode::WhiteVanilla => 26, + Gamemode::BlackOnion => todo!(), + } + } } -fn confirm_dialog(ctx: &Context, tx: Sender, msg: String) { - let vp_builder = ViewportBuilder::default() - .with_title("ZeroSplitter") - .with_active(true) - .with_resizable(false) - .with_minimize_button(false) - .with_maximize_button(false) - .with_inner_size([200., 100.]); - - ctx.show_viewport_deferred(ViewportId::from_hash_of("confirm dialog"), vp_builder, move |ctx, _| { - if ctx.input(|input| input.viewport().close_requested()) { - let _ = tx.send("".to_string()); - request_repaint(); - return; +impl From for Gamemode { + fn from(value: i8) -> Self { + match value { + -1 => Self::WhiteVanilla, + 0 => Self::GreenOrange, + 1 => panic!("illegal black onion detected"), + _ => panic!(), } + } +} +pub struct EntryDialogData { + pub textbox: String, + pub mode: Gamemode, +} - CentralPanel::default().show(ctx, |ui| { - ui.vertical_centered_justified(|ui| { - ui.label(msg.clone()); - ui.columns_const(|[left, right]| { - if left.button("Delete").clicked() { - let _ = tx.send("Deleted".to_string()); - request_repaint(); - } else if right.button("Cancel").clicked() { - let _ = tx.send("".to_string()); - request_repaint(); - } - }); - }); - }); - }); +fn vanilla_split_names(split: usize) -> &'static str { + [ + "1-1", "1-2", "1-3", "1-4", "Bonus 1", "2-1", "2-2", "2-3", "2-4", "2-5", "2-6", "Bonus 2", "3-1", "3-2", + "3-3", "3-4", "3-5", "3-6", "Bonus 3", "4-1", "4-2", "4-3", "4-4", "4-5", "4-6", "Stage EX", + ][split] } -fn request_repaint() { - if let Some(ctx) = EGUI_CTX.get() { - ctx.request_repaint_after(Duration::from_millis(100)); - } +fn vanilla_descriptive_split_names(split: usize) -> &'static str { + [ + "Stage 1 Start", //0 + "Cloudoos", + "Arc Adder", + "Catastrophy", + "Bonus 1", + "Stage 2 Start", //5 + "Box Blockade", + "Snake", + "Artypo", + "Skull Taxis", + "2nd Apocalypse", + "Bonus 2", + "Stage 3 Start", //12 + "Crab Landing", + "Plane", + "Crab", + "Tank", + "Grapefruit", + "Bonus 3", + "Stage 4 Start", //19 + "Left Tunnel", + "Maze", + "Trains", + "Knight Ships", + "Orb Spewer", + "Stage EX", + ][split] } #[derive(Debug, Default, Serialize, Deserialize, Clone, Copy)] -struct Run { +struct OldRun { splits: [i32; 8], score: i32, } -#[derive(Debug, Serialize, Deserialize, Clone)] -struct Category { - personal_best: Run, - best_splits: [i32; 8], - name: String, +// #[derive(Debug, Serialize, Deserialize, Clone)] +// struct Run { +// splits: Vec, +// score: i32, +// mode: Gamemode, +// active: bool +// } + +// impl Run { +// fn new(mode: Gamemode) -> Self { +// Run { +// splits: vec![0; mode.splits()], +// score: 0, +// mode, +// active: false, +// } +// } + +// fn start(&mut self, category: &CategoryManager) { +// if category.current().mode == self.mode { +// self.splits = vec![0; self.mode.splits()]; +// self.score = 0; +// self.active = true +// } +// } + +// fn stop(&mut self) { +// self.active = false +// } +// } + +struct CategoryManager { + categories: Vec, + current: usize, + comparison_cache: Vec, + golds_cache: Vec, } -impl Category { - fn new(name: String) -> Self { - Category { - personal_best: Default::default(), - best_splits: Default::default(), - name, +impl CategoryManager { + fn init() -> Self { + CategoryManager { + categories: Vec::new(), + current: 0, + comparison_cache: Vec::new(), + golds_cache: Vec::new(), } } - fn update_from_run(&mut self, run: &Run) { - if run.score > self.personal_best.score { - self.personal_best = *run; + fn current(&self) -> &Category { + &self.categories.get(self.current).unwrap() + } + + fn current_mut(&mut self) -> &mut Category { + &mut self.categories[self.current] + } + + pub fn push(&mut self, name: String, mode: Gamemode, db: &Database) -> Result<(), ZeroError> { + let id = db.insert_new_category(name.clone(), mode)?; + self.categories.push(Category { name, mode, id }); + Ok(()) + } + + pub fn index(&self, index: usize) -> Option<&Category> { + self.categories.get(index) + } + + pub fn len(&self) -> usize { + self.categories.len() + } + + /// Populate the CategoryManager with data from the database + pub fn load(&mut self, db: &Database) -> Result<(), ZeroError> { + self.categories = db.get_categories()?; + Ok(()) + } + + pub fn delete_current(&mut self, db: &Database) -> Result { + if self.categories.len() > 1 { + db.delete_category(self.categories.remove(self.current)) + .map_err(ZeroError::DatabaseError) + } else { + Err(ZeroError::Illegal) } + } - for (best, new) in self.best_splits.iter_mut().zip(run.splits.iter()) { - if *new > *best { - *best = *new; - } + pub fn rename_current(&mut self, db: &Database, new_name: String) -> Result { + self.current_mut().name = new_name.clone(); + db.rename_category(self.current(), new_name) + .map_err(ZeroError::DatabaseError) + } + + /// Sets the current selected category by index. + /// Returns true if the category changed + pub fn set_current(&mut self, new_idx: usize, db: &Database) -> Result { + if new_idx == self.current { + return Ok(false); + } else if new_idx >= self.categories.len() { + return Err(ZeroError::CategoryOutOfRange); } + self.current = new_idx; + self.refresh_comparison(db)?; + self.refresh_golds(db)?; + + Ok(true) + } + + pub fn get_comparison(&self) -> &Vec { + if self.comparison_cache.len() == 0 { + panic!() + } + &self.comparison_cache + } + + pub fn get_golds(&self) -> &Vec { + if self.golds_cache.len() == 0 { + panic!() + } + &self.golds_cache + } + + pub fn refresh_caches(&mut self, db: &Database) -> Result<(), ZeroError> { + self.refresh_comparison(db)?; + self.refresh_golds(db) + } + + fn refresh_comparison(&mut self, db: &Database) -> Result<(), ZeroError> { + self.comparison_cache = match db.get_pb_run(self) { + Ok((scores, _, mode)) if mode == self.current().mode => scores, + Ok(_) => return Err(ZeroError::DifficultyMismatch), + Err(rusqlite::Error::QueryReturnedNoRows) => vec![0; self.current().mode.splits()], + Err(e) => return Err(ZeroError::DatabaseError(e)), + }; + Ok(()) + } + + fn refresh_golds(&mut self, db: &Database) -> Result<(), ZeroError> { + self.golds_cache = match db.get_gold_splits(self) { + Ok(scores) => scores, + Err(rusqlite::Error::QueryReturnedNoRows) => vec![0; self.current().mode.splits()], + Err(e) => return Err(ZeroError::DatabaseError(e)), + }; + Ok(()) + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct Category { + name: String, + mode: Gamemode, + id: i64, +} + +#[derive(Debug)] +#[non_exhaustive] +#[allow(dead_code)] +enum ZeroError { + Illegal, + DatabaseError(rusqlite::Error), + RunInactive, + DifficultyMismatch, + SplitOutOfRange, + CategoryOutOfRange, + IOError(std::io::Error), + TOMLError(toml::de::Error), + StaticAlreadyInit, + ReqwestError(reqwest::Error), + ParseError, + ConfigError(String), +} + +impl From for ZeroError { + fn from(value: reqwest::Error) -> Self { + ZeroError::ReqwestError(value) + } +} + +impl From for ZeroError { + fn from(value: rusqlite::Error) -> Self { + ZeroError::DatabaseError(value) + } +} + +impl From for ZeroError { + fn from(value: std::io::Error) -> Self { + ZeroError::IOError(value) + } +} + +impl From for ZeroError { + fn from(value: toml::de::Error) -> Self { + ZeroError::TOMLError(value) } } diff --git a/splitter/src/run.rs b/splitter/src/run.rs new file mode 100644 index 0000000..978ec9f --- /dev/null +++ b/splitter/src/run.rs @@ -0,0 +1,284 @@ +use common::FrameData; + +use crate::{Gamemode, ZeroError}; + +#[derive(Debug, PartialEq)] +pub enum Run { + Inactive, + Active { + difficulty: Gamemode, + splits: Vec, + score: i32, + current_split: usize, + split_base_score: i32, + }, + Residual { + difficulty: Gamemode, + splits: Vec, + score: i32, + }, +} + +impl Run { + fn current_data_mut(&mut self) -> &mut SplitData { + if let Run::Active { + current_split, splits, .. + } = self + { + &mut splits[*current_split] + } else { + panic!() + } + } + + pub fn score(&self) -> Option { + match *self { + Run::Inactive => None, + Run::Active { score, .. } => Some(score), + Run::Residual { score, .. } => Some(score), + } + } + + pub fn scores(&self) -> Result, ZeroError> { + match self { + Run::Inactive => Err(ZeroError::RunInactive), + Run::Active { splits, .. } => Ok(splits.iter().map(|x| x.score).collect()), + Run::Residual { splits, .. } => Ok(splits.iter().map(|x| x.score).collect()), + } + } + + pub fn splits(&self) -> Result, ZeroError> { + match self { + Run::Inactive => Err(ZeroError::RunInactive), + Run::Active { splits, .. } => Ok(splits.iter().map(|&s| s).collect()), + Run::Residual { splits, .. } => Ok(splits.iter().map(|&s| s).collect()), + } + } + + /// Start a new run with the difficulty of the frame + pub fn start(&mut self, frame: FrameData) { + let mode = frame.difficulty.into(); + *self = Self::Active { + difficulty: mode, + splits: vec![Default::default(); mode.splits()], + score: 0, + current_split: 0, + split_base_score: 0, + }; + } + + /// End the run; turning an active run into a residual + pub fn end(&mut self) { + *self = match self { + Run::Inactive => Run::Inactive, + Run::Active { + difficulty, + splits, + score, + .. + } => Run::Residual { + difficulty: *difficulty, + splits: splits.clone(), + score: *score, + }, + Run::Residual { .. } => Run::Inactive, + } + } + + /// Abruptly cancel the run with no closing behavior. This destroys the data from the run. + /// Use Zerosplitter::end_run() to write data to the database + pub fn deactivate(&mut self) { + *self = Self::Inactive + } + + /// Reset the data of the run while keeping its inactive/active status. + /// Deactivates a residual run + pub fn reset(&mut self) { + *self = match *self { + Run::Inactive => Run::Inactive, + Run::Active { difficulty, .. } => Run::Active { + difficulty: difficulty, + splits: vec![Default::default(); difficulty.splits()], + score: 0, + current_split: 0, + split_base_score: 0, + }, + Run::Residual { .. } => Run::Inactive, + } + } + + /// Integrate the data from the frame into the Run data. + /// Call this one at the end of the split + /// Stores score, mult, and rank + pub fn update(&mut self, frame: FrameData) -> Result<(), ZeroError> { + if let Self::Active { + difficulty, + splits, + score, + current_split, + split_base_score, + } = self + { + if *difficulty == Gamemode::from(frame.difficulty) { + *score = frame.total_score(); + if *split_base_score > *score { + *split_base_score = 0 + } + let current_data = &mut splits[*current_split]; + current_data.score = frame.total_score() - *split_base_score; + current_data.pattern_rank = frame.pattern_rank; + current_data.dynamic_rank = frame.dynamic_rank; + + Ok(()) + } else { + Err(ZeroError::DifficultyMismatch) + } + } else { + Err(ZeroError::RunInactive) + } + } + + pub fn store_time(&mut self, frame: FrameData) -> Result<(), ZeroError> { + if let Self::Active { + splits, current_split, .. + } = self + { + let current_data = &mut splits[*current_split]; + + current_data.time_frames = frame.timer_wave * 60 + frame.timer_wave_frames as u32; + current_data.coldframes = current_data.time_frames - frame.timer_wave_hotframes; + let factr = 1_f32.max(1_f32 + ((frame.timer_wave_hotframes as f32 / 60_f32) - 1_f32)); + current_data.time_bonus = (0.5_f32 + (frame.timer_wave_bonus as f32 / factr) as f32).floor() as u32; + + Ok(()) + } else { + Err(ZeroError::RunInactive) + } + } + + pub fn store_mult(&mut self, frame: FrameData) -> Result<(), ZeroError> { + if let Self::Active { + splits, current_split, .. + } = self + { + let current_data = &mut splits[*current_split]; + + current_data.mult = frame.multiplier_one; + + Ok(()) + } else { + Err(ZeroError::RunInactive) + } + } + + pub fn split(&mut self) -> Result<(), ZeroError> { + if let Self::Active { + current_split, + difficulty, + score, + split_base_score, + .. + } = self + { + if *current_split < difficulty.splits() { + *current_split += 1; + *split_base_score = *score; + Ok(()) + } else { + Err(ZeroError::SplitOutOfRange) + } + } else { + Err(ZeroError::RunInactive) + } + } + + pub fn set_split(&mut self, new_split: usize) -> Result<(), ZeroError> { + if let Self::Active { + current_split, + difficulty, + .. + } = self + { + if new_split < difficulty.splits() { + *current_split = new_split; + Ok(()) + } else { + Err(ZeroError::SplitOutOfRange) + } + } else { + Err(ZeroError::RunInactive) + } + } + pub fn current_split(&self) -> Result { + match self { + Run::Inactive => Err(ZeroError::RunInactive), + Run::Active { current_split, .. } => Ok(*current_split), + Run::Residual { difficulty, .. } => Ok(difficulty.splits() + 1), + } + } + + pub fn is_active(&self) -> bool { + match self { + Run::Inactive => false, + Run::Active { .. } => true, + Run::Residual { .. } => false, + } + } + + pub fn bump_mult_drops(&mut self) { + if let Run::Active { .. } = self { + self.current_data_mut().mult_drops += 1 + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct SplitData { + pub score: i32, + pub mult: u32, + pub pattern_rank: f32, + pub dynamic_rank: f32, + pub time_frames: u32, + pub time_bonus: u32, + pub coldframes: u32, + pub mult_drops: u32, +} + +impl SplitData { + fn new( + score: i32, + mult: u32, + pattern_rank: f32, + dynamic_rank: f32, + time_frames: u32, + time_bonus: u32, + cool_frames: u32, + mult_drops: u32, + ) -> Self { + Self { + score, + mult, + pattern_rank, + dynamic_rank, + time_frames, + time_bonus, + coldframes: cool_frames, + mult_drops, + } + } +} + +impl Default for SplitData { + fn default() -> Self { + Self { + score: Default::default(), + mult: Default::default(), + pattern_rank: Default::default(), + dynamic_rank: Default::default(), + time_frames: Default::default(), + time_bonus: Default::default(), + coldframes: Default::default(), + mult_drops: Default::default(), + } + } +} diff --git a/splitter/src/system.rs b/splitter/src/system.rs index d1f3b91..92fb1b6 100644 --- a/splitter/src/system.rs +++ b/splitter/src/system.rs @@ -49,7 +49,7 @@ impl ProcessHandle { pub unsafe fn from_raw(raw: HANDLE) -> Self { ProcessHandle { raw } } - + #[allow(dead_code)] pub fn as_raw(&self) -> HANDLE { self.raw } @@ -62,7 +62,7 @@ impl ProcessHandle { }; OsString::from_wide(&buffer[0..size as usize]).into() } - + #[allow(dead_code)] pub unsafe fn read_memory(&self, base_addr: *const c_void, buffer: &mut [u8]) -> Result<(), Error> { unsafe { ReadProcessMemory(self.raw, base_addr, buffer.as_mut_ptr().cast(), buffer.len(), None) } } @@ -101,7 +101,7 @@ impl ProcessHandle { }; res } - + #[allow(dead_code)] pub fn enumerate_modules(&self) -> Vec { let mut needed = 0; unsafe { @@ -121,7 +121,7 @@ impl ProcessHandle { modules } - + #[allow(dead_code)] pub fn get_module_file_name_ex(&self, module: HMODULE) -> OsString { let mut buffer = [0; 256]; let size = unsafe { GetModuleFileNameExW(Some(self.raw), Some(module), &mut buffer) }; diff --git a/splitter/src/theme.rs b/splitter/src/theme.rs new file mode 100644 index 0000000..453b346 --- /dev/null +++ b/splitter/src/theme.rs @@ -0,0 +1,102 @@ +use eframe::egui::{ + self, Color32, CornerRadius, Stroke, + style::{self, WidgetVisuals}, +}; + +#[allow(unused)] +pub const DARK_GREEN: Color32 = Color32::from_rgb(0, 0x4f, 0x4d); +#[allow(unused)] +pub const GREEN: Color32 = Color32::from_rgb(0, 0x94, 0x79); +#[allow(unused)] +pub const LIGHT_ORANGE: Color32 = Color32::from_rgb(0xff, 0xc0, 0x73); +#[allow(unused)] +pub const DARK_ORANGE: Color32 = Color32::from_rgb(0xff, 0x80, 0); +#[allow(unused)] +pub const DARKER_ORANGE: Color32 = Color32::from_rgb(0xdd, 0x59, 0x28); +#[allow(unused)] +pub const ORANGEST: Color32 = Color32::from_rgb(0xad, 0x2f, 0x17); +#[allow(unused)] +pub const DARKER_GREEN: Color32 = Color32::from_rgb(0x00, 0x32, 0x32); +#[allow(unused)] +pub const GREENEST: Color32 = Color32::from_rgb(0x00, 0x1d, 0x23); +#[allow(unused)] +pub const WHITE: Color32 = Color32::WHITE; +#[allow(unused)] +pub const BLACK: Color32 = Color32::BLACK; + +pub fn zeroranger_visuals() -> egui::Visuals { + egui::Visuals { + window_fill: BLACK, + extreme_bg_color: GREENEST, + panel_fill: BLACK, + widgets: egui::style::Widgets { + inactive: egui::style::WidgetVisuals { + bg_fill: GREENEST, + weak_bg_fill: GREENEST, + bg_stroke: Stroke { ..Default::default() }, + corner_radius: CornerRadius::ZERO, + fg_stroke: Stroke { + width: 1.5, + color: DARK_ORANGE, + }, + expansion: 0.0, + }, + active: egui::style::WidgetVisuals { + bg_fill: GREENEST, + weak_bg_fill: GREENEST, + bg_stroke: Stroke { ..Default::default() }, + corner_radius: CornerRadius::ZERO, + fg_stroke: Stroke { + width: 1.0, + color: DARK_ORANGE, + }, + expansion: 0.0, + }, + hovered: WidgetVisuals { + bg_fill: LIGHT_ORANGE, + weak_bg_fill: LIGHT_ORANGE, + bg_stroke: Stroke { ..Default::default() }, + corner_radius: CornerRadius::ZERO, + fg_stroke: Stroke { + width: 1.0, + color: DARK_GREEN, + }, + expansion: 0.0, + }, + noninteractive: WidgetVisuals { + bg_fill: LIGHT_ORANGE, + weak_bg_fill: LIGHT_ORANGE, + bg_stroke: Stroke { + color: GREEN, + width: 1.0, + ..Default::default() + }, + corner_radius: CornerRadius::ZERO, + fg_stroke: Stroke { + width: 1.0, + color: DARKER_ORANGE, + }, + expansion: 0.0, + }, + open: WidgetVisuals { + bg_fill: LIGHT_ORANGE, + weak_bg_fill: LIGHT_ORANGE, + bg_stroke: Stroke { ..Default::default() }, + corner_radius: CornerRadius::ZERO, + fg_stroke: Stroke { + width: 1.0, + color: DARKER_ORANGE, + }, + expansion: 0.0, + }, + }, + selection: style::Selection { + bg_fill: DARK_ORANGE, + stroke: Stroke { + width: 1.0, + color: GREENEST, + }, + }, + ..Default::default() + } +} diff --git a/splitter/src/ui.rs b/splitter/src/ui.rs index 8b13789..c987078 100644 --- a/splitter/src/ui.rs +++ b/splitter/src/ui.rs @@ -1 +1,105 @@ +use std::{sync::mpsc::Sender, time::Duration}; +use eframe::egui::{CentralPanel, ComboBox, Context, Id, TopBottomPanel, ViewportBuilder, ViewportId}; + +use crate::{EGUI_CTX, EntryDialogData, Gamemode}; + +/// Category entry dialoge menu with a gamemode dropdown. +pub fn category_maker_dialog(ctx: &Context, tx: Sender>, msg: &'static str, mode_select: bool) { + let vp_builder = ViewportBuilder::default() + .with_title("ZeroSplitter") + .with_active(true) + .with_resizable(false) + .with_minimize_button(false) + .with_maximize_button(false) + .with_inner_size([200., 100.]); + + ctx.show_viewport_deferred(ViewportId::from_hash_of("entry dialog"), vp_builder, move |ctx, _| { + if ctx.input(|input| input.viewport().close_requested()) { + let _ = tx.send(None); + request_repaint(); + return; + } + + let text_id = Id::new("edit text"); + let mode_id = Id::new("gamemode"); + let mut edit_str = ctx.data_mut(|data| data.get_temp_mut_or_insert_with(text_id, String::new).clone()); + let mut mode = ctx.data_mut(|data| *data.get_temp_mut_or(mode_id, Gamemode::GreenOrange)); + + CentralPanel::default().show(ctx, |ui| { + ui.vertical_centered_justified(|ui| { + ui.label(msg); + ui.text_edit_singleline(&mut edit_str); + if ui.button("Confirm").clicked() { + let _ = tx.send(Some(EntryDialogData { + textbox: edit_str.clone(), + mode, + })); + request_repaint(); + ctx.send_viewport_cmd(eframe::egui::ViewportCommand::Close); + } + }); + }); + + if mode_select { + TopBottomPanel::bottom("mode_select").show(ctx, |ui| { + ui.vertical_centered_justified(|ui| { + ComboBox::from_label("Mode") + .selected_text(format!("{mode:?}")) + .show_ui(ui, |ui| { + ui.selectable_value(&mut mode, Gamemode::GreenOrange, "Green Orange"); + ui.selectable_value(&mut mode, Gamemode::WhiteVanilla, "White Vanilla"); + // ui.selectable_value(&mut mode, Gamemode::BlackOnion, "Black Onion"); + }); + }) + }); + } + + ctx.data_mut(|data| { + data.insert_temp(text_id, edit_str); + data.insert_temp(mode_id, mode); + }); + }); +} + +pub fn confirm_dialog(ctx: &Context, tx: Sender>, msg: String) { + let vp_builder = ViewportBuilder::default() + .with_title("ZeroSplitter") + .with_active(true) + .with_resizable(false) + .with_minimize_button(false) + .with_maximize_button(false) + .with_inner_size([200., 100.]); + + ctx.show_viewport_deferred(ViewportId::from_hash_of("confirm dialog"), vp_builder, move |ctx, _| { + if ctx.input(|input| input.viewport().close_requested()) { + let _ = tx.send(None); + request_repaint(); + return; + } + + CentralPanel::default().show(ctx, |ui| { + ui.vertical_centered_justified(|ui| { + ui.label(msg.clone()); + ui.columns_const(|[left, right]| { + if left.button("Delete").clicked() { + let _ = tx.send(Some(EntryDialogData { + textbox: "Deleted".to_string(), + mode: Gamemode::GreenOrange, + })); + request_repaint(); + } else if right.button("Cancel").clicked() { + let _ = tx.send(None); + request_repaint(); + } + }); + }); + }); + }); +} + +fn request_repaint() { + if let Some(ctx) = EGUI_CTX.get() { + ctx.request_repaint_after(Duration::from_millis(100)); + } +} diff --git a/splitter/src/update.rs b/splitter/src/update.rs new file mode 100644 index 0000000..5ff0690 --- /dev/null +++ b/splitter/src/update.rs @@ -0,0 +1,50 @@ +use reqwest::{Url, header::ACCEPT}; +use semver::Version; +use serde::Deserialize; + +use crate::{VERSION, ZeroError}; + +const LATEST_URL: &'static str = "https://api.github.com/repos/lily-and-doll/zerosplitter/releases/latest"; + +pub fn check_for_updates() -> Result, ZeroError> { + let response = reqwest::blocking::Client::builder() + .user_agent("ZeroSplitter") + .build()? + .get(LATEST_URL) + .header(ACCEPT, "application/vnd.github+json") + .send()?; + + let json = response.json::()?; + + if Version::parse(&json.tag_name).expect("Malformed tag on release!") + > VERSION.parse().expect("No package version found!") + { + let download_url = json + .assets + .zero + .browser_download_url + .parse::() + .map_err(|_| ZeroError::ParseError)?; + + Ok(Some(download_url)) + } else { + Ok(None) + } +} + +#[derive(Deserialize)] +struct LatestResponse { + tag_name: String, + assets: Assets, +} + +#[derive(Deserialize)] +struct Assets { + #[serde(rename = "0")] + zero: Asset, +} + +#[derive(Deserialize)] +struct Asset { + browser_download_url: String, +}