logging and bug hunting

This commit is contained in:
Eric 2022-12-20 17:56:15 -08:00
parent 006156aef7
commit c296d965a2
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
16 changed files with 432 additions and 152 deletions

View File

@ -420,41 +420,41 @@
"assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/60/ad/38269b7f1c7dc20cb9a506cd0681",
"assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/72/85/d6fc4d16b7081d91fba2850b5b10",
"assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/e9/ae/1d674d0c086eaa0bd1c3b1db0505",
"assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/3c/3f/dc185a4ea8f2512770558ce0ff90",
"assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/c5/81/e386a592e4fdf702b9089f106610",
"assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/a8/a2/8c6816daac85d0b899a324509cf6",
"assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/92/43/36b34307575f6d6219bdf4898e18",
"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/8e/4f/992f2a50dbe9514d774c1bb4fd28",
"assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/aa/ed/4bd02af3cffbd4c9c4be532fb1fe",
"assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/c2/a4/993d5f0f30d0670d7053466929b6",
"assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/c9/73/01a1343af814131b1ee96af0b687",
"assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/cb/df/f2d54d3146a159c678a47d3ff01b",
"assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/4e/8c/72ddb584856a15dfb11df95f9283",
"assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/6a/fa/fcf4a804beaff927b0f12c179eaa",
"assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/68/93/da8e9874f41a786edf52ba4ccaad",
"assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/7e/e7/836562182c2056902a326f5c7b9d",
"assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/ad/85/3caf0c981389e46835862248386a",
"assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/ac/f5/c0922a99e40dfc9f5e026d43b533",
"assets/build/ba_data/data/languages/filipino.json": "https://files.ballistica.net/cache/ba1/65/3f/6f1b739feac015dc39e97675b49d",
"assets/build/ba_data/data/languages/filipino.json": "https://files.ballistica.net/cache/ba1/8e/90/3ba17e62e21919bc2fa7e46884be",
"assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/5d/2a/a5363cbe713fd67ea0baaa44403a",
"assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/27/48/4cf2f4a3dd35260ef9b3b188ccde",
"assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/63/64/8073ab02f55940292099513d341b",
"assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/cb/7b/b881356f22e5f8293a5e4b8976ae",
"assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/ee/fa/6eb38e7d4cfd13702c66d37b9723",
"assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/8a/82/392f2a4e0e6e5a5e367f19e49538",
"assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/2e/d1/b506ddf3d27af7be1ae6159531a3",
"assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/b2/81/53c8cd7617d649403e539c3a6171",
"assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/b4/51/0f993429723480691d5289c7bc5d",
"assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/30/91/9dc870d35ddca657bf07d0f88a82",
"assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/72/35/c40aee4c2f7f64fa030f83eb08d5",
"assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/7c/38/d4a44c481757d355836f292ede48",
"assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/32/97/4c61425d7c200a5c4c9ae3a94a0e",
"assets/build/ba_data/data/languages/malay.json": "https://files.ballistica.net/cache/ba1/66/32/92ae734c4358397d2e90c1c85325",
"assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/db/14/2f441ccb65023775dc8139a63f3f",
"assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/67/93/372c2a2428a830056e9ba22bbf95",
"assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/e6/fb/dfef0975c9c58cbcc621c022ec4b",
"assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/cb/96/86bb139f20e126593f7fdba9e9e1",
"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/a4/08/5e70701b63899cddf21733b0eea6",
"assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/b7/98/2523d11d09614bcfad8fa50be100",
"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/20/a9/163d189884edf802636bf291e432",
"assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/e9/6d/62090311ae9aabaaae3918ea2d5b",
"assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/d8/19/21882f76375ade330ef5a6e791a4",
"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/48/2c/78cb542498a59e3023b4838df515",
"assets/build/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/3d/83/e1bb0a664d1c14c41b1a083acf0d",
"assets/build/ba_data/data/languages/thai.json": "https://files.ballistica.net/cache/ba1/d6/16/523c643358880b03b233ed88e557",
"assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/c3/d2/d075ad07ec8d8aec3616f8760534",
"assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/73/7b/b8822b5632a8d3c7cf134e2859cc",
"assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/2a/0e/b164149e76efd0e6d591a9bf04bb",
"assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/3e/b6/052f1faed0264bf7135feb5c4cc3",
"assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/a6/ed/416638d46950c9ab4f6155b9c334",
"assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/1f/ae/abe3f105b3c4b51f6b7942773305",
"assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed",
@ -4008,50 +4008,50 @@
"assets/src/ba_data/python/ba/_generated/__init__.py": "https://files.ballistica.net/cache/ba1/ee/e8/cad05aa531c7faf7ff7b96db7f6e",
"assets/src/ba_data/python/ba/_generated/enums.py": "https://files.ballistica.net/cache/ba1/1c/77/ac670a5118abdf8a7687af0e159b",
"ballisticacore-windows/Generic/BallisticaCore.ico": "https://files.ballistica.net/cache/ba1/89/c0/e32c7d2a35dc9aef57cc73b0911a",
"build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6f/3c/b6d4e92dcbac32aa3093d9139b9d",
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/b8/31ad72ffe5df6bbedbd59eb3f02b",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d2/d9/084996631fa94337e0a92c93b753",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/89/0a/4483e91a808e4724dfbc382d6f60",
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ec/4d/6c58d9a9c5b13837d87d3d871868",
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/dd/12/2e3164bd4770a6c648e2e7dbc4f0",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fa/41/63a57ecf884cecf7ee1c8b9b2dcf",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/64/2b/0ebcdfd2f61027dcfff899d8894f",
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8f/e7/3ca7ed13d4a03013ecbb80ecb78c",
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ec/e2/ebe20cc007e87d0ede6e0ec169af",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3a/77/32299795fdb8b0c0fbc3130b7193",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c2/1a/bfaeccd961429479947ea1cb2c47",
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/43/74/b5749a746e72007f2f464b2941c6",
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/eb/e2/f97727387a3f9707b079b7b2acd0",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5f/da/6a048012e6b94a303e59b8dae61b",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f5/11/e75118e0a8f821e030f82e79c1bc",
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d2/ad/4ee541d9d19b2d6fc1dab4947a26",
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/10/2b/133d1cf611800e518d5353a10a94",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/85/53/fde7e925ac80da650a02ee078ad0",
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/96/8e/c8292f6fc6967003affeb6ca32b7",
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/28/f6/26327365481296a963bb37d58d82",
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6d/b6/4e4a46d553d1949c956e72a3617d",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/81/57/d0a2b72a86d6f7f542d07e4fba29",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ac/f5/a6350f397911c2833c35fb86aa6c",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/91/87/78eab8de6f5bc52ff10f75e9d0b5",
"build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a9/29/9cf3b260aae600ccafb535309b62",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/56/c2/75943b307817b0f23807b4f36632",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/93/51/6cf630d6ab82f8946569b96f01b5",
"build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e4/ba/31a54b98463bc261835ac9cc7c51",
"build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/64/25/bba77bfd767e14a9df46795c93bb",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f2/17/02a1053141eac72b24c323b10003",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/98/ca/dcbb87a7c32120a42ab6ca1e7194",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ca/dc/4a0fcdee7fc3c57960d5381a0299",
"build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6c/a3/b70ad508a305efc2a10b5ba4508e",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/98/a9/1426b7eadc8be33f98f103fb12f0",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/38/8f/50753e457af4c626e2285c3171ac",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/fe/4d/77331e69f4fc0ef288df17377b42",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/9b/07/37e3a24a6ee588d0e5d4ba7b5335",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/0a/60/0109e5badaf8d6610cc9a4a61aa2",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/6d/e7/4e5bf2f3c16ca59770d5789c2481",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/b5/de/6914b0c6ab3142ad99547e930d88",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/3e/a4/e22b4cc12099dc6863a418d186f9",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/bd/c7/c97d29a73c75b3e699f14bcd6e37",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/44/36/de0a2f89ccd4e4728301cecd1033",
"build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b2/8a/31e68e8aeb4a440a98cdb37e688e",
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7e/c2/ed0e710cd33e9a96c7f54fdf400a",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/62/35/37d0f605248971a7d270914c0e61",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/91/a1/5da5cec236aa862f7f92f89783cd",
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/37/bb/b6bfe02bbd14a9c2d02fb782e4a9",
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/05/38/a9adca329b4a147d58dd81a714ac",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2c/03/e562ae1a5cc7be268e1bf0ccc4c0",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c9/d5/066f05c777e200dd73084f0a1c25",
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f7/6f/239efdb4e9e06cc0256f74da3aa8",
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d7/77/48d470740edb84a271bfb18c2a16",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e1/2f/d8e39443dd972ea41fb0c241e8fd",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/32/9b/9d76eef13898e654b088698512d7",
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/34/94/4abfe29e9b0443b292c53659a133",
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/43/b1/2a8098e867f5d2a2cc086a4fb3f5",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/19/b6/0700636b968985ecc9ff1d3bd28e",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/db/ee/569470160da9dff657538c06ce7b",
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/91/f9/6ec6bf4f8496ec4f71b3716db983",
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/66/8a/7f50eede3fb6b6d7a655e4613f2e",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/d4/40/1121fb6089b698565347acec66f6",
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/06/3b/0d289dd9a1170f750859e1c35b99",
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f5/70/38d78023e0b99fdbe6ee29edd809",
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/35/92/f2e39484904878e7eb9f5b3aff60",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6e/c5/6a81e0fc6027de9eca1c4a63143d",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/88/b5/e58450cec94d586f3d824f53c580",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/66/af/cf144d78359363ba027f2bd98a55",
"build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/9d/96/78f5d0d1e9249c71f018d84d9b24",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/58/d1/0f90ecfd6631b5476da915a76c55",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7c/bc/ec9ef218fb8065b58182493c981d",
"build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4c/6b/b2a4eb26f043bb474e7e7e958470",
"build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/64/e1/93f3afbc17ba6405cc970b559bb2",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/79/d2/f3b45d1aca8056c6cb951adc99ba",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4b/40/2ad8e00744d0b821e86fc42fc1f6",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8d/55/9876fecbe5d5076879b08d441665",
"build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b4/f1/6c795ec50a26c24c734c5e0168b4",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7d/44/03c734fb003671a15182e8446a44",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7b/65/cadda8309ad9a4360a6930f05df8",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/41/a5/13590a172a2bf749bf419f67ce9f",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/76/26/0f89328b9e4554a5e656b1ead2d1",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/4b/da/b914c9e05be25d475155727046f4",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/c3/fb/78fe613f999fc6a9291c7141aeb8",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/f8/b2/cf697fd62a3f0bdbd248173551f0",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/d3/56/62b48ba16afb6023e730c9a42e75",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/4c/6e/009f37e5b619ce32e398b8039f62",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/26/03/2ee19e3130a7455efe5c9f78cd93",
"src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/25/77/8093dfffddaa80cd513ddaa61867",
"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"

