Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
204dce366f | |||
99301bb990 | |||
28ffc82ac0 | |||
792c386008 | |||
151b99c3e6 | |||
b0e0bda101 | |||
510aef07a8 | |||
2c07673b7d | |||
2a73f8a469 | |||
4023ae60b1 | |||
1016f95b48 | |||
c0769abc1b | |||
74eefcb78f | |||
f770f5ac7b | |||
5b710b531e | |||
a77b2fd78f | |||
915d6c67cd | |||
9b7101cbea | |||
e67b29148e | |||
384b42f1ff | |||
aceae11d42 | |||
5123573822 | |||
49a5acf73b | |||
ba2d40970b | |||
d638e633ba | |||
61e44f2aba | |||
347b1176d2 | |||
7c0ad5b601 | |||
62851bbd60 | |||
b3a6d08656 | |||
5409548348 | |||
57552c1a6a | |||
aace3bb2a3 | |||
4899003766 | |||
0c991715ab | |||
72e0caa84a |
Cargo.lock
engine
graphics
physics
session
settings
integration-testing
lib
bsp_loader
common
deferred_loader
fixed_wide
linear_ops
ratio_ops
rbx_loader
rbxassetid
roblox_emulator
snf
map-tool
strafe-client
tools
190
Cargo.lock
generated
190
Cargo.lock
generated
@ -155,9 +155,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.95"
|
version = "1.0.96"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
|
checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "approx"
|
name = "approx"
|
||||||
@ -384,15 +384,16 @@ checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blake3"
|
name = "blake3"
|
||||||
version = "1.5.5"
|
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 = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e"
|
checksum = "1230237285e3e10cde447185e8975408ae24deaa67205ce684805c25bc0c7937"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayref",
|
"arrayref",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"constant_time_eq",
|
"constant_time_eq",
|
||||||
|
"memmap2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -428,9 +429,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "built"
|
name = "built"
|
||||||
version = "0.7.5"
|
version = "0.7.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b"
|
checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
@ -519,9 +520,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.12"
|
version = "1.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "755717a7de9ec452bf7f3f1a3099085deabd7f2962b861dae91ecd7a365903d2"
|
checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
@ -583,9 +584,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.28"
|
version = "4.5.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff"
|
checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@ -593,9 +594,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.27"
|
version = "4.5.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
|
checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@ -836,9 +837,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "document-features"
|
name = "document-features"
|
||||||
version = "0.2.10"
|
version = "0.2.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0"
|
checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"litrs",
|
"litrs",
|
||||||
]
|
]
|
||||||
@ -883,23 +884,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "err-derive"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c34a887c8df3ed90498c1c437ce21f211c8e27672921a8ffa293cb8d6d4caa9e"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"rustversion",
|
|
||||||
"syn 1.0.109",
|
|
||||||
"synstructure 0.12.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
@ -1181,9 +1168,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glam"
|
name = "glam"
|
||||||
version = "0.29.2"
|
version = "0.30.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677"
|
checksum = "17fcdf9683c406c2fc4d124afd29c0d595e22210d633cbdb8695ba9935ab1dc6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glow"
|
name = "glow"
|
||||||
@ -1259,9 +1246,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.4.7"
|
version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e"
|
checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -1713,9 +1700,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ispc_rt"
|
name = "ispc_rt"
|
||||||
version = "2.0.1"
|
version = "2.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c8d30e08ddfd6fe26c3ee2e856dff022420cd0514ed16f5ccf2dc3e1d5cae578"
|
checksum = "be3c9e80f134cdd180b136adbebdc5664605f998fcc909e1ca3605565d0f2abe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
@ -1974,9 +1961,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "luau0-src"
|
name = "luau0-src"
|
||||||
version = "0.12.0+luau657"
|
version = "0.12.2+luau660"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3a4b4c16b82ddf60e0fa93ca5a6afc504a6db22310cc82ecec629cd2e405b2ca"
|
checksum = "d62e6fe44400150a045b8f2a6721a268437d45dc67600f8ca716e2fa3a3cc2fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
@ -2145,9 +2132,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.3"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924"
|
checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler2",
|
"adler2",
|
||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
@ -2176,7 +2163,7 @@ dependencies = [
|
|||||||
"mlua-sys",
|
"mlua-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rustc-hash 2.1.0",
|
"rustc-hash 2.1.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2215,9 +2202,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.13"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c"
|
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@ -2595,15 +2582,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.20.2"
|
version = "1.20.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
version = "0.10.70"
|
version = "0.10.71"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6"
|
checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.8.0",
|
"bitflags 2.8.0",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@ -2633,9 +2620,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.105"
|
version = "0.9.106"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc"
|
checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
@ -2905,30 +2892,6 @@ dependencies = [
|
|||||||
"toml_edit",
|
"toml_edit",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error-attr",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error-attr"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.93"
|
version = "1.0.93"
|
||||||
@ -3346,15 +3309,14 @@ checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.17.8"
|
version = "0.17.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom 0.2.15",
|
"getrandom 0.2.15",
|
||||||
"libc",
|
"libc",
|
||||||
"spin",
|
|
||||||
"untrusted",
|
"untrusted",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
@ -3408,9 +3370,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "2.1.0"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
|
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
@ -3427,9 +3389,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.22"
|
version = "0.23.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7"
|
checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
@ -3544,18 +3506,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.217"
|
version = "1.0.218"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.217"
|
version = "1.0.218"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -3564,9 +3526,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.138"
|
version = "1.0.139"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
|
checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -3653,9 +3615,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.13.2"
|
version = "1.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay-client-toolkit"
|
name = "smithay-client-toolkit"
|
||||||
@ -3701,12 +3663,6 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "spin"
|
|
||||||
version = "0.9.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spirv"
|
name = "spirv"
|
||||||
version = "0.3.0+sdk-1.3.268.0"
|
version = "0.3.0+sdk-1.3.268.0"
|
||||||
@ -3947,18 +3903,6 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "synstructure"
|
|
||||||
version = "0.12.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
"unicode-xid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "synstructure"
|
name = "synstructure"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
@ -4012,9 +3956,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.16.0"
|
version = "3.17.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
|
checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
@ -4190,9 +4134,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.19"
|
version = "0.8.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
|
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
@ -4211,9 +4155,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.22.23"
|
version = "0.22.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee"
|
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde",
|
"serde",
|
||||||
@ -4300,9 +4244,9 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.16"
|
version = "1.0.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
@ -4465,16 +4409,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vtf"
|
name = "vtf"
|
||||||
version = "0.3.0"
|
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 = "66720c07784e3b49062ea42cddef8df72291f7c5d0ea7dcb5882a0653b32a21b"
|
checksum = "b76193ac26521a6c4f93d7b1f816c7003237bc3ea1dec292d848f8d98d21da46"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.5.0",
|
"byteorder 1.5.0",
|
||||||
"err-derive",
|
|
||||||
"image",
|
"image",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"parse-display 0.10.0",
|
"parse-display 0.10.0",
|
||||||
"texpresso",
|
"texpresso",
|
||||||
|
"thiserror 2.0.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5126,9 +5070,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit"
|
name = "winit"
|
||||||
version = "0.30.8"
|
version = "0.30.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f5d74280aabb958072864bff6cfbcf9025cf8bfacdde5e32b5e12920ef703b0f"
|
checksum = "a809eacf18c8eca8b6635091543f02a5a06ddf3dad846398795460e6e0ae3cc0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"android-activity",
|
"android-activity",
|
||||||
@ -5178,9 +5122,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.1"
|
version = "0.7.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86e376c75f4f43f44db463cf729e0d3acbf954d13e22c51e26e4c264b4ab545f"
|
checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@ -5290,7 +5234,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.98",
|
"syn 2.0.98",
|
||||||
"synstructure 0.13.1",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5332,7 +5276,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.98",
|
"syn 2.0.98",
|
||||||
"synstructure 0.13.1",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "strafesnet_graphics"
|
name = "strafesnet_graphics"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytemuck = { version = "1.13.1", features = ["derive"] }
|
bytemuck = { version = "1.13.1", features = ["derive"] }
|
||||||
ddsfile = "0.5.1"
|
ddsfile = "0.5.1"
|
||||||
glam = "0.29.0"
|
glam = "0.30.0"
|
||||||
id = { version = "0.1.0", registry = "strafesnet" }
|
id = { version = "0.1.0", registry = "strafesnet" }
|
||||||
strafesnet_common = { path = "../../lib/common", registry = "strafesnet" }
|
strafesnet_common = { path = "../../lib/common", registry = "strafesnet" }
|
||||||
strafesnet_session = { path = "../session", registry = "strafesnet" }
|
strafesnet_session = { path = "../session", registry = "strafesnet" }
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "strafesnet_physics"
|
name = "strafesnet_physics"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
arrayvec = "0.7.6"
|
arrayvec = "0.7.6"
|
||||||
glam = "0.29.0"
|
glam = "0.30.0"
|
||||||
id = { version = "0.1.0", registry = "strafesnet" }
|
id = { version = "0.1.0", registry = "strafesnet" }
|
||||||
strafesnet_common = { path = "../../lib/common", registry = "strafesnet" }
|
strafesnet_common = { path = "../../lib/common", registry = "strafesnet" }
|
||||||
|
@ -484,12 +484,15 @@ impl TransformedMesh<'_>{
|
|||||||
pub fn verts<'a>(&'a self)->impl Iterator<Item=vec3::Vector3<Fixed<2,64>>>+'a{
|
pub fn verts<'a>(&'a self)->impl Iterator<Item=vec3::Vector3<Fixed<2,64>>>+'a{
|
||||||
self.view.data.verts.iter().map(|&Vert(pos)|self.transform.vertex.transform_point3(pos))
|
self.view.data.verts.iter().map(|&Vert(pos)|self.transform.vertex.transform_point3(pos))
|
||||||
}
|
}
|
||||||
|
pub fn faces(&self)->impl Iterator<Item=SubmeshFaceId>{
|
||||||
|
(0..self.view.topology.faces.len() as u32).map(SubmeshFaceId::new)
|
||||||
|
}
|
||||||
fn farthest_vert(&self,dir:Planar64Vec3)->SubmeshVertId{
|
fn farthest_vert(&self,dir:Planar64Vec3)->SubmeshVertId{
|
||||||
//this happens to be well-defined. there are no virtual virtices
|
//this happens to be well-defined. there are no virtual virtices
|
||||||
SubmeshVertId::new(
|
SubmeshVertId::new(
|
||||||
self.view.topology.verts.iter()
|
self.view.topology.verts.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.max_by_key(|(_,&vert_id)|
|
.max_by_key(|&(_,&vert_id)|
|
||||||
dir.dot(self.transform.vertex.transform_point3(self.view.data.verts[vert_id.get() as usize].0))
|
dir.dot(self.transform.vertex.transform_point3(self.view.data.verts[vert_id.get() as usize].0))
|
||||||
)
|
)
|
||||||
//assume there is more than zero vertices.
|
//assume there is more than zero vertices.
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use std::collections::{HashMap,HashSet};
|
use std::collections::{HashMap,HashSet};
|
||||||
|
use crate::model::DirectedEdge;
|
||||||
use crate::model::{self as model_physics,PhysicsMesh,PhysicsMeshTransform,TransformedMesh,MeshQuery,PhysicsMeshId,PhysicsSubmeshId};
|
use crate::model::{self as model_physics,PhysicsMesh,PhysicsMeshTransform,TransformedMesh,MeshQuery,PhysicsMeshId,PhysicsSubmeshId};
|
||||||
use strafesnet_common::bvh;
|
use strafesnet_common::bvh;
|
||||||
use strafesnet_common::map;
|
use strafesnet_common::map;
|
||||||
@ -280,7 +281,8 @@ impl PhysicsCamera{
|
|||||||
.clamp(Self::ANGLE_PITCH_LOWER_LIMIT,Self::ANGLE_PITCH_UPPER_LIMIT);
|
.clamp(Self::ANGLE_PITCH_LOWER_LIMIT,Self::ANGLE_PITCH_UPPER_LIMIT);
|
||||||
mat3::from_rotation_yx(ax,ay)
|
mat3::from_rotation_yx(ax,ay)
|
||||||
}
|
}
|
||||||
fn rotation(&self)->Planar64Mat3{
|
#[inline]
|
||||||
|
pub fn rotation(&self)->Planar64Mat3{
|
||||||
self.get_rotation(self.clamped_mouse_pos)
|
self.get_rotation(self.clamped_mouse_pos)
|
||||||
}
|
}
|
||||||
fn simulate_move_rotation(&self,mouse_delta:glam::IVec2)->Planar64Mat3{
|
fn simulate_move_rotation(&self,mouse_delta:glam::IVec2)->Planar64Mat3{
|
||||||
@ -556,7 +558,7 @@ impl MoveState{
|
|||||||
=>None,
|
=>None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn next_move_instruction(&self,strafe:&Option<gameplay_style::StrafeSettings>,time:Time)->Option<TimedInstruction<InternalInstruction,TimeInner>>{
|
fn next_move_instruction(&self,strafe:&Option<gameplay_style::StrafeSettings>,time:Time)->Option<TimedInstruction<InternalInstruction,Time>>{
|
||||||
//check if you have a valid walk state and create an instruction
|
//check if you have a valid walk state and create an instruction
|
||||||
match self{
|
match self{
|
||||||
MoveState::Walk(walk_state)|MoveState::Ladder(walk_state)=>match &walk_state.target{
|
MoveState::Walk(walk_state)|MoveState::Ladder(walk_state)=>match &walk_state.target{
|
||||||
@ -784,7 +786,7 @@ impl TouchingState{
|
|||||||
}).collect();
|
}).collect();
|
||||||
crate::push_solve::push_solve(&contacts,acceleration)
|
crate::push_solve::push_solve(&contacts,acceleration)
|
||||||
}
|
}
|
||||||
fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector<InternalInstruction,TimeInner>,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,start_time:Time){
|
fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector<InternalInstruction,Time>,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,start_time:Time){
|
||||||
// let relative_body=body.relative_to(&Body::ZERO);
|
// let relative_body=body.relative_to(&Body::ZERO);
|
||||||
let relative_body=body;
|
let relative_body=body;
|
||||||
for contact in &self.contacts{
|
for contact in &self.contacts{
|
||||||
@ -878,7 +880,7 @@ impl PhysicsState{
|
|||||||
fn reset_to_default(&mut self){
|
fn reset_to_default(&mut self){
|
||||||
*self=Self::default();
|
*self=Self::default();
|
||||||
}
|
}
|
||||||
fn next_move_instruction(&self)->Option<TimedInstruction<InternalInstruction,TimeInner>>{
|
fn next_move_instruction(&self)->Option<TimedInstruction<InternalInstruction,Time>>{
|
||||||
self.move_state.next_move_instruction(&self.style.strafe,self.time)
|
self.move_state.next_move_instruction(&self.style.strafe,self.time)
|
||||||
}
|
}
|
||||||
fn cull_velocity(&mut self,data:&PhysicsData,velocity:Planar64Vec3){
|
fn cull_velocity(&mut self,data:&PhysicsData,velocity:Planar64Vec3){
|
||||||
@ -935,7 +937,7 @@ pub struct PhysicsData{
|
|||||||
impl Default for PhysicsData{
|
impl Default for PhysicsData{
|
||||||
fn default()->Self{
|
fn default()->Self{
|
||||||
Self{
|
Self{
|
||||||
bvh:bvh::BvhNode::default(),
|
bvh:bvh::BvhNode::empty(),
|
||||||
models:Default::default(),
|
models:Default::default(),
|
||||||
modes:Default::default(),
|
modes:Default::default(),
|
||||||
hitbox_mesh:StyleModifiers::default().calculate_mesh(),
|
hitbox_mesh:StyleModifiers::default().calculate_mesh(),
|
||||||
@ -950,21 +952,21 @@ pub struct PhysicsContext<'a>{
|
|||||||
// the physics consumes both Instruction and PhysicsInternalInstruction,
|
// the physics consumes both Instruction and PhysicsInternalInstruction,
|
||||||
// but can only emit PhysicsInternalInstruction
|
// but can only emit PhysicsInternalInstruction
|
||||||
impl InstructionConsumer<InternalInstruction> for PhysicsContext<'_>{
|
impl InstructionConsumer<InternalInstruction> for PhysicsContext<'_>{
|
||||||
type TimeInner=TimeInner;
|
type Time=Time;
|
||||||
fn process_instruction(&mut self,ins:TimedInstruction<InternalInstruction,TimeInner>){
|
fn process_instruction(&mut self,ins:TimedInstruction<InternalInstruction,Time>){
|
||||||
atomic_internal_instruction(&mut self.state,&self.data,ins)
|
atomic_internal_instruction(&mut self.state,&self.data,ins)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl InstructionConsumer<Instruction> for PhysicsContext<'_>{
|
impl InstructionConsumer<Instruction> for PhysicsContext<'_>{
|
||||||
type TimeInner=TimeInner;
|
type Time=Time;
|
||||||
fn process_instruction(&mut self,ins:TimedInstruction<Instruction,TimeInner>){
|
fn process_instruction(&mut self,ins:TimedInstruction<Instruction,Time>){
|
||||||
atomic_input_instruction(&mut self.state,&self.data,ins)
|
atomic_input_instruction(&mut self.state,&self.data,ins)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl InstructionEmitter<InternalInstruction> for PhysicsContext<'_>{
|
impl InstructionEmitter<InternalInstruction> for PhysicsContext<'_>{
|
||||||
type TimeInner=TimeInner;
|
type Time=Time;
|
||||||
//this little next instruction function could cache its return value and invalidate the cached value by watching the State.
|
//this little next instruction function could cache its return value and invalidate the cached value by watching the State.
|
||||||
fn next_instruction(&self,time_limit:Time)->Option<TimedInstruction<InternalInstruction,TimeInner>>{
|
fn next_instruction(&self,time_limit:Time)->Option<TimedInstruction<InternalInstruction,Time>>{
|
||||||
next_instruction_internal(&self.state,&self.data,time_limit)
|
next_instruction_internal(&self.state,&self.data,time_limit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -972,7 +974,7 @@ impl PhysicsContext<'_>{
|
|||||||
pub fn run_input_instruction(
|
pub fn run_input_instruction(
|
||||||
state:&mut PhysicsState,
|
state:&mut PhysicsState,
|
||||||
data:&PhysicsData,
|
data:&PhysicsData,
|
||||||
instruction:TimedInstruction<Instruction,TimeInner>
|
instruction:TimedInstruction<Instruction,Time>
|
||||||
){
|
){
|
||||||
let mut context=PhysicsContext{state,data};
|
let mut context=PhysicsContext{state,data};
|
||||||
context.process_exhaustive(instruction.time);
|
context.process_exhaustive(instruction.time);
|
||||||
@ -980,6 +982,34 @@ impl PhysicsContext<'_>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl PhysicsData{
|
impl PhysicsData{
|
||||||
|
pub fn trace_ray(&self,ray:strafesnet_common::ray::Ray)->Option<ModelId>{
|
||||||
|
let (_time,convex_mesh_id)=self.bvh.sample_ray(&ray,Time::ZERO,Time::MAX/4,|&model,ray|{
|
||||||
|
let mesh=self.models.mesh(model);
|
||||||
|
// brute force trace every face
|
||||||
|
mesh.faces().filter_map(|face_id|{
|
||||||
|
let (n,d)=mesh.face_nd(face_id);
|
||||||
|
// trace ray onto face
|
||||||
|
// n.(o+d*t)==n.p
|
||||||
|
// n.o + n.d * t == n.p
|
||||||
|
// t == (n.p - n.o)/n.d
|
||||||
|
let nd=n.dot(ray.direction);
|
||||||
|
if nd.is_zero(){
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let t=(d-n.dot(ray.origin))/nd;
|
||||||
|
// check if point of intersection is behind face edges
|
||||||
|
// *2 because average of 2 vertices
|
||||||
|
let p=ray.extrapolate(t)*2;
|
||||||
|
mesh.face_edges(face_id).iter().all(|&directed_edge_id|{
|
||||||
|
let edge_n=mesh.directed_edge_n(directed_edge_id);
|
||||||
|
let cross_n=edge_n.cross(n);
|
||||||
|
let &[vert0,vert1]=mesh.edge_verts(directed_edge_id.as_undirected()).as_ref();
|
||||||
|
cross_n.dot(p)<cross_n.dot(mesh.vert(vert0)+mesh.vert(vert1))
|
||||||
|
}).then(||t)
|
||||||
|
}).min().map(Into::into)
|
||||||
|
})?;
|
||||||
|
Some(convex_mesh_id.model_id.into())
|
||||||
|
}
|
||||||
/// use with caution, this is the only non-instruction way to mess with physics
|
/// use with caution, this is the only non-instruction way to mess with physics
|
||||||
pub fn generate_models(&mut self,map:&map::CompleteMap){
|
pub fn generate_models(&mut self,map:&map::CompleteMap){
|
||||||
let mut modes=map.modes.clone();
|
let mut modes=map.modes.clone();
|
||||||
@ -1121,7 +1151,7 @@ impl PhysicsData{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//this is the one who asks
|
//this is the one who asks
|
||||||
fn next_instruction_internal(state:&PhysicsState,data:&PhysicsData,time_limit:Time)->Option<TimedInstruction<InternalInstruction,TimeInner>>{
|
fn next_instruction_internal(state:&PhysicsState,data:&PhysicsData,time_limit:Time)->Option<TimedInstruction<InternalInstruction,Time>>{
|
||||||
//JUST POLLING!!! NO MUTATION
|
//JUST POLLING!!! NO MUTATION
|
||||||
let mut collector=instruction::InstructionCollector::new(time_limit);
|
let mut collector=instruction::InstructionCollector::new(time_limit);
|
||||||
|
|
||||||
@ -1136,7 +1166,7 @@ impl PhysicsData{
|
|||||||
//relative to moving platforms
|
//relative to moving platforms
|
||||||
//let relative_body=state.body.relative_to(&Body::ZERO);
|
//let relative_body=state.body.relative_to(&Body::ZERO);
|
||||||
let relative_body=&state.body;
|
let relative_body=&state.body;
|
||||||
data.bvh.the_tester(&aabb,&mut |&convex_mesh_id|{
|
data.bvh.sample_aabb(&aabb,&mut |&convex_mesh_id|{
|
||||||
//no checks are needed because of the time limits.
|
//no checks are needed because of the time limits.
|
||||||
let model_mesh=data.models.mesh(convex_mesh_id);
|
let model_mesh=data.models.mesh(convex_mesh_id);
|
||||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,data.hitbox_mesh.transformed_mesh());
|
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,data.hitbox_mesh.transformed_mesh());
|
||||||
@ -1198,7 +1228,7 @@ fn recalculate_touching(
|
|||||||
aabb.inflate(hitbox_mesh.halfsize);
|
aabb.inflate(hitbox_mesh.halfsize);
|
||||||
//relative to moving platforms
|
//relative to moving platforms
|
||||||
//let relative_body=state.body.relative_to(&Body::ZERO);
|
//let relative_body=state.body.relative_to(&Body::ZERO);
|
||||||
bvh.the_tester(&aabb,&mut |&convex_mesh_id|{
|
bvh.sample_aabb(&aabb,&mut |&convex_mesh_id|{
|
||||||
//no checks are needed because of the time limits.
|
//no checks are needed because of the time limits.
|
||||||
let model_mesh=models.mesh(convex_mesh_id);
|
let model_mesh=models.mesh(convex_mesh_id);
|
||||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
||||||
@ -1259,7 +1289,7 @@ fn set_velocity_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsM
|
|||||||
culled
|
culled
|
||||||
}
|
}
|
||||||
fn set_velocity(body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,v:Planar64Vec3){
|
fn set_velocity(body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,v:Planar64Vec3){
|
||||||
body.velocity=touching.constrain_velocity(models,hitbox_mesh,v);;
|
body.velocity=touching.constrain_velocity(models,hitbox_mesh,v);
|
||||||
}
|
}
|
||||||
fn set_acceleration_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,a:Planar64Vec3)->bool{
|
fn set_acceleration_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,a:Planar64Vec3)->bool{
|
||||||
//This is not correct but is better than what I have
|
//This is not correct but is better than what I have
|
||||||
@ -1651,7 +1681,7 @@ fn collision_end_intersect(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction<InternalInstruction,TimeInner>){
|
fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction<InternalInstruction,Time>){
|
||||||
state.time=ins.time;
|
state.time=ins.time;
|
||||||
let (should_advance_body,goober_time)=match ins.instruction{
|
let (should_advance_body,goober_time)=match ins.instruction{
|
||||||
InternalInstruction::CollisionStart(_,dt)
|
InternalInstruction::CollisionStart(_,dt)
|
||||||
@ -1747,7 +1777,7 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction<Instruction,TimeInner>){
|
fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction<Instruction,Time>){
|
||||||
state.time=ins.time;
|
state.time=ins.time;
|
||||||
let should_advance_body=match ins.instruction{
|
let should_advance_body=match ins.instruction{
|
||||||
//the body may as well be a quantum wave function
|
//the body may as well be a quantum wave function
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use strafesnet_common::integer::{self,vec3::{self,Vector3},Fixed,Planar64,Planar64Vec3,Ratio};
|
use strafesnet_common::integer::vec3::{self,Vector3};
|
||||||
|
use strafesnet_common::integer::{Fixed,Planar64Vec3,Ratio};
|
||||||
|
use strafesnet_common::ray::Ray;
|
||||||
|
|
||||||
// This algorithm is based on Lua code
|
// This algorithm is based on Lua code
|
||||||
// written by Trey Reynolds in 2021
|
// written by Trey Reynolds in 2021
|
||||||
@ -12,24 +14,6 @@ type Conts<'a>=arrayvec::ArrayVec<&'a Contact,4>;
|
|||||||
// hack to allow comparing ratios to zero
|
// hack to allow comparing ratios to zero
|
||||||
const RATIO_ZERO:Ratio<Fixed<1,32>,Fixed<1,32>>=Ratio::new(Fixed::ZERO,Fixed::EPSILON);
|
const RATIO_ZERO:Ratio<Fixed<1,32>,Fixed<1,32>>=Ratio::new(Fixed::ZERO,Fixed::EPSILON);
|
||||||
|
|
||||||
struct Ray{
|
|
||||||
origin:Planar64Vec3,
|
|
||||||
direction:Planar64Vec3,
|
|
||||||
}
|
|
||||||
impl Ray{
|
|
||||||
fn extrapolate<Num,Den,N1,T1>(&self,t:Ratio<Num,Den>)->Planar64Vec3
|
|
||||||
where
|
|
||||||
Num:Copy,
|
|
||||||
Den:Copy,
|
|
||||||
Num:core::ops::Mul<Planar64,Output=N1>,
|
|
||||||
Planar64:core::ops::Mul<Den,Output=N1>,
|
|
||||||
N1:integer::Divide<Den,Output=T1>,
|
|
||||||
T1:integer::Fix<Planar64>,
|
|
||||||
{
|
|
||||||
self.origin+self.direction.map(|elem|(t*elem).divide().fix())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Information about a contact restriction
|
/// Information about a contact restriction
|
||||||
pub struct Contact{
|
pub struct Contact{
|
||||||
pub position:Planar64Vec3,
|
pub position:Planar64Vec3,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "strafesnet_session"
|
name = "strafesnet_session"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
glam = "0.29.0"
|
glam = "0.30.0"
|
||||||
replace_with = "0.1.7"
|
replace_with = "0.1.7"
|
||||||
strafesnet_common = { path = "../../lib/common", registry = "strafesnet" }
|
strafesnet_common = { path = "../../lib/common", registry = "strafesnet" }
|
||||||
strafesnet_physics = { path = "../physics", registry = "strafesnet" }
|
strafesnet_physics = { path = "../physics", registry = "strafesnet" }
|
||||||
|
@ -5,13 +5,13 @@ use strafesnet_common::physics::{
|
|||||||
TimeInner as PhysicsTimeInner,
|
TimeInner as PhysicsTimeInner,
|
||||||
Time as PhysicsTime,
|
Time as PhysicsTime,
|
||||||
};
|
};
|
||||||
use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner};
|
use strafesnet_common::session::Time as SessionTime;
|
||||||
use strafesnet_common::instruction::{InstructionConsumer,InstructionEmitter,TimedInstruction};
|
use strafesnet_common::instruction::{InstructionConsumer,InstructionEmitter,TimedInstruction};
|
||||||
|
|
||||||
type TimedSelfInstruction=TimedInstruction<Instruction,PhysicsTimeInner>;
|
type TimedSelfInstruction=TimedInstruction<Instruction,PhysicsTime>;
|
||||||
type DoubleTimedSelfInstruction=TimedInstruction<TimedSelfInstruction,SessionTimeInner>;
|
type DoubleTimedSelfInstruction=TimedInstruction<TimedSelfInstruction,SessionTime>;
|
||||||
|
|
||||||
type TimedPhysicsInstruction=TimedInstruction<PhysicsInstruction,PhysicsTimeInner>;
|
type TimedPhysicsInstruction=TimedInstruction<PhysicsInstruction,PhysicsTime>;
|
||||||
|
|
||||||
const MOUSE_TIMEOUT:SessionTime=SessionTime::from_millis(10);
|
const MOUSE_TIMEOUT:SessionTime=SessionTime::from_millis(10);
|
||||||
|
|
||||||
@ -89,14 +89,14 @@ pub struct MouseInterpolator{
|
|||||||
// Maybe MouseInterpolator manipulation is better expressed using impls
|
// Maybe MouseInterpolator manipulation is better expressed using impls
|
||||||
// and called from Instruction trait impls in session
|
// and called from Instruction trait impls in session
|
||||||
impl InstructionConsumer<TimedSelfInstruction> for MouseInterpolator{
|
impl InstructionConsumer<TimedSelfInstruction> for MouseInterpolator{
|
||||||
type TimeInner=SessionTimeInner;
|
type Time=SessionTime;
|
||||||
fn process_instruction(&mut self,ins:DoubleTimedSelfInstruction){
|
fn process_instruction(&mut self,ins:DoubleTimedSelfInstruction){
|
||||||
self.push_unbuffered_input(ins.time,ins.instruction.time,ins.instruction.instruction.into())
|
self.push_unbuffered_input(ins.time,ins.instruction.time,ins.instruction.instruction.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl InstructionEmitter<StepInstruction> for MouseInterpolator{
|
impl InstructionEmitter<StepInstruction> for MouseInterpolator{
|
||||||
type TimeInner=SessionTimeInner;
|
type Time=SessionTime;
|
||||||
fn next_instruction(&self,time_limit:SessionTime)->Option<TimedInstruction<StepInstruction,Self::TimeInner>>{
|
fn next_instruction(&self,time_limit:SessionTime)->Option<TimedInstruction<StepInstruction,Self::Time>>{
|
||||||
self.buffered_instruction_with_timeout(time_limit)
|
self.buffered_instruction_with_timeout(time_limit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,7 +108,7 @@ impl MouseInterpolator{
|
|||||||
output:std::collections::VecDeque::new(),
|
output:std::collections::VecDeque::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn push_mouse_and_flush_buffer(&mut self,ins:TimedInstruction<MouseInstruction,PhysicsTimeInner>){
|
fn push_mouse_and_flush_buffer(&mut self,ins:TimedInstruction<MouseInstruction,PhysicsTime>){
|
||||||
self.buffer.push_front(TimedInstruction{
|
self.buffer.push_front(TimedInstruction{
|
||||||
time:ins.time,
|
time:ins.time,
|
||||||
instruction:BufferedInstruction::Mouse(ins.instruction).into(),
|
instruction:BufferedInstruction::Mouse(ins.instruction).into(),
|
||||||
@ -219,7 +219,7 @@ impl MouseInterpolator{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn buffered_instruction_with_timeout(&self,time_limit:SessionTime)->Option<TimedInstruction<StepInstruction,SessionTimeInner>>{
|
fn buffered_instruction_with_timeout(&self,time_limit:SessionTime)->Option<TimedInstruction<StepInstruction,SessionTime>>{
|
||||||
match self.get_mouse_timedout_at(time_limit){
|
match self.get_mouse_timedout_at(time_limit){
|
||||||
Some(timeout)=>Some(TimedInstruction{
|
Some(timeout)=>Some(TimedInstruction{
|
||||||
time:timeout,
|
time:timeout,
|
||||||
@ -232,7 +232,7 @@ impl MouseInterpolator{
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn pop_buffered_instruction(&mut self,ins:TimedInstruction<StepInstruction,PhysicsTimeInner>)->Option<TimedPhysicsInstruction>{
|
pub fn pop_buffered_instruction(&mut self,ins:TimedInstruction<StepInstruction,PhysicsTime>)->Option<TimedPhysicsInstruction>{
|
||||||
match ins.instruction{
|
match ins.instruction{
|
||||||
StepInstruction::Pop=>(),
|
StepInstruction::Pop=>(),
|
||||||
StepInstruction::Timeout=>self.timeout_mouse(ins.time),
|
StepInstruction::Timeout=>self.timeout_mouse(ins.time),
|
||||||
@ -244,6 +244,7 @@ impl MouseInterpolator{
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test{
|
mod test{
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use strafesnet_common::session::TimeInner as SessionTimeInner;
|
||||||
#[test]
|
#[test]
|
||||||
fn test(){
|
fn test(){
|
||||||
let mut interpolator=MouseInterpolator::new();
|
let mut interpolator=MouseInterpolator::new();
|
||||||
|
@ -88,11 +88,11 @@ impl Simulation{
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Recording{
|
pub struct Recording{
|
||||||
instructions:Vec<TimedInstruction<PhysicsInputInstruction,PhysicsTimeInner>>,
|
instructions:Vec<TimedInstruction<PhysicsInputInstruction,PhysicsTime>>,
|
||||||
}
|
}
|
||||||
impl Recording{
|
impl Recording{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
instructions:Vec<TimedInstruction<PhysicsInputInstruction,PhysicsTimeInner>>,
|
instructions:Vec<TimedInstruction<PhysicsInputInstruction,PhysicsTime>>,
|
||||||
)->Self{
|
)->Self{
|
||||||
Self{instructions}
|
Self{instructions}
|
||||||
}
|
}
|
||||||
@ -161,6 +161,7 @@ pub struct Session{
|
|||||||
recording:Recording,
|
recording:Recording,
|
||||||
//players:HashMap<PlayerId,Simulation>,
|
//players:HashMap<PlayerId,Simulation>,
|
||||||
replays:HashMap<BotId,Replay>,
|
replays:HashMap<BotId,Replay>,
|
||||||
|
last_ray_hit:Option<strafesnet_common::model::ModelId>,
|
||||||
}
|
}
|
||||||
impl Session{
|
impl Session{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@ -177,6 +178,7 @@ impl Session{
|
|||||||
view_state:ViewState::Play,
|
view_state:ViewState::Play,
|
||||||
recording:Default::default(),
|
recording:Default::default(),
|
||||||
replays:HashMap::new(),
|
replays:HashMap::new(),
|
||||||
|
last_ray_hit:None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn clear_recording(&mut self){
|
fn clear_recording(&mut self){
|
||||||
@ -194,6 +196,19 @@ impl Session{
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn debug_raycast_print_model_id_if_changed(&mut self,time:SessionTime){
|
||||||
|
if let Some(frame_state)=self.get_frame_state(time){
|
||||||
|
let ray=strafesnet_common::ray::Ray{
|
||||||
|
origin:frame_state.body.extrapolated_position(self.simulation.timer.time(time)),
|
||||||
|
direction:-frame_state.camera.rotation().z_axis,
|
||||||
|
};
|
||||||
|
let model_id=self.geometry_shared.trace_ray(ray);
|
||||||
|
if model_id!=self.last_ray_hit{
|
||||||
|
println!("hit={model_id:?}");
|
||||||
|
self.last_ray_hit=model_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn user_settings(&self)->&UserSettings{
|
pub fn user_settings(&self)->&UserSettings{
|
||||||
&self.user_settings
|
&self.user_settings
|
||||||
}
|
}
|
||||||
@ -207,8 +222,8 @@ impl Session{
|
|||||||
// Session emits DoStep
|
// Session emits DoStep
|
||||||
|
|
||||||
impl InstructionConsumer<Instruction<'_>> for Session{
|
impl InstructionConsumer<Instruction<'_>> for Session{
|
||||||
type TimeInner=SessionTimeInner;
|
type Time=SessionTime;
|
||||||
fn process_instruction(&mut self,ins:TimedInstruction<Instruction,Self::TimeInner>){
|
fn process_instruction(&mut self,ins:TimedInstruction<Instruction,Self::Time>){
|
||||||
// repetitive procedure macro
|
// repetitive procedure macro
|
||||||
macro_rules! run_mouse_interpolator_instruction{
|
macro_rules! run_mouse_interpolator_instruction{
|
||||||
($instruction:expr)=>{
|
($instruction:expr)=>{
|
||||||
@ -425,8 +440,8 @@ impl InstructionConsumer<Instruction<'_>> for Session{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl InstructionConsumer<StepInstruction> for Session{
|
impl InstructionConsumer<StepInstruction> for Session{
|
||||||
type TimeInner=SessionTimeInner;
|
type Time=SessionTime;
|
||||||
fn process_instruction(&mut self,ins:TimedInstruction<StepInstruction,Self::TimeInner>){
|
fn process_instruction(&mut self,ins:TimedInstruction<StepInstruction,Self::Time>){
|
||||||
let time=self.simulation.timer.time(ins.time);
|
let time=self.simulation.timer.time(ins.time);
|
||||||
if let Some(instruction)=self.mouse_interpolator.pop_buffered_instruction(ins.set_time(time)){
|
if let Some(instruction)=self.mouse_interpolator.pop_buffered_instruction(ins.set_time(time)){
|
||||||
//record
|
//record
|
||||||
@ -436,8 +451,8 @@ impl InstructionConsumer<StepInstruction> for Session{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl InstructionEmitter<StepInstruction> for Session{
|
impl InstructionEmitter<StepInstruction> for Session{
|
||||||
type TimeInner=SessionTimeInner;
|
type Time=SessionTime;
|
||||||
fn next_instruction(&self,time_limit:SessionTime)->Option<TimedInstruction<StepInstruction,Self::TimeInner>>{
|
fn next_instruction(&self,time_limit:SessionTime)->Option<TimedInstruction<StepInstruction,Self::Time>>{
|
||||||
self.mouse_interpolator.next_instruction(time_limit)
|
self.mouse_interpolator.next_instruction(time_limit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "strafesnet_settings"
|
name = "strafesnet_settings"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
configparser = "3.0.2"
|
configparser = "3.0.2"
|
||||||
directories = "6.0.0"
|
directories = "6.0.0"
|
||||||
glam = "0.29.0"
|
glam = "0.30.0"
|
||||||
strafesnet_common = { path = "../../lib/common", registry = "strafesnet" }
|
strafesnet_common = { path = "../../lib/common", registry = "strafesnet" }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "integration-testing"
|
name = "integration-testing"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
strafesnet_common = { path = "../lib/common", registry = "strafesnet" }
|
strafesnet_common = { path = "../lib/common", registry = "strafesnet" }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "strafesnet_bsp_loader"
|
name = "strafesnet_bsp_loader"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Convert Valve BSP files to StrafesNET data structures."
|
description = "Convert Valve BSP files to StrafesNET data structures."
|
||||||
@ -10,7 +10,7 @@ authors = ["Rhys Lloyd <krakow20@gmail.com>"]
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
glam = "0.29.0"
|
glam = "0.30.0"
|
||||||
strafesnet_common = { version = "0.6.0", path = "../common", registry = "strafesnet" }
|
strafesnet_common = { version = "0.6.0", path = "../common", registry = "strafesnet" }
|
||||||
strafesnet_deferred_loader = { version = "0.5.0", path = "../deferred_loader", registry = "strafesnet" }
|
strafesnet_deferred_loader = { version = "0.5.0", path = "../deferred_loader", registry = "strafesnet" }
|
||||||
vbsp = "0.6.0"
|
vbsp = "0.6.0"
|
||||||
|
@ -1,294 +0,0 @@
|
|||||||
use strafesnet_common::integer::Planar64;
|
|
||||||
use strafesnet_common::{model,integer};
|
|
||||||
use strafesnet_common::integer::{vec3::Vector3,Fixed,Ratio};
|
|
||||||
|
|
||||||
use crate::{valve_transform_normal,valve_transform_dist};
|
|
||||||
|
|
||||||
#[derive(Hash,Eq,PartialEq)]
|
|
||||||
struct Face{
|
|
||||||
normal:integer::Planar64Vec3,
|
|
||||||
dot:integer::Planar64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Faces{
|
|
||||||
faces:Vec<Vec<integer::Planar64Vec3>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn solve3(c0:&Face,c1:&Face,c2:&Face)->Option<Ratio<Vector3<Fixed<3,96>>,Fixed<3,96>>>{
|
|
||||||
let n0_n1=c0.normal.cross(c1.normal);
|
|
||||||
let det=c2.normal.dot(n0_n1);
|
|
||||||
if det.abs().is_zero(){
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some((
|
|
||||||
c1.normal.cross(c2.normal)*c0.dot
|
|
||||||
+c2.normal.cross(c0.normal)*c1.dot
|
|
||||||
+c0.normal.cross(c1.normal)*c2.dot
|
|
||||||
)/det)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum PlanesToFacesError{
|
|
||||||
InitFace1,
|
|
||||||
InitFace2,
|
|
||||||
InitIntersection,
|
|
||||||
FindNewIntersection,
|
|
||||||
EmptyFaces,
|
|
||||||
InfiniteLoop1,
|
|
||||||
InfiniteLoop2,
|
|
||||||
}
|
|
||||||
impl std::fmt::Display for PlanesToFacesError{
|
|
||||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
|
||||||
write!(f,"{self:?}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl core::error::Error for PlanesToFacesError{}
|
|
||||||
|
|
||||||
fn planes_to_faces(face_list:std::collections::HashSet<Face>)->Result<Faces,PlanesToFacesError>{
|
|
||||||
let mut faces=Vec::new();
|
|
||||||
// for each face, determine one edge at a time until you complete the face
|
|
||||||
'face: for face0 in &face_list{
|
|
||||||
// 1. find first edge
|
|
||||||
// 2. follow edges around face
|
|
||||||
|
|
||||||
// === finding first edge ===
|
|
||||||
// 1. pick the most perpendicular set of 3 faces
|
|
||||||
// 2. check if any faces occlude the intersection
|
|
||||||
// 3. use this test to replace left and right alternating until they are not occluded
|
|
||||||
|
|
||||||
// find the most perpendicular face to face0
|
|
||||||
let mut face1=face_list.iter().min_by_key(|&p|{
|
|
||||||
face0.normal.dot(p.normal).abs()
|
|
||||||
}).ok_or(PlanesToFacesError::InitFace1)?;
|
|
||||||
|
|
||||||
// direction of edge formed by face0 x face1
|
|
||||||
let edge_dir=face0.normal.cross(face1.normal);
|
|
||||||
|
|
||||||
// find the most perpendicular face to both face0 and face1
|
|
||||||
let mut face2=face_list.iter().max_by_key(|&p|{
|
|
||||||
// find the best *oriented* face (no .abs())
|
|
||||||
edge_dir.dot(p.normal)
|
|
||||||
}).ok_or(PlanesToFacesError::InitFace2)?;
|
|
||||||
|
|
||||||
let mut detect_loop=200u8;
|
|
||||||
|
|
||||||
let mut intersection=solve3(face0,face1,face2).ok_or(PlanesToFacesError::InitIntersection)?;
|
|
||||||
|
|
||||||
// repeatedly update face0, face1 until all faces form part of the convex solid
|
|
||||||
'find: loop{
|
|
||||||
if let Some(a)=detect_loop.checked_sub(1){
|
|
||||||
detect_loop=a;
|
|
||||||
}else{
|
|
||||||
return Err(PlanesToFacesError::InfiniteLoop1);
|
|
||||||
}
|
|
||||||
// test if any *other* faces occlude the intersection
|
|
||||||
for new_face in &face_list{
|
|
||||||
// new face occludes intersection point
|
|
||||||
if (new_face.dot.fix_2()/Planar64::ONE).lt_ratio(new_face.normal.dot(intersection.num)/intersection.den){
|
|
||||||
// replace one of the faces with the new face
|
|
||||||
// dont' try to replace face0 because we are exploring that face in particular
|
|
||||||
if let Some(new_intersection)=solve3(face0,new_face,face2){
|
|
||||||
// face1 does not occlude (or intersect) the new intersection
|
|
||||||
if (face1.dot.fix_2()/Planar64::ONE).gt_ratio(face1.normal.dot(new_intersection.num)/new_intersection.den){
|
|
||||||
face1=new_face;
|
|
||||||
intersection=new_intersection;
|
|
||||||
continue 'find;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(new_intersection)=solve3(face0,face1,new_face){
|
|
||||||
// face2 does not occlude (or intersect) the new intersection
|
|
||||||
if (face2.dot.fix_2()/Planar64::ONE).gt_ratio(face2.normal.dot(new_intersection.num)/new_intersection.den){
|
|
||||||
face2=new_face;
|
|
||||||
intersection=new_intersection;
|
|
||||||
continue 'find;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we have found a set of faces for which the intersection is on the convex solid
|
|
||||||
break 'find;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if face0 must go, meaning it is a degenerate face and does not contribute anything to the convex solid
|
|
||||||
for new_face in &face_list{
|
|
||||||
if core::ptr::eq(face0,new_face){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if core::ptr::eq(face1,new_face){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if core::ptr::eq(face2,new_face){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let Some(new_intersection)=solve3(new_face,face1,face2){
|
|
||||||
// face0 does not occlude (or intersect) the new intersection
|
|
||||||
if (face0.dot.fix_2()/Planar64::ONE).lt_ratio(face0.normal.dot(new_intersection.num)/new_intersection.den){
|
|
||||||
// abort! reject face0 entirely
|
|
||||||
continue 'face;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === follow edges around face ===
|
|
||||||
// Note that we chose face2 such that the 3 faces create a particular winding order.
|
|
||||||
// If we choose a consistent face to follow (face1, face2) it will always wind with a consistent chirality
|
|
||||||
|
|
||||||
let mut detect_loop=200u8;
|
|
||||||
|
|
||||||
// keep looping until we meet this face again
|
|
||||||
let face1=face1;
|
|
||||||
let mut face=Vec::new();
|
|
||||||
loop{
|
|
||||||
// push point onto vertices
|
|
||||||
// problem: this may push a vertex that does not fit in the fixed point range and is thus meaningless
|
|
||||||
face.push(intersection.divide().fix_1());
|
|
||||||
|
|
||||||
// we looped back around to face1, we're done!
|
|
||||||
if core::ptr::eq(face1,face2){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the measure
|
|
||||||
let edge_dir=face0.normal.cross(face2.normal);
|
|
||||||
|
|
||||||
// the dot product to beat
|
|
||||||
let d_intersection=edge_dir.dot(intersection.num)/intersection.den;
|
|
||||||
|
|
||||||
// find the next face moving clockwise around face0
|
|
||||||
let (new_face,new_intersection,_)=face_list.iter().filter_map(|new_face|{
|
|
||||||
// ignore faces that are part of the current edge
|
|
||||||
if core::ptr::eq(face0,new_face)
|
|
||||||
|core::ptr::eq(face2,new_face){
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let new_intersection=solve3(face0,face2,new_face)?;
|
|
||||||
|
|
||||||
// the d value must be larger
|
|
||||||
let d_new_intersection=edge_dir.dot(new_intersection.num)/new_intersection.den;
|
|
||||||
if d_new_intersection.le_ratio(d_intersection){
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some((new_face,new_intersection,d_new_intersection))
|
|
||||||
}).min_by_key(|&(_,_,d)|d).ok_or(PlanesToFacesError::FindNewIntersection)?;
|
|
||||||
|
|
||||||
face2=new_face;
|
|
||||||
intersection=new_intersection;
|
|
||||||
|
|
||||||
if let Some(a)=detect_loop.checked_sub(1){
|
|
||||||
detect_loop=a;
|
|
||||||
}else{
|
|
||||||
return Err(PlanesToFacesError::InfiniteLoop2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
faces.push(face);
|
|
||||||
}
|
|
||||||
|
|
||||||
if faces.is_empty(){
|
|
||||||
Err(PlanesToFacesError::EmptyFaces)
|
|
||||||
}else{
|
|
||||||
Ok(Faces{
|
|
||||||
faces,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum BrushToMeshError{
|
|
||||||
SliceBrushSides,
|
|
||||||
MissingPlane,
|
|
||||||
InvalidFaceCount{
|
|
||||||
count:usize,
|
|
||||||
},
|
|
||||||
InvalidPlanes(PlanesToFacesError),
|
|
||||||
}
|
|
||||||
impl std::fmt::Display for BrushToMeshError{
|
|
||||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
|
||||||
write!(f,"{self:?}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl core::error::Error for BrushToMeshError{}
|
|
||||||
|
|
||||||
pub fn brush_to_mesh(bsp:&vbsp::Bsp,brush:&vbsp::Brush)->Result<model::Mesh,BrushToMeshError>{
|
|
||||||
let brush_start_idx=brush.brush_side as usize;
|
|
||||||
let sides_range=brush_start_idx..brush_start_idx+brush.num_brush_sides as usize;
|
|
||||||
let sides=bsp.brush_sides.get(sides_range).ok_or(BrushToMeshError::SliceBrushSides)?;
|
|
||||||
let face_list=sides.iter().map(|side|{
|
|
||||||
let plane=bsp.plane(side.plane as usize)?;
|
|
||||||
Some(Face{
|
|
||||||
normal:valve_transform_normal(plane.normal.into()),
|
|
||||||
dot:valve_transform_dist(plane.dist.into()),
|
|
||||||
})
|
|
||||||
}).collect::<Option<std::collections::HashSet<_>>>().ok_or(BrushToMeshError::MissingPlane)?;
|
|
||||||
|
|
||||||
if face_list.len()<4{
|
|
||||||
return Err(BrushToMeshError::InvalidFaceCount{count:face_list.len()});
|
|
||||||
}
|
|
||||||
|
|
||||||
let faces=planes_to_faces(face_list).map_err(BrushToMeshError::InvalidPlanes)?;
|
|
||||||
|
|
||||||
// generate the mesh
|
|
||||||
let mut mb=model::MeshBuilder::new();
|
|
||||||
let color=mb.acquire_color_id(glam::Vec4::ONE);
|
|
||||||
let tex=mb.acquire_tex_id(glam::Vec2::ZERO);
|
|
||||||
// normals are ignored by physics
|
|
||||||
let normal=mb.acquire_normal_id(integer::vec3::ZERO);
|
|
||||||
|
|
||||||
let polygon_list=faces.faces.into_iter().map(|face|{
|
|
||||||
face.into_iter().map(|pos|{
|
|
||||||
let pos=mb.acquire_pos_id(pos);
|
|
||||||
mb.acquire_vertex_id(model::IndexedVertex{
|
|
||||||
pos,
|
|
||||||
tex,
|
|
||||||
normal,
|
|
||||||
color,
|
|
||||||
})
|
|
||||||
}).collect()
|
|
||||||
}).collect();
|
|
||||||
|
|
||||||
let polygon_groups=vec![model::PolygonGroup::PolygonList(model::PolygonList::new(polygon_list))];
|
|
||||||
let physics_groups=vec![model::IndexedPhysicsGroup{
|
|
||||||
groups:vec![model::PolygonGroupId::new(0)],
|
|
||||||
}];
|
|
||||||
let graphics_groups=vec![model::IndexedGraphicsGroup{
|
|
||||||
render:model::RenderConfigId::new(0),
|
|
||||||
groups:vec![model::PolygonGroupId::new(0)],
|
|
||||||
}];
|
|
||||||
|
|
||||||
Ok(mb.build(polygon_groups,graphics_groups,physics_groups))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test{
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_cube(){
|
|
||||||
let face_list=[
|
|
||||||
Face{normal:integer::vec3::X,dot:Planar64::ONE},
|
|
||||||
Face{normal:integer::vec3::Y,dot:Planar64::ONE},
|
|
||||||
Face{normal:integer::vec3::Z,dot:Planar64::ONE},
|
|
||||||
Face{normal:integer::vec3::NEG_X,dot:Planar64::ONE},
|
|
||||||
Face{normal:integer::vec3::NEG_Y,dot:Planar64::ONE},
|
|
||||||
Face{normal:integer::vec3::NEG_Z,dot:Planar64::ONE},
|
|
||||||
].into_iter().collect();
|
|
||||||
let faces=planes_to_faces(face_list).unwrap();
|
|
||||||
dbg!(faces);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_cube_with_degernate_face(){
|
|
||||||
let face_list=[
|
|
||||||
Face{normal:integer::vec3::X,dot:Planar64::ONE},
|
|
||||||
Face{normal:integer::vec3::Y,dot:Planar64::ONE},
|
|
||||||
Face{normal:integer::vec3::Z,dot:Planar64::ONE},
|
|
||||||
Face{normal:integer::vec3::NEG_X,dot:Planar64::ONE},
|
|
||||||
Face{normal:integer::vec3::NEG_Y,dot:Planar64::ONE},
|
|
||||||
Face{normal:integer::vec3::NEG_Z,dot:Planar64::ONE},
|
|
||||||
Face{normal:integer::vec3::NEG_Z,dot:Planar64::EPSILON},
|
|
||||||
].into_iter().collect();
|
|
||||||
let faces=planes_to_faces(face_list).unwrap();
|
|
||||||
dbg!(faces);
|
|
||||||
}
|
|
||||||
}
|
|
@ -41,41 +41,38 @@ pub fn convert<'a>(
|
|||||||
//figure out real attributes later
|
//figure out real attributes later
|
||||||
let mut unique_attributes=Vec::new();
|
let mut unique_attributes=Vec::new();
|
||||||
unique_attributes.push(gameplay_attributes::CollisionAttributes::Decoration);
|
unique_attributes.push(gameplay_attributes::CollisionAttributes::Decoration);
|
||||||
unique_attributes.push(gameplay_attributes::CollisionAttributes::contact_default());
|
const TEMP_TOUCH_ME_ATTRIBUTE:gameplay_attributes::CollisionAttributesId=gameplay_attributes::CollisionAttributesId::new(0);
|
||||||
const ATTRIBUTE_DECORATION:gameplay_attributes::CollisionAttributesId=gameplay_attributes::CollisionAttributesId::new(0);
|
|
||||||
const ATTRIBUTE_CONTACT_DEFAULT:gameplay_attributes::CollisionAttributesId=gameplay_attributes::CollisionAttributesId::new(1);
|
|
||||||
|
|
||||||
//declare all prop models to Loader
|
//declare all prop models to Loader
|
||||||
let prop_models=Vec::new();
|
let prop_models=bsp.static_props().map(|prop|{
|
||||||
// let prop_models=bsp.static_props().map(|prop|{
|
//get or create mesh_id
|
||||||
// //get or create mesh_id
|
let mesh_id=mesh_deferred_loader.acquire_mesh_id(prop.model());
|
||||||
// let mesh_id=mesh_deferred_loader.acquire_mesh_id(prop.model());
|
let placement=prop.as_prop_placement();
|
||||||
// let placement=prop.as_prop_placement();
|
model::Model{
|
||||||
// model::Model{
|
mesh:mesh_id,
|
||||||
// mesh:mesh_id,
|
attributes:TEMP_TOUCH_ME_ATTRIBUTE,
|
||||||
// attributes:ATTRIBUTE_DECORATION,
|
transform:integer::Planar64Affine3::new(
|
||||||
// transform:integer::Planar64Affine3::new(
|
integer::mat3::try_from_f32_array_2d((
|
||||||
// integer::mat3::try_from_f32_array_2d((
|
glam::Mat3A::from_diagonal(glam::Vec3::splat(placement.scale))
|
||||||
// glam::Mat3A::from_diagonal(glam::Vec3::splat(placement.scale))
|
//TODO: figure this out
|
||||||
// //TODO: figure this out
|
*glam::Mat3A::from_quat(glam::Quat::from_array(placement.rotation.into()))
|
||||||
// *glam::Mat3A::from_quat(glam::Quat::from_array(placement.rotation.into()))
|
).to_cols_array_2d()).unwrap(),
|
||||||
// ).to_cols_array_2d()).unwrap(),
|
valve_transform(placement.origin.into()),
|
||||||
// valve_transform(placement.origin.into()),
|
),
|
||||||
// ),
|
color:glam::Vec4::ONE,
|
||||||
// color:glam::Vec4::ONE,
|
}
|
||||||
// }
|
}).collect();
|
||||||
// }).collect();
|
|
||||||
|
|
||||||
//TODO: make the main map one single mesh with a bunch of different physics groups and graphics groups
|
//TODO: make the main map one single mesh with a bunch of different physics groups and graphics groups
|
||||||
|
|
||||||
//the generated MeshIds in here will collide with the Loader Mesh Ids
|
//the generated MeshIds in here will collide with the Loader Mesh Ids
|
||||||
//but I can't think of a good workaround other than just remapping one later.
|
//but I can't think of a good workaround other than just remapping one later.
|
||||||
let mut world_meshes:Vec<model::Mesh>=bsp.models().map(|world_model|{
|
let world_meshes:Vec<model::Mesh>=bsp.models().map(|world_model|{
|
||||||
let mut mb=model::MeshBuilder::new();
|
let mut mb=model::MeshBuilder::new();
|
||||||
|
|
||||||
let color=mb.acquire_color_id(glam::Vec4::ONE);
|
let color=mb.acquire_color_id(glam::Vec4::ONE);
|
||||||
let mut graphics_groups=Vec::new();
|
let mut graphics_groups=Vec::new();
|
||||||
//let mut render_id_to_graphics_group_id=std::collections::HashMap::new();
|
let mut render_id_to_graphics_group_id=std::collections::HashMap::new();
|
||||||
let polygon_groups=world_model.faces().enumerate().map(|(polygon_group_id,face)|{
|
let polygon_groups=world_model.faces().enumerate().map(|(polygon_group_id,face)|{
|
||||||
let polygon_group_id=model::PolygonGroupId::new(polygon_group_id as u32);
|
let polygon_group_id=model::PolygonGroupId::new(polygon_group_id as u32);
|
||||||
let face_texture=face.texture();
|
let face_texture=face.texture();
|
||||||
@ -105,15 +102,15 @@ pub fn convert<'a>(
|
|||||||
//a render config for it, and then returns the id to that render config
|
//a render config for it, and then returns the id to that render config
|
||||||
let render_id=render_config_deferred_loader.acquire_render_config_id(Some(Cow::Borrowed(face_texture_data.name())));
|
let render_id=render_config_deferred_loader.acquire_render_config_id(Some(Cow::Borrowed(face_texture_data.name())));
|
||||||
//deduplicate graphics groups by render id
|
//deduplicate graphics groups by render id
|
||||||
// let graphics_group_id=*render_id_to_graphics_group_id.entry(render_id).or_insert_with(||{
|
let graphics_group_id=*render_id_to_graphics_group_id.entry(render_id).or_insert_with(||{
|
||||||
// let graphics_group_id=graphics_groups.len();
|
let graphics_group_id=graphics_groups.len();
|
||||||
// graphics_groups.push(model::IndexedGraphicsGroup{
|
graphics_groups.push(model::IndexedGraphicsGroup{
|
||||||
// render:render_id,
|
render:render_id,
|
||||||
// groups:vec![],
|
groups:vec![],
|
||||||
// });
|
});
|
||||||
// graphics_group_id
|
graphics_group_id
|
||||||
// });
|
});
|
||||||
// graphics_groups[graphics_group_id].groups.push(polygon_group_id);
|
graphics_groups[graphics_group_id].groups.push(polygon_group_id);
|
||||||
}
|
}
|
||||||
model::PolygonGroup::PolygonList(model::PolygonList::new(polygon_list))
|
model::PolygonGroup::PolygonList(model::PolygonList::new(polygon_list))
|
||||||
}).collect();
|
}).collect();
|
||||||
@ -121,17 +118,6 @@ pub fn convert<'a>(
|
|||||||
mb.build(polygon_groups,graphics_groups,vec![])
|
mb.build(polygon_groups,graphics_groups,vec![])
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
let brush_mesh_start_idx=world_meshes.len();
|
|
||||||
for brush in &bsp.brushes{
|
|
||||||
let mesh_result=crate::brush::brush_to_mesh(bsp,brush);
|
|
||||||
match mesh_result{
|
|
||||||
Ok(mesh)=>world_meshes.push(mesh),
|
|
||||||
Err(e)=>println!("Brush mesh error: {e}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("How many brush: {}",bsp.brushes.len());
|
|
||||||
println!("Generated brush models: {}",world_meshes.len()-brush_mesh_start_idx);
|
|
||||||
|
|
||||||
let world_models:Vec<model::Model>=
|
let world_models:Vec<model::Model>=
|
||||||
//one instance of the main world mesh
|
//one instance of the main world mesh
|
||||||
std::iter::once((
|
std::iter::once((
|
||||||
@ -157,26 +143,17 @@ pub fn convert<'a>(
|
|||||||
(model::MeshId::new(mesh_id),brush.origin,brush.color)
|
(model::MeshId::new(mesh_id),brush.origin,brush.color)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
).map(|(mesh_id,model_origin,vbsp::Color{r,g,b})|model::Model{
|
).map(|(mesh_id,model_origin,vbsp::Color{r,g,b})|{
|
||||||
mesh:mesh_id,
|
model::Model{
|
||||||
attributes:ATTRIBUTE_DECORATION,
|
mesh:mesh_id,
|
||||||
transform:integer::Planar64Affine3::new(
|
attributes:TEMP_TOUCH_ME_ATTRIBUTE,
|
||||||
integer::mat3::identity(),
|
|
||||||
valve_transform(model_origin.into())
|
|
||||||
),
|
|
||||||
color:(glam::Vec3::from_array([r as f32,g as f32,b as f32])/255.0).extend(1.0),
|
|
||||||
}).chain(
|
|
||||||
// physics models
|
|
||||||
(brush_mesh_start_idx..world_meshes.len()).map(|mesh_id|model::Model{
|
|
||||||
mesh:model::MeshId::new(mesh_id as u32),
|
|
||||||
attributes:ATTRIBUTE_CONTACT_DEFAULT,
|
|
||||||
transform:integer::Planar64Affine3::new(
|
transform:integer::Planar64Affine3::new(
|
||||||
integer::mat3::identity(),
|
integer::mat3::identity(),
|
||||||
integer::vec3::ZERO,
|
valve_transform(model_origin.into())
|
||||||
),
|
),
|
||||||
color:glam::Vec4::ONE,
|
color:(glam::Vec3::from_array([r as f32,g as f32,b as f32])/255.0).extend(1.0),
|
||||||
})
|
}
|
||||||
).collect();
|
}).collect();
|
||||||
|
|
||||||
PartialMap1{
|
PartialMap1{
|
||||||
attributes:unique_attributes,
|
attributes:unique_attributes,
|
||||||
|
@ -2,16 +2,9 @@ use strafesnet_deferred_loader::deferred_loader::{LoadFailureMode,MeshDeferredLo
|
|||||||
|
|
||||||
mod bsp;
|
mod bsp;
|
||||||
mod mesh;
|
mod mesh;
|
||||||
mod brush;
|
|
||||||
pub mod loader;
|
pub mod loader;
|
||||||
|
|
||||||
const VALVE_SCALE:f32=1.0/16.0;
|
const VALVE_SCALE:f32=1.0/16.0;
|
||||||
pub(crate) fn valve_transform_dist(d:f32)->strafesnet_common::integer::Planar64{
|
|
||||||
(d*VALVE_SCALE).try_into().unwrap()
|
|
||||||
}
|
|
||||||
pub(crate) fn valve_transform_normal([x,y,z]:[f32;3])->strafesnet_common::integer::Planar64Vec3{
|
|
||||||
strafesnet_common::integer::vec3::try_from_f32_array([x,z,-y]).unwrap()
|
|
||||||
}
|
|
||||||
pub(crate) fn valve_transform([x,y,z]:[f32;3])->strafesnet_common::integer::Planar64Vec3{
|
pub(crate) fn valve_transform([x,y,z]:[f32;3])->strafesnet_common::integer::Planar64Vec3{
|
||||||
strafesnet_common::integer::vec3::try_from_f32_array([x*VALVE_SCALE,z*VALVE_SCALE,-y*VALVE_SCALE]).unwrap()
|
strafesnet_common::integer::vec3::try_from_f32_array([x*VALVE_SCALE,z*VALVE_SCALE,-y*VALVE_SCALE]).unwrap()
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "strafesnet_common"
|
name = "strafesnet_common"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Common types and helpers for Strafe Client associated projects."
|
description = "Common types and helpers for Strafe Client associated projects."
|
||||||
@ -15,5 +15,5 @@ bitflags = "2.6.0"
|
|||||||
fixed_wide = { version = "0.1.2", path = "../fixed_wide", registry = "strafesnet", features = ["deferred-division","zeroes","wide-mul"] }
|
fixed_wide = { version = "0.1.2", path = "../fixed_wide", registry = "strafesnet", features = ["deferred-division","zeroes","wide-mul"] }
|
||||||
linear_ops = { version = "0.1.0", path = "../linear_ops", registry = "strafesnet", features = ["deferred-division","named-fields"] }
|
linear_ops = { version = "0.1.0", path = "../linear_ops", registry = "strafesnet", features = ["deferred-division","named-fields"] }
|
||||||
ratio_ops = { version = "0.1.0", path = "../ratio_ops", registry = "strafesnet" }
|
ratio_ops = { version = "0.1.0", path = "../ratio_ops", registry = "strafesnet" }
|
||||||
glam = "0.29.0"
|
glam = "0.30.0"
|
||||||
id = { version = "0.1.0", registry = "strafesnet" }
|
id = { version = "0.1.0", registry = "strafesnet" }
|
||||||
|
@ -34,6 +34,10 @@ impl Aabb{
|
|||||||
self.min-=hs;
|
self.min-=hs;
|
||||||
self.max+=hs;
|
self.max+=hs;
|
||||||
}
|
}
|
||||||
|
pub fn contains(&self,point:Planar64Vec3)->bool{
|
||||||
|
let bvec=self.min.lt(point)&point.lt(self.max);
|
||||||
|
bvec.all()
|
||||||
|
}
|
||||||
pub fn intersects(&self,aabb:&Aabb)->bool{
|
pub fn intersects(&self,aabb:&Aabb)->bool{
|
||||||
let bvec=self.min.lt(aabb.max)&aabb.min.lt(self.max);
|
let bvec=self.min.lt(aabb.max)&aabb.min.lt(self.max);
|
||||||
bvec.all()
|
bvec.all()
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::aabb::Aabb;
|
use crate::aabb::Aabb;
|
||||||
|
use crate::ray::Ray;
|
||||||
|
use crate::integer::{Ratio,Planar64};
|
||||||
|
use crate::instruction::{InstructionCollector,TimedInstruction};
|
||||||
|
|
||||||
//da algaritum
|
//da algaritum
|
||||||
//lista boxens
|
//lista boxens
|
||||||
@ -10,35 +16,117 @@ use crate::aabb::Aabb;
|
|||||||
//sort the centerpoints on each axis (3 lists)
|
//sort the centerpoints on each axis (3 lists)
|
||||||
//bv is put into octant based on whether it is upper or lower in each list
|
//bv is put into octant based on whether it is upper or lower in each list
|
||||||
|
|
||||||
pub enum RecursiveContent<R,T>{
|
|
||||||
Branch(Vec<R>),
|
pub fn intersect_aabb(ray:&Ray,aabb:&Aabb)->Option<Ratio<Planar64,Planar64>>{
|
||||||
Leaf(T),
|
// n.(o+d*t)==n.p
|
||||||
|
// n.o + n.d * t == n.p
|
||||||
|
// t == (n.p - n.o)/n.d
|
||||||
|
let mut hit=None;
|
||||||
|
match ray.direction.x.cmp(&Planar64::ZERO){
|
||||||
|
Ordering::Less=>{
|
||||||
|
let rel_min=aabb.min()-ray.origin;
|
||||||
|
let rel_max=aabb.max()-ray.origin;
|
||||||
|
let dy=rel_max.x*ray.direction.y;
|
||||||
|
let dz=rel_max.x*ray.direction.z;
|
||||||
|
// x is negative, so inequalities are flipped
|
||||||
|
if rel_min.y*ray.direction.x>dy&&dy>rel_max.y*ray.direction.x
|
||||||
|
&&rel_min.z*ray.direction.x>dz&&dz>rel_max.z*ray.direction.x{
|
||||||
|
let t=rel_max.x/ray.direction.x;
|
||||||
|
hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ordering::Equal=>(),
|
||||||
|
Ordering::Greater=>{
|
||||||
|
let rel_min=aabb.min()-ray.origin;
|
||||||
|
let rel_max=aabb.max()-ray.origin;
|
||||||
|
let dy=rel_min.x*ray.direction.y;
|
||||||
|
let dz=rel_min.x*ray.direction.z;
|
||||||
|
// x is positive, so inequalities are normal
|
||||||
|
if rel_min.y*ray.direction.x<dy&&dy<rel_max.y*ray.direction.x
|
||||||
|
&&rel_min.z*ray.direction.x<dz&&dz<rel_max.z*ray.direction.x{
|
||||||
|
let t=rel_min.x/ray.direction.x;
|
||||||
|
hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
match ray.direction.z.cmp(&Planar64::ZERO){
|
||||||
|
Ordering::Less=>{
|
||||||
|
let rel_min=aabb.min()-ray.origin;
|
||||||
|
let rel_max=aabb.max()-ray.origin;
|
||||||
|
let dx=rel_max.z*ray.direction.x;
|
||||||
|
let dy=rel_max.z*ray.direction.y;
|
||||||
|
// z is negative, so inequalities are flipped
|
||||||
|
if rel_min.x*ray.direction.z>dx&&dx>rel_max.x*ray.direction.z
|
||||||
|
&&rel_min.y*ray.direction.z>dy&&dy>rel_max.y*ray.direction.z{
|
||||||
|
let t=rel_max.z/ray.direction.z;
|
||||||
|
hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ordering::Equal=>(),
|
||||||
|
Ordering::Greater=>{
|
||||||
|
let rel_min=aabb.min()-ray.origin;
|
||||||
|
let rel_max=aabb.max()-ray.origin;
|
||||||
|
let dx=rel_min.z*ray.direction.x;
|
||||||
|
let dy=rel_min.z*ray.direction.y;
|
||||||
|
// z is positive, so inequalities are normal
|
||||||
|
if rel_min.x*ray.direction.z<dx&&dx<rel_max.x*ray.direction.z
|
||||||
|
&&rel_min.y*ray.direction.z<dy&&dy<rel_max.y*ray.direction.z{
|
||||||
|
let t=rel_min.z/ray.direction.z;
|
||||||
|
hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
match ray.direction.y.cmp(&Planar64::ZERO){
|
||||||
|
Ordering::Less=>{
|
||||||
|
let rel_min=aabb.min()-ray.origin;
|
||||||
|
let rel_max=aabb.max()-ray.origin;
|
||||||
|
let dz=rel_max.y*ray.direction.z;
|
||||||
|
let dx=rel_max.y*ray.direction.x;
|
||||||
|
// y is negative, so inequalities are flipped
|
||||||
|
if rel_min.z*ray.direction.y>dz&&dz>rel_max.z*ray.direction.y
|
||||||
|
&&rel_min.x*ray.direction.y>dx&&dx>rel_max.x*ray.direction.y{
|
||||||
|
let t=rel_max.y/ray.direction.y;
|
||||||
|
hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ordering::Equal=>(),
|
||||||
|
Ordering::Greater=>{
|
||||||
|
let rel_min=aabb.min()-ray.origin;
|
||||||
|
let rel_max=aabb.max()-ray.origin;
|
||||||
|
let dz=rel_min.y*ray.direction.z;
|
||||||
|
let dx=rel_min.y*ray.direction.x;
|
||||||
|
// y is positive, so inequalities are normal
|
||||||
|
if rel_min.z*ray.direction.y<dz&&dz<rel_max.z*ray.direction.y
|
||||||
|
&&rel_min.x*ray.direction.y<dx&&dx<rel_max.x*ray.direction.y{
|
||||||
|
let t=rel_min.y/ray.direction.y;
|
||||||
|
hit=Some(hit.map_or(t,|best_t|t.min(best_t)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
hit
|
||||||
}
|
}
|
||||||
impl<R,T> Default for RecursiveContent<R,T>{
|
|
||||||
fn default()->Self{
|
pub enum RecursiveContent<N,L>{
|
||||||
|
Branch(Vec<N>),
|
||||||
|
Leaf(L),
|
||||||
|
}
|
||||||
|
impl<N,L> RecursiveContent<N,L>{
|
||||||
|
pub fn empty()->Self{
|
||||||
Self::Branch(Vec::new())
|
Self::Branch(Vec::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub struct BvhNode<T>{
|
pub struct BvhNode<L>{
|
||||||
content:RecursiveContent<BvhNode<T>,T>,
|
content:RecursiveContent<BvhNode<L>,L>,
|
||||||
aabb:Aabb,
|
aabb:Aabb,
|
||||||
}
|
}
|
||||||
impl<T> Default for BvhNode<T>{
|
impl<L> BvhNode<L>{
|
||||||
fn default()->Self{
|
pub fn empty()->Self{
|
||||||
Self{
|
Self{
|
||||||
content:Default::default(),
|
content:RecursiveContent::empty(),
|
||||||
aabb:Aabb::default(),
|
aabb:Aabb::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
pub fn sample_aabb<F:FnMut(&L)>(&self,aabb:&Aabb,f:&mut F){
|
||||||
pub struct BvhWeightNode<W,T>{
|
|
||||||
content:RecursiveContent<BvhWeightNode<W,T>,T>,
|
|
||||||
weight:W,
|
|
||||||
aabb:Aabb,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> BvhNode<T>{
|
|
||||||
pub fn the_tester<F:FnMut(&T)>(&self,aabb:&Aabb,f:&mut F){
|
|
||||||
match &self.content{
|
match &self.content{
|
||||||
RecursiveContent::Leaf(model)=>f(model),
|
RecursiveContent::Leaf(model)=>f(model),
|
||||||
RecursiveContent::Branch(children)=>for child in children{
|
RecursiveContent::Branch(children)=>for child in children{
|
||||||
@ -47,51 +135,101 @@ impl<T> BvhNode<T>{
|
|||||||
//you're probably not going to spend a lot of time outside the map,
|
//you're probably not going to spend a lot of time outside the map,
|
||||||
//so the test is extra work for nothing
|
//so the test is extra work for nothing
|
||||||
if aabb.intersects(&child.aabb){
|
if aabb.intersects(&child.aabb){
|
||||||
child.the_tester(aabb,f);
|
child.sample_aabb(aabb,f);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn into_visitor<F:FnMut(T)>(self,f:&mut F){
|
fn populate_nodes<'a,T,F>(
|
||||||
match self.content{
|
&'a self,
|
||||||
RecursiveContent::Leaf(model)=>f(model),
|
collector:&mut InstructionCollector<&'a L,Ratio<Planar64,Planar64>>,
|
||||||
|
nodes:&mut BTreeMap<Ratio<Planar64,Planar64>,&'a BvhNode<L>>,
|
||||||
|
ray:&Ray,
|
||||||
|
start_time:Ratio<Planar64,Planar64>,
|
||||||
|
f:&F,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
T:Ord+Copy,
|
||||||
|
Ratio<Planar64,Planar64>:From<T>,
|
||||||
|
F:Fn(&L,&Ray)->Option<T>,
|
||||||
|
{
|
||||||
|
match &self.content{
|
||||||
|
RecursiveContent::Leaf(leaf)=>if let Some(time)=f(leaf,ray){
|
||||||
|
let ins=TimedInstruction{time:time.into(),instruction:leaf};
|
||||||
|
if start_time.lt_ratio(ins.time)&&ins.time.lt_ratio(collector.time()){
|
||||||
|
collector.collect(Some(ins));
|
||||||
|
}
|
||||||
|
},
|
||||||
RecursiveContent::Branch(children)=>for child in children{
|
RecursiveContent::Branch(children)=>for child in children{
|
||||||
child.into_visitor(f)
|
if child.aabb.contains(ray.origin){
|
||||||
},
|
child.populate_nodes(collector,nodes,ray,start_time,f);
|
||||||
}
|
}else{
|
||||||
}
|
// Am I an upcoming superstar?
|
||||||
pub fn weigh_contents<W:Copy+std::iter::Sum<W>,F:Fn(&T)->W>(self,f:&F)->BvhWeightNode<W,T>{
|
if let Some(t)=intersect_aabb(ray,&child.aabb){
|
||||||
match self.content{
|
if start_time.lt_ratio(t)&&t.lt_ratio(collector.time()){
|
||||||
RecursiveContent::Leaf(model)=>BvhWeightNode{
|
nodes.insert(t,child);
|
||||||
weight:f(&model),
|
}
|
||||||
content:RecursiveContent::Leaf(model),
|
}
|
||||||
aabb:self.aabb,
|
|
||||||
},
|
|
||||||
RecursiveContent::Branch(children)=>{
|
|
||||||
let branch:Vec<BvhWeightNode<W,T>>=children.into_iter().map(|child|
|
|
||||||
child.weigh_contents(f)
|
|
||||||
).collect();
|
|
||||||
BvhWeightNode{
|
|
||||||
weight:branch.iter().map(|node|node.weight).sum(),
|
|
||||||
content:RecursiveContent::Branch(branch),
|
|
||||||
aabb:self.aabb,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
pub fn sample_ray<T,F>(
|
||||||
|
&self,
|
||||||
|
ray:&Ray,
|
||||||
|
start_time:T,
|
||||||
|
time_limit:T,
|
||||||
|
f:F,
|
||||||
|
)->Option<(T,&L)>
|
||||||
|
where
|
||||||
|
T:Ord+Copy,
|
||||||
|
T:From<Ratio<Planar64,Planar64>>,
|
||||||
|
Ratio<Planar64,Planar64>:From<T>,
|
||||||
|
F:Fn(&L,&Ray)->Option<T>,
|
||||||
|
{
|
||||||
|
// source of nondeterminism when Aabb boundaries are coplanar
|
||||||
|
let mut nodes=BTreeMap::new();
|
||||||
|
|
||||||
impl <W,T> BvhWeightNode<W,T>{
|
let start_time=start_time.into();
|
||||||
pub const fn weight(&self)->&W{
|
let time_limit=time_limit.into();
|
||||||
&self.weight
|
let mut collector=InstructionCollector::new(time_limit);
|
||||||
|
// break open all nodes that contain ray.origin and populate nodes with future intersection times
|
||||||
|
self.populate_nodes(&mut collector,&mut nodes,ray,start_time,&f);
|
||||||
|
|
||||||
|
// swim through nodes one at a time
|
||||||
|
while let Some((t,node))=nodes.pop_first(){
|
||||||
|
if collector.time()<t{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
match &node.content{
|
||||||
|
RecursiveContent::Leaf(leaf)=>if let Some(time)=f(leaf,ray){
|
||||||
|
let ins=TimedInstruction{time:time.into(),instruction:leaf};
|
||||||
|
// this lower bound can also be omitted
|
||||||
|
// but it causes type inference errors lol
|
||||||
|
if start_time.lt_ratio(ins.time)&&ins.time.lt_ratio(collector.time()){
|
||||||
|
collector.collect(Some(ins));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// break open the node and predict collisions with the child nodes
|
||||||
|
RecursiveContent::Branch(children)=>for child in children{
|
||||||
|
// Am I an upcoming superstar?
|
||||||
|
if let Some(t)=intersect_aabb(ray,&child.aabb){
|
||||||
|
// we don't need to check the lower bound
|
||||||
|
// because child aabbs are guaranteed to be within the parent bounds.
|
||||||
|
if t<collector.time(){
|
||||||
|
nodes.insert(t,child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collector.take().map(|TimedInstruction{time,instruction:leaf}|(time.into(),leaf))
|
||||||
}
|
}
|
||||||
pub const fn aabb(&self)->&Aabb{
|
pub fn into_inner(self)->(RecursiveContent<BvhNode<L>,L>,Aabb){
|
||||||
&self.aabb
|
(self.content,self.aabb)
|
||||||
}
|
}
|
||||||
pub fn into_content(self)->RecursiveContent<BvhWeightNode<W,T>,T>{
|
pub fn into_visitor<F:FnMut(L)>(self,f:&mut F){
|
||||||
self.content
|
|
||||||
}
|
|
||||||
pub fn into_visitor<F:FnMut(T)>(self,f:&mut F){
|
|
||||||
match self.content{
|
match self.content{
|
||||||
RecursiveContent::Leaf(model)=>f(model),
|
RecursiveContent::Leaf(model)=>f(model),
|
||||||
RecursiveContent::Branch(children)=>for child in children{
|
RecursiveContent::Branch(children)=>for child in children{
|
||||||
@ -130,9 +268,9 @@ fn generate_bvh_node<T>(boxen:Vec<(T,Aabb)>,force:bool)->BvhNode<T>{
|
|||||||
sort_y.push((i,center.y));
|
sort_y.push((i,center.y));
|
||||||
sort_z.push((i,center.z));
|
sort_z.push((i,center.z));
|
||||||
}
|
}
|
||||||
sort_x.sort_by(|tup0,tup1|tup0.1.cmp(&tup1.1));
|
sort_x.sort_by_key(|&(_,c)|c);
|
||||||
sort_y.sort_by(|tup0,tup1|tup0.1.cmp(&tup1.1));
|
sort_y.sort_by_key(|&(_,c)|c);
|
||||||
sort_z.sort_by(|tup0,tup1|tup0.1.cmp(&tup1.1));
|
sort_z.sort_by_key(|&(_,c)|c);
|
||||||
let h=n/2;
|
let h=n/2;
|
||||||
let median_x=sort_x[h].1;
|
let median_x=sort_x[h].1;
|
||||||
let median_y=sort_y[h].1;
|
let median_y=sort_y[h].1;
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
use crate::integer::Time;
|
|
||||||
|
|
||||||
#[derive(Clone,Debug)]
|
#[derive(Clone,Debug)]
|
||||||
pub struct TimedInstruction<I,T>{
|
pub struct TimedInstruction<I,T>{
|
||||||
pub time:Time<T>,
|
pub time:T,
|
||||||
pub instruction:I,
|
pub instruction:I,
|
||||||
}
|
}
|
||||||
impl<I,T> TimedInstruction<I,T>{
|
impl<I,T> TimedInstruction<I,T>{
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_time<TimeInner>(self,new_time:Time<TimeInner>)->TimedInstruction<I,TimeInner>{
|
pub fn set_time<T2>(self,new_time:T2)->TimedInstruction<I,T2>{
|
||||||
TimedInstruction{
|
TimedInstruction{
|
||||||
time:new_time,
|
time:new_time,
|
||||||
instruction:self.instruction,
|
instruction:self.instruction,
|
||||||
@ -17,21 +15,21 @@ impl<I,T> TimedInstruction<I,T>{
|
|||||||
|
|
||||||
/// Ensure all emitted instructions are processed before consuming external instructions
|
/// Ensure all emitted instructions are processed before consuming external instructions
|
||||||
pub trait InstructionEmitter<I>{
|
pub trait InstructionEmitter<I>{
|
||||||
type TimeInner;
|
type Time;
|
||||||
fn next_instruction(&self,time_limit:Time<Self::TimeInner>)->Option<TimedInstruction<I,Self::TimeInner>>;
|
fn next_instruction(&self,time_limit:Self::Time)->Option<TimedInstruction<I,Self::Time>>;
|
||||||
}
|
}
|
||||||
/// Apply an atomic state update
|
/// Apply an atomic state update
|
||||||
pub trait InstructionConsumer<I>{
|
pub trait InstructionConsumer<I>{
|
||||||
type TimeInner;
|
type Time;
|
||||||
fn process_instruction(&mut self,instruction:TimedInstruction<I,Self::TimeInner>);
|
fn process_instruction(&mut self,instruction:TimedInstruction<I,Self::Time>);
|
||||||
}
|
}
|
||||||
/// If the object produces its own instructions, allow exhaustively feeding them back in
|
/// If the object produces its own instructions, allow exhaustively feeding them back in
|
||||||
pub trait InstructionFeedback<I,T>:InstructionEmitter<I,TimeInner=T>+InstructionConsumer<I,TimeInner=T>
|
pub trait InstructionFeedback<I,T>:InstructionEmitter<I,Time=T>+InstructionConsumer<I,Time=T>
|
||||||
where
|
where
|
||||||
Time<T>:Copy,
|
T:Copy,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn process_exhaustive(&mut self,time_limit:Time<T>){
|
fn process_exhaustive(&mut self,time_limit:T){
|
||||||
while let Some(instruction)=self.next_instruction(time_limit){
|
while let Some(instruction)=self.next_instruction(time_limit){
|
||||||
self.process_instruction(instruction);
|
self.process_instruction(instruction);
|
||||||
}
|
}
|
||||||
@ -39,39 +37,24 @@ pub trait InstructionFeedback<I,T>:InstructionEmitter<I,TimeInner=T>+Instruction
|
|||||||
}
|
}
|
||||||
impl<I,T,X> InstructionFeedback<I,T> for X
|
impl<I,T,X> InstructionFeedback<I,T> for X
|
||||||
where
|
where
|
||||||
Time<T>:Copy,
|
T:Copy,
|
||||||
X:InstructionEmitter<I,TimeInner=T>+InstructionConsumer<I,TimeInner=T>,
|
X:InstructionEmitter<I,Time=T>+InstructionConsumer<I,Time=T>,
|
||||||
{}
|
{}
|
||||||
|
|
||||||
//PROPER PRIVATE FIELDS!!!
|
//PROPER PRIVATE FIELDS!!!
|
||||||
pub struct InstructionCollector<I,T>{
|
pub struct InstructionCollector<I,T>{
|
||||||
time:Time<T>,
|
time:T,
|
||||||
instruction:Option<I>,
|
instruction:Option<I>,
|
||||||
}
|
}
|
||||||
impl<I,T> InstructionCollector<I,T>
|
impl<I,T> InstructionCollector<I,T>{
|
||||||
where Time<T>:Copy+PartialOrd,
|
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn new(time:Time<T>)->Self{
|
pub const fn new(time:T)->Self{
|
||||||
Self{
|
Self{
|
||||||
time,
|
time,
|
||||||
instruction:None
|
instruction:None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn time(&self)->Time<T>{
|
|
||||||
self.time
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub fn collect(&mut self,instruction:Option<TimedInstruction<I,T>>){
|
|
||||||
if let Some(ins)=instruction{
|
|
||||||
if ins.time<self.time{
|
|
||||||
self.time=ins.time;
|
|
||||||
self.instruction=Some(ins.instruction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub fn take(self)->Option<TimedInstruction<I,T>>{
|
pub fn take(self)->Option<TimedInstruction<I,T>>{
|
||||||
//STEAL INSTRUCTION AND DESTROY INSTRUCTIONCOLLECTOR
|
//STEAL INSTRUCTION AND DESTROY INSTRUCTIONCOLLECTOR
|
||||||
self.instruction.map(|instruction|TimedInstruction{
|
self.instruction.map(|instruction|TimedInstruction{
|
||||||
@ -80,3 +63,20 @@ impl<I,T> InstructionCollector<I,T>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<I,T:Copy> InstructionCollector<I,T>{
|
||||||
|
#[inline]
|
||||||
|
pub const fn time(&self)->T{
|
||||||
|
self.time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<I,T:PartialOrd> InstructionCollector<I,T>{
|
||||||
|
#[inline]
|
||||||
|
pub fn collect(&mut self,instruction:Option<TimedInstruction<I,T>>){
|
||||||
|
if let Some(ins)=instruction{
|
||||||
|
if ins.time<self.time{
|
||||||
|
self.time=ins.time;
|
||||||
|
self.instruction=Some(ins.instruction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,11 +4,11 @@ pub use ratio_ops::ratio::{Ratio,Divide};
|
|||||||
//integer units
|
//integer units
|
||||||
|
|
||||||
/// specific example of a "default" time type
|
/// specific example of a "default" time type
|
||||||
#[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)]
|
#[derive(Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd,Debug)]
|
||||||
pub enum TimeInner{}
|
pub enum TimeInner{}
|
||||||
pub type AbsoluteTime=Time<TimeInner>;
|
pub type AbsoluteTime=Time<TimeInner>;
|
||||||
|
|
||||||
#[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)]
|
#[derive(Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd,Debug)]
|
||||||
pub struct Time<T>(i64,core::marker::PhantomData<T>);
|
pub struct Time<T>(i64,core::marker::PhantomData<T>);
|
||||||
impl<T> Time<T>{
|
impl<T> Time<T>{
|
||||||
pub const MIN:Self=Self::raw(i64::MIN);
|
pub const MIN:Self=Self::raw(i64::MIN);
|
||||||
@ -63,6 +63,12 @@ impl<T> From<Planar64> for Time<T>{
|
|||||||
Self::raw((value*Planar64::raw(1_000_000_000)).fix_1().to_raw())
|
Self::raw((value*Planar64::raw(1_000_000_000)).fix_1().to_raw())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<T> From<Time<T>> for Ratio<Planar64,Planar64>{
|
||||||
|
#[inline]
|
||||||
|
fn from(value:Time<T>)->Self{
|
||||||
|
value.to_ratio()
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<T,Num,Den,N1,T1> From<Ratio<Num,Den>> for Time<T>
|
impl<T,Num,Den,N1,T1> From<Ratio<Num,Den>> for Time<T>
|
||||||
where
|
where
|
||||||
Num:core::ops::Mul<Planar64,Output=N1>,
|
Num:core::ops::Mul<Planar64,Output=N1>,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
pub mod bvh;
|
pub mod bvh;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
|
pub mod ray;
|
||||||
pub mod run;
|
pub mod run;
|
||||||
pub mod aabb;
|
pub mod aabb;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::mouse::MouseState;
|
use crate::mouse::MouseState;
|
||||||
use crate::gameplay_modes::{ModeId,StageId};
|
use crate::gameplay_modes::{ModeId,StageId};
|
||||||
|
|
||||||
#[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)]
|
#[derive(Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd,Debug)]
|
||||||
pub enum TimeInner{}
|
pub enum TimeInner{}
|
||||||
pub type Time=crate::integer::Time<TimeInner>;
|
pub type Time=crate::integer::Time<TimeInner>;
|
||||||
|
|
||||||
|
20
lib/common/src/ray.rs
Normal file
20
lib/common/src/ray.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use ratio_ops::ratio::Ratio;
|
||||||
|
use crate::integer::{self,Planar64,Planar64Vec3};
|
||||||
|
|
||||||
|
pub struct Ray{
|
||||||
|
pub origin:Planar64Vec3,
|
||||||
|
pub direction:Planar64Vec3,
|
||||||
|
}
|
||||||
|
impl Ray{
|
||||||
|
pub fn extrapolate<Num,Den,N1,T1>(&self,t:Ratio<Num,Den>)->Planar64Vec3
|
||||||
|
where
|
||||||
|
Num:Copy,
|
||||||
|
Den:Copy,
|
||||||
|
Num:core::ops::Mul<Planar64,Output=N1>,
|
||||||
|
Planar64:core::ops::Mul<Den,Output=N1>,
|
||||||
|
N1:integer::Divide<Den,Output=T1>,
|
||||||
|
T1:integer::Fix<Planar64>,
|
||||||
|
{
|
||||||
|
self.origin+self.direction.map(|elem|(t*elem).divide().fix())
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@ use crate::timer::{TimerFixed,Realtime,Paused,Unpaused};
|
|||||||
|
|
||||||
use crate::physics::{TimeInner as PhysicsTimeInner,Time as PhysicsTime};
|
use crate::physics::{TimeInner as PhysicsTimeInner,Time as PhysicsTime};
|
||||||
|
|
||||||
#[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)]
|
#[derive(Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd,Debug)]
|
||||||
pub enum TimeInner{}
|
pub enum TimeInner{}
|
||||||
pub type Time=crate::integer::Time<TimeInner>;
|
pub type Time=crate::integer::Time<TimeInner>;
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)]
|
#[derive(Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd,Debug)]
|
||||||
pub enum TimeInner{}
|
pub enum TimeInner{}
|
||||||
pub type Time=crate::integer::Time<TimeInner>;
|
pub type Time=crate::integer::Time<TimeInner>;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "strafesnet_deferred_loader"
|
name = "strafesnet_deferred_loader"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Acquire IDs for objects before loading them in bulk."
|
description = "Acquire IDs for objects before loading them in bulk."
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "fixed_wide"
|
name = "fixed_wide"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Fixed point numbers with optional widening Mul operator."
|
description = "Fixed point numbers with optional widening Mul operator."
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "linear_ops"
|
name = "linear_ops"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Vector/Matrix operations using trait bounds."
|
description = "Vector/Matrix operations using trait bounds."
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::vector::Vector;
|
use crate::vector::Vector;
|
||||||
|
|
||||||
#[repr(transparent)]
|
|
||||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
||||||
pub struct Matrix<const X:usize,const Y:usize,T>{
|
pub struct Matrix<const X:usize,const Y:usize,T>{
|
||||||
pub(crate) array:[[T;Y];X],
|
pub(crate) array:[[T;Y];X],
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
/// v.x += v.z;
|
/// v.x += v.z;
|
||||||
/// println!("v.x={}",v.x);
|
/// println!("v.x={}",v.x);
|
||||||
|
|
||||||
#[repr(transparent)]
|
|
||||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
||||||
pub struct Vector<const N:usize,T>{
|
pub struct Vector<const N:usize,T>{
|
||||||
pub(crate) array:[T;N],
|
pub(crate) array:[T;N],
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ratio_ops"
|
name = "ratio_ops"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Ratio operations using trait bounds for avoiding division like the plague."
|
description = "Ratio operations using trait bounds for avoiding division like the plague."
|
||||||
|
@ -268,30 +268,35 @@ impl<LhsNum,LhsDen,RhsNum,RhsDen,T,U> PartialEq<Ratio<RhsNum,RhsDen>> for Ratio<
|
|||||||
}
|
}
|
||||||
impl<Num,Den> Eq for Ratio<Num,Den> where Self:PartialEq{}
|
impl<Num,Den> Eq for Ratio<Num,Den> where Self:PartialEq{}
|
||||||
|
|
||||||
|
// Wow! These were both completely wrong!
|
||||||
|
// Idea: use a 'signed' trait instead of parity and float the sign to the numerator.
|
||||||
impl<LhsNum,LhsDen,RhsNum,RhsDen,T,U> PartialOrd<Ratio<RhsNum,RhsDen>> for Ratio<LhsNum,LhsDen>
|
impl<LhsNum,LhsDen,RhsNum,RhsDen,T,U> PartialOrd<Ratio<RhsNum,RhsDen>> for Ratio<LhsNum,LhsDen>
|
||||||
where
|
where
|
||||||
LhsNum:Copy,
|
LhsNum:Copy,
|
||||||
LhsDen:Copy,
|
LhsDen:Copy+Parity,
|
||||||
RhsNum:Copy,
|
RhsNum:Copy,
|
||||||
RhsDen:Copy,
|
RhsDen:Copy+Parity,
|
||||||
LhsNum:core::ops::Mul<RhsDen,Output=T>,
|
LhsNum:core::ops::Mul<RhsDen,Output=T>,
|
||||||
|
LhsDen:core::ops::Mul<RhsNum,Output=T>,
|
||||||
RhsNum:core::ops::Mul<LhsDen,Output=U>,
|
RhsNum:core::ops::Mul<LhsDen,Output=U>,
|
||||||
T:PartialOrd<U>,
|
RhsDen:core::ops::Mul<LhsNum,Output=U>,
|
||||||
|
T:PartialOrd<U>+Ord,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn partial_cmp(&self,other:&Ratio<RhsNum,RhsDen>)->Option<core::cmp::Ordering>{
|
fn partial_cmp(&self,&other:&Ratio<RhsNum,RhsDen>)->Option<core::cmp::Ordering>{
|
||||||
(self.num*other.den).partial_cmp(&(other.num*self.den))
|
self.partial_cmp_ratio(other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<Num,Den,T> Ord for Ratio<Num,Den>
|
impl<Num,Den,T> Ord for Ratio<Num,Den>
|
||||||
where
|
where
|
||||||
Num:Copy,
|
Num:Copy,
|
||||||
Den:Copy,
|
Den:Copy+Parity,
|
||||||
Num:core::ops::Mul<Den,Output=T>,
|
Num:core::ops::Mul<Den,Output=T>,
|
||||||
|
Den:core::ops::Mul<Num,Output=T>,
|
||||||
T:Ord,
|
T:Ord,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cmp(&self,other:&Self)->std::cmp::Ordering{
|
fn cmp(&self,&other:&Self)->std::cmp::Ordering{
|
||||||
(self.num*other.den).cmp(&(other.num*self.den))
|
self.cmp_ratio(other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "strafesnet_rbx_loader"
|
name = "strafesnet_rbx_loader"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Convert Roblox place and model files to StrafesNET data structures."
|
description = "Convert Roblox place and model files to StrafesNET data structures."
|
||||||
@ -11,7 +11,7 @@ authors = ["Rhys Lloyd <krakow20@gmail.com>"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytemuck = "1.14.3"
|
bytemuck = "1.14.3"
|
||||||
glam = "0.29.0"
|
glam = "0.30.0"
|
||||||
lazy-regex = "3.1.0"
|
lazy-regex = "3.1.0"
|
||||||
rbx_binary = { version = "0.7.4", registry = "strafesnet" }
|
rbx_binary = { version = "0.7.4", registry = "strafesnet" }
|
||||||
rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" }
|
rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rbxassetid"
|
name = "rbxassetid"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Parse Roblox asset id from 'Content' urls."
|
description = "Parse Roblox asset id from 'Content' urls."
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "roblox_emulator"
|
name = "roblox_emulator"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Run embedded Luau scripts which manipulate the DOM."
|
description = "Run embedded Luau scripts which manipulate the DOM."
|
||||||
@ -12,7 +12,7 @@ default=["run-service"]
|
|||||||
run-service=[]
|
run-service=[]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
glam = "0.29.0"
|
glam = "0.30.0"
|
||||||
mlua = { version = "0.10.1", features = ["luau"] }
|
mlua = { version = "0.10.1", features = ["luau"] }
|
||||||
phf = { version = "0.11.2", features = ["macros"] }
|
phf = { version = "0.11.2", features = ["macros"] }
|
||||||
rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" }
|
rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "strafesnet_snf"
|
name = "strafesnet_snf"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ use strafesnet_common::physics::Time;
|
|||||||
|
|
||||||
const VERSION:u32=0;
|
const VERSION:u32=0;
|
||||||
|
|
||||||
type TimedPhysicsInstruction=strafesnet_common::instruction::TimedInstruction<strafesnet_common::physics::Instruction,strafesnet_common::physics::TimeInner>;
|
type TimedPhysicsInstruction=strafesnet_common::instruction::TimedInstruction<strafesnet_common::physics::Instruction,strafesnet_common::physics::Time>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error{
|
pub enum Error{
|
||||||
|
@ -6,7 +6,7 @@ use crate::file::BlockId;
|
|||||||
use binrw::{binrw,BinReaderExt,BinWriterExt};
|
use binrw::{binrw,BinReaderExt,BinWriterExt};
|
||||||
use strafesnet_common::model;
|
use strafesnet_common::model;
|
||||||
use strafesnet_common::aabb::Aabb;
|
use strafesnet_common::aabb::Aabb;
|
||||||
use strafesnet_common::bvh::BvhNode;
|
use strafesnet_common::bvh::{BvhNode,RecursiveContent};
|
||||||
use strafesnet_common::gameplay_modes;
|
use strafesnet_common::gameplay_modes;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -233,7 +233,7 @@ impl<R:BinReaderExt> StreamableMap<R>{
|
|||||||
}
|
}
|
||||||
pub fn get_intersecting_region_block_ids(&self,aabb:&Aabb)->Vec<BlockId>{
|
pub fn get_intersecting_region_block_ids(&self,aabb:&Aabb)->Vec<BlockId>{
|
||||||
let mut block_ids=Vec::new();
|
let mut block_ids=Vec::new();
|
||||||
self.bvh.the_tester(aabb,&mut |&block_id|block_ids.push(block_id));
|
self.bvh.sample_aabb(aabb,&mut |&block_id|block_ids.push(block_id));
|
||||||
block_ids
|
block_ids
|
||||||
}
|
}
|
||||||
pub fn load_region(&mut self,block_id:BlockId)->Result<Vec<(model::ModelId,model::Model)>,Error>{
|
pub fn load_region(&mut self,block_id:BlockId)->Result<Vec<(model::ModelId,model::Model)>,Error>{
|
||||||
@ -287,12 +287,60 @@ impl<R:BinReaderExt> StreamableMap<R>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// silly redefinition of Bvh for determining the size of subnodes
|
||||||
|
// without duplicating work by running weight calculation recursion top down on every node
|
||||||
|
pub struct BvhWeightNode<W,T>{
|
||||||
|
content:RecursiveContent<BvhWeightNode<W,T>,T>,
|
||||||
|
weight:W,
|
||||||
|
aabb:Aabb,
|
||||||
|
}
|
||||||
|
impl <W,T> BvhWeightNode<W,T>{
|
||||||
|
pub const fn weight(&self)->&W{
|
||||||
|
&self.weight
|
||||||
|
}
|
||||||
|
pub const fn aabb(&self)->&Aabb{
|
||||||
|
&self.aabb
|
||||||
|
}
|
||||||
|
pub fn into_content(self)->RecursiveContent<BvhWeightNode<W,T>,T>{
|
||||||
|
self.content
|
||||||
|
}
|
||||||
|
pub fn into_visitor<F:FnMut(T)>(self,f:&mut F){
|
||||||
|
match self.content{
|
||||||
|
RecursiveContent::Leaf(model)=>f(model),
|
||||||
|
RecursiveContent::Branch(children)=>for child in children{
|
||||||
|
child.into_visitor(f)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn weigh_contents<T,W:Copy+std::iter::Sum<W>,F:Fn(&T)->W>(node:BvhNode<T>,f:&F)->BvhWeightNode<W,T>{
|
||||||
|
let (content,aabb)=node.into_inner();
|
||||||
|
match content{
|
||||||
|
RecursiveContent::Leaf(model)=>BvhWeightNode{
|
||||||
|
weight:f(&model),
|
||||||
|
content:RecursiveContent::Leaf(model),
|
||||||
|
aabb,
|
||||||
|
},
|
||||||
|
RecursiveContent::Branch(children)=>{
|
||||||
|
let branch:Vec<BvhWeightNode<W,T>>=children.into_iter().map(|child|
|
||||||
|
weigh_contents(child,f)
|
||||||
|
).collect();
|
||||||
|
BvhWeightNode{
|
||||||
|
weight:branch.iter().map(|node|node.weight).sum(),
|
||||||
|
content:RecursiveContent::Branch(branch),
|
||||||
|
aabb,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const BVH_NODE_MAX_WEIGHT:usize=64*1024;//64 kB
|
const BVH_NODE_MAX_WEIGHT:usize=64*1024;//64 kB
|
||||||
fn collect_spacial_blocks(
|
fn collect_spacial_blocks(
|
||||||
block_location:&mut Vec<u64>,
|
block_location:&mut Vec<u64>,
|
||||||
block_headers:&mut Vec<SpacialBlockHeader>,
|
block_headers:&mut Vec<SpacialBlockHeader>,
|
||||||
sequential_block_data:&mut std::io::Cursor<&mut Vec<u8>>,
|
sequential_block_data:&mut std::io::Cursor<&mut Vec<u8>>,
|
||||||
bvh_node:strafesnet_common::bvh::BvhWeightNode<usize,(model::ModelId,newtypes::model::Model)>
|
bvh_node:BvhWeightNode<usize,(model::ModelId,newtypes::model::Model)>
|
||||||
)->Result<(),Error>{
|
)->Result<(),Error>{
|
||||||
//inspect the node weights top-down.
|
//inspect the node weights top-down.
|
||||||
//When a node weighs less than the limit,
|
//When a node weighs less than the limit,
|
||||||
@ -342,7 +390,7 @@ pub fn write_map<W:BinWriterExt>(mut writer:W,map:strafesnet_common::map::Comple
|
|||||||
}
|
}
|
||||||
Ok(((model::ModelId::new(model_id as u32),model.into()),aabb))
|
Ok(((model::ModelId::new(model_id as u32),model.into()),aabb))
|
||||||
}).collect::<Result<Vec<_>,_>>()?;
|
}).collect::<Result<Vec<_>,_>>()?;
|
||||||
let bvh=strafesnet_common::bvh::generate_bvh(boxen).weigh_contents(&|_|std::mem::size_of::<newtypes::model::Model>());
|
let bvh=weigh_contents(strafesnet_common::bvh::generate_bvh(boxen),&|_|std::mem::size_of::<newtypes::model::Model>());
|
||||||
//build blocks
|
//build blocks
|
||||||
//block location is initialized with two values
|
//block location is initialized with two values
|
||||||
//the first value represents the location of the first byte after the file header
|
//the first value represents the location of the first byte after the file header
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::integer::Time;
|
use super::integer::Time;
|
||||||
use super::common::{bool_from_u8,bool_into_u8};
|
use super::common::{bool_from_u8,bool_into_u8};
|
||||||
|
|
||||||
type TimedPhysicsInstruction=strafesnet_common::instruction::TimedInstruction<strafesnet_common::physics::Instruction,strafesnet_common::physics::TimeInner>;
|
type TimedPhysicsInstruction=strafesnet_common::instruction::TimedInstruction<strafesnet_common::physics::Instruction,strafesnet_common::physics::Time>;
|
||||||
|
|
||||||
#[binrw::binrw]
|
#[binrw::binrw]
|
||||||
#[brw(little)]
|
#[brw(little)]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "map-tool"
|
name = "map-tool"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "strafe-client"
|
name = "strafe-client"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
repository = "https://git.itzana.me/StrafesNET/strafe-project"
|
||||||
license = "Custom"
|
license = "Custom"
|
||||||
description = "StrafesNET game client for bhop and surf."
|
description = "StrafesNET game client for bhop and surf."
|
||||||
@ -16,7 +16,7 @@ source = ["dep:strafesnet_deferred_loader", "dep:strafesnet_bsp_loader"]
|
|||||||
roblox = ["dep:strafesnet_deferred_loader", "dep:strafesnet_rbx_loader"]
|
roblox = ["dep:strafesnet_deferred_loader", "dep:strafesnet_rbx_loader"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
glam = "0.29.0"
|
glam = "0.30.0"
|
||||||
parking_lot = "0.12.1"
|
parking_lot = "0.12.1"
|
||||||
pollster = "0.4.0"
|
pollster = "0.4.0"
|
||||||
strafesnet_bsp_loader = { path = "../lib/bsp_loader", registry = "strafesnet", optional = true }
|
strafesnet_bsp_loader = { path = "../lib/bsp_loader", registry = "strafesnet", optional = true }
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
use crate::window::Instruction;
|
use crate::window::Instruction;
|
||||||
use strafesnet_common::integer;
|
use strafesnet_common::integer;
|
||||||
use strafesnet_common::instruction::TimedInstruction;
|
use strafesnet_common::instruction::TimedInstruction;
|
||||||
use strafesnet_common::session::TimeInner as SessionTimeInner;
|
use strafesnet_common::session::Time as SessionTime;
|
||||||
|
|
||||||
pub struct App<'a>{
|
pub struct App<'a>{
|
||||||
root_time:std::time::Instant,
|
root_time:std::time::Instant,
|
||||||
window_thread:crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTimeInner>>,
|
window_thread:crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTime>>,
|
||||||
}
|
}
|
||||||
impl<'a> App<'a>{
|
impl<'a> App<'a>{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
root_time:std::time::Instant,
|
root_time:std::time::Instant,
|
||||||
window_thread:crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTimeInner>>,
|
window_thread:crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTime>>,
|
||||||
)->App<'a>{
|
)->App<'a>{
|
||||||
Self{
|
Self{
|
||||||
root_time,
|
root_time,
|
||||||
|
@ -2,7 +2,6 @@ mod app;
|
|||||||
mod file;
|
mod file;
|
||||||
mod setup;
|
mod setup;
|
||||||
mod window;
|
mod window;
|
||||||
mod worker;
|
|
||||||
mod compat_worker;
|
mod compat_worker;
|
||||||
mod physics_worker;
|
mod physics_worker;
|
||||||
mod graphics_worker;
|
mod graphics_worker;
|
||||||
|
@ -6,7 +6,7 @@ use strafesnet_session::session::{
|
|||||||
};
|
};
|
||||||
use strafesnet_common::instruction::{TimedInstruction,InstructionConsumer};
|
use strafesnet_common::instruction::{TimedInstruction,InstructionConsumer};
|
||||||
use strafesnet_common::physics::Time as PhysicsTime;
|
use strafesnet_common::physics::Time as PhysicsTime;
|
||||||
use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner};
|
use strafesnet_common::session::Time as SessionTime;
|
||||||
use strafesnet_common::timer::Timer;
|
use strafesnet_common::timer::Timer;
|
||||||
|
|
||||||
pub enum Instruction{
|
pub enum Instruction{
|
||||||
@ -23,7 +23,7 @@ pub fn new<'a>(
|
|||||||
mut graphics_worker:crate::compat_worker::INWorker<'a,crate::graphics_worker::Instruction>,
|
mut graphics_worker:crate::compat_worker::INWorker<'a,crate::graphics_worker::Instruction>,
|
||||||
directories:Directories,
|
directories:Directories,
|
||||||
user_settings:settings::UserSettings,
|
user_settings:settings::UserSettings,
|
||||||
)->crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTimeInner>>{
|
)->crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTime>>{
|
||||||
let physics=strafesnet_physics::physics::PhysicsState::default();
|
let physics=strafesnet_physics::physics::PhysicsState::default();
|
||||||
let timer=Timer::unpaused(SessionTime::ZERO,PhysicsTime::ZERO);
|
let timer=Timer::unpaused(SessionTime::ZERO,PhysicsTime::ZERO);
|
||||||
let simulation=Simulation::new(timer,physics);
|
let simulation=Simulation::new(timer,physics);
|
||||||
@ -32,7 +32,7 @@ pub fn new<'a>(
|
|||||||
directories,
|
directories,
|
||||||
simulation,
|
simulation,
|
||||||
);
|
);
|
||||||
crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<Instruction,SessionTimeInner>|{
|
crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<Instruction,SessionTime>|{
|
||||||
// excruciating pain
|
// excruciating pain
|
||||||
macro_rules! run_session_instruction{
|
macro_rules! run_session_instruction{
|
||||||
($time:expr,$instruction:expr)=>{
|
($time:expr,$instruction:expr)=>{
|
||||||
@ -77,5 +77,8 @@ pub fn new<'a>(
|
|||||||
run_session_instruction!(ins.time,SessionInstruction::LoadReplay(bot));
|
run_session_instruction!(ins.time,SessionInstruction::LoadReplay(bot));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//whatever just do it
|
||||||
|
session.debug_raycast_print_model_id_if_changed(ins.time);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use strafesnet_common::instruction::TimedInstruction;
|
use strafesnet_common::instruction::TimedInstruction;
|
||||||
use strafesnet_common::session::{Time as SessionTime,TimeInner as SessionTimeInner};
|
use strafesnet_common::session::Time as SessionTime;
|
||||||
use strafesnet_common::physics::{MiscInstruction,SetControlInstruction};
|
use strafesnet_common::physics::{MiscInstruction,SetControlInstruction};
|
||||||
use crate::file::LoadFormat;
|
use crate::file::LoadFormat;
|
||||||
use crate::physics_worker::Instruction as PhysicsWorkerInstruction;
|
use crate::physics_worker::Instruction as PhysicsWorkerInstruction;
|
||||||
@ -17,7 +17,7 @@ struct WindowContext<'a>{
|
|||||||
mouse_pos:glam::DVec2,
|
mouse_pos:glam::DVec2,
|
||||||
screen_size:glam::UVec2,
|
screen_size:glam::UVec2,
|
||||||
window:&'a winit::window::Window,
|
window:&'a winit::window::Window,
|
||||||
physics_thread:crate::compat_worker::QNWorker<'a,TimedInstruction<PhysicsWorkerInstruction,SessionTimeInner>>,
|
physics_thread:crate::compat_worker::QNWorker<'a,TimedInstruction<PhysicsWorkerInstruction,SessionTime>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowContext<'_>{
|
impl WindowContext<'_>{
|
||||||
@ -223,7 +223,7 @@ impl WindowContext<'_>{
|
|||||||
pub fn worker<'a>(
|
pub fn worker<'a>(
|
||||||
window:&'a winit::window::Window,
|
window:&'a winit::window::Window,
|
||||||
setup_context:crate::setup::SetupContext<'a>,
|
setup_context:crate::setup::SetupContext<'a>,
|
||||||
)->crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTimeInner>>{
|
)->crate::compat_worker::QNWorker<'a,TimedInstruction<Instruction,SessionTime>>{
|
||||||
// WindowContextSetup::new
|
// WindowContextSetup::new
|
||||||
#[cfg(feature="user-install")]
|
#[cfg(feature="user-install")]
|
||||||
let directories=Directories::user().unwrap();
|
let directories=Directories::user().unwrap();
|
||||||
@ -252,7 +252,7 @@ pub fn worker<'a>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
//WindowContextSetup::into_worker
|
//WindowContextSetup::into_worker
|
||||||
crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<Instruction,SessionTimeInner>|{
|
crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<Instruction,SessionTime>|{
|
||||||
match ins.instruction{
|
match ins.instruction{
|
||||||
Instruction::WindowEvent(window_event)=>{
|
Instruction::WindowEvent(window_event)=>{
|
||||||
window_context.window_event(ins.time,window_event);
|
window_context.window_event(ins.time,window_event);
|
||||||
|
@ -1 +1 @@
|
|||||||
/run/media/quat/Files/Documents/map-files/verify-scripts/maps/bhop_snfm
|
/run/media/quat/Files/Documents/map-files/strafesnet/maps/bhop_snfm
|
@ -1 +1 @@
|
|||||||
/run/media/quat/Files/Documents/map-files/verify-scripts/meshes
|
/run/media/quat/Files/Documents/map-files/strafesnet/meshes
|
@ -1 +1 @@
|
|||||||
/run/media/quat/Files/Documents/map-files/verify-scripts/replays
|
/run/media/quat/Files/Documents/map-files/strafesnet/replays
|
@ -1 +1 @@
|
|||||||
/run/media/quat/Files/Documents/map-files/verify-scripts/maps/surf_snfm
|
/run/media/quat/Files/Documents/map-files/strafesnet/maps/surf_snfm
|
@ -1 +1 @@
|
|||||||
/run/media/quat/Files/Documents/map-files/verify-scripts/textures
|
/run/media/quat/Files/Documents/map-files/strafesnet/textures
|
@ -1 +1 @@
|
|||||||
/run/media/quat/Files/Documents/map-files/verify-scripts/unions
|
/run/media/quat/Files/Documents/map-files/strafesnet/unions
|
Reference in New Issue
Block a user