diff --git a/.efrocachemap b/.efrocachemap index 300321f8..7cec964e 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -421,7 +421,7 @@ "build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26", "build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8", "build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55", - "build/assets/ba_data/data/langdata.json": "bb60812044af0a8d1bdefee759ff2522", + "build/assets/ba_data/data/langdata.json": "29a60e77c26b1f397617f8d8c8d652f9", "build/assets/ba_data/data/languages/arabic.json": "0db32e21b6d5337ccca478381744aa88", "build/assets/ba_data/data/languages/belarussian.json": "a112dfca3e188387516788bd8229c5b0", "build/assets/ba_data/data/languages/chinese.json": "93f3ca9f90d86dc7c8d0923f5f11ef46", @@ -429,23 +429,23 @@ "build/assets/ba_data/data/languages/croatian.json": "766532c67af5bd0144c2d63cab0516fa", "build/assets/ba_data/data/languages/czech.json": "c9d518a324870066b987b8f412881dd3", "build/assets/ba_data/data/languages/danish.json": "3fd69080783d5c9dcc0af737f02b6f1e", - "build/assets/ba_data/data/languages/dutch.json": "5cbf1a68a9d93dee00dbc27f834d878a", + "build/assets/ba_data/data/languages/dutch.json": "b0900d572c9141897d53d6574c471343", "build/assets/ba_data/data/languages/english.json": "1c4037fea1066d39d6eced419f314f35", "build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880", "build/assets/ba_data/data/languages/filipino.json": "0031cbb8eb6a638a94fb43c5d892346c", - "build/assets/ba_data/data/languages/french.json": "8bc35eb4b20a0b30c3348bcc9a3844a6", + "build/assets/ba_data/data/languages/french.json": "cc8ac601f5443dd539893728db983f5c", "build/assets/ba_data/data/languages/german.json": "450fa41ae264f29a5d1af22143d0d0ad", "build/assets/ba_data/data/languages/gibberish.json": "b461539243e8efe3137137b886256ba7", "build/assets/ba_data/data/languages/greek.json": "287c0ec437b38772284ef9d3e4fb2fc3", "build/assets/ba_data/data/languages/hindi.json": "8848f6b0caec0fcf9d85bc6e683809ec", "build/assets/ba_data/data/languages/hungarian.json": "796a290a8c44a1e7635208c2ff5fdc6e", - "build/assets/ba_data/data/languages/indonesian.json": "408fb026e84c24a8dd7a43cb2b794541", + "build/assets/ba_data/data/languages/indonesian.json": "9103845242b572aa8ba48e24f81ddb68", "build/assets/ba_data/data/languages/italian.json": "f550810b6866ea9bcf1985b7228f8cff", "build/assets/ba_data/data/languages/korean.json": "03fd99d5e1155e81053fc028f69df982", "build/assets/ba_data/data/languages/malay.json": "832562ce997fc70704b9234c95fb2e38", "build/assets/ba_data/data/languages/persian.json": "9728d631cf7d9ad3b209ae1244bb59c0", "build/assets/ba_data/data/languages/polish.json": "3a90b2d9e2c59305580c96f8098fc839", - "build/assets/ba_data/data/languages/portuguese.json": "0274cb9a4b7d2bd49c8eb8120144a1bf", + "build/assets/ba_data/data/languages/portuguese.json": "b52164747c6308fc9d054eb6c0ff3c54", "build/assets/ba_data/data/languages/romanian.json": "aeebdd54f65939c2facc6ac50c117826", "build/assets/ba_data/data/languages/russian.json": "30d5f3d2415088e1fb6558fcd6ccfa98", "build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69", @@ -4060,50 +4060,50 @@ "build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "cd19dfdf480de6e73949db674e1b02d2", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "8c08cdda59e731a3830624000de5ca7f", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "14685eca62b8540cc2a268883d0ebc5d", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "f81876d7827a10be412306c52b03fa08", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "b8370845743ebba86ed6eaa6ee1d79d5", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "cdf04825dedae8fb2c26502ec2a505db", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "4036493f98646b58de8bf425bee227cb", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "1cf36c63f68ecaa954fb9c48a132725e", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "b757a940c5157197a0138e12e308f859", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "92a07f83fceeddf3b29cfe2ead57f7e3", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "90002c085c66be4af378d4b3fc8e0260", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "eeb363d0d48e68f5f2ac2e536a26aeeb", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "e119b480fc7e542f33ceb16e8c04585f", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "6e657aa09d052765ed891789ec60dfb2", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "2d4eab8ea8399defd1afdbe548216e9c", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "b03bb9d5d1eb695a11843f64f24906ef", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "163fbc40b479ef1db1c753f7beb73c0f", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "37291abd76871f4556348f77e12dd363", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "acca6904f2f2f952ecae99922c602b9d", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "3c2dfd9cf26e77a0b803ed43c85df113", - "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "3af5cf00e5eb30d55030e8705b83353a", - "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "be337c05f72235b5b486277bb1a9c259", - "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "3af5cf00e5eb30d55030e8705b83353a", - "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "be337c05f72235b5b486277bb1a9c259", - "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "17c7d0041bc7c84077bf6692b16e3988", - "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "4affbfea91e8a33ab62da763ffc07ddd", - "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "17c7d0041bc7c84077bf6692b16e3988", - "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "4affbfea91e8a33ab62da763ffc07ddd", - "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "58656b49d34e6c650983fbf79b5c41ae", - "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "3ce5652e0ff5d277e256f517dec4eb61", - "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "58656b49d34e6c650983fbf79b5c41ae", - "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "3ce5652e0ff5d277e256f517dec4eb61", - "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "b94fff3a719003c1d8f5dd16dffdb3fc", - "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "5d68e1957febe6053815bbee3f068e76", - "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "85bbca447ca8a1d0fad984afc6f0700a", - "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "5d68e1957febe6053815bbee3f068e76", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "7f2ed141a475e051d3350d571ef6cb0c", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "93fb764531ae16a30d4886eb183c3681", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "750cd7ef428f4faf65ccbeff50c21f8e", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "104cf85df9f1f7ffbf4de5997f7c6879", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "af85fb387d755b152c42f8dfb0891ad7", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "01ce8e0619b342e4cc2cc5f18f81a727", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "f8aae2e04f95f4cfb863791da36ff931", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "66252d58a1be97db8523bd0bf8098a16", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "c1f5b6a9fe5aee5baab40248a00eb606", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "88888a9139b8a047d1dde25ae0aa9ea6", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "e51014b672283258ba29f546f3a8833e", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "811973441c2d7998445182b2ab4bcc24", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "01e0fe6152b79211acec7e88a99c6579", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "9e2b7acbcd3892af6be5f85bfe328c2c", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "2f54025a53bb947c89eee520131eae52", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "b9df392dca06e52b958ea3c9b676ae6a", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "f2ed10e0b5956ce8ef5b87c3e0c75eea", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "e1c27e7ecb5272f92e6cfdb91b0750d3", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "67827bd210a484f7d93974b581b95a85", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "c03d44f4096cbffe0d1b3391a7b09555", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "a78c8b08a19dc23d1881eee37fdbcfdd", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "ca2caba96a855ac6fa7459855bfa49bb", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "9521bca3d6dc02e896fa01ab0ccdfd0c", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "31762c816772ba2c0516c26589428c08", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "ab72b100f5c1eaaac6264b8f662fabb7", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "edf145cc7855aced80f60766a9420df5", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "4d4e6e57f179666e8f5a50352b9cda9b", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "20babca2eb9cc062f583ecea557a945e", + "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "8ccecbffbaa9886636741cca293d2893", + "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "42679aef4dd8b35b39a2c968ff20ed45", + "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "8ccecbffbaa9886636741cca293d2893", + "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "42679aef4dd8b35b39a2c968ff20ed45", + "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "b2c2c33149201227ba96459dbeeba012", + "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "2b27b84fe8305b7f3829aa28ab5e5705", + "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "b2c2c33149201227ba96459dbeeba012", + "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "2b27b84fe8305b7f3829aa28ab5e5705", + "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "f6b49cee7baf1ee49598b803566d9914", + "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "a15dc59a2de8a8d32b32f07fe25d41b1", + "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "f6b49cee7baf1ee49598b803566d9914", + "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "a15dc59a2de8a8d32b32f07fe25d41b1", + "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "80fd9070d92797ff6e26c0a5493dcb42", + "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "07c2b1098c1c08d2e28934a6f0e1fcf2", + "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "724d8dcd34fb6c2c0109906d44a4fb12", + "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "07c2b1098c1c08d2e28934a6f0e1fcf2", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "698b55a6c11f38e5c28587a7039e6175", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "753db5761ce823966fcef472b73e06d1", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "b1e41720089a0d7724337071442238c9", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "37d3e9fa31a003dd9609f476d4165d12", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "105f4dc0399235e4a9c25c3977febec8", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "820c04dd9965698a86e4f5efffdb729d", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "070727ad10a727b22beef6ee736c7a5f", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "6d2969401a8a022e28f4680b01004a50", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/enums.py": "b611c090513a21e2fe90e56582724e9d", "src/ballistica/base/mgen/pyembed/binding_base.inc": "72bfed2cce8ff19741989dec28302f3f", diff --git a/CHANGELOG.md b/CHANGELOG.md index d1480580..f4aa736e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.33 (build 21757, api 8, 2024-01-06) +### 1.7.33 (build 21760, api 8, 2024-01-16) - Stress test input-devices are now a bit smarter; they won't press any buttons while UIs are up (this could cause lots of chaos if it happened). - Added a 'Show Demos When Idle' option in advanced settings. If enabled, the diff --git a/ballisticakit-cmake/.idea/misc.xml b/ballisticakit-cmake/.idea/misc.xml index f01f08b8..fbb3740e 100644 --- a/ballisticakit-cmake/.idea/misc.xml +++ b/ballisticakit-cmake/.idea/misc.xml @@ -49,9 +49,6 @@ - - - diff --git a/src/assets/ba_data/python/babase/_app.py b/src/assets/ba_data/python/babase/_app.py index 4a021ab8..2b0191f1 100644 --- a/src/assets/ba_data/python/babase/_app.py +++ b/src/assets/ba_data/python/babase/_app.py @@ -1,12 +1,13 @@ # Released under the MIT License. See LICENSE for details. # +# pylint: disable=too-many-lines """Functionality related to the high level state of the app.""" from __future__ import annotations import os import logging from enum import Enum -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, TypeVar from concurrent.futures import ThreadPoolExecutor from functools import cached_property @@ -26,7 +27,7 @@ from babase._devconsole import DevConsoleSubsystem if TYPE_CHECKING: import asyncio - from typing import Any, Callable, Coroutine + from typing import Any, Callable, Coroutine, Generator, Awaitable from concurrent.futures import Future import babase @@ -42,6 +43,8 @@ if TYPE_CHECKING: # __FEATURESET_APP_SUBSYSTEM_IMPORTS_END__ +T = TypeVar('T') + class App: """A class for high level app functionality and state. @@ -199,7 +202,8 @@ class App: self._called_on_running = False self._subsystem_registration_ended = False self._pending_apply_app_config = False - self._aioloop: asyncio.AbstractEventLoop | None = None + self._asyncio_loop: asyncio.AbstractEventLoop | None = None + self._asyncio_tasks: set[asyncio.Task] = set() self._asyncio_timer: babase.AppTimer | None = None self._config: babase.AppConfig | None = None self._pending_intent: AppIntent | None = None @@ -239,18 +243,68 @@ class App: return _babase.app_is_active() @property - def aioloop(self) -> asyncio.AbstractEventLoop: + def asyncio_loop(self) -> asyncio.AbstractEventLoop: """The logic thread's asyncio event loop. This allow async tasks to be run in the logic thread. + + Generally you should call App.create_async_task() to schedule + async code to run instead of using this directly. That will + handle retaining the task and logging errors automatically. + Only schedule tasks onto asyncio_loop yourself when you intend + to hold on to the returned task and await its results. Releasing + the task reference can lead to subtle bugs such as unreported + errors and garbage-collected tasks disappearing before their + work is done. + Note that, at this time, the asyncio loop is encapsulated and explicitly stepped by the engine's logic thread loop and - thus things like asyncio.get_running_loop() will not return this - loop from most places in the logic thread; only from within a - task explicitly created in this loop. + thus things like asyncio.get_running_loop() will unintuitively + *not* return this loop from most places in the logic thread; + only from within a task explicitly created in this loop. + Hopefully this situation will be improved in the future with a + unified event loop. """ - assert self._aioloop is not None - return self._aioloop + assert _babase.in_logic_thread() + assert self._asyncio_loop is not None + return self._asyncio_loop + + def create_async_task( + self, + coro: Generator[Any, Any, T] | Coroutine[Any, Any, T], + *, + name: str | None = None, + ) -> None: + """Create a fully managed async task. + + This will automatically retain and release a reference to the task + and log any exceptions that occur in it. If you need to await a task + or otherwise need more control, schedule a task directly using + App.asyncio_loop. + """ + assert _babase.in_logic_thread() + # Hold a strong reference to the task until it is done. + # Otherwise it is possible for it to be garbage collected and + # disappear midway if the caller does not hold on to the + # returned task, which seems like a great way to introduce + # hard-to-track bugs. + task = self.asyncio_loop.create_task(coro, name=name) + self._asyncio_tasks.add(task) + task.add_done_callback(self._on_task_done) + # return task + + def _on_task_done(self, task: asyncio.Task) -> None: + # Report any errors that occurred. + try: + exc = task.exception() + if exc is not None: + logging.error( + "Error in async task '%s'.", task.get_name(), exc_info=exc + ) + except Exception: + logging.exception('Error reporting async task error.') + + self._asyncio_tasks.remove(task) @property def config(self) -> babase.AppConfig: @@ -594,7 +648,7 @@ class App: _env.on_app_state_initing() - self._aioloop = _asyncio.setup_asyncio() + self._asyncio_loop = _asyncio.setup_asyncio() self.health_monitor = AppHealthMonitor() # __FEATURESET_APP_SUBSYSTEM_CREATE_BEGIN__ @@ -874,8 +928,8 @@ class App: ) # Now kick off any async shutdown task(s). - assert self._aioloop is not None - self._shutdown_task = self._aioloop.create_task(self._shutdown()) + assert self._asyncio_loop is not None + self._shutdown_task = self._asyncio_loop.create_task(self._shutdown()) def _on_shutdown_complete(self) -> None: """(internal)""" diff --git a/src/assets/ba_data/python/baclassic/_ads.py b/src/assets/ba_data/python/baclassic/_ads.py index 2373df36..5cd454d0 100644 --- a/src/assets/ba_data/python/baclassic/_ads.py +++ b/src/assets/ba_data/python/baclassic/_ads.py @@ -229,9 +229,7 @@ class AdsSubsystem: await asyncio.sleep(1.0) payload.run(fallback=True) - _fallback_task = babase.app.aioloop.create_task( - add_fallback_task() - ) + babase.app.create_async_task(add_fallback_task()) self.show_ad('between_game', on_completion_call=payload.run) else: babase.pushcall(call) # Just run the callback without the ad. diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 664ef95d..d1521b91 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -52,7 +52,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 21757 +TARGET_BALLISTICA_BUILD = 21760 TARGET_BALLISTICA_VERSION = '1.7.33' diff --git a/src/assets/ba_data/python/bauiv1lib/promocode.py b/src/assets/ba_data/python/bauiv1lib/promocode.py index 3cf745b5..6be09ab6 100644 --- a/src/assets/ba_data/python/bauiv1lib/promocode.py +++ b/src/assets/ba_data/python/bauiv1lib/promocode.py @@ -5,9 +5,13 @@ from __future__ import annotations import time +from typing import TYPE_CHECKING import bauiv1 as bui +if TYPE_CHECKING: + from typing import Any + class PromoCodeWindow(bui.Window): """Window for entering promo codes.""" @@ -167,9 +171,6 @@ class PromoCodeWindow(bui.Window): if not self._root_widget or self._root_widget.transitioning_out: return - plus = bui.app.plus - assert plus is not None - bui.containerwidget( edit=self._root_widget, transition=self._transition_out ) @@ -179,11 +180,22 @@ class PromoCodeWindow(bui.Window): AdvancedSettingsWindow(transition='in_left').get_root_widget(), from_window=self._root_widget, ) - plus.add_v1_account_transaction( - { - 'type': 'PROMO_CODE', - 'expire_time': time.time() + 5, - 'code': bui.textwidget(query=self._text_field), - } - ) - plus.run_v1_account_transactions() + + code: Any = bui.textwidget(query=self._text_field) + assert isinstance(code, str) + + bui.app.create_async_task(_run_code(code)) + + +async def _run_code(code: str) -> None: + plus = bui.app.plus + assert plus is not None + + plus.add_v1_account_transaction( + { + 'type': 'PROMO_CODE', + 'expire_time': time.time() + 5, + 'code': code, + } + ) + plus.run_v1_account_transactions() diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index 4badfe1f..fa6f3b9a 100644 --- a/src/ballistica/shared/ballistica.cc +++ b/src/ballistica/shared/ballistica.cc @@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int { namespace ballistica { // These are set automatically via script; don't modify them here. -const int kEngineBuildNumber = 21757; +const int kEngineBuildNumber = 21760; const char* kEngineVersion = "1.7.33"; const int kEngineApiVersion = 8; diff --git a/tools/bacommon/transfer.py b/tools/bacommon/transfer.py index f6704b26..a53c6153 100644 --- a/tools/bacommon/transfer.py +++ b/tools/bacommon/transfer.py @@ -31,7 +31,7 @@ class DirectoryManifest: files: Annotated[dict[str, DirectoryManifestFile], IOAttrs('f')] - _empty_hash: str | None = None + # _empty_hash: str | None = None @classmethod def create_from_disk(cls, path: Path) -> DirectoryManifest: @@ -92,12 +92,12 @@ class DirectoryManifest: ) break # 1 error is enough for now. - @classmethod - def get_empty_hash(cls) -> str: - """Return the hash for an empty file.""" - if cls._empty_hash is None: - import hashlib + # @classmethod + # def get_empty_hash(cls) -> str: + # """Return the hash for an empty file.""" + # if cls._empty_hash is None: + # import hashlib - sha = hashlib.sha256() - cls._empty_hash = sha.hexdigest() - return cls._empty_hash + # sha = hashlib.sha256() + # cls._empty_hash = sha.hexdigest() + # return cls._empty_hash diff --git a/tools/efro/dataclassio/_base.py b/tools/efro/dataclassio/_base.py index 6ef37105..afe19deb 100644 --- a/tools/efro/dataclassio/_base.py +++ b/tools/efro/dataclassio/_base.py @@ -70,6 +70,13 @@ class IOExtendedData: Can be overridden to migrate old data formats to new, etc. """ + def did_input(self) -> None: + """Called on a class instance after created from data. + + Can be useful to correct values from the db, etc. in the + type-safe form. + """ + def _is_valid_for_codec(obj: Any, codec: Codec) -> bool: """Return whether a value consists solely of json-supported types. diff --git a/tools/efro/dataclassio/_inputter.py b/tools/efro/dataclassio/_inputter.py index d6650a65..97075528 100644 --- a/tools/efro/dataclassio/_inputter.py +++ b/tools/efro/dataclassio/_inputter.py @@ -64,11 +64,23 @@ class _Inputter(Generic[T]): # For special extended data types, call their 'will_output' callback. tcls = self._cls + if issubclass(tcls, IOExtendedData): + is_ext = True tcls.will_input(values) + else: + is_ext = False out = self._dataclass_from_input(self._cls, '', values) assert isinstance(out, self._cls) + + if is_ext: + # mypy complains that we're no longer returning a T + # if we operate on out directly. + out2 = out + assert isinstance(out2, IOExtendedData) + out2.did_input() + return out def _value_from_input( diff --git a/tools/efro/util.py b/tools/efro/util.py index 8bc4542a..807d4c00 100644 --- a/tools/efro/util.py +++ b/tools/efro/util.py @@ -174,17 +174,20 @@ def empty_weakref(objtype: type[T]) -> weakref.ref[T]: # Just create an object and let it die. Is there a cleaner way to do this? # return weakref.ref(_EmptyObj()) # type: ignore + # Sharing a single ones seems at least a bit better. return _g_empty_weak_ref # type: ignore -def data_size_str(bytecount: int) -> str: +def data_size_str(bytecount: int, compact: bool = False) -> str: """Given a size in bytes, returns a short human readable string. - This should be 6 or fewer chars for most all sane file sizes. + In compact mode this should be 6 or fewer chars for most all + sane file sizes. """ # pylint: disable=too-many-return-statements if bytecount <= 999: - return f'{bytecount} B' + suffix = 'B' if compact else 'bytes' + return f'{bytecount} {suffix}' kbytecount = bytecount / 1024 if round(kbytecount, 1) < 10.0: return f'{kbytecount:.1f} KB' @@ -623,7 +626,7 @@ def check_non_optional(obj: T | None) -> T: Use assert_non_optional for a more efficient (but less safe) equivalent. """ if obj is None: - raise TypeError('Got None value in check_non_optional.') + raise ValueError('Got None value in check_non_optional.') return obj