View File

@ -721,6 +721,7 @@
<w>dummyret</w>
<w>dummytoken</w>
<w>dummyval</w>
<w>dumpminlog</w>
<w>dups</w>
<w>dval</w>
<w>dxml</w>
@ -1376,6 +1377,7 @@
<w>levelmodule</w>
<w>levelname</w>
<w>levelno</w>
<w>levelnos</w>
<w>levelstr</w>
<w>lfull</w>
<w>lfval</w>
@ -1542,6 +1544,7 @@
<w>mdiv</w>
<w>mdocs</w>
<w>mdocslines</w>
<w>mdpath</w>
<w>mdpi</w>
<w>megalint</w>
<w>memfunctions</w>
@ -1569,6 +1572,7 @@
<w>minigame</w>
<w>minigames</w>
<w>miniplayer</w>
<w>minlog</w>
<w>minping</w>
<w>minusbutton</w>
<w>minval</w>
@ -2342,6 +2346,7 @@
<w>shobs</w>
<w>shortname</w>
<w>shouldn</w>
<w>showbuffer</w>
<w>showpoints</w>
<w>showstats</w>
<w>showsubseconds</w>
@ -2869,6 +2874,7 @@
<w>webpage</w>
<w>webpages</w>
<w>weeeird</w>
<w>whatarev</w>
<w>whatevs</w>
<w>whatisv</w>
<w>wheee</w>

