diff --git a/Cargo.lock b/Cargo.lock index 645bd96..78977f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,9 +45,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arbitrary" @@ -176,9 +176,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -203,9 +203,9 @@ checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" dependencies = [ "serde", ] @@ -276,9 +276,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.17" +version = "1.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" dependencies = [ "jobserver", "libc", @@ -333,9 +333,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -434,9 +434,9 @@ checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "pem-rfc7468", @@ -445,9 +445,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", ] @@ -509,9 +509,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", @@ -558,6 +558,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", + "libz-rs-sys", "miniz_oxide", ] @@ -699,9 +700,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -710,9 +711,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "js-sys", @@ -730,9 +731,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "git2" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5220b8ba44c68a9a7f7a7659e864dd73692e417ef0211bea133c7b74e031eeb9" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" dependencies = [ "bitflags", "libc", @@ -745,9 +746,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" dependencies = [ "atomic-waker", "bytes", @@ -770,9 +771,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", @@ -785,7 +786,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] [[package]] @@ -917,21 +918,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -940,31 +942,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -972,67 +954,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "idna" version = "1.0.3" @@ -1046,9 +1015,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -1056,12 +1025,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] [[package]] @@ -1095,7 +1064,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", ] @@ -1112,13 +1081,12 @@ dependencies = [ [[package]] name = "kcp" version = "0.1.0" +source = "git+https://git.xeondev.com/ReversedRoomsMisc/kcp-rs.git#607a9c8b8a7542d0ff5fca9586ba8331f508186c" dependencies = [ "bytes", - "log", - "rand 0.8.5", - "thiserror 1.0.69", - "time", + "thiserror 2.0.12", "tokio", + "tracing", ] [[package]] @@ -1132,9 +1100,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libgit2-sys" @@ -1152,15 +1120,15 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libmimalloc-sys" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b20daca3a4ac14dbdc753c5e90fc7b490a48a9131daed3c9a9ced7b2defd37b" +checksum = "ec9d6fac27761dabcd4ee73571cdb06b7022dc99089acbe5435691edffaac0f4" dependencies = [ "cc", "libc", @@ -1190,6 +1158,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libz-rs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a" +dependencies = [ + "zlib-rs", +] + [[package]] name = "libz-sys" version = "1.1.22" @@ -1204,15 +1181,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" @@ -1224,12 +1201,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - [[package]] name = "log" version = "0.4.27" @@ -1290,9 +1261,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mimalloc" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03cb1f88093fe50061ca1195d336ffec131347c7b833db31f9ab62a2d1b7925f" +checksum = "995942f432bbb4822a7e9c3faa87a695185b0d09273ba85f097b54f4e458f2af" dependencies = [ "libmimalloc-sys", ] @@ -1315,9 +1286,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -1335,9 +1306,9 @@ dependencies = [ [[package]] name = "multimap" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] name = "nu-ansi-term" @@ -1425,9 +1396,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.106" +version = "0.9.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" dependencies = [ "cc", "libc", @@ -1550,6 +1521,15 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1567,9 +1547,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.31" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" dependencies = [ "proc-macro2", "syn", @@ -1577,9 +1557,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -1664,13 +1644,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy", ] [[package]] @@ -1699,7 +1678,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -1708,7 +1687,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] @@ -1743,9 +1722,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ "bitflags", ] @@ -1802,7 +1781,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -1836,9 +1815,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags", "errno", @@ -1849,9 +1828,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.25" +version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "log", "once_cell", @@ -1873,15 +1852,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] [[package]] name = "rustls-webpki" -version = "0.103.1" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "ring", "rustls-pki-types", @@ -1993,9 +1975,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -2019,9 +2001,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -2053,9 +2035,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" dependencies = [ "serde", ] @@ -2091,9 +2073,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f" +checksum = "f3c3a85280daca669cfd3bcb68a337882a8bc57ec882f72c5d13a430613a738e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2104,10 +2086,11 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0" +checksum = "f743f2a3cea30a58cd479013f75550e879009e3a02f616f18ca699335aa248c3" dependencies = [ + "base64", "bytes", "crc", "crossbeam-queue", @@ -2117,7 +2100,7 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "hashlink", "indexmap", "log", @@ -2125,7 +2108,6 @@ dependencies = [ "once_cell", "percent-encoding", "rustls", - "rustls-pemfile", "serde", "serde_json", "sha2", @@ -2135,14 +2117,14 @@ dependencies = [ "tokio-stream", "tracing", "url", - "webpki-roots", + "webpki-roots 0.26.11", ] [[package]] name = "sqlx-macros" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310" +checksum = "7f4200e0fde19834956d4252347c12a083bdcb237d7a1a1446bffd8768417dce" dependencies = [ "proc-macro2", "quote", @@ -2153,9 +2135,9 @@ dependencies = [ [[package]] name = "sqlx-macros-core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad" +checksum = "882ceaa29cade31beca7129b6beeb05737f44f82dbe2a9806ecea5a7093d00b7" dependencies = [ "dotenvy", "either", @@ -2179,9 +2161,9 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233" +checksum = "0afdd3aa7a629683c2d750c2df343025545087081ab5942593a5288855b1b7a7" dependencies = [ "atoi", "base64", @@ -2221,9 +2203,9 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613" +checksum = "a0bedbe1bbb5e2615ef347a5e9d8cd7680fb63e77d9dafc0f29be15e53f1ebe6" dependencies = [ "atoi", "base64", @@ -2258,9 +2240,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540" +checksum = "c26083e9a520e8eb87a06b12347679b142dc2ea29e6e409f805644a7a979a5bc" dependencies = [ "atoi", "flume", @@ -2275,6 +2257,7 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", + "thiserror 2.0.12", "tracing", "url", ] @@ -2304,9 +2287,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -2321,9 +2304,9 @@ checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", @@ -2332,12 +2315,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", "rustix", "windows-sys 0.59.0", @@ -2414,9 +2397,9 @@ checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -2439,9 +2422,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.44.1" +version = "1.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" dependencies = [ "backtrace", "bytes", @@ -2479,9 +2462,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -2493,9 +2476,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -2505,26 +2488,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "tower" version = "0.5.2" @@ -2543,9 +2533,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" +checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" dependencies = [ "bitflags", "bytes", @@ -2696,9 +2686,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "3.0.10" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0351ca625c7b41a8e4f9bb6c5d9755f67f62c2187ebedecacd9974674b271d" +checksum = "b7a3e9af6113ecd57b8c63d3cd76a385b2e3881365f1f489e54f49801d0c83ea" dependencies = [ "base64", "flate2", @@ -2709,14 +2699,14 @@ dependencies = [ "rustls-pki-types", "ureq-proto", "utf-8", - "webpki-roots", + "webpki-roots 0.26.11", ] [[package]] name = "ureq-proto" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae239d0a3341aebc94259414d1dc67cfce87d41cbebc816772c91b77902fafa4" +checksum = "fadf18427d33828c311234884b7ba2afb57143e6e7e69fda7ee883b624661e36" dependencies = [ "base64", "http", @@ -2741,12 +2731,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -2759,7 +2743,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] @@ -2860,9 +2844,18 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.8" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.0", +] + +[[package]] +name = "webpki-roots" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" dependencies = [ "rustls-pki-types", ] @@ -2941,7 +2934,7 @@ dependencies = [ "hex", "indexmap", "paste", - "rand 0.9.0", + "rand 0.9.1", "serde", "thiserror 1.0.69", "tokio", @@ -3033,7 +3026,7 @@ dependencies = [ [[package]] name = "wicked-waifus-protocol" version = "0.1.0" -source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#75096f1a9810546b0152c12e902378455ce2c269" +source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#6f2733c09b78a6e874f379254c9b71fbef23c3a0" dependencies = [ "byteorder", "crc32fast", @@ -3051,7 +3044,7 @@ dependencies = [ [[package]] name = "wicked-waifus-protocol-derive" version = "0.1.0" -source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#75096f1a9810546b0152c12e902378455ce2c269" +source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#6f2733c09b78a6e874f379254c9b71fbef23c3a0" dependencies = [ "proc-macro2", "quote", @@ -3265,9 +3258,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.4" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] @@ -3281,17 +3274,11 @@ dependencies = [ "bitflags", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "xz2" @@ -3304,9 +3291,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -3316,9 +3303,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", @@ -3328,18 +3315,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", @@ -3415,10 +3402,21 @@ dependencies = [ ] [[package]] -name = "zerovec" -version = "0.10.4" +name = "zerotrie" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -3427,9 +3425,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", @@ -3438,19 +3436,18 @@ dependencies = [ [[package]] name = "zip" -version = "2.5.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c03817464f64e23f6f37574b4fdc8cf65925b5bfd2b0f2aedf959791941f88" +checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308" dependencies = [ "aes", "arbitrary", "bzip2", "constant_time_eq", "crc32fast", - "crossbeam-utils", "deflate64", "flate2", - "getrandom 0.3.2", + "getrandom 0.3.3", "hmac", "indexmap", "lzma-rs", @@ -3466,26 +3463,30 @@ dependencies = [ [[package]] name = "zip-extract" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a8c9e90f27d1435088a7b540b6cc8ae6ee525d992a695f16012d2f365b3d3c" +checksum = "db6d94e397dd6d0273e6747e46e7aa0289bfd9736ba8772f2fe948bc4adc3f73" dependencies = [ "log", - "thiserror 1.0.69", + "thiserror 2.0.12", "zip", ] [[package]] -name = "zopfli" -version = "0.8.1" +name = "zlib-rs" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8" + +[[package]] +name = "zopfli" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" dependencies = [ "bumpalo", "crc32fast", - "lockfree-object-pool", "log", - "once_cell", "simd-adler32", ] diff --git a/Cargo.toml b/Cargo.toml index 699b7ec..684d628 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["wicked-waifus-asset-updater", "wicked-waifus-commons", "wicked-waifus-config-server", "wicked-waifus-hotpatch-server", "wicked-waifus-login-server", "wicked-waifus-gateway-server", "wicked-waifus-gateway-server/kcp", "wicked-waifus-database", "wicked-waifus-http", "wicked-waifus-protokey", "wicked-waifus-protocol-internal", "wicked-waifus-game-server", "wicked-waifus-network", "wicked-waifus-data"] +members = ["wicked-waifus-asset-updater", "wicked-waifus-commons", "wicked-waifus-config-server", "wicked-waifus-hotpatch-server", "wicked-waifus-login-server", "wicked-waifus-gateway-server", "wicked-waifus-database", "wicked-waifus-http", "wicked-waifus-protokey", "wicked-waifus-protocol-internal", "wicked-waifus-game-server", "wicked-waifus-network", "wicked-waifus-data"] resolver = "2" [workspace.package] @@ -46,7 +46,6 @@ tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } # Internal -kcp = { path = "wicked-waifus-gateway-server/kcp" } wicked-waifus-asset-updater = { path = "wicked-waifus-asset-updater" } wicked-waifus-commons = { path = "wicked-waifus-commons" } wicked-waifus-http = { path = "wicked-waifus-http" } diff --git a/wicked-waifus-config-server/configserver.default.toml b/wicked-waifus-config-server/configserver.default.toml index 67ac32a..99b3b7a 100644 --- a/wicked-waifus-config-server/configserver.default.toml +++ b/wicked-waifus-config-server/configserver.default.toml @@ -11,5 +11,5 @@ serve_dir_path = "data/assets/config-server" [asset_config] repository_url = "https://git.xeondev.com/wickedwaifus/wicked-waifus-config-server-files.git" -reference = "8f109f2724" +reference = "f088e91db3" discard_local_changes = true \ No newline at end of file diff --git a/wicked-waifus-data/src/base_property.rs b/wicked-waifus-data/src/base_property.rs index 362518f..2ab652b 100644 --- a/wicked-waifus-data/src/base_property.rs +++ b/wicked-waifus-data/src/base_property.rs @@ -47,21 +47,6 @@ pub struct BasePropertyData { pub damage_reduce_element4: i32, pub damage_reduce_element5: i32, pub damage_reduce_element6: i32, - pub reaction_change1: i32, - pub reaction_change2: i32, - pub reaction_change3: i32, - pub reaction_change4: i32, - pub reaction_change5: i32, - pub reaction_change6: i32, - pub reaction_change7: i32, - pub reaction_change8: i32, - pub reaction_change9: i32, - pub reaction_change10: i32, - pub reaction_change11: i32, - pub reaction_change12: i32, - pub reaction_change13: i32, - pub reaction_change14: i32, - pub reaction_change15: i32, pub energy_max: i32, pub energy: i32, pub special_energy_1_max: i32, diff --git a/wicked-waifus-data/src/lib.rs b/wicked-waifus-data/src/lib.rs index c47505b..c92daf1 100644 --- a/wicked-waifus-data/src/lib.rs +++ b/wicked-waifus-data/src/lib.rs @@ -149,6 +149,7 @@ json_data! { RoleInfo; RoleLevelConsume; RolePropertyGrowth; + RoleSkin; SilentAreaDetection; SynthesisFormula; Teleporter; diff --git a/wicked-waifus-data/src/misc_data.rs b/wicked-waifus-data/src/misc_data.rs index 27a8f75..e721665 100644 --- a/wicked-waifus-data/src/misc_data.rs +++ b/wicked-waifus-data/src/misc_data.rs @@ -68,6 +68,8 @@ pub enum GachaViewTypeInfoId { StandardResonatorConvene = 4, StandardWeaponConvene = 5, BeginnersChoiceConvene = 6, + MultipleChoiceResonatorConvene = 7, + MultipleChoiceWeaponConvene = 8, } #[derive(Debug, Deserialize, Clone)] @@ -120,6 +122,7 @@ pub enum EntityType { ControlConnector, ConveyorBelt, CookTool, + CurveControlDestructible, CustomAoiEditor, Destructible, DestructibleControl, @@ -132,6 +135,7 @@ pub enum EntityType { DynamicPortalCreater, EffectArea, EnrichmentArea, + EntityBatchRefresh, EntityBundle, EntityList, EntityPackage, @@ -163,6 +167,7 @@ pub enum EntityType { LevelPlay, LevelPlayReward, LevelQteTrigger, + LevelSeqTrigger, LevitateMagnet, LifePointCenter, Lift, @@ -202,16 +207,19 @@ pub enum EntityType { SimpleInteract, SimpleNPc, SkyboxTrigger, + SlideRail, SoundBox, SpawnMonster, SpawnPasserbyNpc, Spline, + SplineRange, SummonGongduolaPoint, StateSceneItem, StateTrigger, StatueFoundation, SuiGuangHook, TargetGear, + TargetGear2, TargetGearGroup, TargetGearGroup2, TargetGearPro, @@ -220,6 +228,7 @@ pub enum EntityType { TeleControl3, TeleControlGroup, Teleporter, + TemplateEntitySpawner, TemporaryTeleporter, TimedStrikeDevice, TimelineTrackController, diff --git a/wicked-waifus-data/src/node_data/mod.rs b/wicked-waifus-data/src/node_data/mod.rs index d93e15c..622b4dc 100644 --- a/wicked-waifus-data/src/node_data/mod.rs +++ b/wicked-waifus-data/src/node_data/mod.rs @@ -217,6 +217,15 @@ pub struct NodeDataDetailAction { pub actions: Vec, } +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct NodeDataDetailActionWithResult { + #[serde(flatten)] + pub common: NodeDataDetailCommon, + pub action: Action, +} + #[derive(Debug, Deserialize)] #[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] @@ -258,6 +267,7 @@ pub enum NodeDataDetail { Repeater(NodeDataDetailRepeater), Condition(NodeDataDetailCondition), Action(NodeDataDetailAction), + ActionWithResult(NodeDataDetailActionWithResult), QuestSucceed(NodeDataDetailQuestSucceed), QuestFailed(NodeDataDetailQuestFailed), AlwaysFalse(NodeDataDetailAlways), diff --git a/wicked-waifus-data/src/pb_components/action.rs b/wicked-waifus-data/src/pb_components/action.rs index 5a983bb..8b9395d 100644 --- a/wicked-waifus-data/src/pb_components/action.rs +++ b/wicked-waifus-data/src/pb_components/action.rs @@ -196,7 +196,8 @@ pub enum LeisureInteractOption { FailurePose, GameplayPose1, GameplayPose2, - GameplayPose3 + GameplayPose3, + FaithJump } #[derive(Deserialize, Debug, Clone)] @@ -508,6 +509,11 @@ pub struct CameraLookAt { pub camera_pos: Option, } +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct StopCameraLookAt {} + #[derive(Deserialize, Debug, Clone)] #[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase")] @@ -2257,6 +2263,94 @@ pub struct ActiveAntiGravitySafePoint { pub config: serde_json::Value, } +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BvbPlayDialog { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BvbSendSystemEvent { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BvbSendAiEvent { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BvbPlayerOperationConstraint { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ExecClientBattleAction { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct TriggerSpecificScanEffect { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SetActorVar { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RunActorCustomEvent { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct StopUiScreenEffect { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct StopNewMoveWithSpline { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RequestSystemFunction { + #[cfg(feature = "strict_json_fields")] + pub config: serde_json::Value, +} + #[derive(Deserialize, Debug, Clone)] #[serde(tag = "Name")] pub enum Action { @@ -2279,6 +2373,7 @@ pub enum Action { TeleportDungeon(ActionFields), DestroySelf(ActionFields), CameraLookAt(ActionFields), + StopCameraLookAt(ActionFields), EnterOrbitalCamera(ActionFields), ExitOrbitalCamera(ActionFields), SendAiEvent(ActionFields), @@ -2432,6 +2527,17 @@ pub enum Action { GetRewardByInteract(ActionFields), OpenQte(ActionFields), ActiveAntiGravitySafePoint(ActionFields), + BvbPlayDialog(ActionFields), + BvbSendSystemEvent(ActionFields), + BvbSendAiEvent(ActionFields), + BvbPlayerOperationConstraint(ActionFields), + ExecClientBattleAction(ActionFields), + TriggerSpecificScanEffect(ActionFields), + SetActorVar(ActionFields), + RunActorCustomEvent(ActionFields), + StopUiScreenEffect(ActionFields), + StopNewMoveWithSpline(ActionFields), + RequestSystemFunction(ActionFields), } #[derive(Deserialize, Debug, Clone)] diff --git a/wicked-waifus-data/src/pb_components/condition.rs b/wicked-waifus-data/src/pb_components/condition.rs index f9d9da3..3ef24cc 100644 --- a/wicked-waifus-data/src/pb_components/condition.rs +++ b/wicked-waifus-data/src/pb_components/condition.rs @@ -335,6 +335,7 @@ pub struct UsingVehicle { pub enum VehicleType { FishingBoat, Gongduola, + SceneItemAutoMoveVehicle, } #[derive(Deserialize, Debug, Clone)] @@ -757,6 +758,13 @@ pub struct AddFlowInteractOption { pub config: serde_json::Value, } +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct MonsterMergedHpBarSettings { + pub display_buff_ids: Vec, +} + #[derive(Deserialize, Debug, Clone)] #[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[serde(rename_all = "PascalCase", deny_unknown_fields)] @@ -765,6 +773,7 @@ pub struct MonsterCreator { pub prefab_var: Option, pub show_monster_merged_hp_bar: Option, pub tid_monster_group_name: Option, + pub monster_merged_hp_bar_settings: Option, } #[derive(Deserialize, Debug, Clone)] @@ -1135,6 +1144,60 @@ pub struct CheckEntityReward { pub UiType: serde_json::Value, } +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckIsGramophonePlayingMusic { + // TODO: + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckBVBEvent { + // TODO: + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct FinishBvbChallenge { + // TODO: + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareActorVarElement { + // TODO: ActorRef > PathName(String) + // pub var1: Var, + // pub compare: CompareType, + // pub var2: Var, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CompareActorVar { + pub conditions: Vec, + pub count: i32, +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct CheckDangoCultivationProgress { + // TODO: + #[cfg(feature = "strict_json_fields")] + pub UiType: serde_json::Value, +} + #[derive(Deserialize, Debug, Clone)] #[serde(tag = "Type")] pub enum Condition { @@ -1237,6 +1300,11 @@ pub enum Condition { CheckEntityGravityDirection(CheckEntityGravityDirection), CheckTeleControlState(CheckTeleControlState), CheckEntityReward(CheckEntityReward), + CheckIsGramophonePlayingMusic(CheckIsGramophonePlayingMusic), + CheckBVBEvent(CheckBVBEvent), + FinishBvbChallenge(FinishBvbChallenge), + CompareActorVar(CompareActorVar), + CheckDangoCultivationProgress(CheckDangoCultivationProgress), } #[derive(Deserialize, Debug, Clone)] diff --git a/wicked-waifus-data/src/pb_components/var.rs b/wicked-waifus-data/src/pb_components/var.rs index 867138c..6149555 100644 --- a/wicked-waifus-data/src/pb_components/var.rs +++ b/wicked-waifus-data/src/pb_components/var.rs @@ -91,6 +91,13 @@ pub struct SelfVar { pub name: String, } +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct System { + pub r#type: VarType, + // TODO: Add Var substruct +} #[derive(Deserialize, Debug, Clone)] #[serde(tag = "Source")] @@ -100,4 +107,5 @@ pub enum Var { Global(Global), #[serde(rename = "Self")] SelfVar(SelfVar), + System(System), } \ No newline at end of file diff --git a/wicked-waifus-data/src/role_skin.rs b/wicked-waifus-data/src/role_skin.rs new file mode 100644 index 0000000..a246d24 --- /dev/null +++ b/wicked-waifus-data/src/role_skin.rs @@ -0,0 +1,101 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct RoleSkinData { + pub id: i32, + pub role_id: i32, + pub suit_weapon_skin_id: i32, + pub head_id: i32, + pub quality_id: i32, + #[cfg(feature = "strict_json_fields")] + pub name: String, + #[cfg(feature = "strict_json_fields")] + pub title_name: String, + #[cfg(feature = "strict_json_fields")] + pub sub_dec_name: String, + #[cfg(feature = "strict_json_fields")] + pub type_description: String, + #[cfg(feature = "strict_json_fields")] + pub attributes_description: String, + #[cfg(feature = "strict_json_fields")] + pub bg_description: String, + #[cfg(feature = "strict_json_fields")] + pub icon_middle: String, + #[cfg(feature = "strict_json_fields")] + pub icon_small: String, + #[cfg(feature = "strict_json_fields")] + pub item_access: Vec, + #[cfg(feature = "strict_json_fields")] + pub sort_index: i32, + #[cfg(feature = "strict_json_fields")] + pub red_dot_disable_rule: i32, + #[cfg(feature = "strict_json_fields")] + pub show_in_bag: bool, + #[cfg(feature = "strict_json_fields")] + pub obtained_show_description: String, + #[cfg(feature = "strict_json_fields")] + pub icon: String, + #[cfg(feature = "strict_json_fields")] + pub function_desc: String, + #[cfg(feature = "strict_json_fields")] + pub first_obtain_desc: String, + #[cfg(feature = "strict_json_fields")] + pub quality: u8, + #[cfg(feature = "strict_json_fields")] + pub tag: String, + #[cfg(feature = "strict_json_fields")] + pub role_head_icon_circle: String, + #[cfg(feature = "strict_json_fields")] + pub role_head_icon_large: String, + #[cfg(feature = "strict_json_fields")] + pub role_head_icon_big: String, + #[cfg(feature = "strict_json_fields")] + pub card: String, + #[cfg(feature = "strict_json_fields")] + pub role_head_icon: String, + #[cfg(feature = "strict_json_fields")] + pub preview_role_card: String, + #[cfg(feature = "strict_json_fields")] + pub buy_shop_preview_role_card: String, + #[cfg(feature = "strict_json_fields")] + pub formation_role_card: String, + #[cfg(feature = "strict_json_fields")] + pub role_stand: String, + #[cfg(feature = "strict_json_fields")] + pub suit_weapon_skin_color: String, + #[cfg(feature = "strict_json_fields")] + pub role_obtain_color1: String, + #[cfg(feature = "strict_json_fields")] + pub role_obtain_color2: String, + #[cfg(feature = "strict_json_fields")] + pub role_portrait: String, + #[cfg(feature = "strict_json_fields")] + pub mesh_id: i32, + #[cfg(feature = "strict_json_fields")] + pub ui_mesh_id: i32, + #[cfg(feature = "strict_json_fields")] + pub role_body: String, + #[cfg(feature = "strict_json_fields")] + #[serde(rename = "UiScenePerformanceABP")] + pub ui_scene_performance_abp: String, + #[cfg(feature = "strict_json_fields")] + pub foot_step_state: String, + #[cfg(feature = "strict_json_fields")] + pub pay_shop_preview_role_texture_path: String, + #[cfg(feature = "strict_json_fields")] + pub pay_shop_preview_role_texture_bg_path: String, + #[cfg(feature = "strict_json_fields")] + pub pay_shop_preview_weapon_texture_path: String, + #[cfg(feature = "strict_json_fields")] + pub pay_shop_preview_buy_role_texture_path: String, + #[cfg(feature = "strict_json_fields")] + pub pay_shop_preview_buy_role_suit_weapon_texture_path: String, + #[cfg(feature = "strict_json_fields")] + pub share_texture_path: String, + #[cfg(feature = "strict_json_fields")] + pub spine_skeleton_data: String, + #[cfg(feature = "strict_json_fields")] + pub small_spine_atlas: String, +} diff --git a/wicked-waifus-game-server/gameserver.default.toml b/wicked-waifus-game-server/gameserver.default.toml index ffc50c9..c41f0b3 100644 --- a/wicked-waifus-game-server/gameserver.default.toml +++ b/wicked-waifus-game-server/gameserver.default.toml @@ -19,7 +19,7 @@ load_textmaps = true quadrant_size = 1000000 [asset_config] -asset_url = "https://git.xeondev.com/wickedwaifus/wicked-waifus-data/releases/download/pioneer_2.3.1/bundle.zip" +asset_url = "https://git.xeondev.com/wickedwaifus/wicked-waifus-data/releases/download/pioneer_2.4.1/bundle.zip" buffer_size = 268435456 [default_unlocks] diff --git a/wicked-waifus-game-server/src/logic/gacha/gacha_pool.rs b/wicked-waifus-game-server/src/logic/gacha/gacha_pool.rs index 6d6d19f..83b3a99 100644 --- a/wicked-waifus-game-server/src/logic/gacha/gacha_pool.rs +++ b/wicked-waifus-game-server/src/logic/gacha/gacha_pool.rs @@ -2,12 +2,10 @@ use rand::prelude::IndexedRandom; use rand::Rng; use wicked_waifus_protocol::{ErrorCode, GachaResult, GachaReward}; -use wicked_waifus_data::GachaViewTypeInfoId::{BeginnersChoiceConvene, - FeaturedResonatorConvene, - FeaturedWeaponConvene, - NoviceConvene, - StandardResonatorConvene, - StandardWeaponConvene, +use wicked_waifus_data::GachaViewTypeInfoId::{ + BeginnersChoiceConvene, FeaturedResonatorConvene, FeaturedWeaponConvene, + MultipleChoiceResonatorConvene, MultipleChoiceWeaponConvene, NoviceConvene, + StandardResonatorConvene, StandardWeaponConvene, }; use crate::logic::gacha::pool_info::PoolInfo; @@ -53,16 +51,23 @@ impl GachaPool { } } - pub fn pull(&mut self, - rng: &mut T, - player: &mut Player) -> Result { + pub fn pull( + &mut self, + rng: &mut T, + player: &mut Player, + ) -> Result { self.check_limits()?; let result = if (self.info.pool_type == BeginnersChoiceConvene) - && (self.info.pool_id > 50) && (self.info.pool_id < 60) { + && (self.info.pool_id > 50) + && (self.info.pool_id < 60) + { let item_id = self.info.guaranteed_character_id.unwrap(); GachaResult { - gacha_reward: Some(GachaReward { item_id, item_count: 1 }), + gacha_reward: Some(GachaReward { + item_id, + item_count: 1, + }), extra_rewards: self.calculate_extra_rewards(2), transform_rewards: Self::get_transform_rewards(player, item_id), bottom: None, @@ -84,13 +89,14 @@ impl GachaPool { }; item_id } - _ => { - self.get_random_item(rarity, rng) - } + _ => self.get_random_item(rarity, rng), }; self.update_pity(rarity); GachaResult { - gacha_reward: Some(GachaReward { item_id, item_count: 1 }), + gacha_reward: Some(GachaReward { + item_id, + item_count: 1, + }), extra_rewards: self.calculate_extra_rewards(rarity), transform_rewards: Self::get_transform_rewards(player, item_id), bottom: None, @@ -123,15 +129,29 @@ impl GachaPool { fn get_random_item(&self, rarity: usize, rng: &mut impl Rng) -> i32 { let items: &[i32] = match rarity { - 0 => &[21010013, 21020013, 21030013, 21040013, 21050013, 21010023, 21020023, 21030023, 21040023, 21050023, 21010043, 21020043, 21030043, 21040043, 21050043], + 0 => &[ + 21010013, 21020013, 21030013, 21040013, 21050013, 21010023, 21020023, 21030023, + 21040023, 21050023, 21010043, 21020043, 21030043, 21040043, 21050043, + ], 1 => match self.info.pool_type { - StandardWeaponConvene => &[21010024, 21020024, 21030024, 21040024, 21050024, 21010044, 21020044, 21030044, 21040044, 21050044, 21010064, 21020064, 21030064, 21040064, 21050064], - FeaturedResonatorConvene | FeaturedWeaponConvene => &self.info.rate_up_four_star[..], + StandardWeaponConvene => &[ + 21010024, 21020024, 21030024, 21040024, 21050024, 21010044, 21020044, 21030044, + 21040044, 21050044, 21010064, 21020064, 21030064, 21040064, 21050064, + ], + FeaturedResonatorConvene | FeaturedWeaponConvene => { + &self.info.rate_up_four_star[..] + } _ => &[1303, 1602, 1102, 1204, 1403, 1103, 1402, 1202, 1601], }, 2 => match self.info.pool_type { NoviceConvene | StandardResonatorConvene => &[1405, 1301, 1503, 1104, 1203], - FeaturedResonatorConvene | FeaturedWeaponConvene | StandardWeaponConvene | BeginnersChoiceConvene => &self.info.rate_up_five_star[..], + // TODO: Review MultipleChoiceConvene + FeaturedResonatorConvene + | FeaturedWeaponConvene + | StandardWeaponConvene + | BeginnersChoiceConvene + | MultipleChoiceResonatorConvene + | MultipleChoiceWeaponConvene => &self.info.rate_up_five_star[..], }, _ => unreachable!(), }; @@ -154,15 +174,23 @@ impl GachaPool { } fn calculate_probabilities(&self) -> [f32; 3] { - let mut prob = [self.rates.three_star, self.rates.four_star, self.rates.five_star]; + let mut prob = [ + self.rates.three_star, + self.rates.four_star, + self.rates.five_star, + ]; if self.pull_count >= self.info.pity_system.soft_pity_start { - let extra_prob = 0.8 + 8.0 * (self.pull_count - self.info.pity_system.soft_pity_start - 1) as f32; + let extra_prob = + 0.8 + 8.0 * (self.pull_count - self.info.pity_system.soft_pity_start - 1) as f32; prob[0] -= extra_prob; prob[2] = extra_prob; } - match (self.pity_four + 1 >= self.info.pity_system.hard_pity_four, self.pull_count + 1 >= self.info.pity_system.hard_pity_five) { + match ( + self.pity_four + 1 >= self.info.pity_system.hard_pity_four, + self.pull_count + 1 >= self.info.pity_system.hard_pity_five, + ) { (true, _) => [0.0, 100.0, 0.0], (_, true) => [0.0, 0.0, 100.0], _ => prob, @@ -172,9 +200,9 @@ impl GachaPool { fn determine_rarity(&self, prob: &[f32; 3], rng: &mut impl Rng) -> usize { let roll: f32 = rng.random_range(0.0..100.0); match (roll < prob[2], roll < prob[2] + prob[1]) { - (true, _) => 2, // 5-star - (_, true) => 1, // 4-star - _ => 0, // 3-star + (true, _) => 2, // 5-star + (_, true) => 1, // 4-star + _ => 0, // 3-star } } @@ -206,18 +234,18 @@ impl GachaPool { } /* -TODO: update rewards for duplicates + TODO: update rewards for duplicates -4-star duplicate: - 1st to 6th duplicate: 3 afterglow corals and 1 waveband of that char - 7th duplicate onwards: 8 afterglow corals - will not receive any afterglow corals when you pull a 4-star that you do not already own for the first time. + 4-star duplicate: + 1st to 6th duplicate: 3 afterglow corals and 1 waveband of that char + 7th duplicate onwards: 8 afterglow corals + will not receive any afterglow corals when you pull a 4-star that you do not already own for the first time. -5-star duplicate: - 1st to 6th duplicate: 15 afterglow corals and 1 waveband of that char - 7th duplicate onwards: 40 afterglow corals - will not receive any afterglow corals when you pull a 5-star that you do not already own for the first time. - */ + 5-star duplicate: + 1st to 6th duplicate: 15 afterglow corals and 1 waveband of that char + 7th duplicate onwards: 40 afterglow corals + will not receive any afterglow corals when you pull a 5-star that you do not already own for the first time. + */ match rarity { 2 => rewards.push(GachaReward { item_id: 50004, // afterglow corals @@ -236,4 +264,4 @@ TODO: update rewards for duplicates pub fn is_active(&self) -> bool { self.info.is_active() } -} \ No newline at end of file +} diff --git a/wicked-waifus-game-server/src/logic/gacha/pool_info.rs b/wicked-waifus-game-server/src/logic/gacha/pool_info.rs index b9cb441..a4ebdb6 100644 --- a/wicked-waifus-game-server/src/logic/gacha/pool_info.rs +++ b/wicked-waifus-game-server/src/logic/gacha/pool_info.rs @@ -1,12 +1,10 @@ use std::time::SystemTime; use wicked_waifus_data::GachaViewTypeInfoId; -use wicked_waifus_data::GachaViewTypeInfoId::{BeginnersChoiceConvene, - FeaturedResonatorConvene, - FeaturedWeaponConvene, - NoviceConvene, - StandardResonatorConvene, - StandardWeaponConvene, +use wicked_waifus_data::GachaViewTypeInfoId::{ + BeginnersChoiceConvene, FeaturedResonatorConvene, FeaturedWeaponConvene, + MultipleChoiceResonatorConvene, MultipleChoiceWeaponConvene, NoviceConvene, + StandardResonatorConvene, StandardWeaponConvene, }; use crate::logic::gacha::category::PoolCategory; @@ -58,30 +56,37 @@ impl PoolInfo { const NOVICE_GACHA_POOL_RESOURCE: &'static str = "UiItem_NewPlayerGachaPool"; const BASE_GACHA_POOL_RESOURCE: &'static str = "UiItem_BaseGachaPool"; - pub(crate) fn new(pool_id: i32, - pool_type: GachaViewTypeInfoId, - category: PoolCategory, - rate_up_five_star: &[i32], - rate_up_four_star: &[i32], - guaranteed_character_id: Option) -> Self { + pub(crate) fn new( + pool_id: i32, + pool_type: GachaViewTypeInfoId, + category: PoolCategory, + rate_up_five_star: &[i32], + rate_up_four_star: &[i32], + guaranteed_character_id: Option, + ) -> Self { let start_time = SystemTime::now(); let end_time = match category { PoolCategory::Permanent => None, - PoolCategory::Event(duration) | PoolCategory::Special(duration) => Some(start_time + duration), + PoolCategory::Event(duration) | PoolCategory::Special(duration) => { + Some(start_time + duration) + } }; // TODO: Make objects const 50001, 50002, 50005, 50006 or check if gacha consumes exist let (item_id, daily_limit, total_limit, pity_system) = match pool_type { NoviceConvene => (50001, 0, 50, PitySystem::novice()), - StandardResonatorConvene | StandardWeaponConvene => (50001, 0, 80, PitySystem::default()), - FeaturedResonatorConvene => (50002, 0, 0, PitySystem::default()), - FeaturedWeaponConvene => (50005, 0, 0, PitySystem::default()), - BeginnersChoiceConvene => { - match pool_id { - 51..56 => (50006, 0, 1, PitySystem::default()), - _ => (50001, 0, 80, PitySystem::default()), - } + StandardResonatorConvene | StandardWeaponConvene => { + (50001, 0, 80, PitySystem::default()) } + // TODO: Review MultipleChoiceConvene + FeaturedResonatorConvene + | MultipleChoiceResonatorConvene + | MultipleChoiceWeaponConvene => (50002, 0, 0, PitySystem::default()), + FeaturedWeaponConvene => (50005, 0, 0, PitySystem::default()), + BeginnersChoiceConvene => match pool_id { + 51..56 => (50006, 0, 1, PitySystem::default()), + _ => (50001, 0, 80, PitySystem::default()), + }, }; Self { diff --git a/wicked-waifus-game-server/src/logic/gacha/service.rs b/wicked-waifus-game-server/src/logic/gacha/service.rs index 68597d1..80435cb 100644 --- a/wicked-waifus-game-server/src/logic/gacha/service.rs +++ b/wicked-waifus-game-server/src/logic/gacha/service.rs @@ -5,12 +5,10 @@ use rand::prelude::StdRng; use rand::SeedableRng; use wicked_waifus_data::gacha_view_info_data; -use wicked_waifus_data::GachaViewTypeInfoId::{BeginnersChoiceConvene, - FeaturedResonatorConvene, - FeaturedWeaponConvene, - NoviceConvene, - StandardResonatorConvene, - StandardWeaponConvene, +use wicked_waifus_data::GachaViewTypeInfoId::{ + BeginnersChoiceConvene, FeaturedResonatorConvene, FeaturedWeaponConvene, + MultipleChoiceResonatorConvene, MultipleChoiceWeaponConvene, NoviceConvene, + StandardResonatorConvene, StandardWeaponConvene, }; use wicked_waifus_protocol::{ErrorCode, GachaResult}; @@ -40,29 +38,48 @@ impl GachaService { for element in gacha_view_info_data::iter() { let duration = match element.r#type { - NoviceConvene | StandardResonatorConvene | StandardWeaponConvene => PoolCategory::Permanent, - FeaturedResonatorConvene | FeaturedWeaponConvene => PoolCategory::Event(Self::THREE_WEEKS), + NoviceConvene | StandardResonatorConvene | StandardWeaponConvene => { + PoolCategory::Permanent + } + // TODO: Review MultipleChoiceConvene + FeaturedResonatorConvene + | FeaturedWeaponConvene + | MultipleChoiceResonatorConvene + | MultipleChoiceWeaponConvene => PoolCategory::Event(Self::THREE_WEEKS), BeginnersChoiceConvene => match element.id { 51..56 => PoolCategory::Special(Self::ONE_WEEK), _ => PoolCategory::Permanent, }, }; - let guaranteed = if (element.show_id_list.len() > 0) && (element.r#type == FeaturedResonatorConvene) { + let guaranteed = if (element.show_id_list.len() > 0) + && (element.r#type == FeaturedResonatorConvene) + { Some(element.show_id_list[0]) } else { None }; - let info = PoolInfo::new(element.id, element.r#type, duration, &element.up_list[..], &element.show_id_list[..], guaranteed); + let info = PoolInfo::new( + element.id, + element.r#type, + duration, + &element.up_list[..], + &element.show_id_list[..], + guaranteed, + ); pools.insert(element.id, GachaPool::new(info)); } pools } - pub fn pull(&mut self, - player: &mut Player, - pool_id: i32, - times: i32) -> Result, ErrorCode> { - let pool = self.pools.get_mut(&pool_id) + pub fn pull( + &mut self, + player: &mut Player, + pool_id: i32, + times: i32, + ) -> Result, ErrorCode> { + let pool = self + .pools + .get_mut(&pool_id) .ok_or(ErrorCode::ErrGachaPoolConfigNotFound)?; if !pool.is_active() { @@ -83,7 +100,8 @@ impl GachaService { } pub fn get_active_pools(&self) -> Vec<(i32, &GachaPool)> { - self.pools.iter() + self.pools + .iter() .filter(|(_, pool)| pool.is_active()) .map(|(id, pool)| (*id, pool)) .collect() @@ -91,8 +109,9 @@ impl GachaService { #[allow(dead_code)] pub fn get_all_pools(&self) -> Vec<(i32, &PoolInfo)> { - self.pools.iter() + self.pools + .iter() .map(|(id, pool)| (*id, &pool.info)) .collect() } -} \ No newline at end of file +} diff --git a/wicked-waifus-game-server/src/logic/handler/combat.rs b/wicked-waifus-game-server/src/logic/handler/combat.rs index 901d4c3..c7e18f2 100644 --- a/wicked-waifus-game-server/src/logic/handler/combat.rs +++ b/wicked-waifus-game-server/src/logic/handler/combat.rs @@ -3,7 +3,12 @@ use wicked_waifus_protocol::combat_message::{ combat_send_data, CombatNotifyData, CombatReceiveData, CombatRequestData, CombatResponseData, CombatSendPackRequest, CombatSendPackResponse, }; -use wicked_waifus_protocol::{AttributeChangedNotify, CombatCommon, DamageExecuteRequest, DamageExecuteResponse, EAttributeType, ERemoveEntityType, EntityRemoveNotify, ErrorCode, GameplayAttributeData, SwitchRoleRequest, SwitchRoleResponse}; +use wicked_waifus_protocol::{ + AttributeChangedNotify, CombatCommon, DErrorResult, DamageExecuteRequest, + DamageExecuteResponse, EAttributeType, ERemoveEntityType, ErrorCode, + FsmConditionPassRequest, FsmConditionPassResponse, GameplayAttributeData, + PlayerBattleStateChangeNotify, SwitchRoleRequest, SwitchRoleResponse, +}; use wicked_waifus_data::damage_data; @@ -55,6 +60,9 @@ pub fn on_combat_message_combat_send_pack_request( combat_request_data::Message::SwitchRoleRequest(ref request) => { handle_switch_role_request(player, request_data, request, response); } + combat_request_data::Message::FsmConditionPassRequest(ref request) => { + handle_fsm_condition_request(player, request_data, request, response); + } combat_request_data::Message::DamageExecuteRequest(ref request) => { handle_damage_execute_request(player, request_data, request, response); } @@ -117,16 +125,20 @@ fn handle_damage_execute_request( .unwrap(); if let Ok(related_attribute) = EAttributeType::try_from(damage_data.related_property) { if let Some((value, _)) = attribute.attr_map.get(&related_attribute) { - if let Some(&rate_lv) = damage_data.rate_lv.iter().find(|&lvl| *lvl == request.skill_level) { + if let Some(&rate_lv) = damage_data + .rate_lv + .iter() + .find(|&lvl| *lvl == request.skill_level) + { let hardness_lv = damage_data.hardness_lv[0]; tracing::info!( - "atk: {}, damage_id: {}, role_id: {}, rate_lv: {}, hardness_lv: {}", - value, - request.damage_id, - config_id, - rate_lv, - hardness_lv - ); + "atk: {}, damage_id: {}, role_id: {}, rate_lv: {}, hardness_lv: {}", + value, + request.damage_id, + config_id, + rate_lv, + hardness_lv + ); damage = if hardness_lv == 0 || rate_lv <= 0 { 1 } else { @@ -173,9 +185,58 @@ fn handle_damage_execute_request( }), )); if updated_value == 0 { - world_util::remove_entity(player, request.target_entity_id, ERemoveEntityType::HpIsZero); + world_util::remove_entity( + player, + request.target_entity_id, + ERemoveEntityType::HpIsZero, + ); } } response.error_code = ErrorCode::Success.into(); } + +fn handle_battle( + player: &mut Player, + combat_request: &CombatRequestData, + response: &mut CombatSendPackResponse, + condition: bool, +) { + let receive_pack = response + .receive_pack_notify + .get_or_insert_with(Default::default); + + receive_pack.data.push(create_combat_notify( + combat_request.combat_common.unwrap(), + combat_notify_data::Message::PlayerBattleStateChangeNotify(PlayerBattleStateChangeNotify { + player_id: player.basic_info.id, + + in_battle: condition, + }), + )); +} + +fn handle_fsm_condition_request( + player: &mut Player, + combat_request: &CombatRequestData, + request: &FsmConditionPassRequest, + response: &mut CombatSendPackResponse, +) { + let receive_pack = response + .receive_pack_notify + .get_or_insert_with(Default::default); + + receive_pack.data.push(create_combat_response( + combat_request, + combat_response_data::Message::FsmConditionPassResponse(FsmConditionPassResponse { + fsm_id: request.fsm_id, + + error: Some(DErrorResult { + error_code: ErrorCode::Success.into(), + + error_params: Vec::new(), + }), + }), + )); + handle_battle(player, combat_request, response, true); +} diff --git a/wicked-waifus-game-server/src/logic/handler/dummy.rs b/wicked-waifus-game-server/src/logic/handler/dummy.rs index 0f17700..9f78205 100644 --- a/wicked-waifus-game-server/src/logic/handler/dummy.rs +++ b/wicked-waifus-game-server/src/logic/handler/dummy.rs @@ -44,6 +44,7 @@ dummy_handler! { TowerSeasonUpdate; ValidTimeItem; PayShopInfo; + PayInfo; InitRange; Activity; BattlePass; diff --git a/wicked-waifus-game-server/src/logic/handler/mod.rs b/wicked-waifus-game-server/src/logic/handler/mod.rs index 60ffc36..da75c57 100644 --- a/wicked-waifus-game-server/src/logic/handler/mod.rs +++ b/wicked-waifus-game-server/src/logic/handler/mod.rs @@ -216,6 +216,7 @@ handle_request! { PayShopInfo; // PayShopUpdate; // MonthCard; + PayInfo; // Skill (TODO: Review this on_..., port some from go) VisionExploreSkillSet; diff --git a/wicked-waifus-game-server/src/logic/handler/scene.rs b/wicked-waifus-game-server/src/logic/handler/scene.rs index 88d2ce1..cca218d 100644 --- a/wicked-waifus-game-server/src/logic/handler/scene.rs +++ b/wicked-waifus-game-server/src/logic/handler/scene.rs @@ -73,5 +73,7 @@ pub fn on_unlock_role_skin_list_request( response: &mut UnlockRoleSkinListResponse, ) { // TODO: port this from golang - response.phantom_skin_list = vec![]; + response.role_skin_list = wicked_waifus_data::role_skin_data::iter() + .map(|data| data.id) + .collect::>(); } \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/role/formation.rs b/wicked-waifus-game-server/src/logic/role/formation.rs index ea7e25c..30ee4c4 100644 --- a/wicked-waifus-game-server/src/logic/role/formation.rs +++ b/wicked-waifus-game-server/src/logic/role/formation.rs @@ -8,7 +8,8 @@ pub struct RoleFormation { } // Will be updated every version -const DEFAULT_FORMATION: &[i32] = &[1506, 1407, 1507];//5101, 1407, 1507]; // 5022 MChibi 5023 FChibi //5023, 5025, 5026 //1607 +// const DEFAULT_FORMATION: &[i32] = &[5101, 1407, 1507]; +const DEFAULT_FORMATION: &[i32] = &[1205, 1207, 1409]; impl RoleFormation { pub fn default_roles() -> &'static [i32] { diff --git a/wicked-waifus-game-server/src/logic/utils/action_utils.rs b/wicked-waifus-game-server/src/logic/utils/action_utils.rs index 74e7e05..309951c 100644 --- a/wicked-waifus-game-server/src/logic/utils/action_utils.rs +++ b/wicked-waifus-game-server/src/logic/utils/action_utils.rs @@ -43,6 +43,7 @@ pub fn perform_action(player: &mut Player, Action::TeleportDungeon(action) => unimplemented_action! { action }, Action::DestroySelf(action) => unimplemented_action! { action }, Action::CameraLookAt(action) => unimplemented_action! { action }, + Action::StopCameraLookAt(action) => unimplemented_action! { action }, Action::EnterOrbitalCamera(action) => unimplemented_action! { action }, Action::ExitOrbitalCamera(action) => unimplemented_action! { action }, Action::SendAiEvent(action) => unimplemented_action! { action }, @@ -196,6 +197,17 @@ pub fn perform_action(player: &mut Player, Action::GetRewardByInteract(action) => unimplemented_action! { action }, Action::OpenQte(action) => unimplemented_action! { action }, Action::ActiveAntiGravitySafePoint(action) => unimplemented_action! { action }, + Action::BvbPlayDialog(action) => unimplemented_action! { action }, + Action::BvbSendSystemEvent(action) => unimplemented_action! { action }, + Action::BvbSendAiEvent(action) => unimplemented_action! { action }, + Action::BvbPlayerOperationConstraint(action) => unimplemented_action! { action }, + Action::ExecClientBattleAction(action) => unimplemented_action! { action }, + Action::TriggerSpecificScanEffect(action) => unimplemented_action! { action }, + Action::SetActorVar(action) => unimplemented_action! { action }, + Action::RunActorCustomEvent(action) => unimplemented_action! { action }, + Action::StopUiScreenEffect(action) => unimplemented_action! { action }, + Action::StopNewMoveWithSpline(action) => unimplemented_action! { action }, + Action::RequestSystemFunction(action) => unimplemented_action! { action }, } } diff --git a/wicked-waifus-game-server/src/logic/utils/condition_utils.rs b/wicked-waifus-game-server/src/logic/utils/condition_utils.rs index 58ac04b..eb46702 100644 --- a/wicked-waifus-game-server/src/logic/utils/condition_utils.rs +++ b/wicked-waifus-game-server/src/logic/utils/condition_utils.rs @@ -119,6 +119,11 @@ pub fn check_condition(player: &Player, Condition::CheckEntityGravityDirection(condition) => unimplemented_condition! { condition }, Condition::CheckTeleControlState(condition) => unimplemented_condition! { condition }, Condition::CheckEntityReward(condition) => unimplemented_condition! { condition }, + Condition::CheckIsGramophonePlayingMusic(condition) => unimplemented_condition! { condition }, + Condition::CheckBVBEvent(condition) => unimplemented_condition! { condition }, + Condition::FinishBvbChallenge(condition) => unimplemented_condition! { condition }, + Condition::CompareActorVar(condition) => unimplemented_condition! { condition }, + Condition::CheckDangoCultivationProgress(condition) => unimplemented_condition! { condition }, } } diff --git a/wicked-waifus-game-server/src/logic/utils/load_role_info.rs b/wicked-waifus-game-server/src/logic/utils/load_role_info.rs index abb18dd..85a110c 100644 --- a/wicked-waifus-game-server/src/logic/utils/load_role_info.rs +++ b/wicked-waifus-game-server/src/logic/utils/load_role_info.rs @@ -62,21 +62,6 @@ impl_base_prop!( damage_reduce_element4, damage_reduce_element5, damage_reduce_element6, - reaction_change1, - reaction_change2, - reaction_change3, - reaction_change4, - reaction_change5, - reaction_change6, - reaction_change7, - reaction_change8, - reaction_change9, - reaction_change10, - reaction_change11, - reaction_change12, - reaction_change13, - reaction_change14, - reaction_change15, energy_max, energy, special_energy_1_max, diff --git a/wicked-waifus-gateway-server/Cargo.toml b/wicked-waifus-gateway-server/Cargo.toml index 51bb976..5351164 100644 --- a/wicked-waifus-gateway-server/Cargo.toml +++ b/wicked-waifus-gateway-server/Cargo.toml @@ -4,14 +4,19 @@ edition = "2021" version.workspace = true [features] +# If supporting clients < 2.0 please use "--no-default-features" +# (additonally you could add "-F ack-cmd-conv" but it's currently a NO-OP) +default = ["ack-cmd-conv"] debug-msg = [] +ack-cmd-conv = [] +ack-cmd-conv-crc-mtu = [] [dependencies] # Framework tokio.workspace = true # Networking -kcp = { workspace = true, features = ["tokio"] } +kcp = { git = "https://git.xeondev.com/ReversedRoomsMisc/kcp-rs.git", features = ["wuthering-waves-old", "tokio"] } # Serialization serde.workspace = true diff --git a/wicked-waifus-gateway-server/gateway.default.toml b/wicked-waifus-gateway-server/gateway.default.toml index cd6192c..bc66007 100644 --- a/wicked-waifus-gateway-server/gateway.default.toml +++ b/wicked-waifus-gateway-server/gateway.default.toml @@ -2,6 +2,7 @@ service_id = 1 [network] kcp_port = 7777 +kcp_crc = false [protokey] builtin_encryption_msg_id = [111, 112] diff --git a/wicked-waifus-gateway-server/kcp/Cargo.toml b/wicked-waifus-gateway-server/kcp/Cargo.toml deleted file mode 100644 index 2f77ad1..0000000 --- a/wicked-waifus-gateway-server/kcp/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "kcp" -edition = "2021" -version.workspace = true - -[features] -fastack-conserve = [] -tokio = ["dep:tokio"] - -[dependencies] -bytes = "1.6.0" -log = "0.4.21" -thiserror = "1.0.58" -tokio = { version = "1.37.0", optional = true, features = ["io-util"] } - -[dev-dependencies] -time = "0.3.34" -rand = "0.8.5" - diff --git a/wicked-waifus-gateway-server/kcp/src/error.rs b/wicked-waifus-gateway-server/kcp/src/error.rs deleted file mode 100644 index 2c39481..0000000 --- a/wicked-waifus-gateway-server/kcp/src/error.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::{ - error::Error as StdError, - io::{self, ErrorKind}, -}; - -/// KCP protocol errors -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("conv inconsistent, expected {0}, found {1}")] - ConvInconsistent(u32, u32), - #[error("invalid mtu {0}")] - InvalidMtu(usize), - #[error("invalid segment size {0}")] - InvalidSegmentSize(usize), - #[error("invalid segment data size, expected {0}, found {1}")] - InvalidSegmentDataSize(usize, usize), - #[error("{0}")] - IoError( - #[from] - #[source] - io::Error, - ), - #[error("need to call update() once")] - NeedUpdate, - #[error("recv queue is empty")] - RecvQueueEmpty, - #[error("expecting fragment")] - ExpectingFragment, - #[error("command {0} is not supported")] - UnsupportedCmd(u8), - #[error("user's send buffer is too big")] - UserBufTooBig, - #[error("user's recv buffer is too small")] - UserBufTooSmall, -} - -fn make_io_error(kind: ErrorKind, msg: T) -> io::Error -where - T: Into>, -{ - io::Error::new(kind, msg) -} - -impl From for io::Error { - fn from(err: Error) -> Self { - let kind = match err { - Error::IoError(err) => return err, - Error::RecvQueueEmpty | Error::ExpectingFragment => ErrorKind::WouldBlock, - _ => ErrorKind::Other, - }; - - make_io_error(kind, err) - } -} diff --git a/wicked-waifus-gateway-server/kcp/src/kcp.rs b/wicked-waifus-gateway-server/kcp/src/kcp.rs deleted file mode 100644 index ea88edd..0000000 --- a/wicked-waifus-gateway-server/kcp/src/kcp.rs +++ /dev/null @@ -1,1504 +0,0 @@ -//! KCP - -#[cfg(feature = "tokio")] -use std::pin::Pin; -#[cfg(feature = "tokio")] -use std::task::{Context, Poll}; -use std::{ - cmp, - cmp::Ordering, - collections::VecDeque, - fmt::{self, Debug}, - io::{self, Cursor, Read, Write}, -}; - -use bytes::{Buf, BufMut, BytesMut}; -#[cfg(feature = "tokio")] -use tokio::io::{AsyncWrite, AsyncWriteExt}; - -use crate::{error::Error, KcpResult}; - -const KCP_RTO_NDL: u32 = 20; // no delay min rto -const KCP_RTO_MIN: u32 = 100; // normal min rto -const KCP_RTO_DEF: u32 = 200; -const KCP_RTO_MAX: u32 = 60000; - -const KCP_CMD_PUSH: u8 = 81; // cmd: push data -const KCP_CMD_ACK: u8 = 82; // cmd: ack -const KCP_CMD_WASK: u8 = 83; // cmd: window probe (ask) -const KCP_CMD_WINS: u8 = 84; // cmd: window size (tell) - -const KCP_ASK_SEND: u32 = 1; // need to send IKCP_CMD_WASK -const KCP_ASK_TELL: u32 = 2; // need to send IKCP_CMD_WINS - -const KCP_WND_SND: u16 = 32; -const KCP_WND_RCV: u16 = 258; // must >= max fragment size - -const KCP_MTU_DEF: usize = 1400; -// const KCP_ACK_FAST: u32 = 3; - -const KCP_INTERVAL: u32 = 100; -/// KCP Header size -pub const KCP_OVERHEAD: usize = 24; -const KCP_DEADLINK: u32 = 20; - -const KCP_THRESH_INIT: u16 = 2; -const KCP_THRESH_MIN: u16 = 2; - -const KCP_PROBE_INIT: u32 = 7000; // 7 secs to probe window size -const KCP_PROBE_LIMIT: u32 = 120_000; // up to 120 secs to probe window -const KCP_FASTACK_LIMIT: u32 = 5; // max times to trigger fastack - -/// Read `conv` from raw buffer -#[must_use] -pub fn get_conv(mut buf: &[u8]) -> u32 { - assert!(buf.len() >= KCP_OVERHEAD); - buf.get_u32_le() -} - -/// Set `conv` to raw buffer -pub fn set_conv(mut buf: &mut [u8], conv: u32) { - assert!(buf.len() >= KCP_OVERHEAD); - buf.put_u32_le(conv); -} - -/// Get `sn` from raw buffer -#[must_use] -pub fn get_sn(buf: &[u8]) -> u32 { - assert!(buf.len() >= KCP_OVERHEAD); - (&buf[12..]).get_u32_le() -} - -#[must_use] -fn bound(lower: u32, v: u32, upper: u32) -> u32 { - cmp::min(cmp::max(lower, v), upper) -} - -#[must_use] -const fn timediff(later: u32, earlier: u32) -> i32 { - later as i32 - earlier as i32 -} - -#[derive(Default, Clone, Debug)] -struct KcpSegment { - conv: u32, - cmd: u8, - frg: u8, - wnd: u16, - ts: u32, - sn: u32, - una: u32, - resendts: u32, - rto: u32, - fastack: u32, - xmit: u32, - data: BytesMut, -} - -impl KcpSegment { - fn new(data: BytesMut) -> Self { - Self { - data, - ..Default::default() - } - } - - fn encode(&self, buf: &mut BytesMut) { - assert!( - buf.remaining_mut() >= self.encoded_len(), - "REMAIN {} encoded {} {self:?}", - buf.remaining_mut(), - self.encoded_len(), - ); - - buf.put_u32_le(self.conv); - buf.put_u8(self.cmd); - buf.put_u8(self.frg); - buf.put_u16_le(self.wnd); - buf.put_u32_le(self.ts); - buf.put_u32_le(self.sn); - buf.put_u32_le(self.una); - buf.put_u32_le(self.data.len() as u32); - buf.put_slice(&self.data); - } - - fn encoded_len(&self) -> usize { - KCP_OVERHEAD + self.data.len() - } -} - -#[derive(Default)] -struct KcpOutput(O); - -impl Write for KcpOutput { - fn write(&mut self, data: &[u8]) -> io::Result { - trace!("[RO] {} bytes", data.len()); - self.0.write(data) - } - - fn flush(&mut self) -> io::Result<()> { - self.0.flush() - } -} - -#[cfg(feature = "tokio")] -impl AsyncWrite for KcpOutput { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - Pin::new(&mut self.0).poll_write(cx, buf) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.0).poll_flush(cx) - } - - fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.0).poll_shutdown(cx) - } - - fn poll_write_vectored( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[io::IoSlice<'_>], - ) -> Poll> { - Pin::new(&mut self.0).poll_write_vectored(cx, bufs) - } - - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } -} - -/// KCP control -#[derive(Default)] -pub struct Kcp { - /// Conversation ID - conv: u32, - /// Maximum Transmission Unit - mtu: usize, - /// Maximum Segment Size - mss: usize, - /// Connection state - state: i32, - - /// First unacknowledged packet - snd_una: u32, - /// Next packet - snd_nxt: u32, - /// Next packet to be received - rcv_nxt: u32, - - /// Congestion window threshold - ssthresh: u16, - - /// ACK receive variable RTT - rx_rttval: u32, - /// ACK receive static RTT - rx_srtt: u32, - /// Resend time (calculated by ACK delay time) - rx_rto: u32, - /// Minimal resend timeout - rx_minrto: u32, - - /// Send window - snd_wnd: u16, - /// Receive window - rcv_wnd: u16, - /// Remote receive window - rmt_wnd: u16, - /// Congestion window - cwnd: u16, - /// Check window - /// - `IKCP_ASK_TELL`, telling window size to remote - /// - `IKCP_ASK_SEND`, ask remote for window size - probe: u32, - - /// Last update time - current: u32, - /// Flush interval - interval: u32, - /// Next flush interval - ts_flush: u32, - xmit: u32, - - /// Enable nodelay - nodelay: bool, - /// Updated has been called or not - updated: bool, - - /// Next check window timestamp - ts_probe: u32, - /// Check window wait time - probe_wait: u32, - - /// Maximum resend time - dead_link: u32, - /// Maximum payload size - incr: usize, - - snd_queue: VecDeque, - rcv_queue: VecDeque, - snd_buf: VecDeque, - rcv_buf: VecDeque, - - /// Pending ACK - acklist: VecDeque<(u32, u32)>, - buf: BytesMut, - - /// ACK number to trigger fast resend - fastresend: u32, - fastlimit: u32, - /// Disable congestion control - nocwnd: bool, - /// Enable stream mode - stream: bool, - - /// Get conv from the next input call - input_conv: bool, - - output: KcpOutput, -} - -impl Debug for Kcp { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Kcp") - .field("conv", &self.conv) - .field("mtu", &self.mtu) - .field("mss", &self.mss) - .field("state", &self.state) - .field("snd_una", &self.snd_una) - .field("snd_nxt", &self.snd_nxt) - .field("rcv_nxt", &self.rcv_nxt) - .field("ssthresh", &self.ssthresh) - .field("rx_rttval", &self.rx_rttval) - .field("rx_srtt", &self.rx_srtt) - .field("rx_rto", &self.rx_rto) - .field("rx_minrto", &self.rx_minrto) - .field("snd_wnd", &self.snd_wnd) - .field("rcv_wnd", &self.rcv_wnd) - .field("rmt_wnd", &self.rmt_wnd) - .field("cwnd", &self.cwnd) - .field("probe", &self.probe) - .field("current", &self.current) - .field("interval", &self.interval) - .field("ts_flush", &self.ts_flush) - .field("xmit", &self.xmit) - .field("nodelay", &self.nodelay) - .field("updated", &self.updated) - .field("ts_probe", &self.ts_probe) - .field("probe_wait", &self.probe_wait) - .field("dead_link", &self.dead_link) - .field("incr", &self.incr) - .field("snd_queue.len", &self.snd_queue.len()) - .field("rcv_queue.len", &self.rcv_queue.len()) - .field("snd_buf.len", &self.snd_buf.len()) - .field("rcv_buf.len", &self.rcv_buf.len()) - .field("acklist.len", &self.acklist.len()) - .field("buf.len", &self.buf.len()) - .field("fastresend", &self.fastresend) - .field("fastlimit", &self.fastlimit) - .field("nocwnd", &self.nocwnd) - .field("stream", &self.stream) - .field("input_conv", &self.input_conv) - .finish() - } -} - -impl Kcp { - /// Create a KCP control object. - /// - /// `conv` represents the conversation, it must be equal in both endpoints given a connection - /// `stream` will enable stream mode if set to `true`. - /// `output` is the callback object for writing. - pub fn new(conv: u32, stream: bool, output: Output) -> Self { - Self { - conv, - snd_una: 0, - snd_nxt: 0, - rcv_nxt: 0, - ts_probe: 0, - probe_wait: 0, - snd_wnd: KCP_WND_SND, - rcv_wnd: KCP_WND_RCV, - rmt_wnd: KCP_WND_RCV, - cwnd: 0, - incr: 0, - probe: 0, - mtu: KCP_MTU_DEF, - mss: KCP_MTU_DEF - KCP_OVERHEAD, - stream, - - buf: BytesMut::with_capacity((KCP_MTU_DEF + KCP_OVERHEAD) * 3), - - snd_queue: VecDeque::new(), - rcv_queue: VecDeque::new(), - snd_buf: VecDeque::new(), - rcv_buf: VecDeque::new(), - - state: 0, - - acklist: VecDeque::new(), - - rx_srtt: 0, - rx_rttval: 0, - rx_rto: KCP_RTO_DEF, - rx_minrto: KCP_RTO_MIN, - - current: 0, - interval: KCP_INTERVAL, - ts_flush: KCP_INTERVAL, - nodelay: false, - updated: false, - ssthresh: KCP_THRESH_INIT, - fastresend: 0, - fastlimit: KCP_FASTACK_LIMIT, - nocwnd: false, - xmit: 0, - dead_link: KCP_DEADLINK, - - input_conv: false, - output: KcpOutput(output), - } - } - - // move available data from rcv_buf -> rcv_queue - pub fn move_buf(&mut self) { - while !self.rcv_buf.is_empty() { - let nrcv_que = self.rcv_queue.len(); - { - let seg = self.rcv_buf.front().unwrap(); - if seg.sn == self.rcv_nxt && nrcv_que < self.rcv_wnd as usize { - self.rcv_nxt += 1; - } else { - break; - } - } - - let seg = self.rcv_buf.pop_front().unwrap(); - self.rcv_queue.push_back(seg); - } - } - - /// Receive data from buffer - pub fn recv(&mut self, buf: &mut [u8]) -> KcpResult { - if self.rcv_queue.is_empty() { - return Err(Error::RecvQueueEmpty); - } - - let peeksize = self.peeksize()?; - - if peeksize > buf.len() { - debug!("recv peeksize={peeksize} bufsize={} too small", buf.len()); - return Err(Error::UserBufTooSmall); - } - - let recover = self.rcv_queue.len() >= self.rcv_wnd as usize; - - // Merge fragment - let mut cur = Cursor::new(buf); - while let Some(seg) = self.rcv_queue.pop_front() { - Write::write_all(&mut cur, &seg.data)?; - - trace!("recv sn={}", seg.sn); - - if seg.frg == 0 { - break; - } - } - assert_eq!(cur.position() as usize, peeksize); - - self.move_buf(); - - // fast recover - if self.rcv_queue.len() < self.rcv_wnd as usize && recover { - // ready to send back IKCP_CMD_WINS in ikcp_flush - // tell remote my window size - self.probe |= KCP_ASK_TELL; - } - - Ok(cur.position() as usize) - } - - /// Check buffer size without actually consuming it - pub fn peeksize(&self) -> KcpResult { - match self.rcv_queue.front() { - Some(segment) => { - if segment.frg == 0 { - return Ok(segment.data.len()); - } - - if self.rcv_queue.len() < (segment.frg + 1) as usize { - return Err(Error::ExpectingFragment); - } - - let mut len = 0; - - for segment in &self.rcv_queue { - len += segment.data.len(); - if segment.frg == 0 { - break; - } - } - - Ok(len) - } - None => Err(Error::RecvQueueEmpty), - } - } - - /// Send bytes into buffer - pub fn send(&mut self, mut buf: &[u8]) -> KcpResult { - let mut sent_size = 0; - - assert!(self.mss > 0); - - // append to previous segment in streaming mode (if possible) - if self.stream { - if let Some(old) = self.snd_queue.back_mut() { - let l = old.data.len(); - if l < self.mss { - let capacity = self.mss - l; - let extend = cmp::min(buf.len(), capacity); - - trace!( - "send stream mss={} last length={l} extend={extend}", - self.mss, - ); - - let (lf, rt) = buf.split_at(extend); - old.data.extend_from_slice(lf); - buf = rt; - - old.frg = 0; - sent_size += extend; - } - } - - if buf.is_empty() { - return Ok(sent_size); - } - } - - let count = if buf.len() <= self.mss { - 1 - } else { - (buf.len() + self.mss - 1) / self.mss - }; - - if count >= KCP_WND_RCV as usize { - debug!("send bufsize={} mss={} too large", buf.len(), self.mss); - return Err(Error::UserBufTooBig); - } - - let count = cmp::max(1, count); - - for i in 0..count { - let size = cmp::min(self.mss, buf.len()); - - let (lf, rt) = buf.split_at(size); - - let mut new_segment = KcpSegment::new(lf.into()); - buf = rt; - - new_segment.frg = if self.stream { - 0 - } else { - (count - i - 1) as u8 - }; - - self.snd_queue.push_back(new_segment); - sent_size += size; - } - - Ok(sent_size) - } - - fn update_ack(&mut self, rtt: u32) { - if self.rx_srtt == 0 { - self.rx_srtt = rtt; - self.rx_rttval = rtt / 2; - } else { - let delta = if rtt > self.rx_srtt { - rtt - self.rx_srtt - } else { - self.rx_srtt - rtt - }; - self.rx_rttval = (3 * self.rx_rttval + delta) / 4; - self.rx_srtt = ((7 * u64::from(self.rx_srtt) + u64::from(rtt)) / 8) as u32; - if self.rx_srtt < 1 { - self.rx_srtt = 1; - } - } - let rto = self.rx_srtt + cmp::max(self.interval, 4 * self.rx_rttval); - self.rx_rto = bound(self.rx_minrto, rto, KCP_RTO_MAX); - } - - fn shrink_buf(&mut self) { - self.snd_una = match self.snd_buf.front() { - Some(seg) => seg.sn, - None => self.snd_nxt, - }; - } - - fn parse_ack(&mut self, sn: u32) { - if timediff(sn, self.snd_una) < 0 || timediff(sn, self.snd_nxt) >= 0 { - return; - } - - let mut i = 0_usize; - while i < self.snd_buf.len() { - match sn.cmp(&self.snd_buf[i].sn) { - Ordering::Equal => { - self.snd_buf.remove(i); - break; - } - Ordering::Less => break, - Ordering::Greater => i += 1, - } - } - } - - fn parse_una(&mut self, una: u32) { - while let Some(seg) = self.snd_buf.front() { - if timediff(una, seg.sn) > 0 { - self.snd_buf.pop_front(); - } else { - break; - } - } - } - - fn parse_fastack(&mut self, sn: u32, ts: u32) { - if timediff(sn, self.snd_una) < 0 || timediff(sn, self.snd_nxt) >= 0 { - return; - } - - for seg in &mut self.snd_buf { - if timediff(sn, seg.sn) < 0 { - break; - } else if sn != seg.sn { - #[cfg(feature = "fastack-conserve")] - { - seg.fastack += 1; - } - #[cfg(not(feature = "fastack-conserve"))] - if timediff(ts, seg.ts) >= 0 { - seg.fastack += 1; - } - } - } - } - - fn ack_push(&mut self, sn: u32, ts: u32) { - self.acklist.push_back((sn, ts)); - } - - fn parse_data(&mut self, new_segment: KcpSegment) { - let sn = new_segment.sn; - - if timediff(sn, self.rcv_nxt + u32::from(self.rcv_wnd)) >= 0 - || timediff(sn, self.rcv_nxt) < 0 - { - return; - } - - let mut repeat = false; - let mut new_index = self.rcv_buf.len(); - - for segment in self.rcv_buf.iter().rev() { - if segment.sn == sn { - repeat = true; - break; - } - if timediff(sn, segment.sn) > 0 { - break; - } - new_index -= 1; - } - - if !repeat { - self.rcv_buf.insert(new_index, new_segment); - } - - // move available data from rcv_buf -> rcv_queue - self.move_buf(); - } - - /// Get `conv` from the next `input` call - pub fn input_conv(&mut self) { - self.input_conv = true; - } - - /// Check if Kcp is waiting for the next input - #[must_use] - pub const fn waiting_conv(&self) -> bool { - self.input_conv - } - - /// Set `conv` value - pub fn set_conv(&mut self, conv: u32) { - self.conv = conv; - } - - /// Get `conv` - #[must_use] - pub const fn conv(&self) -> u32 { - self.conv - } - - /// Call this when you received a packet from raw connection - pub fn input(&mut self, buf: &[u8]) -> KcpResult { - let input_size = buf.len(); - - trace!("[RI] {} bytes", buf.len()); - - if buf.len() < KCP_OVERHEAD { - debug!( - "input bufsize={} too small, at least {KCP_OVERHEAD}", - buf.len(), - ); - return Err(Error::InvalidSegmentSize(buf.len())); - } - - let mut flag = false; - let mut max_ack = 0; - let old_una = self.snd_una; - let mut latest_ts = 0; - - let mut buf = Cursor::new(buf); - while buf.remaining() >= KCP_OVERHEAD { - let conv = buf.get_u32_le(); - if conv != self.conv { - // This allows getting conv from this call, which allows us to allocate - // conv from the server side. - if self.input_conv { - debug!("input conv={conv} updated, original conv={}", self.conv); - self.conv = conv; - self.input_conv = false; - } else { - debug!("input conv={conv} expected conv={} not match", self.conv); - return Err(Error::ConvInconsistent(self.conv, conv)); - } - } - - let cmd = buf.get_u8(); - let frg = buf.get_u8(); - let wnd = buf.get_u16_le(); - let ts = buf.get_u32_le(); - let sn = buf.get_u32_le(); - let una = buf.get_u32_le(); - let len = buf.get_u32_le() as usize; - - if buf.remaining() < len { - debug!( - "input bufsize={input_size} payload length={len} remaining={} not match", - buf.remaining() - ); - return Err(Error::InvalidSegmentDataSize(len, buf.remaining())); - } - - match cmd { - KCP_CMD_PUSH | KCP_CMD_ACK | KCP_CMD_WASK | KCP_CMD_WINS => {} - _ => { - debug!("input cmd={cmd} unrecognized"); - return Err(Error::UnsupportedCmd(cmd)); - } - } - - self.rmt_wnd = wnd; - - self.parse_una(una); - self.shrink_buf(); - - let mut has_read_data = false; - - match cmd { - KCP_CMD_ACK => { - let rtt = timediff(self.current, ts); - if rtt >= 0 { - self.update_ack(rtt as u32); - } - self.parse_ack(sn); - self.shrink_buf(); - - if !flag { - flag = true; - max_ack = sn; - latest_ts = ts; - } else if timediff(sn, max_ack) > 0 { - #[cfg(feature = "fastack-conserve")] - { - max_ack = sn; - latest_ts = ts; - } - #[cfg(not(feature = "fastack-conserve"))] - if timediff(ts, latest_ts) > 0 { - max_ack = sn; - latest_ts = ts; - } - } - - trace!( - "input ack: sn={sn} rtt={} rto={}", - timediff(self.current, ts), - self.rx_rto - ); - } - KCP_CMD_PUSH => { - trace!("input psh: sn={sn} ts={ts}"); - - if timediff(sn, self.rcv_nxt + u32::from(self.rcv_wnd)) < 0 { - self.ack_push(sn, ts); - if timediff(sn, self.rcv_nxt) >= 0 { - let mut sbuf = BytesMut::with_capacity(len); - unsafe { - sbuf.set_len(len); - } - buf.read_exact(&mut sbuf).unwrap(); - has_read_data = true; - - let mut segment = KcpSegment::new(sbuf); - - segment.conv = conv; - segment.cmd = cmd; - segment.frg = frg; - segment.wnd = wnd; - segment.ts = ts; - segment.sn = sn; - segment.una = una; - - self.parse_data(segment); - } - } - } - KCP_CMD_WASK => { - // ready to send back IKCP_CMD_WINS in ikcp_flush - // tell remote my window size - trace!("input probe"); - self.probe |= KCP_ASK_TELL; - } - KCP_CMD_WINS => { - // Do nothing - trace!("input wins: {wnd}"); - } - _ => unreachable!(), - } - - // Force skip unread data - if !has_read_data { - let next_pos = buf.position() + len as u64; - buf.set_position(next_pos); - } - } - - if flag { - self.parse_fastack(max_ack, latest_ts); - } - - if timediff(self.snd_una, old_una) > 0 && self.cwnd < self.rmt_wnd { - let mss = self.mss; - if self.cwnd < self.ssthresh { - self.cwnd += 1; - self.incr += mss; - } else { - if self.incr < mss { - self.incr = mss; - } - self.incr += (mss * mss) / self.incr + (mss / 16); - if (self.cwnd as usize + 1) * mss <= self.incr { - // self.cwnd += 1; - self.cwnd = ((self.incr + mss - 1) / if mss > 0 { mss } else { 1 }) as u16; - } - } - if self.cwnd > self.rmt_wnd { - self.cwnd = self.rmt_wnd; - self.incr = self.rmt_wnd as usize * mss; - } - } - - Ok(buf.position() as usize) - } - - #[must_use] - fn wnd_unused(&self) -> u16 { - if self.rcv_queue.len() < self.rcv_wnd as usize { - self.rcv_wnd - self.rcv_queue.len() as u16 - } else { - 0 - } - } - - fn probe_wnd_size(&mut self) { - // probe window size (if remote window size equals zero) - if self.rmt_wnd == 0 { - if self.probe_wait == 0 { - self.probe_wait = KCP_PROBE_INIT; - self.ts_probe = self.current + self.probe_wait; - } else if timediff(self.current, self.ts_probe) >= 0 { - if self.probe_wait < KCP_PROBE_INIT { - self.probe_wait = KCP_PROBE_INIT; - } - - self.probe_wait += self.probe_wait / 2; - - if self.probe_wait > KCP_PROBE_LIMIT { - self.probe_wait = KCP_PROBE_LIMIT; - } - - self.ts_probe = self.current + self.probe_wait; - self.probe |= KCP_ASK_SEND; - } - } else { - self.ts_probe = 0; - self.probe_wait = 0; - } - } - - /// Determine when you should call `update`. - /// Return when you should invoke `update` in millisec, if there is no `input`/`send` calling. - /// You can call `update` in that time without calling it repeatly. - #[must_use] - pub fn check(&self, current: u32) -> u32 { - if !self.updated { - return 0; - } - - let mut ts_flush = self.ts_flush; - let mut tm_packet = u32::MAX; - - if timediff(current, ts_flush) >= 10000 || timediff(current, ts_flush) < -10000 { - ts_flush = current; - } - - if timediff(current, ts_flush) >= 0 { - return 0; - } - - let tm_flush = timediff(ts_flush, current) as u32; - for seg in &self.snd_buf { - let diff = timediff(seg.resendts, current); - if diff <= 0 { - return 0; - } - if (diff as u32) < tm_packet { - tm_packet = diff as u32; - } - } - - let mut minimal = cmp::min(tm_packet, tm_flush); - if minimal >= self.interval { - minimal = self.interval; - } - - minimal - } - - /// Change MTU size, default is 1400 - /// - /// MTU = Maximum Transmission Unit - pub fn set_mtu(&mut self, mtu: usize) -> KcpResult<()> { - if mtu < 50 || mtu < KCP_OVERHEAD { - debug!("set_mtu mtu={mtu} invalid"); - return Err(Error::InvalidMtu(mtu)); - } - - self.mtu = mtu; - self.mss = self.mtu - KCP_OVERHEAD; - - let target_size = (mtu + KCP_OVERHEAD) * 3; - if target_size > self.buf.capacity() { - self.buf.reserve(target_size - self.buf.capacity()); - } - - Ok(()) - } - - /// Get MTU - #[must_use] - pub const fn mtu(&self) -> usize { - self.mtu - } - - /// Set check interval - pub fn set_interval(&mut self, interval: u32) { - self.interval = interval.clamp(10, 5000); - } - - /// Set nodelay - /// - /// fastest config: nodelay(true, 20, 2, true) - /// - /// `nodelay`: default is disable (false) - /// `interval`: internal update timer interval in millisec, default is 100ms - /// `resend`: 0:disable fast resend(default), 1:enable fast resend - /// `nc`: `false`: normal congestion control(default), `true`: disable congestion control - pub fn set_nodelay(&mut self, nodelay: bool, interval: i32, resend: i32, nc: bool) { - if nodelay { - self.nodelay = true; - self.rx_minrto = KCP_RTO_NDL; - } else { - self.nodelay = false; - self.rx_minrto = KCP_RTO_MIN; - } - - match interval { - interval if interval < 10 => self.interval = 10, - interval if interval > 5000 => self.interval = 5000, - _ => self.interval = interval as u32, - } - - if resend >= 0 { - self.fastresend = resend as u32; - } - - self.nocwnd = nc; - } - - /// Set `wndsize` - /// set maximum window size: `sndwnd=32`, `rcvwnd=32` by default - pub fn set_wndsize(&mut self, sndwnd: u16, rcvwnd: u16) { - if sndwnd > 0 { - self.snd_wnd = sndwnd; - } - - if rcvwnd > 0 { - self.rcv_wnd = cmp::max(rcvwnd, KCP_WND_RCV) as u16; - } - } - - /// `snd_wnd` Send window - #[must_use] - pub const fn snd_wnd(&self) -> u16 { - self.snd_wnd - } - - /// `rcv_wnd` Receive window - #[must_use] - pub const fn rcv_wnd(&self) -> u16 { - self.rcv_wnd - } - - /// Get `waitsnd`, how many packet is waiting to be sent - pub fn wait_snd(&self) -> usize { - self.snd_buf.len() + self.snd_queue.len() - } - - /// Get `rmt_wnd`, remote window size - #[must_use] - pub const fn rmt_wnd(&self) -> u16 { - self.rmt_wnd - } - - /// Set `rx_minrto` - pub fn set_rx_minrto(&mut self, rto: u32) { - self.rx_minrto = rto; - } - - /// Set `fastresend` - pub fn set_fast_resend(&mut self, fr: u32) { - self.fastresend = fr; - } - - /// KCP header size - #[must_use] - pub const fn header_len() -> usize { - KCP_OVERHEAD - } - - /// Enabled stream or not - #[must_use] - pub const fn is_stream(&self) -> bool { - self.stream - } - - /// Maximum Segment Size - #[must_use] - pub const fn mss(&self) -> usize { - self.mss - } - - /// Set maximum resend times - pub fn set_maximum_resend_times(&mut self, dead_link: u32) { - self.dead_link = dead_link; - } - - /// Check if KCP connection is dead (resend times excceeded) - #[must_use] - pub const fn is_dead_link(&self) -> bool { - self.state != 0 - } -} - -impl Kcp { - fn _flush_ack(&mut self, segment: &mut KcpSegment) -> KcpResult<()> { - // flush acknowledges - // while let Some((sn, ts)) = self.acklist.pop_front() { - for &(sn, ts) in &self.acklist { - if self.buf.len() + KCP_OVERHEAD > self.mtu { - self.output.write_all(&self.buf)?; - self.buf.clear(); - } - segment.sn = sn; - segment.ts = ts; - segment.encode(&mut self.buf); - } - self.acklist.clear(); - - Ok(()) - } - - fn _flush_probe_commands(&mut self, cmd: u8, segment: &mut KcpSegment) -> KcpResult<()> { - segment.cmd = cmd; - if self.buf.len() + KCP_OVERHEAD > self.mtu { - self.output.write_all(&self.buf)?; - self.buf.clear(); - } - segment.encode(&mut self.buf); - Ok(()) - } - - fn flush_probe_commands(&mut self, segment: &mut KcpSegment) -> KcpResult<()> { - // flush window probing commands - if (self.probe & KCP_ASK_SEND) != 0 { - self._flush_probe_commands(KCP_CMD_WASK, segment)?; - } - - // flush window probing commands - if (self.probe & KCP_ASK_TELL) != 0 { - self._flush_probe_commands(KCP_CMD_WINS, segment)?; - } - self.probe = 0; - Ok(()) - } - - /// Flush pending ACKs - pub fn flush_ack(&mut self) -> KcpResult<()> { - if !self.updated { - debug!("flush updated() must be called at least once"); - return Err(Error::NeedUpdate); - } - - let mut segment = KcpSegment { - conv: self.conv, - cmd: KCP_CMD_ACK, - wnd: self.wnd_unused(), - una: self.rcv_nxt, - ..Default::default() - }; - - self._flush_ack(&mut segment) - } - - /// Flush pending data in buffer. - pub fn flush(&mut self) -> KcpResult<()> { - if !self.updated { - debug!("flush updated() must be called at least once"); - return Err(Error::NeedUpdate); - } - - let mut segment = KcpSegment { - conv: self.conv, - cmd: KCP_CMD_ACK, - wnd: self.wnd_unused(), - una: self.rcv_nxt, - ..Default::default() - }; - - self._flush_ack(&mut segment)?; - self.probe_wnd_size(); - self.flush_probe_commands(&mut segment)?; - - // calculate window size - let mut cwnd = cmp::min(self.snd_wnd, self.rmt_wnd); - if !self.nocwnd { - cwnd = cmp::min(self.cwnd, cwnd); - } - - // move data from snd_queue to snd_buf - while timediff(self.snd_nxt, self.snd_una + u32::from(cwnd)) < 0 { - match self.snd_queue.pop_front() { - Some(mut new_segment) => { - new_segment.conv = self.conv; - new_segment.cmd = KCP_CMD_PUSH; - new_segment.wnd = segment.wnd; - new_segment.ts = self.current; - new_segment.sn = self.snd_nxt; - self.snd_nxt += 1; - new_segment.una = self.rcv_nxt; - new_segment.resendts = self.current; - new_segment.rto = self.rx_rto; - new_segment.fastack = 0; - new_segment.xmit = 0; - self.snd_buf.push_back(new_segment); - } - None => break, - } - } - - // calculate resent - let resent = if self.fastresend > 0 { - self.fastresend - } else { - u32::MAX - }; - - let rtomin = if !self.nodelay { self.rx_rto >> 3 } else { 0 }; - - let mut lost = false; - let mut change = 0; - - for snd_segment in &mut self.snd_buf { - let mut need_send = false; - - if snd_segment.xmit == 0 { - need_send = true; - snd_segment.xmit += 1; - snd_segment.rto = self.rx_rto; - snd_segment.resendts = self.current + snd_segment.rto + rtomin; - } else if timediff(self.current, snd_segment.resendts) >= 0 { - need_send = true; - snd_segment.xmit += 1; - self.xmit += 1; - if !self.nodelay { - snd_segment.rto += cmp::max(snd_segment.rto, self.rx_rto); - } else { - let step = snd_segment.rto; // (kcp->nodelay < 2) ? ((IINT32)(segment->rto)) : kcp->rx_rto; - snd_segment.rto += step / 2; - } - snd_segment.resendts = self.current + snd_segment.rto; - lost = true; - } else if snd_segment.fastack >= resent - && (snd_segment.xmit <= self.fastlimit || self.fastlimit == 0) - { - need_send = true; - snd_segment.xmit += 1; - snd_segment.fastack = 0; - snd_segment.resendts = self.current + snd_segment.rto; - change += 1; - } - - if need_send { - snd_segment.ts = self.current; - snd_segment.wnd = segment.wnd; - snd_segment.una = self.rcv_nxt; - - let need = KCP_OVERHEAD + snd_segment.data.len(); - - if self.buf.len() + need > self.mtu { - self.output.write_all(&self.buf)?; - self.buf.clear(); - } - - snd_segment.encode(&mut self.buf); - - if snd_segment.xmit >= self.dead_link { - self.state = -1; // (IUINT32)-1 - } - } - } - - // Flush all data in buffer - if !self.buf.is_empty() { - self.output.write_all(&self.buf)?; - self.buf.clear(); - } - - // update ssthresh - if change > 0 { - let inflight = self.snd_nxt - self.snd_una; - self.ssthresh = inflight as u16 / 2; - if self.ssthresh < KCP_THRESH_MIN { - self.ssthresh = KCP_THRESH_MIN; - } - self.cwnd = self.ssthresh + resent as u16; - self.incr = self.cwnd as usize * self.mss; - } - - if lost { - self.ssthresh = cwnd / 2; - if self.ssthresh < KCP_THRESH_MIN { - self.ssthresh = KCP_THRESH_MIN; - } - self.cwnd = 1; - self.incr = self.mss; - } - - if self.cwnd < 1 { - self.cwnd = 1; - self.incr = self.mss; - } - - Ok(()) - } - - /// Update state every 10ms ~ 100ms. - /// - /// Or you can ask `check` when to call this again. - pub fn update(&mut self, current: u32) -> KcpResult<()> { - self.current = current; - - if !self.updated { - self.updated = true; - self.ts_flush = self.current; - } - - let mut slap = timediff(self.current, self.ts_flush); - - if !(-10000..10000).contains(&slap) { - self.ts_flush = self.current; - slap = 0; - } - - if slap >= 0 { - self.ts_flush += self.interval; - if timediff(self.current, self.ts_flush) >= 0 { - self.ts_flush = self.current + self.interval; - } - self.flush()?; - } - - Ok(()) - } -} - -#[cfg(feature = "tokio")] -impl Kcp { - async fn _async_flush_ack(&mut self, segment: &mut KcpSegment) -> KcpResult<()> { - // flush acknowledges - // while let Some((sn, ts)) = self.acklist.pop_front() { - for &(sn, ts) in &self.acklist { - if self.buf.len() + KCP_OVERHEAD > self.mtu { - self.output.write_all(&self.buf).await?; - self.buf.clear(); - } - segment.sn = sn; - segment.ts = ts; - segment.encode(&mut self.buf); - } - self.acklist.clear(); - - Ok(()) - } - - async fn _async_flush_probe_commands( - &mut self, - cmd: u8, - segment: &mut KcpSegment, - ) -> KcpResult<()> { - segment.cmd = cmd; - if self.buf.len() + KCP_OVERHEAD > self.mtu { - self.output.write_all(&self.buf).await?; - self.buf.clear(); - } - segment.encode(&mut self.buf); - Ok(()) - } - - async fn async_flush_probe_commands(&mut self, segment: &mut KcpSegment) -> KcpResult<()> { - // flush window probing commands - if (self.probe & KCP_ASK_SEND) != 0 { - self._async_flush_probe_commands(KCP_CMD_WASK, segment) - .await?; - } - - // flush window probing commands - if (self.probe & KCP_ASK_TELL) != 0 { - self._async_flush_probe_commands(KCP_CMD_WINS, segment) - .await?; - } - self.probe = 0; - Ok(()) - } - - /// Flush pending ACKs - pub async fn async_flush_ack(&mut self) -> KcpResult<()> { - if !self.updated { - debug!("flush updated() must be called at least once"); - return Err(Error::NeedUpdate); - } - - let mut segment = KcpSegment { - conv: self.conv, - cmd: KCP_CMD_ACK, - wnd: self.wnd_unused(), - una: self.rcv_nxt, - ..Default::default() - }; - - self._async_flush_ack(&mut segment).await - } - - /// Flush pending data in buffer. - pub async fn async_flush(&mut self) -> KcpResult<()> { - if !self.updated { - debug!("flush updated() must be called at least once"); - return Err(Error::NeedUpdate); - } - - let mut segment = KcpSegment { - conv: self.conv, - cmd: KCP_CMD_ACK, - wnd: self.wnd_unused(), - una: self.rcv_nxt, - ..Default::default() - }; - - self._async_flush_ack(&mut segment).await?; - self.probe_wnd_size(); - self.async_flush_probe_commands(&mut segment).await?; - - // calculate window size - let mut cwnd = cmp::min(self.snd_wnd, self.rmt_wnd); - if !self.nocwnd { - cwnd = cmp::min(self.cwnd, cwnd); - } - - // move data from snd_queue to snd_buf - while timediff(self.snd_nxt, self.snd_una + u32::from(cwnd)) < 0 { - match self.snd_queue.pop_front() { - Some(mut new_segment) => { - new_segment.conv = self.conv; - new_segment.cmd = KCP_CMD_PUSH; - new_segment.wnd = segment.wnd; - new_segment.ts = self.current; - new_segment.sn = self.snd_nxt; - self.snd_nxt += 1; - new_segment.una = self.rcv_nxt; - new_segment.resendts = self.current; - new_segment.rto = self.rx_rto; - new_segment.fastack = 0; - new_segment.xmit = 0; - self.snd_buf.push_back(new_segment); - } - None => break, - } - } - - // calculate resent - let resent = if self.fastresend > 0 { - self.fastresend - } else { - u32::MAX - }; - - let rtomin = if !self.nodelay { self.rx_rto >> 3 } else { 0 }; - - let mut lost = false; - let mut change = 0; - - for snd_segment in &mut self.snd_buf { - let mut need_send = false; - - if snd_segment.xmit == 0 { - need_send = true; - snd_segment.xmit += 1; - snd_segment.rto = self.rx_rto; - snd_segment.resendts = self.current + snd_segment.rto + rtomin; - } else if timediff(self.current, snd_segment.resendts) >= 0 { - need_send = true; - snd_segment.xmit += 1; - self.xmit += 1; - if !self.nodelay { - snd_segment.rto += cmp::max(snd_segment.rto, self.rx_rto); - } else { - let step = snd_segment.rto; // (kcp->nodelay < 2) ? ((IINT32)(segment->rto)) : kcp->rx_rto; - snd_segment.rto += step / 2; - } - snd_segment.resendts = self.current + snd_segment.rto; - lost = true; - } else if snd_segment.fastack >= resent - && (snd_segment.xmit <= self.fastlimit || self.fastlimit == 0) - { - need_send = true; - snd_segment.xmit += 1; - snd_segment.fastack = 0; - snd_segment.resendts = self.current + snd_segment.rto; - change += 1; - } - - if need_send { - snd_segment.ts = self.current; - snd_segment.wnd = segment.wnd; - snd_segment.una = self.rcv_nxt; - - let need = KCP_OVERHEAD + snd_segment.data.len(); - - if self.buf.len() + need > self.mtu { - self.output.write_all(&self.buf).await?; - self.buf.clear(); - } - - snd_segment.encode(&mut self.buf); - - if snd_segment.xmit >= self.dead_link { - self.state = -1; // (IUINT32)-1 - } - } - } - - // Flush all data in buffer - if !self.buf.is_empty() { - self.output.write_all(&self.buf).await?; - self.buf.clear(); - } - - // update ssthresh - if change > 0 { - let inflight = self.snd_nxt - self.snd_una; - self.ssthresh = inflight as u16 / 2; - if self.ssthresh < KCP_THRESH_MIN { - self.ssthresh = KCP_THRESH_MIN; - } - self.cwnd = self.ssthresh + resent as u16; - self.incr = self.cwnd as usize * self.mss; - } - - if lost { - self.ssthresh = cwnd / 2; - if self.ssthresh < KCP_THRESH_MIN { - self.ssthresh = KCP_THRESH_MIN; - } - self.cwnd = 1; - self.incr = self.mss; - } - - if self.cwnd < 1 { - self.cwnd = 1; - self.incr = self.mss; - } - - Ok(()) - } - - /// Update state every 10ms ~ 100ms. - /// - /// Or you can ask `check` when to call this again. - pub async fn async_update(&mut self, current: u32) -> KcpResult<()> { - self.current = current; - - if !self.updated { - self.updated = true; - self.ts_flush = self.current; - } - - let mut slap = timediff(self.current, self.ts_flush); - - if !(-10000..10000).contains(&slap) { - self.ts_flush = self.current; - slap = 0; - } - - if slap >= 0 { - self.ts_flush += self.interval; - if timediff(self.current, self.ts_flush) >= 0 { - self.ts_flush = self.current + self.interval; - } - self.async_flush().await?; - } - - Ok(()) - } -} diff --git a/wicked-waifus-gateway-server/kcp/src/lib.rs b/wicked-waifus-gateway-server/kcp/src/lib.rs deleted file mode 100644 index 0f9e066..0000000 --- a/wicked-waifus-gateway-server/kcp/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -extern crate bytes; -#[macro_use] -extern crate log; - -mod error; -mod kcp; - -/// The `KCP` prelude -pub mod prelude { - pub use super::{get_conv, Kcp, KCP_OVERHEAD}; -} - -pub use error::Error; -pub use kcp::{get_conv, get_sn, set_conv, Kcp, KCP_OVERHEAD}; - -/// KCP result -pub type KcpResult = Result; diff --git a/wicked-waifus-gateway-server/src/config.rs b/wicked-waifus-gateway-server/src/config.rs index 2cecdfc..0565b3c 100644 --- a/wicked-waifus-gateway-server/src/config.rs +++ b/wicked-waifus-gateway-server/src/config.rs @@ -17,6 +17,7 @@ pub struct ServerConfig { #[derive(Deserialize)] pub struct NetworkSettings { pub kcp_port: u16, + pub kcp_crc: Option } impl TomlConfig for ServerConfig { diff --git a/wicked-waifus-gateway-server/src/main.rs b/wicked-waifus-gateway-server/src/main.rs index 9784042..01c8716 100644 --- a/wicked-waifus-gateway-server/src/main.rs +++ b/wicked-waifus-gateway-server/src/main.rs @@ -38,6 +38,7 @@ async fn main() -> Result<()> { let server = UdpServer::new( &CONFIG.network, PROTOKEY_HELPER.get_or_init(|| protokey_helper), + CONFIG.network.kcp_crc.unwrap_or(false), &SESSION_MGR, Arc::new(database), ) diff --git a/wicked-waifus-gateway-server/src/session/mod.rs b/wicked-waifus-gateway-server/src/session/mod.rs index f90f9ad..5088e27 100644 --- a/wicked-waifus-gateway-server/src/session/mod.rs +++ b/wicked-waifus-gateway-server/src/session/mod.rs @@ -41,6 +41,7 @@ impl Session { addr: SocketAddr, socket: Arc, helper: &'static ServerProtoKeyHelper, + use_crc: bool, database: Arc, ) -> Self { let output = SessionOutput { @@ -51,7 +52,7 @@ impl Session { let cur_time_ms = time_util::unix_timestamp_ms(); Self { protokey_helper: helper, - kcp: Kcp::new(conv_id, true, output), + kcp: Kcp::new(conv_id, 0, use_crc, 0, true, output), decoder: LengthFieldBasedDecoder::new(), start_time_ms: cur_time_ms, last_heartbeat_time_ms: cur_time_ms, diff --git a/wicked-waifus-gateway-server/src/udp_server.rs b/wicked-waifus-gateway-server/src/udp_server.rs index 215421c..525b79c 100644 --- a/wicked-waifus-gateway-server/src/udp_server.rs +++ b/wicked-waifus-gateway-server/src/udp_server.rs @@ -9,6 +9,7 @@ use crate::{config::NetworkSettings, session::Session, session::SessionManager}; pub struct UdpServer { socket: Arc, protokey_helper: &'static ServerProtoKeyHelper, + kcp_use_crc: bool, session_mgr: &'static SessionManager, db: Arc, } @@ -21,6 +22,7 @@ impl UdpServer { pub async fn new( network_settings: &'static NetworkSettings, protokey_helper: &'static ServerProtoKeyHelper, + kcp_use_crc: bool, session_mgr: &'static SessionManager, db: Arc, ) -> Result { @@ -29,6 +31,7 @@ impl UdpServer { Ok(Self { socket: Arc::new(socket), protokey_helper, + kcp_use_crc, session_mgr, db, }) @@ -65,6 +68,7 @@ impl UdpServer { addr, self.socket.clone(), self.protokey_helper, + self.kcp_use_crc, self.db.clone(), ); self.session_mgr.add(conv_id, session); @@ -72,6 +76,11 @@ impl UdpServer { let mut ack = Vec::with_capacity(5); ack.push(Self::CMD_ACK); ack.extend(conv_id.to_le_bytes()); + #[cfg(feature = "ack-cmd-conv-crc-mtu")] + { + ack.extend((self.kcp_use_crc as u32).to_le_bytes()); + ack.extend(Self::MTU.to_le_bytes()); + } let _ = self.socket.send_to(&ack, addr).await; tracing::debug!("new connection from {addr}, conv_id: {conv_id}");