Language updates and minor bug fixes

This commit is contained in:
Eric Froemling 2022-07-14 14:33:48 -07:00
parent 3f427c7747
commit 738bad8852
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
17 changed files with 220 additions and 149 deletions

View File

@ -420,39 +420,39 @@
"assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/d5/f8/de3b22ac60d0caee44369117c8db",
"assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/c7/37/660e2ceca8b9b2db2cfce5a9f6f0",
"assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/d9/82/92157cb4f21fdd8c911eec910ad4",
"assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/4b/50/f349b757f92f6362a39f70ea7a80",
"assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/45/70/91f386517fa3dc7322e1345ee1ab",
"assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/25/20/31a26a4899e68dd9a0c6c272b998",
"assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/a5/48/9e4424d04b273c8bdc25f9be4b6e",
"assets/build/ba_data/data/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/55/93/1f358b653e9a347593d9b23f0061",
"assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/fa/2e/fe2446e2dab7d8c7cf18a39b4b8e",
"assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/60/48/bf681053e91e38d0f4c4b1f8f1a6",
"assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/6c/2b/7a0669cc74fbcebbb76c440c6c04",
"assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/61/77/ae85d46474923707f8a7190849a2",
"assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28",
"assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/68/93/da8e9874f41a786edf52ba4ccaad",
"assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/13/42/9585944a58dd340611373a48732f",
"assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/11/26/c3dfae5a52f337529c4ea129237c",
"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/a6/43/180ad35f294f7087661479687a12",
"assets/build/ba_data/data/languages/filipino.json": "https://files.ballistica.net/cache/ba1/ac/ec/2677e8fd26c395a5032d7d6e7aa1",
"assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/b6/e0/37dd30b686f475733ccc4b3cab49",
"assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/c0/26/04875251b9237f3133c84a910afd",
"assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/f6/5c/591661f58ee2cf4a78fd8fa54bed",
"assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/45/5c/abf0567aaea410b43783453eba5f",
"assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/82/eb/37ff44af76812097f9c98f05c730",
"assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/08/3b/68cea4d16f7020d932829af85323",
"assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/b0/48/e1ebe08bfdfc94fcb61a16b851e5",
"assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/75/70/e33e6ee95830052e8f36cd2135f7",
"assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/f3/11/d81cc9f0c76b81b0b8dcf64fe292",
"assets/build/ba_data/data/languages/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/1b/45/b1e45fe07e0d632e979a9433dadd",
"assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/37/90/0350db0bd1e98215fde8ee3f4059",
"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/08/be/543b564010ad45e191d6ff5f130b",
"assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/df/30/9ab2f22cdd54f0393a7d2aba2ae0",
"assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/f2/41/d4f06aabfc3499534e04fedb10dd",
"assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/13/19/828be486951be254445263f36c6e",
"assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/a6/ad/7ee52772db14f9008044bb877ed1",
"assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/d7/06/9d70642d0a4d1e3b1c2149d7a17c",
"assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/6c/46/292406974d45fd9a92e40022b443",
"assets/build/ba_data/data/languages/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/bc/93/b5d78fcd8cdffda7f3d9cc238cef",
"assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/80/d7/bd62eacc2ec901e145e37168c737",
"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/9f/2c/367db6734a89603ed45534fccb14",
"assets/build/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/55/46/61fa6c9a93f6c0d57529d7949190",
"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/7e/d0/b21f8bcdc7f2727a6e68af3d0e68",
"assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/c0/4e/c8a66ed415b8b0ce3ff30462b2a2",
"assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/7f/bb/6239adeb551be5e09f3457d7b411",
"assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/68/77/cc871b6ed611cb8d6f74cf1a9d00",
"assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/f2/af/afd1503c7a10cacaa15bc02369b2",
@ -3995,50 +3995,50 @@
"assets/src/ba_data/python/ba/_generated/__init__.py": "https://files.ballistica.net/cache/ba1/ee/e8/cad05aa531c7faf7ff7b96db7f6e",
"assets/src/ba_data/python/ba/_generated/enums.py": "https://files.ballistica.net/cache/ba1/b2/e5/0ee0561e16257a32830645239f34",
"ballisticacore-windows/Generic/BallisticaCore.ico": "https://files.ballistica.net/cache/ba1/89/c0/e32c7d2a35dc9aef57cc73b0911a",
"build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e2/e0/7e12f13ce528c828ae8c482ac1c5",
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a4/cd/a23c971748bee4c4726192d892e6",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/04/c6/240b3031c13ca7df990e5c867e82",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/58/c4/339c89e00d13ed26f2b83ace0053",
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d6/fa/9d66b57832c3155899fda3b9ed2d",
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3a/7f/df248f9fcab1f0a6b3188de679f1",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4a/a2/a9e03eabf8dce07d7d150dbe533f",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/12/c4/672108a20af3efd292f0f19cb6d1",
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f9/70/991734c16666f041ec26fd3d24fc",
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3f/1d/5867b2567b0b5092898c79ba13c6",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/46/b7/69773f4298626ff327680db9aa26",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/03/75/f2f6bb1c9eebf8c3eecb44fd76b5",
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b7/40/3c89c40a3522c5533bf567b86005",
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6c/0f/982997d664d258a9f2dd7d100447",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d0/52/a06b3b9ec34d78c27ece18dfc04c",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/51/e7/5d1b3acd640935f2d262adf9f56e",
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/57/d4/79d1653f278e083ff3d970b345e5",
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/0b/ce/5aef8c58b6120549ac677c0aa83a",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/5b/57/68e576ff9ceed03102d2ef199a23",
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/53/77/fb69f8b5475e0ab5fb5c028fda1c",
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3c/08/bcb4ce1689de4f0a4ffe1d7c542f",
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/67/44/8916488c91538d83248f0ec5a2e5",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8c/d7/6ff4bfa3bb6805fa812fb023876e",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c1/f0/a26ed674437c26c8af557c10fc25",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b9/b0/e3a2098f4324d361135d140c7d16",
"build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/98/d2/25ea99e21ab82489758ad2f4eda1",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/18/d3/b3fa835ed6fce67f22513718fcf5",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/74/37/d65ed9c851e97a4c16f99ce4b996",
"build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/85/4a/c04a061403b47b26c2fe477bce5b",
"build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/04/37/dd511de9d333afd4f77c8a37d11c",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/2d/40/33c32f48b5ec2ff940d8ed114e0f",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/55/f7/3f6a200eae7baf961a9ba3d1857d",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fd/e8/af76c5dccfe324c6081185f5e8f0",
"build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/aa/c5/159b01f8dc8a4201dec430c77a5c",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c3/ec/f087eff8388ef3f0a16699bb44b3",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/64/98/01a2649fa88ad6513e8c36d3ac04",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/ee/67/86f37883c1d82436296c107cb0af",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/b6/0a/288ab61d465b4901cf7112a241c9",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/73/88/561fac00c0eb27f6b451322cf777",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/e6/11/73127ddbd3a779076770a7448ce1",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/2a/3c/ef57604bb8e94075d74eafe258e3",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/5d/ca/0e6d9a2ac4d0f750b8295b6d775e",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/ff/e3/f03bc482b4e305288e7418acb38a",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/8a/33/713bfca4012f0d1b7b7b4e896d46",
"src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/6e/6f/004b696e9a13b083069374e4bb6a",
"build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2f/ec/756d728d0a912a0a0ce1e46b3351",
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/2e/d8/41fb2f73f9b915e809a3d8671c45",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/51/a9/931e229fed568facc7d77b407a9a",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9c/f3/aef423feb4f5e91ce72fb5a25fa0",
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/cd/c2/f5f0a7ae3197fe5f05bfcee3a3e3",
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4f/dc/2a1a296dddd5d5fef6b2f0bef6e8",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c6/4c/e1274ac12ae7a0a60d02686abc0b",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6c/b1/f56d3edb7c6efa23518b78b74846",
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/87/b2/0a85ffc1ed64724da5663086a2a9",
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/bc/95/67636889721c129a697a55fc47c2",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/59/8f/0bfe1878a0941351294b2306b2ad",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/de/43/bfab4d3fda82d02e97207f5be4cd",
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/39/d0/6bb26d2fce1d6f8644191217c00c",
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/80/33/fc11bdaba571fc91429518881081",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/be/9d/9e39fc8085e1061d016e9ea242a6",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8a/aa/fef783198a65c064b1c8be235307",
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/87/4b/06fca73ff1a1c22f92f462c8e539",
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/97/32/95378dfe465d38aa3bbebb932669",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/e3/af/8e86cf496985267f69a98613eb15",
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/3a/4a/2860a58d8b460ca6ff8243a0f185",
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c3/a5/d77c0da95027f6c6b2158d554692",
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/92/93/d343eb8e8783494d8d04949fcd34",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/65/26/c623cadc48e151bf438579730e33",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/cc/32/eb7bd9b981c303d59ec32efc46b7",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7a/9a/43e14da4b3ec46f69fd710d4daba",
"build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a4/c1/e4548f2abcba4c48e713dd24e2fd",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/69/79/8e676bba0b03ed522c2475bb07b4",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/69/97/6119b7a2dd5c1f3fbcb2d921652d",
"build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/73/53/98ea7844b411cbc99a347213410f",
"build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/74/78/9b5b9048e0fcb3f6283983046cd8",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7a/1a/503e5789b08c3a85bb34bebccdf8",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/04/cf/a70ffac469d5bbc2ba9d56ebffcb",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6f/e6/66090d68d391eba428a6b5d146e5",
"build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/2f/4c/d59f4dd0c41e1cb3f32f3864e8cc",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/16/9c/bda065fbb75646796383ff4c0490",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8c/56/b6f1a19cda20dada065f0f43cd83",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/f4/76/36e047c715c69980bf53f47cc03b",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/83/03/e08562ec65eba9577c9fbe1a98b0",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/26/08/755cd4f6d908359e0a7d33a5f9dd",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/bd/d7/0de5664c35680f40a9c8efbc264b",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/e9/65/0693588e1b04bff51d197c77e6c6",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/bd/b1/866126ff56ab9c6148b750282295",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/ef/47/19efea33fdbd69c376f35b590e3b",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/5b/e6/174649077bcc202ead74e7e5bf4d",
"src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/7d/3e/229a581cb2454ed856f1d8b564a7",
"src/ballistica/generated/python_embedded/bootstrap.inc": "https://files.ballistica.net/cache/ba1/d3/db/e73d4dcf1280d5f677c3cf8b47c3"
}

