Work on android and detecting network problems

This commit is contained in:
Eric Froemling 2022-07-05 14:59:10 -07:00
parent d58ab12bc4
commit ea67658558
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
19 changed files with 247 additions and 119 deletions

View File

@ -420,18 +420,18 @@
"assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/dc/d2/160fc27fcaff10793327ac2c70fd", "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/dc/d2/160fc27fcaff10793327ac2c70fd",
"assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/11/7a/87d6bca0acfb877fd4fd8fe3a598", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/11/7a/87d6bca0acfb877fd4fd8fe3a598",
"assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/44/f5/c943c9075abb3e1835d2408a1ef8", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/44/f5/c943c9075abb3e1835d2408a1ef8",
"assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/c4/e7/432f66c84194bd6d04ecc485e308", "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/9d/0a/e98c8e794fe9cd741b5f8e5642c7",
"assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/4c/fd/67a9dcdecb85dbaf549a8fbbdc78", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/db/6a/02249b1d9bdc66f603a33e91d118",
"assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/61/03/89070ca765e06da3a419a579f503", "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/32/a7/b9208ab804dfe2d1c3960256e9f8", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/18/7f/03acf6a5fcc9d3958f9746eadaf4",
"assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/61/e6/caf06ce99017fdf5d2da0c038445", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/61/e6/caf06ce99017fdf5d2da0c038445",
"assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/f5/d4/683ef2d47b669e5f177bc1ae4ff0", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/f5/d4/683ef2d47b669e5f177bc1ae4ff0",
"assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/87/84/9f3d39610453b3bf350698a23316", "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/87/84/9f3d39610453b3bf350698a23316",
"assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", "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/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/b9/72/96f5843dffe76fd16fa691845497", "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/2c/41/2c43429b95bef4e88fc279071470",
"assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/4c/c7/0184b8178869d1a3827a1bfcd5bb", "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/f8/ac/ade62ff2a8c13550f56c918d55fb", "assets/build/ba_data/data/languages/filipino.json": "https://files.ballistica.net/cache/ba1/4b/d5/7c877f9550c0154c52f410b93315",
"assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/b6/e0/37dd30b686f475733ccc4b3cab49", "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/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/6b/f3/5ca25b080c7f04403ffd1c918787", "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/6b/f3/5ca25b080c7f04403ffd1c918787",
@ -439,22 +439,22 @@
"assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/08/3b/68cea4d16f7020d932829af85323", "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/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/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/94/2d/4f17fc4b73260e99453ee3122c0c", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/f3/11/d81cc9f0c76b81b0b8dcf64fe292",
"assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/07/37/ab65ccee3a555bd40e9661860c58", "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/02/ab/e310f81582b6dc2ae93348d45166", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/02/ab/e310f81582b6dc2ae93348d45166",
"assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/76/be/84e567de0aabd9f9145b62179c2c", "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/e2/cd/8738b4ac572fc3f98714a4a4be67", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/fa/21/62f7d0885c1ddf8cbdaf13a46685",
"assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/c9/5c/ccbae41f2baa11599563b4aabe00", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/20/35/19ab623ce299a61e325f2ac5354b",
"assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/8c/a7/1dea3643720ced9fa40a0b3d1add", "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/92/a7/a6d22213dd30f5f57919d6cc2e94",
"assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/13/19/828be486951be254445263f36c6e", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/13/19/828be486951be254445263f36c6e",
"assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/f9/4b/d9f01814224066856695452ef57c", "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/b3/a3/3e1befdc621a503219fa78ba6d8b", "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/a3/20/bf03c91445f7083378d55a476415",
"assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/91/0a/35c4baf539d5951fc03a794c0e0b", "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/75/b3/c344f382251cb7e696bedb712421", "assets/build/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/9a/7f/39c9ac42c22776a65e59503b189e",
"assets/build/ba_data/data/languages/thai.json": "https://files.ballistica.net/cache/ba1/9d/51/f699dbd4beb88bc3cff699a287a7", "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/6f/2e/20bed8fefb23ca42c18a7b6c75b2", "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/d3/41/bef1112708d7ee012c7187967dcd",
"assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/7f/bb/6239adeb551be5e09f3457d7b411", "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/d9/97/e3ec72c08fcaeb2f69569c20f085", "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/68/77/cc871b6ed611cb8d6f74cf1a9d00",
"assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/f2/af/afd1503c7a10cacaa15bc02369b2", "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/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", "assets/build/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/03/4b/57ee9b42854b26f23f81bd8c58ef",
@ -3992,50 +3992,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/__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", "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", "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/14/32/34006cd68ca39d27add8c36839a9", "build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/70/3b/0c7d541b3856884a747ff4606125",
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f9/27/943498c90fd48490581721549831", "build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/af/8b/9191ae1c05ed11d77bf9099abdaf",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/99/ee/a7e516ce3d295c32a9fae1f61837", "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8f/88/e96a5cf5728280557a229c3cd196",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/33/1c/c84d7e2f9108787614e8fa47b178", "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/40/8c/e3932b01bfb03bf3d930fa6b0075",
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/66/ca/89977fb3b87de266a9da81655879", "build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/4e/dd/cceaa79ecc33d116254129115ab6",
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/50/ed/fa670d5646074507df2bd11cc9f3", "build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/bc/d5/2992911e42d4019062a5ee7922be",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5d/e1/7dde73d49d729d4ad722d7042821", "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2d/75/b81d14e56fac5cb36204b99d438b",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3a/57/a994445b5ba27e8b21df9218f05f", "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bd/35/af73fd25f90b260a7e1f2b45604a",
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/db/742462576b3e78cc42cbe8c15b4d", "build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a4/b9/2d9d7fdf7f8fc36a395396c17396",
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/98/52/3dd887570176346b2b0a9c40658e", "build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ac/ec/cbd0cd6b30ffc5e9899df476ff75",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ad/26/9bc36871955e6bafc5a5c6f21e74", "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fb/db/28557fffa11dc30193dfdf2bc1cc",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5e/94/f021148e84ed3ba2997c51c701bf", "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cb/34/83e11c5a79dcb4a925b05a65741c",
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2b/11/63ecf6112d1a3ea71ee31c192d32", "build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d5/12/cd06cac7c7bb070397da839850df",
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ae/5a/bc6c4c10a64fb230edb1d16ec0e7", "build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/da/87/5df008ea5c203eb4a97bfa9648fe",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/76/ce/ba8b95c2ea1fbef5ee6fc22fc421", "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/93/ca/2afe9fc10c37c16a91a556350be0",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bf/b3/6b576d8587719ec0f9dcdc851613", "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/19/cc/c1bb1e323387f590c3ad649cf2b1",
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a6/25/6c769b43530cc0f5870fde6b01f4", "build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a0/31/1f941c66e9290a4ae69f5f4b0aa4",
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/4f/b2/915fa6ee32e67839fdab20b20e9f", "build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/74/15/89bb4aa1472f0848808b215fbab6",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/54/a0/02d658b28cee638eb2587e5800af", "build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/25/a3/4c7334e53c11997b7cf292c96da8",
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/e7/56/3aa98841dab173ddfe3e4c7dd19e", "build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/64/e0/f9f926a34c2e0243419b20a28138",
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3f/60/5fb1cb5bd1ee656517914df2eb26", "build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/11/a6/7db8addcd876b1933e16f380696a",
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/95/92/1bac3bcac3e1f71417b7ff053b52", "build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c7/8a/3d8501efecca4f20b9702d24f9db",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/54/55/b16bb20de7c3ab30311e73707e17", "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/74/fb/8ba0b3bddf4e0f1184a68e648959",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6d/79/9b588be3e8d74c8c8bd761899be5", "build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/24/ab/393d381b77a85cdbba6c47d8a67a",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e2/17/168f29b83ee04a412c0fa402258b", "build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/da/23/026d70f770273a92def633d57935",
"build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a5/60/8d865d088dbc8d34d739b2c16fee", "build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/35/e8/37eeb762bbae9daffae6d5d69b7e",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/38/4d/101a78df34eada8ffa73636cd178", "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3a/6b/0e26e2ab6eab60258ddcab0601fd",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/54/4b/4f8648af8ea56398da8b56babffa", "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/70/38/7ff58456d824e3461c6a1a3f3f5a",
"build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3a/08/e5955806784ca0dbc2e9e679136a", "build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/10/39/9501e3afd9a1a0af817989e18c7d",
"build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e2/7c/6d600a764587eb8d74b9701fe73f", "build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/42/f6/e8943073f00d93b2e2cd1822916a",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/96/4f/a761ffd6cbcc9d19015e8a2ebbd2", "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/67/82/220d9a12ed10c885aadc02b9919b",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4a/18/c94f7cf05127e82cd71f46dc7dd6", "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3f/c5/dc64be0a0f9d09630074e630312b",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/39/d1/0bd6a2cf0f447642d8e58b538243", "build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f2/5f/e75027e1f6f31fae1f1d20a8b2ee",
"build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/bc/c0/1230a5a3ff3786fc335b57800324", "build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1d/11/18a94007cbcaf2e10c46fc367f7a",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b5/7f/0e2c1cf8683876727192587148ac", "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/51/a8/414d1a0ad00982cd961f0a29a501",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fe/04/375a70cb1510e2ec904a8d413a84", "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4b/0c/26593bd6f6191a19531ce1dd492b",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/09/77/21bbba5f4a88b3534e133dc156d5", "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/62/9e/e8679467880812a2a31266704517",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/72/95/fc9be2f3b29b4bcc19079269d4b3", "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/56/f1/af68b9666c2ce5038b813719c458",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/19/d8/d2728c0e48b220b7c20e2690ecae", "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/d2/a9/9087249ba5a8873f59503a7cb3e4",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/07/d6/d4305dab6a066c0a1459efcec85e", "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/fd/3f/57f64be3b335dbbe0f261edf0861",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/75/26/dc45c1c15b7727a013fd98ce1796", "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/8b/cf/cc26378a8800b0efd14455e7f6b5",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/ee/39/9498eb5c1103b27df3454b52ba98", "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/64/34/18f21d11fda7f1472e0212169904",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/61/b1/3ab8780ac812d4cdedf19f504aaa", "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/24/71/93680835ec6af90acf9d4e2fd63f",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/43/90/175c959c383fe983a614f92b6dec", "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/af/ae/86b7f88249a684530c6d30831889",
"src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/6e/6f/004b696e9a13b083069374e4bb6a", "src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/6e/6f/004b696e9a13b083069374e4bb6a",
"src/ballistica/generated/python_embedded/bootstrap.inc": "https://files.ballistica.net/cache/ba1/d3/db/e73d4dcf1280d5f677c3cf8b47c3" "src/ballistica/generated/python_embedded/bootstrap.inc": "https://files.ballistica.net/cache/ba1/d3/db/e73d4dcf1280d5f677c3cf8b47c3"
} }

