a bit more shutdown process cleanup

This commit is contained in:
Eric 2023-09-10 13:28:28 -07:00
parent a34a78f4e6
commit f23365726b
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
13 changed files with 147 additions and 118 deletions

88
.efrocachemap generated
View File

@ -4064,50 +4064,50 @@
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "be7456a804d5eb5d2ff3e3b0530b0017", "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "44dec65bbb43c2424334cce255b55836",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "b399f5228f71d01ad463f9adf6f9f3e3", "build/prefab/full/linux_arm64_gui/release/ballisticakit": "55489d3d62fd081b83c4df871e40ad27",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "c4571dc43b79a99f26a4063fe99cd24c", "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "21530b0be2f54d1c457a8c2ca5bfb480",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "26e0d031dbb08e82f7972a605a00f54b", "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "a3d058738fc7891bc1d0139654b5fc26",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "dfa74ed91d8a078ce7b1f55b81eef757", "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "8d4b813a4955b6574b4e0e6b413ad7cf",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "8e3910433139fefbe38aa1c82860a74d", "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "7c618d9dac85afc6a7be8c7927693e81",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "21bc802d885c62fd08e5401c194d9ade", "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "2b2ddfe86feb7e701d472264c5d7ea83",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "c197698cbf697bc2a9dcde4360e77774", "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "63f59ed473e1f954786284d6988c1a2b",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "15a86a0b661bdc17dd45e090499f543a", "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "b703788a1e3aef102349db7968b2dd99",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "fa7e82973a3c7c3c65ab34289dcf1347", "build/prefab/full/mac_arm64_gui/release/ballisticakit": "dd4ea149455ddf77db357bbcf92622ac",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "d90df2394233c26521a95fd28480eea7", "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "d0651d0ed865c44f45a0e86a93fdf46b",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "fa6046684edee83a2e284713fa95d429", "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "65f43cfa50bf3fb198ccdacb5ac7dfe4",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "0705a4932544b892d270211232635d40", "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "a2b3388c4deec4e980a0268b0757ac3a",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "400866a75e8e2e7c585c52ab1d1d31e7", "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "a60d7430b9ba3cf71bc9ffe5944026fc",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "935d50a2ed3a47b7e91a31f9270702c5", "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "d08625da75aba13159ea4e649b87eff9",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "cb26b566d37c2855f76d4e5d0d282389", "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "c265fede38b25b8257ae1e6acb1d8036",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "67030df7a210f36f7bc0440c710aabd3", "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "74f47c43f480f60732b43a0f9b80f76d",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "76febafca7f3234053af1b9aec0c2e17", "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "c9b4d66d5ce318e5cecb7412771fbfba",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "679e7c1cc7429e7d6e3d2c3acf7af7e5", "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "fe6ad3d4cdaadd56326f5e616588b3fb",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "4a05fa84099fdb1ac4a1079e80c2820c", "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "772769bf8f5c49031782f68eaa49c0d3",
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "c60d7bbdc75fc714a982213c8ca8dddb", "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "a075beb846859a3bee6b4fc1c4d9369b",
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "38c3726c684e5a87c9b875ba33d416d2", "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "208a67fb7e7b942988e8520f9570138e",
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "c60d7bbdc75fc714a982213c8ca8dddb", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "a075beb846859a3bee6b4fc1c4d9369b",
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "38c3726c684e5a87c9b875ba33d416d2", "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "208a67fb7e7b942988e8520f9570138e",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "ed4ba7cce56cc2b91d344f03b22ec23d", "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "2a98d808b017ddac714d2f266d443394",
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "b2a242985db24c2d486d72e0c4d06bde", "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "24c7f0248a8f59e5349db9c040e6bd4f",
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "ed4ba7cce56cc2b91d344f03b22ec23d", "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "2a98d808b017ddac714d2f266d443394",
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "b2a242985db24c2d486d72e0c4d06bde", "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "24c7f0248a8f59e5349db9c040e6bd4f",
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "57d5225333eaf9e0df25cd54a1f58411", "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "e8f8be3a0ba00a2ecb8956c2459107ec",
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "e17654c90848f85140030c45e5a6ed6b", "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "741e277f99d48437a5a1b9dacef107ee",
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "57d5225333eaf9e0df25cd54a1f58411", "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "e8f8be3a0ba00a2ecb8956c2459107ec",
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "e17654c90848f85140030c45e5a6ed6b", "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "741e277f99d48437a5a1b9dacef107ee",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "8d4d62bb78e1bae5947a9e1c5f602425", "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "3db2e9a04f23052f3a14390a0f7ba00e",
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "e00d5c375cabf7026557f2780edc6589", "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "15cf0e78e70d952c14c4b5e9ad6ef749",
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "cafeecd06961bee4ca51e2c34a25f137", "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "a0b27fbfca2dd7404a20997fbfa10a7f",
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "e00d5c375cabf7026557f2780edc6589", "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "15cf0e78e70d952c14c4b5e9ad6ef749",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "202043a4df67abe971cb887cc9ab40ce", "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "25d06d95141284fff10db4a55ed481eb",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "73aada04161cc1e64306ba8964b65273", "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "708878d75d73b8510b354b2f353da621",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "808a7fe357ceb8fc3f387d44b9c82890", "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "b8b36fd481e253e83b3cf90734a7d627",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "5e757aa1dcdc5a66826c1f21e31a85fd", "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "17cb96c46a7e1763fdfbc6f48199f547",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "aec6cbbbaff1be15c197999b4a2adb76", "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "ae3b27deef1240beb1b32a17a46b7d90",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "b6dc26173fd02722a96e6994a775a3f6", "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "0e2c5cec39ac27d42cb5cd635da996bd",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "e799ebd0d74fec947b2d8696701b5719", "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "6b278874c0c0526494bd94aad4a817ae",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "fd08bc9cc162d1339394145d20516447", "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/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
"src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318", "src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318",
"src/ballistica/base/mgen/pyembed/binding_base.inc": "ad347097a38e0d7ede9eb6dec6a80ee9", "src/ballistica/base/mgen/pyembed/binding_base.inc": "ad347097a38e0d7ede9eb6dec6a80ee9",