View File

@ -1,4 +1,8 @@
### 1.7.5 (20648, 2022-07-12)
### 1.7.5 (20650, 2022-07-14)
- Android build now uses the ReLinker library to load the native main.so, which will (hopefully) avoid some random load failures on older Android versions.
- Android Google Play build now prints a message at launch if the billing library isn't available or needs to be updated (explaining why purchases won't work in that case).
- Various minor bug fixes (mostly cleaning up unnecessary error logging)
- Updated Android builds to use the new NDK 25 release
### 1.7.4 (20646, 2022-07-12)
- Fixed the trophies list showing an incorrect total (Thanks itsre3!)

View File

@ -204,6 +204,12 @@ def no_game_circle_message() -> None:
_ba.screenmessage(Lstr(resource='noGameCircleText'), color=(1, 0, 0))
def google_play_purchases_not_available_message() -> None:
from ba._language import Lstr
_ba.screenmessage(Lstr(resource='googlePlayPurchasesNotAvailableText'),
color=(1, 0, 0))
def empty_call() -> None:
pass

View File

@ -127,29 +127,33 @@ class MasterServerCallThread(threading.Thread):
self._callback(arg)
def run(self) -> None:
# pylint: disable=too-many-branches, consider-using-with
# pylint: disable=consider-using-with
import urllib.request
import urllib.parse
import urllib.error
import json
from efro.error import is_urllib_network_error
from efro.error import is_urllib_communication_error
from ba import _general
response_data: Any = None
url: str | None = None
try:
self._data = _general.utf8_all(self._data)
_ba.set_thread_name('BA_ServerCallThread')
if self._request_type == 'get':
url = (_ba.get_master_server_address() + '/' + self._request +
'?' + urllib.parse.urlencode(self._data))
response = urllib.request.urlopen(
urllib.request.Request(
(_ba.get_master_server_address() + '/' +
self._request + '?' +
urllib.parse.urlencode(self._data)), None,
{'User-Agent': _ba.app.user_agent_string}),
url, None, {'User-Agent': _ba.app.user_agent_string}),
context=_ba.app.net.sslcontext,
timeout=DEFAULT_REQUEST_TIMEOUT_SECONDS)
elif self._request_type == 'post':
url = _ba.get_master_server_address() + '/' + self._request
response = urllib.request.urlopen(
urllib.request.Request(
_ba.get_master_server_address() + '/' + self._request,
url,
urllib.parse.urlencode(self._data).encode(),
{'User-Agent': _ba.app.user_agent_string}),
context=_ba.app.net.sslcontext,
@ -172,29 +176,18 @@ class MasterServerCallThread(threading.Thread):
raise TypeError(f'invalid responsetype: {self._response_type}')
except Exception as exc:
do_print = False
response_data = None
# Ignore common network errors; note unexpected ones.
if is_urllib_network_error(exc):
pass
elif (self._response_type == MasterServerResponseType.JSON
and isinstance(exc, json.decoder.JSONDecodeError)):
# FIXME: should handle this better; could mean either the
# server sent us bad data or it got corrupted along the way.
pass
else:
do_print = True
if do_print:
# Any other error here is unexpected,
# so let's make a note of it,
if not is_urllib_communication_error(exc, url=url):
print(f'Error in MasterServerCallThread'
f' (response-type={self._response_type},'
f' (url={url},'
f' response-type={self._response_type},'
f' response-data={response_data}):')
import traceback
traceback.print_exc()
response_data = None
if self._callback is not None:
_ba.pushcall(_general.Call(self._run_callback, response_data),
from_other_thread=True)

View File

@ -705,8 +705,8 @@ class ManualGatherTab(GatherTab):
from_other_thread=True,
)
except Exception as exc:
from efro.error import is_udp_network_error
if is_udp_network_error(exc):
from efro.error import is_udp_communication_error
if is_udp_communication_error(exc):
ba.pushcall(ba.Call(
_safe_set_text, self._checking_state_text,
ba.Lstr(resource='gatherWindow.'

View File

@ -219,9 +219,9 @@ class AddrFetchThread(threading.Thread):
sock.close()
ba.pushcall(ba.Call(self._call, val), from_other_thread=True)
except Exception as exc:
from efro.error import is_udp_network_error
from efro.error import is_udp_communication_error
# Ignore expected network errors; log others.
if is_udp_network_error(exc):
if is_udp_communication_error(exc):
pass
else:
ba.print_exception()
@ -271,8 +271,8 @@ class PingThread(threading.Thread):
ping if accessible else None),
from_other_thread=True)
except Exception as exc:
from efro.error import is_udp_network_error
if is_udp_network_error(exc):
from efro.error import is_udp_communication_error
if is_udp_communication_error(exc):
pass
else:
ba.print_exception('Error on gather ping', once=True)

View File

@ -10,6 +10,8 @@
;; Projectile indexing and search will ignore the following
;; (in addition to git-ignored stuff which it ignores by default)
;; NOTE TO SELF: this means searches in spinoff projects will mostly fail
;; because everything is gitignored; should search in parent repo instead.
(nil . ((projectile-globally-ignored-directories . ("docs"
"submodules"
"src/external"

View File

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

View File

@ -25,10 +25,6 @@ auto FatalError::ReportFatalError(const std::string& message,
// error to the user and exiting the app cleanly (so we don't pollute our
// crash records with results of user tinkering).
// Try to avoid crash reports if we're not a clean blessed build.
// bool exit_cleanly = !IsUnmodifiedBlessedBuild();
// printf("BLESSED %d\n", static_cast<int>(IsUnmodifiedBlessedBuild()));
// Give the platform the opportunity to completely override our handling.
if (g_platform) {
auto handled =

View File

@ -195,21 +195,14 @@ auto PyExtraHashValue(PyObject* self, PyObject* args, PyObject* keywds)
const_cast<char**>(kwlist))) {
return nullptr;
}
const char* h = (g_app_globals->user_ran_commands ? "cjief3l" : "wofocj8");
const char* h =
((g_app_globals->user_ran_commands || g_app_globals->have_mods)
? "cjief3l"
: "wofocj8");
return PyUnicode_FromString(h);
BA_PYTHON_CATCH;
}
auto PySetHaveMods(PyObject* self, PyObject* args) -> PyObject* {
BA_PYTHON_TRY;
Platform::SetLastPyCall("set_have_mods");
int have_mods;
if (!PyArg_ParseTuple(args, "p", &have_mods)) return nullptr;
g_app_globals->have_mods = static_cast<bool>(have_mods);
Py_RETURN_NONE;
BA_PYTHON_CATCH;
}
auto PyGetIdleTime(PyObject* self, PyObject* args) -> PyObject* {
BA_PYTHON_TRY;
Platform::SetLastPyCall("get_idle_time");
@ -1077,11 +1070,6 @@ auto PythonMethodsSystem::GetMethods() -> std::vector<PyMethodDef> {
"\n"
"Returns the amount of time since any game input has been received."},
{"set_have_mods", PySetHaveMods, METH_VARARGS,
"set_have_mods(have_mods: bool) -> None\n"
"\n"
"(internal)"},
{"ehv", (PyCFunction)PyExtraHashValue, METH_VARARGS | METH_KEYWORDS,
"ehv() -> None\n"
"\n"

View File

@ -309,6 +309,7 @@ class Python {
kSubmitAnalyticsCountsCall,
kSetLastAdNetworkCall,
kNoGameCircleMessageCall,
kGooglePlayPurchasesNotAvailableMessageCall,
kEmptyCall,
kLevelIconPressCall,
kTrophyIconPressCall,

View File

@ -64,6 +64,7 @@ def get_binding_values() -> tuple[Any, ...]:
_hooks.submit_analytics_counts, # kSubmitAnalyticsCountsCall
_hooks.set_last_ad_network, # kSetLastAdNetworkCall
_hooks.no_game_circle_message, # kNoGameCircleMessageCall
_hooks.google_play_purchases_not_available_message, # kGooglePlayPurchasesNotAvailableMessageCall
_hooks.empty_call, # kEmptyCall
_hooks.level_icon_press, # kLevelIconPressCall
_hooks.trophy_icon_press, # kTrophyIconPressCall

View File

@ -12,7 +12,7 @@ from dataclasses import dataclass
import pytest
from efrotools.statictest import static_type_equals
from efro.error import CleanError, RemoteError
from efro.error import CleanError, RemoteError, CommunicationError
from efro.dataclassio import ioprepped
from efro.message import (Message, Response, MessageProtocol, MessageSender,
BoundMessageSender, MessageReceiver,
@ -748,6 +748,8 @@ def test_full_pipeline() -> None:
msg = _TestMessageSenderBBoth()
test_handling_unregistered = False
test_send_method_exceptions = False
test_send_method_exceptions_comm = False
def __init__(self, target: TestClassRSync | TestClassRAsync) -> None:
self.test_sidecar = False
@ -756,6 +758,13 @@ def test_full_pipeline() -> None:
@msg.send_method
def _send_raw_message(self, data: str) -> str:
"""Handle synchronous sending of raw json message data."""
# Test throwing exceptions in send methods.
if self.test_send_method_exceptions:
raise (CommunicationError()
if self.test_send_method_exceptions_comm else
RuntimeError())
# Just talk directly to the receiver for this example.
# (currently only support synchronous receivers)
assert isinstance(self._target, TestClassRSync)
@ -774,6 +783,13 @@ def test_full_pipeline() -> None:
@msg.send_async_method
async def _send_raw_message_async(self, data: str) -> str:
"""Handle asynchronous sending of raw json message data."""
# Test throwing exceptions in async send methods.
if self.test_send_method_exceptions:
raise (CommunicationError()
if self.test_send_method_exceptions_comm else
RuntimeError())
# Just talk directly to the receiver for this example.
# (we can do sync or async receivers)
if isinstance(self._target, TestClassRSync):
@ -932,3 +948,21 @@ def test_full_pipeline() -> None:
assert getattr(response1, '_sidecar_data') == 198
obj.test_sidecar = False
obj_r_sync.test_sidecar = False
# Now test errors in the raw-send function. Errors there should
# come across as either CommunicationErrors or RuntimeErrors
obj.test_send_method_exceptions = True
obj.test_send_method_exceptions_comm = False
with pytest.raises(RuntimeError):
response1 = obj.msg.send(_TMsg1(ival=0))
with pytest.raises(RuntimeError):
response4 = asyncio.run(obj.msg.send_async(_TMsg1(ival=0)))
obj.test_send_method_exceptions_comm = True
with pytest.raises(CommunicationError):
response1 = obj.msg.send(_TMsg1(ival=0))
with pytest.raises(CommunicationError):
response4 = asyncio.run(obj.msg.send_async(_TMsg1(ival=0)))
obj.test_send_method_exceptions = False

View File

@ -4,6 +4,7 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import errno
if TYPE_CHECKING:
pass
@ -39,12 +40,13 @@ class CommunicationError(Exception):
"""A communication related error has occurred.
This covers anything network-related going wrong in the sending
of data or receiving of a response. This error does not imply
of data or receiving of a response. Basically anything that is out
of our control should get lumped in here. This error does not imply
that data was not received on the other end; only that a full
acknowledgement round trip was not completed.
These errors should be gracefully handled whenever possible, as
occasional network outages are generally unavoidable.
occasional network issues are unavoidable.
"""
@ -55,9 +57,9 @@ class RemoteError(Exception):
occurs remotely. The error string can consist of a remote stack
trace or a simple message depending on the context.
Communication systems should raise more specific error types when
more introspection/control is needed; this is intended somewhat as
a catch-all.
Communication systems should raise more specific error types locally
when more introspection/control is needed; this is intended somewhat
as a catch-all.
"""
def __str__(self) -> str:
@ -69,31 +71,43 @@ class IntegrityError(ValueError):
"""Data has been tampered with or corrupted in some form."""
def is_urllib_network_error(exc: BaseException) -> bool:
"""Is the provided exception from urllib a network-related error?
def is_urllib_communication_error(exc: BaseException, url: str | None) -> bool:
"""Is the provided exception from urllib a communication-related error?
Url, if provided can provide extra context for when to treat an error
as such an error.
This should be passed an exception which resulted from opening or
reading a urllib Request. It returns True for any errors that could
conceivably arise due to unavailable/poor network connections,
firewall/connectivity issues, etc. These issues can often be safely
ignored or presented to the user as general 'network-unavailable'
states.
firewall/connectivity issues, or other issues out of our control.
These errors can often be safely ignored or presented to the user
as general 'network-unavailable' states.
"""
import urllib.error
import http.client
import errno
import socket
if isinstance(
exc,
(urllib.error.URLError, ConnectionError, http.client.IncompleteRead,
http.client.BadStatusLine, socket.timeout)):
if isinstance(exc, (urllib.error.URLError, ConnectionError,
http.client.IncompleteRead, http.client.BadStatusLine,
http.client.RemoteDisconnected, socket.timeout)):
# Special case: although an HTTPError is a subclass of URLError,
# we don't return True for it. It means we have successfully
# communicated with the server but what we are asking for is
# not there/etc.
# we don't consider it a communication error. It generally means we
# have successfully communicated with the server but what we are asking
# for is not there/etc.
if isinstance(exc, urllib.error.HTTPError):
# Special sub-case: appspot.com hosting seems to give 403 errors
# (forbidden) to some countries. I'm assuming for legal reasons?..
# Let's consider that a communication error since its out of our
# control so we don't fill up logs with it.
if exc.code == 403 and url is not None and '.appspot.com' in url:
return True
return False
return True
if isinstance(exc, OSError):
if exc.errno == 10051: # Windows unreachable network error.
return True
@ -106,18 +120,17 @@ def is_urllib_network_error(exc: BaseException) -> bool:
return False
def is_udp_network_error(exc: BaseException) -> bool:
"""Is the provided exception a network-related error?
def is_udp_communication_error(exc: BaseException) -> bool:
"""Should this udp-related exception be considered a communication error?
This should be passed an exception which resulted from creating and
using a socket.SOCK_DGRAM type socket. It should return True for any
errors that could conceivably arise due to unavailable/poor network
connections, firewall/connectivity issues, etc. These issues can often
conditions, firewall/connectivity issues, etc. These issues can often
be safely ignored or presented to the user as general
'network-unavailable' states.
"""
import errno
if isinstance(exc, ConnectionRefusedError):
if isinstance(exc, ConnectionRefusedError | TimeoutError):
return True
if isinstance(exc, OSError):
if exc.errno == 10051: # Windows unreachable network error.
@ -140,8 +153,8 @@ def is_udp_network_error(exc: BaseException) -> bool:
return False
def is_asyncio_streams_network_error(exc: BaseException) -> bool:
"""Is the provided exception a network-related error?
def is_asyncio_streams_communication_error(exc: BaseException) -> bool:
"""Should this streams error be considered a communication error?
This should be passed an exception which resulted from creating and
using asyncio streams. It should return True for any errors that could
@ -149,7 +162,6 @@ def is_asyncio_streams_network_error(exc: BaseException) -> bool:
firewall/connectivity issues, etc. These issues can often be safely
ignored or presented to the user as general 'connection-lost' events.
"""
import errno
import ssl
if isinstance(exc, (

View File

@ -56,6 +56,7 @@ class ErrorResponse(Response):
OTHER = 0
CLEAN = 1
LOCAL = 2
COMMUNICATION = 3
error_message: Annotated[str, IOAttrs('m')]
error_type: Annotated[ErrorType, IOAttrs('e')] = ErrorType.OTHER

View File

@ -9,7 +9,7 @@ from __future__ import annotations
import logging
from typing import TYPE_CHECKING, TypeVar
from efro.error import CleanError, RemoteError
from efro.error import CleanError, RemoteError, CommunicationError
from efro.message._message import EmptyResponse, ErrorResponse
if TYPE_CHECKING:
@ -35,7 +35,7 @@ class MessageSender:
def send_raw_message(self, message: str) -> str:
# Actually send the message here.
# MyMessageSender class should provide overloads for send(), send_bg(),
# MyMessageSender class should provide overloads for send(), send_async(),
# etc. to ensure all sending happens with valid types.
obj = MyClass()
obj.msg.send(SomeMessageType())
@ -54,7 +54,12 @@ class MessageSender:
def send_method(
self, call: Callable[[Any, str],
str]) -> Callable[[Any, str], str]:
"""Function decorator for setting raw send method."""
"""Function decorator for setting raw send method.
Send methods take strings and should return strings.
Any Exception raised during the send_method manifests as
a CommunicationError for the message sender.
"""
assert self._send_raw_message_call is None
self._send_raw_message_call = call
return call
@ -62,7 +67,12 @@ class MessageSender:
def send_async_method(
self, call: Callable[[Any, str], Awaitable[str]]
) -> Callable[[Any, str], Awaitable[str]]:
"""Function decorator for setting raw send-async method."""
"""Function decorator for setting raw send-async method.
Send methods take strings and should return strings.
Any Exception raised during the send_method manifests as
a CommunicationError for the message sender.
"""
assert self._send_async_raw_message_call is None
self._send_async_raw_message_call = call
return call
@ -123,7 +133,17 @@ class MessageSender:
raise RuntimeError('send() is unimplemented for this type.')
msg_encoded = self._encode_message(bound_obj, message)
response_encoded = self._send_raw_message_call(bound_obj, msg_encoded)
try:
response_encoded = self._send_raw_message_call(
bound_obj, msg_encoded)
except Exception as exc:
# Any error in the raw send call gets recorded as either
# a local or communication error.
return ErrorResponse(
error_message=f'Error in send async method: {exc}',
error_type=(ErrorResponse.ErrorType.COMMUNICATION
if isinstance(exc, CommunicationError) else
ErrorResponse.ErrorType.LOCAL))
return self._decode_raw_response(bound_obj, message, response_encoded)
async def send_split_part_1_async(self, bound_obj: Any,
@ -139,9 +159,17 @@ class MessageSender:
raise RuntimeError('send_async() is unimplemented for this type.')
msg_encoded = self._encode_message(bound_obj, message)
response_encoded = await self._send_async_raw_message_call(
bound_obj, msg_encoded)
try:
response_encoded = await self._send_async_raw_message_call(
bound_obj, msg_encoded)
except Exception as exc:
# Any error in the raw send call gets recorded as either
# a local or communication error.
return ErrorResponse(
error_message=f'Error in send async method: {exc}',
error_type=(ErrorResponse.ErrorType.COMMUNICATION
if isinstance(exc, CommunicationError) else
ErrorResponse.ErrorType.LOCAL))
return self._decode_raw_response(bound_obj, message, response_encoded)
def send_split_part_2(self, message: Message,
@ -183,8 +211,8 @@ class MessageSender:
# If we got to this point, we successfully communicated
# with the other end so errors represent protocol mismatches
# or other invalid data. For now let's just log it but perhaps
# we'd want to somehow embed it in the ErrorResponse to be raised
# directly to the user later.
# we'd want to somehow embed it in the ErrorResponse to be
# available directly to the user later.
logging.exception('Error decoding raw response')
response = ErrorResponse(
error_message=
@ -208,6 +236,10 @@ class MessageSender:
# Some error occurred. Raise a local Exception for it.
if isinstance(raw_response, ErrorResponse):
if (raw_response.error_type is
ErrorResponse.ErrorType.COMMUNICATION):
raise CommunicationError(raw_response.error_message)
# If something went wrong on our end of the connection,
# don't say it was a remote error.
if raw_response.error_type is ErrorResponse.ErrorType.LOCAL:

View File

@ -14,7 +14,8 @@ from threading import current_thread
from typing import TYPE_CHECKING, Annotated
from efro.util import assert_never
from efro.error import CommunicationError, is_asyncio_streams_network_error
from efro.error import (CommunicationError,
is_asyncio_streams_communication_error)
from efro.dataclassio import (dataclass_to_json, dataclass_from_json,
ioprepped, IOAttrs)
@ -596,7 +597,7 @@ class RPCEndpoint:
if isinstance(exc, _KeepaliveTimeoutError):
return True
return is_asyncio_streams_network_error(exc)
return is_asyncio_streams_communication_error(exc)
def _check_env(self) -> None:
# I was seeing that asyncio stuff wasn't working as expected if