diff --git a/.efrocachemap b/.efrocachemap
index 8b2276a2..c72004d0 100644
--- a/.efrocachemap
+++ b/.efrocachemap
@@ -420,8 +420,8 @@
"assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/51/eb/0a567253cc08c94c5d315a64d9af",
"assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/bc/8f/a9c51a09c418136e386b7fdf21c7",
"assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/02/e5/84916e123f47ccf11ddda380d699",
- "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/d6/7e/598e11bd8dfc90de5edb9151cfc8",
- "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/68/6d/7a251c216dda7550ca871871e2d1",
+ "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/f4/ee/ee34ed3985e810bd795c7979ec95",
+ "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/0f/e1/94378b32c786d5365a7810a15d73",
"assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/55/8c/8d0a0585e434b94865ae4befc090",
"assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/fc/a4/813e4ef8c4204d8616aa68a80891",
"assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/ff/7c/3bcab4ae1f39977434acb0d6f795",
@@ -429,31 +429,32 @@
"assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/19/c5/2b1ae9e2b622892ff8c0beaad25b",
"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/97/90/39ba65c2ad714429aec82ea1ae3e",
- "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/d6/9d/4c4f878cc2ea5a6ecfca48a6ea02",
+ "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/5a/63/382c2cd707cd34d232f28f45f5d3",
"assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/4c/c7/0184b8178869d1a3827a1bfcd5bb",
- "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/94/66/31892eb13c227d10562b1af3e0ac",
- "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/f2/5a/c68991b1c36c9341bc2dac73269d",
- "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/de/57/e732c7bb0b70fe90bcb8529f6f0b",
+ "assets/build/ba_data/data/languages/filipino.json": "https://files.ballistica.net/cache/ba1/b3/3b/65ec8c4100bf9170b85ad9b23164",
+ "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/f7/15/08a411143de698f715c69551cea3",
+ "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/83/a3/01a5ba0d128630afd31ecb518f82",
+ "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/03/6a/4db89c5bf1ced8eb5a5615a4ae64",
"assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/01/ea/cd9dac4a24a5c92495c37cd98371",
- "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/40/d7/84b6bc5eaef05145af3bef5e5e1c",
+ "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/c2/f5/e7549f5179c22c6da97fafffc058",
"assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/2d/e5/3737c6c3979cf381321c5472bea5",
"assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/b1/81/d99fb5b8c368430944b357aa15fe",
- "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/cc/5d/94c4004b798e74922830280bc8bc",
- "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/7f/57/fd4b9a63be0207ba2ad49e19253c",
+ "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/d7/f0/436072225f713259eaa5fa39ba5d",
+ "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/d7/8b/acdfb39196be7856f8bad77eb6a0",
"assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/f1/49/a7a94c6a662f65de4d8e9d5303f4",
"assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/04/fa/b24dd48bfbf3c2d67ee5ad1269c3",
- "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/d5/f0/b5015710dfdc0e48f3e0a9d75332",
+ "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/83/e8/26ccc434b55b79a343cfe8cfaa7d",
"assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/82/12/57bf144e12be229a9b70da9c45cb",
"assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/97/38/c8ae1079059dd6b6579c89802ed8",
- "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/38/d6/376433fa66f1798c64035efc1371",
+ "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e6/59/af13a5d296da5935699bec902ed7",
"assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/9f/a6/a2c9d7f3f90a2320aa45ccfd65cd",
"assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/6d/25/745fec991d43eadfbde149d897bf",
"assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0",
- "assets/build/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/6a/ab/e5321ab73beb56d58948bbee6f0d",
+ "assets/build/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/3c/cf/89114640ffa253721583c0d2699b",
"assets/build/ba_data/data/languages/thai.json": "https://files.ballistica.net/cache/ba1/74/3d/c3d40a1e5ee1edf82555da05eda9",
"assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/e8/0b/6825043ce101a831732eb9c97e4f",
"assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/87/20/259904441097b886b841d7c4d09a",
- "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/ff/a7/d74151ee6fa1d228cafb52e52f04",
+ "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/35/31/47dbbc1e3a581565681d4a0c0361",
"assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/0b/24/3cc2b5a6ebe4bca1e01b40f8ed09",
"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",
@@ -3966,50 +3967,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/79/7f/b35e110c2414ed3e9c2a63a5edb8",
+ "build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/fa/12a0c294c686015a09b4e483fb5a",
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/74/1d/fc9e33e565475daaac80da5252f0",
- "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c9/9d/8cf082284a49571f791b90d9106b",
- "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2a/7d/e5fc72327db6442b8eff92084a86",
- "build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/9d/d0/27123ab8460edbe2b81e2fbe26f4",
+ "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/12/3f/6bb33262268ec504c42889599d03",
+ "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/db/53/ea4f6e7fae365e12c005a8d8a207",
+ "build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/17/95/1b4b9f735830a3e4569ff38bcaf3",
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9c/7b/ac1a200be0f37078af0991faca3b",
- "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f6/f3/097b3f57775872ce2cb1a5056a1f",
- "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b0/8d/3950a671608e034d98873d296d79",
- "build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3e/d7/98b17fd0a2c9fbe165e3305545c8",
- "build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e8/14/16e4569e8ba8d81add5185d093d5",
- "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/03/11/be7f105d7fa6481ee733fa27e395",
- "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4e/ca/37f1978ef5964519797bc7c86c85",
- "build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ae/27/2159c832c5cfbb0bd6377d53c51a",
- "build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/68/ca/02d14e37337c724d9e81c2c07042",
- "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/13/ea/5dbca074d091cb18ba66d69396f5",
- "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4a/2d/3eb7994b464507b25d402c911981",
- "build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d3/63/cfc5b59bcca871bc90cbca08d135",
- "build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7c/6f/1d4b4b019d85acc2bbe22ac61f66",
- "build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/57/7e/bbc31eed5601c189ea3b45c5aa30",
- "build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/85/02/03b08c4bd892da2f364e747cbc7d",
- "build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d5/9e/9ba956c3fab76d0d078abfa1da58",
- "build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/94/5c/d2328912be397d0c47c94de88600",
- "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c6/b4/d2bcc9d5e3ed7c6e0ebf952c7e8c",
- "build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0d/fb/4e30bf2f94a1d7952033c95751dc",
- "build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/52/24/1317c155820a39aa1f8e6355f30a",
- "build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/59/e0/d31d41a094422aa0e76aa0720016",
- "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5d/e5/9c6d67f911ee6bbf83e6be8471f9",
- "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/94/bb/8e22dfe10d8caf5c69705bdeee5c",
- "build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1d/a1/1eae4803fdc5817b339639484050",
- "build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7c/6b/51ccdd8d9b1543a4ecbec5d86283",
- "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/bb/78/8b75f03d6dbc1f8a52b6f474d805",
- "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/37/51/31e9201bcdc1c7ee64629b03651f",
- "build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/db/7a/2e01ec9f3b9bb73344664ee77531",
- "build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/60/10/6076b395d00cba9af31a23f23088",
- "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/62/db/263a5fd8732b884cefb225eb0152",
- "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3f/69/4a6b0e32ccad4a175c3ce81965d6",
- "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/8a/ad/a1d95af5a8a0fc7432b7d18424ce",
- "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/64/0f/417d7d670cb537a2c33c34413ab0",
- "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/8f/7f/2a543aedbeda4415c7d6a133446c",
- "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/2c/29/9881e42f274b27a2267e0fcbf2c4",
- "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/a9/14/628cfc0a73eb6bd115c12b910e16",
- "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/9f/d5/a133e0b5f1b7ee494b6e848164fe",
- "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/8a/85/a3b4ca183c808225b08562e2ad32",
- "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/01/28/06fe724ed0a007ddc4806e4cfee2",
+ "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bc/05/865ee1d03b3bc560e2fb723767f5",
+ "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8d/1c/6e9568248f1314a7b1d4cb4c39ca",
+ "build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/12/31/a9be39151d99a41505ca048e9629",
+ "build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d3/58/e2b9debb00c8fde97dc38963af0a",
+ "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/62/3c/cc07faff46fc8a19efc08c0d3c10",
+ "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d8/aa/72c60fcf1848c6f4c744390317d3",
+ "build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/73/75/101c990503a9ba965331040d9bf7",
+ "build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d2/b6/01a84b2ccc5056d6479a3da492d4",
+ "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9b/57/86fdcd4b5646d76ef6c0b433eead",
+ "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6d/ef/4689aedf79f95b27fb584baff536",
+ "build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c3/43/f1d740ee7581d08b7bc47e4a1e3c",
+ "build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/29/2c/d67cc5a3c2af08cedc9f81cc6b31",
+ "build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/ae/c7/499833108f4a230e576b1d2686f0",
+ "build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/91/c9/44e47eb68aa3f16bd73f23abda1d",
+ "build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d7/9c/d585f497c36b22f6872b4d8b0d14",
+ "build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/53/cd/7bcdeb377a33413266fcbc066b13",
+ "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5c/5b/15c498b609f447f346cd2f004915",
+ "build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/62/d4/e6bbb3e7730c9f5a4519c3a94f06",
+ "build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ae/2d/6e509a3a27127d365dc9af83ab2b",
+ "build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/36/18/b81804ac8d0384fc72f0367371a1",
+ "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e1/64/fcd5e883cd2c979be76e9e9f7987",
+ "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c7/6b/8326914b322f281c5ab03c6ced51",
+ "build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0e/07/ae4fffc008f05352690c16ea144f",
+ "build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/66/f3/6268d6d28f9412ea65f5fa134749",
+ "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/59/a3/37af52a4d954b5e13bd690ccbf8c",
+ "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/88/1e/24ca02cbce792d64c008affbb8b2",
+ "build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ba/a8/a8c6e992194a6d8f012ed89b80eb",
+ "build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c4/0c/8469d0febecd1ef898627fb088c7",
+ "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1f/b5/540e02a79ac1bae8b4ff74ae73e4",
+ "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a7/91/f4bc68c09b30b207bf66e62da00a",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/d1/c3/ffd69def77c4564ccb86025bc77b",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/7e/4b/eed633dcb3da435ee44fc917f3bf",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/30/1d/4cd247b5626fccbf9cb4cca8c6f3",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/26/1c/07cd64a03263f572dfdd25438b00",
+ "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/20/bf/182851b81a0a14d49cec25d7ed6d",
+ "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/fe/ff/703deeb403ee68a4414f60e97309",
+ "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/10/b3/19c3d5559ba7e9e877c2f2a51334",
+ "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/de/d5/851bca0dd2b7b608eb477075d3d0",
"src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/c5/18/29d9fe8e483ce222d3263336f7e6",
"src/ballistica/generated/python_embedded/bootstrap.inc": "https://files.ballistica.net/cache/ba1/65/ac/d5c4162a71028c1bfa73ebc1f881"
}
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 720ecf12..f1addad6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -45,7 +45,7 @@ jobs:
# significantly between windows and linux/apple. We also are able to
# build our windows binary.
check_and_compile_windows:
- runs-on: windows-latest
+ runs-on: windows-2019
steps:
- uses: actions/checkout@v1
- name: Set up Python
diff --git a/.gitignore b/.gitignore
index cbdcc1a5..3355e9a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -122,6 +122,7 @@ xcuserdata/
# Generated sources
/src/ballistica/generated
/assets/src/ba_data/python/ba/_generated
+/src/meta/bametainternal/generated
# Dynamically generated resource files
/ballisticacore-android/BallisticaCore/src/cardboard/res/drawable-*/vr_icon.png
diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml
index b820759c..83c39a0c 100644
--- a/.idea/dictionaries/ericf.xml
+++ b/.idea/dictionaries/ericf.xml
@@ -129,6 +129,7 @@
assetpackputmanifest
assetpackputupload
assetpath
+ assetsmakefile
assettype
assettypestr
assigninput
@@ -192,6 +193,9 @@
baseval
basew
basn
+ basnmessagereceiver
+ basnmessagesender
+ basntoclient
bastd
batools
batoolsinternal
@@ -381,6 +385,7 @@
cleanupchecks
clientid
clientlist
+ clienttobasn
clionbin
clioncode
clionroot
@@ -472,6 +477,7 @@
cpus
cpython
crashlytics
+ createtime
creationflags
creditslist
cresult
@@ -723,6 +729,7 @@
excludepowerups
excludetypes
excstr
+ exec'ed
execcode
execing
execlocals
@@ -917,6 +924,7 @@
gbytecount
gearvr
genchangelog
+ gencmd
gendocs
gendummymodule
genericpath
@@ -1103,6 +1111,7 @@
infilename
infilepath
infos
+ infoset
infotextcolor
infotxt
inidividual
@@ -1928,6 +1937,7 @@
redist
redistributables
regtp
+ reimported
relpath
remainingchecks
remoteapp
@@ -2174,6 +2184,7 @@
srcdir
srcfolder
srcjson
+ srcname
srcnode
srcpath
srcpathfull
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7b237610..1fa6460b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,8 @@
-### 1.6.7 (20435)
+### 1.6.8 (20444)
+- Added Filipino language (Thanks David!)
+- Restored pre-v1.5 jump behaviour.
+
+### 1.6.7 (20436)
- Fixed a vulnerability which could expose device-account uuids.
- Now generating Linux Arm64 server and test builds (currently built against Ubuntu 20).
- Mac test builds are now Universal binaries (Arm64 & x86-64 versions bundled together).
diff --git a/Makefile b/Makefile
index 3326bdc5..f637b7ab 100644
--- a/Makefile
+++ b/Makefile
@@ -40,7 +40,7 @@ help:
PREREQS = .cache/checkenv $(PREREQ_IRONY) .dir-locals.el \
.mypy.ini .pycheckers .pylintrc .style.yapf .clang-format \
- ballisticacore-cmake/.clang-format .projectile .editorconfig
+ ballisticacore-cmake/.clang-format .editorconfig
# Target that should be built before running most any other build.
# This installs tool config files, runs environment checks, etc.
diff --git a/assets/.asset_manifest_private.json b/assets/.asset_manifest_private.json
index 6ce51979..dcf73da1 100644
--- a/assets/.asset_manifest_private.json
+++ b/assets/.asset_manifest_private.json
@@ -431,6 +431,7 @@
"ba_data/data/languages/dutch.json",
"ba_data/data/languages/english.json",
"ba_data/data/languages/esperanto.json",
+ "ba_data/data/languages/filipino.json",
"ba_data/data/languages/french.json",
"ba_data/data/languages/german.json",
"ba_data/data/languages/gibberish.json",
diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json
index 6431ecdd..d2309e47 100644
--- a/assets/.asset_manifest_public.json
+++ b/assets/.asset_manifest_public.json
@@ -134,9 +134,11 @@
"ba_data/python/bacommon/__init__.py",
"ba_data/python/bacommon/__pycache__/__init__.cpython-39.opt-1.pyc",
"ba_data/python/bacommon/__pycache__/assets.cpython-39.opt-1.pyc",
+ "ba_data/python/bacommon/__pycache__/build.cpython-39.opt-1.pyc",
"ba_data/python/bacommon/__pycache__/net.cpython-39.opt-1.pyc",
"ba_data/python/bacommon/__pycache__/servermanager.cpython-39.opt-1.pyc",
"ba_data/python/bacommon/assets.py",
+ "ba_data/python/bacommon/build.py",
"ba_data/python/bacommon/net.py",
"ba_data/python/bacommon/servermanager.py",
"ba_data/python/bastd/__init__.py",
diff --git a/assets/Makefile b/assets/Makefile
index 1129328a..5b0786b7 100644
--- a/assets/Makefile
+++ b/assets/Makefile
@@ -128,6 +128,7 @@ $1: $$(subst /__pycache__,,$$(subst .cpython-39.opt-1.pyc,.py,$1))
$$(TOOLS_DIR)/pcommand compile_python_files $$^ && chmod 444 $$@
endef
+# This section is generated by batools.assetsmakefile; do not edit by hand.
# __AUTOGENERATED_PUBLIC_BEGIN__
SCRIPT_TARGETS_PY_PUBLIC = \
@@ -641,6 +642,7 @@ $(eval $(call make-opt-pyc-target,$(element))))
SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \
build/ba_data/python/bacommon/__init__.py \
build/ba_data/python/bacommon/assets.py \
+ build/ba_data/python/bacommon/build.py \
build/ba_data/python/bacommon/net.py \
build/ba_data/python/bacommon/servermanager.py \
build/ba_data/python/efro/__init__.py \
@@ -660,6 +662,7 @@ SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \
SCRIPT_TARGETS_PYC_PUBLIC_TOOLS = \
build/ba_data/python/bacommon/__pycache__/__init__.cpython-39.opt-1.pyc \
build/ba_data/python/bacommon/__pycache__/assets.cpython-39.opt-1.pyc \
+ build/ba_data/python/bacommon/__pycache__/build.cpython-39.opt-1.pyc \
build/ba_data/python/bacommon/__pycache__/net.cpython-39.opt-1.pyc \
build/ba_data/python/bacommon/__pycache__/servermanager.cpython-39.opt-1.pyc \
build/ba_data/python/efro/__pycache__/__init__.cpython-39.opt-1.pyc \
@@ -691,6 +694,7 @@ $(foreach element,$(SCRIPT_TARGETS_PYC_PUBLIC_TOOLS),\
$(eval $(call make-opt-pyc-target,$(element))))
# __AUTOGENERATED_PUBLIC_END__
+# This section is generated by batools.assetsmakefile; do not edit by hand.
# __AUTOGENERATED_PRIVATE_BEGIN__
SCRIPT_TARGETS_PY_PRIVATE_APPLE = \
@@ -4793,6 +4797,7 @@ DATA_TARGETS = \
build/ba_data/data/languages/dutch.json \
build/ba_data/data/languages/english.json \
build/ba_data/data/languages/esperanto.json \
+ build/ba_data/data/languages/filipino.json \
build/ba_data/data/languages/french.json \
build/ba_data/data/languages/german.json \
build/ba_data/data/languages/gibberish.json \
diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py
index 27b3597d..d9bd3383 100644
--- a/assets/src/ba_data/python/ba/_app.py
+++ b/assets/src/ba_data/python/ba/_app.py
@@ -346,27 +346,6 @@ class App:
for key in ('lc14173', 'lc14292'):
cfg.setdefault(key, launch_count)
- # Debugging - make note if we're using the local test server so we
- # don't accidentally leave it on in a release.
- # FIXME - should move these sort of warnings to the C++ layer.
- server_addr = _ba.get_master_server_address()
- if 'localhost' in server_addr:
- _ba.timer(2.0,
- lambda: _ba.screenmessage(
- 'Note: using local server',
- (1, 1, 0),
- log=True,
- ),
- timetype=TimeType.REAL)
- elif 'test' in server_addr:
- _ba.timer(2.0,
- lambda: _ba.screenmessage(
- 'Note: using test server-module',
- (1, 1, 0),
- log=True,
- ),
- timetype=TimeType.REAL)
-
cfg['launchCount'] = launch_count
cfg.commit()
diff --git a/assets/src/ba_data/python/ba/_language.py b/assets/src/ba_data/python/ba/_language.py
index 5709b6e2..6bf49f3e 100644
--- a/assets/src/ba_data/python/ba/_language.py
+++ b/assets/src/ba_data/python/ba/_language.py
@@ -87,6 +87,7 @@ class LanguageSubsystem:
'vec': 'Venetian',
'hi': 'Hindi',
'ta': 'Tamil',
+ 'fil': 'Filipino',
}
# Special case for Chinese: map specific variations to traditional.
diff --git a/assets/src/ba_data/python/bastd/actor/spaz.py b/assets/src/ba_data/python/bastd/actor/spaz.py
index 8209e4da..37ab09e9 100644
--- a/assets/src/ba_data/python/bastd/actor/spaz.py
+++ b/assets/src/ba_data/python/bastd/actor/spaz.py
@@ -199,6 +199,7 @@ class Spaz(ba.Actor):
self.equip_boxing_gloves()
self.last_punch_time_ms = -9999
self.last_pickup_time_ms = -9999
+ self.last_jump_time_ms = -9999
self.last_run_time_ms = -9999
self._last_run_value = 0.0
self.last_bomb_time_ms = -9999
@@ -363,7 +364,11 @@ class Spaz(ba.Actor):
"""
if not self.node:
return
- self.node.jump_pressed = True
+ t_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
+ assert isinstance(t_ms, int)
+ if t_ms - self.last_jump_time_ms >= self._jump_cooldown:
+ self.node.jump_pressed = True
+ self.last_jump_time_ms = t_ms
self._turbo_filter_add_press('jump')
def on_jump_release(self) -> None:
diff --git a/assets/src/ba_data/python/bastd/gameutils.py b/assets/src/ba_data/python/bastd/gameutils.py
index 01a913f6..89d7ed4d 100644
--- a/assets/src/ba_data/python/bastd/gameutils.py
+++ b/assets/src/ba_data/python/bastd/gameutils.py
@@ -26,7 +26,7 @@ class SharedObjects:
def __init__(self) -> None:
activity = ba.getactivity()
- if hasattr(activity, self._STORENAME):
+ if self._STORENAME in activity.customdata:
raise RuntimeError('Use SharedObjects.get() to fetch the'
' shared instance for this activity.')
self._object_material: Optional[ba.Material] = None
diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py
index e7f2db68..86818e21 100644
--- a/assets/src/ba_data/python/bastd/mainmenu.py
+++ b/assets/src/ba_data/python/bastd/mainmenu.py
@@ -60,7 +60,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]):
'scale': scale,
'position': (0, 10),
'vr_depth': -10,
- 'text': '\xa9 2011-2021 Eric Froemling'
+ 'text': '\xa9 2011-2022 Eric Froemling'
}))
# Throw up some text that only clients can see so they know that the
diff --git a/ballisticacore-cmake/.idea/dictionaries/ericf.xml b/ballisticacore-cmake/.idea/dictionaries/ericf.xml
index ba5b65d9..2d8c997b 100644
--- a/ballisticacore-cmake/.idea/dictionaries/ericf.xml
+++ b/ballisticacore-cmake/.idea/dictionaries/ericf.xml
@@ -60,6 +60,7 @@
appstate
argsjoined
asci
+ assetsmakefile
assigninput
atest
athome
@@ -86,6 +87,9 @@
basetype
basicsize
basn
+ basnmessagereceiver
+ basnmessagesender
+ basntoclient
bastd
batoolsinternal
bbbb
@@ -192,6 +196,7 @@
cleanupcheck
clientid
clientinfo
+ clienttobasn
clipcount
cmath
cmds
@@ -219,6 +224,7 @@
cpuid
crashenv
crashlytics
+ createtime
cresult
crom
crosswire
@@ -342,6 +348,7 @@
ewwwww
exargs
exctype
+ exec'ed
execinfo
execing
exhash
@@ -428,6 +435,7 @@
gcc's
gearvr
genchangelog
+ gencmd
getactivity
getattro
getattrofunc
@@ -519,6 +527,7 @@
incentivized
indata
inet
+ infoset
infotxt
inides
initguid
@@ -921,6 +930,7 @@
refl
regtp
rehel
+ reimported
reloadmedia
rendererdata
renormalize
@@ -1030,6 +1040,7 @@
spivak
srcattr
srcfolder
+ srcname
srcpath
srcsz
sresult
diff --git a/config/toolconfigsrc/dir-locals.el b/config/toolconfigsrc/dir-locals.el
index 2ff903f0..2f645a4b 100644
--- a/config/toolconfigsrc/dir-locals.el
+++ b/config/toolconfigsrc/dir-locals.el
@@ -7,4 +7,10 @@
"--sys-path" "__EFRO_PROJECT_ROOT__/assets/src/ba_data/python")))
;; Shorter name in projectile status bar to save valuable space.
(nil . ((projectile-project-name . "__EFRO_PROJECT_SHORTNAME__")))
+
+ ;; Projectile indexing and search will ignore the following
+ ;; (in addition to git-ignored stuff which it ignores by default)
+ (nil . ((projectile-globally-ignored-directories . ("docs"
+ "src/external"))))
+
)
diff --git a/config/toolconfigsrc/projectile b/config/toolconfigsrc/projectile
deleted file mode 100644
index e7af40de..00000000
--- a/config/toolconfigsrc/projectile
+++ /dev/null
@@ -1,2 +0,0 @@
-+/tools
-+/assets/src/ba_data/python
diff --git a/docs/ba_module.md b/docs/ba_module.md
index f5036fd3..9ad4462e 100644
--- a/docs/ba_module.md
+++ b/docs/ba_module.md
@@ -1,5 +1,5 @@
-
last updated on 2022-02-01 for Ballistica version 1.6.7 build 20436
+last updated for Ballistica version 1.6.8 build 20446
This page documents the Python classes and functions in the 'ba' module,
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please let me know. Happy modding!
diff --git a/resources/Makefile b/resources/Makefile
index 39b4411b..a93c1761 100644
--- a/resources/Makefile
+++ b/resources/Makefile
@@ -2,12 +2,12 @@
all: resources
-# This section is autogenerated; do not edit by hand.
+# This section is generated by batools.resourcesmakefile; do not edit by hand.
# __AUTOGENERATED_PUBLIC_BEGIN__
# __AUTOGENERATED_PUBLIC_END__
-# This section is autogenerated; do not edit by hand.
+# This section is generated by batools.resourcesmakefile; do not edit by hand.
# __AUTOGENERATED_PRIVATE_BEGIN__
resources: \
diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc
index 6a089a83..92afd09f 100644
--- a/src/ballistica/ballistica.cc
+++ b/src/ballistica/ballistica.cc
@@ -21,8 +21,8 @@
namespace ballistica {
// These are set automatically via script; don't modify them here.
-const int kAppBuildNumber = 20436;
-const char* kAppVersion = "1.6.7";
+const int kAppBuildNumber = 20446;
+const char* kAppVersion = "1.6.8";
// Our standalone globals.
// These are separated out for easy access.
diff --git a/src/meta/Makefile b/src/meta/Makefile
index 7336a97c..c5ac8a4e 100644
--- a/src/meta/Makefile
+++ b/src/meta/Makefile
@@ -8,7 +8,7 @@ clean:
rm -rf ../ballistica/generated ../../assets/src/ba_data/python/ba/_generated
-# This section is autogenerated; do not edit by hand.
+# This section is generated by batools.metamakefile; do not edit by hand.
# __AUTOGENERATED_PUBLIC_BEGIN__
sources: \
@@ -31,13 +31,13 @@ sources: \
# __AUTOGENERATED_PUBLIC_END__
-# This section is autogenerated; do not edit by hand.
+# This section is generated by batools.metamakefile; do not edit by hand.
# __AUTOGENERATED_PRIVATE_BEGIN__
# Note: we include our public targets in efrocache even
# though they are buildable in public. This allows us to
-# fetch them on Windows to bootstrap binary CI builds in
-# cases where we can't use our full Makefiles.
+# fetch them to bootstrap binary builds in cases where
+# we can't use our full Makefiles (like Windows CI).
efrocache-list:
@echo "../../assets/src/ba_data/python/ba/_generated/__init__.py" \
diff --git a/src/meta/bameta/__init__.py b/src/meta/bameta/__init__.py
index 583b42dd..b39b3d0d 100644
--- a/src/meta/bameta/__init__.py
+++ b/src/meta/bameta/__init__.py
@@ -1,7 +1,3 @@
# Released under the MIT License. See LICENSE for details.
#
-"""Build/tool functionality specific to the Ballistica project.
-
-This stuff can be a bit more sloppy/loosey-goosey since it is not used by the
-game itself.
-"""
+"""Meta source files."""
diff --git a/src/meta/bameta/python_embedded/__init__.py b/src/meta/bameta/python_embedded/__init__.py
new file mode 100644
index 00000000..5463acf0
--- /dev/null
+++ b/src/meta/bameta/python_embedded/__init__.py
@@ -0,0 +1,3 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Sources used to embed code in the c++ layer."""
diff --git a/tools/bacommon/build.py b/tools/bacommon/build.py
new file mode 100644
index 00000000..44ce4897
--- /dev/null
+++ b/tools/bacommon/build.py
@@ -0,0 +1,33 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Functionality related to game builds."""
+
+from __future__ import annotations
+
+import datetime
+from dataclasses import dataclass, field
+from typing import TYPE_CHECKING, Annotated
+
+from efro.dataclassio import ioprepped, IOAttrs
+
+if TYPE_CHECKING:
+ pass
+
+
+@ioprepped
+@dataclass
+class BuildInfoSet:
+ """Set of build infos."""
+
+ @dataclass
+ class Entry:
+ """Info about a particular build."""
+ filename: Annotated[str, IOAttrs('fname')]
+ size: Annotated[int, IOAttrs('size')]
+ version: Annotated[str, IOAttrs('version')]
+ build_number: Annotated[int, IOAttrs('build')]
+ checksum: Annotated[str, IOAttrs('checksum')]
+ createtime: Annotated[datetime.datetime, IOAttrs('createtime')]
+
+ builds: Annotated[list[Entry],
+ IOAttrs('builds')] = field(default_factory=list)
diff --git a/tools/batools/build.py b/tools/batools/build.py
index f6c5df0a..8158c662 100644
--- a/tools/batools/build.py
+++ b/tools/batools/build.py
@@ -137,6 +137,7 @@ def _lazybuild_check_paths(inpaths: list[str], category: SourceCategory,
# Ignore python cache files.
if '__pycache__' in root:
continue
+
for fname in fnames:
# Ignore dot files
if fname.startswith('.'):
@@ -441,7 +442,10 @@ def gen_fulltest_buildfile_apple() -> None:
extras = [e for e in extras if e.startswith('mac.')]
for extra in extras:
if extra == 'mac.package':
- lines.append('make mac-package')
+ # FIXME; Currently skipping notarization because it requires us
+ # to be logged in via the gui to succeed.
+ lines.append('BA_MAC_DISK_IMAGE_SKIP_NOTARIZATION=1'
+ ' make mac-package')
elif extra == 'mac.package.server.x86_64':
lines.append('make mac-server-package-x86-64')
elif extra == 'mac.package.server.arm64':
diff --git a/tools/batools/metamakefile.py b/tools/batools/metamakefile.py
index 7a7c240d..26366ba4 100755
--- a/tools/batools/metamakefile.py
+++ b/tools/batools/metamakefile.py
@@ -45,9 +45,8 @@ class Target:
return out
-def _emit_group_build_lines(targets: list[Target], basename: str) -> list[str]:
- """Gen a group build target."""
- del basename # Unused.
+def _emit_sources_lines(targets: list[Target]) -> list[str]:
+ """Gen lines to build provided targets."""
out: list[str] = []
if not targets:
return out
@@ -59,8 +58,8 @@ def _emit_group_build_lines(targets: list[Target], basename: str) -> list[str]:
return out
-def _emit_group_efrocache_lines(targets: list[Target]) -> list[str]:
- """Gen a group clean target."""
+def _emit_efrocache_lines(targets: list[Target]) -> list[str]:
+ """Gen lines to cache provided targets."""
out: list[str] = []
if not targets:
return out
@@ -93,11 +92,11 @@ def _add_enums_module_target(targets: list[Target]) -> None:
))
-def _add_init_module_target(targets: list[Target]) -> None:
+def _add_init_module_target(targets: list[Target], moduledir: str) -> None:
targets.append(
Target(
src=[os.path.join(TOOLS_DIR, 'batools', 'pcommand.py')],
- dst=os.path.join(OUT_DIR_PYTHON, '__init__.py'),
+ dst=os.path.join(moduledir, '__init__.py'),
cmd='$(PCOMMAND) gen_python_init_module $@',
))
@@ -136,15 +135,52 @@ def _add_python_embedded_targets_internal(targets: list[Target]) -> None:
or 'flycheck' in fname):
continue
name = os.path.splitext(fname)[0]
- src = [
- f'{pkg}/python_embedded/{name}.py',
- os.path.join(TOOLS_DIR, 'batoolsinternal', 'meta.py')
- ]
- dst = os.path.join(OUT_DIR_CPP, 'python_embedded', f'{name}.inc')
targets.append(
- Target(src=src,
- dst=dst,
- cmd='$(PCOMMAND) gen_encrypted_python_code $< $@'))
+ Target(
+ src=[
+ f'{pkg}/python_embedded/{name}.py',
+ os.path.join(TOOLS_DIR, 'batoolsinternal', 'meta.py')
+ ],
+ dst=os.path.join(OUT_DIR_CPP, 'python_embedded',
+ f'{name}.inc'),
+ cmd='$(PCOMMAND) gen_encrypted_python_code $< $@',
+ ))
+
+
+def _add_extra_targets_internal(targets: list[Target]) -> None:
+
+ # Add targets to generate message sender/receiver classes for
+ # our basn/client protocols. Their outputs go to 'generated' so they
+ # don't get added to git.
+ _add_init_module_target(targets, moduledir='bametainternal/generated')
+ for srcname, dstname, gencmd in [
+ ('clienttobasn', 'basnmessagesender', 'gen_basn_msg_sender'),
+ ('basntoclient', 'basnmessagereceiver', 'gen_basn_msg_receiver'),
+ ]:
+ targets.append(
+ Target(
+ src=[
+ f'bametainternal/python_embedded/{srcname}.py',
+ os.path.join(TOOLS_DIR, 'batoolsinternal', 'meta.py')
+ ],
+ dst=f'bametainternal/generated/{dstname}.py',
+ cmd=f'$(PCOMMAND) {gencmd} $@',
+ ))
+
+ # Now add explicit targets to generate embedded code for the resulting
+ # classes. We can't simply place them in a scanned dir like
+ # python_embedded because they might not exist yet at update time.
+ for name in ['basnmessagesender', 'basnmessagereceiver']:
+ targets.append(
+ Target(
+ src=[
+ f'bametainternal/generated/{name}.py',
+ os.path.join(TOOLS_DIR, 'batoolsinternal', 'meta.py')
+ ],
+ dst=os.path.join(OUT_DIR_CPP, 'python_embedded',
+ f'{name}.inc'),
+ cmd='$(PCOMMAND) gen_encrypted_python_code $< $@',
+ ))
def _empty_line_if(condition: bool) -> list[str]:
@@ -199,12 +235,11 @@ def update(projroot: str, check: bool) -> None:
# Public targets (full sources available in public)
targets: list[Target] = []
pubtargets = targets
- basename = 'public'
_add_python_embedded_targets(targets)
- _add_init_module_target(targets)
+ _add_init_module_target(targets, moduledir=OUT_DIR_PYTHON)
_add_enums_module_target(targets)
our_lines_public = (_empty_line_if(bool(targets)) +
- _emit_group_build_lines(targets, basename) +
+ _emit_sources_lines(targets) +
[t.emit() for t in targets])
all_dsts_public.update(t.dst for t in targets)
@@ -215,25 +250,23 @@ def update(projroot: str, check: bool) -> None:
else:
# Private targets (available in public through efrocache)
targets = []
- basename = 'private'
our_lines_private_1 = (
- _empty_line_if(bool(targets)) +
- _emit_group_build_lines(targets, basename) +
+ _empty_line_if(bool(targets)) + _emit_sources_lines(targets) +
['# __EFROCACHE_TARGET__\n' + t.emit() for t in targets] + [
'\n# Note: we include our public targets in efrocache even\n'
'# though they are buildable in public. This allows us to\n'
- '# fetch them on Windows to bootstrap binary CI builds in\n'
- '# cases where we can\'t use our full Makefiles.\n'
- ] + _emit_group_efrocache_lines(pubtargets + targets))
+ '# fetch them to bootstrap binary builds in cases where\n'
+ '# we can\'t use our full Makefiles (like Windows CI).\n'
+ ] + _emit_efrocache_lines(pubtargets + targets))
all_dsts_private.update(t.dst for t in targets)
# Private-internal targets (not available at all in public)
targets = []
- basename = 'private-internal'
_add_python_embedded_targets_internal(targets)
+ _add_extra_targets_internal(targets)
our_lines_private_2 = (['# __PUBSYNC_STRIP_BEGIN__'] +
_empty_line_if(bool(targets)) +
- _emit_group_build_lines(targets, basename) +
+ _emit_sources_lines(targets) +
[t.emit() for t in targets] +
['# __PUBSYNC_STRIP_END__'])
our_lines_private = our_lines_private_1 + our_lines_private_2
diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py
index 74e2ccd1..9f7bc20b 100644
--- a/tools/batools/pcommand.py
+++ b/tools/batools/pcommand.py
@@ -982,3 +982,9 @@ def update_dummy_module() -> None:
update(projroot=str(PROJROOT),
check='--check' in sys.argv,
force='--force' in sys.argv)
+
+
+def version() -> None:
+ """Check app versions."""
+ from batools.version import run
+ run(projroot=str(PROJROOT), args=sys.argv[2:])
diff --git a/tools/batools/project.py b/tools/batools/project.py
index 7352e45e..5c8967e6 100755
--- a/tools/batools/project.py
+++ b/tools/batools/project.py
@@ -32,7 +32,7 @@ def project_centric_path(projroot: str, path: str) -> str:
def get_legal_notice_private() -> str:
"""Return the one line legal notice we expect private files to have."""
- return 'Copyright (c) 2011-2021 Eric Froemling'
+ return 'Copyright (c) 2011-2022 Eric Froemling'
@dataclass
@@ -376,6 +376,9 @@ class Updater:
and 'THIS FILE IS AUTOGENERATED' in lines[copyrightline + 1]):
copyrightline += 2
+ if lines[copyrightline].startswith('# Synced from '):
+ copyrightline += 3
+
# In all cases, look for our one-line legal notice.
# In the public case, look for the rest of our public license too.
if self._license_line_checks:
diff --git a/tools/batools/version.py b/tools/batools/version.py
new file mode 100755
index 00000000..eadfcb28
--- /dev/null
+++ b/tools/batools/version.py
@@ -0,0 +1,73 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Util to get ballisticacore versions."""
+
+from __future__ import annotations
+
+import os
+import sys
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from typing import Sequence
+
+
+def _handle_args(args: list[str]) -> str:
+ """parse os args and return a mode"""
+ mode = None
+ if len(args) == 0:
+ print('OPTIONS: info, build, version')
+ sys.exit(0)
+ elif len(args) == 1:
+ if args[0] == 'info':
+ mode = 'info'
+ if args[0] == 'build':
+ mode = 'build'
+ if args[0] == 'version':
+ mode = 'version'
+ if mode is None:
+ raise Exception('invalid args')
+ return mode
+
+
+def get_current_version() -> tuple[str, int]:
+ """Pull current version and build_number from the project."""
+ version = None
+ build_number = None
+ with open('src/ballistica/ballistica.cc', encoding='utf-8') as infile:
+ lines = infile.readlines()
+ for line in lines:
+ if line.startswith('const char* kAppVersion = "'):
+ if version is not None:
+ raise Exception('found multiple version lines')
+ version = line[27:-3]
+ if line.startswith('const int kAppBuildNumber = '):
+ if build_number is not None:
+ raise Exception('found multiple build number lines')
+ build_number = int(line[28:-2])
+ if version is None:
+ raise Exception('version not found')
+ if build_number is None:
+ raise Exception('build number not found')
+ return version, build_number
+
+
+def run(projroot: str, args: list[str]) -> None:
+ """Main entry point for this script."""
+
+ mode = _handle_args(args)
+
+ # We want to run from the root dir.
+ os.chdir(projroot)
+
+ version, build_number = get_current_version()
+
+ if mode == 'info':
+ print('version = ' + version)
+ print('build = ' + str(build_number))
+ elif mode == 'version':
+ print(version)
+ elif mode == 'build':
+ print(build_number)
+ else:
+ raise Exception('invalid mode: ' + str(mode))
diff --git a/tools/efro/dataclassio/_prep.py b/tools/efro/dataclassio/_prep.py
index eec61c57..aaf348df 100644
--- a/tools/efro/dataclassio/_prep.py
+++ b/tools/efro/dataclassio/_prep.py
@@ -35,7 +35,7 @@ PREP_ATTR = '_DCIOPREP'
PREP_SESSION_ATTR = '_DCIOPREPSESSION'
-def ioprep(cls: type) -> None:
+def ioprep(cls: type, globalns: dict = None) -> None:
"""Prep a dataclass type for use with this module's functionality.
Prepping ensures that all types contained in a data class as well as
@@ -49,10 +49,14 @@ def ioprep(cls: type) -> None:
Prepping a dataclass involves evaluating its type annotations, which,
as of PEP 563, are stored simply as strings. This evaluation is done
- in the module namespace containing the class, so all referenced types
- must be defined at that level.
+ with localns set to the class dict (so that types defined in the class
+ can be used) and globalns set to the containing module's class.
+ It is possible to override globalns for special cases such as when
+ prepping happens as part of an exec'ed string instead of within a
+ module.
"""
- PrepSession(explicit=True).prep_dataclass(cls, recursion_level=0)
+ PrepSession(explicit=True,
+ globalns=globalns).prep_dataclass(cls, recursion_level=0)
def ioprepped(cls: type[T]) -> type[T]:
@@ -108,8 +112,9 @@ class PrepData:
class PrepSession:
"""Context for a prep."""
- def __init__(self, explicit: bool):
+ def __init__(self, explicit: bool, globalns: Optional[dict] = None):
self.explicit = explicit
+ self.globalns = globalns
def prep_dataclass(self, cls: type,
recursion_level: int) -> Optional[PrepData]:
@@ -164,6 +169,7 @@ class PrepSession:
# which allows us to pick up nested classes, etc.
resolved_annotations = get_type_hints(cls,
localns=vars(cls),
+ globalns=self.globalns,
include_extras=True)
# pylint: enable=unexpected-keyword-arg
except Exception as exc:
diff --git a/tools/efrotools/message.py b/tools/efrotools/message.py
index 6ea37489..cc8c8e22 100644
--- a/tools/efrotools/message.py
+++ b/tools/efrotools/message.py
@@ -15,12 +15,12 @@ if TYPE_CHECKING:
def standard_message_sender_gen_pcommand(
- projroot: Path,
- basename: str,
- source_module: str,
- enable_sync_sends: bool,
- enable_async_sends: bool,
-) -> None:
+ projroot: Path,
+ basename: str,
+ source_module: str,
+ enable_sync_sends: bool,
+ enable_async_sends: bool,
+ get_protocol_call: str = 'get_protocol') -> None:
"""Used by pcommands taking a single filename argument."""
import efro.message
@@ -29,17 +29,23 @@ def standard_message_sender_gen_pcommand(
if len(sys.argv) != 3:
raise CleanError('Expected 1 arg: out-path.')
-
dst = sys.argv[2]
- out = format_yapf_str(
- projroot,
- efro.message.create_sender_module(
- basename,
- protocol_create_code=(f'from {source_module} import get_protocol\n'
- f'protocol = get_protocol()'),
- enable_sync_sends=enable_sync_sends,
- enable_async_sends=enable_async_sends,
- ))
+
+ # Use wrapping-friendly form for long call names.
+ get_protocol_import = (f'({get_protocol_call})' if
+ len(get_protocol_call) >= 14 else get_protocol_call)
+
+ protocol_create_code = (
+ f'from {source_module} import {get_protocol_import}\n'
+ f'protocol = {get_protocol_call}()')
+
+ module_code = efro.message.create_sender_module(
+ basename,
+ protocol_create_code=protocol_create_code,
+ enable_sync_sends=enable_sync_sends,
+ enable_async_sends=enable_async_sends,
+ )
+ out = format_yapf_str(projroot, module_code)
print(f'Meta-building {Clr.BLD}{dst}{Clr.RST}')
Path(dst).parent.mkdir(parents=True, exist_ok=True)
@@ -48,11 +54,11 @@ def standard_message_sender_gen_pcommand(
def standard_message_receiver_gen_pcommand(
- projroot: Path,
- basename: str,
- source_module: str,
- is_async: bool,
-) -> None:
+ projroot: Path,
+ basename: str,
+ source_module: str,
+ is_async: bool,
+ get_protocol_call: str = 'get_protocol') -> None:
"""Used by pcommands generating efro.message receiver modules."""
import efro.message
@@ -63,14 +69,22 @@ def standard_message_receiver_gen_pcommand(
raise CleanError('Expected 1 arg: out-path.')
dst = sys.argv[2]
- out = format_yapf_str(
- projroot,
- efro.message.create_receiver_module(
- basename,
- protocol_create_code=(f'from {source_module} import get_protocol\n'
- f'protocol = get_protocol()'),
- is_async=is_async,
- ))
+
+ # Use wrapping-friendly form for long call names.
+ get_protocol_import = (f'({get_protocol_call})' if
+ len(get_protocol_call) >= 14 else get_protocol_call)
+
+ protocol_create_code = (
+ f'from {source_module} import {get_protocol_import}\n'
+ f'protocol = {get_protocol_call}()')
+
+ module_code = efro.message.create_receiver_module(
+ basename,
+ protocol_create_code=protocol_create_code,
+ is_async=is_async,
+ )
+
+ out = format_yapf_str(projroot, module_code)
print(f'Meta-building {Clr.BLD}{dst}{Clr.RST}')
Path(dst).parent.mkdir(parents=True, exist_ok=True)