diff --git a/src/node/Cargo.lock b/src/node/Cargo.lock index 85f93ebc..09b8e59d 100644 --- a/src/node/Cargo.lock +++ b/src/node/Cargo.lock @@ -24,10 +24,15 @@ dependencies = [ ] [[package]] -name = "anyhow" -version = "1.0.79" +name = "audiopus_sys" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "62314a1546a2064e033665d658e88c620a62904be945f8147e6b16c3db9f8651" +dependencies = [ + "cmake", + "log", + "pkg-config", +] [[package]] name = "autocfg" @@ -41,12 +46,6 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99528ca30abb9495c7e106bf7c3177b257c62040fc0f2909fe470b0f43097296" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.4.0" @@ -55,9 +54,30 @@ checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bitter" -version = "0.6.2" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef3a13b71496a92e8c00ebe576b260655b56935cd5118d5a8949788b651b5e07" + +[[package]] +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e5958a5c88910651ad16ab92586bce672368e90e4f49ad0dd32518d13b0a73d" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" + +[[package]] +name = "cc" +version = "1.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -65,6 +85,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cmake" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" +dependencies = [ + "cc", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -80,16 +109,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -127,9 +146,10 @@ dependencies = [ name = "csgoproto" version = "0.1.5" dependencies = [ + "bytes", + "glob", "proc-macro2", "protobuf", - "protobuf-codegen", ] [[package]] @@ -139,7 +159,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" dependencies = [ "quote", - "syn 2.0.37", + "syn 2.0.77", ] [[package]] @@ -161,22 +181,6 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - [[package]] name = "getrandom" version = "0.2.10" @@ -189,41 +193,25 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hermit-abi" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" - -[[package]] -name = "home" -version = "0.5.9" +name = "glob" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] -name = "indexmap" -version = "1.9.3" +name = "itertools" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ - "autocfg", - "hashbrown", + "either", ] [[package]] name = "itertools" -version = "0.10.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -240,12 +228,14 @@ version = "0.0.0" dependencies = [ "ahash", "csgoproto", + "itertools 0.12.1", "memmap2", "napi", "napi-build", "napi-derive", "parser", "protobuf-support", + "rayon", "serde_json", ] @@ -257,9 +247,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libloading" @@ -271,12 +261,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - [[package]] name = "log" version = "0.4.20" @@ -291,9 +275,9 @@ checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "memmap2" -version = "0.5.10" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] @@ -313,7 +297,7 @@ version = "2.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd063c93b900149304e3ba96ce5bf210cd4f81ef5eb80ded0d100df3e85a3ac0" dependencies = [ - "bitflags 2.4.0", + "bitflags", "ctor", "napi-derive", "napi-sys", @@ -366,40 +350,44 @@ dependencies = [ "libloading", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "once_cell" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "opus" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6526409b274a7e98e55ff59d96aafd38e6cd34d46b7dbbc32ce126dffcd75e8e" +dependencies = [ + "audiopus_sys", + "libc", +] + [[package]] name = "parser" version = "0.1.1" dependencies = [ "ahash", + "audiopus_sys", "bit_reverse", "bitter", + "bytes", "csgoproto", "derive_more", - "itertools", + "itertools 0.13.0", "lazy_static", "libc", "memmap2", + "opus", "phf", "phf_macros", "proc-macro2", "protobuf", "protobuf-support", + "rand", "rayon", "regex", "serde", @@ -435,7 +423,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.77", ] [[package]] @@ -448,70 +436,55 @@ dependencies = [ ] [[package]] -name = "proc-macro2" -version = "1.0.78" +name = "pkg-config" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] -name = "protobuf" -version = "3.3.0" +name = "ppv-lite86" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65f4a8ec18723a734e5dc09c173e0abf9690432da5340285d536edcb4dac190" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "once_cell", - "protobuf-support", - "thiserror", + "zerocopy", ] [[package]] -name = "protobuf-codegen" -version = "3.3.0" +name = "proc-macro2" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e85514a216b1c73111d9032e26cc7a5ecb1bb3d4d9539e91fb72a4395060f78" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ - "anyhow", - "once_cell", - "protobuf", - "protobuf-parse", - "regex", - "tempfile", - "thiserror", + "unicode-ident", ] [[package]] -name = "protobuf-parse" -version = "3.3.0" +name = "protobuf" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77d6fbd6697c9e531873e81cec565a85e226b99a0f10e1acc079be057fe2fcba" +checksum = "df67496db1a89596beaced1579212e9b7c53c22dca1d9745de00ead76573d514" dependencies = [ - "anyhow", - "indexmap", - "log", - "protobuf", + "bytes", + "once_cell", "protobuf-support", - "tempfile", "thiserror", - "which", ] [[package]] name = "protobuf-support" -version = "3.3.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6872f4d4f4b98303239a2b5838f5bbbb77b01ffc892d627957f37a22d7cfe69c" +checksum = "70e2d30ab1878b2e72d1e2fc23ff5517799c9929e2cf81a8516f9f4dcf2b9cf3" dependencies = [ "thiserror", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -522,6 +495,18 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", "rand_core", ] @@ -530,12 +515,15 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] [[package]] name = "rayon" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -543,23 +531,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", ] [[package]] @@ -600,19 +577,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.38.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" -dependencies = [ - "bitflags 2.4.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - [[package]] name = "ryu" version = "1.0.15" @@ -633,22 +597,22 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.77", ] [[package]] @@ -662,6 +626,12 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "siphasher" version = "0.3.11" @@ -687,28 +657,15 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "tempfile" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.48.0", -] - [[package]] name = "thiserror" version = "1.0.48" @@ -726,7 +683,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.77", ] [[package]] @@ -753,18 +710,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "winapi" version = "0.3.9" @@ -788,133 +733,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" +name = "zerocopy" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "byteorder", + "zerocopy-derive", ] [[package]] -name = "windows-targets" -version = "0.52.0" +name = "zerocopy-derive" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "proc-macro2", + "quote", + "syn 2.0.77", ] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/src/node/Cargo.toml b/src/node/Cargo.toml index b12beacd..e43c417e 100644 --- a/src/node/Cargo.toml +++ b/src/node/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] ahash = "0.8.3" memmap2 = "0.9.4" # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix -napi = { version = "2.12.2", default-features = false, features = ["napi4","serde-json"] } +napi = { version = "2.12.2", default-features = false, features = ["napi6","serde-json"] } napi-derive = "2.12.2" serde_json = "1.0.96" protobuf-support = "3.3.0" diff --git a/src/node/index.d.ts b/src/node/index.d.ts index 07909ced..40fba085 100644 --- a/src/node/index.d.ts +++ b/src/node/index.d.ts @@ -3,11 +3,17 @@ /* auto-generated by NAPI-RS */ -export function parseChatMessages(path: string): any -export function listGameEvents(path: string): any -export function parseGrenades(path: string): any -export function parseHeader(path: string): any -export function parseEvent(path: string, eventName: string, playerExtra?: Array | undefined | null, otherExtra?: Array | undefined | null): any -export function parseEvents(path: string, eventNames?: Array | undefined | null, playerExtra?: Array | undefined | null, otherExtra?: Array | undefined | null): any -export function parseTicks(path: string, wantedProps: Array, wantedTicks?: Array | undefined | null, structOfArrays?: boolean | undefined | null): any -export function parsePlayerInfo(path: string): any +export function parseVoice(pathOrBuf: string | Buffer): Record> +export function listGameEvents(pathOrBuf: string | Buffer): any +export function parseGrenades(pathOrBuf: string | Buffer): any +export function parseHeader(pathOrBuf: string | Buffer): any +export function parseEvent(pathOrBuf: string | Buffer, eventName: string, playerExtra?: Array | undefined | null, otherExtra?: Array | undefined | null): any +export function parseEvents(pathOrBuf: string | Buffer, eventNames?: Array | undefined | null, playerExtra?: Array | undefined | null, otherExtra?: Array | undefined | null): any +export function parseTicks(pathOrBuf: string | Buffer, wantedProps: Array, wantedTicks?: Array | undefined | null, wantedPlayers?: Array | undefined | null, structOfArrays?: boolean | undefined | null, orderBySteamid?: boolean | undefined | null, propStates?: Array | undefined | null): any +export function parsePlayerInfo(pathOrBuf: string | Buffer): any +export function parsePlayerSkins(pathOrBuf: string | Buffer): any +export declare class JsVariant { } +export declare class WantedPropState { + prop: string + state: JsVariant +} diff --git a/src/node/index.js b/src/node/index.js index f1a96e6d..4fbb1b88 100644 --- a/src/node/index.js +++ b/src/node/index.js @@ -224,14 +224,72 @@ switch (platform) { } break case 'arm': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'demoparser2.linux-arm-musleabihf.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./demoparser2.linux-arm-musleabihf.node') + } else { + nativeBinding = require('@laihoe/demoparser2-linux-arm-musleabihf') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'demoparser2.linux-arm-gnueabihf.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./demoparser2.linux-arm-gnueabihf.node') + } else { + nativeBinding = require('@laihoe/demoparser2-linux-arm-gnueabihf') + } + } catch (e) { + loadError = e + } + } + break + case 'riscv64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'demoparser2.linux-riscv64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./demoparser2.linux-riscv64-musl.node') + } else { + nativeBinding = require('@laihoe/demoparser2-linux-riscv64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'demoparser2.linux-riscv64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./demoparser2.linux-riscv64-gnu.node') + } else { + nativeBinding = require('@laihoe/demoparser2-linux-riscv64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 's390x': localFileExisted = existsSync( - join(__dirname, 'demoparser2.linux-arm-gnueabihf.node') + join(__dirname, 'demoparser2.linux-s390x-gnu.node') ) try { if (localFileExisted) { - nativeBinding = require('./demoparser2.linux-arm-gnueabihf.node') + nativeBinding = require('./demoparser2.linux-s390x-gnu.node') } else { - nativeBinding = require('@laihoe/demoparser2-linux-arm-gnueabihf') + nativeBinding = require('@laihoe/demoparser2-linux-s390x-gnu') } } catch (e) { loadError = e @@ -252,9 +310,11 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { parseChatMessages, listGameEvents, parseGrenades, parseHeader, parseEvent, parseEvents, parseTicks, parsePlayerInfo } = nativeBinding +const { JsVariant, WantedPropState, parseVoice, listGameEvents, parseGrenades, parseHeader, parseEvent, parseEvents, parseTicks, parsePlayerInfo, parsePlayerSkins } = nativeBinding -module.exports.parseChatMessages = parseChatMessages +module.exports.JsVariant = JsVariant +module.exports.WantedPropState = WantedPropState +module.exports.parseVoice = parseVoice module.exports.listGameEvents = listGameEvents module.exports.parseGrenades = parseGrenades module.exports.parseHeader = parseHeader @@ -262,3 +322,4 @@ module.exports.parseEvent = parseEvent module.exports.parseEvents = parseEvents module.exports.parseTicks = parseTicks module.exports.parsePlayerInfo = parsePlayerInfo +module.exports.parsePlayerSkins = parsePlayerSkins diff --git a/src/node/src/lib.rs b/src/node/src/lib.rs index 735646b2..c35c1b58 100644 --- a/src/node/src/lib.rs +++ b/src/node/src/lib.rs @@ -6,6 +6,9 @@ use ahash::AHashMap; use memmap2::MmapOptions; use napi::bindgen_prelude::*; use napi::Either; +use napi::JsBigInt; +use napi::JsUnknown; +use parser::first_pass::parser_settings::rm_map_user_friendly_names; use parser::first_pass::parser_settings::rm_user_friendly_names; use parser::first_pass::parser_settings::ParserInputs; use parser::parse_demo::DemoOutput; @@ -14,6 +17,7 @@ use parser::second_pass::parser_settings::create_huffman_lookup_table; use parser::second_pass::variants::soa_to_aos; use parser::second_pass::variants::BytesVariant; use parser::second_pass::variants::OutputSerdeHelperStruct; +use parser::second_pass::variants::Variant; use parser::second_pass::voice_data::convert_voice_data_to_wav; use serde_json::Value; use std::collections::HashMap; @@ -21,6 +25,108 @@ use std::fs::File; use std::hash::RandomState; use std::result::Result; +#[napi] +#[derive(Clone)] +pub struct JsVariant(Variant); + +impl FromNapiValue for JsVariant { + unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> napi::Result { + let js_unknown = JsUnknown::from_napi_value(env, napi_val)?; + + match js_unknown.get_type() { + Ok(js_unknown_type) => { + if js_unknown_type == ValueType::Boolean { + if let Ok(val) = js_unknown.coerce_to_bool() { + Ok(JsVariant(Variant::Bool(val.get_value()?))) + } else { + Err(Error::new( + Status::InvalidArg, + "Unspported Boolean type for Variant".to_owned(), + )) + } + } else if js_unknown_type == ValueType::String { + if let Ok(val) = js_unknown.coerce_to_string() { + Ok(JsVariant(Variant::String(val.into_utf8()?.into_owned()?))) + } else { + Err(Error::new( + Status::InvalidArg, + "Unsupported String for Variant".to_owned(), + )) + } + } else if js_unknown_type == ValueType::Number { + if let Ok(val) = js_unknown.coerce_to_number() { + let num = val.get_double()?; + if num.fract() == 0.0 { + if num >= u8::MIN as f64 && num <= u8::MAX as f64 { + Ok(JsVariant(Variant::U8(num as u8))) + } else if let Ok(val) = val.get_int32() { + let int32_val = val; + if int32_val >= i16::MIN as i32 && int32_val <= i16::MAX as i32 { + Ok(JsVariant(Variant::I16(int32_val as i16))) + } else { + Ok(JsVariant(Variant::I32(int32_val))) + } + } else if let Ok(val) = val.get_uint32() { + Ok(JsVariant(Variant::U32(val))) + } else { + Err(Error::new( + Status::InvalidArg, + "Unsupported number type".to_owned(), + )) + } + } else { + Ok(JsVariant(Variant::F32(num as f32))) + } + } else { + Err(Error::new( + Status::InvalidArg, + "Unsupported number type".to_owned(), + )) + } + } else if js_unknown_type == ValueType::BigInt { + let bigint_val = js_unknown.cast::(); + match bigint_val.get_u64() { + Ok((val, true)) => Ok(JsVariant(Variant::U64(val))), + _ => Err(Error::new( + Status::InvalidArg, + "Unsupported number type".to_owned(), + )), + } + } else { + Err(Error::new( + Status::InvalidArg, + "Unspported type for Variant".to_owned(), + )) + } + } + _ => Err(Error::new( + Status::InvalidArg, + "Unspported type for Variant".to_owned(), + )), + } + } +} + +#[napi] +pub struct WantedPropState { + pub prop: String, + pub state: JsVariant, +} + +impl FromNapiValue for WantedPropState { + unsafe fn from_napi_value( + env: sys::napi_env, + napi_val: napi::sys::napi_value, + ) -> napi::Result { + let obj: Object = Object::from_napi_value(env, napi_val)?; + + let prop: String = obj.get_named_property("prop")?; + let state: JsVariant = obj.get_named_property("state")?; + + Ok(WantedPropState { prop, state }) + } +} + fn parse_demo(bytes: BytesVariant, parser: &mut Parser) -> Result { match bytes { BytesVariant::Mmap(m) => match parser.parse_demo(&m) { @@ -42,6 +148,7 @@ pub fn parse_voice(path_or_buf: Either) -> napi::Result) -> napi::Result) -> napi::Result) -> napi::Result wanted_players: vec![], wanted_player_props: vec![], wanted_other_props: vec![], + wanted_prop_states: AHashMap::default(), wanted_events: vec![], parse_ents: false, wanted_ticks: vec![], @@ -198,6 +308,7 @@ pub fn parse_event( wanted_players: vec![], wanted_player_props: real_names_player.clone(), wanted_other_props: real_other_props, + wanted_prop_states: AHashMap::default(), wanted_events: vec![event_name], parse_ents: true, wanted_ticks: vec![], @@ -260,6 +371,7 @@ pub fn parse_events( wanted_players: vec![], wanted_player_props: real_names_player.clone(), wanted_other_props: real_other_props.clone(), + wanted_prop_states: AHashMap::default(), wanted_events: event_names, parse_ents: true, wanted_ticks: vec![], @@ -287,6 +399,7 @@ pub fn parse_ticks( wanted_players: Option>, struct_of_arrays: Option, order_by_steamid: Option, + prop_states: Option>, ) -> napi::Result { let mut real_names = match rm_user_friendly_names(&wanted_props) { Ok(names) => names, @@ -296,6 +409,17 @@ pub fn parse_ticks( Some(v) => v.iter().map(|x| x.parse::().unwrap_or(0)).collect(), None => vec![], }; + let wanted_prop_states: AHashMap = prop_states + .unwrap_or_default() + .into_iter() + .map(|prop| (prop.prop.clone(), prop.state.0.clone())) + .collect(); + + let real_wanted_prop_states = rm_map_user_friendly_names(&wanted_prop_states); + let real_wanted_prop_states = match real_wanted_prop_states { + Ok(real_wanted_prop_states) => real_wanted_prop_states, + Err(e) => return Err(Error::new(Status::InvalidArg, format!("{}", e).to_owned())), + }; let bytes = resolve_byte_type(path_or_buf)?; let huf = create_huffman_lookup_table(); @@ -304,6 +428,12 @@ pub fn parse_ticks( for (real_name, user_friendly_name) in real_names.iter().zip(&wanted_props) { real_name_to_og_name.insert(real_name.clone(), user_friendly_name.clone()); } + for (real_name, user_friendly_name) in real_wanted_prop_states + .keys() + .zip(wanted_prop_states.keys()) + { + real_name_to_og_name.insert(real_name.clone(), user_friendly_name.clone()); + } let wanted_ticks = match wanted_ticks { Some(t) => t, @@ -320,6 +450,7 @@ pub fn parse_ticks( wanted_player_props: real_names.clone(), wanted_other_props: vec![], wanted_events: vec![], + wanted_prop_states: real_wanted_prop_states, parse_ents: true, wanted_ticks: wanted_ticks, parse_projectiles: false, @@ -391,6 +522,7 @@ pub fn parse_player_info(path_or_buf: Either) -> napi::Result) -> napi::Result (DemoOutput, PropController, BTreeMap parse_ents: true, wanted_players: vec![], wanted_ticks: (0..5).into_iter().map(|x| x * 10000).collect_vec(), + wanted_prop_states: AHashMap::default(), parse_projectiles: true, only_header: false, count_props: false, @@ -1076,6 +1079,7 @@ fn create_data() -> (DemoOutput, PropController, BTreeMap parse_ents: true, wanted_players: vec![], wanted_ticks: (0..5).into_iter().map(|x| x * 10000).collect_vec(), + wanted_prop_states: AHashMap::default(), parse_projectiles: true, only_header: false, count_props: false, @@ -1169,6 +1173,7 @@ mod tests { use crate::second_pass::variants::VarVec; use crate::second_pass::variants::VarVec::String; use crate::second_pass::variants::VarVec::*; + use crate::second_pass::variants::Variant; use ahash::AHashMap; use lazy_static::lazy_static; use memmap2::MmapOptions; @@ -1179,6 +1184,109 @@ mod tests { static ref out: (DemoOutput, PropController, BTreeMap>) = create_data(); } + #[test] + fn test_parse_ticks_prop_state_filter() { + let huf = create_huffman_lookup_table(); + let huf2 = create_huffman_lookup_table(); + + let settings = ParserInputs { + wanted_players: vec![76561198244754626], + real_name_to_og_name: AHashMap::default(), + wanted_player_props: vec!["X".to_string(), "CCSGameRulesProxy.CCSGameRules.m_bBombPlanted".to_string()], + wanted_events: vec![], + wanted_other_props: vec![], + parse_ents: true, + wanted_ticks: vec![], + wanted_prop_states: AHashMap::default(), + parse_projectiles: true, + only_header: false, + count_props: false, + only_convars: false, + huffman_lookup_table: &huf, + order_by_steamid: false, + }; + + let mut wanted_prop_states: AHashMap = AHashMap::default(); + wanted_prop_states.insert( + "CCSGameRulesProxy.CCSGameRules.m_bBombPlanted".to_string(), + Variant::Bool(true), + ); + let settings_with_filter = ParserInputs { + wanted_players: vec![76561198244754626], + real_name_to_og_name: AHashMap::default(), + wanted_player_props: vec!["X".to_string()], + wanted_events: vec![], + wanted_other_props: vec![], + parse_ents: true, + wanted_ticks: vec![], + wanted_prop_states: wanted_prop_states, + parse_projectiles: true, + only_header: false, + count_props: false, + only_convars: false, + huffman_lookup_table: &huf2, + order_by_steamid: false, + }; + + let mut ds = Parser::new(settings, crate::parse_demo::ParsingMode::ForceMultiThreaded); + let mut ds_with_filter = Parser::new(settings_with_filter, crate::parse_demo::ParsingMode::ForceMultiThreaded); + let file = File::open("test_demo.dem").unwrap(); + let mmap = unsafe { MmapOptions::new().map(&file).unwrap() }; + let output = ds.parse_demo(&mmap).unwrap(); + let output_with_filter = ds_with_filter.parse_demo(&mmap).unwrap(); + + let positions = match output + .df + .get(&PLAYER_X_ID) + .unwrap() + .data + .clone() + .unwrap_or(VarVec::F32(vec![])) + { + VarVec::F32(positions_vec) => positions_vec, + _ => vec![], + }; + let bomb_prop_id = output + .prop_controller + .prop_infos + .iter() + .find(|prop| prop.prop_name == "CCSGameRulesProxy.CCSGameRules.m_bBombPlanted") + .map(|prop| prop.id) + .unwrap(); + let bomb = match output + .df + .get(&bomb_prop_id) + .unwrap() + .data + .clone() + .unwrap_or(VarVec::Bool(vec![])) + { + VarVec::Bool(bomb_vec) => bomb_vec, + _ => vec![], + }; + let manually_filtered_positions: Vec> = positions + .iter() + .zip(bomb.iter()) + .filter_map(|(xPos, bombPlanted)| match bombPlanted { + Some(true) => Some(*xPos), + _ => None, + }) + .collect(); + let automatically_filtered_positions = match output_with_filter + .df + .get(&PLAYER_X_ID) + .unwrap() + .data + .clone() + .unwrap_or(VarVec::F32(vec![])) + { + VarVec::F32(positions_vec) => positions_vec, + _ => vec![], + }; + + assert_eq!(manually_filtered_positions, automatically_filtered_positions); + } + #[test] fn test_player_filter() { let huf = create_huffman_lookup_table(); @@ -1191,6 +1299,7 @@ mod tests { wanted_other_props: vec!["CCSTeam.m_iScore".to_string()], parse_ents: true, wanted_ticks: vec![10000, 10001], + wanted_prop_states: AHashMap::default(), parse_projectiles: true, only_header: false, count_props: false, diff --git a/src/parser/src/first_pass/parser_settings.rs b/src/parser/src/first_pass/parser_settings.rs index 3a6cdeb1..c27f5e5c 100644 --- a/src/parser/src/first_pass/parser_settings.rs +++ b/src/parser/src/first_pass/parser_settings.rs @@ -10,6 +10,7 @@ use crate::second_pass::decoder::QfMapper; use crate::second_pass::other_netmessages::Class; use crate::second_pass::parser_settings::PlayerEndMetaData; use crate::second_pass::parser_settings::SpecialIDs; +use crate::second_pass::variants::Variant; use ahash::AHashMap; use ahash::AHashSet; use ahash::RandomState; @@ -27,6 +28,7 @@ pub struct ParserInputs<'a> { pub wanted_players: Vec, pub wanted_player_props: Vec, pub wanted_other_props: Vec, + pub wanted_prop_states: AHashMap, pub wanted_ticks: Vec, pub wanted_events: Vec, pub parse_ents: bool, @@ -63,6 +65,7 @@ pub struct FirstPassParser<'a> { pub wanted_players: AHashSet, pub wanted_ticks: AHashSet, pub wanted_other_props: Vec, + pub wanted_prop_states: AHashMap, pub wanted_events: Vec, pub parse_entities: bool, pub parse_projectiles: bool, @@ -104,6 +107,7 @@ impl<'a> FirstPassParser<'a> { prop_controller: PropController::new( inputs.wanted_player_props.clone(), inputs.wanted_other_props.clone(), + inputs.wanted_prop_states.clone(), inputs.real_name_to_og_name.clone(), false, &vec!["None".to_string()], @@ -131,6 +135,7 @@ impl<'a> FirstPassParser<'a> { wanted_players: AHashSet::from_iter(inputs.wanted_players.iter().cloned()), wanted_ticks: AHashSet::from_iter(inputs.wanted_ticks.iter().cloned()), wanted_other_props: inputs.wanted_other_props.clone(), + wanted_prop_states: inputs.wanted_prop_states.clone(), settings: &inputs, controller_ids: SpecialIDs::new(), id: 0, @@ -160,6 +165,17 @@ pub fn rm_user_friendly_names(names: &Vec) -> Result, DemoPa Ok(real_names) } +pub fn rm_map_user_friendly_names(map: &AHashMap) -> Result, DemoParserError> { + let mut real_names_map: AHashMap = AHashMap::default(); + for (name, variant) in map { + match FRIENDLY_NAMES_MAPPING.get(&name) { + Some(real_name) => real_names_map.insert(real_name.to_string(), variant.clone()), + None => return Err(DemoParserError::UnknownPropName(name.to_string())), + }; + } + Ok(real_names_map) +} + pub fn create_mmap(path: String) -> Result { let file = match File::open(path) { Err(e) => return Err(DemoParserError::FileNotFound(format!("{}", e))), diff --git a/src/parser/src/first_pass/prop_controller.rs b/src/parser/src/first_pass/prop_controller.rs index c75d5046..96d0807f 100644 --- a/src/parser/src/first_pass/prop_controller.rs +++ b/src/parser/src/first_pass/prop_controller.rs @@ -2,9 +2,11 @@ use crate::first_pass::sendtables::Field; use crate::first_pass::sendtables::Serializer; use crate::first_pass::sendtables::ValueField; use crate::maps::BUTTONMAP; +use crate::maps::CUSTOM_PLAYER_PROP_IDS; use crate::maps::TYPEHM; use crate::second_pass::collect_data::PropType; use crate::second_pass::parser_settings::SpecialIDs; +use crate::second_pass::variants::Variant; use ahash::AHashMap; pub const PLAYER_ENTITY_HANDLE_MISSING: i32 = 2047; @@ -63,6 +65,8 @@ pub struct PropController { pub event_with_velocity: bool, pub needs_velocity: bool, pub path_to_name: AHashMap<[i32; 7], String>, + pub wanted_prop_states: AHashMap, + pub wanted_prop_state_infos: Vec, } #[derive(Debug, Clone, PartialEq)] @@ -74,6 +78,12 @@ pub struct PropInfo { pub is_player_prop: bool, } +#[derive(Debug, Clone, PartialEq)] +pub struct WantedPropStateInfo { + pub base: PropInfo, + pub wanted_prop_state: Variant, +} + pub enum PropCollectionType { Player, Rules, @@ -84,6 +94,7 @@ impl PropController { pub fn new( wanted_player_props: Vec, wanted_other_props: Vec, + wanted_prop_states: AHashMap, real_name_to_og_name: AHashMap, needs_velocty: bool, wanted_events: &[String], @@ -102,12 +113,15 @@ impl PropController { event_with_velocity: !wanted_events.is_empty() && needs_velocty, path_to_name: AHashMap::default(), needs_velocity: needs_velocty, + wanted_prop_states: wanted_prop_states, + wanted_prop_state_infos: vec![], } } pub fn set_custom_propinfos(&mut self) { let button_names = BUTTONMAP.keys(); let mut someid = BUTTONS_BASEID; + let mut someid2 = BUTTONS_BASEID; for bn in button_names { if self.wanted_player_props.contains(&(bn.to_string())) { self.prop_infos.push(PropInfo { @@ -119,100 +133,53 @@ impl PropController { }); someid += 1; } + if let Some(wanted_state) = self.wanted_prop_states.get(&(bn.to_string())) { + self.wanted_prop_state_infos.push(WantedPropStateInfo { + base: PropInfo { + id: someid2, + prop_type: PropType::Button, + prop_name: bn.to_string(), + prop_friendly_name: bn.to_string(), + is_player_prop: true, + }, + wanted_prop_state: wanted_state.clone(), + }); + someid2 += 1; + } } - if self - .wanted_player_props - .contains(&("active_weapon_original_owner".to_string())) - { - self.prop_infos.push(PropInfo { - id: WEAPON_ORIGINGAL_OWNER_ID, - prop_type: PropType::Custom, - prop_name: "active_weapon_original_owner".to_string(), - prop_friendly_name: "active_weapon_original_owner".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("inventory".to_string())) { - self.prop_infos.push(PropInfo { - id: INVENTORY_ID, - prop_type: PropType::Custom, - prop_name: "inventory".to_string(), - prop_friendly_name: "inventory".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("inventory_as_ids".to_string())) { - self.prop_infos.push(PropInfo { - id: INVENTORY_AS_IDS_ID, - prop_type: PropType::Custom, - prop_name: "inventory_as_ids".to_string(), - prop_friendly_name: "inventory_as_ids".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("user_id".to_string())) { - self.prop_infos.push(PropInfo { - id: USERID_ID, - prop_type: PropType::Custom, - prop_name: "user_id".to_string(), - prop_friendly_name: "user_id".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("velocity_X".to_string())) { - self.prop_infos.push(PropInfo { - id: VELOCITY_X_ID, - prop_type: PropType::Custom, - prop_name: "velocity_X".to_string(), - prop_friendly_name: "velocity_X".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("velocity_Y".to_string())) { - self.prop_infos.push(PropInfo { - id: VELOCITY_Y_ID, - prop_type: PropType::Custom, - prop_name: "velocity_Y".to_string(), - prop_friendly_name: "velocity_Y".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("velocity_Z".to_string())) { - self.prop_infos.push(PropInfo { - id: VELOCITY_Z_ID, - prop_type: PropType::Custom, - prop_name: "velocity_Z".to_string(), - prop_friendly_name: "velocity_Z".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("velocity".to_string())) { - self.prop_infos.push(PropInfo { - id: VELOCITY_ID, - prop_type: PropType::Custom, - prop_name: "velocity".to_string(), - prop_friendly_name: "velocity".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("is_alive".to_string())) { - self.prop_infos.push(PropInfo { - id: IS_ALIVE_ID, - prop_type: PropType::Custom, - prop_name: "is_alive".to_string(), - prop_friendly_name: "is_alive".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("entity_id".to_string())) { - self.prop_infos.push(PropInfo { - id: ENTITY_ID_ID, - prop_type: PropType::Custom, - prop_name: "entity_id".to_string(), - prop_friendly_name: "entity_id".to_string(), - is_player_prop: true, - }); + + for (custom_prop_name, custom_prop_id) in CUSTOM_PLAYER_PROP_IDS.entries() { + if self.wanted_player_props.contains(&(custom_prop_name.to_string())) { + self.prop_infos.push(PropInfo { + id: *custom_prop_id, + prop_type: PropType::Custom, + prop_name: custom_prop_name.to_string(), + prop_friendly_name: self + .real_name_to_og_name + .get(&custom_prop_name.to_string()) + .unwrap_or(&custom_prop_name.to_string()) + .to_string(), + is_player_prop: true, + }) + } + if let Some(wanted_state) = self.wanted_prop_states.get(&(custom_prop_name.to_string())) { + self.wanted_prop_state_infos.push(WantedPropStateInfo { + base: PropInfo { + id: *custom_prop_id, + prop_type: PropType::Custom, + prop_name: custom_prop_name.to_string(), + prop_friendly_name: self + .real_name_to_og_name + .get(&custom_prop_name.to_string()) + .unwrap_or(&custom_prop_name.to_string()) + .to_string(), + is_player_prop: true, + }, + wanted_prop_state: wanted_state.clone(), + }) + } } + if self.wanted_player_props.contains(&("game_time".to_string())) { self.prop_infos.push(PropInfo { id: GAME_TIME_ID, @@ -222,6 +189,18 @@ impl PropController { is_player_prop: true, }); } + if let Some(wanted_state) = self.wanted_prop_states.get(&("game_time".to_string())) { + self.wanted_prop_state_infos.push(WantedPropStateInfo { + base: PropInfo { + id: GAME_TIME_ID, + prop_type: PropType::GameTime, + prop_name: "game_time".to_string(), + prop_friendly_name: "game_time".to_string(), + is_player_prop: true, + }, + wanted_prop_state: wanted_state.clone(), + }); + } // Can also be non-player prop if self.wanted_other_props.contains(&("game_time".to_string())) { self.prop_infos.push(PropInfo { @@ -232,123 +211,7 @@ impl PropController { is_player_prop: false, }); } - if self.wanted_player_props.contains(&("weapon_skin".to_string())) { - self.prop_infos.push(PropInfo { - id: WEAPON_SKIN_NAME, - prop_type: PropType::Custom, - prop_name: "weapon_skin".to_string(), - prop_friendly_name: "active_weapon_skin".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("weapon_skin_id".to_string())) { - self.prop_infos.push(PropInfo { - id: WEAPON_SKIN_ID, - prop_type: PropType::Custom, - prop_name: "weapon_skin_id".to_string(), - prop_friendly_name: "weapon_skin_id".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("weapon_paint_seed".to_string())) { - self.prop_infos.push(PropInfo { - id: WEAPON_PAINT_SEED, - prop_type: PropType::Custom, - prop_name: "weapon_paint_seed".to_string(), - prop_friendly_name: "weapon_paint_seed".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("weapon_float".to_string())) { - self.prop_infos.push(PropInfo { - id: WEAPON_FLOAT, - prop_type: PropType::Custom, - prop_name: "weapon_float".to_string(), - prop_friendly_name: "weapon_float".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("weapon_stickers".to_string())) { - self.prop_infos.push(PropInfo { - id: WEAPON_STICKERS_ID, - prop_type: PropType::Custom, - prop_name: "weapon_stickers".to_string(), - prop_friendly_name: "weapon_stickers".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("weapon_name".to_string())) { - self.prop_infos.push(PropInfo { - id: WEAPON_NAME_ID, - prop_type: PropType::Custom, - prop_name: "weapon_name".to_string(), - prop_friendly_name: "active_weapon_name".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("pitch".to_string())) { - self.prop_infos.push(PropInfo { - id: PITCH_ID, - prop_type: PropType::Custom, - prop_name: "pitch".to_string(), - prop_friendly_name: "pitch".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("yaw".to_string())) { - self.prop_infos.push(PropInfo { - id: YAW_ID, - prop_type: PropType::Custom, - prop_name: "yaw".to_string(), - prop_friendly_name: "yaw".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("agent_skin".to_string())) { - self.prop_infos.push(PropInfo { - id: AGENT_SKIN_ID, - prop_type: PropType::Custom, - prop_name: "agent_skin".to_string(), - prop_friendly_name: "agent_skin".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("X".to_string())) { - self.prop_infos.push(PropInfo { - id: PLAYER_X_ID, - prop_type: PropType::Custom, - prop_name: "X".to_string(), - prop_friendly_name: "X".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("Y".to_string())) { - self.prop_infos.push(PropInfo { - id: PLAYER_Y_ID, - prop_type: PropType::Custom, - prop_name: "Y".to_string(), - prop_friendly_name: "Y".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("Z".to_string())) { - self.prop_infos.push(PropInfo { - id: PLAYER_Z_ID, - prop_type: PropType::Custom, - prop_name: "Z".to_string(), - prop_friendly_name: "Z".to_string(), - is_player_prop: true, - }); - } - if self.wanted_player_props.contains(&("is_airborne".to_string())) { - self.prop_infos.push(PropInfo { - id: IS_AIRBORNE_ID, - prop_type: PropType::Custom, - prop_name: "is_airborne".to_string(), - prop_friendly_name: "is_airborne".to_string(), - is_player_prop: true, - }); - } + self.prop_infos.push(PropInfo { id: TICK_ID, prop_type: PropType::Tick, @@ -356,7 +219,6 @@ impl PropController { prop_friendly_name: "tick".to_string(), is_player_prop: true, }); - self.prop_infos.push(PropInfo { id: STEAMID_ID, prop_type: PropType::Steamid, @@ -423,6 +285,22 @@ impl PropController { is_player_prop: false, }) } + if let Some(wanted_state) = self.wanted_prop_states.get(&prop_name.to_string()) { + self.wanted_prop_state_infos.push(WantedPropStateInfo { + base: PropInfo { + id: f.prop_id as u32, + prop_type: *prop_type, + prop_name: prop_name.to_string(), + prop_friendly_name: self + .real_name_to_og_name + .get(&prop_name.to_string()) + .unwrap_or(&(prop_name.to_string())) + .to_string(), + is_player_prop: true, + }, + wanted_prop_state: wanted_state.clone(), + }); + } } } pub fn handle_prop(&mut self, full_name: &str, f: &mut ValueField, path: Vec) { diff --git a/src/parser/src/first_pass/sendtables.rs b/src/parser/src/first_pass/sendtables.rs index c7fd557b..b08fad34 100644 --- a/src/parser/src/first_pass/sendtables.rs +++ b/src/parser/src/first_pass/sendtables.rs @@ -97,6 +97,7 @@ impl<'a> FirstPassParser<'a> { let mut prop_controller = PropController::new( self.wanted_player_props.clone(), self.wanted_other_props.clone(), + self.wanted_prop_states.clone(), self.real_name_to_og_name.clone(), needs_velocity(&self.wanted_player_props), &self.wanted_events, diff --git a/src/parser/src/maps.rs b/src/parser/src/maps.rs index 24bceca4..fa2ea434 100644 --- a/src/parser/src/maps.rs +++ b/src/parser/src/maps.rs @@ -1,3 +1,26 @@ +use crate::first_pass::prop_controller::AGENT_SKIN_ID; +use crate::first_pass::prop_controller::ENTITY_ID_ID; +use crate::first_pass::prop_controller::INVENTORY_AS_IDS_ID; +use crate::first_pass::prop_controller::INVENTORY_ID; +use crate::first_pass::prop_controller::IS_AIRBORNE_ID; +use crate::first_pass::prop_controller::IS_ALIVE_ID; +use crate::first_pass::prop_controller::PITCH_ID; +use crate::first_pass::prop_controller::PLAYER_X_ID; +use crate::first_pass::prop_controller::PLAYER_Y_ID; +use crate::first_pass::prop_controller::PLAYER_Z_ID; +use crate::first_pass::prop_controller::USERID_ID; +use crate::first_pass::prop_controller::VELOCITY_ID; +use crate::first_pass::prop_controller::VELOCITY_X_ID; +use crate::first_pass::prop_controller::VELOCITY_Y_ID; +use crate::first_pass::prop_controller::VELOCITY_Z_ID; +use crate::first_pass::prop_controller::WEAPON_FLOAT; +use crate::first_pass::prop_controller::WEAPON_NAME_ID; +use crate::first_pass::prop_controller::WEAPON_ORIGINGAL_OWNER_ID; +use crate::first_pass::prop_controller::WEAPON_PAINT_SEED; +use crate::first_pass::prop_controller::WEAPON_SKIN_ID; +use crate::first_pass::prop_controller::WEAPON_SKIN_NAME; +use crate::first_pass::prop_controller::WEAPON_STICKERS_ID; +use crate::first_pass::prop_controller::YAW_ID; use crate::first_pass::read_bits::DemoParserError; use crate::second_pass::collect_data::PropType; use crate::second_pass::decoder::Decoder; @@ -1931,6 +1954,32 @@ pub static PAINTKITS: phf::Map = phf_map! { 10088_u32=>"Unhinged", }; +pub static CUSTOM_PLAYER_PROP_IDS: phf::Map<&'static str, u32> = phf_map! { + "entity_id" => ENTITY_ID_ID, + "user_id"=> USERID_ID, + "X"=> PLAYER_X_ID, + "Y"=> PLAYER_Y_ID, + "Z"=> PLAYER_Z_ID, + "velocity_X" => VELOCITY_X_ID, + "velocity_Y" => VELOCITY_Y_ID, + "velocity_Z" => VELOCITY_Z_ID, + "velocity" => VELOCITY_ID, + "pitch"=> PITCH_ID, + "yaw"=> YAW_ID, + "is_alive" => IS_ALIVE_ID, + "is_airborne" => IS_AIRBORNE_ID, + "agent_skin" => AGENT_SKIN_ID, + "inventory" => INVENTORY_ID, + "inventory_as_ids" => INVENTORY_AS_IDS_ID, + "active_weapon_original_owner" => WEAPON_ORIGINGAL_OWNER_ID, + "weapon_name" => WEAPON_NAME_ID, + "weapon_skin" => WEAPON_SKIN_NAME, + "weapon_skin_id" => WEAPON_SKIN_ID, + "weapon_paint_seed" => WEAPON_PAINT_SEED, + "weapon_float" => WEAPON_FLOAT, + "weapon_stickers" => WEAPON_STICKERS_ID, +}; + pub static TYPEHM: phf::Map<&'static str, PropType> = phf_map! { "FORWARD" => PropType::Button, "LEFT" => PropType::Button, diff --git a/src/parser/src/second_pass/collect_data.rs b/src/parser/src/second_pass/collect_data.rs index d9e33e5b..539d9b97 100644 --- a/src/parser/src/second_pass/collect_data.rs +++ b/src/parser/src/second_pass/collect_data.rs @@ -70,6 +70,19 @@ impl<'a> SecondPassParser<'a> { // iterate every player and every wanted prop name // if either one is missing then push None to output for (entity_id, player) in &self.players { + // iterate every wanted prop state + // if any prop's state for this tick is not the wanted state, dont extract info from tick + for wanted_prop_state_info in &self.prop_controller.wanted_prop_state_infos { + match self.find_prop(&wanted_prop_state_info.base, entity_id, player) { + Ok(prop) => { + if prop != wanted_prop_state_info.wanted_prop_state { + return; + } + } + Err(_e) => return, + } + } + for prop_info in &self.prop_controller.prop_infos { let player_steamid = match player.steamid { Some(steamid) => steamid, diff --git a/src/parser/src/second_pass/parser_settings.rs b/src/parser/src/second_pass/parser_settings.rs index 8554853c..c7f390d0 100644 --- a/src/parser/src/second_pass/parser_settings.rs +++ b/src/parser/src/second_pass/parser_settings.rs @@ -137,7 +137,14 @@ impl<'a> SecondPassParser<'a> { header: None, player_md: self.player_end_data, game_events_counter: self.game_events_counter, - prop_info: PropController::new(vec![], vec![], AHashMap::default(), false, &["none".to_string()]), + prop_info: PropController::new( + vec![], + vec![], + AHashMap::default(), + AHashMap::default(), + false, + &["none".to_string()], + ), projectiles: self.projectile_records, ptr: self.ptr, df_per_player: self.df_per_player, diff --git a/src/python/Cargo.lock b/src/python/Cargo.lock index 896894e0..8f99c620 100644 --- a/src/python/Cargo.lock +++ b/src/python/Cargo.lock @@ -374,7 +374,7 @@ dependencies = [ [[package]] name = "demoparser2" -version = "0.26.2" +version = "0.32.0" dependencies = [ "ahash", "csgoproto", @@ -1318,9 +1318,9 @@ dependencies = [ [[package]] name = "protobuf" -version = "3.3.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65f4a8ec18723a734e5dc09c173e0abf9690432da5340285d536edcb4dac190" +checksum = "df67496db1a89596beaced1579212e9b7c53c22dca1d9745de00ead76573d514" dependencies = [ "bytes", "once_cell", @@ -1330,9 +1330,9 @@ dependencies = [ [[package]] name = "protobuf-support" -version = "3.3.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6872f4d4f4b98303239a2b5838f5bbbb77b01ffc892d627957f37a22d7cfe69c" +checksum = "70e2d30ab1878b2e72d1e2fc23ff5517799c9929e2cf81a8516f9f4dcf2b9cf3" dependencies = [ "thiserror", ] diff --git a/src/python/src/lib.rs b/src/python/src/lib.rs index a28d6de0..0d916cec 100644 --- a/src/python/src/lib.rs +++ b/src/python/src/lib.rs @@ -2,6 +2,7 @@ use ahash::AHashMap; use itertools::Itertools; use memmap2::Mmap; use parser::first_pass::parser_settings::create_mmap; +use parser::first_pass::parser_settings::rm_map_user_friendly_names; use parser::first_pass::parser_settings::rm_user_friendly_names; use parser::first_pass::parser_settings::ParserInputs; use parser::first_pass::read_bits::DemoParserError; @@ -35,6 +36,38 @@ use std::sync::Arc; use pyo3::create_exception; create_exception!(DemoParser, Exception, pyo3::exceptions::PyException); +struct PyVariant(Variant); + +impl<'source> FromPyObject<'source> for PyVariant { + fn extract_bound(obj: &pyo3::Bound<'source, PyAny>) -> PyResult { + if let Ok(val) = obj.extract::() { + Ok(PyVariant(Variant::Bool(val))) + } else if let Ok(val) = obj.extract::() { + Ok(PyVariant(Variant::String(val))) + } else if let Ok(val) = obj.extract::() { + Ok(PyVariant(Variant::U8(val))) + } else if let Ok(val) = obj.extract::() { + Ok(PyVariant(Variant::I16(val))) + } else if let Ok(val) = obj.extract::() { + Ok(PyVariant(Variant::I32(val))) + } else if let Ok(val) = obj.extract::() { + Ok(PyVariant(Variant::U32(val))) + } else if let Ok(val) = obj.extract::() { + Ok(PyVariant(Variant::U64(val))) + } else if let Ok(val) = obj.extract::() { + Ok(PyVariant(Variant::F32(val))) + } else { + Err(PyValueError::new_err("Unsupported type for Variant")) + } + } +} + +#[derive(FromPyObject)] +struct WantedPropState { + prop: String, + state: PyVariant, +} + #[pymethods] impl DemoParser { #[new] @@ -60,6 +93,7 @@ impl DemoParser { wanted_players: vec![], wanted_player_props: vec![], wanted_other_props: vec![], + wanted_prop_states: AHashMap::default(), wanted_events: vec![], parse_ents: false, wanted_ticks: vec![], @@ -87,6 +121,7 @@ impl DemoParser { wanted_players: vec![], wanted_player_props: vec![], wanted_other_props: vec![], + wanted_prop_states: AHashMap::default(), wanted_events: vec!["all".to_string()], parse_ents: false, wanted_ticks: vec![], @@ -121,6 +156,7 @@ impl DemoParser { wanted_players: vec![], wanted_player_props: vec![], wanted_other_props: vec![], + wanted_prop_states: AHashMap::default(), wanted_events: vec![], parse_ents: true, wanted_ticks: vec![], @@ -191,6 +227,7 @@ impl DemoParser { wanted_players: vec![], wanted_player_props: vec![], wanted_other_props: vec![], + wanted_prop_states: AHashMap::default(), wanted_events: vec![], parse_ents: false, wanted_ticks: vec![], @@ -235,6 +272,7 @@ impl DemoParser { wanted_players: vec![], wanted_player_props: vec![], wanted_other_props: vec![], + wanted_prop_states: AHashMap::default(), wanted_events: vec![], parse_ents: false, wanted_ticks: vec![], @@ -315,6 +353,7 @@ impl DemoParser { wanted_players: vec![], wanted_player_props: vec![], wanted_other_props: vec![], + wanted_prop_states: AHashMap::default(), wanted_events: vec![], parse_ents: false, wanted_ticks: vec![], @@ -389,6 +428,7 @@ impl DemoParser { ) -> PyResult> { let wanted_player_props = player.unwrap_or_default(); let wanted_other_props = other.unwrap_or_default(); + let real_player_props = rm_user_friendly_names(&wanted_player_props); let real_other_props = rm_user_friendly_names(&wanted_other_props); @@ -400,6 +440,7 @@ impl DemoParser { Ok(real_props) => real_props, Err(e) => return Err(PyValueError::new_err(format!("{e}"))), }; + let mut real_name_to_og_name = AHashMap::default(); for (real_name, user_friendly_name) in real_player_props.iter().zip(&wanted_player_props) { real_name_to_og_name.insert(real_name.clone(), user_friendly_name.clone()); @@ -414,6 +455,7 @@ impl DemoParser { wanted_player_props: real_player_props, wanted_other_props: real_other_props, wanted_events: vec![event_name], + wanted_prop_states: AHashMap::default(), parse_ents: true, wanted_ticks: vec![], parse_projectiles: false, @@ -445,6 +487,7 @@ impl DemoParser { ) -> PyResult> { let wanted_player_props = player.unwrap_or_default(); let wanted_other_props = other.unwrap_or_default(); + let real_player_props = rm_user_friendly_names(&wanted_player_props); let real_other_props = rm_user_friendly_names(&wanted_other_props); @@ -456,6 +499,7 @@ impl DemoParser { Ok(real_props) => real_props, Err(e) => return Err(PyValueError::new_err(format!("{e}"))), }; + let mut real_name_to_og_name = AHashMap::default(); for (real_name, user_friendly_name) in real_player_props.iter().zip(&wanted_player_props) { real_name_to_og_name.insert(real_name.clone(), user_friendly_name.clone()); @@ -470,6 +514,7 @@ impl DemoParser { wanted_player_props: real_player_props, wanted_other_props: real_other_props, wanted_events: event_name, + wanted_prop_states: AHashMap::default(), parse_ents: true, wanted_ticks: vec![], parse_projectiles: false, @@ -496,6 +541,7 @@ impl DemoParser { wanted_players: vec![], wanted_player_props: vec![], wanted_other_props: vec![], + wanted_prop_states: AHashMap::default(), wanted_events: vec![], wanted_ticks: vec![], real_name_to_og_name: AHashMap::default(), @@ -521,34 +567,53 @@ impl DemoParser { Ok(out_hm.to_object(py)) } - #[pyo3(signature = (wanted_props, *, players=None, ticks=None))] + #[pyo3(signature = (wanted_props, *, players=None, ticks=None, prop_states=None))] pub fn parse_ticks( &self, py: Python, wanted_props: Vec, players: Option>, ticks: Option>, + prop_states: Option>, ) -> PyResult { let wanted_players = players.unwrap_or_default(); let wanted_ticks = ticks.unwrap_or_default(); + let wanted_prop_states = prop_states + .unwrap_or_default() + .into_iter() + .map(|prop| (prop.prop, prop.state.0)) + .collect(); let real_props = rm_user_friendly_names(&wanted_props); + let real_wanted_prop_states = rm_map_user_friendly_names(&wanted_prop_states); let real_props = match real_props { Ok(real_props) => real_props, Err(e) => return Err(Exception::new_err(format!("{e}"))), }; + let real_wanted_prop_states = match real_wanted_prop_states { + Ok(real_wanted_prop_states) => real_wanted_prop_states, + Err(e) => return Err(Exception::new_err(format!("{e}"))), + }; let arc_huf = Arc::new(&self.huf); let mut real_name_to_og_name = AHashMap::default(); for (real_name, user_friendly_name) in real_props.iter().zip(&wanted_props) { real_name_to_og_name.insert(real_name.clone(), user_friendly_name.clone()); } + for (real_name, user_friendly_name) in real_wanted_prop_states + .keys() + .zip(wanted_prop_states.keys()) + { + real_name_to_og_name.insert(real_name.clone(), user_friendly_name.clone()); + } + let settings = ParserInputs { real_name_to_og_name, wanted_players, wanted_player_props: real_props, wanted_other_props: vec![], wanted_events: vec![], + wanted_prop_states: real_wanted_prop_states, parse_ents: true, wanted_ticks, parse_projectiles: false, diff --git a/src/python/tests/signature_tests.py b/src/python/tests/signature_tests.py index 5e68a4bd..6796bbfe 100644 --- a/src/python/tests/signature_tests.py +++ b/src/python/tests/signature_tests.py @@ -6,6 +6,12 @@ demo_path = "../parser/test_demo.dem" +class WantedPropState: + def __init__(self, prop, state): + self.prop = prop + self.state = state + + class SignatureTest(TestCase): def test_parse_header_signature(self): parser = DemoParser(demo_path) @@ -128,6 +134,7 @@ def test_parse_ticks_signature(self): parser.parse_ticks(["X", "Y"], players=[1, 2, 3], ticks=[1, 2, 3]) parser.parse_ticks(["X", "Y"], players=None, ticks=None) parser.parse_ticks(["X", "Y"], players=[], ticks=[]) + parser.parse_ticks(["X", "Y"], prop_states=[WantedPropState("is_alive", True), WantedPropState("is_bomb_planted", True)]) with self.assertRaises(TypeError): parser.parse_ticks(["X", "Y"], players=5, ticks=None) @@ -141,6 +148,9 @@ def test_parse_ticks_signature(self): with self.assertRaises(TypeError): parser.parse_ticks(5) + with self.assertRaises(AttributeError): + parser.parse_ticks(["X", "Y"], prop_states=[{"prop": "is_alive", "state": True}]) + if __name__ == "__main__": unittest.main()