View File

@ -1,4 +1,4 @@
### 1.7.3 (20627, 2022-07-01) ### 1.7.3 (20629, 2022-07-05)
- Fixed an issue with King of the Hill flag regions not working when players entered them (Thanks itsre3!) - Fixed an issue with King of the Hill flag regions not working when players entered them (Thanks itsre3!)
- Fixed an issue in Chosen One where the flag resetting on top of a player would not cause them to become the chosen one (Thanks Dliwk!) - Fixed an issue in Chosen One where the flag resetting on top of a player would not cause them to become the chosen one (Thanks Dliwk!)
- Fixed an issue where triple-bomb powerup would not flash before wearing off (Thanks Juleskie!). - Fixed an issue where triple-bomb powerup would not flash before wearing off (Thanks Juleskie!).
@ -7,6 +7,14 @@
- The app now issues a gentle notice if plugins are removed instead of erroring and continuing to look for them on subsequent launches. This makes things much smoother when switching between workspaces or users. - The app now issues a gentle notice if plugins are removed instead of erroring and continuing to look for them on subsequent launches. This makes things much smoother when switching between workspaces or users.
- Added new translation entries for Workspace/Plugin stuff. - Added new translation entries for Workspace/Plugin stuff.
- tools/bacloud workspace get/put commands are now functional (wiki page with instructions coming soon). - tools/bacloud workspace get/put commands are now functional (wiki page with instructions coming soon).
- `_ba.android_get_external_storage_path` is now `_ba.android_get_external_files_dir` which maps to the actual call it makes under the hood these days.
- Android logging now breaks up long entries such as stack-traces into multiple log entries so they should not get truncated.
- The app now issues a warning if device time varies significantly from actual world time. This can lead to things like the app incorrectly treating SSL certificates as not yet valid and network functionality failing.
- The app now issues a warning if unable to establish secure connections to cloud servers (which can be due to aforementioned issue, but could also stem from other network problems).
- The Network Testing utility (Settings->Advanced->Network Testing) now tests for more potential issues including ones mentioned above.
- The Android version now stores files such as extracted assets and audio caches in the non-backed-up files dir (Android's Context.getNoBackupFilesDir()). These files can always be recreated by the app so they don't need backups, and this makes it more likely that Android will back up what's left in the regular files dir (the app config, etc).
### 1.7.2 (20620, 2022-06-25) ### 1.7.2 (20620, 2022-06-25)
- Minor fixes in some minigames (Thanks Droopy!) - Minor fixes in some minigames (Thanks Droopy!)

View File

@ -11,6 +11,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import asyncio import asyncio
import logging
import time
if TYPE_CHECKING: if TYPE_CHECKING:
import ba import ba
@ -53,7 +55,17 @@ def setup_asyncio() -> asyncio.AbstractEventLoop:
def run_cycle() -> None: def run_cycle() -> None:
assert _asyncio_event_loop is not None assert _asyncio_event_loop is not None
_asyncio_event_loop.call_soon(_asyncio_event_loop.stop) _asyncio_event_loop.call_soon(_asyncio_event_loop.stop)
starttime = time.monotonic()
_asyncio_event_loop.run_forever() _asyncio_event_loop.run_forever()
endtime = time.monotonic()
# We'd like to keep the app running at a smooth 120hz, so
# complain if we're taking more than half that time per update.
warn_time = 1.0 / 240
duration = endtime - starttime
if duration > warn_time:
logging.warning('Asyncio loop step took %.4fs; ideal max is %.4f',
duration, warn_time)
global _asyncio_timer # pylint: disable=invalid-name global _asyncio_timer # pylint: disable=invalid-name
_asyncio_timer = _ba.Timer(1.0 / 30.0, _asyncio_timer = _ba.Timer(1.0 / 30.0,

View File

@ -56,6 +56,14 @@ class CloudSubsystem:
) -> None: ) -> None:
... ...
@overload
def send_message_cb(
self,
msg: bacommon.cloud.PingMessage,
on_response: Callable[[bacommon.cloud.PingResponse | Exception], None],
) -> None:
...
def send_message_cb( def send_message_cb(
self, self,
msg: Message, msg: Message,

View File

@ -211,7 +211,7 @@ class MusicSubsystem:
return 'Mac' in uas return 'Mac' in uas
if entry_type in ('musicFile', 'musicFolder'): if entry_type in ('musicFile', 'musicFolder'):
return ('android' in uas return ('android' in uas
and _ba.android_get_external_storage_path() is not None) and _ba.android_get_external_files_dir() is not None)
if entry_type == 'default': if entry_type == 'default':
return True return True
return False return False

View File

@ -29,7 +29,7 @@ class NetworkSubsystem:
# as it is updated by a background thread. # as it is updated by a background thread.
self.zone_pings_lock = threading.Lock() self.zone_pings_lock = threading.Lock()
# Region IDs mapped to average pings. This will remain empty # Zone IDs mapped to average pings. This will remain empty
# until enough pings have been run to be reasonably certain # until enough pings have been run to be reasonably certain
# that a nearby server has been pinged. # that a nearby server has been pinged.
self.zone_pings: dict[str, float] = {} self.zone_pings: dict[str, float] = {}
@ -37,6 +37,7 @@ class NetworkSubsystem:
# For debugging. # For debugging.
self.v1_test_log: str = '' self.v1_test_log: str = ''
self.v1_ctest_results: dict[int, str] = {} self.v1_ctest_results: dict[int, str] = {}
self.server_time_offset_hours: float | None = None
def get_ip_address_type(addr: str) -> socket.AddressFamily: def get_ip_address_type(addr: str) -> socket.AddressFamily:

View File

@ -112,10 +112,11 @@ class PluginSubsystem:
# or workspaces. # or workspaces.
if disappeared_plugs: if disappeared_plugs:
_ba.playsound(_ba.getsound('shieldDown')) _ba.playsound(_ba.getsound('shieldDown'))
_ba.screenmessage(Lstr(resource='pluginsRemovedText', _ba.screenmessage(
subs=[('${NUM}', Lstr(resource='pluginsRemovedText',
str(len(disappeared_plugs)))]), subs=[('${NUM}', str(len(disappeared_plugs)))]),
color=(1, 1, 0)) color=(1, 1, 0),
)
_ba.log( _ba.log(
f'{len(disappeared_plugs)} plugin(s) no longer found:' f'{len(disappeared_plugs)} plugin(s) no longer found:'
f' {disappeared_plugs}', f' {disappeared_plugs}',

View File

@ -27,8 +27,7 @@ def get_human_readable_user_scripts_path() -> str:
# only visible to the user's processes and thus not really useful printed # only visible to the user's processes and thus not really useful printed
# in its entirety; lets print it as <External Storage>/myfilepath. # in its entirety; lets print it as <External Storage>/myfilepath.
if app.platform == 'android': if app.platform == 'android':
ext_storage_path: str | None = ( ext_storage_path: str | None = (_ba.android_get_external_files_dir())
_ba.android_get_external_storage_path())
if (ext_storage_path is not None if (ext_storage_path is not None
and app.python_directory_user.startswith(ext_storage_path)): and app.python_directory_user.startswith(ext_storage_path)):
path = ('<' + path = ('<' +

View File

@ -10,6 +10,7 @@ import weakref
from threading import Thread from threading import Thread
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from efro.error import CleanError
import _ba import _ba
import ba import ba
from bastd.ui.settings.testing import TestingWindow from bastd.ui.settings.testing import TestingWindow
@ -148,10 +149,12 @@ def _run_diagnostics(weakwin: weakref.ref[NetTestingWindow]) -> None:
call() call()
duration = time.monotonic() - starttime duration = time.monotonic() - starttime
_print(f'Succeeded in {duration:.2f}s.', color=(0, 1, 0)) _print(f'Succeeded in {duration:.2f}s.', color=(0, 1, 0))
except Exception: except Exception as exc:
import traceback import traceback
duration = time.monotonic() - starttime duration = time.monotonic() - starttime
_print(traceback.format_exc(), color=(1.0, 1.0, 0.3)) msg = (str(exc)
if isinstance(exc, CleanError) else traceback.format_exc())
_print(msg, color=(1.0, 1.0, 0.3))
_print(f'Failed in {duration:.2f}s.', color=(1, 0, 0)) _print(f'Failed in {duration:.2f}s.', color=(1, 0, 0))
have_error[0] = True have_error[0] = True
@ -193,6 +196,9 @@ def _run_diagnostics(weakwin: weakref.ref[NetTestingWindow]) -> None:
_print(f'\nContacting V2 master-server ({baseaddr})...') _print(f'\nContacting V2 master-server ({baseaddr})...')
_print_test_results(lambda: _test_fetch(baseaddr)) _print_test_results(lambda: _test_fetch(baseaddr))
_print('\nComparing local time to V2 server...')
_print_test_results(_test_v2_time)
# Get V2 nearby zone # Get V2 nearby zone
with ba.app.net.zone_pings_lock: with ba.app.net.zone_pings_lock:
zone_pings = copy.deepcopy(ba.app.net.zone_pings) zone_pings = copy.deepcopy(ba.app.net.zone_pings)
@ -206,6 +212,9 @@ def _run_diagnostics(weakwin: weakref.ref[NetTestingWindow]) -> None:
_print(f'\nChecking nearest V2 zone ping ({nearstr})...') _print(f'\nChecking nearest V2 zone ping ({nearstr})...')
_print_test_results(lambda: _test_nearby_zone_ping(nearest_zone)) _print_test_results(lambda: _test_nearby_zone_ping(nearest_zone))
_print('\nSending V2 cloud message...')
_print_test_results(_test_v2_cloud_message)
if have_error[0]: if have_error[0]:
_print('\nDiagnostics complete. Some diagnostics failed.', _print('\nDiagnostics complete. Some diagnostics failed.',
color=(10, 0, 0)) color=(10, 0, 0))
@ -271,6 +280,58 @@ def _test_v1_transaction() -> None:
raise RuntimeError(results[0]) raise RuntimeError(results[0])
def _test_v2_cloud_message() -> None:
from dataclasses import dataclass
import bacommon.cloud
@dataclass
class _Results:
errstr: str | None = None
send_time: float | None = None
response_time: float | None = None
results = _Results()
def _cb(response: bacommon.cloud.PingResponse | Exception) -> None:
# Note: this runs in another thread so need to avoid exceptions.
results.response_time = time.monotonic()
if isinstance(response, Exception):
results.errstr = str(response)
if not isinstance(response, bacommon.cloud.PingResponse):
results.errstr = f'invalid response type: {type(response)}.'
def _send() -> None:
# Note: this runs in another thread so need to avoid exceptions.
results.send_time = time.monotonic()
ba.app.cloud.send_message_cb(bacommon.cloud.PingMessage(), _cb)
# This stuff expects to be run from the logic thread.
ba.pushcall(_send, from_other_thread=True)
wait_start_time = time.monotonic()
while True:
if results.response_time is not None:
break
time.sleep(0.01)
if time.monotonic() - wait_start_time > 10.0:
raise RuntimeError('Timeout waiting for cloud message response')
if results.errstr is not None:
raise RuntimeError(results.errstr)
def _test_v2_time() -> None:
offset = ba.app.net.server_time_offset_hours
if offset is None:
raise RuntimeError('no time offset found;'
' perhaps unable to communicate with v2 server?')
if abs(offset) >= 2.0:
raise CleanError(
f'Your device time is off from world time by {offset:.1f} hours.\n'
'This may cause network operations to fail due to your device\n'
' incorrectly treating SSL certificates as not-yet-valid, etc.\n'
'Check your device time and time-zone settings to fix this.\n')
def _test_fetch(baseaddr: str) -> None: def _test_fetch(baseaddr: str) -> None:
# pylint: disable=consider-using-with # pylint: disable=consider-using-with
import urllib.request import urllib.request

View File

@ -160,7 +160,7 @@ class SoundtrackEntryTypeSelectWindow(ba.Window):
from ba.osmusic import OSMusicPlayer from ba.osmusic import OSMusicPlayer
from bastd.ui.fileselector import FileSelectorWindow from bastd.ui.fileselector import FileSelectorWindow
ba.containerwidget(edit=self._root_widget, transition='out_left') ba.containerwidget(edit=self._root_widget, transition='out_left')
base_path = _ba.android_get_external_storage_path() base_path = _ba.android_get_external_files_dir()
ba.app.ui.set_main_menu_window( ba.app.ui.set_main_menu_window(
FileSelectorWindow( FileSelectorWindow(
base_path, base_path,
@ -173,7 +173,7 @@ class SoundtrackEntryTypeSelectWindow(ba.Window):
def _on_music_folder_press(self) -> None: def _on_music_folder_press(self) -> None:
from bastd.ui.fileselector import FileSelectorWindow from bastd.ui.fileselector import FileSelectorWindow
ba.containerwidget(edit=self._root_widget, transition='out_left') ba.containerwidget(edit=self._root_widget, transition='out_left')
base_path = _ba.android_get_external_storage_path() base_path = _ba.android_get_external_files_dir()
ba.app.ui.set_main_menu_window( ba.app.ui.set_main_menu_window(
FileSelectorWindow(base_path, FileSelectorWindow(base_path,
callback=self._music_folder_selector_cb, callback=self._music_folder_selector_cb,

View File

@ -21,7 +21,7 @@
namespace ballistica { namespace ballistica {
// These are set automatically via script; don't modify them here. // These are set automatically via script; don't modify them here.
const int kAppBuildNumber = 20627; const int kAppBuildNumber = 20629;
const char* kAppVersion = "1.7.3"; const char* kAppVersion = "1.7.3";
// Our standalone globals. // Our standalone globals.

View File

@ -269,13 +269,18 @@ auto Platform::GetUserPythonDirectory() -> std::string {
auto Platform::GetVolatileDataDirectory() -> std::string { auto Platform::GetVolatileDataDirectory() -> std::string {
if (!made_volatile_data_dir_) { if (!made_volatile_data_dir_) {
volatile_data_dir_ = GetConfigDirectory() + BA_DIRSLASH + "vdata"; volatile_data_dir_ = GetDefaultVolatileDataDirectory();
MakeDir(volatile_data_dir_); MakeDir(volatile_data_dir_);
made_volatile_data_dir_ = true; made_volatile_data_dir_ = true;
} }
return volatile_data_dir_; return volatile_data_dir_;
} }
auto Platform::GetDefaultVolatileDataDirectory() -> std::string {
// By default, stuff this in a subdir under our config dir.
return GetConfigDirectory() + BA_DIRSLASH + "vdata";
}
auto Platform::GetAppPythonDirectory() -> std::string { auto Platform::GetAppPythonDirectory() -> std::string {
static bool checked_dir = false; static bool checked_dir = false;
if (!checked_dir) { if (!checked_dir) {
@ -437,8 +442,8 @@ void Platform::MakeDir(const std::string& dir, bool quiet) {
} }
} }
auto Platform::GetExternalStoragePath() -> std::string { auto Platform::AndroidGetExternalFilesDir() -> std::string {
throw Exception("GetExternalStoragePath() unimplemented"); throw Exception("AndroidGetExternalFilesDir() unimplemented");
} }
auto Platform::DoGetUserPythonDirectory() -> std::string { auto Platform::DoGetUserPythonDirectory() -> std::string {
@ -708,7 +713,7 @@ auto Platform::GetKeyName(int keycode) -> std::string {
void Platform::CreateAuxiliaryModules() { void Platform::CreateAuxiliaryModules() {
#if !BA_HEADLESS_BUILD #if !BA_HEADLESS_BUILD
auto bg_dynamics_thread = new Thread(ThreadIdentifier::kBGDynamics); auto* bg_dynamics_thread = new Thread(ThreadIdentifier::kBGDynamics);
g_app_globals->pausable_threads.push_back(bg_dynamics_thread); g_app_globals->pausable_threads.push_back(bg_dynamics_thread);
#endif #endif
#if !BA_HEADLESS_BUILD #if !BA_HEADLESS_BUILD
@ -719,7 +724,7 @@ void Platform::CreateAuxiliaryModules() {
// Start listening for stdin commands (on platforms where that makes sense). // Start listening for stdin commands (on platforms where that makes sense).
// Note: this thread blocks indefinitely for input so we don't add it to the // Note: this thread blocks indefinitely for input so we don't add it to the
// pausable list. // pausable list.
auto std_input_thread = new Thread(ThreadIdentifier::kStdin); auto* std_input_thread = new Thread(ThreadIdentifier::kStdin);
std_input_thread->AddModule<StdInputModule>(); std_input_thread->AddModule<StdInputModule>();
g_std_input_module->PushBeginReadCall(); g_std_input_module->PushBeginReadCall();
} }
@ -1209,7 +1214,7 @@ auto Platform::GetBroadcastAddrs() -> std::vector<uint32_t> {
throw Exception(); throw Exception();
#else #else
std::vector<uint32_t> addrs; std::vector<uint32_t> addrs;
struct ifaddrs* ifaddr; struct ifaddrs* ifaddr{};
if (getifaddrs(&ifaddr) != -1) { if (getifaddrs(&ifaddr) != -1) {
int i = 0; int i = 0;
for (ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { for (ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
@ -1252,7 +1257,7 @@ auto Platform::SetSocketNonBlocking(int sd) -> bool {
#endif #endif
} }
auto Platform::GetTicks() -> millisecs_t { auto Platform::GetTicks() const -> millisecs_t {
return GetCurrentMilliseconds() - starttime_; return GetCurrentMilliseconds() - starttime_;
} }

View File

@ -239,9 +239,6 @@ class Platform {
/// Are we running on fireTV hardware? /// Are we running on fireTV hardware?
virtual auto IsRunningOnFireTV() -> bool; virtual auto IsRunningOnFireTV() -> bool;
/// Return the external storage path (currently only relevant on Android).
virtual auto GetExternalStoragePath() -> std::string;
// For enabling some special hardware optimizations for nvidia. // For enabling some special hardware optimizations for nvidia.
auto is_tegra_k1() const -> bool { return is_tegra_k1_; } auto is_tegra_k1() const -> bool { return is_tegra_k1_; }
auto set_is_tegra_k1(bool val) -> void { is_tegra_k1_ = val; } auto set_is_tegra_k1(bool val) -> void { is_tegra_k1_ = val; }
@ -276,6 +273,7 @@ class Platform {
const std::string& code) -> void; const std::string& code) -> void;
virtual auto AndroidRefreshFile(const std::string& file) -> void; virtual auto AndroidRefreshFile(const std::string& file) -> void;
virtual auto AndroidShowWifiSettings() -> void; virtual auto AndroidShowWifiSettings() -> void;
virtual auto AndroidGetExternalFilesDir() -> std::string;
#pragma mark PERMISSIONS ------------------------------------------------------- #pragma mark PERMISSIONS -------------------------------------------------------
@ -462,7 +460,7 @@ class Platform {
// Return a monotonic time measurement in milliseconds since launch. // Return a monotonic time measurement in milliseconds since launch.
// To get a time value that is guaranteed to not jump around or go backwards, // To get a time value that is guaranteed to not jump around or go backwards,
// use ballistica::GetRealTime() (which is an abstraction around this). // use ballistica::GetRealTime() (which is an abstraction around this).
auto GetTicks() -> millisecs_t; auto GetTicks() const -> millisecs_t;
// A raw milliseconds value (not relative to launch time). // A raw milliseconds value (not relative to launch time).
static auto GetCurrentMilliseconds() -> millisecs_t; static auto GetCurrentMilliseconds() -> millisecs_t;
@ -552,8 +550,15 @@ class Platform {
virtual auto DoGetUserPythonDirectory() -> std::string; virtual auto DoGetUserPythonDirectory() -> std::string;
/// Return the default config directory for this platform. /// Return the default config directory for this platform.
/// This will be used as the config dir if not overridden via command
/// line options, etc.
virtual auto GetDefaultConfigDirectory() -> std::string; virtual auto GetDefaultConfigDirectory() -> std::string;
/// Return the default Volatile data dir for this platform.
/// This will be used as the volatile-data-dir if not overridden via command
/// line options/etc.
virtual auto GetDefaultVolatileDataDirectory() -> std::string;
/// Generate a random UUID string. /// Generate a random UUID string.
virtual auto GenerateUUID() -> std::string; virtual auto GenerateUUID() -> std::string;

View File

@ -729,17 +729,17 @@ auto PyAndroidMediaScanFile(PyObject* self, PyObject* args, PyObject* keywds)
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma ide diagnostic ignored "ConstantFunctionResult" #pragma ide diagnostic ignored "ConstantFunctionResult"
auto PyAndroidGetExternalStoragePath(PyObject* self, PyObject* args, auto PyAndroidGetExternalFilesDir(PyObject* self, PyObject* args,
PyObject* keywds) -> PyObject* { PyObject* keywds) -> PyObject* {
BA_PYTHON_TRY; BA_PYTHON_TRY;
Platform::SetLastPyCall("android_get_external_storage_path"); Platform::SetLastPyCall("android_get_external_files_dir");
static const char* kwlist[] = {nullptr}; static const char* kwlist[] = {nullptr};
if (!PyArg_ParseTupleAndKeywords(args, keywds, "", if (!PyArg_ParseTupleAndKeywords(args, keywds, "",
const_cast<char**>(kwlist))) { const_cast<char**>(kwlist))) {
return nullptr; return nullptr;
} }
#if BA_OSTYPE_ANDROID #if BA_OSTYPE_ANDROID
std::string path = g_platform->GetExternalStoragePath(); std::string path = g_platform->AndroidGetExternalFilesDir();
if (path.empty()) { if (path.empty()) {
Py_RETURN_NONE; Py_RETURN_NONE;
} else { } else {
@ -883,10 +883,9 @@ auto PythonMethodsSystem::GetMethods() -> std::vector<PyMethodDef> {
"Refreshes Android MTP Index for a file; use this to get file\n" "Refreshes Android MTP Index for a file; use this to get file\n"
"modifications to be reflected in Android File Transfer."}, "modifications to be reflected in Android File Transfer."},
{"android_get_external_storage_path", {"android_get_external_files_dir",
(PyCFunction)PyAndroidGetExternalStoragePath, (PyCFunction)PyAndroidGetExternalFilesDir, METH_VARARGS | METH_KEYWORDS,
METH_VARARGS | METH_KEYWORDS, "android_get_external_files_dir() -> str\n"
"android_get_external_storage_path() -> str\n"
"\n" "\n"
"(internal)\n" "(internal)\n"
"\n" "\n"

View File

@ -423,8 +423,8 @@ TEST_PROTOCOL = MessageProtocol(
0: _TResp1, 0: _TResp1,
1: _TResp2, 1: _TResp2,
}, },
trusted_sender=True, receiver_returns_stack_traces=True,
log_remote_exceptions=False, receiver_logs_exceptions=False,
) )
# Represents an 'evolved' TEST_PROTOCOL (one extra message type added). # Represents an 'evolved' TEST_PROTOCOL (one extra message type added).
@ -440,8 +440,8 @@ TEST_PROTOCOL_B = MessageProtocol(
0: _TResp1, 0: _TResp1,
1: _TResp2, 1: _TResp2,
}, },
trusted_sender=True, receiver_returns_stack_traces=True,
log_remote_exceptions=False, receiver_logs_exceptions=False,
) )
TEST_PROTOCOL_SINGLE = MessageProtocol( TEST_PROTOCOL_SINGLE = MessageProtocol(
@ -451,8 +451,8 @@ TEST_PROTOCOL_SINGLE = MessageProtocol(
response_types={ response_types={
0: _TResp1, 0: _TResp1,
}, },
trusted_sender=True, receiver_returns_stack_traces=True,
log_remote_exceptions=False, receiver_logs_exceptions=False,
) )

View File

@ -76,6 +76,22 @@ class LoginProxyCompleteMessage(Message):
proxyid: Annotated[str, IOAttrs('p')] proxyid: Annotated[str, IOAttrs('p')]
@ioprepped
@dataclass
class PingMessage(Message):
"""Standard ping."""
@classmethod
def get_response_types(cls) -> list[type[Response]]:
return [PingResponse]
@ioprepped
@dataclass
class PingResponse(Response):
"""pong."""
@ioprepped @ioprepped
@dataclass @dataclass
class TestMessage(Message): class TestMessage(Message):

View File

@ -4,6 +4,7 @@
from __future__ import annotations from __future__ import annotations
import datetime
from typing import TYPE_CHECKING, Any, Annotated from typing import TYPE_CHECKING, Any, Annotated
from dataclasses import dataclass, field from dataclasses import dataclass, field
@ -27,6 +28,9 @@ class ServerNodeEntry:
class ServerNodeQueryResponse: class ServerNodeQueryResponse:
"""A response to a query about server-nodes.""" """A response to a query about server-nodes."""
# The current utc time on the master server.
time: Annotated[datetime.datetime, IOAttrs('t')]
# If present, something went wrong, and this describes it. # If present, something went wrong, and this describes it.
error: Annotated[str | None, IOAttrs('e', store_default=False)] = None error: Annotated[str | None, IOAttrs('e', store_default=False)] = None

View File

@ -25,28 +25,40 @@ class MessageProtocol:
"""Wrangles a set of message types, formats, and response types. """Wrangles a set of message types, formats, and response types.
Both endpoints must be using a compatible Protocol for communication Both endpoints must be using a compatible Protocol for communication
to succeed. To maintain Protocol compatibility between revisions, to succeed. To maintain Protocol compatibility between revisions,
all message types must retain the same id, message attr storage names must all message types must retain the same id, message attr storage
not change, newly added attrs must have default values, etc. names must not change, newly added attrs must have default values,
etc.
""" """
def __init__(self, def __init__(self,
message_types: dict[int, type[Message]], message_types: dict[int, type[Message]],
response_types: dict[int, type[Response]], response_types: dict[int, type[Response]],
preserve_clean_errors: bool = True, preserve_clean_errors: bool = True,
log_remote_exceptions: bool = True, receiver_logs_exceptions: bool = True,
trusted_sender: bool = False) -> None: receiver_returns_stack_traces: bool = False) -> None:
"""Create a protocol with a given configuration. """Create a protocol with a given configuration.
Note that common response types are automatically registered Note that common response types are automatically registered
with (unchanging negative ids) so they don't need to be passed with (unchanging negative ids) so they don't need to be passed
explicitly (but can be if a different id is desired). explicitly (but can be if a different id is desired).
If 'preserve_clean_errors' is True, efro.error.CleanError errors If 'preserve_clean_errors' is True, efro.error.CleanError
on the remote end will result in the same error raised locally. exceptions raised on the receiver end will result in a matching
All other Exception types come across as efro.error.RemoteError. CleanError raised back on the sender. All other Exception types
come across as efro.error.RemoteError.
If 'trusted_sender' is True, stringified remote stack traces will When 'receiver_logs_exceptions' is True, any uncaught Exceptions
be included in the responses if errors occur. on the receiver end will be logged there via logging.exception()
(in addition to the usual behavior of returning an ErrorResponse
to the sender). This is good to leave enabled if your
intention is to never return ErrorResponses. Looser setups
making routine use of CleanErrors or whatnot may want to
disable this, however.
If 'receiver_returns_stack_traces' is True, stringified stack
traces will be returned to the sender for exceptions occurring
on the receiver end. This can make debugging easier but should
only be used when the client is trusted to see such info.
""" """
self.message_types_by_id: dict[int, type[Message]] = {} self.message_types_by_id: dict[int, type[Message]] = {}
self.message_ids_by_type: dict[type[Message], int] = {} self.message_ids_by_type: dict[type[Message], int] = {}
@ -102,9 +114,9 @@ class MessageProtocol:
assert is_ioprepped_dataclass(cls) assert is_ioprepped_dataclass(cls)
assert issubclass(cls, Response) assert issubclass(cls, Response)
if cls not in self.response_ids_by_type: if cls not in self.response_ids_by_type:
raise ValueError(f'Possible response type {cls}' raise ValueError(
f' needs to be included in response_types' f'Possible response type {cls} needs to be included'
f' for this protocol.') f' in response_types for this protocol.')
# Make sure all registered types have unique base names. # Make sure all registered types have unique base names.
# We can take advantage of this to generate cleaner looking # We can take advantage of this to generate cleaner looking
@ -116,8 +128,8 @@ class MessageProtocol:
' all types are required to have unique names.') ' all types are required to have unique names.')
self.preserve_clean_errors = preserve_clean_errors self.preserve_clean_errors = preserve_clean_errors
self.log_remote_exceptions = log_remote_exceptions self.receiver_logs_exceptions = receiver_logs_exceptions
self.trusted_sender = trusted_sender self.receiver_returns_stack_traces = receiver_returns_stack_traces
@staticmethod @staticmethod
def encode_dict(obj: dict) -> str: def encode_dict(obj: dict) -> str:
@ -134,7 +146,9 @@ class MessageProtocol:
def error_to_response(self, exc: Exception) -> Response: def error_to_response(self, exc: Exception) -> Response:
"""Translate an error to a response.""" """Translate an error to a response."""
if self.log_remote_exceptions:
# Log any errors we got during handling if so desired.
if self.receiver_logs_exceptions:
logging.exception('Error handling message.') logging.exception('Error handling message.')
# If anything goes wrong, return a ErrorResponse instead. # If anything goes wrong, return a ErrorResponse instead.
@ -142,8 +156,9 @@ class MessageProtocol:
return ErrorResponse(error_message=str(exc), return ErrorResponse(error_message=str(exc),
error_type=ErrorResponse.ErrorType.CLEAN) error_type=ErrorResponse.ErrorType.CLEAN)
return ErrorResponse( return ErrorResponse(
error_message=(traceback.format_exc() if self.trusted_sender else error_message=(traceback.format_exc()
'An unknown error has occurred.'), if self.receiver_returns_stack_traces else
'An internal error has occurred.'),
error_type=ErrorResponse.ErrorType.OTHER) error_type=ErrorResponse.ErrorType.OTHER)
def _to_dict(self, message: Any, ids_by_type: dict[type, int], def _to_dict(self, message: Any, ids_by_type: dict[type, int],

View File

@ -71,12 +71,6 @@ def build_apple(arch: str, debug: bool = False) -> None:
txt = readfile('Makefile') txt = readfile('Makefile')
# Fix a bug where spaces in PATH cause errors (darn you vmware fusion!)
txt = replace_exact(
txt,
'\t\tPATH=$(PROJECT_DIR)/$(PYTHON_DIR-macOS)/_install/bin:$(PATH)',
'\t\tPATH="$(PROJECT_DIR)/$(PYTHON_DIR-macOS)/_install/bin:$(PATH)"')
# Turn doc strings on; looks like it only adds a few hundred k. # Turn doc strings on; looks like it only adds a few hundred k.
txt = replace_exact(txt, txt = replace_exact(txt,
'--without-doc-strings', '--without-doc-strings',