From f23365726b3d5daabc6c4a91adcedb5e5e4ae65d Mon Sep 17 00:00:00 2001 From: Eric Date: Sun, 10 Sep 2023 13:28:28 -0700 Subject: [PATCH] a bit more shutdown process cleanup --- .efrocachemap | 88 +++++++++---------- CHANGELOG.md | 2 +- src/assets/ba_data/python/babase/__init__.py | 2 - src/assets/ba_data/python/babase/_app.py | 61 ++++++++++--- .../ba_data/python/babase/_appmodeselector.py | 2 +- .../ba_data/python/babase/_appsubsystem.py | 7 +- src/assets/ba_data/python/babase/_general.py | 59 +++---------- .../ba_data/python/baclassic/_subsystem.py | 31 +++++++ src/assets/ba_data/python/baenv.py | 2 +- src/assets/ba_data/python/bascenev1/_lobby.py | 2 +- src/ballistica/base/base.cc | 2 + src/ballistica/base/logic/logic.cc | 5 +- src/ballistica/shared/ballistica.cc | 2 +- 13 files changed, 147 insertions(+), 118 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 7f37d834..c77a4af6 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4064,50 +4064,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": "be7456a804d5eb5d2ff3e3b0530b0017", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "b399f5228f71d01ad463f9adf6f9f3e3", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "c4571dc43b79a99f26a4063fe99cd24c", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "26e0d031dbb08e82f7972a605a00f54b", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "dfa74ed91d8a078ce7b1f55b81eef757", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "8e3910433139fefbe38aa1c82860a74d", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "21bc802d885c62fd08e5401c194d9ade", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "c197698cbf697bc2a9dcde4360e77774", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "15a86a0b661bdc17dd45e090499f543a", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "fa7e82973a3c7c3c65ab34289dcf1347", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "d90df2394233c26521a95fd28480eea7", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "fa6046684edee83a2e284713fa95d429", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "0705a4932544b892d270211232635d40", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "400866a75e8e2e7c585c52ab1d1d31e7", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "935d50a2ed3a47b7e91a31f9270702c5", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "cb26b566d37c2855f76d4e5d0d282389", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "67030df7a210f36f7bc0440c710aabd3", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "76febafca7f3234053af1b9aec0c2e17", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "679e7c1cc7429e7d6e3d2c3acf7af7e5", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "4a05fa84099fdb1ac4a1079e80c2820c", - "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "c60d7bbdc75fc714a982213c8ca8dddb", - "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "38c3726c684e5a87c9b875ba33d416d2", - "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "c60d7bbdc75fc714a982213c8ca8dddb", - "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "38c3726c684e5a87c9b875ba33d416d2", - "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "ed4ba7cce56cc2b91d344f03b22ec23d", - "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "b2a242985db24c2d486d72e0c4d06bde", - "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "ed4ba7cce56cc2b91d344f03b22ec23d", - "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "b2a242985db24c2d486d72e0c4d06bde", - "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "57d5225333eaf9e0df25cd54a1f58411", - "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "e17654c90848f85140030c45e5a6ed6b", - "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "57d5225333eaf9e0df25cd54a1f58411", - "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "e17654c90848f85140030c45e5a6ed6b", - "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "8d4d62bb78e1bae5947a9e1c5f602425", - "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "e00d5c375cabf7026557f2780edc6589", - "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "cafeecd06961bee4ca51e2c34a25f137", - "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "e00d5c375cabf7026557f2780edc6589", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "202043a4df67abe971cb887cc9ab40ce", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "73aada04161cc1e64306ba8964b65273", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "808a7fe357ceb8fc3f387d44b9c82890", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "5e757aa1dcdc5a66826c1f21e31a85fd", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "aec6cbbbaff1be15c197999b4a2adb76", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "b6dc26173fd02722a96e6994a775a3f6", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "e799ebd0d74fec947b2d8696701b5719", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "fd08bc9cc162d1339394145d20516447", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "44dec65bbb43c2424334cce255b55836", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "55489d3d62fd081b83c4df871e40ad27", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "21530b0be2f54d1c457a8c2ca5bfb480", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "a3d058738fc7891bc1d0139654b5fc26", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "8d4b813a4955b6574b4e0e6b413ad7cf", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "7c618d9dac85afc6a7be8c7927693e81", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "2b2ddfe86feb7e701d472264c5d7ea83", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "63f59ed473e1f954786284d6988c1a2b", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "b703788a1e3aef102349db7968b2dd99", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "dd4ea149455ddf77db357bbcf92622ac", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "d0651d0ed865c44f45a0e86a93fdf46b", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "65f43cfa50bf3fb198ccdacb5ac7dfe4", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "a2b3388c4deec4e980a0268b0757ac3a", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "a60d7430b9ba3cf71bc9ffe5944026fc", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "d08625da75aba13159ea4e649b87eff9", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "c265fede38b25b8257ae1e6acb1d8036", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "74f47c43f480f60732b43a0f9b80f76d", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "c9b4d66d5ce318e5cecb7412771fbfba", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "fe6ad3d4cdaadd56326f5e616588b3fb", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "772769bf8f5c49031782f68eaa49c0d3", + "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "a075beb846859a3bee6b4fc1c4d9369b", + "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "208a67fb7e7b942988e8520f9570138e", + "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "a075beb846859a3bee6b4fc1c4d9369b", + "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "208a67fb7e7b942988e8520f9570138e", + "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "2a98d808b017ddac714d2f266d443394", + "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "24c7f0248a8f59e5349db9c040e6bd4f", + "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "2a98d808b017ddac714d2f266d443394", + "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "24c7f0248a8f59e5349db9c040e6bd4f", + "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "e8f8be3a0ba00a2ecb8956c2459107ec", + "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "741e277f99d48437a5a1b9dacef107ee", + "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "e8f8be3a0ba00a2ecb8956c2459107ec", + "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "741e277f99d48437a5a1b9dacef107ee", + "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "3db2e9a04f23052f3a14390a0f7ba00e", + "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "15cf0e78e70d952c14c4b5e9ad6ef749", + "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "a0b27fbfca2dd7404a20997fbfa10a7f", + "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "15cf0e78e70d952c14c4b5e9ad6ef749", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "25d06d95141284fff10db4a55ed481eb", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "708878d75d73b8510b354b2f353da621", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "b8b36fd481e253e83b3cf90734a7d627", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "17cb96c46a7e1763fdfbc6f48199f547", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "ae3b27deef1240beb1b32a17a46b7d90", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "0e2c5cec39ac27d42cb5cd635da996bd", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "6b278874c0c0526494bd94aad4a817ae", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "55d3224895c30042caca26e6d77e406b", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318", "src/ballistica/base/mgen/pyembed/binding_base.inc": "ad347097a38e0d7ede9eb6dec6a80ee9", diff --git a/CHANGELOG.md b/CHANGELOG.md index aed93447..fbbc62da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.28 (build 21328, api 8, 2023-09-09) +### 1.7.28 (build 21329, api 8, 2023-09-10) - Renamed Console to DevConsole, and added an option under advanced settings to always show an ugly 'dev' button onscreen which can be used to toggle it. The diff --git a/src/assets/ba_data/python/babase/__init__.py b/src/assets/ba_data/python/babase/__init__.py index cdf8c69d..1b5520b3 100644 --- a/src/assets/ba_data/python/babase/__init__.py +++ b/src/assets/ba_data/python/babase/__init__.py @@ -143,7 +143,6 @@ from babase._general import ( storagename, getclass, get_type_name, - json_prep, ) from babase._keyboard import Keyboard from babase._language import Lstr, LanguageSubsystem @@ -244,7 +243,6 @@ __all__ = [ 'is_point_in_box', 'is_running_on_fire_tv', 'is_xcode_build', - 'json_prep', 'Keyboard', 'LanguageSubsystem', 'lock_all_input', diff --git a/src/assets/ba_data/python/babase/_app.py b/src/assets/ba_data/python/babase/_app.py index b6ce5648..ac366c04 100644 --- a/src/assets/ba_data/python/babase/_app.py +++ b/src/assets/ba_data/python/babase/_app.py @@ -97,6 +97,9 @@ class App: # The app is shutting down. SHUTTING_DOWN = 6 + # The app has completed shutdown. + SHUTDOWN_COMPLETE = 7 + class DefaultAppModeSelector(AppModeSelector): """Decides which AppModes to use to handle AppIntents. @@ -142,7 +145,8 @@ class App: feature-set modules such as babase. """ - # Hack for docs-generation. + # Hack for docs-generation: we can be imported with dummy modules + # instead of our actual binary ones, but we don't function. if os.environ.get('BA_RUNNING_WITH_DUMMY_MODULES') == '1': return @@ -174,6 +178,7 @@ class App: self._native_start_called = False self._native_paused = False self._native_shutdown_called = False + self._native_shutdown_complete_called = False self._initial_sign_in_completed = False self._called_on_initing = False self._called_on_loading = False @@ -193,16 +198,17 @@ class App: ] def postinit(self) -> None: - """Called after we've been inited and assigned to babase.app.""" + """Called after we've been inited and assigned to babase.app. - # Hack for docs-generation. + Anything that accesses babase.app as part of its init process + must go here instead of __init__. + """ + + # Hack for docs-generation: we can be imported with dummy modules + # instead of our actual binary ones, but we don't function. if os.environ.get('BA_RUNNING_WITH_DUMMY_MODULES') == '1': return - # NOTE: the reason we need a postinit here is that some of this - # stuff accesses babase.app and that doesn't exist yet as of our - # __init__() call. - self.lang = LanguageSubsystem() self.plugins = PluginSubsystem() @@ -308,9 +314,13 @@ class App: Note that tasks will be killed after App.SHUTDOWN_TASK_TIMEOUT_SECONDS if they are still running. """ - if self.state is self.State.SHUTTING_DOWN: + if ( + self.state is self.State.SHUTTING_DOWN + or self.state is self.State.SHUTDOWN_COMPLETE + ): + stname = self.state.name raise RuntimeError( - 'Cannot add shutdown tasks with state SHUTTING_DOWN.' + f'Cannot add shutdown tasks with current state {stname}.' ) self._shutdown_tasks.append(coro) @@ -398,6 +408,8 @@ class App: def on_native_shutdown_complete(self) -> None: """Called by the native layer when the app is done shutting down.""" assert _babase.in_logic_thread() + self._native_shutdown_complete_called = True + self._update_state() def read_config(self) -> None: """(internal)""" @@ -697,13 +709,21 @@ class App: # pylint: disable=too-many-branches assert _babase.in_logic_thread() - # Shutdown trumps all. Though we can't shut down until init is - # completed since we need our asyncio stuff to exist for the - # shutdown process. - if self._native_shutdown_called and self._init_completed: + # Shutdown-complete trumps absolutely all. + if self._native_shutdown_complete_called: + if self.state is not self.State.SHUTDOWN_COMPLETE: + self.state = self.State.SHUTDOWN_COMPLETE + _babase.lifecyclelog('app state shutdown complete') + self._on_shutdown_complete() + + # Shutdown trumps all. Though we can't start shutting down until + # init is completed since we need our asyncio stuff to exist for + # the shutdown process. + elif self._native_shutdown_called and self._init_completed: # Entering shutdown state: if self.state is not self.State.SHUTTING_DOWN: self.state = self.State.SHUTTING_DOWN + _babase.lifecyclelog('app state shutting down') self._on_shutting_down() elif self._native_paused: @@ -825,6 +845,21 @@ class App: assert self._aioloop is not None self._shutdown_task = self._aioloop.create_task(self._shutdown()) + def _on_shutdown_complete(self) -> None: + """(internal)""" + assert _babase.in_logic_thread() + + # Inform app subsystems that we're done shutting down in the opposite + # order they were inited. + for subsystem in reversed(self._subsystems): + try: + subsystem.on_app_shutdown_complete() + except Exception: + logging.exception( + 'Error in on_app_shutdown_complete for subsystem %s.', + subsystem, + ) + async def _wait_for_shutdown_suppressions(self) -> None: import asyncio diff --git a/src/assets/ba_data/python/babase/_appmodeselector.py b/src/assets/ba_data/python/babase/_appmodeselector.py index cfdf03ba..9dff2cbc 100644 --- a/src/assets/ba_data/python/babase/_appmodeselector.py +++ b/src/assets/ba_data/python/babase/_appmodeselector.py @@ -1,6 +1,6 @@ # Released under the MIT License. See LICENSE for details. # -"""Provides AppMode functionality.""" +"""Contains AppModeSelector base class.""" from __future__ import annotations from typing import TYPE_CHECKING diff --git a/src/assets/ba_data/python/babase/_appsubsystem.py b/src/assets/ba_data/python/babase/_appsubsystem.py index 6bee6f97..eae0981a 100644 --- a/src/assets/ba_data/python/babase/_appsubsystem.py +++ b/src/assets/ba_data/python/babase/_appsubsystem.py @@ -18,8 +18,8 @@ class AppSubsystem: An app 'subsystem' is a bit of a vague term, as pieces of the app can technically be any class and are not required to use this, but - building one out of this base class provides some conveniences such - as predefined callbacks during app state changes. + building one out of this base class provides conveniences such as + predefined callbacks during app state changes. Subsystems must be registered with the app before it completes its transition to the 'running' state. @@ -48,5 +48,8 @@ class AppSubsystem: def on_app_shutdown(self) -> None: """Called when the app is shutting down.""" + def on_app_shutdown_complete(self) -> None: + """Called when the app is done shutting down.""" + def do_apply_app_config(self) -> None: """Called when the app config should be applied.""" diff --git a/src/assets/ba_data/python/babase/_general.py b/src/assets/ba_data/python/babase/_general.py index bc3ec1c3..206ac036 100644 --- a/src/assets/ba_data/python/babase/_general.py +++ b/src/assets/ba_data/python/babase/_general.py @@ -6,12 +6,13 @@ from __future__ import annotations import types import weakref import random +import logging import inspect from typing import TYPE_CHECKING, TypeVar, Protocol, NewType from efro.terminal import Clr + import _babase -from babase._error import print_error, print_exception if TYPE_CHECKING: from typing import Any @@ -19,7 +20,8 @@ if TYPE_CHECKING: # Declare distinct types for different time measurements we use so the -# type-checker can help prevent us from mixing and matching accidentally. +# type-checker can help prevent us from mixing and matching accidentally, +# even if the *actual* types being used are the same. # Our monotonic time measurement that starts at 0 when the app launches # and pauses while the app is suspended. @@ -85,39 +87,6 @@ def getclass(name: str, subclassof: type[T]) -> type[T]: return cls -def json_prep(data: Any) -> Any: - """Return a json-friendly version of the provided data. - - This converts any tuples to lists and any bytes to strings - (interpreted as utf-8, ignoring errors). Logs errors (just once) - if any data is modified/discarded/unsupported. - """ - - if isinstance(data, dict): - return dict( - (json_prep(key), json_prep(value)) - for key, value in list(data.items()) - ) - if isinstance(data, list): - return [json_prep(element) for element in data] - if isinstance(data, tuple): - print_error('json_prep encountered tuple', once=True) - return [json_prep(element) for element in data] - if isinstance(data, bytes): - try: - return data.decode(errors='ignore') - except Exception: - from babase import _error - - print_error('json_prep encountered utf-8 decode error', once=True) - return data.decode(errors='ignore') - if not isinstance(data, (str, float, bool, type(None), int)): - print_error( - 'got unsupported type in json_prep:' + str(type(data)), once=True - ) - return data - - def utf8_all(data: Any) -> Any: """Convert any unicode data in provided sequence(s) to utf8 bytes.""" if isinstance(data, dict): @@ -136,7 +105,7 @@ def utf8_all(data: Any) -> Any: def get_type_name(cls: type) -> str: """Return a full type name including module for a class.""" - return cls.__module__ + '.' + cls.__name__ + return f'{cls.__module__}.{cls.__name__}' class _WeakCall: @@ -195,18 +164,12 @@ class _WeakCall: else: app = _babase.app if not self._did_invalid_call_warning: - print( - ( - 'Warning: callable passed to babase.WeakCall() is not' - ' weak-referencable (' - + str(args[0]) - + '); use babase.Call() instead to avoid this ' - 'warning. Stack-trace:' - ) + logging.warning( + 'Warning: callable passed to babase.WeakCall() is not' + ' weak-referencable (%s); use babase.Call() instead' + ' to avoid this warning.', + stack_info=True, ) - import traceback - - traceback.print_stack() self._did_invalid_call_warning = True self._call = args[0] self._args = args[1:] @@ -320,7 +283,7 @@ def verify_object_death(obj: object) -> None: try: ref = weakref.ref(obj) except Exception: - print_exception('Unable to create weak-ref in verify_object_death') + logging.exception('Unable to create weak-ref in verify_object_death') return # Use a slight range for our checks so they don't all land at once diff --git a/src/assets/ba_data/python/baclassic/_subsystem.py b/src/assets/ba_data/python/baclassic/_subsystem.py index 620c2ad3..db4fea55 100644 --- a/src/assets/ba_data/python/baclassic/_subsystem.py +++ b/src/assets/ba_data/python/baclassic/_subsystem.py @@ -466,6 +466,37 @@ class ClassicSubsystem(babase.AppSubsystem): _analytics.game_begin_analytics() + @classmethod + def json_prep(cls, data: Any) -> Any: + """Return a json-friendly version of the provided data. + + This converts any tuples to lists and any bytes to strings + (interpreted as utf-8, ignoring errors). Logs errors (just once) + if any data is modified/discarded/unsupported. + """ + + if isinstance(data, dict): + return dict( + (cls.json_prep(key), cls.json_prep(value)) + for key, value in list(data.items()) + ) + if isinstance(data, list): + return [cls.json_prep(element) for element in data] + if isinstance(data, tuple): + logging.exception('json_prep encountered tuple') + return [cls.json_prep(element) for element in data] + if isinstance(data, bytes): + try: + return data.decode(errors='ignore') + except Exception: + logging.exception('json_prep encountered utf-8 decode error') + return data.decode(errors='ignore') + if not isinstance(data, (str, float, bool, type(None), int)): + logging.exception( + 'got unsupported type in json_prep: %s', type(data) + ) + return data + def master_server_v1_get( self, request: str, diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 75aa2c64..89695cc6 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 = 21328 +TARGET_BALLISTICA_BUILD = 21329 TARGET_BALLISTICA_VERSION = '1.7.28' diff --git a/src/assets/ba_data/python/bascenev1/_lobby.py b/src/assets/ba_data/python/bascenev1/_lobby.py index 9422a4e4..aa2ab16f 100644 --- a/src/assets/ba_data/python/bascenev1/_lobby.py +++ b/src/assets/ba_data/python/bascenev1/_lobby.py @@ -462,7 +462,7 @@ class Chooser: # (non-unicode/non-json) version. # Make sure they conform to our standards # (unicode strings, no tuples, etc) - self._profiles = babase.json_prep(self._profiles) + self._profiles = app.classic.json_prep(self._profiles) # Filter out any characters we're unaware of. for profile in list(self._profiles.items()): diff --git a/src/ballistica/base/base.cc b/src/ballistica/base/base.cc index 8701ea85..30b74748 100644 --- a/src/ballistica/base/base.cc +++ b/src/ballistica/base/base.cc @@ -230,6 +230,8 @@ void BaseFeatureSet::OnAppShutdownComplete() { assert(g_core); assert(g_base); + g_core->LifecycleLog("app exiting (main thread)"); + // Flag our own event loop to exit (or ask the OS to if they're managing). if (app_adapter->ManagesEventLoop()) { g_core->main_event_loop()->Quit(); diff --git a/src/ballistica/base/logic/logic.cc b/src/ballistica/base/logic/logic.cc index 2b51e0aa..825ac8a0 100644 --- a/src/ballistica/base/logic/logic.cc +++ b/src/ballistica/base/logic/logic.cc @@ -221,8 +221,6 @@ void Logic::OnAppShutdown() { assert(g_base->CurrentContext().IsEmpty()); assert(shutting_down_); - g_core->LifecycleLog("app state shutting down"); - // Nuke the app from orbit if we get stuck while shutting down. g_core->StartSuicideTimer("shutdown", 10000); @@ -259,13 +257,12 @@ void Logic::OnAppShutdownComplete() { // Wrap up any last business here in the logic thread and then kick things // over to the main thread to exit out of the main loop. - g_core->LifecycleLog("app shutdown complete"); // Let our logic subsystems know in case there's any last thing they'd // like to do right before we exit. // Note: Keep these in opposite order of OnAppStart. // Note2: Any shutdown processes that take a non-zero amount of time - // should be registered as shutdown-tasks + // should be registered as shutdown-tasks. g_base->python->OnAppShutdownComplete(); if (g_base->HavePlus()) { g_base->plus()->OnAppShutdownComplete(); diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index dab2e917..eeab6728 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 = 21328; +const int kEngineBuildNumber = 21329; const char* kEngineVersion = "1.7.28"; const int kEngineApiVersion = 8;