lang updates and cache functionality for LogHandler

This commit is contained in:
Eric 2022-09-15 12:40:56 -07:00
parent 3816f1dcb9
commit d3f3679473
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
10 changed files with 152 additions and 79 deletions

View File

@ -420,8 +420,8 @@
"assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/60/ad/38269b7f1c7dc20cb9a506cd0681", "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/60/ad/38269b7f1c7dc20cb9a506cd0681",
"assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/72/85/d6fc4d16b7081d91fba2850b5b10", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/72/85/d6fc4d16b7081d91fba2850b5b10",
"assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/e9/ae/1d674d0c086eaa0bd1c3b1db0505", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/e9/ae/1d674d0c086eaa0bd1c3b1db0505",
"assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/e8/42/a43c158be7fa45f2c0c3d4b84a1f", "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/d4/64/6fff42a428e5c775795c081474e6",
"assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/5b/cf/4501b151257c3d8d6ee8d0497d14", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/e2/24/5e7ea9ca5c9de4d3b7a28e53564d",
"assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/61/03/89070ca765e06da3a419a579f503", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/61/03/89070ca765e06da3a419a579f503",
"assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/f8/15/e1a2fa38697417bcf2cf19cd34ef", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/f8/15/e1a2fa38697417bcf2cf19cd34ef",
"assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/44/aa/c12568afb4558dc7f9f2fa155467", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/44/aa/c12568afb4558dc7f9f2fa155467",
@ -431,17 +431,17 @@
"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/72/80/d6395c8a168558750c0d79ce769b", "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/72/80/d6395c8a168558750c0d79ce769b",
"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/8f/73/093120ae2241d8f4b899ccda2d75", "assets/build/ba_data/data/languages/filipino.json": "https://files.ballistica.net/cache/ba1/e9/07/b2dc862601bcd70701b083d43279",
"assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/25/65/1cb03566e73811fc6e1b841d9072", "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/2e/48/b0a8fafc5e5436e99d9a3d697d23",
"assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/ef/e6/d4909f571d7473fd04055728490e", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/ef/e6/d4909f571d7473fd04055728490e",
"assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/8a/2a/b2bc00eed0608b2199b2bc379b2e", "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/8a/2a/b2bc00eed0608b2199b2bc379b2e",
"assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/82/eb/37ff44af76812097f9c98f05c730", "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/50/e8/837be1324c8128507b3df89b689f", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/91/98/42701cd595c2f70b7484614a8f49",
"assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/d8/f2/aa16bc336bd7660cc86c3264bfc4", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/d8/f2/aa16bc336bd7660cc86c3264bfc4",
"assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/e3/85/14e57e3f49505e5a190daf7fe276", "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/23/3b/26e9be528460af952a11e98c3b68",
"assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/1a/10/9563348e729d1e5c8ae8c9cbc1f2", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/1a/10/9563348e729d1e5c8ae8c9cbc1f2",
"assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/a8/e9/171a904f1331fdb7b1918a0f2598", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/a8/e9/171a904f1331fdb7b1918a0f2598",
"assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/83/4a/ec10142ac479bf8d80455b47a62b", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/df/b1/b2c9ebaad5e873ebedd365726d3d",
"assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/19/e9/59c891b1fb85f3ba9f19283c233d", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/19/e9/59c891b1fb85f3ba9f19283c233d",
"assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/da/95/36797ec53a697a04e55b225a701d", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/da/95/36797ec53a697a04e55b225a701d",
"assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/d7/06/9d70642d0a4d1e3b1c2149d7a17c", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/d7/06/9d70642d0a4d1e3b1c2149d7a17c",
@ -452,7 +452,7 @@
"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/94/1a/533bc718e676191bafc25e2dc98f", "assets/build/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/94/1a/533bc718e676191bafc25e2dc98f",
"assets/build/ba_data/data/languages/thai.json": "https://files.ballistica.net/cache/ba1/f7/df/7ba5f99c5c2c4c86fc0503fcf0b7", "assets/build/ba_data/data/languages/thai.json": "https://files.ballistica.net/cache/ba1/f7/df/7ba5f99c5c2c4c86fc0503fcf0b7",
"assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/14/a0/783cc6da2d122e9a7482c6a5ef8c", "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/9a/90/8e2ed626def09f88c3b9ab5215a3",
"assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/ab/35/644e4239cfa62a597a905412b90c", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/ab/35/644e4239cfa62a597a905412b90c",
"assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/53/9e/068074156b38bab7f732977a4031", "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/53/9e/068074156b38bab7f732977a4031",
"assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/25/13/b64b849fc9fedcc18d81f6e08c4d", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/25/13/b64b849fc9fedcc18d81f6e08c4d",
@ -3995,26 +3995,26 @@
"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/15/b2/0744afc264f1e55a5944bf8ae964", "build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f3/e1/0ee9ade5e9943dc4749aa4cc2182",
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8e/98/ea10bd892f89c7ba5aec76721667", "build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/32/4e/a7c1b096c62864641a59e65e7778",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/aa/e4/7c73515c9044e051a5d07cb1e964", "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6a/f4/8b86611cbaa7237c8a52e8fe6428",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/37/245e7c3dc79588d73a57f9f08b55", "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/13/f5/fa3c97269613316994f0c2134860",
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ad/28/034d014eea6aeba4b67d51cfc262", "build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f8/7a/87877003ee3a13ff7cbbf1ec76a2",
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/77/df/c85dfe5cb062b6925da7df8e740c", "build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/81/0c/708a16fff55ee37338b2d87f7620",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/58/6b/058b05227950f5d83f23b01617d1", "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4a/91/89523b8f155261e0045a6bb6e277",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bd/31/02ecb4d8c3bea8eb68d92befdd9d", "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a9/04/da76c8e848852fef1e58577f59e3",
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/aa/9d/96555101ebf8b14223b7639cea5b", "build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/dd/ac/33aed9cc1396ccba2111dfed02f6",
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1d/9a/16feda78b815cbed47b89983c48e", "build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1a/5a/0f1e671137a2ec60c2df8e95e078",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b0/31/f60dc64681a35406595ed4836f0a", "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/92/50/ec5fbb3f8b9f4a60934f2dacf180",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b5/44/eb4645945794253446c55dc682bc", "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7c/77/a430bf182d5210792716b6dbd8ee",
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/43/56/592cd419bfad9cbbb6e3f57c1007", "build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/6b/de6c811fa70bf4d5d1cdfe49eaae",
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c6/55/0dfcc3d90a9cee9212e2e10a91b1", "build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/92/e0/b9b1053231d7323d185298f8caaa",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/19/c6/994729e095b54e6963ac2d4bbd10", "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/08/ef/c70efcd89a666758437f0736d956",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ce/21/77cd76cd1b0307ae8cc7038152e7", "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9d/94/1f0d32c943b64ff558f28ad89653",
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a9/e6/23835561d55b6c1d1862217fc115", "build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a6/fb/a6e6a78d7b04d547c9c716ff0a8e",
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/21/3d/e0a1e20ae12dd7b5ba1d61aed074", "build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5a/b0/d0e087fcdf1756a0b9b5bf805f10",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/be/b5/fc827900f411576b992fc15a25fc", "build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/34/fb/e6c9fb0e20af0ba3376ca2abba29",
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/6f/51/d6a0951b6ab9122dd99ef33d4427", "build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/b1/8b/5ba626c39ef586f3ba4bfd508181",
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d5/f6/d62e6e6d5e7fe1945f08ccbb9a8f", "build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d5/f6/d62e6e6d5e7fe1945f08ccbb9a8f",
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/02/c5/44d0082442b06153a7d7dce4c8ce", "build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/02/c5/44d0082442b06153a7d7dce4c8ce",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d0/00/61378fb26ddcbf023fd3c40e4ffb", "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d0/00/61378fb26ddcbf023fd3c40e4ffb",
@ -4031,14 +4031,14 @@
"build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ff/26/da4a58abecf5d9275477eaec0c17", "build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ff/26/da4a58abecf5d9275477eaec0c17",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/62/5d/8658a206b8c9b741be2422162784", "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/62/5d/8658a206b8c9b741be2422162784",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fc/57/d59920e098d23a2d150c899cde29", "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fc/57/d59920e098d23a2d150c899cde29",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/fb/8e/3bb1c858451a447f1a102d77c281", "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/39/a1/bce547622da143fcf9ea970cd3ab",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/ae/ad/13ae735e45d31d2944c89e8bdcec", "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/d6/f3/8ca052a667342e316fa09655bc51",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/e8/3e/6c2546278ad0428965a05c9bd536", "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/e0/b4/99c403ccbfd0c4b9b071e656d480",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/d4/e5/0fe217cac5837cf663c7c7f1aa92", "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/11/a0/e06103dae63a4648850bd089aacb",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/ea/38/a5082d73202113900166a1ebd15f", "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/77/17/99eba0c7d42a9452306f7927ae4e",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/ba/1c/16df69d156e23ab29e2c84465bd7", "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/92/da/2faf9031e7c5ba5a99dd9e0c609d",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/9e/b0/91b2e0b1dbd4541543f3f147bc06", "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/64/2a/1b30ee7b4e8238ec2ea16bcacdeb",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/c1/04/ad892d77317be76bc8fa035f9e86", "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/41/92/35b689da32ee45a4e7483feae8f8",
"src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/c0/32/b7907e3859a5c5013a3d97b6b523", "src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/c0/32/b7907e3859a5c5013a3d97b6b523",
"src/ballistica/generated/python_embedded/bootstrap.inc": "https://files.ballistica.net/cache/ba1/2d/4f/f4fe67827f36cd59cd5193333a02", "src/ballistica/generated/python_embedded/bootstrap.inc": "https://files.ballistica.net/cache/ba1/2d/4f/f4fe67827f36cd59cd5193333a02",
"src/ballistica/generated/python_embedded/bootstrap_monolithic.inc": "https://files.ballistica.net/cache/ba1/ef/c1/aa5f1aa10af89f5c0b1e616355fd" "src/ballistica/generated/python_embedded/bootstrap_monolithic.inc": "https://files.ballistica.net/cache/ba1/ef/c1/aa5f1aa10af89f5c0b1e616355fd"

