diff --git a/Cargo.lock b/Cargo.lock index cf871e56..a4a9f24b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -592,15 +592,14 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-tls" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfeefd0ca297cbbb3bd34fd6b228401c2a5177038257afd751bc29f0a2da4795" +checksum = "b2ae3c9eba89d472a0e4fe1dea433df78fbbe63d2b764addaf2ba3a6bde89a5e" dependencies = [ "futures-core", "futures-io", - "rustls 0.20.9", + "rustls 0.21.12", "rustls-pemfile 1.0.4", - "webpki", "webpki-roots 0.22.6", ] @@ -617,9 +616,9 @@ dependencies = [ [[package]] name = "async-tungstenite" -version = "0.22.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce01ac37fdc85f10a43c43bc582cbd566720357011578a935761075f898baf58" +checksum = "90e661b6cb0a6eb34d02c520b052daa3aa9ac0cc02495c9d066bbce13ead132b" dependencies = [ "async-std", "async-tls", @@ -627,7 +626,7 @@ dependencies = [ "futures-util", "log", "pin-project-lite", - "tungstenite 0.19.0", + "tungstenite 0.24.0", ] [[package]] @@ -867,7 +866,7 @@ dependencies = [ [[package]] name = "bevy" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_internal", ] @@ -875,7 +874,7 @@ dependencies = [ [[package]] name = "bevy_a11y" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "accesskit", "bevy_app", @@ -886,7 +885,7 @@ dependencies = [ [[package]] name = "bevy_animation" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_asset", @@ -915,7 +914,7 @@ dependencies = [ [[package]] name = "bevy_app" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_derive", "bevy_ecs", @@ -932,7 +931,7 @@ dependencies = [ [[package]] name = "bevy_asset" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "async-broadcast", "async-fs", @@ -964,7 +963,7 @@ dependencies = [ [[package]] name = "bevy_asset_macros" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_macro_utils 0.14.1", "proc-macro2", @@ -997,7 +996,7 @@ dependencies = [ [[package]] name = "bevy_audio" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_asset", @@ -1015,7 +1014,7 @@ dependencies = [ [[package]] name = "bevy_color" version = "0.14.2" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_math", "bevy_reflect", @@ -1052,7 +1051,7 @@ dependencies = [ [[package]] name = "bevy_core" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_ecs", @@ -1065,7 +1064,7 @@ dependencies = [ [[package]] name = "bevy_core_pipeline" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_asset", @@ -1089,7 +1088,7 @@ dependencies = [ [[package]] name = "bevy_derive" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_macro_utils 0.14.1", "quote", @@ -1099,7 +1098,7 @@ dependencies = [ [[package]] name = "bevy_diagnostic" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_core", @@ -1125,7 +1124,7 @@ dependencies = [ [[package]] name = "bevy_ecs" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "arrayvec", "bevy_ecs_macros", @@ -1145,7 +1144,7 @@ dependencies = [ [[package]] name = "bevy_ecs_macros" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_macro_utils 0.14.1", "proc-macro2", @@ -1190,7 +1189,7 @@ dependencies = [ [[package]] name = "bevy_encase_derive" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_macro_utils 0.14.1", "encase_derive_impl", @@ -1199,7 +1198,7 @@ dependencies = [ [[package]] name = "bevy_gilrs" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_ecs", @@ -1213,7 +1212,7 @@ dependencies = [ [[package]] name = "bevy_gizmos" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_asset", @@ -1235,7 +1234,7 @@ dependencies = [ [[package]] name = "bevy_gizmos_macros" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_macro_utils 0.14.1", "proc-macro2", @@ -1246,7 +1245,7 @@ dependencies = [ [[package]] name = "bevy_gltf" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "base64 0.22.1", "bevy_animation", @@ -1276,7 +1275,7 @@ dependencies = [ [[package]] name = "bevy_hierarchy" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_core", @@ -1289,7 +1288,7 @@ dependencies = [ [[package]] name = "bevy_input" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_ecs", @@ -1303,7 +1302,7 @@ dependencies = [ [[package]] name = "bevy_internal" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_a11y", "bevy_animation", @@ -1356,7 +1355,7 @@ dependencies = [ [[package]] name = "bevy_log" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "android_log-sys", "bevy_app", @@ -1372,7 +1371,7 @@ dependencies = [ [[package]] name = "bevy_macro_utils" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "proc-macro2", "quote", @@ -1395,7 +1394,7 @@ dependencies = [ [[package]] name = "bevy_math" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_reflect", "glam 0.27.0", @@ -1408,7 +1407,7 @@ dependencies = [ [[package]] name = "bevy_mikktspace" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "glam 0.27.0", ] @@ -1416,7 +1415,7 @@ dependencies = [ [[package]] name = "bevy_pbr" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_asset", @@ -1442,12 +1441,12 @@ dependencies = [ [[package]] name = "bevy_ptr" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" [[package]] name = "bevy_reflect" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_ptr", "bevy_reflect_derive", @@ -1466,7 +1465,7 @@ dependencies = [ [[package]] name = "bevy_reflect_derive" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_macro_utils 0.14.1", "proc-macro2", @@ -1478,7 +1477,7 @@ dependencies = [ [[package]] name = "bevy_render" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "async-channel 2.3.1", "bevy_app", @@ -1526,7 +1525,7 @@ dependencies = [ [[package]] name = "bevy_render_macros" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_macro_utils 0.14.1", "proc-macro2", @@ -1537,7 +1536,7 @@ dependencies = [ [[package]] name = "bevy_scene" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_asset", @@ -1566,7 +1565,7 @@ dependencies = [ [[package]] name = "bevy_sprite" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_asset", @@ -1591,7 +1590,7 @@ dependencies = [ [[package]] name = "bevy_state" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_ecs", @@ -1604,7 +1603,7 @@ dependencies = [ [[package]] name = "bevy_state_macros" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_macro_utils 0.14.1", "proc-macro2", @@ -1615,7 +1614,7 @@ dependencies = [ [[package]] name = "bevy_tasks" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "async-channel 2.3.1", "async-executor", @@ -1627,7 +1626,7 @@ dependencies = [ [[package]] name = "bevy_text" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_asset", @@ -1651,7 +1650,7 @@ dependencies = [ [[package]] name = "bevy_time" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_ecs", @@ -1664,7 +1663,7 @@ dependencies = [ [[package]] name = "bevy_transform" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_app", "bevy_ecs", @@ -1677,7 +1676,7 @@ dependencies = [ [[package]] name = "bevy_ui" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_a11y", "bevy_app", @@ -1706,7 +1705,7 @@ dependencies = [ [[package]] name = "bevy_utils" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "ahash", "bevy_utils_proc_macros", @@ -1720,7 +1719,7 @@ dependencies = [ [[package]] name = "bevy_utils_proc_macros" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "proc-macro2", "quote", @@ -1730,7 +1729,7 @@ dependencies = [ [[package]] name = "bevy_window" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "bevy_a11y", "bevy_app", @@ -1745,7 +1744,7 @@ dependencies = [ [[package]] name = "bevy_winit" version = "0.14.1" -source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#985cbb2a9a7e4106584fcb57e67908d210936340" +source = "git+https://github.com/robtfm/bevy?branch=release-0.14-dcl-cosmic-noimage#5cd52a4e31c9561926b98bb404db3e81db6bccc2" dependencies = [ "accesskit_winit", "approx", @@ -1813,7 +1812,7 @@ dependencies = [ "bitflags 2.6.0", "cexpr", "clang-sys", - "itertools 0.11.0", + "itertools 0.12.1", "lazy_static", "lazycell", "log", @@ -3074,7 +3073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b28bfe653d79bd16c77f659305b195b82bb5ce0c0eb2a4846b82ddbd77586813" dependencies = [ "bitflags 2.6.0", - "libloading 0.7.4", + "libloading 0.8.5", "winapi", ] @@ -3153,8 +3152,7 @@ dependencies = [ [[package]] name = "dcl-rpc" version = "2.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9dcef99269dbf4186fc0936f03cf7496f0401ffeacf3784211c065710321d8d" +source = "git+https://github.com/decentraland/rpc-rust?branch=chore/bump-tokio-tungstenite#2422cc210de8c07a3ade39347257dc3b0848ac7e" dependencies = [ "async-channel 1.9.0", "async-trait", @@ -3167,7 +3165,7 @@ dependencies = [ "prost-build 0.11.9", "quote", "tokio", - "tokio-tungstenite 0.18.0", + "tokio-tungstenite 0.24.0", "tokio-util", ] @@ -3620,7 +3618,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.7.4", + "libloading 0.8.5", ] [[package]] @@ -5053,7 +5051,7 @@ dependencies = [ "bitflags 2.6.0", "com", "libc", - "libloading 0.7.4", + "libloading 0.8.5", "thiserror", "widestring", "winapi", @@ -8282,7 +8280,7 @@ checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.11.0", + "itertools 0.12.1", "log", "multimap 0.10.0", "once_cell", @@ -8315,7 +8313,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.79", @@ -8738,9 +8736,12 @@ dependencies = [ "anyhow", "avatar", "bevy", + "bevy_console", "bevy_dui", + "clap", "common", "comms", + "console", "dcl_component", "ethers-core", "ipfs", @@ -9126,18 +9127,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustls" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" -dependencies = [ - "log", - "ring 0.16.20", - "sct", - "webpki", -] - [[package]] name = "rustls" version = "0.21.12" @@ -10642,31 +10631,31 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.18.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "native-tls", + "rustls 0.21.12", "tokio", - "tokio-native-tls", - "tungstenite 0.18.0", + "tokio-rustls 0.24.1", + "tungstenite 0.20.1", + "webpki-roots 0.25.4", ] [[package]] name = "tokio-tungstenite" -version = "0.20.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", - "rustls 0.21.12", + "native-tls", "tokio", - "tokio-rustls 0.24.1", - "tungstenite 0.20.1", - "webpki-roots 0.25.4", + "tokio-native-tls", + "tungstenite 0.24.0", ] [[package]] @@ -10998,29 +10987,9 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http 0.2.12", - "httparse", - "log", - "native-tls", - "rand", - "sha1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "tungstenite" -version = "0.19.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" dependencies = [ "byteorder", "bytes", @@ -11029,6 +10998,7 @@ dependencies = [ "httparse", "log", "rand", + "rustls 0.21.12", "sha1", "thiserror", "url", @@ -11037,21 +11007,20 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.20.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" dependencies = [ "byteorder", "bytes", "data-encoding", - "http 0.2.12", + "http 1.1.0", "httparse", "log", + "native-tls", "rand", - "rustls 0.21.12", "sha1", "thiserror", - "url", "utf-8", ] @@ -11990,7 +11959,7 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.7.4", + "libloading 0.8.5", "log", "metal", "naga", diff --git a/Cargo.toml b/Cargo.toml index 3514a3f3..b3267eb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,11 +108,12 @@ bevy_simple_text_input = { git = "https://github.com/robtfm/bevy_simple_text_inp directories = "5" uuid = { version = "1.7", features = ["v4"] } build-time = "0.1.3" -async-tungstenite = { version = "0.22.0", features = ["async-std-runtime", "async-tls"] } +async-tungstenite = { version = "0.28.0", features = ["async-std-runtime", "async-tls"] } dcl-rpc = { version = "2.3.5", default-features = false, features=["client", "websockets", "codegen", "server", "tungstenite"] } async-trait = "0.1.68" fastrand = "2" futures-util = "0.3.28" +async-tls = "0.13.0" [dependencies] analytics = { workspace = true } @@ -163,6 +164,7 @@ bevy_simple_text_input = { workspace = true } prost-build = "0.11.8" [patch.crates-io] +dcl-rpc = { git = "https://github.com/decentraland/rpc-rust", branch = "chore/bump-tokio-tungstenite" } bevy = { git = "https://github.com/robtfm/bevy", branch = "release-0.14-dcl-cosmic-noimage" } # bevy = { path="../bevy" } ffmpeg-next = { git = "https://github.com/robtfm/rust-ffmpeg", branch = "audio-linesize-0-6.1" } diff --git a/assets/images/screenshots/montage.png b/assets/images/screenshots/montage.png new file mode 100644 index 00000000..f1e107f6 Binary files /dev/null and b/assets/images/screenshots/montage.png differ diff --git a/crates/av/src/audio_source.rs b/crates/av/src/audio_source.rs index 2a9cde25..35987e15 100644 --- a/crates/av/src/audio_source.rs +++ b/crates/av/src/audio_source.rs @@ -232,11 +232,11 @@ fn play_system_audio( #[allow(clippy::too_many_arguments, clippy::type_complexity)] fn update_source_volume( - query: Query<( + mut query: Query<( Entity, Option<&SceneEntity>, Option<&AudioSource>, - &AudioEmitter, + &mut AudioEmitter, &GlobalTransform, )>, mut audio_instances: ResMut>, @@ -255,7 +255,7 @@ fn update_source_volume( let mut prev_instances = std::mem::take(&mut *all_instances); - for (ent, maybe_scene, maybe_source, emitter, transform) in query.iter() { + for (ent, maybe_scene, maybe_source, mut emitter, transform) in query.iter_mut() { if maybe_scene.map_or(true, |scene| current_scenes.contains(&scene.root)) { let (volume, panning) = if maybe_source.map_or(false, |source| source.0.global()) { ( @@ -276,14 +276,15 @@ fn update_source_volume( (volume * volume_adjust, panning) }; - for h_instance in &emitter.instances { + emitter.instances.retain_mut(|h_instance| { if let Some(instance) = audio_instances.get_mut(h_instance) { instance.set_volume(volume as f64, AudioTween::linear(Duration::ZERO)); instance.set_panning(panning as f64, AudioTween::default()); + true } else { - warn!("missing audio instance"); + false } - } + }); } else if maybe_scene.map_or(false, |scene| prev_scenes.contains(&scene.root)) { debug!("stop [{:?}]", ent); for h_instance in &emitter.instances { diff --git a/crates/common/src/profile.rs b/crates/common/src/profile.rs index 37973722..36eadb7f 100644 --- a/crates/common/src/profile.rs +++ b/crates/common/src/profile.rs @@ -95,6 +95,10 @@ impl Default for SerializedProfile { {\"slot\": 8, \"urn\": \"headexplode\" }, {\"slot\": 9, \"urn\": \"shrug\" } ], + \"snapshots\": { + \"face256\":\"\", + \"body\":\"\" + }, \"eyes\":{ \"color\":{\"r\":0.3,\"g\":0.2235294133424759,\"b\":0.99,\"a\":1} }, diff --git a/crates/comms/Cargo.toml b/crates/comms/Cargo.toml index b8be64ff..e9f598b9 100644 --- a/crates/comms/Cargo.toml +++ b/crates/comms/Cargo.toml @@ -32,8 +32,8 @@ kira = { workspace = true } async-trait = { workspace = true } async-tungstenite = { workspace = true } futures-util = { workspace = true } +async-tls = { workspace = true } -async-tls = "0.12.0" livekit = { git = "https://github.com/robtfm/client-sdk-rust", branch="0.6-h264-false-2", features=["rustls-tls-webpki-roots"], optional = true } rand = "0.8.5" multihash-codetable = { version = "0.1.1", features = ["digest", "sha2"] } diff --git a/crates/comms/src/profile.rs b/crates/comms/src/profile.rs index ad1b6a01..35f53e75 100644 --- a/crates/comms/src/profile.rs +++ b/crates/comms/src/profile.rs @@ -103,11 +103,21 @@ impl<'w, 's> ProfileManager<'w, 's> { let Some(profile) = profile else { return Ok(None); }; - let Some(path) = profile.content.avatar.snapshots.as_ref().map(|snapshots| { - let url = format!("{}{}", profile.base_url, snapshots.face256); - let ipfs_path = IpfsPath::new_from_url(&url, "png"); - PathBuf::from(&ipfs_path) - }) else { + let Some(path) = profile + .content + .avatar + .snapshots + .as_ref() + .and_then(|snapshots| { + if snapshots.face256.is_empty() { + None + } else { + let url = format!("{}{}", profile.base_url, snapshots.face256); + let ipfs_path = IpfsPath::new_from_url(&url, "png"); + Some(PathBuf::from(&ipfs_path)) + } + }) + else { return Err(ProfileMissingError); }; Ok(Some(self.ipfs.asset_server().load(path))) diff --git a/crates/comms/src/test.rs b/crates/comms/src/test.rs index 93ab21a1..15481e44 100644 --- a/crates/comms/src/test.rs +++ b/crates/comms/src/test.rs @@ -2,10 +2,7 @@ use std::{collections::HashMap, sync::Arc}; -use async_tungstenite::tungstenite::{ - client::IntoClientRequest, - http::{HeaderValue, Uri}, -}; +use async_tungstenite::tungstenite::{client::IntoClientRequest, http::HeaderValue}; #[cfg(feature = "livekit")] use livekit::{ options::TrackPublishOptions, @@ -26,6 +23,8 @@ fn test_tls() { #[cfg(feature = "livekit")] #[test] fn test_livekit() { + use isahc::http::Uri; + let mut wallet = Wallet::default(); wallet.finalize_as_guest(); diff --git a/crates/restricted_actions/Cargo.toml b/crates/restricted_actions/Cargo.toml index f92c01fc..337ae520 100644 --- a/crates/restricted_actions/Cargo.toml +++ b/crates/restricted_actions/Cargo.toml @@ -16,9 +16,11 @@ wallet = { workspace = true } dcl_component = { workspace = true } nft = { workspace = true } system_ui = { workspace = true } +console = { workspace = true } bevy = { workspace = true } bevy_dui = { workspace = true } +bevy_console = { workspace = true } tokio = { workspace = true } isahc = { workspace = true } serde_json = { workspace = true } @@ -26,3 +28,4 @@ ethers-core = { workspace = true } urlencoding = { workspace = true } opener = { workspace = true } anyhow = { workspace = true } +clap = { workspace = true } diff --git a/crates/restricted_actions/src/lib.rs b/crates/restricted_actions/src/lib.rs index 1f740af9..d08089fb 100644 --- a/crates/restricted_actions/src/lib.rs +++ b/crates/restricted_actions/src/lib.rs @@ -10,6 +10,7 @@ use bevy::{ tasks::{IoTaskPool, Task}, utils::{HashMap, HashSet}, }; +use bevy_console::{ConsoleCommand, PrintConsoleLine}; use bevy_dui::{DuiCommandsExt, DuiProps, DuiRegistry}; use common::{ profile::SerializedProfile, @@ -26,6 +27,7 @@ use comms::{ profile::{CurrentUserProfile, UserProfile}, NetworkMessage, Transport, }; +use console::DoAddConsoleCommand; use dcl_component::proto_components::kernel::comms::rfc4; use ethers_core::types::Address; use ipfs::{ipfs_path::IpfsPath, ChangeRealmEvent, EntityDefinition, IpfsAssetServer, ServerAbout}; @@ -78,10 +80,14 @@ impl Plugin for RestrictedActionsPlugin { handle_eth_async, handle_texture_size, handle_generic_perm, + handle_spawned_command, ), ) .in_set(SceneSets::RestrictedActions), ); + app.init_resource::(); + app.add_console_command::(spawn_portable_command); + app.add_console_command::(kill_portable_command); } } @@ -247,6 +253,52 @@ fn external_url( } } +async fn lookup_ens( + parent_scene: Option, + ens: String, +) -> Result<(String, PortableSource), String> { + let mut about = isahc::get_async(format!( + "https://worlds-content-server.decentraland.org/world/{ens}/about" + )) + .await + .map_err(|e| e.to_string())?; + if about.status() != StatusCode::OK { + return Err(format!("status: {}", about.status())); + } + + let about = about + .json::() + .await + .map_err(|e| e.to_string())?; + let Some(config) = about.configurations else { + return Err("No configurations on server/about".to_owned()); + }; + let Some(scenes) = config.scenes_urn else { + return Err("No scenesUrn on server/about/configurations".to_owned()); + }; + let Some(urn) = scenes.first() else { + return Err("Empty scenesUrn on server/about/configurations".to_owned()); + }; + let hacked_urn = urn.replace('?', "?=&"); + + let Ok(path) = IpfsPath::new_from_urn::(&hacked_urn) else { + return Err("failed to parse urn".to_owned()); + }; + + let Ok(Some(hash)) = path.context_free_hash() else { + return Err("failed to resolve content hash from urn".to_owned()); + }; + + Ok(( + hash, + PortableSource { + pid: hacked_urn, + parent_scene, + ens: Some(ens), + }, + )) +} + type SpawnResponseChannel = Option>>; #[allow(clippy::type_complexity, clippy::too_many_arguments)] @@ -324,49 +376,7 @@ fn spawn_portable( PortableLocation::Ens(ens) => { let ens = ens.clone(); pending_lookups.push(( - IoTaskPool::get().spawn(async move { - let mut about = isahc::get_async(format!( - "https://worlds-content-server.decentraland.org/world/{ens}/about" - )) - .await - .map_err(|e| e.to_string())?; - if about.status() != StatusCode::OK { - return Err(format!("status: {}", about.status())); - } - - let about = about - .json::() - .await - .map_err(|e| e.to_string())?; - let Some(config) = about.configurations else { - return Err("No configurations on server/about".to_owned()); - }; - let Some(scenes) = config.scenes_urn else { - return Err("No scenesUrn on server/about/configurations".to_owned()); - }; - let Some(urn) = scenes.first() else { - return Err("Empty scenesUrn on server/about/configurations".to_owned()); - }; - let hacked_urn = urn.replace('?', "?=&"); - - let Ok(path) = IpfsPath::new_from_urn::(&hacked_urn) - else { - return Err("failed to parse urn".to_owned()); - }; - - let Ok(Some(hash)) = path.context_free_hash() else { - return Err("failed to resolve content hash from urn".to_owned()); - }; - - Ok(( - hash, - PortableSource { - pid: hacked_urn, - parent_scene: Some(parent_hash), - ens: Some(ens), - }, - )) - }), + IoTaskPool::get().spawn(lookup_ens(Some(parent_hash), ens)), Some(response.take()), )); } @@ -1141,3 +1151,91 @@ pub fn handle_generic_perm( } } } + +enum PortableAction { + Spawn, + Kill, +} + +#[allow(clippy::type_complexity)] +#[derive(Resource, Default)] +struct PendingPortableCommands( + Vec<( + Task>, + PortableAction, + )>, +); + +/// manually spawn a portable +#[derive(clap::Parser, ConsoleCommand)] +#[command(name = "/spawn")] +struct SpawnPortableCommand { + ens: String, +} + +fn spawn_portable_command( + mut input: ConsoleCommand, + mut pending: ResMut, +) { + if let Some(Ok(command)) = input.take() { + pending.0.push(( + IoTaskPool::get().spawn(lookup_ens(None, command.ens)), + PortableAction::Spawn, + )); + } +} + +/// manually kill a portable +#[derive(clap::Parser, ConsoleCommand)] +#[command(name = "/kill")] +struct KillPortableCommand { + ens: String, +} + +fn kill_portable_command( + mut input: ConsoleCommand, + mut pending: ResMut, +) { + if let Some(Ok(command)) = input.take() { + pending.0.push(( + IoTaskPool::get().spawn(lookup_ens(None, command.ens)), + PortableAction::Kill, + )); + } +} + +fn handle_spawned_command( + mut pending: ResMut, + mut portables: ResMut, + mut reply: EventWriter, +) { + pending.0.retain_mut(|(task, action)| { + if let Some(result) = task.complete() { + match result { + Ok((hash, source)) => match action { + PortableAction::Spawn => { + portables.0.insert(hash.clone(), source); + reply.send(PrintConsoleLine::new("[ok]".into())); + } + PortableAction::Kill => { + if portables.0.remove(&hash).is_some() { + reply.send(PrintConsoleLine::new("[ok]".into())); + } else { + reply.send(PrintConsoleLine::new("portable not running".into())); + reply.send(PrintConsoleLine::new("[failed]".into())); + } + } + }, + Err(e) => { + reply.send(PrintConsoleLine::new( + format!("failed to lookup ens: {e}").into(), + )); + reply.send(PrintConsoleLine::new("[failed]".into())); + } + } + false + } else { + true + } + }) +} diff --git a/crates/scene_runner/src/update_scene/pointer_results.rs b/crates/scene_runner/src/update_scene/pointer_results.rs index 0339d2ee..134111e1 100644 --- a/crates/scene_runner/src/update_scene/pointer_results.rs +++ b/crates/scene_runner/src/update_scene/pointer_results.rs @@ -138,7 +138,7 @@ fn update_pointer_target( ray.origin, ray.direction.into(), f32::MAX, - ColliderLayer::ClPointer as u32 | ColliderLayer::ClPhysics as u32, + ColliderLayer::ClPointer as u32, true, ); diff --git a/crates/scene_runner/src/update_world/animation.rs b/crates/scene_runner/src/update_world/animation.rs index 56fa9e64..1fba3884 100644 --- a/crates/scene_runner/src/update_world/animation.rs +++ b/crates/scene_runner/src/update_world/animation.rs @@ -83,7 +83,10 @@ fn update_animations( .collect(), }; - let mut prev_anims: HashSet<_> = player.playing_animations().map(|(ix, _)| *ix).collect(); + let mut prev_anims: HashSet<_> = player + .playing_animations() + .filter_map(|(ix, anim)| (!anim.is_finished()).then_some(*ix)) + .collect(); for (ix, (duration, state)) in targets.into_iter() { let playing = state.playing.unwrap_or(true); diff --git a/crates/scene_runner/src/update_world/gltf_container.rs b/crates/scene_runner/src/update_world/gltf_container.rs index 8609ec52..e5f3b224 100644 --- a/crates/scene_runner/src/update_world/gltf_container.rs +++ b/crates/scene_runner/src/update_world/gltf_container.rs @@ -381,7 +381,13 @@ fn update_ready_gltfs( } let instance = loaded.0.as_ref().unwrap(); if scene_spawner.instance_is_ready(*instance) { - let gltf = gltfs.get(h_gltf).unwrap(); + let Some(gltf) = gltfs.get(h_gltf) else { + commands + .entity(bevy_scene_entity) + .try_insert(GltfProcessed::default()); + error!("gltf was unloaded mysteriously. this shouldn't happen and things will be broken as a result."); + continue; + }; // let graph = _node_graph(&_debug_query, bevy_scene_entity); // println!("{bevy_scene_entity:?}"); diff --git a/crates/scene_runner/src/update_world/material.rs b/crates/scene_runner/src/update_world/material.rs index 61cbab4a..608bb541 100644 --- a/crates/scene_runner/src/update_world/material.rs +++ b/crates/scene_runner/src/update_world/material.rs @@ -64,12 +64,10 @@ impl MaterialDefinition { .map(|b| &b.material) .unwrap_or(DEFAULT_BASE.get_or_init(|| StandardMaterial { base_color: Color::WHITE, - double_sided: true, emissive: LinearRgba::BLACK, perceptual_roughness: 0.5, metallic: 0.5, reflectance: 0.5, - cull_mode: None, ..Default::default() })); @@ -93,7 +91,6 @@ impl MaterialDefinition { ( StandardMaterial { base_color, - double_sided: true, unlit: true, alpha_mode, ..base.clone() diff --git a/crates/scene_runner/src/update_world/mesh_renderer/mod.rs b/crates/scene_runner/src/update_world/mesh_renderer/mod.rs index cd6887b7..a479cdac 100644 --- a/crates/scene_runner/src/update_world/mesh_renderer/mod.rs +++ b/crates/scene_runner/src/update_world/mesh_renderer/mod.rs @@ -90,38 +90,87 @@ impl Plugin for MeshDefinitionPlugin { mesh.generate_tangents().unwrap(); mesh }; - let _flip_uv = |mut mesh: Mesh| { - let Some(VertexAttributeValues::Float32x3(ref mut positions)) = - mesh.attribute_mut(Mesh::ATTRIBUTE_POSITION) + let cube_uvs = |mut mesh: Mesh| { + let Some(VertexAttributeValues::Float32x2(ref mut uvs)) = + mesh.attribute_mut(Mesh::ATTRIBUTE_UV_0) else { panic!() }; - for pos in positions.iter_mut() { - *pos = [pos[0], -pos[2], pos[1]]; + let mut uvs = uvs.iter_mut(); + for uv in uvs.by_ref().take(4) { + *uv = [uv[0], 1.0 - uv[1]]; } - let Some(VertexAttributeValues::Float32x3(ref mut normals)) = - mesh.attribute_mut(Mesh::ATTRIBUTE_NORMAL) + for uv in uvs.by_ref().take(4) { + *uv = [1.0 - uv[0], 1.0 - uv[1]]; + } + for uv in uvs.by_ref().take(4) { + *uv = [uv[0], 1.0 - uv[1]]; + } + for uv in uvs.by_ref().take(4) { + *uv = [1.0 - uv[0], 1.0 - uv[1]]; + } + for uv in uvs.by_ref().take(4) { + *uv = [1.0 - uv[1], uv[0]]; + } + for uv in uvs.by_ref().take(4) { + *uv = [uv[1], uv[0]]; + } + mesh + }; + let plane_uvs = |mut mesh: Mesh| { + let Some(VertexAttributeValues::Float32x2(ref mut uvs)) = + mesh.attribute_mut(Mesh::ATTRIBUTE_UV_0) + else { + panic!() + }; + uvs[0] = [0.0, 1.0]; + uvs[1] = [1.0, 1.0]; + uvs[2] = [1.0, 0.0]; + uvs[3] = [0.0, 0.0]; + uvs[4] = [0.0, 0.0]; + uvs[5] = [1.0, 0.0]; + uvs[6] = [1.0, 1.0]; + uvs[7] = [0.0, 1.0]; + mesh + }; + let yflip_uvs = |mut mesh: Mesh| { + let Some(VertexAttributeValues::Float32x2(ref mut uvs)) = + mesh.attribute_mut(Mesh::ATTRIBUTE_UV_0) else { panic!() }; - for pos in normals.iter_mut() { - *pos = [pos[0], -pos[2], pos[1]]; + for uv in uvs.iter_mut() { + uv[1] = 1.0 - uv[1]; + } + mesh + }; + let xyflip_uvs = |mut mesh: Mesh| { + let Some(VertexAttributeValues::Float32x2(ref mut uvs)) = + mesh.attribute_mut(Mesh::ATTRIBUTE_UV_0) + else { + panic!() + }; + for uv in uvs.iter_mut() { + uv[0] = 1.0 - uv[0]; + uv[1] = 1.0 - uv[1]; } mesh }; - let mut assets = app.world_mut().resource_mut::>(); - let boxx = assets.add(generate_tangents( - bevy::math::primitives::Cuboid::default().into(), - )); - let cylinder = assets.add(generate_tangents(Cylinder::default().into())); - let plane = assets.add(generate_tangents(Rectangle::default().mesh().into())); - let sphere = assets.add(generate_tangents( + let boxx = assets.add(generate_tangents(cube_uvs(Cuboid::default().into()))); + let cylinder = assets.add(generate_tangents(yflip_uvs(Cylinder::default().into()))); + let plane = assets.add(generate_tangents(plane_uvs( + Cuboid::default() + .mesh() + .build() + .scaled_by(Vec3::new(1.0, 1.0, 0.0)), + ))); + let sphere = assets.add(xyflip_uvs(generate_tangents( Sphere::new(0.5) .mesh() .uv(36, 18) .rotated_by(Quat::from_rotation_x(-FRAC_PI_2)), - )); + ))); app.insert_resource(MeshPrimitiveDefaults { boxx, plane, @@ -162,7 +211,7 @@ pub fn update_mesh( commands.entity(ent).remove::(); let handle = match prim { MeshDefinition::Box { uvs } => { - if uvs.is_empty() { + if uvs.len() != 24 { defaults.boxx.clone() } else { let mut mesh = Mesh::from(bevy::math::primitives::Cuboid::default()); @@ -171,8 +220,34 @@ pub fn update_mesh( else { panic!("uvs are not f32x2") }; - for (attr, uv) in mesh_uvs.iter_mut().zip(uvs) { - *attr = *uv + for (from, to) in [ + (0, 17), + (1, 16), + (2, 19), + (3, 18), + (4, 22), + (5, 23), + (6, 20), + (7, 21), + (8, 14), + (9, 13), + (10, 12), + (11, 15), + (12, 9), + (13, 10), + (14, 11), + (15, 8), + (16, 4), + (17, 5), + (18, 6), + (19, 7), + (20, 3), + (21, 2), + (22, 1), + (23, 0), + ] { + mesh_uvs[to][0] = uvs[from][0]; + mesh_uvs[to][1] = 1.0 - uvs[from][1]; } meshes.add(mesh) } @@ -192,21 +267,30 @@ pub fn update_mesh( } } MeshDefinition::Plane { uvs } => { - if uvs.is_empty() { + if uvs.len() != 8 { defaults.plane.clone() } else { - let mut mesh = Rectangle::default() + let mut mesh = Cuboid::default() .mesh() .build() - .rotated_by(Quat::from_rotation_z(-FRAC_PI_2)); + .scaled_by(Vec3::new(1.0, 1.0, 0.0)); let Some(VertexAttributeValues::Float32x2(mesh_uvs)) = mesh.attribute_mut(Mesh::ATTRIBUTE_UV_0) else { panic!("uvs are not f32x2") }; - for (attr, uv) in mesh_uvs.iter_mut().zip(uvs) { - attr[0] = uv[0]; - attr[1] = 1.0 - uv[1]; + for (from, to) in [ + (0, 0), + (1, 3), + (2, 2), + (3, 1), + (4, 6), + (5, 5), + (6, 4), + (7, 7), + ] { + mesh_uvs[to][0] = uvs[from][0]; + mesh_uvs[to][1] = 1.0 - uvs[from][1]; } meshes.add(mesh) } @@ -241,8 +325,6 @@ pub fn update_mesh( .unwrap_or_default(); materials.add(SceneMaterial { base: StandardMaterial { - double_sided: true, - cull_mode: None, ..Default::default() }, extension: SceneBound::new(bounds, config.graphics.oob), diff --git a/crates/scene_runner/src/update_world/scene_ui/ui_text.rs b/crates/scene_runner/src/update_world/scene_ui/ui_text.rs index 1cf1805b..db2041f8 100644 --- a/crates/scene_runner/src/update_world/scene_ui/ui_text.rs +++ b/crates/scene_runner/src/update_world/scene_ui/ui_text.rs @@ -106,7 +106,7 @@ pub fn set_ui_text( continue; }; - let text = make_text_section( + let (text, extras) = make_text_section( ui_text.text.as_str(), ui_text.font_size, ui_text @@ -207,11 +207,15 @@ pub fn set_ui_text( ..Default::default() }) .try_with_children(|c| { - c.spawn(TextBundle { + let mut cmds = c.spawn(TextBundle { text, z_index: ZIndex::Local(1), ..Default::default() }); + + if let Some(extras) = extras { + cmds.insert(extras); + } }); }); }); diff --git a/crates/scene_runner/src/update_world/text_shape.rs b/crates/scene_runner/src/update_world/text_shape.rs index 0f1f710e..1a8ed41f 100644 --- a/crates/scene_runner/src/update_world/text_shape.rs +++ b/crates/scene_runner/src/update_world/text_shape.rs @@ -90,8 +90,9 @@ bevy: not implemented use bevy::{ core::FrameCount, prelude::*, - text::{BreakLineOn, CosmicBuffer}, - utils::hashbrown::HashMap, + text::{BreakLineOn, CosmicBuffer, TextLayoutInfo}, + ui::{update::update_clipping_system, widget::text_system}, + utils::{hashbrown::HashMap, HashSet}, }; use common::{ sets::{SceneLoopSets, SceneSets}, @@ -125,6 +126,13 @@ impl Plugin for TextShapePlugin { Update, add_cosmic_buffers.after(SceneSets::RestrictedActions), ); + app.add_systems( + PostUpdate, + apply_text_extras + .after(text_system) + .after(TransformSystem::TransformPropagate) + .before(update_clipping_system), + ); } } @@ -262,7 +270,7 @@ fn update_text_shapes( }; // create ui layout - let text = make_text_section( + let (text, extras) = make_text_section( text_shape.0.text.as_str(), font_size, text_shape @@ -308,7 +316,7 @@ fn update_text_shapes( ..Default::default() }) .with_children(|c| { - c.spawn(TextBundle { + let mut cmds = c.spawn(TextBundle { text, style: Style { align_self: match halign { @@ -321,6 +329,9 @@ fn update_text_shapes( }, ..Default::default() }); + if let Some(extras) = extras { + cmds.insert(extras); + } }); if halign != JustifyText::Right { @@ -363,6 +374,229 @@ fn update_text_shapes( } } +#[derive(Component)] +pub struct TextExtraMarker; + +#[inline] +fn round_ties_up(value: f32) -> f32 { + if value.fract() != -0.5 { + value.round() + } else { + value.ceil() + } +} + +#[inline] +fn round_layout_coords(value: Vec2) -> Vec2 { + Vec2 { + x: round_ties_up(value.x), + y: round_ties_up(value.y), + } +} +fn apply_text_extras( + mut commands: Commands, + q: Query< + ( + &Text, + &TextExtras, + &CosmicBuffer, + &Parent, + &GlobalTransform, + &Node, + Option<&TargetCamera>, + Option<&Children>, + ), + Or<(Changed, Changed, Changed)>, + >, + existing: Query<(), With>, + mut removed: RemovedComponents, + children: Query<&Children>, +) { + for removed in removed.read() { + if let Ok(children) = children.get(removed) { + for child in children { + if existing.get(*child).is_ok() { + commands.entity(*child).despawn_recursive(); + } + } + } + } + + let find_bounds = |buffer: &CosmicBuffer, text: &Text, section: usize| -> Vec { + let mut segments = Vec::default(); + let preceding_text = text.sections[..section] + .iter() + .map(|s| s.value.clone()) + .collect::>() + .join(""); + let start_line = preceding_text.chars().filter(|c| *c == '\n').count(); + let start_line_index = preceding_text + .char_indices() + .rfind(|(_, c)| *c == '\n') + .map(|(ix, _)| ix) + .unwrap_or(0); + let start_section_index = preceding_text + .char_indices() + .last() + .map(|(ix, _)| ix) + .unwrap_or(0) + - start_line_index; + + let end_line = start_line + + text.sections[section] + .value + .chars() + .filter(|c| *c == '\n') + .count(); + let end_line_index = text.sections[section] + .value + .char_indices() + .last() + .map(|(ix, _)| ix) + .unwrap_or(0); + let end_section_index = text.sections[section] + .value + .char_indices() + .rfind(|(_, c)| *c == '\n') + .map(|(ix, _)| end_line_index - ix) + .unwrap_or(start_section_index + end_line_index + 1); + + let mut segment_y = f32::NEG_INFINITY; + let runs = buffer + .layout_runs() + .skip_while(|run| run.line_i < start_line) + .take_while(|run| run.line_i <= end_line); + + for run in runs { + let glyphs = run + .glyphs + .iter() + .skip_while(|g| run.line_i == start_line && g.start < start_section_index) + .take_while(|g| run.line_i < end_line || g.end <= end_section_index); + + for glyph in glyphs { + debug!("g: {},{}", glyph.x, glyph.y); + if run.line_top + glyph.y != segment_y { + segments.push(Vec4::new( + glyph.x, + run.line_top + glyph.y, + glyph.w, + run.line_height, + )); + segment_y = run.line_top + glyph.y; + } else { + let segment = segments.last_mut().unwrap(); + segment.z = glyph.x + glyph.w - segment.x; + } + } + } + + segments + }; + + for (text, extras, buffer, parent, gt, node, maybe_camera, maybe_children) in q.iter() { + for &child in maybe_children.map(|c| c.iter()).unwrap_or_default() { + if existing.get(child).is_ok() { + commands.entity(child).despawn_recursive(); + } + } + let mut ents = Vec::default(); + + let mut make_mark = |bound: Vec4, color: Color, top: f32, height: f32| -> Entity { + // because we make marks based on calculated text positions, we have to run after the ui layout functions + // but that means our marks won't be positioned until next frame. if text is deleted/replaced every frame + // then it never shows. + // so we do the layouting ourselves, copying bevy's `update_uinode_geometry_recursive`, and set the visibility explicitly. + // we have to also add the equivalent style settings, or it will be overwritten next frame. + let mut view_visibility = ViewVisibility::default(); + view_visibility.set(); + let height = (bound.w * height).max(1.0); + let size = Vec2::new(bound.z, height); + let parent_tl = gt.translation().truncate() - node.calculated_size * 0.5; + let my_tl = parent_tl + Vec2::new(bound.x, bound.y + bound.w * top); + let my_translation = round_layout_coords(my_tl + size * 0.5); + let mut cmds = commands.spawn(( + NodeBundle { + style: Style { + position_type: PositionType::Absolute, + left: Val::Px(bound.x), + top: Val::Px(bound.y + bound.w * top), + width: Val::Px(bound.z), + height: Val::Px(height), + ..Default::default() + }, + background_color: color.into(), + z_index: ZIndex::Local(1), + view_visibility, + node: Node { + stack_index: node.stack_index + 1, + calculated_size: round_layout_coords(size), + outline_width: 0.0, + outline_offset: 0.0, + unrounded_size: size, + }, + global_transform: GlobalTransform::from_translation(my_translation.extend(0.0)), + ..Default::default() + }, + TextExtraMarker, + )); + + if let Some(target_camera) = maybe_camera { + cmds.insert(target_camera.clone()); + } + + cmds.id() + }; + + for strike in extras.strike.iter() { + let bounds = find_bounds(buffer, text, *strike); + for bound in bounds { + ents.push(make_mark( + bound, + text.sections[*strike].style.color, + 0.6, + 0.1, + )); + } + } + + for under in extras.underline.iter() { + let bounds = find_bounds(buffer, text, *under); + for bound in bounds { + ents.push(make_mark( + bound, + text.sections[*under].style.color, + 0.95, + 0.1, + )); + } + } + + for (mark_section, mark_color) in extras.mark.iter() { + let bounds = find_bounds(buffer, text, *mark_section); + for bound in bounds { + ents.push(make_mark(bound, *mark_color, 0.0, 1.0)); + } + } + + commands + .entity(parent.get()) + .try_push_children(ents.as_slice()); + } +} + +#[derive(Component, Default)] +pub struct TextExtras { + strike: HashSet, + underline: HashSet, + mark: HashMap, +} + +impl TextExtras { + pub fn is_empty(&self) -> bool { + self.strike.is_empty() && self.underline.is_empty() && self.mark.is_empty() + } +} pub fn make_text_section( text: &str, font_size: f32, @@ -370,8 +604,9 @@ pub fn make_text_section( font: dcl_component::proto_components::sdk::components::common::Font, justify: JustifyText, wrapping: bool, -) -> Text { +) -> (Text, Option) { let text = text.replace("\\n", "\n"); + let mut extras = TextExtras::default(); let font_name = match font { dcl_component::proto_components::sdk::components::common::Font::FSansSerif => { @@ -386,24 +621,74 @@ pub fn make_text_section( // split by s and s let mut b_count = 0usize; let mut i_count = 0usize; - let mut b_offset = text.find(""); - let mut i_offset = text.find(""); - let mut xb_offset = text.find(""); - let mut xi_offset = text.find(""); - let mut section_start = 0; + let mut u_count = 0usize; + let mut s_count = 0usize; + let mut marks = Vec::::default(); + let mut section_start = 0usize; let mut sections = Vec::default(); loop { - let section_end = [b_offset, i_offset, xb_offset, xi_offset] - .iter() - .fold(usize::MAX, |c, o| c.min(o.unwrap_or(c))); + // read initial tags + while text[section_start..].starts_with('<') { + if let Some((close, _)) = text[section_start..] + .char_indices() + .find(|(_, c)| *c == '>') + { + let tag = text[section_start + 1..section_start + close] + .trim() + .to_ascii_lowercase(); + match tag.as_str() { + "b" => b_count += 1, + "i" => i_count += 1, + "s" => s_count += 1, + "u" => u_count += 1, + "/b" => b_count = b_count.saturating_sub(1), + "/i" => i_count = i_count.saturating_sub(1), + "/s" => s_count = s_count.saturating_sub(1), + "/u" => u_count = u_count.saturating_sub(1), + i if i.get(0..4) == Some("mark") => { + marks.push( + i.get(5..) + .and_then(|color| Srgba::hex(color).map(Color::from).ok()) + .unwrap_or_else(|| { + warn!("unrecognised mark color `{i}`"); + let mut mark_color = color; + mark_color.set_alpha(color.alpha() * 0.5); + mark_color + }), + ); + } + "/mark" => { + marks.pop(); + } + _ => warn!("unrecognised text tag `{tag}`"), + } + section_start = section_start + close + 1; + } + } + let weight = match (b_count, i_count) { (0, 0) => WeightName::Regular, (0, _) => WeightName::Italic, (_, 0) => WeightName::Bold, (_, _) => WeightName::BoldItalic, }; + if s_count > 0 { + extras.strike.insert(sections.len()); + } + if u_count > 0 { + extras.underline.insert(sections.len()); + } + if let Some(mark) = marks.last().as_ref() { + extras.mark.insert(sections.len(), **mark); + } + + let section_end = text[section_start..] + .char_indices() + .find(|(_, c)| *c == '<') + .map(|(ix, _)| section_start + ix) + .unwrap_or(usize::MAX); if section_end == usize::MAX { sections.push(TextSection::new( @@ -426,51 +711,21 @@ pub fn make_text_section( }, )); - match &text[section_end..section_end + 3] { - "" => { - b_count += 1; - b_offset = text[section_end + 1..] - .find("") - .map(|v| v + section_end + 1); - section_start = section_end + 3; - } - "" => { - i_count += 1; - i_offset = text[section_end + 1..] - .find("") - .map(|v| v + section_end + 1); - section_start = section_end + 3; - } - " { - b_count = b_count.saturating_sub(1); - xb_offset = text[section_end + 1..] - .find("") - .map(|v| v + section_end + 1); - section_start = section_end + 4; - } - " { - i_count = i_count.saturating_sub(1); - xi_offset = text[section_end + 1..] - .find("") - .map(|v| v + section_end + 1); - section_start = section_end + 4; - } - _ => { - error!("{}", &text[section_end..=section_end + 2]); - panic!() - } - } + section_start = section_end; } - Text { - sections, - linebreak_behavior: if wrapping { - BreakLineOn::WordBoundary - } else { - BreakLineOn::NoWrap + ( + Text { + sections, + linebreak_behavior: if wrapping { + BreakLineOn::WordBoundary + } else { + BreakLineOn::NoWrap + }, + justify, }, - justify, - } + (!extras.is_empty()).then_some(extras), + ) } // workaround for using bevy cosmic buffer patch without lib support diff --git a/crates/social/src/client.rs b/crates/social/src/client.rs index 33eae868..ce60b531 100644 --- a/crates/social/src/client.rs +++ b/crates/social/src/client.rs @@ -81,7 +81,7 @@ impl SocialLogin { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct DirectChatMessage { pub partner: Address, pub me_speaking: bool, @@ -362,6 +362,16 @@ fn dbgerr(e: E) -> anyhow::Error { anyhow!(format!("{e:?}")) } +#[cfg(test)] +const MATRIX_URL: &str = "https://social.decentraland.org"; // zone doesn't work +#[cfg(not(test))] +const MATRIX_URL: &str = "https://social.decentraland.org"; + +#[cfg(test)] +const SOCIAL_URL: &str = "wss://rpc-social-service.decentraland.org"; // zone doesn't work +#[cfg(not(test))] +const SOCIAL_URL: &str = "wss://rpc-social-service.decentraland.org"; + async fn social_socket_handler_inner( wallet: wallet::Wallet, mut rx: UnboundedReceiver, @@ -374,7 +384,7 @@ async fn social_socket_handler_inner( .unwrap() .clone(); let matrix_client = matrix_sdk::Client::builder() - .homeserver_url("https://social.decentraland.org") + .homeserver_url(MATRIX_URL) .build() .await?; let login = matrix_client @@ -387,11 +397,9 @@ async fn social_socket_handler_inner( // create connection let service_connection = - dcl_rpc::transports::web_sockets::tungstenite::WebSocketClient::connect( - "wss://rpc-social-service.decentraland.org", - ) - .await - .map_err(dbgerr)?; + dcl_rpc::transports::web_sockets::tungstenite::WebSocketClient::connect(SOCIAL_URL) + .await + .map_err(dbgerr)?; let service_transport = WebSocketTransport::new(service_connection); let mut service_client = RpcClient::new(service_transport).await.unwrap(); let port = service_client.create_port("whatever").await.unwrap(); @@ -751,3 +759,172 @@ async fn social_socket_handler_inner( r = f_matrix_history => r, } } + +#[cfg(test)] +mod test { + use std::{thread, time::Duration}; + + use bevy::tasks::{IoTaskPool, TaskPoolBuilder}; + use dcl_component::proto_components::social::{ + friendship_event_response::Body, AcceptResponse, DeleteResponse, RequestResponse, + }; + use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver}; + use wallet::Wallet; + + use crate::client::DirectChatMessage; + + use super::SocialClientHandler; + + fn blocking_recv_timeout( + client: &mut SocialClientHandler, + r: &mut UnboundedReceiver, + ) -> Option { + for _ in 0..10 { + client.update(); + if let Ok(data) = r.try_recv() { + return Some(data); + } + thread::sleep(Duration::from_secs(1)); + } + + return None; + } + + #[test] + fn social_test() { + IoTaskPool::get_or_init(|| TaskPoolBuilder::new().num_threads(4).build()); + + let mut wallet_a = Wallet::default(); + wallet_a.finalize_as_guest(); + let mut wallet_b = Wallet::default(); + wallet_b.finalize_as_guest(); + + let (chat_a_sx, mut chat_a) = unbounded_channel(); + let (friend_a_sx, mut friend_a) = unbounded_channel(); + + let (chat_b_sx, mut chat_b) = unbounded_channel(); + let (friend_b_sx, mut friend_b) = unbounded_channel(); + + let mut client_a = SocialClientHandler::connect( + wallet_a.clone(), + move |ev| { + friend_a_sx.send(ev.clone()).unwrap(); + }, + move |chat| { + chat_a_sx.send(chat).unwrap(); + }, + ) + .unwrap(); + let mut client_b = SocialClientHandler::connect( + wallet_b.clone(), + move |ev| { + friend_b_sx.send(ev.clone()).unwrap(); + }, + move |chat| { + chat_b_sx.send(chat).unwrap(); + }, + ) + .unwrap(); + + let mut i = 0; + while (!client_a.is_initialized || !client_b.is_initialized) && i < 10 { + println!("waiting for connection..."); + thread::sleep(Duration::from_secs(1)); + client_a.update(); + client_b.update(); + i += 1; + } + assert!(client_a.is_initialized); + assert!(client_b.is_initialized); + + client_a + .friend_request(wallet_b.address().unwrap(), None) + .unwrap(); + println!("waiting for request..."); + let Some(Body::Request(RequestResponse { + user: Some(user), .. + })) = blocking_recv_timeout(&mut client_b, &mut friend_b) + else { + panic!() + }; + assert_eq!(user.address, format!("{:#x}", wallet_a.address().unwrap())); + + client_b + .accept_request(wallet_a.address().unwrap()) + .unwrap(); + println!("waiting for accept..."); + let Some(Body::Accept(AcceptResponse { + user: Some(user), .. + })) = blocking_recv_timeout(&mut client_a, &mut friend_a) + else { + panic!() + }; + assert_eq!(user.address, format!("{:#x}", wallet_b.address().unwrap())); + + client_a + .chat(wallet_b.address().unwrap(), "Hi".to_owned()) + .unwrap(); + println!("waiting for chat a->b"); + let Some(chat) = blocking_recv_timeout(&mut client_a, &mut chat_a) else { + panic!() + }; + assert_eq!( + chat, + DirectChatMessage { + partner: wallet_b.address().unwrap(), + me_speaking: true, + message: "Hi".to_owned() + } + ); + let Some(chat) = blocking_recv_timeout(&mut client_b, &mut chat_b) else { + panic!() + }; + assert_eq!( + chat, + DirectChatMessage { + partner: wallet_a.address().unwrap(), + me_speaking: false, + message: "Hi".to_owned() + } + ); + + client_b + .chat(wallet_a.address().unwrap(), "Hello!".to_owned()) + .unwrap(); + println!("waiting for chat b->a"); + let Some(chat) = blocking_recv_timeout(&mut client_a, &mut chat_a) else { + panic!() + }; + assert_eq!( + chat, + DirectChatMessage { + partner: wallet_b.address().unwrap(), + me_speaking: false, + message: "Hello!".to_owned() + } + ); + let Some(chat) = blocking_recv_timeout(&mut client_b, &mut chat_b) else { + panic!() + }; + assert_eq!( + chat, + DirectChatMessage { + partner: wallet_a.address().unwrap(), + me_speaking: true, + message: "Hello!".to_owned() + } + ); + + client_a.delete_friend(wallet_b.address().unwrap()).unwrap(); + println!("waiting for delete"); + let Some(Body::Delete(DeleteResponse { + user: Some(user), .. + })) = blocking_recv_timeout(&mut client_b, &mut friend_b) + else { + panic!() + }; + assert_eq!(user.address, format!("{:#x}", wallet_a.address().unwrap())); + + println!("done"); + } +} diff --git a/crates/system_ui/src/chat/history.rs b/crates/system_ui/src/chat/history.rs index a7905246..8e4d9b3f 100644 --- a/crates/system_ui/src/chat/history.rs +++ b/crates/system_ui/src/chat/history.rs @@ -6,7 +6,7 @@ use common::{ structs::{ShowProfileEvent, SystemAudio}, util::{AsH160, FireEventEx}, }; -use comms::{global_crdt::ChatEvent, profile::UserProfile}; +use comms::{chat_marker_things, global_crdt::ChatEvent, profile::UserProfile}; use dcl_component::proto_components::social::friendship_event_response::{self, Body}; use social::{client::DirectChatMessage, DirectChatEvent, FriendshipEvent}; use ui_core::{ @@ -72,6 +72,13 @@ fn update_chat_history( return None; } + if chat_marker_things::ALL + .iter() + .any(|marker| ev.message.starts_with(*marker)) + { + return None; + } + let partner = if ev.sender == Entity::PLACEHOLDER { return None; } else { diff --git a/crates/user_input/src/camera.rs b/crates/user_input/src/camera.rs index 4dc8a297..a32d1fc2 100644 --- a/crates/user_input/src/camera.rs +++ b/crates/user_input/src/camera.rs @@ -309,7 +309,7 @@ pub fn update_camera_position( target_transform.translation = translation; target_transform.rotation = rotation * Quat::from_euler(EulerRot::YXZ, options.yaw, options.pitch, options.roll); - let target_fov = FRAC_PI_4 / options.distance; + let target_fov = FRAC_PI_4 * 1.25 / options.distance; let Projection::Perspective(PerspectiveProjection { ref mut fov, .. }) = &mut *projection else { panic!(); @@ -318,7 +318,7 @@ pub fn update_camera_position( *fov = target_fov; } } else { - let target_fov = (dynamic_state.velocity.length() / 4.0).clamp(1.0, 1.0) * FRAC_PI_4; + let target_fov = (dynamic_state.velocity.length() / 4.0).clamp(1.25, 1.25) * FRAC_PI_4; let Projection::Perspective(PerspectiveProjection { ref mut fov, .. }) = &mut *projection else { panic!(); diff --git a/crates/wallet/Cargo.toml b/crates/wallet/Cargo.toml index 1fee227b..87668db4 100644 --- a/crates/wallet/Cargo.toml +++ b/crates/wallet/Cargo.toml @@ -30,6 +30,6 @@ chrono = { workspace = true } async-trait = { workspace = true } async-tungstenite = { workspace = true } futures-util = { workspace = true } +async-tls = { workspace = true } -async-tls = "0.12.0" rand = "0.8.5" diff --git a/crates/world_ui/src/lib.rs b/crates/world_ui/src/lib.rs index e629d0b8..9aff0fed 100644 --- a/crates/world_ui/src/lib.rs +++ b/crates/world_ui/src/lib.rs @@ -120,8 +120,6 @@ pub fn add_worldui_materials( base_color: Color::srgb(2.0, 2.0, 2.0), base_color_texture: Some(target.clone()), unlit: true, - double_sided: true, - cull_mode: None, alpha_mode: AlphaMode::Blend, ..Default::default() }, diff --git a/readme.md b/readme.md index c550ff18..abde571e 100644 --- a/readme.md +++ b/readme.md @@ -2,6 +2,10 @@ A forward-looking implementation of the Decentraland protocol. +visit our [Releases](https://github.com/decentraland/bevy-explorer/releases/latest) page for the latest client downloads. + +![screenshots](assets/images/screenshots/montage.png) + This implementation uses [rust](https://www.rust-lang.org/) and the [Bevy](https://bevyengine.org) engine, and targets desktop clients. This project's goals are to: @@ -10,7 +14,7 @@ This project's goals are to: - increase the field of alternative Explorers - prioritize solid fundamentals, extensibility, and the use of modern open-source frameworks -# Building and Running +# Building from source 1. Clone the repo using `git clone https://github.com/decentraland/bevy-explorer` 2. Install [rust](https://www.rust-lang.org/tools/install) @@ -19,7 +23,7 @@ This project's goals are to: - *note: livekit networking (main-realm transport) in the linux build is temporarily disabled due to conflicting imports in webrtc and deno. we hope this will be resolved soon* - Install alsa and udev: `sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev` - Install ffmpeg deps: `sudo apt install -y --no-install-recommends clang curl pkg-config libavcodec-dev libavformat-dev libavutil-dev libavfilter-dev libavdevice-dev` - - (*not needed currently*) Install Livekit deps: `sudo apt update -y; sudo apt install -y libssl-dev libx11-dev libgl1-mesa-dev libxext-dev` + - Install Livekit deps: `sudo apt update -y; sudo apt install -y libssl-dev libx11-dev libgl1-mesa-dev libxext-dev` - on macos: - `brew install ffmpeg@6 pkg-config` - `export PKG_CONFIG_PATH=/opt/homebrew/opt/ffmpeg@6/lib/pkgconfig`