View File

@ -1,4 +1,10 @@
### 1.7.16 (build 20967, api 7, 2022-12-16)
### 1.7.17 (build 20973, api 7, 2022-12-20)
- V2 accounts now show a 'Unlink Legacy (V1) Accounts' button in account settings if they have any old v1 links present. This can be used to clear out old links to replace them with V2 links which work correctly with V2 accounts.
- `ba.internal.dump_tracebacks()` is now `ba.internal.dump_app_state()` and `ba.internal.log_dumped_tracebacks()` is now `ba.internal.log_dumped_app_state()`. This reflects the fact that these calls may be expanded to include other app state in the future (C++ layer thread states, etc.).
- Added `ba.app.health_monitor` which will dump app state if the logic thread ever stops responding for 5+ seconds while the app is running (to help diagnose deadlock situations).
- Various extra logging and bug fixes related to V2 accounts and master server communication (trying to get this stuff working as smoothly as possible now that it is feature-complete).
### 1.7.16 (build 20969, api 7, 2022-12-18)
- Fixed a bug where profile names encased in curly brackets could cause harmless error messages.
- Android will no longer log errors on ba.open_url() calls if a browser is not available (it still just falls back to the in-app dialog in that case).
- The 'Upgrade' button for device accounts now signs you out and closes the upgrade window to hopefully make it more clear that you need to sign in with your newly created/upgraded BombSquad account.

View File

@ -32,6 +32,7 @@ if TYPE_CHECKING:
from bastd.actor import spazappearance
from ba._accountv2 import AccountV2Subsystem
from ba._level import Level
from ba._apputils import AppHealthMonitor
class App:
@ -50,7 +51,9 @@ class App:
# Implementations for these will be filled in by internal libs.
accounts_v2: AccountV2Subsystem
cloud: CloudSubsystem
log_handler: efro.log.LogHandler
health_monitor: AppHealthMonitor
class State(Enum):
"""High level state the app can be in."""
@ -346,7 +349,6 @@ class App:
# pylint: disable=cyclic-import
# pylint: disable=too-many-locals
from ba import _asyncio
from ba import _apputils
from ba import _appconfig
from ba import _map
from ba import _campaign
@ -354,11 +356,16 @@ class App:
from bastd import maps as stdmaps
from bastd.actor import spazappearance
from ba._generated.enums import TimeType
from ba._apputils import log_dumped_tracebacks
from ba._apputils import (
log_dumped_app_state,
handle_leftover_v1_cloud_log_file,
AppHealthMonitor,
)
assert _ba.in_logic_thread()
self._aioloop = _asyncio.setup_asyncio()
self.health_monitor = AppHealthMonitor()
cfg = self.config
@ -402,7 +409,7 @@ class App:
# If there's a leftover log file, attempt to upload it to the
# master-server and/or get rid of it.
_apputils.handle_leftover_v1_cloud_log_file()
handle_leftover_v1_cloud_log_file()
# Only do this stuff if our config file is healthy so we don't
# overwrite a broken one or whatnot and wipe out data.
@ -461,7 +468,7 @@ class App:
)
# If any traceback dumps happened last run, log and clear them.
log_dumped_tracebacks()
log_dumped_app_state()
self._launch_completed = True
self._update_state()
@ -493,6 +500,7 @@ class App:
self.cloud.on_app_pause()
self.accounts_v1.on_app_pause()
self.plugins.on_app_pause()
self.health_monitor.on_app_pause()
else:
# Leaving paused state:
if self.state is self.State.PAUSED:
@ -501,6 +509,7 @@ class App:
self.accounts_v1.on_app_resume()
self.music.on_app_resume()
self.plugins.on_app_resume()
self.health_monitor.on_app_resume()
if self._initial_login_completed and self._meta_scan_completed:
self.state = self.State.RUNNING

