Live location tracking and playback for the game "manhunt"

Implement Game, start tests

bwc9876.dev a8c0ea2f 957af3fd

verified
+1432 -599
+295 -449
backend/Cargo.lock
··· 102 102 103 103 [[package]] 104 104 name = "async-io" 105 - version = "2.4.0" 105 + version = "2.4.1" 106 106 source = "registry+https://github.com/rust-lang/crates.io-index" 107 - checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" 107 + checksum = "1237c0ae75a0f3765f58910ff9cdd0a12eeb39ab2f4c7de23262f337f0aacbb3" 108 108 dependencies = [ 109 109 "async-lock", 110 110 "cfg-if", ··· 113 113 "futures-lite", 114 114 "parking", 115 115 "polling", 116 - "rustix 0.38.44", 116 + "rustix", 117 117 "slab", 118 118 "tracing", 119 119 "windows-sys 0.59.0", ··· 132 132 133 133 [[package]] 134 134 name = "async-process" 135 - version = "2.3.0" 135 + version = "2.3.1" 136 136 source = "registry+https://github.com/rust-lang/crates.io-index" 137 - checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" 137 + checksum = "cde3f4e40e6021d7acffc90095cbd6dc54cb593903d1de5832f435eb274b85dc" 138 138 dependencies = [ 139 139 "async-channel", 140 140 "async-io", ··· 145 145 "cfg-if", 146 146 "event-listener", 147 147 "futures-lite", 148 - "rustix 0.38.44", 148 + "rustix", 149 149 "tracing", 150 150 ] 151 151 ··· 162 162 163 163 [[package]] 164 164 name = "async-signal" 165 - version = "0.2.10" 165 + version = "0.2.11" 166 166 source = "registry+https://github.com/rust-lang/crates.io-index" 167 - checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" 167 + checksum = "d7605a4e50d4b06df3898d5a70bf5fde51ed9059b0434b73105193bc27acce0d" 168 168 dependencies = [ 169 169 "async-io", 170 170 "async-lock", ··· 172 172 "cfg-if", 173 173 "futures-core", 174 174 "futures-io", 175 - "rustix 0.38.44", 175 + "rustix", 176 176 "signal-hook-registry", 177 177 "slab", 178 178 "windows-sys 0.59.0", ··· 232 232 233 233 [[package]] 234 234 name = "backtrace" 235 - version = "0.3.74" 235 + version = "0.3.75" 236 236 source = "registry+https://github.com/rust-lang/crates.io-index" 237 - checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 237 + checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" 238 238 dependencies = [ 239 239 "addr2line", 240 240 "cfg-if", ··· 265 265 266 266 [[package]] 267 267 name = "bitflags" 268 - version = "2.9.0" 268 + version = "2.9.1" 269 269 source = "registry+https://github.com/rust-lang/crates.io-index" 270 - checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 270 + checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" 271 271 dependencies = [ 272 272 "serde", 273 273 ] ··· 366 366 source = "registry+https://github.com/rust-lang/crates.io-index" 367 367 checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" 368 368 dependencies = [ 369 - "bitflags 2.9.0", 369 + "bitflags 2.9.1", 370 370 "cairo-sys-rs", 371 371 "glib", 372 372 "libc", ··· 429 429 430 430 [[package]] 431 431 name = "cc" 432 - version = "1.2.21" 432 + version = "1.2.25" 433 433 source = "registry+https://github.com/rust-lang/crates.io-index" 434 - checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" 434 + checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" 435 435 dependencies = [ 436 436 "shlex", 437 437 ] ··· 483 483 dependencies = [ 484 484 "android-tzdata", 485 485 "iana-time-zone", 486 + "js-sys", 486 487 "num-traits", 487 488 "serde", 489 + "wasm-bindgen", 488 490 "windows-link", 489 491 ] 490 492 ··· 525 527 526 528 [[package]] 527 529 name = "core-foundation" 528 - version = "0.10.0" 530 + version = "0.10.1" 529 531 source = "registry+https://github.com/rust-lang/crates.io-index" 530 - checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" 532 + checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" 531 533 dependencies = [ 532 534 "core-foundation-sys", 533 535 "libc", ··· 545 547 source = "registry+https://github.com/rust-lang/crates.io-index" 546 548 checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" 547 549 dependencies = [ 548 - "bitflags 2.9.0", 550 + "bitflags 2.9.1", 549 551 "core-foundation", 550 552 "core-graphics-types", 551 553 "foreign-types", ··· 558 560 source = "registry+https://github.com/rust-lang/crates.io-index" 559 561 checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" 560 562 dependencies = [ 561 - "bitflags 2.9.0", 563 + "bitflags 2.9.1", 562 564 "core-foundation", 563 565 "libc", 564 566 ] ··· 744 746 source = "registry+https://github.com/rust-lang/crates.io-index" 745 747 checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" 746 748 dependencies = [ 747 - "bitflags 2.9.0", 749 + "bitflags 2.9.1", 748 750 "objc2 0.6.1", 749 751 ] 750 752 ··· 773 775 774 776 [[package]] 775 777 name = "dlopen2_derive" 776 - version = "0.4.0" 778 + version = "0.4.1" 777 779 source = "registry+https://github.com/rust-lang/crates.io-index" 778 - checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" 780 + checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" 779 781 dependencies = [ 780 782 "proc-macro2", 781 783 "quote", ··· 820 822 821 823 [[package]] 822 824 name = "embed-resource" 823 - version = "3.0.2" 825 + version = "3.0.3" 824 826 source = "registry+https://github.com/rust-lang/crates.io-index" 825 - checksum = "7fbc6e0d8e0c03a655b53ca813f0463d2c956bc4db8138dbc89f120b066551e3" 827 + checksum = "e8fe7d068ca6b3a5782ca5ec9afc244acd99dd441e4686a83b1c3973aba1d489" 826 828 dependencies = [ 827 829 "cc", 828 830 "memchr", ··· 883 885 884 886 [[package]] 885 887 name = "errno" 886 - version = "0.3.11" 888 + version = "0.3.12" 887 889 source = "registry+https://github.com/rust-lang/crates.io-index" 888 - checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" 890 + checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" 889 891 dependencies = [ 890 892 "libc", 891 893 "windows-sys 0.59.0", ··· 1226 1228 1227 1229 [[package]] 1228 1230 name = "getrandom" 1229 - version = "0.3.2" 1231 + version = "0.3.3" 1230 1232 source = "registry+https://github.com/rust-lang/crates.io-index" 1231 - checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" 1233 + checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 1232 1234 dependencies = [ 1233 1235 "cfg-if", 1234 1236 "libc", ··· 1280 1282 source = "registry+https://github.com/rust-lang/crates.io-index" 1281 1283 checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" 1282 1284 dependencies = [ 1283 - "bitflags 2.9.0", 1285 + "bitflags 2.9.1", 1284 1286 "futures-channel", 1285 1287 "futures-core", 1286 1288 "futures-executor", ··· 1416 1418 1417 1419 [[package]] 1418 1420 name = "hermit-abi" 1419 - version = "0.4.0" 1421 + version = "0.5.1" 1420 1422 source = "registry+https://github.com/rust-lang/crates.io-index" 1421 - checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" 1423 + checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" 1422 1424 1423 1425 [[package]] 1424 1426 name = "hex" ··· 1501 1503 1502 1504 [[package]] 1503 1505 name = "hyper-util" 1504 - version = "0.1.11" 1506 + version = "0.1.13" 1505 1507 source = "registry+https://github.com/rust-lang/crates.io-index" 1506 - checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" 1508 + checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" 1507 1509 dependencies = [ 1510 + "base64 0.22.1", 1508 1511 "bytes", 1509 1512 "futures-channel", 1513 + "futures-core", 1510 1514 "futures-util", 1511 1515 "http", 1512 1516 "http-body", 1513 1517 "hyper", 1518 + "ipnet", 1514 1519 "libc", 1520 + "percent-encoding", 1515 1521 "pin-project-lite", 1516 1522 "socket2", 1517 1523 "tokio", ··· 1531 1537 "js-sys", 1532 1538 "log", 1533 1539 "wasm-bindgen", 1534 - "windows-core 0.61.0", 1540 + "windows-core", 1535 1541 ] 1536 1542 1537 1543 [[package]] ··· 1555 1561 1556 1562 [[package]] 1557 1563 name = "icu_collections" 1558 - version = "1.5.0" 1564 + version = "2.0.0" 1559 1565 source = "registry+https://github.com/rust-lang/crates.io-index" 1560 - checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 1566 + checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" 1561 1567 dependencies = [ 1562 1568 "displaydoc", 1569 + "potential_utf", 1563 1570 "yoke", 1564 1571 "zerofrom", 1565 1572 "zerovec", 1566 1573 ] 1567 1574 1568 1575 [[package]] 1569 - name = "icu_locid" 1570 - version = "1.5.0" 1576 + name = "icu_locale_core" 1577 + version = "2.0.0" 1571 1578 source = "registry+https://github.com/rust-lang/crates.io-index" 1572 - checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 1579 + checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" 1573 1580 dependencies = [ 1574 1581 "displaydoc", 1575 1582 "litemap", ··· 1579 1586 ] 1580 1587 1581 1588 [[package]] 1582 - name = "icu_locid_transform" 1583 - version = "1.5.0" 1584 - source = "registry+https://github.com/rust-lang/crates.io-index" 1585 - checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 1586 - dependencies = [ 1587 - "displaydoc", 1588 - "icu_locid", 1589 - "icu_locid_transform_data", 1590 - "icu_provider", 1591 - "tinystr", 1592 - "zerovec", 1593 - ] 1594 - 1595 - [[package]] 1596 - name = "icu_locid_transform_data" 1597 - version = "1.5.1" 1598 - source = "registry+https://github.com/rust-lang/crates.io-index" 1599 - checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" 1600 - 1601 - [[package]] 1602 1589 name = "icu_normalizer" 1603 - version = "1.5.0" 1590 + version = "2.0.0" 1604 1591 source = "registry+https://github.com/rust-lang/crates.io-index" 1605 - checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 1592 + checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" 1606 1593 dependencies = [ 1607 1594 "displaydoc", 1608 1595 "icu_collections", ··· 1610 1597 "icu_properties", 1611 1598 "icu_provider", 1612 1599 "smallvec", 1613 - "utf16_iter", 1614 - "utf8_iter", 1615 - "write16", 1616 1600 "zerovec", 1617 1601 ] 1618 1602 1619 1603 [[package]] 1620 1604 name = "icu_normalizer_data" 1621 - version = "1.5.1" 1605 + version = "2.0.0" 1622 1606 source = "registry+https://github.com/rust-lang/crates.io-index" 1623 - checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" 1607 + checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" 1624 1608 1625 1609 [[package]] 1626 1610 name = "icu_properties" 1627 - version = "1.5.1" 1611 + version = "2.0.1" 1628 1612 source = "registry+https://github.com/rust-lang/crates.io-index" 1629 - checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 1613 + checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" 1630 1614 dependencies = [ 1631 1615 "displaydoc", 1632 1616 "icu_collections", 1633 - "icu_locid_transform", 1617 + "icu_locale_core", 1634 1618 "icu_properties_data", 1635 1619 "icu_provider", 1636 - "tinystr", 1620 + "potential_utf", 1621 + "zerotrie", 1637 1622 "zerovec", 1638 1623 ] 1639 1624 1640 1625 [[package]] 1641 1626 name = "icu_properties_data" 1642 - version = "1.5.1" 1627 + version = "2.0.1" 1643 1628 source = "registry+https://github.com/rust-lang/crates.io-index" 1644 - checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" 1629 + checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" 1645 1630 1646 1631 [[package]] 1647 1632 name = "icu_provider" 1648 - version = "1.5.0" 1633 + version = "2.0.0" 1649 1634 source = "registry+https://github.com/rust-lang/crates.io-index" 1650 - checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 1635 + checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" 1651 1636 dependencies = [ 1652 1637 "displaydoc", 1653 - "icu_locid", 1654 - "icu_provider_macros", 1638 + "icu_locale_core", 1655 1639 "stable_deref_trait", 1656 1640 "tinystr", 1657 1641 "writeable", 1658 1642 "yoke", 1659 1643 "zerofrom", 1644 + "zerotrie", 1660 1645 "zerovec", 1661 1646 ] 1662 1647 1663 1648 [[package]] 1664 - name = "icu_provider_macros" 1665 - version = "1.5.0" 1666 - source = "registry+https://github.com/rust-lang/crates.io-index" 1667 - checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 1668 - dependencies = [ 1669 - "proc-macro2", 1670 - "quote", 1671 - "syn 2.0.101", 1672 - ] 1673 - 1674 - [[package]] 1675 1649 name = "ident_case" 1676 1650 version = "1.0.1" 1677 1651 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1690 1664 1691 1665 [[package]] 1692 1666 name = "idna_adapter" 1693 - version = "1.2.0" 1667 + version = "1.2.1" 1694 1668 source = "registry+https://github.com/rust-lang/crates.io-index" 1695 - checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 1669 + checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 1696 1670 dependencies = [ 1697 1671 "icu_normalizer", 1698 1672 "icu_properties", ··· 1736 1710 checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 1737 1711 1738 1712 [[package]] 1713 + name = "iri-string" 1714 + version = "0.7.8" 1715 + source = "registry+https://github.com/rust-lang/crates.io-index" 1716 + checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" 1717 + dependencies = [ 1718 + "memchr", 1719 + "serde", 1720 + ] 1721 + 1722 + [[package]] 1739 1723 name = "is-docker" 1740 1724 version = "0.2.0" 1741 1725 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1849 1833 source = "registry+https://github.com/rust-lang/crates.io-index" 1850 1834 checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" 1851 1835 dependencies = [ 1852 - "bitflags 2.9.0", 1836 + "bitflags 2.9.1", 1853 1837 "serde", 1854 1838 "unicode-segmentation", 1855 1839 ] ··· 1919 1903 source = "registry+https://github.com/rust-lang/crates.io-index" 1920 1904 checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 1921 1905 dependencies = [ 1922 - "bitflags 2.9.0", 1906 + "bitflags 2.9.1", 1923 1907 "libc", 1924 1908 ] 1925 - 1926 - [[package]] 1927 - name = "linux-raw-sys" 1928 - version = "0.4.15" 1929 - source = "registry+https://github.com/rust-lang/crates.io-index" 1930 - checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 1931 1909 1932 1910 [[package]] 1933 1911 name = "linux-raw-sys" ··· 1937 1915 1938 1916 [[package]] 1939 1917 name = "litemap" 1940 - version = "0.7.5" 1918 + version = "0.8.0" 1941 1919 source = "registry+https://github.com/rust-lang/crates.io-index" 1942 - checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" 1920 + checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" 1943 1921 1944 1922 [[package]] 1945 1923 name = "lock_api" 1946 - version = "0.4.12" 1924 + version = "0.4.13" 1947 1925 source = "registry+https://github.com/rust-lang/crates.io-index" 1948 - checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 1926 + checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" 1949 1927 dependencies = [ 1950 1928 "autocfg", 1951 1929 "scopeguard", ··· 1967 1945 name = "manhunt-app" 1968 1946 version = "0.1.0" 1969 1947 dependencies = [ 1948 + "chrono", 1949 + "rand 0.9.1", 1970 1950 "serde", 1971 1951 "serde_json", 1972 1952 "tauri", 1973 1953 "tauri-build", 1954 + "tauri-plugin-geolocation", 1974 1955 "tauri-plugin-opener", 1956 + "tokio", 1975 1957 ] 1976 1958 1977 1959 [[package]] ··· 2027 2009 2028 2010 [[package]] 2029 2011 name = "mio" 2030 - version = "1.0.3" 2012 + version = "1.0.4" 2031 2013 source = "registry+https://github.com/rust-lang/crates.io-index" 2032 - checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 2014 + checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" 2033 2015 dependencies = [ 2034 2016 "libc", 2035 2017 "wasi 0.11.0+wasi-snapshot-preview1", 2036 - "windows-sys 0.52.0", 2018 + "windows-sys 0.59.0", 2037 2019 ] 2038 2020 2039 2021 [[package]] ··· 2063 2045 source = "registry+https://github.com/rust-lang/crates.io-index" 2064 2046 checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" 2065 2047 dependencies = [ 2066 - "bitflags 2.9.0", 2048 + "bitflags 2.9.1", 2067 2049 "jni-sys", 2068 2050 "log", 2069 2051 "ndk-sys", ··· 2095 2077 2096 2078 [[package]] 2097 2079 name = "nix" 2098 - version = "0.29.0" 2080 + version = "0.30.1" 2099 2081 source = "registry+https://github.com/rust-lang/crates.io-index" 2100 - checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" 2082 + checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" 2101 2083 dependencies = [ 2102 - "bitflags 2.9.0", 2084 + "bitflags 2.9.1", 2103 2085 "cfg-if", 2104 2086 "cfg_aliases", 2105 2087 "libc", ··· 2180 2162 source = "registry+https://github.com/rust-lang/crates.io-index" 2181 2163 checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" 2182 2164 dependencies = [ 2183 - "bitflags 2.9.0", 2165 + "bitflags 2.9.1", 2184 2166 "block2 0.6.1", 2185 2167 "libc", 2186 2168 "objc2 0.6.1", ··· 2199 2181 source = "registry+https://github.com/rust-lang/crates.io-index" 2200 2182 checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d" 2201 2183 dependencies = [ 2202 - "bitflags 2.9.0", 2184 + "bitflags 2.9.1", 2203 2185 "objc2 0.6.1", 2204 2186 "objc2-foundation 0.3.1", 2205 2187 ] ··· 2210 2192 source = "registry+https://github.com/rust-lang/crates.io-index" 2211 2193 checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d" 2212 2194 dependencies = [ 2213 - "bitflags 2.9.0", 2195 + "bitflags 2.9.1", 2214 2196 "objc2 0.6.1", 2215 2197 "objc2-foundation 0.3.1", 2216 2198 ] ··· 2221 2203 source = "registry+https://github.com/rust-lang/crates.io-index" 2222 2204 checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" 2223 2205 dependencies = [ 2224 - "bitflags 2.9.0", 2206 + "bitflags 2.9.1", 2225 2207 "dispatch2", 2226 2208 "objc2 0.6.1", 2227 2209 ] ··· 2232 2214 source = "registry+https://github.com/rust-lang/crates.io-index" 2233 2215 checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" 2234 2216 dependencies = [ 2235 - "bitflags 2.9.0", 2217 + "bitflags 2.9.1", 2236 2218 "dispatch2", 2237 2219 "objc2 0.6.1", 2238 2220 "objc2-core-foundation", ··· 2270 2252 source = "registry+https://github.com/rust-lang/crates.io-index" 2271 2253 checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" 2272 2254 dependencies = [ 2273 - "bitflags 2.9.0", 2255 + "bitflags 2.9.1", 2274 2256 "block2 0.5.1", 2275 2257 "libc", 2276 2258 "objc2 0.5.2", ··· 2282 2264 source = "registry+https://github.com/rust-lang/crates.io-index" 2283 2265 checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" 2284 2266 dependencies = [ 2285 - "bitflags 2.9.0", 2267 + "bitflags 2.9.1", 2286 2268 "block2 0.6.1", 2287 2269 "libc", 2288 2270 "objc2 0.6.1", ··· 2295 2277 source = "registry+https://github.com/rust-lang/crates.io-index" 2296 2278 checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" 2297 2279 dependencies = [ 2298 - "bitflags 2.9.0", 2280 + "bitflags 2.9.1", 2299 2281 "objc2 0.6.1", 2300 2282 "objc2-core-foundation", 2301 2283 ] ··· 2306 2288 source = "registry+https://github.com/rust-lang/crates.io-index" 2307 2289 checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" 2308 2290 dependencies = [ 2309 - "bitflags 2.9.0", 2291 + "bitflags 2.9.1", 2310 2292 "block2 0.5.1", 2311 2293 "objc2 0.5.2", 2312 2294 "objc2-foundation 0.2.2", ··· 2318 2300 source = "registry+https://github.com/rust-lang/crates.io-index" 2319 2301 checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" 2320 2302 dependencies = [ 2321 - "bitflags 2.9.0", 2303 + "bitflags 2.9.1", 2322 2304 "block2 0.5.1", 2323 2305 "objc2 0.5.2", 2324 2306 "objc2-foundation 0.2.2", ··· 2331 2313 source = "registry+https://github.com/rust-lang/crates.io-index" 2332 2314 checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" 2333 2315 dependencies = [ 2334 - "bitflags 2.9.0", 2316 + "bitflags 2.9.1", 2335 2317 "objc2 0.6.1", 2336 2318 "objc2-foundation 0.3.1", 2337 2319 ] ··· 2342 2324 source = "registry+https://github.com/rust-lang/crates.io-index" 2343 2325 checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" 2344 2326 dependencies = [ 2345 - "bitflags 2.9.0", 2327 + "bitflags 2.9.1", 2346 2328 "objc2 0.6.1", 2347 2329 "objc2-core-foundation", 2348 2330 "objc2-foundation 0.3.1", ··· 2354 2336 source = "registry+https://github.com/rust-lang/crates.io-index" 2355 2337 checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad" 2356 2338 dependencies = [ 2357 - "bitflags 2.9.0", 2339 + "bitflags 2.9.1", 2358 2340 "block2 0.6.1", 2359 2341 "objc2 0.6.1", 2360 2342 "objc2-app-kit", ··· 2438 2420 2439 2421 [[package]] 2440 2422 name = "parking_lot" 2441 - version = "0.12.3" 2423 + version = "0.12.4" 2442 2424 source = "registry+https://github.com/rust-lang/crates.io-index" 2443 - checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 2425 + checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" 2444 2426 dependencies = [ 2445 2427 "lock_api", 2446 2428 "parking_lot_core", ··· 2448 2430 2449 2431 [[package]] 2450 2432 name = "parking_lot_core" 2451 - version = "0.9.10" 2433 + version = "0.9.11" 2452 2434 source = "registry+https://github.com/rust-lang/crates.io-index" 2453 - checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 2435 + checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" 2454 2436 dependencies = [ 2455 2437 "cfg-if", 2456 2438 "libc", ··· 2662 2644 2663 2645 [[package]] 2664 2646 name = "polling" 2665 - version = "3.7.4" 2647 + version = "3.8.0" 2666 2648 source = "registry+https://github.com/rust-lang/crates.io-index" 2667 - checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" 2649 + checksum = "b53a684391ad002dd6a596ceb6c74fd004fdce75f4be2e3f615068abbea5fd50" 2668 2650 dependencies = [ 2669 2651 "cfg-if", 2670 2652 "concurrent-queue", 2671 2653 "hermit-abi", 2672 2654 "pin-project-lite", 2673 - "rustix 0.38.44", 2655 + "rustix", 2674 2656 "tracing", 2675 2657 "windows-sys 0.59.0", 2658 + ] 2659 + 2660 + [[package]] 2661 + name = "potential_utf" 2662 + version = "0.1.2" 2663 + source = "registry+https://github.com/rust-lang/crates.io-index" 2664 + checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" 2665 + dependencies = [ 2666 + "zerovec", 2676 2667 ] 2677 2668 2678 2669 [[package]] ··· 2813 2804 ] 2814 2805 2815 2806 [[package]] 2807 + name = "rand" 2808 + version = "0.9.1" 2809 + source = "registry+https://github.com/rust-lang/crates.io-index" 2810 + checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" 2811 + dependencies = [ 2812 + "rand_chacha 0.9.0", 2813 + "rand_core 0.9.3", 2814 + ] 2815 + 2816 + [[package]] 2816 2817 name = "rand_chacha" 2817 2818 version = "0.2.2" 2818 2819 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2833 2834 ] 2834 2835 2835 2836 [[package]] 2837 + name = "rand_chacha" 2838 + version = "0.9.0" 2839 + source = "registry+https://github.com/rust-lang/crates.io-index" 2840 + checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 2841 + dependencies = [ 2842 + "ppv-lite86", 2843 + "rand_core 0.9.3", 2844 + ] 2845 + 2846 + [[package]] 2836 2847 name = "rand_core" 2837 2848 version = "0.5.1" 2838 2849 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2848 2859 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 2849 2860 dependencies = [ 2850 2861 "getrandom 0.2.16", 2862 + ] 2863 + 2864 + [[package]] 2865 + name = "rand_core" 2866 + version = "0.9.3" 2867 + source = "registry+https://github.com/rust-lang/crates.io-index" 2868 + checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 2869 + dependencies = [ 2870 + "getrandom 0.3.3", 2851 2871 ] 2852 2872 2853 2873 [[package]] ··· 2880 2900 source = "registry+https://github.com/rust-lang/crates.io-index" 2881 2901 checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" 2882 2902 dependencies = [ 2883 - "bitflags 2.9.0", 2903 + "bitflags 2.9.1", 2884 2904 ] 2885 2905 2886 2906 [[package]] ··· 2925 2945 2926 2946 [[package]] 2927 2947 name = "reqwest" 2928 - version = "0.12.15" 2948 + version = "0.12.19" 2929 2949 source = "registry+https://github.com/rust-lang/crates.io-index" 2930 - checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" 2950 + checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119" 2931 2951 dependencies = [ 2932 2952 "base64 0.22.1", 2933 2953 "bytes", ··· 2952 2972 "tokio", 2953 2973 "tokio-util", 2954 2974 "tower", 2975 + "tower-http", 2955 2976 "tower-service", 2956 2977 "url", 2957 2978 "wasm-bindgen", 2958 2979 "wasm-bindgen-futures", 2959 2980 "wasm-streams", 2960 2981 "web-sys", 2961 - "windows-registry", 2962 2982 ] 2963 2983 2964 2984 [[package]] ··· 2978 2998 2979 2999 [[package]] 2980 3000 name = "rustix" 2981 - version = "0.38.44" 2982 - source = "registry+https://github.com/rust-lang/crates.io-index" 2983 - checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 2984 - dependencies = [ 2985 - "bitflags 2.9.0", 2986 - "errno", 2987 - "libc", 2988 - "linux-raw-sys 0.4.15", 2989 - "windows-sys 0.59.0", 2990 - ] 2991 - 2992 - [[package]] 2993 - name = "rustix" 2994 3001 version = "1.0.7" 2995 3002 source = "registry+https://github.com/rust-lang/crates.io-index" 2996 3003 checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" 2997 3004 dependencies = [ 2998 - "bitflags 2.9.0", 3005 + "bitflags 2.9.1", 2999 3006 "errno", 3000 3007 "libc", 3001 - "linux-raw-sys 0.9.4", 3008 + "linux-raw-sys", 3002 3009 "windows-sys 0.59.0", 3003 3010 ] 3004 3011 3005 3012 [[package]] 3006 3013 name = "rustversion" 3007 - version = "1.0.20" 3014 + version = "1.0.21" 3008 3015 source = "registry+https://github.com/rust-lang/crates.io-index" 3009 - checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" 3016 + checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" 3010 3017 3011 3018 [[package]] 3012 3019 name = "ryu" ··· 3294 3301 3295 3302 [[package]] 3296 3303 name = "socket2" 3297 - version = "0.5.9" 3304 + version = "0.5.10" 3298 3305 source = "registry+https://github.com/rust-lang/crates.io-index" 3299 - checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" 3306 + checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" 3300 3307 dependencies = [ 3301 3308 "libc", 3302 3309 "windows-sys 0.52.0", ··· 3465 3472 source = "registry+https://github.com/rust-lang/crates.io-index" 3466 3473 checksum = "1e59c1f38e657351a2e822eadf40d6a2ad4627b9c25557bc1180ec1b3295ef82" 3467 3474 dependencies = [ 3468 - "bitflags 2.9.0", 3475 + "bitflags 2.9.1", 3469 3476 "core-foundation", 3470 3477 "core-graphics", 3471 3478 "crossbeam-channel", ··· 3492 3499 "tao-macros", 3493 3500 "unicode-segmentation", 3494 3501 "url", 3495 - "windows 0.61.1", 3496 - "windows-core 0.61.0", 3502 + "windows", 3503 + "windows-core", 3497 3504 "windows-version", 3498 3505 "x11-dl", 3499 3506 ] ··· 3563 3570 "webkit2gtk", 3564 3571 "webview2-com", 3565 3572 "window-vibrancy", 3566 - "windows 0.61.1", 3573 + "windows", 3567 3574 ] 3568 3575 3569 3576 [[package]] ··· 3647 3654 ] 3648 3655 3649 3656 [[package]] 3657 + name = "tauri-plugin-geolocation" 3658 + version = "2.2.4" 3659 + source = "registry+https://github.com/rust-lang/crates.io-index" 3660 + checksum = "f70978d3dbca4d900f8708dad1e0cff32c52de578101998d0f30dc7e12104e85" 3661 + dependencies = [ 3662 + "log", 3663 + "serde", 3664 + "serde_json", 3665 + "tauri", 3666 + "tauri-plugin", 3667 + "thiserror 2.0.12", 3668 + ] 3669 + 3670 + [[package]] 3650 3671 name = "tauri-plugin-opener" 3651 - version = "2.2.6" 3672 + version = "2.2.7" 3652 3673 source = "registry+https://github.com/rust-lang/crates.io-index" 3653 - checksum = "2fdc6cb608e04b7d2b6d1f21e9444ad49245f6d03465ba53323d692d1ceb1a30" 3674 + checksum = "66644b71a31ec1a8a52c4a16575edd28cf763c87cf4a7da24c884122b5c77097" 3654 3675 dependencies = [ 3655 3676 "dunce", 3656 3677 "glob", ··· 3664 3685 "tauri-plugin", 3665 3686 "thiserror 2.0.12", 3666 3687 "url", 3667 - "windows 0.60.0", 3688 + "windows", 3668 3689 "zbus", 3669 3690 ] 3670 3691 ··· 3687 3708 "tauri-utils", 3688 3709 "thiserror 2.0.12", 3689 3710 "url", 3690 - "windows 0.61.1", 3711 + "windows", 3691 3712 ] 3692 3713 3693 3714 [[package]] ··· 3713 3734 "url", 3714 3735 "webkit2gtk", 3715 3736 "webview2-com", 3716 - "windows 0.61.1", 3737 + "windows", 3717 3738 "wry", 3718 3739 ] 3719 3740 ··· 3768 3789 3769 3790 [[package]] 3770 3791 name = "tempfile" 3771 - version = "3.19.1" 3792 + version = "3.20.0" 3772 3793 source = "registry+https://github.com/rust-lang/crates.io-index" 3773 - checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" 3794 + checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" 3774 3795 dependencies = [ 3775 3796 "fastrand", 3776 - "getrandom 0.3.2", 3797 + "getrandom 0.3.3", 3777 3798 "once_cell", 3778 - "rustix 1.0.7", 3799 + "rustix", 3779 3800 "windows-sys 0.59.0", 3780 3801 ] 3781 3802 ··· 3869 3890 3870 3891 [[package]] 3871 3892 name = "tinystr" 3872 - version = "0.7.6" 3893 + version = "0.8.1" 3873 3894 source = "registry+https://github.com/rust-lang/crates.io-index" 3874 - checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 3895 + checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" 3875 3896 dependencies = [ 3876 3897 "displaydoc", 3877 3898 "zerovec", ··· 3879 3900 3880 3901 [[package]] 3881 3902 name = "tokio" 3882 - version = "1.45.0" 3903 + version = "1.45.1" 3883 3904 source = "registry+https://github.com/rust-lang/crates.io-index" 3884 - checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" 3905 + checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" 3885 3906 dependencies = [ 3886 3907 "backtrace", 3887 3908 "bytes", ··· 3889 3910 "mio", 3890 3911 "pin-project-lite", 3891 3912 "socket2", 3913 + "tokio-macros", 3892 3914 "windows-sys 0.52.0", 3893 3915 ] 3894 3916 3895 3917 [[package]] 3918 + name = "tokio-macros" 3919 + version = "2.5.0" 3920 + source = "registry+https://github.com/rust-lang/crates.io-index" 3921 + checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 3922 + dependencies = [ 3923 + "proc-macro2", 3924 + "quote", 3925 + "syn 2.0.101", 3926 + ] 3927 + 3928 + [[package]] 3896 3929 name = "tokio-util" 3897 3930 version = "0.7.15" 3898 3931 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3959 3992 "serde_spanned", 3960 3993 "toml_datetime", 3961 3994 "toml_write", 3962 - "winnow 0.7.9", 3995 + "winnow 0.7.10", 3963 3996 ] 3964 3997 3965 3998 [[package]] ··· 3979 4012 "pin-project-lite", 3980 4013 "sync_wrapper", 3981 4014 "tokio", 4015 + "tower-layer", 4016 + "tower-service", 4017 + ] 4018 + 4019 + [[package]] 4020 + name = "tower-http" 4021 + version = "0.6.5" 4022 + source = "registry+https://github.com/rust-lang/crates.io-index" 4023 + checksum = "5cc2d9e086a412a451384326f521c8123a99a466b329941a9403696bff9b0da2" 4024 + dependencies = [ 4025 + "bitflags 2.9.1", 4026 + "bytes", 4027 + "futures-util", 4028 + "http", 4029 + "http-body", 4030 + "iri-string", 4031 + "pin-project-lite", 4032 + "tower", 3982 4033 "tower-layer", 3983 4034 "tower-service", 3984 4035 ] ··· 4161 4212 checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 4162 4213 4163 4214 [[package]] 4164 - name = "utf16_iter" 4165 - version = "1.0.5" 4166 - source = "registry+https://github.com/rust-lang/crates.io-index" 4167 - checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 4168 - 4169 - [[package]] 4170 4215 name = "utf8_iter" 4171 4216 version = "1.0.4" 4172 4217 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4174 4219 4175 4220 [[package]] 4176 4221 name = "uuid" 4177 - version = "1.16.0" 4222 + version = "1.17.0" 4178 4223 source = "registry+https://github.com/rust-lang/crates.io-index" 4179 - checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" 4224 + checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" 4180 4225 dependencies = [ 4181 - "getrandom 0.3.2", 4226 + "getrandom 0.3.3", 4227 + "js-sys", 4182 4228 "serde", 4229 + "wasm-bindgen", 4183 4230 ] 4184 4231 4185 4232 [[package]] ··· 4400 4447 dependencies = [ 4401 4448 "webview2-com-macros", 4402 4449 "webview2-com-sys", 4403 - "windows 0.61.1", 4404 - "windows-core 0.61.0", 4405 - "windows-implement 0.60.0", 4450 + "windows", 4451 + "windows-core", 4452 + "windows-implement", 4406 4453 "windows-interface", 4407 4454 ] 4408 4455 ··· 4424 4471 checksum = "8ae2d11c4a686e4409659d7891791254cf9286d3cfe0eef54df1523533d22295" 4425 4472 dependencies = [ 4426 4473 "thiserror 2.0.12", 4427 - "windows 0.61.1", 4428 - "windows-core 0.61.0", 4474 + "windows", 4475 + "windows-core", 4429 4476 ] 4430 4477 4431 4478 [[package]] ··· 4476 4523 4477 4524 [[package]] 4478 4525 name = "windows" 4479 - version = "0.60.0" 4480 - source = "registry+https://github.com/rust-lang/crates.io-index" 4481 - checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529" 4482 - dependencies = [ 4483 - "windows-collections 0.1.1", 4484 - "windows-core 0.60.1", 4485 - "windows-future 0.1.1", 4486 - "windows-link", 4487 - "windows-numerics 0.1.1", 4488 - ] 4489 - 4490 - [[package]] 4491 - name = "windows" 4492 4526 version = "0.61.1" 4493 4527 source = "registry+https://github.com/rust-lang/crates.io-index" 4494 4528 checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" 4495 4529 dependencies = [ 4496 - "windows-collections 0.2.0", 4497 - "windows-core 0.61.0", 4498 - "windows-future 0.2.0", 4530 + "windows-collections", 4531 + "windows-core", 4532 + "windows-future", 4499 4533 "windows-link", 4500 - "windows-numerics 0.2.0", 4501 - ] 4502 - 4503 - [[package]] 4504 - name = "windows-collections" 4505 - version = "0.1.1" 4506 - source = "registry+https://github.com/rust-lang/crates.io-index" 4507 - checksum = "5467f79cc1ba3f52ebb2ed41dbb459b8e7db636cc3429458d9a852e15bc24dec" 4508 - dependencies = [ 4509 - "windows-core 0.60.1", 4534 + "windows-numerics", 4510 4535 ] 4511 4536 4512 4537 [[package]] ··· 4515 4540 source = "registry+https://github.com/rust-lang/crates.io-index" 4516 4541 checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" 4517 4542 dependencies = [ 4518 - "windows-core 0.61.0", 4543 + "windows-core", 4519 4544 ] 4520 4545 4521 4546 [[package]] 4522 4547 name = "windows-core" 4523 - version = "0.60.1" 4548 + version = "0.61.2" 4524 4549 source = "registry+https://github.com/rust-lang/crates.io-index" 4525 - checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247" 4550 + checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" 4526 4551 dependencies = [ 4527 - "windows-implement 0.59.0", 4528 - "windows-interface", 4529 - "windows-link", 4530 - "windows-result", 4531 - "windows-strings 0.3.1", 4532 - ] 4533 - 4534 - [[package]] 4535 - name = "windows-core" 4536 - version = "0.61.0" 4537 - source = "registry+https://github.com/rust-lang/crates.io-index" 4538 - checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" 4539 - dependencies = [ 4540 - "windows-implement 0.60.0", 4552 + "windows-implement", 4541 4553 "windows-interface", 4542 4554 "windows-link", 4543 4555 "windows-result", 4544 - "windows-strings 0.4.0", 4545 - ] 4546 - 4547 - [[package]] 4548 - name = "windows-future" 4549 - version = "0.1.1" 4550 - source = "registry+https://github.com/rust-lang/crates.io-index" 4551 - checksum = "a787db4595e7eb80239b74ce8babfb1363d8e343ab072f2ffe901400c03349f0" 4552 - dependencies = [ 4553 - "windows-core 0.60.1", 4554 - "windows-link", 4556 + "windows-strings", 4555 4557 ] 4556 4558 4557 4559 [[package]] 4558 4560 name = "windows-future" 4559 - version = "0.2.0" 4561 + version = "0.2.1" 4560 4562 source = "registry+https://github.com/rust-lang/crates.io-index" 4561 - checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" 4563 + checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" 4562 4564 dependencies = [ 4563 - "windows-core 0.61.0", 4565 + "windows-core", 4564 4566 "windows-link", 4565 - ] 4566 - 4567 - [[package]] 4568 - name = "windows-implement" 4569 - version = "0.59.0" 4570 - source = "registry+https://github.com/rust-lang/crates.io-index" 4571 - checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" 4572 - dependencies = [ 4573 - "proc-macro2", 4574 - "quote", 4575 - "syn 2.0.101", 4567 + "windows-threading", 4576 4568 ] 4577 4569 4578 4570 [[package]] ··· 4605 4597 4606 4598 [[package]] 4607 4599 name = "windows-numerics" 4608 - version = "0.1.1" 4609 - source = "registry+https://github.com/rust-lang/crates.io-index" 4610 - checksum = "005dea54e2f6499f2cee279b8f703b3cf3b5734a2d8d21867c8f44003182eeed" 4611 - dependencies = [ 4612 - "windows-core 0.60.1", 4613 - "windows-link", 4614 - ] 4615 - 4616 - [[package]] 4617 - name = "windows-numerics" 4618 4600 version = "0.2.0" 4619 4601 source = "registry+https://github.com/rust-lang/crates.io-index" 4620 4602 checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" 4621 4603 dependencies = [ 4622 - "windows-core 0.61.0", 4604 + "windows-core", 4623 4605 "windows-link", 4624 4606 ] 4625 4607 4626 4608 [[package]] 4627 - name = "windows-registry" 4628 - version = "0.4.0" 4629 - source = "registry+https://github.com/rust-lang/crates.io-index" 4630 - checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" 4631 - dependencies = [ 4632 - "windows-result", 4633 - "windows-strings 0.3.1", 4634 - "windows-targets 0.53.0", 4635 - ] 4636 - 4637 - [[package]] 4638 4609 name = "windows-result" 4639 - version = "0.3.2" 4610 + version = "0.3.4" 4640 4611 source = "registry+https://github.com/rust-lang/crates.io-index" 4641 - checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" 4612 + checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" 4642 4613 dependencies = [ 4643 4614 "windows-link", 4644 4615 ] 4645 4616 4646 4617 [[package]] 4647 4618 name = "windows-strings" 4648 - version = "0.3.1" 4619 + version = "0.4.2" 4649 4620 source = "registry+https://github.com/rust-lang/crates.io-index" 4650 - checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" 4651 - dependencies = [ 4652 - "windows-link", 4653 - ] 4654 - 4655 - [[package]] 4656 - name = "windows-strings" 4657 - version = "0.4.0" 4658 - source = "registry+https://github.com/rust-lang/crates.io-index" 4659 - checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" 4621 + checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" 4660 4622 dependencies = [ 4661 4623 "windows-link", 4662 4624 ] ··· 4668 4630 checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" 4669 4631 dependencies = [ 4670 4632 "windows-targets 0.42.2", 4671 - ] 4672 - 4673 - [[package]] 4674 - name = "windows-sys" 4675 - version = "0.48.0" 4676 - source = "registry+https://github.com/rust-lang/crates.io-index" 4677 - checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 4678 - dependencies = [ 4679 - "windows-targets 0.48.5", 4680 4633 ] 4681 4634 4682 4635 [[package]] ··· 4714 4667 4715 4668 [[package]] 4716 4669 name = "windows-targets" 4717 - version = "0.48.5" 4718 - source = "registry+https://github.com/rust-lang/crates.io-index" 4719 - checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 4720 - dependencies = [ 4721 - "windows_aarch64_gnullvm 0.48.5", 4722 - "windows_aarch64_msvc 0.48.5", 4723 - "windows_i686_gnu 0.48.5", 4724 - "windows_i686_msvc 0.48.5", 4725 - "windows_x86_64_gnu 0.48.5", 4726 - "windows_x86_64_gnullvm 0.48.5", 4727 - "windows_x86_64_msvc 0.48.5", 4728 - ] 4729 - 4730 - [[package]] 4731 - name = "windows-targets" 4732 4670 version = "0.52.6" 4733 4671 source = "registry+https://github.com/rust-lang/crates.io-index" 4734 4672 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" ··· 4736 4674 "windows_aarch64_gnullvm 0.52.6", 4737 4675 "windows_aarch64_msvc 0.52.6", 4738 4676 "windows_i686_gnu 0.52.6", 4739 - "windows_i686_gnullvm 0.52.6", 4677 + "windows_i686_gnullvm", 4740 4678 "windows_i686_msvc 0.52.6", 4741 4679 "windows_x86_64_gnu 0.52.6", 4742 4680 "windows_x86_64_gnullvm 0.52.6", ··· 4744 4682 ] 4745 4683 4746 4684 [[package]] 4747 - name = "windows-targets" 4748 - version = "0.53.0" 4685 + name = "windows-threading" 4686 + version = "0.1.0" 4749 4687 source = "registry+https://github.com/rust-lang/crates.io-index" 4750 - checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" 4688 + checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" 4751 4689 dependencies = [ 4752 - "windows_aarch64_gnullvm 0.53.0", 4753 - "windows_aarch64_msvc 0.53.0", 4754 - "windows_i686_gnu 0.53.0", 4755 - "windows_i686_gnullvm 0.53.0", 4756 - "windows_i686_msvc 0.53.0", 4757 - "windows_x86_64_gnu 0.53.0", 4758 - "windows_x86_64_gnullvm 0.53.0", 4759 - "windows_x86_64_msvc 0.53.0", 4690 + "windows-link", 4760 4691 ] 4761 4692 4762 4693 [[package]] ··· 4776 4707 4777 4708 [[package]] 4778 4709 name = "windows_aarch64_gnullvm" 4779 - version = "0.48.5" 4780 - source = "registry+https://github.com/rust-lang/crates.io-index" 4781 - checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 4782 - 4783 - [[package]] 4784 - name = "windows_aarch64_gnullvm" 4785 4710 version = "0.52.6" 4786 4711 source = "registry+https://github.com/rust-lang/crates.io-index" 4787 4712 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 4788 4713 4789 4714 [[package]] 4790 - name = "windows_aarch64_gnullvm" 4791 - version = "0.53.0" 4792 - source = "registry+https://github.com/rust-lang/crates.io-index" 4793 - checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" 4794 - 4795 - [[package]] 4796 4715 name = "windows_aarch64_msvc" 4797 4716 version = "0.42.2" 4798 4717 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4800 4719 4801 4720 [[package]] 4802 4721 name = "windows_aarch64_msvc" 4803 - version = "0.48.5" 4804 - source = "registry+https://github.com/rust-lang/crates.io-index" 4805 - checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 4806 - 4807 - [[package]] 4808 - name = "windows_aarch64_msvc" 4809 4722 version = "0.52.6" 4810 4723 source = "registry+https://github.com/rust-lang/crates.io-index" 4811 4724 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 4812 4725 4813 4726 [[package]] 4814 - name = "windows_aarch64_msvc" 4815 - version = "0.53.0" 4816 - source = "registry+https://github.com/rust-lang/crates.io-index" 4817 - checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" 4818 - 4819 - [[package]] 4820 4727 name = "windows_i686_gnu" 4821 4728 version = "0.42.2" 4822 4729 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4824 4731 4825 4732 [[package]] 4826 4733 name = "windows_i686_gnu" 4827 - version = "0.48.5" 4828 - source = "registry+https://github.com/rust-lang/crates.io-index" 4829 - checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 4830 - 4831 - [[package]] 4832 - name = "windows_i686_gnu" 4833 4734 version = "0.52.6" 4834 4735 source = "registry+https://github.com/rust-lang/crates.io-index" 4835 4736 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 4836 4737 4837 4738 [[package]] 4838 - name = "windows_i686_gnu" 4839 - version = "0.53.0" 4840 - source = "registry+https://github.com/rust-lang/crates.io-index" 4841 - checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" 4842 - 4843 - [[package]] 4844 4739 name = "windows_i686_gnullvm" 4845 4740 version = "0.52.6" 4846 4741 source = "registry+https://github.com/rust-lang/crates.io-index" 4847 4742 checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 4848 4743 4849 4744 [[package]] 4850 - name = "windows_i686_gnullvm" 4851 - version = "0.53.0" 4852 - source = "registry+https://github.com/rust-lang/crates.io-index" 4853 - checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" 4854 - 4855 - [[package]] 4856 4745 name = "windows_i686_msvc" 4857 4746 version = "0.42.2" 4858 4747 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4860 4749 4861 4750 [[package]] 4862 4751 name = "windows_i686_msvc" 4863 - version = "0.48.5" 4864 - source = "registry+https://github.com/rust-lang/crates.io-index" 4865 - checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 4866 - 4867 - [[package]] 4868 - name = "windows_i686_msvc" 4869 4752 version = "0.52.6" 4870 4753 source = "registry+https://github.com/rust-lang/crates.io-index" 4871 4754 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 4872 4755 4873 4756 [[package]] 4874 - name = "windows_i686_msvc" 4875 - version = "0.53.0" 4876 - source = "registry+https://github.com/rust-lang/crates.io-index" 4877 - checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" 4878 - 4879 - [[package]] 4880 4757 name = "windows_x86_64_gnu" 4881 4758 version = "0.42.2" 4882 4759 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4884 4761 4885 4762 [[package]] 4886 4763 name = "windows_x86_64_gnu" 4887 - version = "0.48.5" 4888 - source = "registry+https://github.com/rust-lang/crates.io-index" 4889 - checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 4890 - 4891 - [[package]] 4892 - name = "windows_x86_64_gnu" 4893 4764 version = "0.52.6" 4894 4765 source = "registry+https://github.com/rust-lang/crates.io-index" 4895 4766 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 4896 4767 4897 4768 [[package]] 4898 - name = "windows_x86_64_gnu" 4899 - version = "0.53.0" 4900 - source = "registry+https://github.com/rust-lang/crates.io-index" 4901 - checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" 4902 - 4903 - [[package]] 4904 4769 name = "windows_x86_64_gnullvm" 4905 4770 version = "0.42.2" 4906 4771 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4908 4773 4909 4774 [[package]] 4910 4775 name = "windows_x86_64_gnullvm" 4911 - version = "0.48.5" 4912 - source = "registry+https://github.com/rust-lang/crates.io-index" 4913 - checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 4914 - 4915 - [[package]] 4916 - name = "windows_x86_64_gnullvm" 4917 4776 version = "0.52.6" 4918 4777 source = "registry+https://github.com/rust-lang/crates.io-index" 4919 4778 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 4920 4779 4921 4780 [[package]] 4922 - name = "windows_x86_64_gnullvm" 4923 - version = "0.53.0" 4924 - source = "registry+https://github.com/rust-lang/crates.io-index" 4925 - checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" 4926 - 4927 - [[package]] 4928 4781 name = "windows_x86_64_msvc" 4929 4782 version = "0.42.2" 4930 4783 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4932 4785 4933 4786 [[package]] 4934 4787 name = "windows_x86_64_msvc" 4935 - version = "0.48.5" 4936 - source = "registry+https://github.com/rust-lang/crates.io-index" 4937 - checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 4938 - 4939 - [[package]] 4940 - name = "windows_x86_64_msvc" 4941 4788 version = "0.52.6" 4942 4789 source = "registry+https://github.com/rust-lang/crates.io-index" 4943 4790 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 4944 4791 4945 4792 [[package]] 4946 - name = "windows_x86_64_msvc" 4947 - version = "0.53.0" 4948 - source = "registry+https://github.com/rust-lang/crates.io-index" 4949 - checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" 4950 - 4951 - [[package]] 4952 4793 name = "winnow" 4953 4794 version = "0.5.40" 4954 4795 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4959 4800 4960 4801 [[package]] 4961 4802 name = "winnow" 4962 - version = "0.7.9" 4803 + version = "0.7.10" 4963 4804 source = "registry+https://github.com/rust-lang/crates.io-index" 4964 - checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" 4805 + checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" 4965 4806 dependencies = [ 4966 4807 "memchr", 4967 4808 ] 4968 4809 4969 4810 [[package]] 4970 4811 name = "winreg" 4971 - version = "0.52.0" 4812 + version = "0.55.0" 4972 4813 source = "registry+https://github.com/rust-lang/crates.io-index" 4973 - checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" 4814 + checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" 4974 4815 dependencies = [ 4975 4816 "cfg-if", 4976 - "windows-sys 0.48.0", 4817 + "windows-sys 0.59.0", 4977 4818 ] 4978 4819 4979 4820 [[package]] ··· 4982 4823 source = "registry+https://github.com/rust-lang/crates.io-index" 4983 4824 checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 4984 4825 dependencies = [ 4985 - "bitflags 2.9.0", 4826 + "bitflags 2.9.1", 4986 4827 ] 4987 4828 4988 4829 [[package]] 4989 - name = "write16" 4990 - version = "1.0.0" 4991 - source = "registry+https://github.com/rust-lang/crates.io-index" 4992 - checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 4993 - 4994 - [[package]] 4995 4830 name = "writeable" 4996 - version = "0.5.5" 4831 + version = "0.6.1" 4997 4832 source = "registry+https://github.com/rust-lang/crates.io-index" 4998 - checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 4833 + checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" 4999 4834 5000 4835 [[package]] 5001 4836 name = "wry" ··· 5035 4870 "webkit2gtk", 5036 4871 "webkit2gtk-sys", 5037 4872 "webview2-com", 5038 - "windows 0.61.1", 5039 - "windows-core 0.61.0", 4873 + "windows", 4874 + "windows-core", 5040 4875 "windows-version", 5041 4876 "x11-dl", 5042 4877 ] ··· 5064 4899 5065 4900 [[package]] 5066 4901 name = "yoke" 5067 - version = "0.7.5" 4902 + version = "0.8.0" 5068 4903 source = "registry+https://github.com/rust-lang/crates.io-index" 5069 - checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 4904 + checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" 5070 4905 dependencies = [ 5071 4906 "serde", 5072 4907 "stable_deref_trait", ··· 5076 4911 5077 4912 [[package]] 5078 4913 name = "yoke-derive" 5079 - version = "0.7.5" 4914 + version = "0.8.0" 5080 4915 source = "registry+https://github.com/rust-lang/crates.io-index" 5081 - checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 4916 + checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" 5082 4917 dependencies = [ 5083 4918 "proc-macro2", 5084 4919 "quote", ··· 5088 4923 5089 4924 [[package]] 5090 4925 name = "zbus" 5091 - version = "5.6.0" 4926 + version = "5.7.1" 5092 4927 source = "registry+https://github.com/rust-lang/crates.io-index" 5093 - checksum = "2522b82023923eecb0b366da727ec883ace092e7887b61d3da5139f26b44da58" 4928 + checksum = "d3a7c7cee313d044fca3f48fa782cb750c79e4ca76ba7bc7718cd4024cdf6f68" 5094 4929 dependencies = [ 5095 4930 "async-broadcast", 5096 4931 "async-executor", ··· 5113 4948 "tracing", 5114 4949 "uds_windows", 5115 4950 "windows-sys 0.59.0", 5116 - "winnow 0.7.9", 4951 + "winnow 0.7.10", 5117 4952 "zbus_macros", 5118 4953 "zbus_names", 5119 4954 "zvariant", ··· 5121 4956 5122 4957 [[package]] 5123 4958 name = "zbus_macros" 5124 - version = "5.6.0" 4959 + version = "5.7.1" 5125 4960 source = "registry+https://github.com/rust-lang/crates.io-index" 5126 - checksum = "05d2e12843c75108c00c618c2e8ef9675b50b6ec095b36dc965f2e5aed463c15" 4961 + checksum = "a17e7e5eec1550f747e71a058df81a9a83813ba0f6a95f39c4e218bdc7ba366a" 5127 4962 dependencies = [ 5128 4963 "proc-macro-crate 3.3.0", 5129 4964 "proc-macro2", ··· 5142 4977 dependencies = [ 5143 4978 "serde", 5144 4979 "static_assertions", 5145 - "winnow 0.7.9", 4980 + "winnow 0.7.10", 5146 4981 "zvariant", 5147 4982 ] 5148 4983 ··· 5188 5023 ] 5189 5024 5190 5025 [[package]] 5026 + name = "zerotrie" 5027 + version = "0.2.2" 5028 + source = "registry+https://github.com/rust-lang/crates.io-index" 5029 + checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" 5030 + dependencies = [ 5031 + "displaydoc", 5032 + "yoke", 5033 + "zerofrom", 5034 + ] 5035 + 5036 + [[package]] 5191 5037 name = "zerovec" 5192 - version = "0.10.4" 5038 + version = "0.11.2" 5193 5039 source = "registry+https://github.com/rust-lang/crates.io-index" 5194 - checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 5040 + checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" 5195 5041 dependencies = [ 5196 5042 "yoke", 5197 5043 "zerofrom", ··· 5200 5046 5201 5047 [[package]] 5202 5048 name = "zerovec-derive" 5203 - version = "0.10.3" 5049 + version = "0.11.1" 5204 5050 source = "registry+https://github.com/rust-lang/crates.io-index" 5205 - checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 5051 + checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" 5206 5052 dependencies = [ 5207 5053 "proc-macro2", 5208 5054 "quote", ··· 5211 5057 5212 5058 [[package]] 5213 5059 name = "zvariant" 5214 - version = "5.5.1" 5060 + version = "5.5.3" 5215 5061 source = "registry+https://github.com/rust-lang/crates.io-index" 5216 - checksum = "557e89d54880377a507c94cd5452f20e35d14325faf9d2958ebeadce0966c1b2" 5062 + checksum = "9d30786f75e393ee63a21de4f9074d4c038d52c5b1bb4471f955db249f9dffb1" 5217 5063 dependencies = [ 5218 5064 "endi", 5219 5065 "enumflags2", 5220 5066 "serde", 5221 - "winnow 0.7.9", 5067 + "winnow 0.7.10", 5222 5068 "zvariant_derive", 5223 5069 "zvariant_utils", 5224 5070 ] 5225 5071 5226 5072 [[package]] 5227 5073 name = "zvariant_derive" 5228 - version = "5.5.1" 5074 + version = "5.5.3" 5229 5075 source = "registry+https://github.com/rust-lang/crates.io-index" 5230 - checksum = "757779842a0d242061d24c28be589ce392e45350dfb9186dfd7a042a2e19870c" 5076 + checksum = "75fda702cd42d735ccd48117b1630432219c0e9616bf6cb0f8350844ee4d9580" 5231 5077 dependencies = [ 5232 5078 "proc-macro-crate 3.3.0", 5233 5079 "proc-macro2", ··· 5247 5093 "serde", 5248 5094 "static_assertions", 5249 5095 "syn 2.0.101", 5250 - "winnow 0.7.9", 5096 + "winnow 0.7.10", 5251 5097 ]
+4
backend/Cargo.toml
··· 17 17 tauri-plugin-opener = "2" 18 18 serde = { version = "1", features = ["derive"] } 19 19 serde_json = "1" 20 + chrono = { version = "0.4.41", features = ["serde", "now"] } 21 + tokio = { version = "1.45.1", features = ["sync", "macros", "time"] } 22 + rand = { version = "0.9.1", features = ["thread_rng"] } 23 + tauri-plugin-geolocation = "2.2.4"
+447
backend/src/game.rs
··· 1 + use std::{collections::HashMap, time::Duration}; 2 + use tauri::Runtime; 3 + use tokio::sync::RwLock; 4 + 5 + use crate::{ 6 + powerup::{PowerUpType, PowerUpUsage}, 7 + state::{GameEvent, GameState, Location, PlayerId, DT}, 8 + }; 9 + 10 + type EventMessage = (PlayerId, DT, GameEvent); 11 + 12 + /// Struct representing an ongoing game, handles communication with 13 + /// other clients via [Transport] and provides high-level methods for 14 + /// taking actions in the game. 15 + struct Game<L: LocationService, T: Transport> { 16 + id: PlayerId, 17 + is_host: bool, 18 + state: RwLock<GameState<L>>, 19 + transport: T, 20 + interval: Duration, 21 + } 22 + 23 + pub trait Transport { 24 + async fn receive_message(&self) -> Option<EventMessage>; 25 + async fn send_event_to(&self, id: PlayerId, event: GameEvent); 26 + async fn send_event_host(&self, event: GameEvent); 27 + async fn send_event_multiple(&self, ids: Vec<PlayerId>, event: GameEvent); 28 + async fn send_event_all(&self, event: GameEvent); 29 + } 30 + 31 + pub trait LocationService { 32 + fn get_loc(&self) -> Location; 33 + } 34 + 35 + impl<L: LocationService, T: Transport> Game<L, T> { 36 + pub fn new(id: PlayerId, game_state: GameState<L>, transport: T, interval: Duration) -> Self { 37 + Self { 38 + id, 39 + is_host: game_state.host.is_some(), 40 + state: RwLock::new(game_state), 41 + transport, 42 + interval, 43 + } 44 + } 45 + 46 + /// Mark yourself as caught, sends out a message to all other players 47 + async fn mark_caught(&self) { 48 + self.transport 49 + .send_event_all(GameEvent::HiderCaught(self.id)) 50 + .await; 51 + } 52 + 53 + /// Get the active powerup, to be called when the user is in range of the powerup 54 + async fn get_powerup(&self) { 55 + let mut state = self.state.write().await; 56 + if let Some(powerup) = state.public.available_powerup.take() { 57 + state.player.held_powerup = Some(powerup.typ); 58 + drop(state); 59 + self.transport 60 + .send_event_all(GameEvent::PowerUpDespawn) 61 + .await; 62 + } 63 + } 64 + 65 + async fn use_powerup(&self) { 66 + let mut state = self.state.write().await; 67 + if let Some(powerup) = state.player.held_powerup.take() { 68 + drop(state); 69 + match powerup { 70 + PowerUpType::PingSeeker => { 71 + let e = GameEvent::PowerUpActivate(PowerUpUsage::PingSeeker); 72 + self.transport.send_event_host(e).await; 73 + } 74 + PowerUpType::PingAllSeekers => { 75 + let e = GameEvent::PingReq(None); 76 + let state = self.state.read().await; 77 + let seekers = state.public.iter_seekers().collect::<Vec<_>>(); 78 + drop(state); 79 + let host_log = GameEvent::PowerUpActivate(PowerUpUsage::PingAllSeekers); 80 + self.transport.send_event_host(host_log).await; 81 + self.transport.send_event_multiple(seekers, e).await; 82 + } 83 + PowerUpType::ForcePingOther => { 84 + let e = GameEvent::PingReq(None); 85 + let mut state = self.state.write().await; 86 + if let Some(target) = state.random_other_hider() { 87 + let host_log = 88 + GameEvent::PowerUpActivate(PowerUpUsage::ForcePingOther(target)); 89 + self.transport.send_event_host(host_log).await; 90 + self.transport.send_event_to(target, e).await; 91 + } 92 + } 93 + } 94 + } 95 + } 96 + 97 + /// Start main loop of the game, this should ideally be put into its own thread via 98 + /// [tokio::spawn]. 99 + async fn main_loop( 100 + &self, 101 + ) -> ( 102 + HashMap<PlayerId, Vec<Location>>, 103 + Vec<(PlayerId, DT, GameEvent)>, 104 + ) { 105 + let interval = tokio::time::interval(self.interval); 106 + tokio::pin!(interval); 107 + 108 + let mut ended = false; 109 + 110 + while !ended { 111 + tokio::select! { 112 + _ = interval.tick() => { 113 + let mut state = self.state.write().await; 114 + let messages = state.tick(); 115 + drop(state); 116 + for (player, event) in messages { 117 + if let Some(player) = player { 118 + self.transport.send_event_to(player, event).await; 119 + } else { 120 + self.transport.send_event_all(event).await; 121 + } 122 + } 123 + } 124 + 125 + Some((player, time_sent, event)) = self.transport.receive_message() => { 126 + if let GameEvent::GameEnd(dt) = event { 127 + ended = true; 128 + 129 + } else { 130 + let mut state = self.state.write().await; 131 + let new_event = state.consume_event(time_sent, event, player); 132 + drop(state); 133 + if let Some(event) = new_event { 134 + self.transport.send_event_all(event).await; 135 + } 136 + } 137 + } 138 + } 139 + } 140 + 141 + let state = self.state.read().await; 142 + let locations = state.player.locations.clone(); 143 + 144 + if self.is_host { 145 + let player_count = state.public.caught_state.len(); 146 + let mut player_location_history = 147 + HashMap::<PlayerId, Vec<Location>>::with_capacity(player_count); 148 + player_location_history.insert(self.id, locations); 149 + while player_location_history.len() != player_count { 150 + // TODO: Join with a timeout, etc 151 + if let Some((id, _, GameEvent::PostGameSync(player_locations))) = 152 + self.transport.receive_message().await 153 + { 154 + player_location_history.insert(id, player_locations); 155 + } 156 + } 157 + let history = ( 158 + player_location_history, 159 + state.host.as_ref().unwrap().event_history.clone(), 160 + ); 161 + let ev = GameEvent::HostHistorySync(history.clone()); 162 + self.transport.send_event_all(ev).await; 163 + history 164 + } else { 165 + self.transport 166 + .send_event_host(GameEvent::PostGameSync(locations)) 167 + .await; 168 + loop { 169 + if let Some((_, _, GameEvent::HostHistorySync(history))) = 170 + self.transport.receive_message().await 171 + { 172 + break history; 173 + } 174 + } 175 + } 176 + } 177 + } 178 + 179 + #[cfg(test)] 180 + mod tests { 181 + use std::collections::HashMap; 182 + use std::sync::Arc; 183 + 184 + use crate::state::{GameSettings, HostState, PingStartCondition}; 185 + 186 + use super::*; 187 + use tokio::sync::mpsc::{Receiver, Sender}; 188 + use tokio::sync::Mutex; 189 + use tokio::task::yield_now; 190 + use tokio::test; 191 + 192 + type EventRx = Receiver<EventMessage>; 193 + type EventTx = Sender<EventMessage>; 194 + 195 + struct MockTransport { 196 + player_id: PlayerId, 197 + rx: Mutex<EventRx>, 198 + txs: HashMap<PlayerId, EventTx>, 199 + } 200 + 201 + impl MockTransport { 202 + fn new(player_id: PlayerId) -> (Self, EventTx) { 203 + let (tx, rx) = tokio::sync::mpsc::channel(5); 204 + let trans = Self { 205 + player_id, 206 + rx: Mutex::new(rx), 207 + txs: HashMap::new(), 208 + }; 209 + (trans, tx) 210 + } 211 + 212 + fn set_txs(&mut self, txs: HashMap<PlayerId, EventTx>) { 213 + self.txs = txs; 214 + } 215 + 216 + fn make_msg(&self, e: GameEvent) -> EventMessage { 217 + (self.player_id, chrono::Utc::now(), e) 218 + } 219 + } 220 + 221 + impl Transport for MockTransport { 222 + async fn receive_message(&self) -> Option<EventMessage> { 223 + let mut rx = self.rx.lock().await; 224 + rx.recv().await 225 + } 226 + 227 + async fn send_event_to(&self, id: PlayerId, event: GameEvent) { 228 + if let Some(tx) = self.txs.get(&id) { 229 + if let Err(why) = tx.send(self.make_msg(event)).await { 230 + eprintln!("Error sending msg to {id}: {why}"); 231 + } 232 + } 233 + } 234 + 235 + async fn send_event_host(&self, event: GameEvent) { 236 + // While testing, host is always player 0 237 + self.send_event_to(0, event).await; 238 + } 239 + 240 + async fn send_event_multiple(&self, ids: Vec<PlayerId>, event: GameEvent) { 241 + for id in ids { 242 + self.send_event_to(id, event.clone()).await; 243 + } 244 + } 245 + 246 + async fn send_event_all(&self, event: GameEvent) { 247 + for id in self.txs.keys() { 248 + self.send_event_to(*id, event.clone()).await; 249 + } 250 + } 251 + } 252 + 253 + struct MockLocation; 254 + 255 + impl LocationService for MockLocation { 256 + fn get_loc(&self) -> Location { 257 + Location { 258 + lat: 0.0, 259 + long: 0.0, 260 + heading: None, 261 + } 262 + } 263 + } 264 + 265 + type MockGame = Game<MockLocation, MockTransport>; 266 + 267 + struct TestMatch { 268 + games: HashMap<PlayerId, Arc<MockGame>>, 269 + } 270 + 271 + impl TestMatch { 272 + /// New test match 273 + /// player_count: number of players 274 + /// num_seekers: number of seekers 275 + /// host_seeker: whether to mark the host as a seeker 276 + pub fn new( 277 + player_count: u32, 278 + num_seekers: u32, 279 + host_seeker: bool, 280 + settings: GameSettings, 281 + ) -> Self { 282 + let caught_state = 283 + HashMap::<PlayerId, bool>::from_iter((0..player_count).into_iter().map(|id| { 284 + let should_seeker = 285 + (if id == 0 || host_seeker { id } else { id - 1 }) < num_seekers; 286 + (id, should_seeker && (host_seeker || id != 0)) 287 + })); 288 + 289 + let mut txs = HashMap::<PlayerId, EventTx>::with_capacity(player_count as usize); 290 + let mut games = HashMap::<PlayerId, MockGame>::with_capacity(player_count as usize); 291 + 292 + for id in 0..player_count { 293 + let (transport, tx) = MockTransport::new(id); 294 + let state = GameState::new( 295 + id == 0, 296 + id, 297 + caught_state.clone(), 298 + settings.clone(), 299 + MockLocation, 300 + ); 301 + txs.insert(id, tx); 302 + let game = MockGame::new(id, state, transport, Duration::from_secs(1)); 303 + games.insert(id, game); 304 + } 305 + 306 + for game in games.values_mut() { 307 + game.transport.set_txs(txs.clone()); 308 + } 309 + 310 + Self { 311 + games: games.into_iter().map(|(k, v)| (k, Arc::new(v))).collect(), 312 + } 313 + } 314 + 315 + pub fn start(&self) { 316 + for game in self.games.values() { 317 + let game = game.clone(); 318 + tokio::spawn(async move { game.main_loop().await }); 319 + } 320 + } 321 + 322 + pub fn host(&self) -> Arc<MockGame> { 323 + self.game(0) 324 + } 325 + 326 + pub fn game(&self, id: PlayerId) -> Arc<MockGame> { 327 + self.games.get(&id).unwrap().clone() 328 + } 329 + 330 + pub async fn wait_tick(&self) { 331 + tokio::time::sleep(Duration::from_secs(1)).await; 332 + yield_now().await; 333 + } 334 + 335 + pub async fn wait_assert_seekers_released(&self) { 336 + tokio::time::sleep(Duration::from_secs(1)).await; 337 + yield_now().await; 338 + 339 + self.assert_all_player_states(|state| { 340 + assert!(state.public.seekers_started.is_some()); 341 + }); 342 + } 343 + 344 + /// Assert a condition on the host state 345 + pub async fn assert_host_state<F: Fn(&HostState)>(&self, f: F) { 346 + let host = self.host(); 347 + let state = host.state.read().await; 348 + f(state.host.as_ref().unwrap()); 349 + } 350 + 351 + /// Assert a condition on all player states 352 + pub async fn assert_all_player_states<F: Fn(&GameState<MockLocation>)>(&self, f: F) { 353 + for game in self.games.values() { 354 + let state = game.state.read().await; 355 + f(&state); 356 + } 357 + } 358 + } 359 + 360 + const TEST_LOC: Location = Location { 361 + lat: 0.0, 362 + long: 0.0, 363 + heading: None, 364 + }; 365 + 366 + #[test] 367 + async fn test_game() { 368 + let settings = GameSettings { 369 + hiding_time_seconds: 1, 370 + ping_start: PingStartCondition::Players(3), 371 + ping_minutes_interval: 0, 372 + powerup_start: PingStartCondition::Players(3), 373 + powerup_chance: 0, 374 + powerup_minutes_cooldown: 1, 375 + powerup_locations: vec![TEST_LOC.clone()], 376 + }; 377 + 378 + // A test match with 5 players, player 0 (host) is a hider, players 1 and 2 are seekers. 379 + let test_match = TestMatch::new(5, 2, false, settings); 380 + 381 + let correct_caught_state = HashMap::<PlayerId, bool>::from_iter([ 382 + (0, false), 383 + (1, true), 384 + (2, true), 385 + (3, false), 386 + (4, false), 387 + ]); 388 + 389 + // Let's make sure our initial `caught_state` is correct 390 + test_match 391 + .assert_all_player_states(|s| assert_eq!(s.public.caught_state, correct_caught_state)) 392 + .await; 393 + 394 + test_match.start(); 395 + 396 + // Wait for seekers to be released, and then assert all player states properly reflect this 397 + test_match.wait_assert_seekers_released().await; 398 + 399 + test_match.wait_tick().await; 400 + 401 + // After a tick, all players should have at least one location in [PlayerState::locations] 402 + test_match 403 + .assert_all_player_states(|s| assert!(!s.player.locations.is_empty())) 404 + .await; 405 + 406 + // Now, let's see if we can mark player 3 as caught 407 + let player_3 = test_match.game(3); 408 + player_3.mark_caught().await; 409 + yield_now().await; 410 + 411 + // All states should be updated to reflect this 412 + test_match 413 + .assert_all_player_states(|s| { 414 + assert_eq!(s.public.caught_state.get(&3).copied(), Some(true)) 415 + }) 416 + .await; 417 + 418 + test_match.wait_tick().await; 419 + 420 + // And now, 3 players have been caught, meaning our [PingStartCondition] has been met, 421 + // let's check the host state to make sure it's starting to perform pings 422 + test_match 423 + .assert_host_state(|h| assert!(h.last_ping.is_some())) 424 + .await; 425 + 426 + test_match.wait_tick().await; 427 + 428 + // Value represents if the [Option] should be [Option::Some] 429 + let correct_pings = HashMap::<u32, bool>::from_iter([ 430 + (0, true), 431 + (1, false), 432 + (2, false), 433 + (3, false), 434 + (4, true), 435 + ]); 436 + 437 + // Now let's make sure the hiders are being pinged (3 was just caught, triggering pings. 438 + // Therefore, 3 should not be pinged) 439 + test_match 440 + .assert_all_player_states(|s| { 441 + for (k, v) in s.public.pings.iter() { 442 + assert_eq!(v.is_some(), correct_pings[k]); 443 + } 444 + }) 445 + .await; 446 + } 447 + }
+5 -6
backend/src/lib.rs
··· 1 - // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ 2 - #[tauri::command] 3 - fn greet(name: &str) -> String { 4 - format!("Hello, {}! You've been greeted from Rust!", name) 5 - } 1 + #[allow(unused)] 2 + mod game; 3 + mod powerup; 4 + mod state; 6 5 7 6 #[cfg_attr(mobile, tauri::mobile_entry_point)] 8 7 pub fn run() { 9 8 tauri::Builder::default() 10 9 .plugin(tauri_plugin_opener::init()) 11 - .invoke_handler(tauri::generate_handler![greet]) 10 + .invoke_handler(tauri::generate_handler![]) 12 11 .run(tauri::generate_context!()) 13 12 .expect("error while running tauri application"); 14 13 }
+65
backend/src/powerup.rs
··· 1 + use crate::state::{Location, PlayerId}; 2 + 3 + #[derive(Clone, Copy)] 4 + /// Type of powerup 5 + pub enum PowerUpType { 6 + /// Ping a random seeker instead of a hider 7 + PingSeeker, 8 + 9 + /// Pings all seekers locations on the map for hiders 10 + PingAllSeekers, 11 + 12 + /// Ping another random hider instantly 13 + ForcePingOther, 14 + } 15 + 16 + impl PowerUpType { 17 + pub const ALL_TYPES: [Self; 3] = [ 18 + PowerUpType::ForcePingOther, 19 + PowerUpType::PingAllSeekers, 20 + PowerUpType::PingSeeker, 21 + ]; 22 + } 23 + 24 + #[derive(Clone)] 25 + /// Usage of a powerup as reported to the host 26 + pub enum PowerUpUsage { 27 + /// The hider will have their location replaced with a random seeker's 28 + PingSeeker, 29 + /// No additional args 30 + PingAllSeekers, 31 + /// Instantly ping another random hider, contains the unlucky person that is being pinged 32 + ForcePingOther(PlayerId), 33 + } 34 + 35 + #[derive(Clone, PartialEq, Eq)] 36 + /// When a plugin is used 37 + pub enum PowerUpTiming { 38 + /// Used the second it's activated 39 + Instant, 40 + /// Used during the next global ping 41 + NextPing, 42 + } 43 + 44 + impl PowerUpUsage { 45 + pub fn timing(&self) -> PowerUpTiming { 46 + match self { 47 + PowerUpUsage::PingSeeker => PowerUpTiming::NextPing, 48 + PowerUpUsage::ForcePingOther(_) => PowerUpTiming::Instant, 49 + PowerUpUsage::PingAllSeekers => PowerUpTiming::Instant, 50 + } 51 + } 52 + } 53 + 54 + #[derive(Clone)] 55 + /// An on-map powerup that can be picked up by hiders 56 + pub struct PowerUp { 57 + loc: Location, 58 + pub typ: PowerUpType, 59 + } 60 + 61 + impl PowerUp { 62 + pub fn new(loc: Location, typ: PowerUpType) -> Self { 63 + Self { loc, typ } 64 + } 65 + }
+475
backend/src/state.rs
··· 1 + use std::collections::HashMap; 2 + 3 + use chrono::{DateTime, Utc}; 4 + 5 + use crate::{ 6 + game::LocationService, 7 + powerup::{PowerUp, PowerUpTiming, PowerUpType, PowerUpUsage}, 8 + }; 9 + 10 + /// UTC DateTime; 11 + pub type DT = DateTime<Utc>; 12 + 13 + /// Type used to uniquely identify players in the game 14 + pub type PlayerId = u32; 15 + 16 + /// Type used for latitude and longitude 17 + pub type LocationComponent = f64; 18 + 19 + #[derive(Debug, Clone)] 20 + /// The starting condition for global pings to begin 21 + pub enum PingStartCondition { 22 + /// Wait For X players to be caught before beginning global pings 23 + Players(u32), 24 + /// Wait for X minutes after game start to begin global pings 25 + Minutes(u32), 26 + /// Don't wait at all, ping location after seekers are released 27 + Instant, 28 + } 29 + 30 + #[derive(Debug, Clone)] 31 + /// Settings for the game, host is the only person able to change these 32 + pub struct GameSettings { 33 + /// The number of seconds to wait before seekers are allowed to go 34 + pub hiding_time_seconds: u64, 35 + /// Condition to wait for global pings to begin 36 + pub ping_start: PingStartCondition, 37 + /// Time between pings after the condition is met (first ping is either after the interval or 38 + /// instantly after the condition is met depending on the condition) 39 + pub ping_minutes_interval: u64, 40 + /// Condition for powerups to start spawning 41 + pub powerup_start: PingStartCondition, 42 + /// Chance (after cooldown) each minute of a powerup spawning, out of 100 43 + pub powerup_chance: u32, 44 + /// Hard cooldown between powerups spawning 45 + pub powerup_minutes_cooldown: u32, 46 + /// Locations that powerups may spawn at 47 + pub powerup_locations: Vec<Location>, 48 + } 49 + 50 + #[derive(Debug, Clone, Copy)] 51 + /// Some location in the world as gotten from the Geolocation API 52 + pub struct Location { 53 + /// Latitude 54 + pub lat: LocationComponent, 55 + /// Longitude 56 + pub long: LocationComponent, 57 + /// The bearing (float normalized from 0 to 1) optional as GPS can't always determine 58 + pub heading: Option<LocationComponent>, 59 + } 60 + 61 + /// State for each player during the game, the host also has this 62 + pub struct PlayerState { 63 + /// The id of this player in this game 64 + pub id: PlayerId, 65 + /// All previous locations of this player, used in replay screen and when a ping happens 66 + pub locations: Vec<Location>, 67 + /// Whether the local player is a seeker 68 + pub seeker: bool, 69 + /// The powerup the player is currently holding 70 + pub held_powerup: Option<PowerUpType>, 71 + } 72 + 73 + /// Host state that determines when "privileged" events happen 74 + pub struct HostState { 75 + /// The last time a location global ping occurred. If this is [Option::None] it means we're not 76 + /// pinging yet 77 + pub last_ping: Option<DT>, 78 + 79 + /// The last time a power-up has spawned. 80 + pub last_powerup: Option<DT>, 81 + 82 + /// Last time a roll was done for a powerup to spawn, if this is [Option::None] it means we're 83 + /// not spawning powerups yet. 84 + pub last_powerup_proc: Option<DT>, 85 + 86 + /// Set of users that will not be pinged / ping someone else next ping 87 + pub ping_power_usages: HashMap<PlayerId, PowerUpUsage>, 88 + 89 + /// A list of all events that happened in this game, and their times 90 + pub event_history: Vec<(PlayerId, DT, GameEvent)>, 91 + } 92 + 93 + impl HostState { 94 + pub fn new() -> Self { 95 + Self { 96 + last_ping: None, 97 + last_powerup: None, 98 + last_powerup_proc: None, 99 + ping_power_usages: HashMap::with_capacity(4), 100 + event_history: Vec::with_capacity(50), 101 + } 102 + } 103 + } 104 + 105 + #[derive(Clone)] 106 + /// An on-map ping of a player 107 + pub struct PlayerPing { 108 + /// Location of the ping 109 + loc: Location, 110 + /// Time the ping happened 111 + time: DT, 112 + /// The player to display who initialized this ping 113 + player: PlayerId, 114 + /// The actual player that initialized this ping 115 + real_player: PlayerId, 116 + } 117 + 118 + impl PlayerPing { 119 + pub fn new(loc: Location, player: PlayerId, real_player: PlayerId) -> Self { 120 + Self { 121 + loc, 122 + player, 123 + real_player, 124 + time: Utc::now(), 125 + } 126 + } 127 + } 128 + 129 + /// State meant to be updated and synced 130 + pub struct PublicState { 131 + /// When the game started 132 + pub game_started: DT, 133 + 134 + /// When seekers were allowed to begin 135 + pub seekers_started: Option<DT>, 136 + 137 + /// Hashmap tracking if a player is a seeker (true) or a hider (false) 138 + pub caught_state: HashMap<PlayerId, bool>, 139 + 140 + /// A map of the latest global ping results for each player 141 + pub pings: HashMap<PlayerId, Option<PlayerPing>>, 142 + 143 + /// Powerup on the map that players can grab. Only one at a time 144 + pub available_powerup: Option<PowerUp>, 145 + } 146 + 147 + impl PublicState { 148 + pub fn new(players: HashMap<PlayerId, bool>) -> Self { 149 + Self { 150 + game_started: Utc::now(), 151 + seekers_started: None, 152 + pings: HashMap::from_iter(players.keys().map(|id| (*id, None))), 153 + caught_state: players, 154 + available_powerup: None, 155 + } 156 + } 157 + 158 + pub fn iter_seekers(&self) -> impl Iterator<Item = PlayerId> + use<'_> { 159 + self.caught_state 160 + .iter() 161 + .filter_map(|(k, v)| if *v { Some(*k) } else { None }) 162 + } 163 + 164 + pub fn iter_hiders(&self) -> impl Iterator<Item = PlayerId> + use<'_> { 165 + self.caught_state 166 + .iter() 167 + .filter_map(|(k, v)| if !*v { Some(*k) } else { None }) 168 + } 169 + } 170 + 171 + impl PlayerState { 172 + pub fn new(id: PlayerId, seeker: bool) -> Self { 173 + Self { 174 + id, 175 + locations: Vec::with_capacity(20), 176 + seeker, 177 + held_powerup: None, 178 + } 179 + } 180 + 181 + /// Create a [PlayerPing] with the latest location saved for the player 182 + pub fn create_self_ping(&self) -> Option<PlayerPing> { 183 + self.create_ping(self.id) 184 + } 185 + 186 + /// Create a [PlayerPing] with the latest location as another player, used when powerups are 187 + /// active 188 + pub fn create_ping(&self, id: PlayerId) -> Option<PlayerPing> { 189 + self.get_loc() 190 + .map(|loc| PlayerPing::new(loc.clone(), id, self.id)) 191 + } 192 + 193 + /// Push a new player location 194 + pub fn push_loc(&mut self, loc: Location) { 195 + self.locations.push(loc); 196 + } 197 + 198 + /// Get the latest player location 199 + pub fn get_loc(&self) -> Option<&Location> { 200 + self.locations.last() 201 + } 202 + } 203 + 204 + /// Central struct for managing the entire game's state 205 + pub struct GameState<L: LocationService> { 206 + /// Player state, different for each player 207 + pub player: PlayerState, 208 + /// Public state, kept in sync via events 209 + pub public: PublicState, 210 + /// Host state, only for host, this being [Option::None] implies not being host 211 + pub host: Option<HostState>, 212 + /// The settings for the current game, read only 213 + pub settings: GameSettings, 214 + loc: L, 215 + } 216 + 217 + #[derive(Clone)] 218 + /// Enum representing all events that can be published, some are host only although 219 + /// implicit trust is given to all players because uh who cares. 220 + pub enum GameEvent { 221 + /// Seekers are now active and can see the map 222 + SeekersReleased(DT), 223 + /// (Host) A request for a given player to ping, optionally includes another player to ping 224 + /// *as* (e.g. when [PowerUpType::PingSeeker] is used) 225 + PingReq(Option<PlayerId>), 226 + /// A [PlayerPing] was published to [PublicState] 227 + Ping(PlayerPing), 228 + /// The given hider has been caught 229 + HiderCaught(PlayerId), 230 + /// (Host) The powerup has spawned and is available to grab 231 + PowerUpSpawn(PowerUp), 232 + /// The powerup has despawned (Was grabbed or timed out) 233 + PowerUpDespawn, 234 + /// A player has activated a powerup, some powerups will be published globally and some will be 235 + /// handled only by the host (such as [PowerUpType::PingSeeker]) 236 + PowerUpActivate(PowerUpUsage), 237 + /// (Host) The game has ended (all players were caught or the host cancelled the game) 238 + GameEnd(DT), 239 + /// (Players) After the game has ended, players send this as the final game message 240 + /// to the host with their entire location history 241 + PostGameSync(Vec<Location>), 242 + /// (Host) After the game has ended and all players have sent their location histories to the 243 + /// host, the host will send this back to all players. Contains the entire history of the game 244 + /// to be saved and replayed. 245 + HostHistorySync( 246 + ( 247 + HashMap<PlayerId, Vec<Location>>, 248 + Vec<(PlayerId, DT, GameEvent)>, 249 + ), 250 + ), 251 + } 252 + 253 + impl<L: LocationService> GameState<L> { 254 + /// Create a new game state (starting a game). Needs the ID of the current player and a HashMap 255 + /// of other player ids to their caught state (whether they start out as seeker). 256 + pub fn new( 257 + host: bool, 258 + id: PlayerId, 259 + players: HashMap<PlayerId, bool>, 260 + settings: GameSettings, 261 + loc: L, 262 + ) -> Self { 263 + let is_seeker = players.get(&id).copied().unwrap_or_default(); 264 + Self { 265 + player: PlayerState::new(id, is_seeker), 266 + public: PublicState::new(players), 267 + host: if host { Some(HostState::new()) } else { None }, 268 + settings, 269 + loc, 270 + } 271 + } 272 + 273 + pub fn random_other_hider(&mut self) -> Option<PlayerId> { 274 + let hiders = self 275 + .public 276 + .iter_hiders() 277 + .filter(|i| *i != self.player.id) 278 + .collect::<Vec<_>>(); 279 + let choice = rand::random_range(0..hiders.len()); 280 + hiders.get(choice).copied() 281 + } 282 + 283 + fn host_tick(&mut self, events: &mut Vec<(Option<PlayerId>, GameEvent)>) { 284 + if let Some(host) = self.host.as_mut() { 285 + let now = Utc::now(); 286 + 287 + // Do seekers need to be released? 288 + if self.public.seekers_started.is_none() 289 + && (now - self.public.game_started) 290 + .num_seconds() 291 + .unsigned_abs() 292 + >= self.settings.hiding_time_seconds 293 + { 294 + events.push((None, GameEvent::SeekersReleased(now))); 295 + } 296 + 297 + // Do we need to start doing global pings? 298 + if host.last_ping.is_none() { 299 + let should_start = match self.settings.ping_start { 300 + PingStartCondition::Players(players) => { 301 + self.public.caught_state.values().filter(|v| **v).count() 302 + >= (players as usize) 303 + } 304 + PingStartCondition::Minutes(min) => { 305 + let delta = now - self.public.game_started; 306 + delta.num_minutes() >= (min as i64) 307 + } 308 + PingStartCondition::Instant => true, 309 + }; 310 + if should_start { 311 + host.last_ping = Some(now); 312 + } 313 + } 314 + 315 + // Do we need to do a global ping? 316 + if let Some(last_ping) = host.last_ping.as_mut() { 317 + if (now - *last_ping).num_minutes().unsigned_abs() 318 + >= self.settings.ping_minutes_interval 319 + { 320 + events.extend(self.public.caught_state.iter().filter_map( 321 + |(player, caught)| { 322 + // If caught, don't send a ping request 323 + if *caught { 324 + None 325 + } else { 326 + // If the player is pinging as someone else, do that here. 327 + if let Some(PowerUpUsage::PingSeeker) = 328 + host.ping_power_usages.get(player) 329 + { 330 + host.ping_power_usages.remove(player); 331 + let seekers = self.public.iter_seekers().collect::<Vec<_>>(); 332 + let choice = rand::random_range(0..seekers.len()); 333 + let seeker = seekers[choice]; 334 + return Some((Some(seeker), GameEvent::PingReq(Some(*player)))); 335 + } 336 + Some((Some(*player), GameEvent::PingReq(None))) 337 + } 338 + }, 339 + )); 340 + 341 + *last_ping = now; 342 + } 343 + } 344 + 345 + // Do we need to start rolling for powerups? 346 + if host.last_powerup_proc.is_none() { 347 + let should_start = match self.settings.ping_start { 348 + PingStartCondition::Players(players) => { 349 + self.public.caught_state.values().filter(|v| **v).count() 350 + >= (players as usize) 351 + } 352 + PingStartCondition::Minutes(min) => { 353 + let delta = now - self.public.game_started; 354 + delta.num_minutes() >= (min as i64) 355 + } 356 + PingStartCondition::Instant => true, 357 + }; 358 + if should_start { 359 + host.last_powerup_proc = Some(now); 360 + } 361 + } 362 + 363 + // Should we roll for a powerup? 364 + if let Some(last_powerup_proc) = host.last_powerup_proc.as_mut() { 365 + if (now - *last_powerup_proc).num_minutes() >= 1 { 366 + // A minute has passed, roll to see if we should spawn a powerup 367 + let cooldown_over = host.last_powerup.is_none_or(|d| { 368 + (now - d).num_minutes() >= (self.settings.powerup_minutes_cooldown as i64) 369 + }); 370 + let roll = rand::random_ratio(self.settings.powerup_chance, 100); 371 + 372 + if cooldown_over && roll { 373 + // Cooldown is over and we rolled positive, choose and send out a powerup. 374 + let typ_choice = rand::random_range(0..PowerUpType::ALL_TYPES.len()); 375 + let loc_choice = 376 + rand::random_range(0..self.settings.powerup_locations.len()); 377 + let powerup = PowerUp::new( 378 + self.settings.powerup_locations[loc_choice], 379 + PowerUpType::ALL_TYPES[typ_choice], 380 + ); 381 + 382 + events.push((None, GameEvent::PowerUpSpawn(powerup))); 383 + 384 + host.last_powerup = Some(now); 385 + } 386 + 387 + *last_powerup_proc = now; 388 + } 389 + } 390 + } 391 + } 392 + 393 + fn update_loc(&mut self) { 394 + let loc = self.loc.get_loc(); 395 + self.player.push_loc(loc); 396 + } 397 + 398 + /// Run a single game tick, returns any messages that need to be sent 399 + pub fn tick(&mut self) -> Vec<(Option<PlayerId>, GameEvent)> { 400 + let mut events = Vec::with_capacity(5); 401 + 402 + self.host_tick(&mut events); 403 + self.update_loc(); 404 + 405 + events 406 + } 407 + 408 + /// Consume an event, optionally returns events to re-broadcast 409 + pub fn consume_event( 410 + &mut self, 411 + time_sent: DT, 412 + event: GameEvent, 413 + player_id: PlayerId, 414 + ) -> Option<GameEvent> { 415 + if let Some(host) = self.host.as_mut() { 416 + host.event_history 417 + .push((player_id, time_sent, event.clone())); 418 + } 419 + 420 + match event { 421 + GameEvent::SeekersReleased(time) => { 422 + self.public.seekers_started = Some(time); 423 + } 424 + GameEvent::PingReq(fake_player) => { 425 + let ping = if let Some(fake_player) = fake_player { 426 + self.player.create_ping(fake_player) 427 + } else { 428 + self.player.create_self_ping() 429 + }; 430 + 431 + return ping.map(|p| GameEvent::Ping(p)); 432 + } 433 + GameEvent::Ping(ping) => { 434 + if let Some(current) = self.public.pings.get_mut(&ping.player) { 435 + *current = Some(ping); 436 + } 437 + } 438 + GameEvent::HiderCaught(id) => { 439 + if id == self.player.id { 440 + self.player.seeker = true; 441 + } 442 + if let Some(state) = self.public.caught_state.get_mut(&id) { 443 + *state = true; 444 + } 445 + if self.host.is_some() && self.public.caught_state.iter().all(|(_, k)| *k) { 446 + return Some(GameEvent::GameEnd(Utc::now())); 447 + } 448 + } 449 + GameEvent::GameEnd(_dt) => { 450 + // [Game] handles this case, do nothing if we get here. 451 + } 452 + GameEvent::PowerUpSpawn(power_up) => { 453 + self.public.available_powerup = Some(power_up); 454 + } 455 + GameEvent::PowerUpDespawn => { 456 + self.public.available_powerup = None; 457 + } 458 + GameEvent::PowerUpActivate(usage) => { 459 + if usage.timing() == PowerUpTiming::NextPing { 460 + if let Some(host) = self.host.as_mut() { 461 + if let Some(old_usage) = host.ping_power_usages.get_mut(&player_id) { 462 + *old_usage = usage; 463 + } else { 464 + host.ping_power_usages.insert(player_id, usage); 465 + } 466 + } 467 + } 468 + } 469 + GameEvent::PostGameSync(_) | GameEvent::HostHistorySync(_) => { 470 + // Handled by [Game] 471 + } 472 + } 473 + None 474 + } 475 + }
+80 -78
flake.lock
··· 1 1 { 2 - "nodes": { 3 - "flakelight": { 4 - "inputs": { 5 - "nixpkgs": "nixpkgs" 6 - }, 7 - "locked": { 8 - "lastModified": 1746449252, 9 - "narHash": "sha256-dFGAaYhaaDTfh08wetspJXt6KedYZwsfFpxZ68k9Qds=", 10 - "owner": "nix-community", 11 - "repo": "flakelight", 12 - "rev": "d156dc871b3cdbe0b52169c4bc5171377a9bd6e0", 13 - "type": "github" 14 - }, 15 - "original": { 16 - "owner": "nix-community", 17 - "repo": "flakelight", 18 - "type": "github" 19 - } 20 - }, 21 - "nixpkgs": { 22 - "locked": { 23 - "lastModified": 1746328495, 24 - "narHash": "sha256-uKCfuDs7ZM3QpCE/jnfubTg459CnKnJG/LwqEVEdEiw=", 25 - "owner": "NixOS", 26 - "repo": "nixpkgs", 27 - "rev": "979daf34c8cacebcd917d540070b52a3c2b9b16e", 28 - "type": "github" 29 - }, 30 - "original": { 31 - "owner": "NixOS", 32 - "ref": "nixos-unstable", 33 - "repo": "nixpkgs", 34 - "type": "github" 35 - } 36 - }, 37 - "nixpkgs_2": { 38 - "locked": { 39 - "lastModified": 1746397377, 40 - "narHash": "sha256-5oLdRa3vWSRbuqPIFFmQBGGUqaYZBxX+GGtN9f/n4lU=", 41 - "owner": "NixOS", 42 - "repo": "nixpkgs", 43 - "rev": "ed30f8aba41605e3ab46421e3dcb4510ec560ff8", 44 - "type": "github" 45 - }, 46 - "original": { 47 - "owner": "NixOS", 48 - "ref": "nixpkgs-unstable", 49 - "repo": "nixpkgs", 50 - "type": "github" 51 - } 52 - }, 53 - "root": { 54 - "inputs": { 55 - "flakelight": "flakelight", 56 - "nixpkgs": "nixpkgs_2", 57 - "rust-overlay": "rust-overlay" 58 - } 59 - }, 60 - "rust-overlay": { 61 - "inputs": { 62 - "nixpkgs": ["nixpkgs"] 63 - }, 64 - "locked": { 65 - "lastModified": 1746498961, 66 - "narHash": "sha256-rp+oh/N88JKHu7ySPuGiA3lBUVIsrOtHbN2eWJdYCgk=", 67 - "owner": "oxalica", 68 - "repo": "rust-overlay", 69 - "rev": "24b00064cdd1d7ba25200c4a8565dc455dc732ba", 70 - "type": "github" 71 - }, 72 - "original": { 73 - "owner": "oxalica", 74 - "repo": "rust-overlay", 75 - "type": "github" 76 - } 77 - } 2 + "nodes": { 3 + "flakelight": { 4 + "inputs": { 5 + "nixpkgs": "nixpkgs" 6 + }, 7 + "locked": { 8 + "lastModified": 1748868585, 9 + "narHash": "sha256-DrrbahOQAwvNM8l5EuGxxkVS7X5/S59zcG0N9ZWQFhk=", 10 + "owner": "nix-community", 11 + "repo": "flakelight", 12 + "rev": "dfbecd12d99c1bf82906521a6a7d5b75d2aa1ca2", 13 + "type": "github" 14 + }, 15 + "original": { 16 + "owner": "nix-community", 17 + "repo": "flakelight", 18 + "type": "github" 19 + } 78 20 }, 79 - "root": "root", 80 - "version": 7 21 + "nixpkgs": { 22 + "locked": { 23 + "lastModified": 1748693115, 24 + "narHash": "sha256-StSrWhklmDuXT93yc3GrTlb0cKSS0agTAxMGjLKAsY8=", 25 + "owner": "NixOS", 26 + "repo": "nixpkgs", 27 + "rev": "910796cabe436259a29a72e8d3f5e180fc6dfacc", 28 + "type": "github" 29 + }, 30 + "original": { 31 + "owner": "NixOS", 32 + "ref": "nixos-unstable", 33 + "repo": "nixpkgs", 34 + "type": "github" 35 + } 36 + }, 37 + "nixpkgs_2": { 38 + "locked": { 39 + "lastModified": 1748792178, 40 + "narHash": "sha256-BHmgfHlCJVNisJShVaEmfDIr/Ip58i/4oFGlD1iK6lk=", 41 + "owner": "NixOS", 42 + "repo": "nixpkgs", 43 + "rev": "5929de975bcf4c7c8d8b5ca65c8cd9ef9e44523e", 44 + "type": "github" 45 + }, 46 + "original": { 47 + "owner": "NixOS", 48 + "ref": "nixpkgs-unstable", 49 + "repo": "nixpkgs", 50 + "type": "github" 51 + } 52 + }, 53 + "root": { 54 + "inputs": { 55 + "flakelight": "flakelight", 56 + "nixpkgs": "nixpkgs_2", 57 + "rust-overlay": "rust-overlay" 58 + } 59 + }, 60 + "rust-overlay": { 61 + "inputs": { 62 + "nixpkgs": [ 63 + "nixpkgs" 64 + ] 65 + }, 66 + "locked": { 67 + "lastModified": 1748832016, 68 + "narHash": "sha256-TQSaFa1wWJr6GOs+K8lecK4AKKr8k6mwxHIPCOmVkgs=", 69 + "owner": "oxalica", 70 + "repo": "rust-overlay", 71 + "rev": "7ec2ea005b600dac9436a7c5c6b66d960cbfcea2", 72 + "type": "github" 73 + }, 74 + "original": { 75 + "owner": "oxalica", 76 + "repo": "rust-overlay", 77 + "type": "github" 78 + } 79 + } 80 + }, 81 + "root": "root", 82 + "version": 7 81 83 }
+61 -66
flake.nix
··· 5 5 rust-overlay.url = "github:oxalica/rust-overlay"; 6 6 rust-overlay.inputs.nixpkgs.follows = "nixpkgs"; 7 7 }; 8 - outputs = { flakelight, ... } @ inputs: 8 + outputs = {flakelight, ...} @ inputs: 9 9 flakelight ./. { 10 10 inherit inputs; 11 - withOverlays = [ inputs.rust-overlay.overlays.default ]; 11 + withOverlays = [inputs.rust-overlay.overlays.default]; 12 12 nixpkgs.config = { 13 13 allowUnfree = true; 14 14 android_sdk.accept_license = true; 15 15 }; 16 16 17 - formatters = 18 - let 19 - forAllTypes = cmd: types: 20 - builtins.listToAttrs (builtins.map 21 - (t: { 22 - name = "*.${t}"; 23 - value = cmd; 24 - }) 25 - types); 26 - in 17 + formatters = let 18 + forAllTypes = cmd: types: 19 + builtins.listToAttrs (builtins.map 20 + (t: { 21 + name = "*.${t}"; 22 + value = cmd; 23 + }) 24 + types); 25 + in 27 26 { 28 27 "*.rs" = "cd backend; cargo fmt"; 29 28 } 30 - // (forAllTypes "prettier --write ." [ "ts" "tsx" "md" "json" ]); 31 - devShell = pkgs: 32 - let 33 - buildToolsVersion = "34.0.0"; 34 - androidComposition = pkgs.androidenv.composeAndroidPackages { 35 - platformVersions = [ 36 - "34" 37 - "latest" 38 - ]; 39 - systemImageTypes = [ "google_apis_playstore" ]; 40 - buildToolsVersions = [ buildToolsVersion ]; 41 - abiVersions = [ 42 - "armeabi-v7a" 43 - "arm64-v8a" 44 - "x86_64" 45 - ]; 46 - includeNDK = true; 47 - includeExtras = [ 48 - "extras;google;auto" 49 - ]; 50 - }; 51 - in 52 - { 53 - shellHook = 54 - let 55 - ANDROID_HOME = "${androidComposition.androidsdk}/libexec/android-sdk"; 56 - in 57 - '' 58 - export XDG_DATA_DIRS="$GSETTINGS_SCHEMAS_PATH" 59 - export GIO_EXTRA_MODULES="${pkgs.dconf.lib}/lib/gio/modules:${pkgs.glib-networking}/lib/gio/modules" 60 - export ANDROID_HOME=${ANDROID_HOME} 61 - export NDK_HOME="${androidComposition.androidsdk}/libexec/android-sdk/ndk/${builtins.head (pkgs.lib.lists.reverseList (builtins.split "-" "${androidComposition.ndk-bundle}"))}" 62 - export GRADLE_OPTS="-Dorg.gradle.project.android.aapt2FromMavenOverride=${ANDROID_HOME}/build-tools/${buildToolsVersion}/aapt2" 63 - ''; 64 - packages = with pkgs; [ 65 - at-spi2-atk 66 - atkmm 67 - cairo 68 - gdk-pixbuf 69 - glib 70 - gtk3 71 - harfbuzz 72 - librsvg 73 - libsoup_3 74 - pango 75 - webkitgtk_4_1 76 - openssl 77 - pkg-config 78 - gobject-introspection 79 - nodePackages.prettier 80 - (rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override { targets = [ "aarch64-linux-android" "armv7-linux-androideabi" "i686-linux-android" "x86_64-linux-android" ]; })) 81 - cargo-tauri 82 - nodejs 83 - (android-studio.withSdk androidComposition.androidsdk) 29 + // (forAllTypes "prettier --write ." ["ts" "tsx" "md" "json"]); 30 + devShell = pkgs: let 31 + buildToolsVersion = "34.0.0"; 32 + androidComposition = pkgs.androidenv.composeAndroidPackages { 33 + platformVersions = [ 34 + "34" 35 + "latest" 36 + ]; 37 + systemImageTypes = ["google_apis_playstore"]; 38 + buildToolsVersions = [buildToolsVersion]; 39 + abiVersions = [ 40 + "armeabi-v7a" 41 + "arm64-v8a" 42 + "x86_64" 43 + ]; 44 + includeNDK = true; 45 + includeExtras = [ 46 + "extras;google;auto" 84 47 ]; 85 48 }; 49 + in { 50 + shellHook = let 51 + ANDROID_HOME = "${androidComposition.androidsdk}/libexec/android-sdk"; 52 + in '' 53 + export XDG_DATA_DIRS="$GSETTINGS_SCHEMAS_PATH" 54 + export GIO_EXTRA_MODULES="${pkgs.dconf.lib}/lib/gio/modules:${pkgs.glib-networking}/lib/gio/modules" 55 + export ANDROID_HOME=${ANDROID_HOME} 56 + export NDK_HOME="${androidComposition.androidsdk}/libexec/android-sdk/ndk/${builtins.head (pkgs.lib.lists.reverseList (builtins.split "-" "${androidComposition.ndk-bundle}"))}" 57 + export GRADLE_OPTS="-Dorg.gradle.project.android.aapt2FromMavenOverride=${ANDROID_HOME}/build-tools/${buildToolsVersion}/aapt2" 58 + ''; 59 + packages = with pkgs; [ 60 + at-spi2-atk 61 + atkmm 62 + cairo 63 + gdk-pixbuf 64 + glib 65 + gtk3 66 + harfbuzz 67 + librsvg 68 + libsoup_3 69 + pango 70 + webkitgtk_4_1 71 + openssl 72 + pkg-config 73 + gobject-introspection 74 + nodePackages.prettier 75 + (rust-bin.stable.latest.default.override {targets = ["aarch64-linux-android" "armv7-linux-androideabi" "i686-linux-android" "x86_64-linux-android"];}) 76 + cargo-tauri 77 + nodejs 78 + (android-studio.withSdk androidComposition.androidsdk) 79 + ]; 80 + }; 86 81 }; 87 82 }