diff --git a/.efrocachemap b/.efrocachemap
index e0741e5d..5c14db1d 100644
--- a/.efrocachemap
+++ b/.efrocachemap
@@ -420,41 +420,41 @@
"assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/d5/f8/de3b22ac60d0caee44369117c8db",
"assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/c7/37/660e2ceca8b9b2db2cfce5a9f6f0",
"assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/d9/82/92157cb4f21fdd8c911eec910ad4",
- "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/25/20/31a26a4899e68dd9a0c6c272b998",
- "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/a5/48/9e4424d04b273c8bdc25f9be4b6e",
+ "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/d0/6f/c2718eee7a68ac8acc1b884db2b3",
+ "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/ec/97/713007418488dd543cf6edcdd9d2",
"assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/61/03/89070ca765e06da3a419a579f503",
- "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/fa/2e/fe2446e2dab7d8c7cf18a39b4b8e",
+ "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/6f/88/b74dac280d4dbd07dea74abb5fc6",
"assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/60/48/bf681053e91e38d0f4c4b1f8f1a6",
"assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/6c/2b/7a0669cc74fbcebbb76c440c6c04",
"assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/61/77/ae85d46474923707f8a7190849a2",
"assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28",
"assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/68/93/da8e9874f41a786edf52ba4ccaad",
- "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/11/26/c3dfae5a52f337529c4ea129237c",
+ "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/c0/03/106450033fe01fba06d733b6b107",
"assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/4c/c7/0184b8178869d1a3827a1bfcd5bb",
- "assets/build/ba_data/data/languages/filipino.json": "https://files.ballistica.net/cache/ba1/ac/ec/2677e8fd26c395a5032d7d6e7aa1",
- "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/b6/e0/37dd30b686f475733ccc4b3cab49",
- "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/c0/26/04875251b9237f3133c84a910afd",
- "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/45/5c/abf0567aaea410b43783453eba5f",
+ "assets/build/ba_data/data/languages/filipino.json": "https://files.ballistica.net/cache/ba1/10/45/197ea6179209f0aa440fe5366a95",
+ "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/b1/71/34760e818883dfec12b9dde3deab",
+ "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/7e/9c/11e9717282006b4cd8cfc02f0764",
+ "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/23/b6/8f7175147d8a6d5de45c2147e294",
"assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/82/eb/37ff44af76812097f9c98f05c730",
"assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/08/3b/68cea4d16f7020d932829af85323",
- "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/b0/48/e1ebe08bfdfc94fcb61a16b851e5",
- "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/75/70/e33e6ee95830052e8f36cd2135f7",
- "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/f3/11/d81cc9f0c76b81b0b8dcf64fe292",
+ "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/d8/f2/aa16bc336bd7660cc86c3264bfc4",
+ "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/df/28/0c30263bcb49720889730e5d20b9",
+ "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/e6/fd/0d1e560035538035c882852045f9",
"assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/07/37/ab65ccee3a555bd40e9661860c58",
- "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/37/90/0350db0bd1e98215fde8ee3f4059",
+ "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/bf/71/11141b8a8c92604da47c7c575034",
"assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/76/be/84e567de0aabd9f9145b62179c2c",
"assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/a6/ad/7ee52772db14f9008044bb877ed1",
"assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/d7/06/9d70642d0a4d1e3b1c2149d7a17c",
- "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/6c/46/292406974d45fd9a92e40022b443",
+ "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/8d/8a/dc288451eb6a1120a5868d64b771",
"assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/4e/91/6f2a9a3ce733908e91377a6ddb9a",
"assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/f9/4b/d9f01814224066856695452ef57c",
- "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/80/d7/bd62eacc2ec901e145e37168c737",
+ "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/e7/cb/69267e2a863a12e9ce90ab3ba209",
"assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/91/0a/35c4baf539d5951fc03a794c0e0b",
- "assets/build/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/55/46/61fa6c9a93f6c0d57529d7949190",
+ "assets/build/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/41/a4/841ab82927c41a6bc8fc9ae5ea11",
"assets/build/ba_data/data/languages/thai.json": "https://files.ballistica.net/cache/ba1/9d/51/f699dbd4beb88bc3cff699a287a7",
"assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/c0/4e/c8a66ed415b8b0ce3ff30462b2a2",
"assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/7f/bb/6239adeb551be5e09f3457d7b411",
- "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/68/77/cc871b6ed611cb8d6f74cf1a9d00",
+ "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/7c/98/c0f7c965a3ac36d86cc17f55428f",
"assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/f2/af/afd1503c7a10cacaa15bc02369b2",
"assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed",
"assets/build/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/03/4b/57ee9b42854b26f23f81bd8c58ef",
@@ -3995,50 +3995,50 @@
"assets/src/ba_data/python/ba/_generated/__init__.py": "https://files.ballistica.net/cache/ba1/ee/e8/cad05aa531c7faf7ff7b96db7f6e",
"assets/src/ba_data/python/ba/_generated/enums.py": "https://files.ballistica.net/cache/ba1/b2/e5/0ee0561e16257a32830645239f34",
"ballisticacore-windows/Generic/BallisticaCore.ico": "https://files.ballistica.net/cache/ba1/89/c0/e32c7d2a35dc9aef57cc73b0911a",
- "build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2f/ec/756d728d0a912a0a0ce1e46b3351",
- "build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/2e/d8/41fb2f73f9b915e809a3d8671c45",
- "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/51/a9/931e229fed568facc7d77b407a9a",
- "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9c/f3/aef423feb4f5e91ce72fb5a25fa0",
- "build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/cd/c2/f5f0a7ae3197fe5f05bfcee3a3e3",
- "build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4f/dc/2a1a296dddd5d5fef6b2f0bef6e8",
- "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c6/4c/e1274ac12ae7a0a60d02686abc0b",
- "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6c/b1/f56d3edb7c6efa23518b78b74846",
- "build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/87/b2/0a85ffc1ed64724da5663086a2a9",
- "build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/bc/95/67636889721c129a697a55fc47c2",
- "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/59/8f/0bfe1878a0941351294b2306b2ad",
- "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/de/43/bfab4d3fda82d02e97207f5be4cd",
- "build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/39/d0/6bb26d2fce1d6f8644191217c00c",
- "build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/80/33/fc11bdaba571fc91429518881081",
- "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/be/9d/9e39fc8085e1061d016e9ea242a6",
- "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8a/aa/fef783198a65c064b1c8be235307",
- "build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/87/4b/06fca73ff1a1c22f92f462c8e539",
- "build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/97/32/95378dfe465d38aa3bbebb932669",
- "build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/e3/af/8e86cf496985267f69a98613eb15",
- "build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/3a/4a/2860a58d8b460ca6ff8243a0f185",
- "build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c3/a5/d77c0da95027f6c6b2158d554692",
- "build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/92/93/d343eb8e8783494d8d04949fcd34",
- "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/65/26/c623cadc48e151bf438579730e33",
- "build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/cc/32/eb7bd9b981c303d59ec32efc46b7",
- "build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7a/9a/43e14da4b3ec46f69fd710d4daba",
- "build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a4/c1/e4548f2abcba4c48e713dd24e2fd",
- "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/69/79/8e676bba0b03ed522c2475bb07b4",
- "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/69/97/6119b7a2dd5c1f3fbcb2d921652d",
- "build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/73/53/98ea7844b411cbc99a347213410f",
- "build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/74/78/9b5b9048e0fcb3f6283983046cd8",
- "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7a/1a/503e5789b08c3a85bb34bebccdf8",
- "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/04/cf/a70ffac469d5bbc2ba9d56ebffcb",
- "build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6f/e6/66090d68d391eba428a6b5d146e5",
- "build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/2f/4c/d59f4dd0c41e1cb3f32f3864e8cc",
- "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/16/9c/bda065fbb75646796383ff4c0490",
- "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8c/56/b6f1a19cda20dada065f0f43cd83",
- "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/f4/76/36e047c715c69980bf53f47cc03b",
- "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/83/03/e08562ec65eba9577c9fbe1a98b0",
- "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/26/08/755cd4f6d908359e0a7d33a5f9dd",
- "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/bd/d7/0de5664c35680f40a9c8efbc264b",
- "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/e9/65/0693588e1b04bff51d197c77e6c6",
- "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/bd/b1/866126ff56ab9c6148b750282295",
- "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/ef/47/19efea33fdbd69c376f35b590e3b",
- "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/5b/e6/174649077bcc202ead74e7e5bf4d",
+ "build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a4/c9/4b7f9effbe8c100648900eaa3261",
+ "build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/00/9b/eaa284f779a3de4213b79cd92107",
+ "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/42/55/3cb41badd1d45910283e0b64df88",
+ "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/95/ff/5c57780407fcb6b7feb0764706df",
+ "build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/40/839b1117d4f93b054eb85cb1b0d5",
+ "build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/bc/15/56d8be246fe39a106db0439833b3",
+ "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a9/05/27ca686143f14394c1b8837d7cb2",
+ "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a5/86/afe3eee3898e9c9fb189f3b77e85",
+ "build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ff/95/de9839cdfec8f326131aa05384c3",
+ "build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e2/26/17c4ae54581e4b5c0330b0719224",
+ "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a4/4c/b89ec4327945297f4d72f9d80d94",
+ "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4c/c6/55b8ba4e0b5c8975712fa0fd1767",
+ "build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/0b/8b/05d548a8a72955c0cb386d9d60b3",
+ "build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/60/27/721444bbebc52a864d8a04b2208c",
+ "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e2/f2/25cff5d0e4f918a9f6d57dfa5285",
+ "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/da/82/ec893df8e6ee94feed9ddb759e6e",
+ "build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/46/6c/eb3d14ac4a6c363962a8066e39e5",
+ "build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/54/b4/4f9767d0cea37f328844507e8ea7",
+ "build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/ff/b6/401674aa0a886de14f437947b728",
+ "build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/2d/6d/5f1c3004f2bf9258162379e26054",
+ "build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/05/99/3cadc83ce9288f9352a3a4a5559c",
+ "build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7a/c2/1c132470c13fc8af1f5d94dfbf6c",
+ "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/98/a6/42ee7341d4a75c5d58f80d2f4dbc",
+ "build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3a/b9/f01ad696e634735773da5f841407",
+ "build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/06/8d/27bfcaedab349160f55ce618384e",
+ "build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e3/74/6c47384a303b68378a80e6d00bac",
+ "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3c/2c/7eb58e0a6678fe13271ec4e1689f",
+ "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ce/a4/37f7da427da665e42b23689ee2b1",
+ "build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/aa/d3/c1f6f9b2487397ff3b8deacdfb88",
+ "build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a0/d1/065efb021ade658501fe3ccbd238",
+ "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7c/6e/116acc4f5c4d51608f56a74a1a35",
+ "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a3/59/9765f24b69af3382eb1ba72a175e",
+ "build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/23/e7/978c348d104ad002d3cc0cef17e9",
+ "build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d1/27/1635e8fd16e9e21e673f5cba7eb3",
+ "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fa/f1/9f93bc6fa9bbdc6547414528b22c",
+ "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4d/a7/b764b6fc1ac50a426e8fec3238df",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/91/d3/9689394fc2464ae3b0be6fb662ca",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/15/2c/29c2e9c783211c5184dc012a7e2a",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/30/84/1b5e42cc51d43c7c0ad256a5d0b8",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/5e/9c/726f930f02dece54d7f1e9be1565",
+ "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/c5/9b/fab63617403f92c0eb3af53c5ceb",
+ "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/92/b1/79f2c94d070fa8d5a279f67429c8",
+ "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/ab/72/2f6f56a9a47658b1b8ffbdd323ca",
+ "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/a7/82/3943a555db1dc3e2ca1ac281248b",
"src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/7d/3e/229a581cb2454ed856f1d8b564a7",
"src/ballistica/generated/python_embedded/bootstrap.inc": "https://files.ballistica.net/cache/ba1/d3/db/e73d4dcf1280d5f677c3cf8b47c3"
}
\ No newline at end of file
diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml
index 3f27d8c7..11355958 100644
--- a/.idea/dictionaries/ericf.xml
+++ b/.idea/dictionaries/ericf.xml
@@ -119,7 +119,9 @@
argstr
argtypes
argval
+ armcap
armeabi
+ armv
arraymodule
asdict
aspx
@@ -599,6 +601,7 @@
dhave
dheadless
dictval
+ didn
diemessages
difflib
dilateerode
@@ -996,6 +999,7 @@
genutils
getaccountid
getactivity
+ getauxval
getcampaign
getclass
getcollide
@@ -2262,6 +2266,7 @@
showsubseconds
shroom
shutil
+ sigsetjmp
simplesubclasses
simpletype
sincelaunch
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7f6e99de..5f12be64 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,9 @@
-### 1.7.5 (20650, 2022-07-14)
+### 1.7.5 (20653, 2022-07-15)
- Android build now uses the ReLinker library to load the native main.so, which will (hopefully) avoid some random load failures on older Android versions.
- Android Google Play build now prints a message at launch if the billing library isn't available or needs to be updated (explaining why purchases won't work in that case).
- Various minor bug fixes (mostly cleaning up unnecessary error logging)
- Updated Android builds to use the new NDK 25 release
+- Added a warning when trying to play a tournament with a workspace active
### 1.7.4 (20646, 2022-07-12)
- Fixed the trophies list showing an incorrect total (Thanks itsre3!)
diff --git a/assets/src/ba_data/python/._ba_sources_hash b/assets/src/ba_data/python/._ba_sources_hash
index 2db1cbda..a2b13ee8 100644
--- a/assets/src/ba_data/python/._ba_sources_hash
+++ b/assets/src/ba_data/python/._ba_sources_hash
@@ -1 +1 @@
-45709261760262192915304287648158055425
\ No newline at end of file
+105185559858403296763219852162674470262
\ No newline at end of file
diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py
index d8cf5bdc..6e72b9f2 100644
--- a/assets/src/ba_data/python/_ba.py
+++ b/assets/src/ba_data/python/_ba.py
@@ -2102,15 +2102,6 @@ def has_gamma_control() -> bool:
return bool()
-def has_user_mods() -> bool:
- """(internal)
-
- Returns whether the system varies from default configuration
- (by user mods, etc)
- """
- return bool()
-
-
def has_user_run_commands() -> bool:
"""(internal)"""
return bool()
@@ -3225,3 +3216,12 @@ def widget(edit: ba.Widget | None = None,
Unlike other UI calls, this can only be used to edit, not to create.
"""
return None
+
+
+def workspaces_in_use() -> bool:
+ """(internal)
+
+ Returns whether workspaces functionality has been enabled at
+ any point this run.
+ """
+ return bool()
diff --git a/assets/src/ba_data/python/ba/_apputils.py b/assets/src/ba_data/python/ba/_apputils.py
index de13b820..7196e646 100644
--- a/assets/src/ba_data/python/ba/_apputils.py
+++ b/assets/src/ba_data/python/ba/_apputils.py
@@ -82,7 +82,7 @@ def handle_log() -> None:
'fatal': 0,
'userRanCommands': _ba.has_user_run_commands(),
'time': _ba.time(TimeType.REAL),
- 'userModded': _ba.has_user_mods(),
+ 'userModded': _ba.workspaces_in_use(),
'newsShow': _ba.get_news_show(),
}
diff --git a/assets/src/ba_data/python/ba/_playlist.py b/assets/src/ba_data/python/ba/_playlist.py
index b6e36046..f99aabe4 100644
--- a/assets/src/ba_data/python/ba/_playlist.py
+++ b/assets/src/ba_data/python/ba/_playlist.py
@@ -139,7 +139,8 @@ def filter_playlist(playlist: PlaylistType,
entry['settings'][setting.name] = setting.default
goodlist.append(entry)
except ImportError as exc:
- print(f'Import failed while scanning playlist: {exc}')
+ _ba.log(f'Import failed while scanning playlist: {exc}',
+ to_server=False)
except Exception:
from ba import _error
_error.print_exception()
diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py
index 84d0ccfe..2aed369c 100644
--- a/assets/src/ba_data/python/bastd/ui/coop/browser.py
+++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py
@@ -941,6 +941,13 @@ class CoopBrowserWindow(ba.Window):
show_sign_in_prompt()
return
+ if _ba.workspaces_in_use():
+ ba.screenmessage(
+ ba.Lstr(resource='tournamentsDisabledWorkspaceText'),
+ color=(1, 0, 0))
+ ba.playsound(ba.getsound('error'))
+ return
+
if not self._tourney_data_up_to_date:
ba.screenmessage(ba.Lstr(resource='tournamentCheckingStateText'),
color=(1, 1, 0))
diff --git a/ballisticacore-cmake/.idea/dictionaries/ericf.xml b/ballisticacore-cmake/.idea/dictionaries/ericf.xml
index f710b4b1..d5924657 100644
--- a/ballisticacore-cmake/.idea/dictionaries/ericf.xml
+++ b/ballisticacore-cmake/.idea/dictionaries/ericf.xml
@@ -67,6 +67,8 @@
appstate
argsjoined
argstr
+ armcap
+ armv
asci
assetsmakefile
assigninput
@@ -320,6 +322,7 @@
dfff
dfmt
dictval
+ didn
diffbit
dinl
dirfilter
@@ -502,6 +505,7 @@
getactivity
getattro
getattrofunc
+ getauxval
getbasetime
getbit
getbits
@@ -1162,6 +1166,7 @@
shouldnt
shufflable
signsubscale
+ sigsetjmp
simd
simpletype
sisssssssss
diff --git a/src/ballistica/app/app_globals.h b/src/ballistica/app/app_globals.h
index dc4cddb3..dd577abe 100644
--- a/src/ballistica/app/app_globals.h
+++ b/src/ballistica/app/app_globals.h
@@ -35,7 +35,7 @@ class AppGlobals {
std::unordered_map node_types_by_id;
std::unordered_map node_message_types;
std::vector node_message_formats;
- bool have_mods{};
+ bool workspaces_in_use{};
bool replay_open{};
std::vector pausable_threads;
TouchInput* touch_input{};
diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc
index 71c9a798..b8446a2a 100644
--- a/src/ballistica/ballistica.cc
+++ b/src/ballistica/ballistica.cc
@@ -21,7 +21,7 @@
namespace ballistica {
// These are set automatically via script; don't modify them here.
-const int kAppBuildNumber = 20650;
+const int kAppBuildNumber = 20653;
const char* kAppVersion = "1.7.5";
// Our standalone globals.
diff --git a/src/ballistica/networking/network_reader.cc b/src/ballistica/networking/network_reader.cc
index 7779a58c..14334ee5 100644
--- a/src/ballistica/networking/network_reader.cc
+++ b/src/ballistica/networking/network_reader.cc
@@ -235,9 +235,30 @@ auto NetworkReader::RunThread() -> int {
fd_set readset;
FD_ZERO(&readset);
if (sd4_ != -1) {
+ if (!g_buildconfig.ostype_windows()) {
+ // Try to get a clean error instead of a crash if we exceed our
+ // open file descriptor limit (except on windows where FD_SETSIZE
+ // is apparently a dummy value).
+ if (sd4_ < 0 || sd4_ >= FD_SETSIZE) {
+ FatalError("Socket/File Descriptor Overflow (sd4="
+ + std::to_string(sd4_) + ", FD_SETSIZE="
+ + std::to_string(FD_SETSIZE) + "). Please report this.");
+ }
+ }
+
FD_SET(sd4_, &readset); // NOLINT
}
if (sd6_ != -1) {
+ if (!g_buildconfig.ostype_windows()) {
+ // Try to get a clean error instead of a crash if we exceed our
+ // open file descriptor limit (except on windows where FD_SETSIZE
+ // is apparently a dummy value).
+ if (sd6_ < 0 || sd6_ >= FD_SETSIZE) {
+ FatalError("Socket/File Descriptor Overflow (sd6="
+ + std::to_string(sd6_) + ", FD_SETSIZE="
+ + std::to_string(FD_SETSIZE) + "). Please report this.");
+ }
+ }
FD_SET(sd6_, &readset); // NOLINT
}
int maxfd = std::max(sd4_, sd6_);
@@ -408,9 +429,9 @@ auto NetworkReader::RunThread() -> int {
PlayerSpec::GetAccountPlayerSpec().GetSpecString();
// This should always be the case (len needs to be 1 byte)
- assert(player_spec_string.size() < 256);
+ BA_PRECONDITION_FATAL(player_spec_string.size() < 256);
- assert(!usid.empty());
+ BA_PRECONDITION_FATAL(!usid.empty());
if (usid.size() > 100) {
Log("had to truncate session-id; shouldn't happen");
usid.resize(100);
@@ -431,9 +452,10 @@ auto NetworkReader::RunThread() -> int {
player_spec_string.size());
size_t msg_len =
11 + player_spec_string.size() + usid.size();
+ BA_PRECONDITION_FATAL(msg_len <= sizeof(msg));
std::vector msg_buffer(msg_len);
- memcpy(&msg_buffer[0], msg, msg_len);
+ memcpy(msg_buffer.data(), msg, msg_len);
g_network_write_module->PushSendToCall(msg_buffer,
SockAddr(from));
diff --git a/src/ballistica/python/methods/python_methods_system.cc b/src/ballistica/python/methods/python_methods_system.cc
index e039c57d..be4c7beb 100644
--- a/src/ballistica/python/methods/python_methods_system.cc
+++ b/src/ballistica/python/methods/python_methods_system.cc
@@ -196,7 +196,7 @@ auto PyExtraHashValue(PyObject* self, PyObject* args, PyObject* keywds)
return nullptr;
}
const char* h =
- ((g_app_globals->user_ran_commands || g_app_globals->have_mods)
+ ((g_app_globals->user_ran_commands || g_app_globals->workspaces_in_use)
? "cjief3l"
: "wofocj8");
return PyUnicode_FromString(h);
@@ -221,10 +221,10 @@ auto PyHasUserRunCommands(PyObject* self, PyObject* args) -> PyObject* {
BA_PYTHON_CATCH;
}
-auto PyHasUserMods(PyObject* self, PyObject* args) -> PyObject* {
+auto PyWorkspacesInUse(PyObject* self, PyObject* args) -> PyObject* {
BA_PYTHON_TRY;
- Platform::SetLastPyCall("has_user_mods");
- if (g_app_globals->have_mods) {
+ Platform::SetLastPyCall("workspaces_in_use");
+ if (g_app_globals->workspaces_in_use) {
Py_RETURN_TRUE;
}
Py_RETURN_FALSE;
@@ -1045,13 +1045,13 @@ auto PythonMethodsSystem::GetMethods() -> std::vector {
"\n"
"(internal)"},
- {"has_user_mods", PyHasUserMods, METH_VARARGS,
- "has_user_mods() -> bool\n"
+ {"workspaces_in_use", PyWorkspacesInUse, METH_VARARGS,
+ "workspaces_in_use() -> bool\n"
"\n"
"(internal)\n"
"\n"
- "Returns whether the system varies from default configuration\n"
- "(by user mods, etc)"},
+ "Returns whether workspaces functionality has been enabled at\n"
+ "any point this run."},
{"has_user_run_commands", PyHasUserRunCommands, METH_VARARGS,
"has_user_run_commands() -> bool\n"
diff --git a/tools/bacloud b/tools/bacloud
index 85edb1a1..39de9443 100755
--- a/tools/bacloud
+++ b/tools/bacloud
@@ -255,6 +255,7 @@ class App:
def _handle_open_url(self, url: str) -> None:
import webbrowser
+ print(f'{Clr.CYN}(url: {url}){Clr.RST}')
webbrowser.open(url)
def _handle_input_prompt(self, prompt: str, as_password: bool) -> None:
diff --git a/tools/efrotools/pybuild.py b/tools/efrotools/pybuild.py
index 27387c47..499a452d 100644
--- a/tools/efrotools/pybuild.py
+++ b/tools/efrotools/pybuild.py
@@ -264,6 +264,31 @@ def android_patch_ssl() -> None:
)
writefile(fname, txt)
+ # Getting a lot of crashes in _armv7_tick, which seems to be a
+ # somewhat known issue with certain arm7 devices. Sounds like
+ # there are no major downsides to disabling this feature, so doing that.
+ # (Sounds like its possible to somehow disable it through an env var
+ # but let's just be sure and #ifdef it out in the source.
+ # see https://github.com/openssl/openssl/issues/17465
+ fname = 'crypto/armcap.c'
+ txt = readfile(fname)
+ txt = replace_exact(
+ txt,
+ ' /* Things that getauxval didn\'t tell us */\n'
+ ' if (sigsetjmp(ill_jmp, 1) == 0) {\n'
+ ' _armv7_tick();\n'
+ ' OPENSSL_armcap_P |= ARMV7_TICK;\n'
+ ' }\n',
+ '# if 0 // ericf disabled; causing crashes on some android devices.\n'
+ ' /* Things that getauxval didn\'t tell us */\n'
+ ' if (sigsetjmp(ill_jmp, 1) == 0) {\n'
+ ' _armv7_tick();\n'
+ ' OPENSSL_armcap_P |= ARMV7_TICK;\n'
+ ' }\n'
+ '# endif // 0\n',
+ )
+ writefile(fname, txt)
+
def _patch_py_ssl() -> None:
@@ -276,6 +301,10 @@ def _patch_py_ssl() -> None:
# Python folks, but for now am just patching it for our Python builds.
# NOTE TO SELF: It would also be good to look into why that call can be
# so slow and if there's anything we can do about that.
+ # UPDATE: This should be fixed in Python itself as of 3.10.6
+ # (see https://github.com/python/cpython/issues/94637)
+ # UPDATE 2: Have confirmed that call is expected to be slow in some
+ # situations.
fname = 'Modules/_ssl.c'
txt = readfile(fname)
txt = replace_exact(