diff --git a/.efrocachemap b/.efrocachemap index 233ed701..4da45859 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,41 +420,41 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/60/ad/38269b7f1c7dc20cb9a506cd0681", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/72/85/d6fc4d16b7081d91fba2850b5b10", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/e9/ae/1d674d0c086eaa0bd1c3b1db0505", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/9a/eb/d3f20cfa6c8a11a49047b1723a00", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/25/11/cfcf4238fb55433521e26cce0d10", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/e2/24/5e7ea9ca5c9de4d3b7a28e53564d", "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/f8/15/e1a2fa38697417bcf2cf19cd34ef", - "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/44/aa/c12568afb4558dc7f9f2fa155467", + "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/ea/22/bb0950095686a71030c67ac74b3b", + "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/3c/22/78a56fc40426ab19ad4e76924b78", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/c9/73/01a1343af814131b1ee96af0b687", - "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/19/c5/7fab8fbd8c2b78bd5fc11cf6bfdd", - "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", + "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/61/20/01291c2cb72b22f204730c0d7574", + "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/6a/fa/fcf4a804beaff927b0f12c179eaa", "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/df/08/29edc91f648c34c3aa7960e04c13", "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/e9/07/b2dc862601bcd70701b083d43279", - "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/2e/48/b0a8fafc5e5436e99d9a3d697d23", + "assets/build/ba_data/data/languages/filipino.json": "https://files.ballistica.net/cache/ba1/c7/2e/e0520f58206da01b829e02ff4576", + "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/e8/84/6c9f123e9a0d82fc595c8f55ac7c", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/8a/09/3e0fa9e44913b53f4dab195d3fae", "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/08/15/13981ce51e1e9f974357a9e0a59c", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/aa/da/dfc8d710af960d7300c7090faeab", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/91/98/42701cd595c2f70b7484614a8f49", "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/82/76/1ca7ba627f34be34961de40fe91f", - "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/1a/10/9563348e729d1e5c8ae8c9cbc1f2", + "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/0d/b4/e225e3838c4b5d9381dcc4594517", + "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/12/62/862228b229057877e89fb195d41d", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/7c/38/d4a44c481757d355836f292ede48", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/df/b1/b2c9ebaad5e873ebedd365726d3d", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/19/e9/59c891b1fb85f3ba9f19283c233d", - "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/6b/9c/0c8fe0e4d5fc0c29b95ad798ee23", + "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/61/5b/847c03407d1c3a85866833323676", "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/8d/c1/90cc02326100ccee7f03d0cb42b7", + "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/34/ed/b97350983272e4b23bf140d7a5f4", "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/ce/be/2f06c3436871fd464ff3a62597d9", "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/94/1a/533bc718e676191bafc25e2dc98f", + "assets/build/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/64/22/7bc899ecbec52cf978a1faf1c127", "assets/build/ba_data/data/languages/thai.json": "https://files.ballistica.net/cache/ba1/f7/df/7ba5f99c5c2c4c86fc0503fcf0b7", - "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/9a/90/8e2ed626def09f88c3b9ab5215a3", - "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/ab/35/644e4239cfa62a597a905412b90c", - "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/22/8e/3fccd3a8c9761c9e60ee4f5ecd85", + "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/ee/08/1f77c7c320d8d8504a11ee495db3", + "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/f3/92/fd7ee5fa8a92fcc8fd2219a88a2f", + "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/2e/86/10d3e39d35014d039cc9ea886ca7", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/1f/ae/abe3f105b3c4b51f6b7942773305", "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", @@ -4003,50 +4003,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/1c/77/ac670a5118abdf8a7687af0e159b", "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/5e/48/354e3b63adf1b81a40c1d2f1e0fb", - "build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/21/6d/f6433bcd3a4682ad5f44a724cedd", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3a/1a/ea630876f62f4b3b7b799d6323b1", - "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/08/8c/87e7f56a0f66064a53f70e0bd3f6", - "build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e1/2c/f5fb11983aca2855e9ee0ba2e5dd", - "build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9e/d5/e793e83bf0fb26817091c22aef16", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1f/ac/b215701ff340222dab77f303d5fd", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f0/5c/78bea7e51781d6f2888867ca5be5", - "build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/29/75/718ad217e3948a7418a6366e91c3", - "build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/46/5a/2c1f20eb101ae08785038ad397d4", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/58/b2/ef20d61be8192fc906c8cc665022", - "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f8/35/8f46daa43dc357b438cdafaa44c0", - "build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/72/73/84586a76cda423aa020e2bf4d1b9", - "build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3e/53/87a14be9f865901c76cb468bd23c", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/57/57/a93d124c30dc513731e995a2fc35", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/73/b2/815428ea403f7c172adaa7c1880d", - "build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/df/ae/1c8f9e6e5ac182528b59764ba2ec", - "build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7d/4c/de308ea636089d4081fec336204e", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/e1/bc/57f69a5e827136993fe632406d37", - "build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/e4/68/39916efa4879fa3d93d2704402af", - "build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/58/6b/fac212417bcb5851ef75783ccc9b", - "build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5c/18/04a0ef7d2da19b204f6beaf12671", - "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/04/8c/a80aa418ddb5db66e32eac4bcfe8", - "build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b6/1d/c6edb81afdaff56c91b9e58f5d86", - "build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/72/01/565daf2d42a3d7d8f53ceeca6b30", - "build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f0/c6/d7f01e55288c9f735cd16982d346", - "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0f/08/1af07293e2c2f711e208e220589f", - "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4d/da/9f84cdbf6893019e9f312159a135", - "build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0d/8b/1c8bef2677c8019fc47d6295b950", - "build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d6/94/b5808b657d70a533904b83372033", - "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/50/de/e8a479118f1f0a85cf076947385c", - "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4c/a5/223faacd74a7df21ce588bd877e0", - "build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c1/7b/36a20200b32e40d5c7789774cae3", - "build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b1/f1/658e04e51212830d1d0bc4dfcf98", - "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5b/ab/4441a951acf01a5e0ecb3456b08c", - "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/37/0b/58ca3c4f357e5af96d5c0670f473", - "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/77/36/384cd7c45db39ae18bfcd089d728", - "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/71/a7/28df114b036f4a9a4de1ad1e57e5", - "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/42/65/fc84a4d62423352de7c232bc25c0", - "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/51/1e/cc38e33b8e84805463880c484966", - "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/6f/a5/deb805afc5f741dfb3891798bbd8", - "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/3a/61/22ef83f4154ba1b438f07108f1c9", - "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/ee/98/2cf472347862d7fde2562b512a2a", - "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/fa/34/04770e9cf2bf915ab6b4679f6419", + "build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/25/c1/91a48aca063af359c132049b8197", + "build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/43/11/80e9836994ab9583053b25e528d8", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f9/3b/4709b8451aecdbc048eef15d01eb", + "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/03/ae/ee60be4a8b4800b90d1e29691518", + "build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/97/4f/cfee84e252f8b0b7571035f5883b", + "build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/68/f6/5b2d8461aba116b7071ebb5dac2b", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a6/7a/0d72ca4eda2320d6b78feaf6de84", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/19/5b/183980b86e0af44a4dad40c874c1", + "build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/51/44/3f426d8fb643b0b1d2fe3d5197c0", + "build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b7/5c/16040bb5fc81e53872880a942f93", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/91/c4/ae905a45513e4b274a618320d4b9", + "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/29/4d/2c46d9c3c20631ce2eb68ad40211", + "build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/13/76/9b2ae697273b918ba1bab69a7157", + "build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/16/c4/4794acfebd1caee39225de24ad69", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0d/b2/0e379d5edb40f49d3a0b0abb0c05", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b3/92/e6914cd28f76d2f69d58502a4d8b", + "build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3a/53/e128b1b67fcc81ebe7b4a46faf8f", + "build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/dd/1f/288de55d2ded8451643d94ba5d24", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/2e/1e/61a605506c87d391fe5b433d1403", + "build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/f2/e0/94772098ebb18f631dbe78ab6130", + "build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/71/7e/cc04f1d847d7d7002a8452eeee19", + "build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/24/00/1bd70964db65d179f2c6779d8982", + "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/16/88/93dd42830a0175d5830747a713b8", + "build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/52/61/b324c91bd0b077a9206d294d52fb", + "build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/84/8e/fbebd6c94cdcf46688b9e38ed8d8", + "build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e9/94/3e87cc52ee7023beb33b8615d86d", + "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e9/2e/466ad54052a7100921e3e748743e", + "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c7/8f/d3e170f94e48ce122c8cab724791", + "build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f0/f5/6a7983215a5582bed19f561afc4c", + "build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ff/37/32e4499e0c163ea025257fe884e9", + "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/db/ce/0da23791696b0c16a157a0401e82", + "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a4/1e/b453b7454f4bfd81cbba6d4f0a68", + "build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d0/14/5ffa8a2415f14d1ea9ffe9cf4125", + "build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/30/1a/7c959297e7ef46f7e9280b67a861", + "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/69/e6/e5c6a65e42307a86cf4e3fcac729", + "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5c/6d/ee68f9f9c28363dda0c6b6290c6e", + "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/f5/c1/86511c74fdc0dbffd9bae04b557e", + "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/1c/4d/4aa5bfbe1c05a3f1d324d9404315", + "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/2a/78/7380dc896cbead611c7a191b81a6", + "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/d8/bb/b49f9176ae9c814e1850c018254a", + "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/3d/7f/8b4147fdb2a3d6353b24fca7335f", + "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/52/9d/4f8294fda439dca8b9b32c5e3936", + "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/78/ce/1b5d8ce25f71fa509b626e55d8fb", + "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/75/af/455bcadaa37686b1593233b855d3", "src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/c0/32/b7907e3859a5c5013a3d97b6b523", "src/ballistica/generated/python_embedded/bootstrap.inc": "https://files.ballistica.net/cache/ba1/2d/4f/f4fe67827f36cd59cd5193333a02", "src/ballistica/generated/python_embedded/bootstrap_monolithic.inc": "https://files.ballistica.net/cache/ba1/ef/c1/aa5f1aa10af89f5c0b1e616355fd" diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d16c28e..74176661 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ -### 1.7.12 (build 20911, api 7, 2022-10-17) +### 1.7.12 (build 20913, api 7, 2022-10-17) +- Disabled some live-objects warnings as it seems their use of certain gc module functionality might be causing some rare errors/crashes. On further inspection, it turns out that is technically expected. Basically those calls are useful for debugging but can break things. Added a note at the top of efro.debug elaborating on the situation. We can reimplement similar warnings later in a safe manner. +- Removed `ba._general.print_active_refs()` because the newer stuff in efro.debug does the same thing better. +- Bug fixes related to v2 account connections. ### 1.7.11 (build 20909, api 7, 2022-10-15) - Switched our Python autoformatting from yapf to black. The yapf project seems to be mostly dead whereas black seems to be thriving. The final straw was yapf not supporting the `match` statement in Python 3.10. diff --git a/assets/src/ba_data/python/._ba_sources_hash b/assets/src/ba_data/python/._ba_sources_hash index 62f1f485..eae45eb7 100644 --- a/assets/src/ba_data/python/._ba_sources_hash +++ b/assets/src/ba_data/python/._ba_sources_hash @@ -1 +1 @@ -31242320059036633417109806113241486230 \ No newline at end of file +114683483191152240226942293819570296816 \ No newline at end of file diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 69482643..ff0acb57 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -735,31 +735,20 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): and/or print debugging info if the Activity still exists. """ try: - import gc - import types - activity = activity_ref() print( 'ERROR: Activity is not dying when expected:', activity, '(warning ' + str(counter[0] + 1) + ')', ) - print('This means something is still strong-referencing it.') + print( + 'This means something is still strong-referencing it.\n' + 'Check out methods such as efro.debug.printrefs() to' + ' help debug this sort of thing.' + ) + # Note: no longer calling gc.get_referrers() here because it's + # usage can bork stuff. (see notes at top of efro.debug) counter[0] += 1 - - # FIXME: Running the code below shows us references but winds up - # keeping the object alive; need to figure out why. - # For now we just print refs if the count gets to 3, and then we - # kill the app at 4 so it doesn't matter anyway. - if counter[0] == 3: - print('Activity references for', activity, ':') - refs = list(gc.get_referrers(activity)) - i = 1 - for ref in refs: - if isinstance(ref, types.FrameType): - continue - print(' reference', i, ':', ref) - i += 1 if counter[0] == 4: print('Killing app due to stuck activity... :-(') _ba.quit() diff --git a/assets/src/ba_data/python/ba/_apputils.py b/assets/src/ba_data/python/ba/_apputils.py index 148cef9c..166b4d33 100644 --- a/assets/src/ba_data/python/ba/_apputils.py +++ b/assets/src/ba_data/python/ba/_apputils.py @@ -170,7 +170,13 @@ def garbage_collect_session_end() -> None: print('PYTHON GC FOUND', len(gc.garbage), 'UNCOLLECTIBLE OBJECTS:') for i, obj in enumerate(gc.garbage): print(str(i) + ':', obj) - print_live_object_warnings('after session shutdown') + + # NOTE: no longer running these checks. Perhaps we can allow + # running them with an explicit flag passed, but we should never + # run them by default because gc.get_objects() can mess up the app. + # See notes at top of efro.debug. + if bool(False): + print_live_object_warnings('after session shutdown') def garbage_collect() -> None: @@ -190,7 +196,11 @@ def print_live_object_warnings( ignore_session: ba.Session | None = None, ignore_activity: ba.Activity | None = None, ) -> None: - """Print warnings for remaining objects in the current context.""" + """Print warnings for remaining objects in the current context. + + IMPORTANT - don't call this in production; usage of gc.get_objects() + can bork Python. See notes at top of efro.debug module. + """ # pylint: disable=cyclic-import from ba._session import Session from ba._actor import Actor diff --git a/assets/src/ba_data/python/ba/_bootstrap.py b/assets/src/ba_data/python/ba/_bootstrap.py index ca2fe80f..e764d4eb 100644 --- a/assets/src/ba_data/python/ba/_bootstrap.py +++ b/assets/src/ba_data/python/ba/_bootstrap.py @@ -47,7 +47,7 @@ def bootstrap() -> None: # Give a soft warning if we're being used with a different binary # version than we expect. - expected_build = 20911 + expected_build = 20913 running_build: int = env['build_number'] if running_build != expected_build: print( diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index dbd58099..bb992315 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -3,7 +3,6 @@ """Utility snippets applying to generic Python code.""" from __future__ import annotations -import gc import types import weakref import random @@ -16,7 +15,6 @@ from ba._error import print_error, print_exception from ba._generated.enums import TimeType if TYPE_CHECKING: - from types import FrameType from typing import Any from efro.call import Call as Call # 'as Call' so we re-export. @@ -125,19 +123,6 @@ def utf8_all(data: Any) -> Any: return data -def print_refs(obj: Any) -> None: - """Print a list of known live references to an object.""" - - # Hmmm; I just noticed that calling this on an object - # seems to keep it alive. Should figure out why. - print('REFERENCES FOR', obj, ':') - refs = list(gc.get_referrers(obj)) - i = 1 - for ref in refs: - print(' ref', i, ':', ref) - i += 1 - - def get_type_name(cls: type) -> str: """Return a full type name including module for a class.""" return cls.__module__ + '.' + cls.__name__ @@ -332,56 +317,6 @@ def verify_object_death(obj: object) -> None: ) -def print_active_refs(obj: Any) -> None: - """Print info about things referencing a given object. - - Category: **General Utility Functions** - - Useful for tracking down cyclical references and causes for zombie objects. - """ - # pylint: disable=too-many-nested-blocks - from types import FrameType, TracebackType - - refs = list(gc.get_referrers(obj)) - print(f'{Clr.YLW}Active referrers to {obj}:{Clr.RST}') - for i, ref in enumerate(refs): - print(f'{Clr.YLW}#{i+1}:{Clr.BLU} {ref}{Clr.RST}') - - # For certain types of objects such as stack frames, show what is - # keeping *them* alive too. - if isinstance(ref, FrameType): - print(f'{Clr.YLW} Active referrers to #{i+1}:{Clr.RST}') - refs2 = list(gc.get_referrers(ref)) - for j, ref2 in enumerate(refs2): - print(f'{Clr.YLW} #a{j+1}:{Clr.BLU} {ref2}{Clr.RST}') - - # Can go further down the rabbit-hole if needed... - if bool(False): - if isinstance(ref2, TracebackType): - print( - f'{Clr.YLW} ' - f'Active referrers to #a{j+1}:{Clr.RST}' - ) - refs3 = list(gc.get_referrers(ref2)) - for k, ref3 in enumerate(refs3): - print( - f'{Clr.YLW} ' - f'#b{k+1}:{Clr.BLU} {ref3}{Clr.RST}' - ) - - if isinstance(ref3, BaseException): - print( - f'{Clr.YLW} Active referrers to' - f' #b{k+1}:{Clr.RST}' - ) - refs4 = list(gc.get_referrers(ref3)) - for x, ref4 in enumerate(refs4): - print( - f'{Clr.YLW} #c{x+1}:{Clr.BLU}' - f' {ref4}{Clr.RST}' - ) - - def _verify_object_death(wref: weakref.ref) -> None: obj = wref() if obj is None: @@ -395,9 +330,9 @@ def _verify_object_death(wref: weakref.ref) -> None: print( f'{Clr.RED}Error: {name} not dying when expected to:' - f' {Clr.BLD}{obj}{Clr.RST}' + f' {Clr.BLD}{obj}{Clr.RST}\n' + 'See efro.debug for ways to debug this.' ) - print_active_refs(obj) def storagename(suffix: str | None = None) -> str: diff --git a/assets/src/ba_data/python/ba/ui/__init__.py b/assets/src/ba_data/python/ba/ui/__init__.py index df7999f2..3d9740b4 100644 --- a/assets/src/ba_data/python/ba/ui/__init__.py +++ b/assets/src/ba_data/python/ba/ui/__init__.py @@ -11,7 +11,6 @@ from typing import TYPE_CHECKING, cast, Type import _ba from ba._generated.enums import TimeType -from ba._general import print_active_refs if TYPE_CHECKING: from typing import Any @@ -230,10 +229,9 @@ def ui_upkeep() -> None: 'WARNING:', obj, 'is still alive 5 second after its widget died;' - ' you might have a memory leak.', + ' you might have a memory leak. See efro.debug module' + ' for tools to help debug this.', ) - print_active_refs(obj) - else: remainingchecks.append(check) ui.cleanupchecks = remainingchecks diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index 489a6c3f..f38dcc44 100644 --- a/src/ballistica/ballistica.cc +++ b/src/ballistica/ballistica.cc @@ -32,7 +32,7 @@ namespace ballistica { // These are set automatically via script; don't modify them here. -const int kAppBuildNumber = 20911; +const int kAppBuildNumber = 20913; const char* kAppVersion = "1.7.12"; // Our standalone globals. diff --git a/src/ballistica/python/methods/python_methods_gameplay.cc b/src/ballistica/python/methods/python_methods_gameplay.cc index 46334d17..73bf636b 100644 --- a/src/ballistica/python/methods/python_methods_gameplay.cc +++ b/src/ballistica/python/methods/python_methods_gameplay.cc @@ -155,13 +155,18 @@ auto PyGetCollisionInfo(PyObject* self, PyObject* args) -> PyObject* { return DoGetCollideValue(dynamics, c, PyUnicode_AsUTF8(obj)); } else if (PyTuple_Check(obj)) { Py_ssize_t size = PyTuple_GET_SIZE(obj); + + // NOTE: Need to make sure we never release the GIL or call out to + // code that could access gc stuff while building this. Ideally should + // create contents first and then create/fill the tuple as last step. + // See https://bugs.python.org/issue15108. PyObject* return_tuple = PyTuple_New(size); for (Py_ssize_t i = 0; i < size; i++) { PyObject* o = PyTuple_GET_ITEM(obj, i); if (PyUnicode_Check(o)) { PyObject* val_obj = DoGetCollideValue(dynamics, c, PyUnicode_AsUTF8(o)); if (val_obj) { - PyTuple_SetItem(return_tuple, i, val_obj); + PyTuple_SET_ITEM(return_tuple, i, val_obj); } else { Py_DECREF(return_tuple); return nullptr; diff --git a/src/ballistica/python/python.cc b/src/ballistica/python/python.cc index 56eeb33e..4ca762fe 100644 --- a/src/ballistica/python/python.cc +++ b/src/ballistica/python/python.cc @@ -1949,7 +1949,7 @@ auto Python::GetNodeAttr(Node* node, const char* attr_name) -> PyObject* { std::vector vals = attr.GetAsFloats(); Py_ssize_t size = vals.size(); PyObject* vals_obj = PyTuple_New(size); - BA_PRECONDITION(vals_obj); + assert(vals_obj); for (Py_ssize_t i = 0; i < size; i++) { PyTuple_SET_ITEM(vals_obj, i, PyFloat_FromDouble(vals[i])); } @@ -1960,7 +1960,7 @@ auto Python::GetNodeAttr(Node* node, const char* attr_name) -> PyObject* { std::vector vals = attr.GetAsInts(); Py_ssize_t size = vals.size(); PyObject* vals_obj = PyTuple_New(size); - BA_PRECONDITION(vals_obj); + assert(vals_obj); for (Py_ssize_t i = 0; i < size; i++) { PyTuple_SET_ITEM(vals_obj, i, PyLong_FromLong(static_cast_check_fit( // NOLINT @@ -1973,7 +1973,7 @@ auto Python::GetNodeAttr(Node* node, const char* attr_name) -> PyObject* { std::vector vals = attr.GetAsNodes(); Py_ssize_t size = vals.size(); PyObject* vals_obj = PyTuple_New(size); - BA_PRECONDITION(vals_obj); + assert(vals_obj); for (Py_ssize_t i = 0; i < size; i++) { Node* n = vals[i]; PyTuple_SET_ITEM(vals_obj, i, @@ -2018,7 +2018,7 @@ auto Python::GetNodeAttr(Node* node, const char* attr_name) -> PyObject* { std::vector vals = attr.GetAsMaterials(); Py_ssize_t size = vals.size(); PyObject* vals_obj = PyTuple_New(size); - BA_PRECONDITION(vals_obj); + assert(vals_obj); for (Py_ssize_t i = 0; i < size; i++) { Material* m = vals[i]; @@ -2033,7 +2033,7 @@ auto Python::GetNodeAttr(Node* node, const char* attr_name) -> PyObject* { std::vector vals = attr.GetAsTextures(); Py_ssize_t size = vals.size(); PyObject* vals_obj = PyTuple_New(size); - BA_PRECONDITION(vals_obj); + assert(vals_obj); for (Py_ssize_t i = 0; i < size; i++) { Texture* t = vals[i]; @@ -2048,7 +2048,7 @@ auto Python::GetNodeAttr(Node* node, const char* attr_name) -> PyObject* { std::vector vals = attr.GetAsSounds(); Py_ssize_t size = vals.size(); PyObject* vals_obj = PyTuple_New(size); - BA_PRECONDITION(vals_obj); + assert(vals_obj); for (Py_ssize_t i = 0; i < size; i++) { Sound* s = vals[i]; @@ -2063,7 +2063,7 @@ auto Python::GetNodeAttr(Node* node, const char* attr_name) -> PyObject* { std::vector vals = attr.GetAsModels(); Py_ssize_t size = vals.size(); PyObject* vals_obj = PyTuple_New(size); - BA_PRECONDITION(vals_obj); + assert(vals_obj); for (Py_ssize_t i = 0; i < size; i++) { Model* m = vals[i]; @@ -2078,7 +2078,7 @@ auto Python::GetNodeAttr(Node* node, const char* attr_name) -> PyObject* { std::vector vals = attr.GetAsCollideModels(); Py_ssize_t size = vals.size(); PyObject* vals_obj = PyTuple_New(size); - BA_PRECONDITION(vals_obj); + assert(vals_obj); for (Py_ssize_t i = 0; i < size; i++) { CollideModel* c = vals[i]; diff --git a/tools/efro/debug.py b/tools/efro/debug.py index 74a72e0e..8a78b545 100644 --- a/tools/efro/debug.py +++ b/tools/efro/debug.py @@ -1,6 +1,15 @@ # Released under the MIT License. See LICENSE for details. # -"""Utilities for debugging memory leaks or other issues.""" +"""Utilities for debugging memory leaks or other issues. + +IMPORTANT - these functions use the gc module which looks 'under the hood' +at Python and sometimes returns not-fully-initialized objects, which may +cause crashes or errors due to suddenly having references to them that they +didn't expect, etc. See https://github.com/python/cpython/issues/59313. +For this reason, these methods should NEVER be called in production code. +Enable them only for debugging situations and be aware that their use may +itself cause problems. The same is true for the gc module itself. +""" from __future__ import annotations import gc