more and better

This commit is contained in:
Robin Appelman 2022-08-25 23:55:50 +02:00
commit 0572f34c99
6 changed files with 745 additions and 177 deletions

460
Cargo.lock generated
View file

@ -1,55 +1,52 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.13" version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "bitbuffer" name = "bitbuffer"
version = "0.8.0" version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2b3cd4415fb790abfc898cd449f319029933a867462634dbd427c3f884ba6c5" checksum = "d75a9c93bd4423a7740feae26d6daf52b7d53451cba0b2d6bed59b836c32e15c"
dependencies = [ dependencies = [
"bitbuffer_derive", "bitbuffer_derive",
"err-derive", "err-derive",
"memchr", "memchr",
"num-traits", "num-traits 0.2.15",
"serde",
] ]
[[package]] [[package]]
name = "bitbuffer_derive" name = "bitbuffer_derive"
version = "0.8.0" version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f51dcbe693d21078994abd2afac5adc9bcc80fbdf80206ebdb33fec4a145693" checksum = "4090254bfbc71442ff4a426ddba663346e26fd14b55b259281f763e350d7f621"
dependencies = [ dependencies = [
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"syn", "syn",
"syn_util", "syn_util",
] ]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.4.0" version = "3.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
[[package]]
name = "byteorder"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -58,55 +55,66 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]] [[package]]
name = "console_error_panic_hook" name = "cfg-if"
version = "0.1.6" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]] [[package]]
name = "derivative" name = "either"
version = "2.1.1" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "enum_primitive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
dependencies = [ dependencies = [
"proc-macro2 1.0.24", "num-traits 0.1.43",
"quote 1.0.7",
"syn",
] ]
[[package]] [[package]]
name = "enumflags2" name = "enumflags2"
version = "0.6.4" version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0" checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb"
dependencies = [ dependencies = [
"enumflags2_derive", "enumflags2_derive",
"serde",
] ]
[[package]] [[package]]
name = "enumflags2_derive" name = "enumflags2_derive"
version = "0.6.4" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce" checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae"
dependencies = [ dependencies = [
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"syn", "syn",
] ]
[[package]] [[package]]
name = "err-derive" name = "err-derive"
version = "0.2.4" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22deed3a8124cff5fa835713fa105621e43bbdc46690c3a6b68328a012d350d4" checksum = "c34a887c8df3ed90498c1c437ce21f211c8e27672921a8ffa293cb8d6d4caa9e"
dependencies = [ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"rustversion", "rustversion",
"syn", "syn",
"synstructure", "synstructure",
@ -120,21 +128,30 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.1.30" version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
[[package]]
name = "itertools"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.6" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.45" version = "0.3.59"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8" checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
@ -147,30 +164,30 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.79" version = "0.2.132"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.11" version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
] ]
[[package]] [[package]]
name = "main_error" name = "main_error"
version = "0.1.1" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb63bb1e282e0b6aba0addb1f0e87cb5181ea68142b2dfd21ba108f8e8088a64" checksum = "155db5e86c6e45ee456bf32fad5a290ee1f7151c2faca27ea27097568da67d1a"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.3.3" version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]] [[package]]
name = "memory_units" name = "memory_units"
@ -179,47 +196,122 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3"
[[package]] [[package]]
name = "num-traits" name = "num"
version = "0.2.12" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits 0.2.15",
]
[[package]]
name = "num-bigint"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3"
dependencies = [
"autocfg",
"num-integer",
"num-traits 0.2.15",
]
[[package]]
name = "num-complex"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5"
dependencies = [
"num-traits 0.2.15",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits 0.2.15",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits 0.2.15",
]
[[package]]
name = "num-rational"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits 0.2.15",
]
[[package]]
name = "num-traits"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
dependencies = [
"num-traits 0.2.15",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
[[package]] [[package]]
name = "num_enum" name = "num_enum"
version = "0.5.1" version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066" checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
dependencies = [ dependencies = [
"derivative",
"num_enum_derive", "num_enum_derive",
] ]
[[package]] [[package]]
name = "num_enum_derive" name = "num_enum_derive"
version = "0.5.1" version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e" checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"syn", "syn",
] ]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.5.2" version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
[[package]] [[package]]
name = "parse-display" name = "parse-display"
version = "0.4.0" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12035532e456d9f4f59fcfa3834dc5f45b391d9029f5287292bf41960b05ce91" checksum = "813e91c6232dbeb2e9deba0eb0dc5c967bd6f380676fd34419f9ddd71411faa7"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"parse-display-derive", "parse-display-derive",
@ -228,24 +320,27 @@ dependencies = [
[[package]] [[package]]
name = "parse-display-derive" name = "parse-display-derive"
version = "0.4.0" version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "449f5881ab953fa168d60a57dd182a3e1fdeff16bb9bdd309145fbd8f32326ec" checksum = "007ed61a69cf7d9b95cc5dc18489dbb4f70d4adb0a0c100e2dd46f0be241711a"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"regex", "regex",
"regex-syntax", "regex-syntax",
"structmeta",
"syn", "syn",
] ]
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "0.1.5" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
dependencies = [ dependencies = [
"once_cell",
"thiserror",
"toml", "toml",
] ]
@ -256,8 +351,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [ dependencies = [
"proc-macro-error-attr", "proc-macro-error-attr",
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"syn", "syn",
"version_check", "version_check",
] ]
@ -268,8 +363,8 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [ dependencies = [
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"version_check", "version_check",
] ]
@ -284,11 +379,11 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.24" version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
dependencies = [ dependencies = [
"unicode-xid 0.2.1", "unicode-ident",
] ]
[[package]] [[package]]
@ -302,47 +397,41 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.7" version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [ dependencies = [
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
] ]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.3.9" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-syntax", "regex-syntax",
"thread_local",
] ]
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.18" version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.3" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9bdc5e856e51e685846fb6c13a1f5e5432946c2c90501bdc76a1319f19e29da" checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.5" version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]] [[package]]
name = "scoped-tls" name = "scoped-tls"
@ -352,29 +441,29 @@ checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.116" version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.116" version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
dependencies = [ dependencies = [
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"syn", "syn",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.58" version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a230ea9107ca2220eea9d46de97eddcb04cd00e92d13dda78e478dd33fa82bd4" checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@ -383,34 +472,68 @@ dependencies = [
[[package]] [[package]]
name = "serde_repr" name = "serde_repr"
version = "0.1.6" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76" checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca"
dependencies = [ dependencies = [
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"syn", "syn",
] ]
[[package]] [[package]]
name = "snap" name = "snap"
version = "0.2.5" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95d697d63d44ad8b78b8d235bf85b34022a78af292c8918527c5f0cffdde7f43" checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451"
[[package]]
name = "steamid-ng"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb049f8faa2cba570c5366dbaf88ee5849725b16edb771848639fac92e33673"
dependencies = [ dependencies = [
"byteorder", "enum_primitive",
"lazy_static", "lazy_static",
"num",
"regex",
"serde",
"serde_derive",
"thiserror",
]
[[package]]
name = "structmeta"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bd9c2155aa89fb2c2cb87d99a610c689e7c47099b3e9f1c8a8f53faf4e3d2e3"
dependencies = [
"proc-macro2 1.0.43",
"quote 1.0.21",
"structmeta-derive",
"syn",
]
[[package]]
name = "structmeta-derive"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bafede0d0a2f21910f36d47b1558caae3076ed80f6f3ad0fc85a91e6ba7e5938"
dependencies = [
"proc-macro2 1.0.43",
"quote 1.0.21",
"syn",
] ]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.42" version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c51d92969d209b54a98397e1b91c8ae82d8c87a7bb87df0b29aa2ad81454228" checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
dependencies = [ dependencies = [
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"unicode-xid 0.2.1", "unicode-ident",
] ]
[[package]] [[package]]
@ -419,41 +542,41 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6754c4559b79657554e9d8a0d56e65e490c76d382b9c23108364ec4125dea23c" checksum = "6754c4559b79657554e9d8a0d56e65e490c76d382b9c23108364ec4125dea23c"
dependencies = [ dependencies = [
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"syn", "syn",
] ]
[[package]] [[package]]
name = "synstructure" name = "synstructure"
version = "0.12.4" version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
dependencies = [ dependencies = [
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"syn", "syn",
"unicode-xid 0.2.1", "unicode-xid 0.2.3",
] ]
[[package]] [[package]]
name = "tf-demo-parser" name = "tf-demo-parser"
version = "0.2.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c55bccc934036ee9fb1c88106ef3b23a4375bc2fb7cddb735e15d1f265561713"
dependencies = [ dependencies = [
"bitbuffer", "bitbuffer",
"enumflags2", "enumflags2",
"err-derive", "err-derive",
"fnv", "fnv",
"itertools",
"main_error", "main_error",
"num-traits", "num-traits 0.2.15",
"num_enum", "num_enum",
"parse-display", "parse-display",
"serde", "serde",
"serde_json", "serde_json",
"serde_repr", "serde_repr",
"snap", "snap",
"steamid-ng",
] ]
[[package]] [[package]]
@ -471,23 +594,40 @@ dependencies = [
] ]
[[package]] [[package]]
name = "thread_local" name = "thiserror"
version = "1.0.1" version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994"
dependencies = [ dependencies = [
"lazy_static", "thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21"
dependencies = [
"proc-macro2 1.0.43",
"quote 1.0.21",
"syn",
] ]
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.5.6" version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "unicode-ident"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.1.0" version = "0.1.0"
@ -496,37 +636,37 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.1" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.2" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.68" version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"wasm-bindgen-macro", "wasm-bindgen-macro",
] ]
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.68" version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68" checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"lazy_static",
"log", "log",
"proc-macro2 1.0.24", "once_cell",
"quote 1.0.7", "proc-macro2 1.0.43",
"quote 1.0.21",
"syn", "syn",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -537,7 +677,7 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c" checksum = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 0.1.10",
"futures", "futures",
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@ -546,22 +686,22 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.68" version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038" checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602"
dependencies = [ dependencies = [
"quote 1.0.7", "quote 1.0.21",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
] ]
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.68" version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da"
dependencies = [ dependencies = [
"proc-macro2 1.0.24", "proc-macro2 1.0.43",
"quote 1.0.7", "quote 1.0.21",
"syn", "syn",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
@ -569,9 +709,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.68" version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a"
[[package]] [[package]]
name = "wasm-bindgen-test" name = "wasm-bindgen-test"
@ -600,9 +740,9 @@ dependencies = [
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.45" version = "0.3.59"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d" checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@ -614,7 +754,7 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 0.1.10",
"libc", "libc",
"memory_units", "memory_units",
"winapi", "winapi",

View file

@ -26,7 +26,8 @@ wasm-opt = false
wasm-bindgen = "0.2.45" wasm-bindgen = "0.2.45"
wee_alloc = { version = "0.4.2", optional = true } wee_alloc = { version = "0.4.2", optional = true }
web-sys = { version = "0.3.22", features = ["console"] } web-sys = { version = "0.3.22", features = ["console"] }
tf-demo-parser = "0.2" #tf-demo-parser = { version = "0.4", git = "https://github.com/demostf/parser" }
tf-demo-parser = { version = "0.4", path = "../tf-demo-parser" }
[dev-dependencies] [dev-dependencies]
wasm-bindgen-test = "0.2.45" wasm-bindgen-test = "0.2.45"

View file

@ -1 +1 @@
export {parseDemo, ParsedDemo, PlayerState, WorldBoundaries, Class, Team} from "./parser"; export {parseDemo, ParsedDemo, PlayerState, WorldBoundaries, Class, Team, BuildingType} from "./parser";

View file

@ -5,13 +5,41 @@ export async function parseDemo(bytes: Uint8Array): Promise<ParsedDemo> {
const state = m.parse_demo(bytes); const state = m.parse_demo(bytes);
let playerCount = state.player_count; let playerCount = state.player_count;
let buildingCount = state.building_count;
let boundaries = state.boundaries; let boundaries = state.boundaries;
let interval_per_tick = state.interval_per_tick; let interval_per_tick = state.interval_per_tick;
let kill_ticks = m.get_kill_ticks(state);
let attackers = m.get_attacker_ids(state);
let assisters = m.get_assister_ids(state);
let victims = m.get_victim_ids(state);
let playerInfo = [];
for (let i = 0; i < playerCount; i++) {
playerInfo.push({
name: m.get_player_name(state, i),
steamId: m.get_player_steam_id(state, i),
entityId: m.get_player_entity_id(state, i),
})
}
let kills = [];
for (let i = 0; i < kill_ticks.length; i++) {
kills.push({
tick: kill_ticks[i],
attacker: attackers[i],
assister: assisters[i],
victim: victims[i],
weapon: m.get_weapon(state, i),
})
}
let map = m.get_map(state); let map = m.get_map(state);
let data = m.get_data(state); let data = m.get_data(state);
return new ParsedDemo( return new ParsedDemo(
playerCount, playerCount,
buildingCount,
{ {
boundary_min: { boundary_min: {
x: boundaries.boundary_min.x, x: boundaries.boundary_min.x,
@ -26,10 +54,18 @@ export async function parseDemo(bytes: Uint8Array): Promise<ParsedDemo> {
map, map,
interval_per_tick interval_per_tick
}, },
data data,
kills,
playerInfo
); );
} }
export interface PlayerInfo {
entityId: number,
name: string,
steamId: string,
}
export enum Team { export enum Team {
Other = 0, Other = 0,
Spectator = 1, Spectator = 1,
@ -50,6 +86,17 @@ export enum Class {
Engineer = 9, Engineer = 9,
} }
export enum BuildingType {
TeleporterEntrance = 0,
TeleporterExit = 1,
Dispenser = 2,
Level1Sentry = 3,
Level2Sentry = 4,
Level3Sentry = 5,
MiniSentry = 6,
Unknown = 7,
}
export interface WorldBoundaries { export interface WorldBoundaries {
boundary_min: { boundary_min: {
x: number, x: number,
@ -70,6 +117,19 @@ export interface PlayerState {
health: number, health: number,
team: Team, team: Team,
playerClass: Class, playerClass: Class,
info: PlayerInfo,
charge: number,
}
export interface BuildingState {
position: {
x: number,
y: number
},
angle: number,
health: number,
team: Team,
buildingType: BuildingType,
} }
export interface Header { export interface Header {
@ -77,6 +137,14 @@ export interface Header {
map: string map: string
} }
export interface Kill {
tick: number,
attacker: number,
assister: number,
victim: number,
weapon: string,
}
function unpack_f32(val: number, min: number, max: number): number { function unpack_f32(val: number, min: number, max: number): number {
const ratio = val / (Math.pow(2, 16) - 1); const ratio = val / (Math.pow(2, 16) - 1);
return ratio * (max - min) + min; return ratio * (max - min) + min;
@ -89,17 +157,23 @@ function unpack_angle(val: number): number {
export class ParsedDemo { export class ParsedDemo {
public readonly playerCount: number; public readonly playerCount: number;
public readonly buildingCount: number;
public readonly world: WorldBoundaries; public readonly world: WorldBoundaries;
public readonly data: Uint8Array; public readonly data: Uint8Array;
private readonly header: Header; private readonly header: Header;
public readonly tickCount: number; public readonly tickCount: number;
public readonly kills: Kill[];
public readonly playerInfo: PlayerInfo[];
constructor(playerCount: number, world: WorldBoundaries, header: Header, data: Uint8Array) { constructor(playerCount: number, buildingCount: number, world: WorldBoundaries, header: Header, data: Uint8Array, kills: Kill[], playerInfo: PlayerInfo[]) {
this.playerCount = playerCount; this.playerCount = playerCount;
this.buildingCount = buildingCount;
this.world = world; this.world = world;
this.header = header; this.header = header;
this.data = data; this.data = data;
this.tickCount = data.length / playerCount / PACK_SIZE; this.kills = kills;
this.playerInfo = playerInfo;
this.tickCount = data.length / (playerCount * PLAYER_PACK_SIZE + buildingCount * BUILDING_PACK_SIZE);
} }
getPlayer(tick: number, playerIndex: number): PlayerState { getPlayer(tick: number, playerIndex: number): PlayerState {
@ -107,14 +181,24 @@ export class ParsedDemo {
throw new Error("Player out of bounds"); throw new Error("Player out of bounds");
} }
const base = ((playerIndex * this.tickCount) + tick) * PACK_SIZE; const base = ((playerIndex * this.tickCount) + tick) * PLAYER_PACK_SIZE;
return unpackPlayer(this.data, base, this.world); return unpackPlayer(this.data, base, this.world, this.playerInfo[playerIndex]);
}
getBuilding(tick: number, buildingIndex: number): BuildingState {
if (buildingIndex >= this.buildingCount) {
throw new Error("Player out of bounds");
}
const base = ((buildingIndex * this.tickCount) + tick) * BUILDING_PACK_SIZE;
return unpackBuilding(this.data, base, this.world);
} }
} }
const PACK_SIZE = 7; const PLAYER_PACK_SIZE = 8;
const BUILDING_PACK_SIZE = 7;
function unpackPlayer(bytes: Uint8Array, base: number, world: WorldBoundaries): PlayerState { function unpackPlayer(bytes: Uint8Array, base: number, world: WorldBoundaries, info: PlayerInfo): PlayerState {
const x = unpack_f32(bytes[base] + (bytes[base + 1] << 8), world.boundary_min.x, world.boundary_max.x); const x = unpack_f32(bytes[base] + (bytes[base + 1] << 8), world.boundary_min.x, world.boundary_max.x);
const y = unpack_f32(bytes[base + 2] + (bytes[base + 3] << 8), world.boundary_min.y, world.boundary_max.y); const y = unpack_f32(bytes[base + 2] + (bytes[base + 3] << 8), world.boundary_min.y, world.boundary_max.y);
const team_class_health = bytes[base + 4] + (bytes[base + 5] << 8); const team_class_health = bytes[base + 4] + (bytes[base + 5] << 8);
@ -122,12 +206,33 @@ function unpackPlayer(bytes: Uint8Array, base: number, world: WorldBoundaries):
const health = team_class_health & 1013; const health = team_class_health & 1013;
const team = (team_class_health >> 14) as Team; const team = (team_class_health >> 14) as Team;
const playerClass = ((team_class_health >> 10) & 15) as Class; const playerClass = ((team_class_health >> 10) & 15) as Class;
const charge = bytes[base + 7];
return { return {
position: {x, y}, position: {x, y},
angle, angle,
health, health,
team, team,
playerClass playerClass,
info,
charge
}
}
function unpackBuilding(bytes: Uint8Array, base: number, world: WorldBoundaries): BuildingState {
const x = unpack_f32(bytes[base] + (bytes[base + 1] << 8), world.boundary_min.x, world.boundary_max.x);
const y = unpack_f32(bytes[base + 2] + (bytes[base + 3] << 8), world.boundary_min.y, world.boundary_max.y);
const team_type_health = bytes[base + 4] + (bytes[base + 5] << 8);
const angle = unpack_angle(bytes[base + 6]);
const health = team_type_health & 1013;
const team = (team_type_health >> 13) as Team;
const buildingType = ((team_type_health >> 10) & 7) as BuildingType;
return {
position: {x, y},
angle,
health,
team,
buildingType
} }
} }

View file

@ -1,9 +1,8 @@
#![feature(const_generics)]
#![allow(incomplete_features)]
#![macro_use] #![macro_use]
use crate::state::ParsedDemo; use crate::state::ParsedDemo;
use tf_demo_parser::demo::header::Header; use tf_demo_parser::demo::header::Header;
use tf_demo_parser::demo::parser::analyser::UserInfo;
use tf_demo_parser::demo::parser::gamestateanalyser::{GameStateAnalyser, World}; use tf_demo_parser::demo::parser::gamestateanalyser::{GameStateAnalyser, World};
use tf_demo_parser::demo::vector::Vector; use tf_demo_parser::demo::vector::Vector;
use tf_demo_parser::{Demo, DemoParser, ParseError}; use tf_demo_parser::{Demo, DemoParser, ParseError};
@ -43,8 +42,15 @@ impl From<World> for WorldBoundaries {
#[wasm_bindgen] #[wasm_bindgen]
pub struct FlatState { pub struct FlatState {
pub player_count: usize, pub player_count: usize,
pub building_count: usize,
pub boundaries: WorldBoundaries, pub boundaries: WorldBoundaries,
pub interval_per_tick: f32, pub interval_per_tick: f32,
kill_ticks: Box<[u32]>,
attackers: Box<[u8]>,
assisters: Box<[u8]>,
victims: Box<[u8]>,
weapons: Vec<String>,
player_info: Vec<UserInfo>,
data: Box<[u8]>, data: Box<[u8]>,
header: Header, header: Header,
} }
@ -52,21 +58,45 @@ pub struct FlatState {
impl FlatState { impl FlatState {
pub fn new(parsed: ParsedDemo, world: World) -> Self { pub fn new(parsed: ParsedDemo, world: World) -> Self {
let ParsedDemo { let ParsedDemo {
players, header, .. players,
header,
buildings,
..
} = parsed; } = parsed;
let player_count = players.len(); let player_count = players.len();
let building_count = buildings.len();
let flat: Vec<_> = players let flat: Vec<_> = players
.into_iter() .into_iter()
.chain(buildings.into_iter())
.flat_map(|player| player.into_iter()) .flat_map(|player| player.into_iter())
.collect(); .collect();
FlatState { FlatState {
player_count, player_count,
building_count,
boundaries: world.into(), boundaries: world.into(),
interval_per_tick: header.duration / (header.ticks as f32), interval_per_tick: header.duration / (header.ticks as f32),
data: flat.into_boxed_slice(), data: flat.into_boxed_slice(),
kill_ticks: parsed.kills.iter().map(|kill| kill.tick as u32).collect(),
attackers: parsed
.kills
.iter()
.map(|kill| kill.attacker_id as u8)
.collect(),
assisters: parsed
.kills
.iter()
.map(|kill| kill.assister_id as u8)
.collect(),
victims: parsed
.kills
.iter()
.map(|kill| kill.victim_id as u8)
.collect(),
weapons: parsed.kills.into_iter().map(|kill| kill.weapon).collect(),
player_info: parsed.player_info,
header, header,
} }
} }
@ -91,6 +121,46 @@ pub fn get_map(state: &FlatState) -> String {
state.header.map.clone() state.header.map.clone()
} }
#[wasm_bindgen]
pub fn get_kill_ticks(state: &FlatState) -> Box<[u32]> {
state.kill_ticks.clone()
}
#[wasm_bindgen]
pub fn get_attacker_ids(state: &FlatState) -> Box<[u8]> {
state.attackers.clone()
}
#[wasm_bindgen]
pub fn get_assister_ids(state: &FlatState) -> Box<[u8]> {
state.assisters.clone()
}
#[wasm_bindgen]
pub fn get_victim_ids(state: &FlatState) -> Box<[u8]> {
state.victims.clone()
}
#[wasm_bindgen]
pub fn get_weapon(state: &FlatState, kill_id: usize) -> String {
state.weapons[kill_id].clone()
}
#[wasm_bindgen]
pub fn get_player_name(state: &FlatState, player_id: usize) -> String {
state.player_info[player_id].name.clone()
}
#[wasm_bindgen]
pub fn get_player_entity_id(state: &FlatState, player_id: usize) -> u32 {
state.player_info[player_id].entity_id.into()
}
#[wasm_bindgen]
pub fn get_player_steam_id(state: &FlatState, player_id: usize) -> String {
state.player_info[player_id].steam_id.clone()
}
pub fn parse_demo_inner(buffer: &[u8]) -> Result<(ParsedDemo, Option<World>), ParseError> { pub fn parse_demo_inner(buffer: &[u8]) -> Result<(ParsedDemo, Option<World>), ParseError> {
let demo = Demo::new(buffer); let demo = Demo::new(buffer);
let parser = DemoParser::new_with_analyser(demo.get_stream(), GameStateAnalyser::default()); let parser = DemoParser::new_with_analyser(demo.get_stream(), GameStateAnalyser::default());
@ -108,6 +178,7 @@ pub fn parse_demo_inner(buffer: &[u8]) -> Result<(ParsedDemo, Option<World>), Pa
} }
let world: Option<&World> = ticker.state().world.as_ref(); let world: Option<&World> = ticker.state().world.as_ref();
parsed_demo.kills = ticker.state().kills.clone();
Ok((parsed_demo, world.map(|w| w.clone()))) Ok((parsed_demo, world.map(|w| w.clone())))
} }

View file

@ -1,5 +1,8 @@
use tf_demo_parser::demo::header::Header; use tf_demo_parser::demo::header::Header;
use tf_demo_parser::demo::parser::gamestateanalyser::{Class, GameState, Team, World}; use tf_demo_parser::demo::parser::analyser::UserInfo;
use tf_demo_parser::demo::parser::gamestateanalyser::{
Building, Class, GameState, Kill, PlayerState as PlayerAliveState, Team, World,
};
use tf_demo_parser::demo::vector::VectorXY; use tf_demo_parser::demo::vector::VectorXY;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
@ -23,7 +26,10 @@ impl From<Angle> for f32 {
pub struct ParsedDemo { pub struct ParsedDemo {
pub tick: usize, pub tick: usize,
pub players: Vec<Vec<u8>>, pub players: Vec<Vec<u8>>,
pub buildings: Vec<Vec<u8>>,
pub kills: Vec<Kill>,
pub header: Header, pub header: Header,
pub player_info: Vec<UserInfo>,
} }
impl ParsedDemo { impl ParsedDemo {
@ -31,6 +37,9 @@ impl ParsedDemo {
ParsedDemo { ParsedDemo {
tick: 0, tick: 0,
players: Vec::new(), players: Vec::new(),
buildings: Vec::new(),
kills: Vec::new(),
player_info: Vec::new(),
header, header,
} }
} }
@ -41,18 +50,42 @@ impl ParsedDemo {
let state = PlayerState { let state = PlayerState {
position: player.position.into(), position: player.position.into(),
angle: Angle::from(player.view_angle), angle: Angle::from(player.view_angle),
health: player.health, health: if player.state == PlayerAliveState::Alive {
player.health
} else {
0
},
team: player.team, team: player.team,
class: player.class, class: player.class,
charge: player.charge,
}; };
if let None = self.players.get(index) { if let None = self.players.get(index) {
let mut new_player = Vec::default(); let mut new_player =
Vec::with_capacity(self.header.ticks as usize * PlayerState::PACKET_SIZE);
// backfill with defaults // backfill with defaults
new_player.resize(self.tick * PlayerState::PACKET_SIZE, 0); new_player.resize(self.tick * PlayerState::PACKET_SIZE, 0);
self.players.push(new_player); self.players.push(new_player);
}; };
match (self.player_info.get(index), player.info.as_ref()) {
(None, Some(info)) => self.player_info.push(info.clone()),
_ => {}
}
let parsed_player = &mut self.players[index];
parsed_player.extend_from_slice(&state.pack(world));
}
for (index, building) in game_state.buildings.iter().enumerate() {
let state = BuildingState::new(building);
if let None = self.buildings.get(index) {
let mut new_building =
Vec::with_capacity(self.header.ticks as usize * BuildingState::PACKET_SIZE);
new_building.resize(self.tick * BuildingState::PACKET_SIZE, 0);
self.buildings.push(new_building);
};
let parsed_player = &mut self.players[index]; let parsed_player = &mut self.players[index];
parsed_player.extend_from_slice(&state.pack(world)); parsed_player.extend_from_slice(&state.pack(world));
} }
@ -74,12 +107,13 @@ pub struct PlayerState {
health: u16, health: u16,
team: Team, team: Team,
class: Class, class: Class,
charge: u8,
} }
impl PlayerState { impl PlayerState {
const PACKET_SIZE: usize = 8; const PACKET_SIZE: usize = 8;
pub fn pack(&self, world: &World) -> [u8; 7] { pub fn pack(&self, world: &World) -> [u8; Self::PACKET_SIZE] {
// for the purpose of viewing the demo in the browser we dont really need high accuracy for // for the purpose of viewing the demo in the browser we dont really need high accuracy for
// position or angle, so we save a bunch of space by truncating those down to half the number // position or angle, so we save a bunch of space by truncating those down to half the number
// of bits // of bits
@ -97,6 +131,223 @@ impl PlayerState {
((self.team as u16) << 14) + ((self.class as u16) << 10) + self.health; ((self.team as u16) << 14) + ((self.class as u16) << 10) + self.health;
let combined_bytes = team_class_health.to_le_bytes(); let combined_bytes = team_class_health.to_le_bytes();
[
x[0],
x[1],
y[0],
y[1],
combined_bytes[0],
combined_bytes[1],
self.angle.0,
self.charge,
]
}
#[allow(dead_code)]
pub fn unpack(bytes: [u8; 8], world: &World) -> Self {
fn unpack_f32(val: u16, min: f32, max: f32) -> f32 {
let ratio = val as f32 / (u16::max_value() as f32);
ratio * (max - min) + min
}
let x = unpack_f32(
u16::from_le_bytes([bytes[0], bytes[1]]),
world.boundary_min.x,
world.boundary_max.x,
);
let y = unpack_f32(
u16::from_le_bytes([bytes[2], bytes[3]]),
world.boundary_min.y,
world.boundary_max.y,
);
let team_class_health = u16::from_le_bytes([bytes[4], bytes[5]]);
let health = team_class_health & 1023;
let angle = Angle(bytes[6]);
let team = Team::new(team_class_health >> 14);
let class = Class::new((team_class_health >> 10) & 15);
let charge = bytes[7];
PlayerState {
position: VectorXY { x, y },
angle,
health,
team,
class,
charge,
}
}
}
#[test]
fn test_player_packing() {
use tf_demo_parser::demo::vector::Vector;
let world = World {
boundary_max: Vector {
x: 10000.0,
y: 10000.0,
z: 100.0,
},
boundary_min: Vector {
x: -10000.0,
y: -10000.0,
z: -100.0,
},
};
let input = PlayerState {
position: VectorXY {
x: 100.0,
y: -5000.0,
},
angle: Angle::from(213.0),
health: 250,
team: Team::Blue,
class: Class::Demoman,
charge: 7,
};
let bytes = input.pack(&world);
let unpacked = PlayerState::unpack(bytes, &world);
assert_eq!(input.angle, unpacked.angle);
assert_eq!(input.health, unpacked.health);
assert_eq!(input.class, unpacked.class);
assert_eq!(input.team, unpacked.team);
assert_eq!(input.charge, unpacked.charge);
assert!(f32::abs(input.position.x - unpacked.position.x) < 0.5);
assert!(f32::abs(input.position.y - unpacked.position.y) < 0.5);
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum BuildingType {
TeleporterEntrance = 0,
TeleporterExit = 1,
Dispenser = 2,
Level1Sentry = 3,
Level2Sentry = 4,
Level3Sentry = 5,
MiniSentry = 6,
Unknown = 7,
}
impl Default for BuildingType {
fn default() -> Self {
BuildingType::Unknown
}
}
impl BuildingType {
pub fn new(raw: u8) -> BuildingType {
match raw {
0 => Self::TeleporterEntrance,
1 => Self::TeleporterExit,
2 => Self::Dispenser,
3 => Self::Level1Sentry,
4 => Self::Level2Sentry,
5 => Self::Level3Sentry,
6 => Self::MiniSentry,
_ => Self::Unknown,
}
}
pub fn from_building(building: &Building) -> Self {
match building {
Building::Sentry { is_mini: true, .. } => BuildingType::MiniSentry,
Building::Sentry {
is_mini: false,
level: 1,
..
} => BuildingType::Level1Sentry,
Building::Sentry {
is_mini: false,
level: 2,
..
} => BuildingType::Level2Sentry,
Building::Sentry {
is_mini: false,
level: 3,
..
} => BuildingType::Level3Sentry,
Building::Dispenser { .. } => BuildingType::Dispenser,
Building::Teleporter {
is_entrance: true, ..
} => BuildingType::TeleporterEntrance,
Building::Teleporter {
is_entrance: false, ..
} => BuildingType::TeleporterExit,
_ => BuildingType::Unknown,
}
}
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct BuildingState {
position: VectorXY,
angle: Angle,
health: u16,
team: Team,
ty: BuildingType,
}
impl BuildingState {
const PACKET_SIZE: usize = 7;
pub fn new(building: &Building) -> Self {
match building {
Building::Sentry {
position,
angle,
health,
team,
..
}
| Building::Dispenser {
position,
angle,
health,
team,
..
}
| Building::Teleporter {
position,
angle,
health,
team,
..
} => BuildingState {
position: VectorXY {
x: position.x,
y: position.y,
},
angle: Angle::from(*angle),
health: *health,
team: *team,
ty: BuildingType::from_building(building),
},
}
}
pub fn pack(&self, world: &World) -> [u8; 7] {
// for the purpose of viewing the demo in the browser we dont really need high accuracy for
// position or angle, so we save a bunch of space by truncating those down to half the number
// of bits
fn pack_f32(val: f32, min: f32, max: f32) -> u16 {
let ratio = (val - min) / (max - min);
(ratio * u16::max_value() as f32) as u16
}
let x = pack_f32(self.position.x, world.boundary_min.x, world.boundary_max.x).to_le_bytes();
let y = pack_f32(self.position.y, world.boundary_min.y, world.boundary_max.y).to_le_bytes();
// 1 bits reserved
// 2 bits reserved
// 3 bits for type
// 10 bits for health
let team_type_health = ((self.team as u16) << 13) + ((self.ty as u16) << 10) + self.health;
let combined_bytes = team_type_health.to_le_bytes();
[ [
x[0], x[0],
x[1], x[1],
@ -125,24 +376,24 @@ impl PlayerState {
world.boundary_min.y, world.boundary_min.y,
world.boundary_max.y, world.boundary_max.y,
); );
let team_class_health = u16::from_le_bytes([bytes[4], bytes[5]]); let team_type_health = u16::from_le_bytes([bytes[4], bytes[5]]);
let health = team_class_health & 1023; let health = team_type_health & 1023;
let angle = Angle(bytes[6]); let angle = Angle(bytes[6]);
let team = Team::new(team_class_health >> 14); let team = Team::new(team_type_health >> 13);
let class = Class::new((team_class_health >> 10) & 15); let ty = BuildingType::new((team_type_health >> 10) as u8 & 7);
PlayerState { BuildingState {
position: VectorXY { x, y }, position: VectorXY { x, y },
angle, angle,
health, health,
team, team,
class, ty,
} }
} }
} }
#[test] #[test]
fn test_packing() { fn test_building_packing() {
use tf_demo_parser::demo::vector::Vector; use tf_demo_parser::demo::vector::Vector;
let world = World { let world = World {
@ -158,7 +409,7 @@ fn test_packing() {
}, },
}; };
let input = PlayerState { let input = BuildingState {
position: VectorXY { position: VectorXY {
x: 100.0, x: 100.0,
y: -5000.0, y: -5000.0,
@ -166,15 +417,15 @@ fn test_packing() {
angle: Angle::from(213.0), angle: Angle::from(213.0),
health: 250, health: 250,
team: Team::Blue, team: Team::Blue,
class: Class::Demoman, ty: BuildingType::Level1Sentry,
}; };
let bytes = input.pack(&world); let bytes = input.pack(&world);
let unpacked = PlayerState::unpack(bytes, &world); let unpacked = BuildingState::unpack(bytes, &world);
assert_eq!(input.angle, unpacked.angle); assert_eq!(input.angle, unpacked.angle);
assert_eq!(input.health, unpacked.health); assert_eq!(input.health, unpacked.health);
assert_eq!(input.class, unpacked.class); assert_eq!(input.ty, unpacked.ty);
assert_eq!(input.team, unpacked.team); assert_eq!(input.team, unpacked.team);
assert!(f32::abs(input.position.x - unpacked.position.x) < 0.5); assert!(f32::abs(input.position.x - unpacked.position.x) < 0.5);