View File

@ -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 - 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 always show an ugly 'dev' button onscreen which can be used to toggle it. The

View File

@ -143,7 +143,6 @@ from babase._general import (
storagename, storagename,
getclass, getclass,
get_type_name, get_type_name,
json_prep,
) )
from babase._keyboard import Keyboard from babase._keyboard import Keyboard
from babase._language import Lstr, LanguageSubsystem from babase._language import Lstr, LanguageSubsystem
@ -244,7 +243,6 @@ __all__ = [
'is_point_in_box', 'is_point_in_box',
'is_running_on_fire_tv', 'is_running_on_fire_tv',
'is_xcode_build', 'is_xcode_build',
'json_prep',
'Keyboard', 'Keyboard',
'LanguageSubsystem', 'LanguageSubsystem',
'lock_all_input', 'lock_all_input',

View File

@ -97,6 +97,9 @@ class App:
# The app is shutting down. # The app is shutting down.
SHUTTING_DOWN = 6 SHUTTING_DOWN = 6
# The app has completed shutdown.
SHUTDOWN_COMPLETE = 7
class DefaultAppModeSelector(AppModeSelector): class DefaultAppModeSelector(AppModeSelector):
"""Decides which AppModes to use to handle AppIntents. """Decides which AppModes to use to handle AppIntents.
@ -142,7 +145,8 @@ class App:
feature-set modules such as babase. 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': if os.environ.get('BA_RUNNING_WITH_DUMMY_MODULES') == '1':
return return
@ -174,6 +178,7 @@ class App:
self._native_start_called = False self._native_start_called = False
self._native_paused = False self._native_paused = False
self._native_shutdown_called = False self._native_shutdown_called = False
self._native_shutdown_complete_called = False
self._initial_sign_in_completed = False self._initial_sign_in_completed = False
self._called_on_initing = False self._called_on_initing = False
self._called_on_loading = False self._called_on_loading = False
@ -193,16 +198,17 @@ class App:
] ]
def postinit(self) -> None: 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': if os.environ.get('BA_RUNNING_WITH_DUMMY_MODULES') == '1':
return 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.lang = LanguageSubsystem()
self.plugins = PluginSubsystem() self.plugins = PluginSubsystem()
@ -308,9 +314,13 @@ class App:
Note that tasks will be killed after Note that tasks will be killed after
App.SHUTDOWN_TASK_TIMEOUT_SECONDS if they are still running. 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( raise RuntimeError(
'Cannot add shutdown tasks with state SHUTTING_DOWN.' f'Cannot add shutdown tasks with current state {stname}.'
) )
self._shutdown_tasks.append(coro) self._shutdown_tasks.append(coro)
@ -398,6 +408,8 @@ class App:
def on_native_shutdown_complete(self) -> None: def on_native_shutdown_complete(self) -> None:
"""Called by the native layer when the app is done shutting down.""" """Called by the native layer when the app is done shutting down."""
assert _babase.in_logic_thread() assert _babase.in_logic_thread()
self._native_shutdown_complete_called = True
self._update_state()
def read_config(self) -> None: def read_config(self) -> None:
"""(internal)""" """(internal)"""
@ -697,13 +709,21 @@ class App:
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
assert _babase.in_logic_thread() assert _babase.in_logic_thread()
# Shutdown trumps all. Though we can't shut down until init is # Shutdown-complete trumps absolutely all.
# completed since we need our asyncio stuff to exist for the if self._native_shutdown_complete_called:
# shutdown process. if self.state is not self.State.SHUTDOWN_COMPLETE:
if self._native_shutdown_called and self._init_completed: 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: # Entering shutdown state:
if self.state is not self.State.SHUTTING_DOWN: if self.state is not self.State.SHUTTING_DOWN:
self.state = self.State.SHUTTING_DOWN self.state = self.State.SHUTTING_DOWN
_babase.lifecyclelog('app state shutting down')
self._on_shutting_down() self._on_shutting_down()
elif self._native_paused: elif self._native_paused:
@ -825,6 +845,21 @@ class App:
assert self._aioloop is not None assert self._aioloop is not None
self._shutdown_task = self._aioloop.create_task(self._shutdown()) 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: async def _wait_for_shutdown_suppressions(self) -> None:
import asyncio import asyncio