View File

@ -6,8 +6,12 @@ from __future__ import annotations
import gc
import os
import logging
from threading import Thread
from dataclasses import dataclass
from typing import TYPE_CHECKING
from efro.log import LogLevel
from efro.dataclassio import ioprepped, dataclass_to_json, dataclass_from_json
import _ba
if TYPE_CHECKING:
@ -266,22 +270,67 @@ def print_corrupt_file_error() -> None:
_tbfiles: list[TextIO] = []
def dump_tracebacks(delay: float) -> None:
"""Dump a traceback of all Python threads after a delay in seconds.
@ioprepped
@dataclass
class DumpedAppStateMetadata:
"""High level info about a dumped app state."""
Can be used for debugging deadlock situations. Will dump to a preset
file location in the app config dir. Will attempt to log and clear
the results after dumping. It will be done at next launch otherwise,
or can be done explicitly via log_dumped_tracebacks().
reason: str
app_time: float
log_level: LogLevel
Do not use this call during regular operation of the app; it is only
intended for debugging as it can leak file descriptors/etc.
def dump_app_state(
delay: float = 0.0,
reason: str = 'Unspecified',
log_level: LogLevel = LogLevel.WARNING,
) -> None:
"""Dump various app state for debugging purposes.
This includes stack traces for all Python threads (and potentially
other info in the future).
This is intended for use debugging deadlock situations. It will dump
to preset file location(s) in the app config dir, and will attempt to
log and clear the results after dumping. If that should fail (due to
a hung app, etc.), then the results will be logged and cleared on the
next app run.
Do not use this call during regular smooth operation of the app; it
is should only be used for debugging or in response to confirmed
problems as it can leak file descriptors, cause hitches, etc.
"""
# pylint: disable=consider-using-with
import faulthandler
from ba._generated.enums import TimeType
tbpath = os.path.join(os.path.dirname(_ba.app.config_file_path), '_tbdump')
# Dump our metadata immediately. If a delay is passed, it generally
# means we expect things to hang momentarily, so we should not delay
# writing our metadata or it will likely not happen. Though we
# should remember that metadata doesn't line up perfectly in time with
# the dump in that case.
try:
mdpath = os.path.join(
os.path.dirname(_ba.app.config_file_path), '_appstate_dump_md'
)
with open(mdpath, 'w', encoding='utf-8') as outfile:
outfile.write(
dataclass_to_json(
DumpedAppStateMetadata(
reason=reason,
app_time=_ba.time(TimeType.REAL),
log_level=log_level,
)
)
)
except Exception:
# Abandon whole dump if we can't write metadata.
logging.exception('Error writing app state dump metadata.')
return
tbpath = os.path.join(
os.path.dirname(_ba.app.config_file_path), '_appstate_dump_tb'
)
# faulthandler needs the raw file descriptor to still be valid when
# it fires, so stuff this into a global var to make sure it doesn't get
@ -289,23 +338,132 @@ def dump_tracebacks(delay: float) -> None:
tbfile = open(tbpath, 'w', encoding='utf-8')
_tbfiles.append(tbfile)
faulthandler.dump_traceback_later(delay, file=tbfile)
if delay > 0.0:
faulthandler.dump_traceback_later(delay, file=tbfile)
else:
faulthandler.dump_traceback(file=tbfile)
# Attempt to log shortly after dumping.
with _ba.Context('ui'):
_ba.timer(delay + 1.0, log_dumped_tracebacks, timetype=TimeType.REAL)
# Allow sufficient time since we don't know how long the dump takes.
# We want this to work from any thread, so need to kick this part
# over to the logic thread so timer works.
_ba.pushcall(
lambda: _ba.timer(
delay + 1.0, log_dumped_app_state, timetype=TimeType.REAL
),
from_other_thread=True,
suppress_other_thread_warning=True,
)
def log_dumped_tracebacks() -> None:
"""If a traceback dump exists, log it and clear it. No-op otherwise."""
def log_dumped_app_state() -> None:
"""If an app-state dump exists, log it and clear it. No-op otherwise."""
try:
tbpath = os.path.join(
os.path.dirname(_ba.app.config_file_path), '_tbdump'
out = ''
mdpath = os.path.join(
os.path.dirname(_ba.app.config_file_path), '_appstate_dump_md'
)
if os.path.exists(tbpath):
with open(tbpath, 'r', encoding='utf-8') as infile:
logging.info('Dumped tracebacks:\n%s', infile.read())
os.unlink(tbpath)
if os.path.exists(mdpath):
with open(mdpath, 'r', encoding='utf-8') as infile:
metadata = dataclass_from_json(
DumpedAppStateMetadata, infile.read()
)
os.unlink(mdpath)
out += (
f'App state dump:\nReason: {metadata.reason}\n'
f'Time: {metadata.app_time:.2f}'
)
tbpath = os.path.join(
os.path.dirname(_ba.app.config_file_path), '_appstate_dump_tb'
)
if os.path.exists(tbpath):
with open(tbpath, 'r', encoding='utf-8') as infile:
out += '\nPython tracebacks:\n' + infile.read()
os.unlink(tbpath)
logging.log(metadata.log_level.python_logging_level, out)
except Exception:
logging.exception('Error logging dumped tracebacks.')
logging.exception('Error logging dumped app state.')
class AppHealthMonitor:
"""Logs things like app-not-responding issues."""
def __init__(self) -> None:
assert _ba.in_logic_thread()
self._running = True
self._thread = Thread(target=self._bg_thread_main, daemon=True)
self._thread.start()
self._response = False
self._first_check = True
def _bg_thread_main(self) -> None:
try:
self._monitor_app()
except Exception:
logging.exception('Error in AppHealthMonitor thread.')
def _set_response(self) -> None:
assert _ba.in_logic_thread()
self._response = True
def _check_running(self) -> bool:
# Workaround for the fact that mypy assumes _running
# doesn't change during the course of a function.
return self._running
def _monitor_app(self) -> None:
import time
while bool(True):
# Always sleep a bit between checks.
time.sleep(1.234)
# Do nothing while backgrounded.
while not self._running:
time.sleep(2.3456)
# Wait for the logic thread to run something we send it.
starttime = time.monotonic()
self._response = False
_ba.pushcall(self._set_response, raw=True)
while not self._response:
# Abort this check if we went into the background.
if not self._check_running():
break
# Wait a bit longer the first time through since the app
# could still be starting up; we generally don't want to
# report that.
threshold = 10 if self._first_check else 5
# If we've been waiting too long (and the app is running)
# dump the app state and bail. Make an exception for the
# first check though since the app could just be taking
# a while to get going; we don't want to report that.
duration = time.monotonic() - starttime
if duration > threshold:
dump_app_state(
reason=f'Logic thread unresponsive'
f' for {threshold} seconds.'
)
# We just do one alert for now.
return
time.sleep(1.042)
self._first_check = False
def on_app_pause(self) -> None:
"""Should be called when the app pauses."""
assert _ba.in_logic_thread()
self._running = False
def on_app_resume(self) -> None:
"""Should be called when the app resumes."""
assert _ba.in_logic_thread()
self._running = True

View File

@ -47,7 +47,7 @@ def bootstrap() -> None:
# Give a soft warning if we're being used with a different binary
# version than we expect.
expected_build = 20967
expected_build = 20973
running_build: int = env['build_number']
if running_build != expected_build:
print(

View File

@ -53,7 +53,9 @@ def get_store_item_display_size(item_name: str) -> tuple[float, float]:
if item_name.startswith('characters.'):
return 340 * 0.6, 430 * 0.6
if item_name in ['pro', 'upgrades.pro', 'merch']:
return 650 * 0.9, 500 * 0.85
return 650 * 0.9, 500 * (
0.72 if _ba.app.config.get('Merch Link') else 0.85
)
if item_name.startswith('maps.'):
return 510 * 0.6, 450 * 0.6
if item_name.startswith('icons.'):

View File

@ -101,8 +101,8 @@ from ba._apputils import (
is_browser_likely_available,
get_remote_app_name,
should_submit_debug_info,
dump_tracebacks,
log_dumped_tracebacks,
dump_app_state,
log_dumped_app_state,
)
from ba._benchmark import (
run_gpu_benchmark,
@ -334,6 +334,6 @@ __all__ = [
'sign_out_v1',
'sign_in_v1',
'mark_config_dirty',
'dump_tracebacks',
'log_dumped_tracebacks',
'dump_app_state',
'log_dumped_app_state',
]

View File

@ -38,6 +38,8 @@ class AccountSettingsWindow(ba.Window):
self._sign_in_v2_proxy_button: ba.Widget | None = None
self._sign_in_device_button: ba.Widget | None = None
self._show_legacy_unlink_button = False
self._signing_in_adapter: LoginAdapter | None = None
self._close_once_signed_in = close_once_signed_in
ba.set_analytics_screen('Account Window')
@ -57,14 +59,8 @@ class AccountSettingsWindow(ba.Window):
self._r = 'accountSettingsWindow'
self._modal = modal
self._needs_refresh = False
self._signed_in = ba.internal.get_v1_account_state() == 'signed_in'
self._account_state_num = ba.internal.get_v1_account_state_num()
self._show_linked = (
self._signed_in
and ba.internal.get_v1_account_misc_read_val(
'allowAccountLinking2', False
)
)
self._v1_signed_in = ba.internal.get_v1_account_state() == 'signed_in'
self._v1_account_state_num = ba.internal.get_v1_account_state_num()
self._check_sign_in_timer = ba.Timer(
1.0,
ba.WeakCall(self._update),
@ -73,12 +69,12 @@ class AccountSettingsWindow(ba.Window):
)
# Currently we can only reset achievements on game-center.
account_type: str | None
if self._signed_in:
account_type = ba.internal.get_v1_account_type()
v1_account_type: str | None
if self._v1_signed_in:
v1_account_type = ba.internal.get_v1_account_type()
else:
account_type = None
self._can_reset_achievements = account_type == 'Game Center'
v1_account_type = None
self._can_reset_achievements = v1_account_type == 'Game Center'
app = ba.app
uiscale = app.ui.uiscale
@ -190,31 +186,25 @@ class AccountSettingsWindow(ba.Window):
def _update(self) -> None:
# If they want us to close once we're signed in, do so.
if self._close_once_signed_in and self._signed_in:
if self._close_once_signed_in and self._v1_signed_in:
self._back()
return
# Hmm should update this to use get_account_state_num.
# Theoretically if we switch from one signed-in account to another
# in the background this would break.
account_state_num = ba.internal.get_v1_account_state_num()
account_state = ba.internal.get_v1_account_state()
show_linked = (
self._signed_in
and ba.internal.get_v1_account_misc_read_val(
'allowAccountLinking2', False
)
)
v1_account_state_num = ba.internal.get_v1_account_state_num()
v1_account_state = ba.internal.get_v1_account_state()
show_legacy_unlink_button = self._should_show_legacy_unlink_button()
if (
account_state_num != self._account_state_num
or self._show_linked != show_linked
v1_account_state_num != self._v1_account_state_num
or show_legacy_unlink_button != self._show_legacy_unlink_button
or self._needs_refresh
):
self._show_linked = show_linked
self._account_state_num = account_state_num
self._signed_in = account_state == 'signed_in'
self._v1_account_state_num = v1_account_state_num
self._v1_signed_in = v1_account_state == 'signed_in'
self._show_legacy_unlink_button = show_legacy_unlink_button
self._refresh()
# Go ahead and refresh some individual things
@ -253,10 +243,10 @@ class AccountSettingsWindow(ba.Window):
False if gpgs_adapter is None else gpgs_adapter.is_back_end_active()
)
show_signed_in_as = self._signed_in
show_signed_in_as = self._v1_signed_in
signed_in_as_space = 95.0
show_sign_in_benefits = not self._signed_in
show_sign_in_benefits = not self._v1_signed_in
sign_in_benefits_space = 80.0
show_signing_in_text = (
@ -282,17 +272,17 @@ class AccountSettingsWindow(ba.Window):
sign_in_button_space = 70.0
deprecated_space = 60
show_game_service_button = self._signed_in and v1_account_type in [
show_game_service_button = self._v1_signed_in and v1_account_type in [
'Game Center'
]
game_service_button_space = 60.0
show_what_is_v2 = self._signed_in and v1_account_type == 'V2'
show_what_is_v2 = self._v1_signed_in and v1_account_type == 'V2'
show_linked_accounts_text = self._signed_in
show_linked_accounts_text = self._v1_signed_in
linked_accounts_text_space = 60.0
show_achievements_button = self._signed_in and v1_account_type in (
show_achievements_button = self._v1_signed_in and v1_account_type in (
'Google Play',
'Local',
'V2',
@ -300,33 +290,33 @@ class AccountSettingsWindow(ba.Window):
achievements_button_space = 60.0
show_achievements_text = (
self._signed_in and not show_achievements_button
self._v1_signed_in and not show_achievements_button
)
achievements_text_space = 27.0
show_leaderboards_button = self._signed_in and is_gpgs
show_leaderboards_button = self._v1_signed_in and is_gpgs
leaderboards_button_space = 60.0
show_campaign_progress = self._signed_in
show_campaign_progress = self._v1_signed_in
campaign_progress_space = 27.0
show_tickets = self._signed_in
show_tickets = self._v1_signed_in
tickets_space = 27.0
show_reset_progress_button = False
reset_progress_button_space = 70.0
show_manage_v2_account_button = (
self._signed_in and v1_account_type == 'V2'
self._v1_signed_in and v1_account_type == 'V2'
)
manage_v2_account_button_space = 100.0
show_player_profiles_button = self._signed_in
show_player_profiles_button = self._v1_signed_in
player_profiles_button_space = (
70.0 if show_manage_v2_account_button else 100.0
)
show_link_accounts_button = self._signed_in and (
show_link_accounts_button = self._v1_signed_in and (
primary_v2_account is None or FORCE_ENABLE_V1_LINKING
)
link_accounts_button_space = 70.0
@ -334,10 +324,12 @@ class AccountSettingsWindow(ba.Window):
show_unlink_accounts_button = show_link_accounts_button
unlink_accounts_button_space = 90.0
show_v2_link_info = self._signed_in and not show_link_accounts_button
show_v2_link_info = self._v1_signed_in and not show_link_accounts_button
v2_link_info_space = 70.0
show_sign_out_button = self._signed_in and v1_account_type in [
legacy_unlink_button_space = 120.0
show_sign_out_button = self._v1_signed_in and v1_account_type in [
'Local',
'Google Play',
'V2',
@ -394,6 +386,8 @@ class AccountSettingsWindow(ba.Window):
self._sub_height += unlink_accounts_button_space
if show_v2_link_info:
self._sub_height += v2_link_info_space
if self._show_legacy_unlink_button:
self._sub_height += legacy_unlink_button_space
if show_sign_out_button:
self._sub_height += sign_out_button_space
if show_cancel_sign_in_button:
@ -460,7 +454,7 @@ class AccountSettingsWindow(ba.Window):
v_align='center',
autoselect=True,
selectable=True,
on_activate_call=ba.WeakCall(self._on_what_is_v2_press),
on_activate_call=show_what_is_v2_page,
click_activate=True,
)
if first_selectable is None:
@ -1046,6 +1040,35 @@ class AccountSettingsWindow(ba.Window):
color=(0.5, 0.45, 0.55),
)
if self._show_legacy_unlink_button:
v -= legacy_unlink_button_space
button_width_w = button_width * 1.5
ba.textwidget(
parent=self._subcontainer,
position=(self._sub_width * 0.5 - 150.0, v + 75),
size=(300.0, 60),
text=ba.Lstr(resource='whatIsThisText'),
scale=0.8,
color=(0.3, 0.7, 0.05),
maxwidth=200.0,
h_align='center',
v_align='center',
autoselect=True,
selectable=True,
on_activate_call=show_what_is_legacy_unlinking_page,
click_activate=True,
)
btn = ba.buttonwidget(
parent=self._subcontainer,
position=((self._sub_width - button_width_w) * 0.5, v + 25),
autoselect=True,
size=(button_width_w, 60),
label=ba.Lstr(resource=self._r + '.unlinkLegacyV1AccountsText'),
textcolor=(0.8, 0.4, 0),
color=(0.55, 0.5, 0.6),
on_activate_call=self._unlink_accounts_press,
)
if show_sign_out_button:
v -= sign_out_button_space
self._sign_out_button = btn = ba.buttonwidget(
@ -1153,7 +1176,7 @@ class AccountSettingsWindow(ba.Window):
timetype=ba.TimeType.REAL,
)
def _have_unlinkable_accounts(self) -> bool:
def _have_unlinkable_v1_accounts(self) -> bool:
# if this is not present, we haven't had contact from the server so
# let's not proceed..
if ba.internal.get_public_login_id() is None:
@ -1166,12 +1189,21 @@ class AccountSettingsWindow(ba.Window):
def _update_unlink_accounts_button(self) -> None:
if self._unlink_accounts_button is None:
return
if self._have_unlinkable_accounts():
if self._have_unlinkable_v1_accounts():
clr = (0.75, 0.7, 0.8, 1.0)
else:
clr = (1.0, 1.0, 1.0, 0.25)
ba.textwidget(edit=self._unlink_accounts_button_label, color=clr)
def _should_show_legacy_unlink_button(self) -> bool:
# Only show this when fully signed in to a v2 account.
if not self._v1_signed_in or ba.app.accounts_v2.primary is None:
return False
out = self._have_unlinkable_v1_accounts()
return out
def _update_linked_accounts_text(self) -> None:
if self._linked_accounts_text is None:
return
@ -1297,7 +1329,7 @@ class AccountSettingsWindow(ba.Window):
# pylint: disable=cyclic-import
from bastd.ui.account import unlink
if not self._have_unlinkable_accounts():
if not self._have_unlinkable_v1_accounts():
ba.playsound(ba.getsound('error'))
return
unlink.AccountUnlinkWindow(origin_widget=self._unlink_accounts_button)
@ -1499,3 +1531,9 @@ def show_what_is_v2_page() -> None:
"""Show the webpage describing V2 accounts."""
bamasteraddr = ba.internal.get_master_server_address(version=2)
ba.open_url(f'{bamasteraddr}/whatisv2')
def show_what_is_legacy_unlinking_page() -> None:
"""Show the webpage describing legacy unlinking."""
bamasteraddr = ba.internal.get_master_server_address(version=2)
ba.open_url(f'{bamasteraddr}/whatarev1links')

View File

@ -515,7 +515,20 @@ class MainMenuWindow(ba.Window):
self._tdelay = 2.0
self._t_delay_inc = 0.02
self._t_delay_play = 1.7
self._next_refresh_allow_time = ba.time(ba.TimeType.REAL) + 2.01
def _set_allow_time() -> None:
self._next_refresh_allow_time = ba.time(ba.TimeType.REAL) + 2.5
# Slight hack: widget transitions currently only progress when
# frames are being drawn, but this tends to get called before
# frame drawing even starts, meaning we don't know exactly how
# long we should wait before refreshing to avoid interrupting
# the transition. To make things a bit better, let's do a
# redundant set of the time in a deferred call which hopefully
# happens closer to actual frame draw times.
_set_allow_time()
ba.pushcall(_set_allow_time)
ba.app.did_menu_intro = True
self._width = 400.0
self._height = 200.0

View File

@ -907,7 +907,11 @@ class StoreBrowserWindow(ba.Window):
dummy_name
)
section['v_spacing'] = (
-17 if self._tab == 'characters' else 0
-25
if self._tab == 'extras'
else -17
if self._tab == 'characters'
else 0
)
if 'title' not in section:
section['title'] = ''
@ -919,7 +923,13 @@ class StoreBrowserWindow(ba.Window):
else 0
)
section['y_offs'] = (
55
20
if (
self._tab == 'extras'
and uiscale is ba.UIScale.SMALL
and ba.app.config.get('Merch Link')
)
else 55
if (
self._tab == 'extras'
and uiscale is ba.UIScale.SMALL

View File

@ -45,19 +45,23 @@ def instantiate_store_item_display(
item['name'] = title = get_store_item_name_translated(item_name)
btn: ba.Widget | None
# Hack; showbuffer stuff isn't working well when we're showing merch.
showbuffer = 10 if item_name in {'merch', 'pro', 'pro_sale'} else 76.0
if button:
item['button'] = btn = ba.buttonwidget(
parent=parent_widget,
position=b_pos,
transition_delay=delay,
show_buffer_top=76.0,
show_buffer_top=showbuffer,
enable_sound=False,
button_type='square',
size=(b_width, b_height),
autoselect=True,
label='',
)
ba.widget(edit=btn, show_buffer_bottom=76.0)
ba.widget(edit=btn, show_buffer_bottom=showbuffer)
else:
btn = None
@ -170,11 +174,11 @@ def instantiate_store_item_display(
)
if item_name == 'merch':
frame_size = b_width * 0.7
frame_size = b_width * 0.65
im_dim = frame_size * (100.0 / 113.0)
im_pos = (
b_pos[0] + b_width * 0.5 - im_dim * 0.5 + b_offs_x,
b_pos[1] + b_height * 0.5 - im_dim * 0.5,
b_pos[1] + b_height * 0.47 - im_dim * 0.5,
)
ba.imagewidget(
parent=parent_widget,

View File

@ -388,6 +388,7 @@
<w>dummyret</w>
<w>dummyval</w>
<w>dummyvalid</w>
<w>dumpminlog</w>
<w>dval</w>
<w>dxgi</w>
<w>dynamicdata</w>
@ -732,6 +733,7 @@
<w>leaderboards</w>
<w>lenval</w>
<w>levelno</w>
<w>levelnos</w>
<w>levelstr</w>
<w>lgui</w>
<w>lhalf</w>
@ -807,6 +809,7 @@
<w>maxtries</w>
<w>maxwait</w>
<w>maxwidth</w>
<w>mdpath</w>
<w>mediump</w>
<w>memalign</w>
<w>memchr</w>
@ -824,6 +827,7 @@
<w>millisecs</w>
<w>minelem</w>
<w>miniplayer</w>
<w>minlog</w>
<w>minping</w>
<w>minsdl</w>
<w>mipmapcount</w>
@ -1245,6 +1249,7 @@
<w>shhh</w>
<w>shifthigh</w>
<w>shouldnt</w>
<w>showbuffer</w>
<w>shufflable</w>
<w>signsubscale</w>
<w>sigsetjmp</w>
@ -1518,6 +1523,7 @@
<w>weeeird</w>
<w>welp</w>
<w>whaaaaaaa</w>
<w>whatarev</w>
<w>whatisv</w>
<w>wheee</w>
<w>wheeee</w>

View File

@ -32,8 +32,8 @@
namespace ballistica {
// These are set automatically via script; don't modify them here.
const int kAppBuildNumber = 20967;
const char* kAppVersion = "1.7.16";
const int kAppBuildNumber = 20973;
const char* kAppVersion = "1.7.17";
// Our standalone globals.
// These are separated out for easy access.

View File

@ -446,7 +446,9 @@ auto ContainerWidget::HandleMessage(const WidgetMessage& m) -> bool {
CheckLayout();
// Ignore mouse stuff while transitioning out.
if (transitioning_ && transitioning_out_) break;
if (transitioning_ && transitioning_out_) {
break;
}
float x = m.fval1;
float y = m.fval2;
@ -505,7 +507,9 @@ auto ContainerWidget::HandleMessage(const WidgetMessage& m) -> bool {
CheckLayout();
// Ignore mouse stuff while transitioning.
if (transitioning_ && transitioning_out_) break;
if (transitioning_ && transitioning_out_) {
break;
}
float x = m.fval1;
float y = m.fval2;
@ -546,7 +550,9 @@ auto ContainerWidget::HandleMessage(const WidgetMessage& m) -> bool {
CheckLayout();
// Ignore mouse stuff while transitioning.
if (transitioning_ && transitioning_out_) break;
if (transitioning_ && transitioning_out_) {
break;
}
float x = m.fval1;
float y = m.fval2;
@ -909,7 +915,9 @@ void ContainerWidget::Draw(RenderPass* pass, bool draw_transparent) {
}
// Don't draw if we've fully transitioned out.
if (transitioning_out_ && !transitioning_) return;
if (transitioning_out_ && !transitioning_) {
return;
}
float l = transition_offset_x_smoothed_ + transition_scale_offset_x_;
float r = l + width_;

View File

@ -37,7 +37,27 @@ class LogLevel(Enum):
ERROR = 3
CRITICAL = 4
@property
def python_logging_level(self) -> int:
"""Give the corresponding logging level."""
return LOG_LEVEL_LEVELNOS[self]
@classmethod
def from_python_logging_level(cls, levelno: int) -> LogLevel:
"""Given a Python logging level, return a LogLevel."""
return LEVELNO_LOG_LEVELS[levelno]
# Python logging levels from LogLevels
LOG_LEVEL_LEVELNOS = {
LogLevel.DEBUG: logging.DEBUG,
LogLevel.INFO: logging.INFO,
LogLevel.WARNING: logging.WARNING,
LogLevel.ERROR: logging.ERROR,
LogLevel.CRITICAL: logging.CRITICAL,
}
# LogLevels from Python logging levels
LEVELNO_LOG_LEVELS = {
logging.DEBUG: LogLevel.DEBUG,
logging.INFO: LogLevel.INFO,