View File

@ -1,4 +1,4 @@
### 1.7.7 (build 20856, api 7, 2022-09-15) ### 1.7.7 (build 20857, api 7, 2022-09-15)
- Added `ba.app.meta.load_exported_classes()` for loading classes discovered by the meta subsystem cleanly in a background thread. - Added `ba.app.meta.load_exported_classes()` for loading classes discovered by the meta subsystem cleanly in a background thread.
- Improved logging of missing playlist game types. - Improved logging of missing playlist game types.
- Some ba.Lstr functionality can now be used in background threads. - Some ba.Lstr functionality can now be used in background threads.

View File

@ -1 +1 @@
76251027805752156826413428926087661089 41453813326605937968225345803585801012

View File

@ -2518,11 +2518,12 @@ def screenmessage(message: str | ba.Lstr,
Category: **General Utility Functions** Category: **General Utility Functions**
If 'top' is True, the message will go to the top message area. If 'top' is True, the message will go to the top message area.
For 'top' messages, 'image' can be a texture to display alongside the For 'top' messages, 'image' must be a dict containing 'texture'
message. and 'tint_texture' textures and 'tint_color' and 'tint2_color'
If 'log' is True, the message will also be printed to the output log colors. This defines an icon to display alongside the message.
'clients' can be a list of client-ids the message should be sent to, If 'log' is True, the message will also be submitted to the log.
or None to specify that everyone should receive it. 'clients' can be a list of client-ids the message should be sent
to, or None to specify that everyone should receive it.
If 'transient' is True, the message will not be included in the If 'transient' is True, the message will not be included in the
game-stream and thus will not show up when viewing replays. game-stream and thus will not show up when viewing replays.
Currently the 'clients' option only works for transient messages. Currently the 'clients' option only works for transient messages.

View File

@ -35,7 +35,8 @@ def bootstrap() -> None:
log_handler = setup_logging(log_path=None, log_handler = setup_logging(log_path=None,
level=LogLevel.DEBUG, level=LogLevel.DEBUG,
suppress_non_root_debug=True, suppress_non_root_debug=True,
log_stdout_stderr=True) log_stdout_stderr=True,
cache_size_limit=1024 * 1024)
log_handler.add_callback(_on_log) log_handler.add_callback(_on_log)
@ -43,7 +44,7 @@ def bootstrap() -> None:
# Give a soft warning if we're being used with a different binary # Give a soft warning if we're being used with a different binary
# version than we expect. # version than we expect.
expected_build = 20856 expected_build = 20857
running_build: int = env['build_number'] running_build: int = env['build_number']
if running_build != expected_build: if running_build != expected_build:
print( print(

View File

@ -32,7 +32,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 = 20856; const int kAppBuildNumber = 20857;
const char* kAppVersion = "1.7.7"; const char* kAppVersion = "1.7.7";
// Our standalone globals. // Our standalone globals.

View File

@ -19,9 +19,9 @@ namespace ballistica {
const int kMaxPartyNameCombinedSize = 25; const int kMaxPartyNameCombinedSize = 25;
/// The Game Module generally runs on a dedicated thread; it manages /// The logic subsystem of the app. This runs on a dedicated thread
/// all game logic, builds frame_defs to send to the graphics-server for /// and is where high level app logic happens. Much app functionality
/// rendering, etc. /// including UI calls must be run on the logic thread.
class Logic { class Logic {
public: public:
Logic(); Logic();

View File

@ -988,14 +988,12 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
"Category: **General Utility Functions**\n" "Category: **General Utility Functions**\n"
"\n" "\n"
"If 'top' is True, the message will go to the top message area.\n" "If 'top' is True, the message will go to the top message area.\n"
"For 'top' messages, 'image' can be a texture to display alongside " "For 'top' messages, 'image' must be a dict containing 'texture'\n"
"the\n" "and 'tint_texture' textures and 'tint_color' and 'tint2_color'\n"
"message.\n" "colors. This defines an icon to display alongside the message.\n"
"If 'log' is True, the message will also be printed to the output " "If 'log' is True, the message will also be submitted to the log.\n"
"log\n" "'clients' can be a list of client-ids the message should be sent\n"
"'clients' can be a list of client-ids the message should be sent " "to, or None to specify that everyone should receive it.\n"
"to,\n"
"or None to specify that everyone should receive it.\n"
"If 'transient' is True, the message will not be included in the\n" "If 'transient' is True, the message will not be included in the\n"
"game-stream and thus will not show up when viewing replays.\n" "game-stream and thus will not show up when viewing replays.\n"
"Currently the 'clients' option only works for transient messages."}, "Currently the 'clients' option only works for transient messages."},

View File

@ -70,7 +70,7 @@ namespace ballistica {
auto Python::LoggingCall(LogLevel loglevel, const std::string& msg) -> void { auto Python::LoggingCall(LogLevel loglevel, const std::string& msg) -> void {
// If we've not yet captured our Python logging calls, stash this call away. // If we've not yet captured our Python logging calls, stash this call away.
// We'll submit all accumulated entries after we bootstrap python. // We'll submit all accumulated entries after we bootstrap Python.
if (!objexists(ObjID::kLoggingCriticalCall)) { if (!objexists(ObjID::kLoggingCriticalCall)) {
std::scoped_lock lock(early_log_lock_); std::scoped_lock lock(early_log_lock_);
early_logs_.emplace_back(std::make_pair(loglevel, msg)); early_logs_.emplace_back(std::make_pair(loglevel, msg));

View File

@ -67,6 +67,21 @@ class LogEntry:
time: Annotated[datetime.datetime, IOAttrs('t')] time: Annotated[datetime.datetime, IOAttrs('t')]
@ioprepped
@dataclass
class LogArchive:
"""Info and data for a log."""
# Total number of entries submitted to the log.
log_size: Annotated[int, IOAttrs('t')]
# Offset for the entries contained here.
# (10 means our first entry is the 10th in the log, etc.)
start_index: Annotated[int, IOAttrs('c')]
entries: Annotated[list[LogEntry], IOAttrs('e')]
class LogHandler(logging.Handler): class LogHandler(logging.Handler):
"""Fancy-pants handler for logging output. """Fancy-pants handler for logging output.
@ -83,7 +98,8 @@ class LogHandler(logging.Handler):
def __init__(self, def __init__(self,
path: str | Path | None, path: str | Path | None,
echofile: TextIO | None, echofile: TextIO | None,
suppress_non_root_debug: bool = False): suppress_non_root_debug: bool = False,
cache_size_limit: int = 0):
super().__init__() super().__init__()
# pylint: disable=consider-using-with # pylint: disable=consider-using-with
self._file = (None self._file = (None
@ -97,14 +113,20 @@ class LogHandler(logging.Handler):
'stdout': None, 'stdout': None,
'stderr': None 'stderr': None
} }
self._cache_size = 0
assert cache_size_limit >= 0
self._cache_size_limit = cache_size_limit
self._cache: list[tuple[int, LogEntry]] = []
self._cache_index_offset = 0
self._cache_lock = Lock()
self._printed_callback_error = False self._printed_callback_error = False
self._thread_bootstrapped = False self._thread_bootstrapped = False
self._thread = Thread(target=self._thread_main, daemon=True) self._thread = Thread(target=self._thread_main, daemon=True)
self._thread.start() self._thread.start()
# Spin until our thread has set up its basic stuff; # Spin until our thread is up and running; otherwise we could
# otherwise we could wind up trying to push stuff to our # wind up trying to push stuff to our event loop before the
# event loop before the loop exists. # loop exists.
while not self._thread_bootstrapped: while not self._thread_bootstrapped:
time.sleep(0.001) time.sleep(0.001)
@ -124,6 +146,37 @@ class LogHandler(logging.Handler):
self._thread_bootstrapped = True self._thread_bootstrapped = True
self._event_loop.run_forever() self._event_loop.run_forever()
def get_archive(self,
start_index: int = 0,
max_entries: int | None = None) -> LogArchive:
"""Build and return an archive of log entries.
This will only return entries that have been processed by the
background thread so may not include just-submitted logs.
Entries in the range [start_index:start_index+max_entries] that
are still in the cache will be returned. Be aware that this may
not be the full requested range.
"""
assert start_index >= 0
if max_entries is not None:
assert max_entries >= 0
with self._cache_lock:
# Transform start_index to our present cache space.
start_index -= self._cache_index_offset
# Calc end-index in our present cache space.
end_index = (len(self._cache)
if max_entries is None else start_index + max_entries)
# Clamp both indexes to both ends of our present space.
start_index = max(0, min(start_index, len(self._cache)))
end_index = max(0, min(end_index, len(self._cache)))
return LogArchive(
log_size=self._cache_index_offset + len(self._cache),
start_index=start_index + self._cache_index_offset,
entries=[e[1] for e in self._cache[start_index:end_index]])
def emit(self, record: logging.LogRecord) -> None: def emit(self, record: logging.LogRecord) -> None:
# Called by logging to send us records. # Called by logging to send us records.
# We simply package them up and ship them to our thread. # We simply package them up and ship them to our thread.
@ -143,22 +196,23 @@ class LogHandler(logging.Handler):
# didn't expect to be stringified. # didn't expect to be stringified.
msg = self.format(record) msg = self.format(record)
# Also print pretty colored output to our echo file (generally # Also immediately print pretty colored output to our echo file
# stderr). We do this part here instead of in our bg thread # (generally stderr). We do this part here instead of in our bg
# because the delay can throw off command line prompts or make # thread because the delay can throw off command line prompts or
# tight debugging harder. # make tight debugging harder.
if self._echofile is not None: if self._echofile is not None:
cbegin: str ends = LEVELNO_COLOR_CODES.get(record.levelno)
cend: str if ends is not None:
cbegin, cend = LEVELNO_COLOR_CODES.get(record.levelno, ('', '')) self._echofile.write(f'{ends[0]}{msg}{ends[1]}\n')
self._echofile.write(f'{cbegin}{msg}{cend}\n') else:
self._echofile.write(f'{msg}\n')
self._event_loop.call_soon_threadsafe( self._event_loop.call_soon_threadsafe(
tpartial(self._emit_in_loop, record.name, record.levelno, tpartial(self._emit_in_thread, record.name, record.levelno,
record.created, msg)) record.created, msg))
def _emit_in_loop(self, name: str, levelno: int, created: float, def _emit_in_thread(self, name: str, levelno: int, created: float,
message: str) -> None: message: str) -> None:
try: try:
self._emit_entry( self._emit_entry(
LogEntry(name=name, LogEntry(name=name,
@ -174,9 +228,9 @@ class LogHandler(logging.Handler):
"""Send raw stdout/stderr output to the logger to be collated.""" """Send raw stdout/stderr output to the logger to be collated."""
self._event_loop.call_soon_threadsafe( self._event_loop.call_soon_threadsafe(
tpartial(self._file_write_in_loop, name, output)) tpartial(self._file_write_in_thread, name, output))
def _file_write_in_loop(self, name: str, output: str) -> None: def _file_write_in_thread(self, name: str, output: str) -> None:
try: try:
assert name in ('stdout', 'stderr') assert name in ('stdout', 'stderr')
@ -222,9 +276,26 @@ class LogHandler(logging.Handler):
self._file_chunk_ship_task[name] = None self._file_chunk_ship_task[name] = None
def _emit_entry(self, entry: LogEntry) -> None: def _emit_entry(self, entry: LogEntry) -> None:
# This runs in our bg event loop thread and does most of the work.
assert current_thread() is self._thread assert current_thread() is self._thread
# Store to our cache.
if self._cache_size_limit > 0:
with self._cache_lock:
# Do a rough calc of how many bytes this entry consumes.
entry_size = sum(
sys.getsizeof(x)
for x in (entry, entry.name, entry.message, entry.level,
entry.time))
self._cache.append((entry_size, entry))
self._cache_size += entry_size
# Prune old until we are back at or under our limit.
while self._cache_size > self._cache_size_limit:
popped = self._cache.pop(0)
self._cache_size -= popped[0]
self._cache_index_offset += 1
# Pass to callbacks.
with self._callbacks_lock: with self._callbacks_lock:
for call in self._callbacks: for call in self._callbacks:
try: try:
@ -271,11 +342,12 @@ class FileLogEcho:
def setup_logging(log_path: str | Path | None, def setup_logging(log_path: str | Path | None,
level: LogLevel, level: LogLevel,
suppress_non_root_debug: bool = False, suppress_non_root_debug: bool = False,
log_stdout_stderr: bool = False) -> LogHandler: log_stdout_stderr: bool = False,
cache_size_limit: int = 0) -> LogHandler:
"""Set up our logging environment. """Set up our logging environment.
Returns the custom handler which can be used to fetch information Returns the custom handler which can be used to fetch information
about logs that have passed through it. (worst log-levels, etc.). about logs that have passed through it. (worst log-levels, caches, etc.).
""" """
lmap = { lmap = {
@ -295,7 +367,8 @@ def setup_logging(log_path: str | Path | None,
loghandler = LogHandler( loghandler = LogHandler(
log_path, log_path,
echofile=sys.stderr if sys.stderr.isatty() else None, echofile=sys.stderr if sys.stderr.isatty() else None,
suppress_non_root_debug=suppress_non_root_debug) suppress_non_root_debug=suppress_non_root_debug,
cache_size_limit=cache_size_limit)
# Note: going ahead with force=True here so that we replace any # Note: going ahead with force=True here so that we replace any
# existing logger. Though we warn if it looks like we are doing # existing logger. Though we warn if it looks like we are doing