View File

@ -1,6 +1,6 @@
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# #
"""Provides AppMode functionality.""" """Contains AppModeSelector base class."""
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING

View File

@ -18,8 +18,8 @@ class AppSubsystem:
An app 'subsystem' is a bit of a vague term, as pieces of the app 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 can technically be any class and are not required to use this, but
building one out of this base class provides some conveniences such building one out of this base class provides conveniences such as
as predefined callbacks during app state changes. predefined callbacks during app state changes.
Subsystems must be registered with the app before it completes its Subsystems must be registered with the app before it completes its
transition to the 'running' state. transition to the 'running' state.
@ -48,5 +48,8 @@ class AppSubsystem:
def on_app_shutdown(self) -> None: def on_app_shutdown(self) -> None:
"""Called when the app is shutting down.""" """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: def do_apply_app_config(self) -> None:
"""Called when the app config should be applied.""" """Called when the app config should be applied."""

View File

@ -6,12 +6,13 @@ from __future__ import annotations
import types import types
import weakref import weakref
import random import random
import logging
import inspect import inspect
from typing import TYPE_CHECKING, TypeVar, Protocol, NewType from typing import TYPE_CHECKING, TypeVar, Protocol, NewType
from efro.terminal import Clr from efro.terminal import Clr
import _babase import _babase
from babase._error import print_error, print_exception
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any from typing import Any
@ -19,7 +20,8 @@ if TYPE_CHECKING:
# Declare distinct types for different time measurements we use so the # 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 # Our monotonic time measurement that starts at 0 when the app launches
# and pauses while the app is suspended. # and pauses while the app is suspended.
@ -85,39 +87,6 @@ def getclass(name: str, subclassof: type[T]) -> type[T]:
return cls 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: def utf8_all(data: Any) -> Any:
"""Convert any unicode data in provided sequence(s) to utf8 bytes.""" """Convert any unicode data in provided sequence(s) to utf8 bytes."""
if isinstance(data, dict): if isinstance(data, dict):
@ -136,7 +105,7 @@ def utf8_all(data: Any) -> Any:
def get_type_name(cls: type) -> str: def get_type_name(cls: type) -> str:
"""Return a full type name including module for a class.""" """Return a full type name including module for a class."""
return cls.__module__ + '.' + cls.__name__ return f'{cls.__module__}.{cls.__name__}'
class _WeakCall: class _WeakCall:
@ -195,18 +164,12 @@ class _WeakCall:
else: else:
app = _babase.app app = _babase.app
if not self._did_invalid_call_warning: if not self._did_invalid_call_warning:
print( logging.warning(
( 'Warning: callable passed to babase.WeakCall() is not'
'Warning: callable passed to babase.WeakCall() is not' ' weak-referencable (%s); use babase.Call() instead'
' weak-referencable (' ' to avoid this warning.',
+ str(args[0]) stack_info=True,
+ '); use babase.Call() instead to avoid this '
'warning. Stack-trace:'
)
) )
import traceback
traceback.print_stack()
self._did_invalid_call_warning = True self._did_invalid_call_warning = True
self._call = args[0] self._call = args[0]
self._args = args[1:] self._args = args[1:]
@ -320,7 +283,7 @@ def verify_object_death(obj: object) -> None:
try: try:
ref = weakref.ref(obj) ref = weakref.ref(obj)
except Exception: 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 return
# Use a slight range for our checks so they don't all land at once # Use a slight range for our checks so they don't all land at once

View File

@ -466,6 +466,37 @@ class ClassicSubsystem(babase.AppSubsystem):
_analytics.game_begin_analytics() _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( def master_server_v1_get(
self, self,
request: str, request: str,

View File

@ -52,7 +52,7 @@ if TYPE_CHECKING:
# Build number and version of the ballistica binary we expect to be # Build number and version of the ballistica binary we expect to be
# using. # using.
TARGET_BALLISTICA_BUILD = 21328 TARGET_BALLISTICA_BUILD = 21329
TARGET_BALLISTICA_VERSION = '1.7.28' TARGET_BALLISTICA_VERSION = '1.7.28'

View File

@ -462,7 +462,7 @@ class Chooser:
# (non-unicode/non-json) version. # (non-unicode/non-json) version.
# Make sure they conform to our standards # Make sure they conform to our standards
# (unicode strings, no tuples, etc) # (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. # Filter out any characters we're unaware of.
for profile in list(self._profiles.items()): for profile in list(self._profiles.items()):

View File

@ -230,6 +230,8 @@ void BaseFeatureSet::OnAppShutdownComplete() {
assert(g_core); assert(g_core);
assert(g_base); 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). // Flag our own event loop to exit (or ask the OS to if they're managing).
if (app_adapter->ManagesEventLoop()) { if (app_adapter->ManagesEventLoop()) {
g_core->main_event_loop()->Quit(); g_core->main_event_loop()->Quit();

View File

@ -221,8 +221,6 @@ void Logic::OnAppShutdown() {
assert(g_base->CurrentContext().IsEmpty()); assert(g_base->CurrentContext().IsEmpty());
assert(shutting_down_); assert(shutting_down_);
g_core->LifecycleLog("app state shutting down");
// Nuke the app from orbit if we get stuck while shutting down. // Nuke the app from orbit if we get stuck while shutting down.
g_core->StartSuicideTimer("shutdown", 10000); 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 // 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. // 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 // Let our logic subsystems know in case there's any last thing they'd
// like to do right before we exit. // like to do right before we exit.
// Note: Keep these in opposite order of OnAppStart. // Note: Keep these in opposite order of OnAppStart.
// Note2: Any shutdown processes that take a non-zero amount of time // 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(); g_base->python->OnAppShutdownComplete();
if (g_base->HavePlus()) { if (g_base->HavePlus()) {
g_base->plus()->OnAppShutdownComplete(); g_base->plus()->OnAppShutdownComplete();

View File

@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
namespace ballistica { namespace ballistica {
// These are set automatically via script; don't modify them here. // These are set automatically via script; don't modify them here.
const int kEngineBuildNumber = 21328; const int kEngineBuildNumber = 21329;
const char* kEngineVersion = "1.7.28"; const char* kEngineVersion = "1.7.28";
const int kEngineApiVersion = 8; const int kEngineApiVersion = 8;