lots of logging improvements

This commit is contained in:
Eric 2024-10-19 09:46:32 -07:00
parent 643104f538
commit b3e23f7bff
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
169 changed files with 2679 additions and 1323 deletions

92
.efrocachemap generated
View File

@ -4096,56 +4096,56 @@
"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": "c8904594aa4867a7525e6644249d5fd5",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "7d3ba05e21b198bdccbdaf9d334f96f2",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "8601ef36314294c18b686995ce9a02f6",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "36742622076742a5642de8c287cd92e4",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "b05ee46d11b618cf917cae591fe6b97a",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "a9a03ded1e4fccfdc1879bd8f70e0e7a",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "05f37deacb796ef45828233ded9325e3",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "f4b4df8f17219f81148efe3dc057856f",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "b6201f83d4f80fcc567398807c7d77b5",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "331335944425c5a48abbcf137da46f0f",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "ac2d7714d87b781659c1e3333f760888",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "1e7cc9348498df9bfb7b25cd83009d7c",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "a3c7e011ad99046d2ef8b102e7d15733",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "43fd8535ad1e2c2c64fe57dacfb3305b",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "fc17d6883ddd4486a62b75494dbb9d15",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "0a557a638ee4cb3150d90bcb5913de3e",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "85afe70f81c1f7d2de9520d498c74eb8",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "a617c0412a804bce272113585c000318",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "5642e5614711b8e106de659db2b33ac7",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "ea7018647c89777469979aa08e88573e",
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "ba7dc0b4e927f32fcf15c2f738fe004c",
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "fb4c90da8d46ddab5847406fa397dbd5",
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "ba7dc0b4e927f32fcf15c2f738fe004c",
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "fb4c90da8d46ddab5847406fa397dbd5",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "225f13c4755aa018e63168c8aca0a8fd",
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "d4c6e0f0ac69af106f1227daeae2db55",
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "225f13c4755aa018e63168c8aca0a8fd",
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "d4c6e0f0ac69af106f1227daeae2db55",
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "e16971f1da7ad7f44bb185b4446965c6",
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "d5638285fa481d769a5cd488a78d8269",
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "e16971f1da7ad7f44bb185b4446965c6",
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "d5638285fa481d769a5cd488a78d8269",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "184b7e4731b09ccf3a6a3b001d8af097",
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "507b5555ef5d067caf18fe9844ca04c7",
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "838ee9bfd43169efe8daff8bb0efb1db",
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "507b5555ef5d067caf18fe9844ca04c7",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "d1edb04136c433b57f3842830e9b272d",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "4e64e07e3527e0536d1dc7f2dacd681a",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "301bad929a4f3c6e9f67e57ab730bded",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "6224ca7790cfa8274c3f9c8e4461b93f",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "bedcc6b5cc2a403a65d83c6244922feb",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "545edb5e8f7cce4e7bc3cdb0e4f98b82",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "79102625aebc9df3a0834f8d571fdbac",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "9e5a350dc8f5fcd1ab96c7a4c24a7ebe",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "b20c6e3a2287f1c6a9a898e78fcab105",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "0f1eff142f1e5796be2e0340dcbb4c8f",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "f40171c1c943c10e2d2120a586a711f7",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "ea494bdeb942cbab86c0371bb0558f3b",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "fba8474fd758e8d76bc6d7e90dfb7795",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "4b1a35c2e6d7c2d9a01c6e2750716c24",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "9ac4ee8aab0243a233ba8650cd0d0b73",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "c804d14d91dab05f644079ae47e61728",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "1f7011d1c77548e48b7f6d3ac09a29da",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "c50790a9a2e3001dd079a6bbd753c36f",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "52528037523bf268e2c59a19626e7f2d",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "a920948fcc94c397495ef8dd674d325b",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "d0f7ad9287edd649d97844ada500a11d",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "1073804b2d2549f9eb992666fc3640c3",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "73e6ca5aee9af5a87960b7ae174f0a71",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "c09c4fac16134d5071a88ec8d3e1e950",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "e78b8bd1cb5aa452f536c57e855bcc27",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "0f08643a492ac7bf8fd3f13460003bce",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "48e684f7db6d88a62009d773ab51b065",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "69a301acc9adfacdb8b3d200390bbfdd",
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "653df60722ed096b8cc3ac3a4196e5a5",
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "f82c1e575e8f23c1e278db61a740a4d5",
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "653df60722ed096b8cc3ac3a4196e5a5",
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "f82c1e575e8f23c1e278db61a740a4d5",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "90125afd27068280c96cf37c950b641f",
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "a210d341f1842b21ebbaadd80ae4a282",
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "90125afd27068280c96cf37c950b641f",
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "a210d341f1842b21ebbaadd80ae4a282",
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "cdf4fca1c1aaae2c2294263f0717b333",
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "937b954eed2571cb4d5f9d2a0e3f77ed",
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "cdf4fca1c1aaae2c2294263f0717b333",
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "937b954eed2571cb4d5f9d2a0e3f77ed",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "cdd7c61d6c0efd5fb0442e625123b63f",
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "ea327f45634a8e42259c5ecadf219e36",
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "547362a74979fa82b854a475dffeae90",
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "ea327f45634a8e42259c5ecadf219e36",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "828f4682e3bbdc0da5b45a0050aeb5d8",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "cf4b13af9f0846a466204afbe74b9e86",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "b43fa205beae83e030ec777d4974736b",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "aef585a4d739765b59f9a85dc27ff67f",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "559b65282ab2bfff034aa64963a7af52",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "5916245826eb4d3b68944006f82de6d9",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "6844834b7fc1030c234bee21a376a017",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "c9b29530b90bb59e8570d991072efd77",
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
"src/assets/ba_data/python/babase/_mgen/enums.py": "794d258d59fd17a61752843a9a0551ad",
"src/ballistica/base/mgen/pyembed/binding_base.inc": "efa61468cf098f77cc6a234461d8b86d",
"src/ballistica/base/mgen/pyembed/binding_base_app.inc": "97efb93f4bfd8e8b09f2db24398e29fc",
"src/ballistica/base/mgen/pyembed/binding_base_app.inc": "f0f9dc33ecd4ef7a384f131d62c96c97",
"src/ballistica/classic/mgen/pyembed/binding_classic.inc": "3ceb412513963f0818ab39c58bf292e3",
"src/ballistica/core/mgen/pyembed/binding_core.inc": "9d0a3c9636138e35284923e0c8311c69",
"src/ballistica/core/mgen/pyembed/binding_core.inc": "73bbc63c2a85aed75c26cfedf047fd9d",
"src/ballistica/core/mgen/pyembed/env.inc": "f015d726b44d2922112fc14d9f146d8b",
"src/ballistica/core/mgen/python_modules_monolithic.h": "fb967ed1c7db0c77d8deb4f00a7103c5",
"src/ballistica/scene_v1/mgen/pyembed/binding_scene_v1.inc": "c25b263f2a31fb5ebe057db07d144879",

View File

@ -1,9 +1,24 @@
### 1.7.37 (build 22025, api 9, 2024-10-07)
### 1.7.37 (build 22040, api 9, 2024-10-19)
- Bumping api version to 9. As you'll see below, there's some UI changes that
will require a bit of work for any UI mods to adapt to. If your mods don't
touch UI stuff at all you can simply bump your api version and call it a day.
I'm hopeful that api version won't need to be bumped again for along time (if
ever).
- Heavily reworked and cleaned up the logging system. There is now a 'ba' Python
logger and various logger categories under it such as 'ba.lifecycle',
'ba.connectivity' or 'ba.v2transport'. By setting these individual loggers to
different levels such as 'debug', one can easily observe and debug specific
parts of app behavior. Over time I will better organize the logger hierarchy
and wire up more functionality to be logged this way.
- Added a 'Logging' tab to the dev-console. This allows easily setting log
levels for all existing Python loggers, as well as resetting them all to
defaults. Levels set here are restored on startup, so it is possible to debug
app startup behavior this way. Previously this sort of thing would generally
require setting cryptic environment variables which was not feasable on all
platforms, but this new system should work everywhere.
- Logs printed to both the command line and the in-app console now include
timestamps and logger names, and are color coded for severity (DEBUG=blue,
INFO=default, WARNING=orange/yellow, ERROR=red, CRITICAL=purple).
- Went ahead and fully removed `efro.call.tpartial` (since we're breaking
compatibility anyway by bumping api version). If you are using
`efro.call.tpartial` anywhere, simply replace it with `functools.partial`.
@ -113,6 +128,8 @@
it will take you back to the co-op screen.
- (build 22018) Hardened SDL joystick handling code so the app won't crash if
SDL_JoystickOpen() returns nullptr for whatever reason.
- (build 22028) Fixed a longstanding issue that could cause logic thread
bg-dynamics message overflows.
### 1.7.36 (build 21944, api 8, 2024-07-26)
- Wired up Tokens, BombSquad's new purchasable currency. The first thing these
@ -159,6 +176,8 @@
version and then upgrading to later builds of the same version containing
incompatibilities with the older sys scripts. This should help with that
problem.
- `efro.log` is now `efro.logging` which better lines up with other logging
module names. It was originally named `log` to work around a mypy bug.
### 1.7.35 (build 21889, api 8, 2024-06-20)
- Fixed an issue where the engine would block at exit on some version of Linux

View File

@ -2,9 +2,9 @@ cpplint==2.0.0
dmgbuild==1.6.2
filelock==3.16.1
furo==2024.8.6
mypy==1.11.2
mypy==1.12.0
pbxproj==4.2.1
pdoc==14.7.0
pdoc==15.0.0
pur==7.3.2
pylint==3.3.1
pylsp-mypy==0.6.9
@ -13,10 +13,10 @@ python-daemon==3.0.1
python-lsp-black==2.0.0
python-lsp-server==1.12.0
requests==2.32.3
Sphinx==8.0.2
Sphinx==8.1.3
tomlkit==0.13.2
types-certifi==2021.10.8.3
types-filelock==3.2.7
types-requests==2.32.0.20240914
types-requests==2.32.0.20241016
typing_extensions==4.12.2
urllib3==2.2.3

View File

@ -14,6 +14,7 @@
"ba_data/python/babase/__pycache__/_assetmanager.cpython-312.opt-1.pyc",
"ba_data/python/babase/__pycache__/_asyncio.cpython-312.opt-1.pyc",
"ba_data/python/babase/__pycache__/_devconsole.cpython-312.opt-1.pyc",
"ba_data/python/babase/__pycache__/_devconsoletabs.cpython-312.opt-1.pyc",
"ba_data/python/babase/__pycache__/_emptyappmode.cpython-312.opt-1.pyc",
"ba_data/python/babase/__pycache__/_env.cpython-312.opt-1.pyc",
"ba_data/python/babase/__pycache__/_error.cpython-312.opt-1.pyc",
@ -42,6 +43,7 @@
"ba_data/python/babase/_assetmanager.py",
"ba_data/python/babase/_asyncio.py",
"ba_data/python/babase/_devconsole.py",
"ba_data/python/babase/_devconsoletabs.py",
"ba_data/python/babase/_emptyappmode.py",
"ba_data/python/babase/_env.py",
"ba_data/python/babase/_error.py",
@ -103,6 +105,8 @@
"ba_data/python/bacommon/__pycache__/bacloud.cpython-312.opt-1.pyc",
"ba_data/python/bacommon/__pycache__/build.cpython-312.opt-1.pyc",
"ba_data/python/bacommon/__pycache__/cloud.cpython-312.opt-1.pyc",
"ba_data/python/bacommon/__pycache__/loggercontrol.cpython-312.opt-1.pyc",
"ba_data/python/bacommon/__pycache__/logging.cpython-312.opt-1.pyc",
"ba_data/python/bacommon/__pycache__/login.cpython-312.opt-1.pyc",
"ba_data/python/bacommon/__pycache__/net.cpython-312.opt-1.pyc",
"ba_data/python/bacommon/__pycache__/servermanager.cpython-312.opt-1.pyc",
@ -112,6 +116,8 @@
"ba_data/python/bacommon/bacloud.py",
"ba_data/python/bacommon/build.py",
"ba_data/python/bacommon/cloud.py",
"ba_data/python/bacommon/loggercontrol.py",
"ba_data/python/bacommon/logging.py",
"ba_data/python/bacommon/login.py",
"ba_data/python/bacommon/net.py",
"ba_data/python/bacommon/servermanager.py",
@ -577,7 +583,7 @@
"ba_data/python/efro/__pycache__/cloudshell.cpython-312.opt-1.pyc",
"ba_data/python/efro/__pycache__/debug.cpython-312.opt-1.pyc",
"ba_data/python/efro/__pycache__/error.cpython-312.opt-1.pyc",
"ba_data/python/efro/__pycache__/log.cpython-312.opt-1.pyc",
"ba_data/python/efro/__pycache__/logging.cpython-312.opt-1.pyc",
"ba_data/python/efro/__pycache__/rpc.cpython-312.opt-1.pyc",
"ba_data/python/efro/__pycache__/terminal.cpython-312.opt-1.pyc",
"ba_data/python/efro/__pycache__/util.cpython-312.opt-1.pyc",
@ -601,7 +607,7 @@
"ba_data/python/efro/dataclassio/extras.py",
"ba_data/python/efro/debug.py",
"ba_data/python/efro/error.py",
"ba_data/python/efro/log.py",
"ba_data/python/efro/logging.py",
"ba_data/python/efro/message/__init__.py",
"ba_data/python/efro/message/__pycache__/__init__.cpython-312.opt-1.pyc",
"ba_data/python/efro/message/__pycache__/_message.cpython-312.opt-1.pyc",

View File

@ -175,6 +175,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
$(BUILD_DIR)/ba_data/python/babase/_assetmanager.py \
$(BUILD_DIR)/ba_data/python/babase/_asyncio.py \
$(BUILD_DIR)/ba_data/python/babase/_devconsole.py \
$(BUILD_DIR)/ba_data/python/babase/_devconsoletabs.py \
$(BUILD_DIR)/ba_data/python/babase/_emptyappmode.py \
$(BUILD_DIR)/ba_data/python/babase/_env.py \
$(BUILD_DIR)/ba_data/python/babase/_error.py \
@ -452,6 +453,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_assetmanager.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_asyncio.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_devconsole.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_devconsoletabs.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_emptyappmode.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_env.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_error.cpython-312.opt-1.pyc \
@ -732,6 +734,8 @@ SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \
$(BUILD_DIR)/ba_data/python/bacommon/bacloud.py \
$(BUILD_DIR)/ba_data/python/bacommon/build.py \
$(BUILD_DIR)/ba_data/python/bacommon/cloud.py \
$(BUILD_DIR)/ba_data/python/bacommon/loggercontrol.py \
$(BUILD_DIR)/ba_data/python/bacommon/logging.py \
$(BUILD_DIR)/ba_data/python/bacommon/login.py \
$(BUILD_DIR)/ba_data/python/bacommon/net.py \
$(BUILD_DIR)/ba_data/python/bacommon/servermanager.py \
@ -751,7 +755,7 @@ SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \
$(BUILD_DIR)/ba_data/python/efro/dataclassio/extras.py \
$(BUILD_DIR)/ba_data/python/efro/debug.py \
$(BUILD_DIR)/ba_data/python/efro/error.py \
$(BUILD_DIR)/ba_data/python/efro/log.py \
$(BUILD_DIR)/ba_data/python/efro/logging.py \
$(BUILD_DIR)/ba_data/python/efro/message/__init__.py \
$(BUILD_DIR)/ba_data/python/efro/message/_message.py \
$(BUILD_DIR)/ba_data/python/efro/message/_module.py \
@ -769,6 +773,8 @@ SCRIPT_TARGETS_PYC_PUBLIC_TOOLS = \
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/bacloud.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/build.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/cloud.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/loggercontrol.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/logging.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/login.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/net.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bacommon/__pycache__/servermanager.cpython-312.opt-1.pyc \
@ -788,7 +794,7 @@ SCRIPT_TARGETS_PYC_PUBLIC_TOOLS = \
$(BUILD_DIR)/ba_data/python/efro/dataclassio/__pycache__/extras.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/efro/__pycache__/debug.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/efro/__pycache__/error.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/efro/__pycache__/log.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/efro/__pycache__/logging.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/efro/message/__pycache__/__init__.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/efro/message/__pycache__/_message.cpython-312.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/efro/message/__pycache__/_module.cpython-312.opt-1.pyc \

View File

@ -15,6 +15,7 @@ a more focused way.
# dependency loops. The exception is TYPE_CHECKING blocks and
# annotations since those aren't evaluated at runtime.
import logging
from efro.util import set_canonical_module_names
@ -109,6 +110,7 @@ from _babase import (
supports_max_fps,
supports_vsync,
unlock_all_input,
update_internal_logger_levels,
user_agent_string,
Vec3,
workspaces_in_use,
@ -185,6 +187,9 @@ from babase._plugin import PluginSpec, Plugin, PluginSubsystem
from babase._stringedit import StringEditAdapter, StringEditSubsystem
from babase._text import timestring
# Our standard set of loggers.
balog = logging.getLogger('ba')
_babase.app = app = App()
app.postinit()
@ -215,6 +220,7 @@ __all__ = [
'apptimer',
'AppTimer',
'asset_loads_allowed',
'balog',
'Call',
'fullscreen_control_available',
'fullscreen_control_get',
@ -344,6 +350,7 @@ __all__ = [
'timestring',
'UIScale',
'unlock_all_input',
'update_internal_logger_levels',
'user_agent_string',
'utf8_all',
'Vec3',

View File

@ -10,11 +10,12 @@ from functools import partial
from typing import TYPE_CHECKING, assert_never
from efro.error import CommunicationError
from efro.call import CallbackSet
from bacommon.login import LoginType
import _babase
if TYPE_CHECKING:
from typing import Any
from typing import Any, Callable
from babase._login import LoginAdapter, LoginInfo
@ -31,10 +32,12 @@ class AccountV2Subsystem:
"""
def __init__(self) -> None:
assert _babase.in_logic_thread()
from babase._login import LoginAdapterGPGS, LoginAdapterGameCenter
# Whether or not everything related to an initial login
# (or lack thereof) has completed. This includes things like
# Whether or not everything related to an initial sign in (or
# lack thereof) has completed. This includes things like
# workspace syncing. Completion of this is what flips the app
# into 'running' state.
self._initial_sign_in_completed = False
@ -46,6 +49,9 @@ class AccountV2Subsystem:
self._implicit_signed_in_adapter: LoginAdapter | None = None
self._implicit_state_changed = False
self._can_do_auto_sign_in = True
self.on_primary_account_changed_callbacks: CallbackSet[
Callable[[AccountV2Handle | None], None]
] = CallbackSet()
adapter: LoginAdapter
if _babase.using_google_play_game_services():
@ -85,6 +91,13 @@ class AccountV2Subsystem:
"""
assert _babase.in_logic_thread()
# Fire any registered callbacks.
for call in self.on_primary_account_changed_callbacks.getcalls():
try:
call(account)
except Exception:
logging.exception('Error in primary-account-changed callback.')
# Currently don't do anything special on sign-outs.
if account is None:
return

View File

@ -23,6 +23,7 @@ from babase._appmodeselector import AppModeSelector
from babase._appintent import AppIntentDefault, AppIntentExec
from babase._stringedit import StringEditSubsystem
from babase._devconsole import DevConsoleSubsystem
from babase._appconfig import AppConfig
if TYPE_CHECKING:
import asyncio
@ -182,6 +183,11 @@ class App:
if os.environ.get('BA_RUNNING_WITH_DUMMY_MODULES') == '1':
return
# Wrap our raw app config in our special wrapper and pass it to
# the native layer.
self.config = AppConfig(_babase.get_initial_app_config())
_babase.set_app_config(self.config)
self.env: babase.Env = _babase.Env()
self.state = self.State.NOT_STARTED
@ -223,7 +229,7 @@ class App:
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._config: babase.AppConfig | None = None
self._pending_intent: AppIntent | None = None
self._intent: AppIntent | None = None
self._mode_selector: babase.AppModeSelector | None = None
@ -330,11 +336,12 @@ class App:
self._asyncio_tasks.remove(task)
@property
def config(self) -> babase.AppConfig:
"""The babase.AppConfig instance representing the app's config state."""
assert self._config is not None
return self._config
# @property
# def config(self) -> babase.AppConfig:
# """The babase.AppConfig instance
# representing the app's config state."""
# assert self._config is not None
# return self._config
@property
def mode_selector(self) -> babase.AppModeSelector:
@ -585,12 +592,6 @@ class App:
if self._mode is not None:
self._mode.on_app_active_changed()
def read_config(self) -> None:
"""(internal)"""
from babase._appconfig import read_app_config
self._config = read_app_config()
def handle_deep_link(self, url: str) -> None:
"""Handle a deep link URL."""
from babase._language import Lstr

View File

@ -3,7 +3,6 @@
"""Provides the AppConfig class."""
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
import _babase
@ -101,43 +100,6 @@ class AppConfig(dict):
self.commit()
def read_app_config() -> AppConfig:
"""Read the app config."""
import os
import json
# NOTE: it is assumed that this only gets called once and the config
# object will not change from here on out
config_file_path = _babase.app.env.config_file_path
config_contents = ''
try:
if os.path.exists(config_file_path):
with open(config_file_path, encoding='utf-8') as infile:
config_contents = infile.read()
config = AppConfig(json.loads(config_contents))
else:
config = AppConfig()
except Exception:
logging.exception(
"Error reading config file '%s' at time %.3f.\n"
"Backing up broken config to'%s.broken'.",
config_file_path,
_babase.apptime(),
config_file_path,
)
try:
import shutil
shutil.copyfile(config_file_path, config_file_path + '.broken')
except Exception:
logging.exception('Error copying broken config.')
config = AppConfig()
return config
def commit_app_config() -> None:
"""Commit the config to persistent storage.
@ -145,6 +107,7 @@ def commit_app_config() -> None:
(internal)
"""
# FIXME - this should not require plus.
plus = _babase.app.plus
assert plus is not None

View File

@ -11,7 +11,7 @@ from functools import partial
from dataclasses import dataclass
from typing import TYPE_CHECKING, override
from efro.log import LogLevel
from efro.logging import LogLevel
from efro.dataclassio import ioprepped, dataclass_to_json, dataclass_from_json
import _babase

View File

@ -5,17 +5,14 @@ from __future__ import annotations
import os
import logging
from functools import partial
from dataclasses import dataclass
from typing import TYPE_CHECKING, override
from typing import TYPE_CHECKING
import _babase
if TYPE_CHECKING:
from typing import Callable, Any, Literal
from babase import AppMode, UIScale
class DevConsoleTab:
"""Defines behavior for a tab in the dev-console."""
@ -38,6 +35,7 @@ class DevConsoleTab:
label_scale: float = 1.0,
corner_radius: float = 8.0,
style: Literal['normal', 'light'] = 'normal',
disabled: bool = False,
) -> None:
"""Add a button to the tab being refreshed."""
assert _babase.app.devconsole.is_refreshing
@ -52,6 +50,7 @@ class DevConsoleTab:
label_scale,
corner_radius,
style,
disabled,
)
def text(
@ -98,151 +97,6 @@ class DevConsoleTab:
return _babase.dev_console_base_scale()
class DevConsoleTabPython(DevConsoleTab):
"""The Python dev-console tab."""
@override
def refresh(self) -> None:
self.python_terminal()
class DevConsoleTabAppModes(DevConsoleTab):
"""Tab to switch app modes."""
@override
def refresh(self) -> None:
modes = _babase.app.mode_selector.testable_app_modes()
self.text(
'Available AppModes:',
scale=0.8,
pos=(15, 55),
h_anchor='left',
h_align='left',
v_align='none',
)
for i, mode in enumerate(modes):
self.button(
f'{mode.__module__}.{mode.__qualname__}',
pos=(10 + i * 260, 10),
size=(250, 40),
h_anchor='left',
label_scale=0.6,
call=partial(self._set_app_mode, mode),
)
@staticmethod
def _set_app_mode(mode: type[AppMode]) -> None:
from babase._appintent import AppIntentDefault
intent = AppIntentDefault()
# Use private functionality to force a specific app-mode to
# handle this intent. Note that this should never be done
# outside of this explicit testing case. It is the app's job to
# determine which app-mode should be used to handle a given
# intent.
setattr(intent, '_force_app_mode_handler', mode)
_babase.app.set_intent(intent)
class DevConsoleTabUI(DevConsoleTab):
"""Tab to debug/test UI stuff."""
@override
def refresh(self) -> None:
from babase._mgen.enums import UIScale
self.text(
'Make sure all interactive UI fits in the'
' virtual bounds at all UI-scales (not counting things'
' that follow screen edges).\n'
'Note that some elements may not reflect UI-scale changes'
' until recreated.',
scale=0.6,
pos=(15, 70),
h_anchor='left',
h_align='left',
v_align='center',
)
ui_overlay = _babase.get_draw_ui_bounds()
self.button(
'Virtual Bounds ON' if ui_overlay else 'Virtual Bounds OFF',
pos=(10, 10),
size=(200, 30),
h_anchor='left',
label_scale=0.6,
call=self.toggle_ui_overlay,
style='light' if ui_overlay else 'normal',
)
x = 300
self.text(
'UI-Scale',
pos=(x - 5, 15),
h_anchor='left',
h_align='right',
v_align='none',
scale=0.6,
)
bwidth = 100
for scale in UIScale:
self.button(
scale.name.capitalize(),
pos=(x, 10),
size=(bwidth, 30),
h_anchor='left',
label_scale=0.6,
call=partial(_babase.app.set_ui_scale, scale),
style=(
'light'
if scale.name.lower() == _babase.get_ui_scale()
else 'normal'
),
)
x += bwidth + 2
def toggle_ui_overlay(self) -> None:
"""Toggle UI overlay drawing."""
_babase.set_draw_ui_bounds(not _babase.get_draw_ui_bounds())
self.request_refresh()
class DevConsoleTabTest(DevConsoleTab):
"""Test dev-console tab."""
@override
def refresh(self) -> None:
import random
self.button(
f'FLOOP-{random.randrange(200)}',
pos=(10, 10),
size=(100, 30),
h_anchor='left',
label_scale=0.6,
call=self.request_refresh,
)
self.button(
f'FLOOP2-{random.randrange(200)}',
pos=(120, 10),
size=(100, 30),
h_anchor='left',
label_scale=0.6,
style='light',
)
self.text(
'TestText',
scale=0.8,
pos=(15, 50),
h_anchor='left',
h_align='left',
v_align='none',
)
@dataclass
class DevConsoleTabEntry:
"""Represents a distinct tab in the dev-console."""
@ -263,28 +117,50 @@ class DevConsoleSubsystem:
"""
def __init__(self) -> None:
# pylint: disable=cyclic-import
from babase._devconsoletabs import (
DevConsoleTabPython,
DevConsoleTabAppModes,
DevConsoleTabUI,
DevConsoleTabLogging,
DevConsoleTabTest,
)
# All tabs in the dev-console. Add your own stuff here via
# plugins or whatnot.
self.tabs: list[DevConsoleTabEntry] = [
DevConsoleTabEntry('Python', DevConsoleTabPython),
DevConsoleTabEntry('AppModes', DevConsoleTabAppModes),
DevConsoleTabEntry('UI', DevConsoleTabUI),
DevConsoleTabEntry('Logging', DevConsoleTabLogging),
]
if os.environ.get('BA_DEV_CONSOLE_TEST_TAB', '0') == '1':
self.tabs.append(DevConsoleTabEntry('Test', DevConsoleTabTest))
self.is_refreshing = False
self._tab_instances: dict[str, DevConsoleTab] = {}
def do_refresh_tab(self, tabname: str) -> None:
"""Called by the C++ layer when a tab should be filled out."""
assert _babase.in_logic_thread()
# FIXME: We currently won't handle multiple tabs with the same
# name. We should give a clean error or something in that case.
tab: DevConsoleTab | None = None
for tabentry in self.tabs:
if tabentry.name == tabname:
tab = tabentry.factory()
break
# Make noise if we have repeating tab names, as that breaks our
# logic.
if __debug__:
alltabnames = set[str](tabentry.name for tabentry in self.tabs)
if len(alltabnames) != len(self.tabs):
logging.error(
'Duplicate dev-console tab names found;'
' tabs may behave unpredictably.'
)
tab: DevConsoleTab | None = self._tab_instances.get(tabname)
# If we haven't instantiated this tab yet, do so.
if tab is None:
for tabentry in self.tabs:
if tabentry.name == tabname:
tab = self._tab_instances[tabname] = tabentry.factory()
break
if tab is None:
logging.error(

View File

@ -0,0 +1,610 @@
# Released under the MIT License. See LICENSE for details.
#
"""Predefined tabs for the dev console."""
from __future__ import annotations
import math
import random
import logging
from functools import partial
from typing import TYPE_CHECKING, override, TypeVar, Generic
import _babase
from babase._devconsole import DevConsoleTab
if TYPE_CHECKING:
from typing import Callable, Literal
from bacommon.loggercontrol import LoggerControlConfig
from babase import AppMode
T = TypeVar('T')
class DevConsoleTabPython(DevConsoleTab):
"""The Python dev-console tab."""
@override
def refresh(self) -> None:
self.python_terminal()
class DevConsoleTabAppModes(DevConsoleTab):
"""Tab to switch app modes."""
@override
def refresh(self) -> None:
bwidth = 260
bpadding = 5
modes = _babase.app.mode_selector.testable_app_modes()
xoffs = -0.5 * bwidth * len(modes)
self.text(
'Available AppModes:',
scale=0.8,
pos=(0, 75),
h_align='center',
v_align='center',
)
# pylint: disable=protected-access
for i, mode in enumerate(modes):
self.button(
f'{mode.__module__}.{mode.__qualname__}',
pos=(xoffs + i * bwidth + bpadding, 10),
size=(bwidth - 2.0 * bpadding, 40),
label_scale=0.6,
call=partial(self._set_app_mode, mode),
style=(
'light' if isinstance(_babase.app._mode, mode) else 'normal'
),
)
def _set_app_mode(self, mode: type[AppMode]) -> None:
from babase._appintent import AppIntentDefault
intent = AppIntentDefault()
# Use private functionality to force a specific app-mode to
# handle this intent. Note that this should never be done
# outside of this explicit testing case. It is the app's job to
# determine which app-mode should be used to handle a given
# intent.
setattr(intent, '_force_app_mode_handler', mode)
_babase.app.set_intent(intent)
# Slight hackish: need to wait a moment before refreshing to
# pick up the new mode, as mode switches are asynchronous.
_babase.apptimer(0.1, self.request_refresh)
class DevConsoleTabUI(DevConsoleTab):
"""Tab to debug/test UI stuff."""
@override
def refresh(self) -> None:
from babase._mgen.enums import UIScale
xoffs = -375
self.text(
'Make sure all interactive UI fits in the'
' virtual bounds at all UI-scales (not counting things'
' that follow screen edges).\n'
'Note that some elements may not reflect UI-scale changes'
' until recreated.',
scale=0.6,
pos=(xoffs + 15, 70),
# h_anchor='left',
h_align='left',
v_align='center',
)
ui_overlay = _babase.get_draw_ui_bounds()
self.button(
'Virtual Bounds ON' if ui_overlay else 'Virtual Bounds OFF',
pos=(xoffs + 10, 10),
size=(200, 30),
# h_anchor='left',
label_scale=0.6,
call=self.toggle_ui_overlay,
style='light' if ui_overlay else 'normal',
)
x = 300
self.text(
'UI-Scale',
pos=(xoffs + x - 5, 15),
# h_anchor='left',
h_align='right',
v_align='none',
scale=0.6,
)
bwidth = 100
for scale in UIScale:
self.button(
scale.name.capitalize(),
pos=(xoffs + x, 10),
size=(bwidth, 30),
# h_anchor='left',
label_scale=0.6,
call=partial(_babase.app.set_ui_scale, scale),
style=(
'light'
if scale.name.lower() == _babase.get_ui_scale()
else 'normal'
),
)
x += bwidth + 2
def toggle_ui_overlay(self) -> None:
"""Toggle UI overlay drawing."""
_babase.set_draw_ui_bounds(not _babase.get_draw_ui_bounds())
self.request_refresh()
class Table(Generic[T]):
"""Used to show controls for arbitrarily large data in a grid form."""
def __init__(
self,
title: str,
entries: list[T],
draw_entry_call: Callable[
[int, T, DevConsoleTab, float, float, float, float], None
],
*,
entry_width: float = 300.0,
entry_height: float = 40.0,
margin_left_right: float = 60.0,
debug_bounds: bool = False,
max_columns: int | None = None,
) -> None:
self._title = title
self._entry_width = entry_width
self._entry_height = entry_height
self._margin_left_right = margin_left_right
self._focus_entry_index = 0
self._entries_per_page = 1
self._debug_bounds = debug_bounds
self._entries = entries
self._draw_entry_call = draw_entry_call
self._max_columns = max_columns
# Values updated on refresh (for aligning other custom
# widgets/etc.)
self.top_left: tuple[float, float] = (0.0, 0.0)
self.top_right: tuple[float, float] = (0.0, 0.0)
def set_entries(self, entries: list[T]) -> None:
"""Update table entries."""
self._entries = entries
# Clamp focus to new entries.
self._focus_entry_index = max(
0, min(len(self._entries) - 1, self._focus_entry_index)
)
def set_focus_entry_index(self, index: int) -> None:
"""Explicitly set the focused entry.
This affects which page is shown at the next refresh.
"""
self._focus_entry_index = max(0, min(len(self._entries) - 1, index))
def refresh(self, tab: DevConsoleTab) -> None:
"""Call to refresh the data."""
# pylint: disable=too-many-locals
margin_top = 50.0
margin_bottom = 10.0
# Update how much we can fit on a page based on our current size.
max_entry_area_width = tab.width - (self._margin_left_right * 2.0)
max_entry_area_height = tab.height - (margin_top + margin_bottom)
columns = max(1, int(max_entry_area_width / self._entry_width))
if self._max_columns is not None:
columns = min(columns, self._max_columns)
rows = max(1, int(max_entry_area_height / self._entry_height))
self._entries_per_page = rows * columns
# See which page our focus index falls in.
pagemax = math.ceil(len(self._entries) / self._entries_per_page)
page = self._focus_entry_index // self._entries_per_page
entry_offset = page * self._entries_per_page
entries_on_this_page = min(
self._entries_per_page, len(self._entries) - entry_offset
)
columns_on_this_page = math.ceil(entries_on_this_page / rows)
rows_on_this_page = min(entries_on_this_page, rows)
# We attach things to the center so resizes are smooth but we do
# some math in a left-centric way.
center_to_left = tab.width * -0.5
# Center our columns.
xoffs = 0.5 * (
max_entry_area_width - columns_on_this_page * self._entry_width
)
# Align everything to the bottom of the dev-console.
yoffs = -1.0 * (
tab.height
- (
rows_on_this_page * self._entry_height
+ margin_top
+ margin_bottom
)
)
# Keep our corners up to date for user use.
self.top_left = (center_to_left + xoffs, tab.height + yoffs)
self.top_right = (
self.top_left[0]
+ self._margin_left_right * 2.0
+ columns_on_this_page * self._entry_width,
self.top_left[1],
)
# Page left/right buttons.
tab.button(
'<',
pos=(center_to_left + xoffs, margin_bottom),
size=(
self._margin_left_right,
rows_on_this_page * self._entry_height,
),
# h_anchor='left',
call=partial(self._page_left, tab),
disabled=entry_offset == 0,
)
tab.button(
'>',
pos=(
center_to_left
+ xoffs
+ self._margin_left_right
+ columns_on_this_page * self._entry_width,
margin_bottom,
),
size=(
self._margin_left_right,
rows_on_this_page * self._entry_height,
),
# h_anchor='left',
call=partial(self._page_right, tab),
disabled=(
entry_offset + entries_on_this_page >= len(self._entries)
),
)
for column in range(columns):
for row in range(rows):
entry_index = entry_offset + column * rows + row
if entry_index >= len(self._entries):
break
xpos = (
xoffs + self._margin_left_right + self._entry_width * column
)
ypos = (
yoffs
+ tab.height
- margin_top
- self._entry_height * (row + 1.0)
)
# Draw debug bounds.
if self._debug_bounds:
tab.button(
str(entry_index),
pos=(
center_to_left + xpos,
ypos,
),
size=(self._entry_width, self._entry_height),
# h_anchor='left',
)
# Run user drawing.
self._draw_entry_call(
entry_index,
self._entries[entry_index],
tab,
center_to_left + xpos,
ypos,
self._entry_width,
self._entry_height,
)
if entry_index >= len(self._entries):
break
tab.text(
f'{self._title} ({page + 1}/{pagemax})',
scale=0.8,
pos=(0, yoffs + tab.height - margin_top * 0.5),
h_align='center',
v_align='center',
)
def _page_right(self, tab: DevConsoleTab) -> None:
# Set focus on the first entry in the page before the current.
page = self._focus_entry_index // self._entries_per_page
page += 1
self.set_focus_entry_index(page * self._entries_per_page)
tab.request_refresh()
def _page_left(self, tab: DevConsoleTab) -> None:
# Set focus on the first entry in the page after the current.
page = self._focus_entry_index // self._entries_per_page
page -= 1
self.set_focus_entry_index(page * self._entries_per_page)
tab.request_refresh()
class DevConsoleTabLogging(DevConsoleTab):
"""Tab to wrangle logging levels."""
def __init__(self) -> None:
self._table = Table(
title='Logging Levels',
entry_width=800,
debug_bounds=False,
entries=list[str](),
draw_entry_call=self._draw_entry,
max_columns=1,
)
@override
def refresh(self) -> None:
assert self._table is not None
# Update table entries with the latest set of loggers (this can
# change over time).
self._table.set_entries(
['root'] + sorted(logging.root.manager.loggerDict)
)
# Draw the table.
self._table.refresh(self)
# Draw our control buttons in the corners.
tl = self._table.top_left
tr = self._table.top_right
bwidth = 140.0
bheight = 30.0
bvpad = 10.0
self.button(
'Reset',
pos=(tl[0], tl[1] - bheight - bvpad),
size=(bwidth, bheight),
label_scale=0.6,
call=self._reset,
disabled=(
not self._get_reset_logger_control_config().would_make_changes()
),
)
self.button(
'Cloud Control OFF',
pos=(tr[0] - bwidth, tl[1] - bheight - bvpad),
size=(bwidth, bheight),
label_scale=0.6,
disabled=True,
)
def _get_reset_logger_control_config(self) -> LoggerControlConfig:
from bacommon.logging import get_base_logger_control_config_client
return get_base_logger_control_config_client()
def _reset(self) -> None:
self._get_reset_logger_control_config().apply()
# Let the native layer know that levels changed.
_babase.update_internal_logger_levels()
# Blow away any existing values in app-config.
appconfig = _babase.app.config
if 'Log Levels' in appconfig:
del appconfig['Log Levels']
appconfig.commit()
self.request_refresh()
def _set_entry_val(self, entry_index: int, entry: str, val: int) -> None:
from bacommon.logging import get_base_logger_control_config_client
from bacommon.loggercontrol import LoggerControlConfig
# Focus on this entry with any interaction, so if we get resized
# it'll still be visible.
self._table.set_focus_entry_index(entry_index)
logging.getLogger(entry).setLevel(val)
# Let the native layer know that levels changed.
_babase.update_internal_logger_levels()
# Store only changes compared to the base config.
baseconfig = get_base_logger_control_config_client()
config = LoggerControlConfig.from_current_loggers().diff(baseconfig)
appconfig = _babase.app.config
appconfig['Log Levels'] = config.levels
appconfig.commit()
self.request_refresh()
def _draw_entry(
self,
entry_index: int,
entry: str,
tab: DevConsoleTab,
x: float,
y: float,
width: float,
height: float,
) -> None:
# pylint: disable=too-many-positional-arguments
# pylint: disable=too-many-locals
xoffs = -15.0
bwidth = 80.0
btextscale = 0.5
tab.text(
entry,
(
x + width - bwidth * 6.5 - 10.0 + xoffs,
y + height * 0.5,
),
h_align='right',
scale=0.7,
)
logger = logging.getLogger(entry)
level = logger.level
index = 0
if entry != 'root' and level == logging.NOTSET:
# Show the level being inherited in NOTSET cases.
notsetlevelname = logging.getLevelName(logger.getEffectiveLevel())
if notsetlevelname == 'NOTSET':
notsetname = 'Not Set'
else:
notsetname = f'Not Set ({notsetlevelname.capitalize()})'
else:
notsetname = 'Not Set'
tab.button(
notsetname,
pos=(x + width - bwidth * 6.5 + xoffs + 1.0, y + 5.0),
size=(bwidth * 1.5 - 2.0, height - 10),
label_scale=btextscale,
style='light' if level == logging.NOTSET else 'normal',
call=partial(
self._set_entry_val, entry_index, entry, logging.NOTSET
),
)
index += 1
tab.button(
'Debug',
pos=(x + width - bwidth * 5 + xoffs + 1.0, y + 5.0),
size=(bwidth - 2.0, height - 10),
label_scale=btextscale,
style='light' if level == logging.DEBUG else 'normal',
call=partial(
self._set_entry_val, entry_index, entry, logging.DEBUG
),
)
index += 1
tab.button(
'Info',
pos=(x + width - bwidth * 4 + xoffs + 1.0, y + 5.0),
size=(bwidth - 2.0, height - 10),
label_scale=btextscale,
style='light' if level == logging.INFO else 'normal',
call=partial(self._set_entry_val, entry_index, entry, logging.INFO),
)
index += 1
tab.button(
'Warning',
pos=(x + width - bwidth * 3 + xoffs + 1.0, y + 5.0),
size=(bwidth - 2.0, height - 10),
label_scale=btextscale,
style='light' if level == logging.WARNING else 'normal',
call=partial(
self._set_entry_val, entry_index, entry, logging.WARNING
),
)
index += 1
tab.button(
'Error',
pos=(x + width - bwidth * 2 + xoffs + 1.0, y + 5.0),
size=(bwidth - 2.0, height - 10),
label_scale=btextscale,
style='light' if level == logging.ERROR else 'normal',
call=partial(
self._set_entry_val, entry_index, entry, logging.ERROR
),
)
index += 1
tab.button(
'Critical',
pos=(x + width - bwidth * 1 + xoffs + 1.0, y + 5.0),
size=(bwidth - 2.0, height - 10),
label_scale=btextscale,
style='light' if level == logging.CRITICAL else 'normal',
call=partial(
self._set_entry_val, entry_index, entry, logging.CRITICAL
),
)
class DevConsoleTabTest(DevConsoleTab):
"""Test dev-console tab."""
@override
def refresh(self) -> None:
self.button(
f'FLOOP-{random.randrange(200)}',
pos=(10, 10),
size=(100, 30),
h_anchor='left',
label_scale=0.6,
call=self.request_refresh,
)
self.button(
f'FLOOP2-{random.randrange(200)}',
pos=(120, 10),
size=(100, 30),
h_anchor='left',
label_scale=0.6,
style='light',
)
self.text(
'TestText',
scale=0.8,
pos=(15, 50),
h_anchor='left',
h_align='left',
v_align='none',
)
# Throw little bits of text in the corners to make sure
# widths/heights are correct.
self.text(
'BL',
scale=0.25,
pos=(0, 0),
h_anchor='left',
h_align='left',
v_align='bottom',
)
self.text(
'BR',
scale=0.25,
pos=(self.width, 0),
h_anchor='left',
h_align='right',
v_align='bottom',
)
self.text(
'TL',
scale=0.25,
pos=(0, self.height),
h_anchor='left',
h_align='left',
v_align='top',
)
self.text(
'TR',
scale=0.25,
pos=(self.width, self.height),
h_anchor='left',
h_align='right',
v_align='top',
)

View File

@ -9,11 +9,11 @@ import logging
import warnings
from typing import TYPE_CHECKING, override
from efro.log import LogLevel
from efro.logging import LogLevel
if TYPE_CHECKING:
from typing import Any
from efro.log import LogEntry, LogHandler
from efro.logging import LogEntry, LogHandler
_g_babase_imported = False # pylint: disable=invalid-name
_g_babase_app_started = False # pylint: disable=invalid-name
@ -186,7 +186,10 @@ def _feed_logs_to_babase(log_handler: LogHandler) -> None:
# Forward this along to the engine to display in the in-app
# console, in the Android log, etc.
_babase.emit_log(
name=entry.name, level=entry.level.name, message=entry.message
name=entry.name,
level=entry.level.name,
timestamp=entry.time.timestamp(),
message=entry.message,
)
# We also want to feed some logs to the old v1-cloud-log system.

View File

@ -14,6 +14,7 @@ from babase import (
AppIntentExec,
AppIntentDefault,
invoke_main_menu,
in_logic_thread,
screenmessage,
)
@ -22,13 +23,19 @@ import _baclassic
if TYPE_CHECKING:
from typing import Callable
from babase import AppIntent
from efro.call import CallbackRegistration
from babase import AppIntent, AccountV2Handle
from bauiv1 import UIV1AppSubsystem, MainWindow, MainWindowState
class ClassicAppMode(AppMode):
"""AppMode for the classic BombSquad experience."""
def __init__(self) -> None:
self._on_primary_account_changed_callback: (
CallbackRegistration | None
) = None
@override
@classmethod
def get_app_experience(cls) -> AppExperience:
@ -54,6 +61,8 @@ class ClassicAppMode(AppMode):
# Let the native layer do its thing.
_baclassic.classic_app_mode_activate()
assert app.plus is not None
# Wire up the root ui to do what we want.
ui = app.ui_v1
ui.root_ui_calls[ui.RootUIElement.ACCOUNT_BUTTON] = (
@ -108,9 +117,24 @@ class ClassicAppMode(AppMode):
self._root_ui_chest_slot_pressed, 4
)
# We want to be informed when primary account changes.
self._on_primary_account_changed_callback = (
app.plus.accounts.on_primary_account_changed_callbacks.add(
self.update_for_primary_account
)
)
# Establish subscriptions/etc. for any current primary account.
self.update_for_primary_account(app.plus.accounts.primary)
@override
def on_deactivate(self) -> None:
# Stop being informed of account changes.
self._on_primary_account_changed_callback = None
# Remove any listeners for any current primary account.
self.update_for_primary_account(None)
# Save where we were in the UI so we return there next time.
if app.classic is not None:
app.classic.save_ui_state()
@ -125,6 +149,14 @@ class ClassicAppMode(AppMode):
if not app.active:
invoke_main_menu()
def update_for_primary_account(
self, account: AccountV2Handle | None
) -> None:
"""Update subscriptions/etc. for a new primary account state."""
assert in_logic_thread()
del account # Unused.
# print('WOULD WIRE UP LISTENERS FOR ACCOUNT', account)
def _root_ui_menu_press(self) -> None:
from babase import push_back_press

View File

@ -18,6 +18,7 @@ from __future__ import annotations
import os
import sys
import time
import logging
from pathlib import Path
from dataclasses import dataclass
@ -27,7 +28,7 @@ import __main__
if TYPE_CHECKING:
from typing import Any
from efro.log import LogHandler
from efro.logging import LogHandler
# IMPORTANT - It is likely (and in some cases expected) that this
# module's code will be exec'ed multiple times. This is because it is
@ -52,7 +53,7 @@ if TYPE_CHECKING:
# Build number and version of the ballistica binary we expect to be
# using.
TARGET_BALLISTICA_BUILD = 22025
TARGET_BALLISTICA_BUILD = 22040
TARGET_BALLISTICA_VERSION = '1.7.37'
@ -87,14 +88,13 @@ class EnvConfig:
# stderr into the engine so they show up on in-app consoles, etc.
log_handler: LogHandler | None
# Initial data from the ballisticakit-config.json file. This is
# passed mostly as an optimization to avoid reading the same config
# file twice, since config data is first needed in baenv and next in
# the engine. It will be cleared after passing it to the app's
# config management subsystem and should not be accessed by any
# other code.
# Initial data from the config.json file in the config dir. The
# config file is parsed by
initial_app_config: Any
# Timestamp when we first started doing stuff.
launch_time: float
@dataclass
class _EnvGlobals:
@ -172,6 +172,11 @@ def configure(
are imported; the environment is locked in as soon as that happens.
"""
# Measure when we start doing this stuff. We plug this in to show
# relative times in our log timestamp displays and also pass this to
# the engine to do the same there.
launch_time = time.time()
envglobals = _EnvGlobals.get()
# Keep track of whether we've been *called*, not whether a config
@ -206,11 +211,19 @@ def configure(
config_dir,
)
# The second thing we do is set up our logging system and pipe
# Python's stdout/stderr into it. At this point we can at least
# debug problems on systems where native stdout/stderr is not easily
# accessible such as Android.
log_handler = _setup_logging() if setup_logging else None
# Set up our log-handler and pipe Python's stdout/stderr into it.
# Later, once the engine comes up, the handler will feed its logs
# (including cached history) to the os-specific output location.
# This means anything printed or logged at this point forward should
# be visible on all platforms.
log_handler = _setup_logging(launch_time) if setup_logging else None
# Load the raw app-config dict.
app_config = _read_app_config(os.path.join(config_dir, 'config.json'))
# Set logging levels to stored values or defaults.
if setup_logging:
_set_log_levels(app_config)
# We want to always be run in UTF-8 mode; complain if we're not.
if sys.flags.utf8_mode != 1:
@ -235,10 +248,46 @@ def configure(
site_python_dir=site_python_dir,
log_handler=log_handler,
is_user_app_python_dir=is_user_app_python_dir,
initial_app_config=None,
initial_app_config=app_config,
launch_time=launch_time,
)
def _read_app_config(config_file_path: str) -> dict:
"""Read the app config."""
import json
config: dict | Any
config_contents = ''
try:
if os.path.exists(config_file_path):
with open(config_file_path, encoding='utf-8') as infile:
config_contents = infile.read()
config = json.loads(config_contents)
if not isinstance(config, dict):
raise RuntimeError('Got non-dict for config root.')
else:
config = {}
except Exception:
logging.exception(
"Error reading config file '%s'.\n"
"Backing up broken config to'%s.broken'.",
config_file_path,
config_file_path,
)
try:
import shutil
shutil.copyfile(config_file_path, config_file_path + '.broken')
except Exception:
logging.exception('Error copying broken config.')
config = {}
return config
def _calc_data_dir(data_dir: str | None) -> str:
if data_dir is None:
# To calc default data_dir, we assume this module was imported
@ -262,23 +311,57 @@ def _calc_data_dir(data_dir: str | None) -> str:
return data_dir
def _setup_logging() -> LogHandler:
from efro.log import setup_logging, LogLevel
def _setup_logging(launch_time: float) -> LogHandler:
from efro.logging import setup_logging, LogLevel
# TODO: should set this up with individual loggers under a top level
# 'ba' logger, and at that point we can kill off the
# suppress_non_root_debug option since we'll only ever need to set
# 'ba' to DEBUG at most.
log_handler = setup_logging(
log_path=None,
level=LogLevel.DEBUG,
suppress_non_root_debug=True,
log_stdout_stderr=True,
cache_size_limit=1024 * 1024,
launch_time=launch_time,
)
return log_handler
def _set_log_levels(app_config: dict) -> None:
from bacommon.logging import get_base_logger_control_config_client
from bacommon.loggercontrol import LoggerControlConfig
try:
config = app_config.get('Log Levels', None)
if config is None:
get_base_logger_control_config_client().apply()
return
# Make sure data is expected types/values.
valid_levels = {
logging.NOTSET,
logging.DEBUG,
logging.INFO,
logging.WARNING,
logging.ERROR,
logging.CRITICAL,
}
for logname, loglevel in config.items():
if (
not isinstance(logname, str)
or not logname
or not isinstance(loglevel, int)
or not loglevel in valid_levels
):
raise ValueError("Invalid 'Log Levels' data read from config.")
get_base_logger_control_config_client().apply_diff(
LoggerControlConfig(levels=config)
).apply()
except Exception:
logging.exception('Error setting log levels.')
def _setup_certs(contains_python_dist: bool) -> None:
# In situations where we're bringing our own Python, let's also
# provide our own root certs so ssl works. We can consider

View File

@ -128,14 +128,8 @@ class CloudSubsystem(babase.AppSubsystem):
The provided on_response call will be run in the logic thread
and passed either the response or the error that occurred.
"""
del msg # Unused.
babase.pushcall(
babase.Call(
on_response,
RuntimeError('Cloud functionality is not available.'),
)
raise NotImplementedError(
'Cloud functionality is not present in this build.'
)
@overload
@ -158,7 +152,9 @@ class CloudSubsystem(babase.AppSubsystem):
Must be called from a background thread.
"""
raise RuntimeError('Cloud functionality is not available.')
raise NotImplementedError(
'Cloud functionality is not present in this build.'
)
@overload
async def send_message_async(
@ -175,7 +171,14 @@ class CloudSubsystem(babase.AppSubsystem):
Must be called from the logic thread.
"""
raise RuntimeError('Cloud functionality is not available.')
raise NotImplementedError(
'Cloud functionality is not present in this build.'
)
# def subscribe(
# self,
# on_response: Callable[[Any], None],
# ) -> CallbackRegistration:
def cloud_console_exec(code: str) -> None:

View File

@ -1575,6 +1575,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
transition_delay=1.0,
).autoretain()
else:
assert rating is not None
ZoomText(
(
f'{rating:.1f}'

View File

@ -387,8 +387,6 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
v_offs = 0.0
tdelay += len(player_entries) * 8 * t_incr
for _score, name, prec in player_entries:
if not prec.player.in_game:
continue
tdelay -= 4 * t_incr
v_offs -= 40
Text(

View File

@ -627,6 +627,7 @@ class StoreBrowserWindow(bui.MainWindow):
sale_title_text: str | bui.Lstr = ''
sale_time_text: str | bui.Lstr = ''
call: Callable | None
if purchased:
title_color = (0.8, 0.7, 0.9, 1.0)
color = (0.63, 0.55, 0.78)

View File

@ -136,7 +136,7 @@ auto AppAdapter::DoClipboardGetText() -> std::string {
}
auto AppAdapter::GetKeyName(int keycode) -> std::string {
BA_LOG_ONCE(LogLevel::kWarning,
BA_LOG_ONCE(LogName::kBa, LogLevel::kWarning,
"CorePlatform::GetKeyName not implemented here.");
return "?";
}

View File

@ -169,7 +169,7 @@ auto AppAdapterApple::InGraphicsContext() -> bool {
void AppAdapterApple::DoPushGraphicsContextRunnable(Runnable* runnable) {
auto lock = std::scoped_lock(graphics_calls_mutex_);
if (graphics_calls_.size() > 1000) {
BA_LOG_ONCE(LogLevel::kError, "graphics_calls_ got too big.");
BA_LOG_ONCE(LogName::kBa, LogLevel::kError, "graphics_calls_ got too big.");
}
graphics_calls_.push_back(runnable);
}

View File

@ -61,7 +61,7 @@ void AppAdapterSDL::OnMainThreadStartApp() {
uint32_t sdl_flags{SDL_INIT_VIDEO | SDL_INIT_JOYSTICK};
if (strict_graphics_context_) {
Log(LogLevel::kWarning,
Log(LogName::kBaNetworking, LogLevel::kWarning,
"AppAdapterSDL strict_graphics_context_ is enabled."
" Remember to turn this off.");
}
@ -309,7 +309,8 @@ void AppAdapterSDL::SleepUntilNextEventCycle_(microsecs_t cycle_start_time) {
const microsecs_t min_sleep{2000};
if (now + min_sleep >= target_time) {
if (debug_log_sdl_frame_timing_) {
Log(LogLevel::kDebug, "no sleep."); // 'till brooklyn!
Log(LogName::kBaNetworking, LogLevel::kDebug,
"no sleep."); // 'till brooklyn!
}
} else {
if (debug_log_sdl_frame_timing_) {
@ -317,7 +318,7 @@ void AppAdapterSDL::SleepUntilNextEventCycle_(microsecs_t cycle_start_time) {
snprintf(buf, sizeof(buf), "render %.1f sleep %.1f",
(now - cycle_start_time) / 1000.0f,
(target_time - now) / 1000.0f);
Log(LogLevel::kDebug, buf);
Log(LogName::kBaNetworking, LogLevel::kDebug, buf);
}
g_core->platform->SleepMicrosecs(target_time - now);
}
@ -375,8 +376,9 @@ void AppAdapterSDL::HandleSDLEvent_(const SDL_Event& event) {
g_base->input->PushJoystickEvent(event, js);
}
} else {
Log(LogLevel::kError, "Unable to get SDL Joystick for event type "
+ std::to_string(event.type));
Log(LogName::kBaInput, LogLevel::kError,
"Unable to get SDL Joystick for event type "
+ std::to_string(event.type));
}
break;
}
@ -563,7 +565,7 @@ void AppAdapterSDL::OnSDLJoystickAdded_(int device_index) {
try {
j = Object::NewDeferred<JoystickInput>(device_index);
} catch (const std::exception& exc) {
Log(LogLevel::kError,
Log(LogName::kBaInput, LogLevel::kError,
std::string("Error creating JoystickInput for SDL device-index "
+ std::to_string(device_index) + ": ")
+ exc.what());
@ -602,7 +604,7 @@ void AppAdapterSDL::RemoveSDLInputDevice_(int index) {
// Note: am running into this with a PS5 controller on macOS Sequoia beta.
if (!j) {
Log(LogLevel::kError,
Log(LogName::kBaInput, LogLevel::kError,
"GetSDLJoystickInput_() returned nullptr on RemoveSDLInputDevice_();"
" joysticks size is "
+ std::to_string(sdl_joysticks_.size()) + "; index is "
@ -614,9 +616,10 @@ void AppAdapterSDL::RemoveSDLInputDevice_(int index) {
if (static_cast_check_fit<int>(sdl_joysticks_.size()) > index) {
sdl_joysticks_[index] = nullptr;
} else {
Log(LogLevel::kError, "Invalid index on RemoveSDLInputDevice: size is "
+ std::to_string(sdl_joysticks_.size())
+ "; index is " + std::to_string(index) + ".");
Log(LogName::kBaInput, LogLevel::kError,
"Invalid index on RemoveSDLInputDevice: size is "
+ std::to_string(sdl_joysticks_.size()) + "; index is "
+ std::to_string(index) + ".");
}
g_base->input->PushRemoveInputDeviceCall(j, true);
}
@ -785,7 +788,8 @@ void AppAdapterSDL::DoPushGraphicsContextRunnable(Runnable* runnable) {
if (strict_graphics_context_) {
auto lock = std::scoped_lock(strict_graphics_calls_mutex_);
if (strict_graphics_calls_.size() > 1000) {
BA_LOG_ONCE(LogLevel::kError, "strict_graphics_calls_ got too big.");
BA_LOG_ONCE(LogName::kBaGraphics, LogLevel::kError,
"strict_graphics_calls_ got too big.");
}
strict_graphics_calls_.push_back(runnable);
} else {

View File

@ -52,7 +52,8 @@ void AppAdapterVR::VRPreDraw() {
assert(g_base->app_adapter->InGraphicsContext());
// FIXME - this is internal graphics-server details that the render-server
// should handle.
Log(LogLevel::kWarning, "FIXME: Have GraphicsServer handle VR drawing.");
Log(LogName::kBaGraphics, LogLevel::kWarning,
"FIXME: Have GraphicsServer handle VR drawing.");
// if (FrameDef* frame_def = g_base->graphics_server->GetRenderFrameDef()) {
// // Note: this could be part of PreprocessRenderFrameDef but the non-vr
// // path needs it to be separate since preprocess doesn't happen
@ -75,7 +76,8 @@ void AppAdapterVR::VRPostDraw() {
g_base->graphics_server->FinishRenderFrameDef(vr_render_frame_def_);
vr_render_frame_def_ = nullptr;
}
Log(LogLevel::kWarning, "WOULD RUN RENDER UPKEEP CYCLE");
Log(LogName::kBaGraphics, LogLevel::kWarning,
"WOULD RUN RENDER UPKEEP CYCLE");
// RunRenderUpkeepCycle();
}

View File

@ -302,7 +302,7 @@ void Assets::PrintLoadInfo() {
snprintf(buffer, sizeof(buffer), " %-50s %10s %10s", "FILE",
"PRELOAD_TIME", "LOAD_TIME");
s += buffer;
Log(LogLevel::kInfo, s);
Log(LogName::kBaAssets, LogLevel::kInfo, s);
millisecs_t total_preload_time = 0;
millisecs_t total_load_time = 0;
assert(asset_lists_locked_);
@ -315,7 +315,7 @@ void Assets::PrintLoadInfo() {
i.second->GetName().c_str(),
static_cast_check_fit<int>(preload_time),
static_cast_check_fit<int>(load_time));
Log(LogLevel::kInfo, buffer);
Log(LogName::kBaAssets, LogLevel::kInfo, buffer);
num++;
}
assert(asset_lists_locked_);
@ -328,7 +328,7 @@ void Assets::PrintLoadInfo() {
i.second->GetName().c_str(),
static_cast_check_fit<int>(preload_time),
static_cast_check_fit<int>(load_time));
Log(LogLevel::kInfo, buffer);
Log(LogName::kBaAssets, LogLevel::kInfo, buffer);
num++;
}
assert(asset_lists_locked_);
@ -341,7 +341,7 @@ void Assets::PrintLoadInfo() {
i.second->GetName().c_str(),
static_cast_check_fit<int>(preload_time),
static_cast_check_fit<int>(load_time));
Log(LogLevel::kInfo, buffer);
Log(LogName::kBaAssets, LogLevel::kInfo, buffer);
num++;
}
assert(asset_lists_locked_);
@ -354,7 +354,7 @@ void Assets::PrintLoadInfo() {
i.second->GetName().c_str(),
static_cast_check_fit<int>(preload_time),
static_cast_check_fit<int>(load_time));
Log(LogLevel::kInfo, buffer);
Log(LogName::kBaAssets, LogLevel::kInfo, buffer);
num++;
}
assert(asset_lists_locked_);
@ -367,7 +367,7 @@ void Assets::PrintLoadInfo() {
i.second->file_name_full().c_str(),
static_cast_check_fit<int>(preload_time),
static_cast_check_fit<int>(load_time));
Log(LogLevel::kInfo, buffer);
Log(LogName::kBaAssets, LogLevel::kInfo, buffer);
num++;
}
snprintf(buffer, sizeof(buffer),
@ -375,7 +375,7 @@ void Assets::PrintLoadInfo() {
"(feeding data to OpenGL, etc): %i",
static_cast<int>(total_preload_time),
static_cast<int>(total_load_time));
Log(LogLevel::kInfo, buffer);
Log(LogName::kBaAssets, LogLevel::kInfo, buffer);
}
void Assets::MarkAllAssetsForLoad() {
@ -1029,35 +1029,35 @@ void Assets::Prune(int level) {
if (kShowPruningInfo) {
assert(asset_lists_locked_);
if (textures_.size() != old_texture_count) {
Log(LogLevel::kInfo, "Textures pruned from "
+ std::to_string(old_texture_count) + " to "
+ std::to_string(textures_.size()));
Log(LogName::kBaAssets, LogLevel::kInfo,
"Textures pruned from " + std::to_string(old_texture_count) + " to "
+ std::to_string(textures_.size()));
}
if (text_textures_.size() != old_text_texture_count) {
Log(LogLevel::kInfo, "TextTextures pruned from "
+ std::to_string(old_text_texture_count) + " to "
+ std::to_string(text_textures_.size()));
Log(LogName::kBaAssets, LogLevel::kInfo,
"TextTextures pruned from " + std::to_string(old_text_texture_count)
+ " to " + std::to_string(text_textures_.size()));
}
if (qr_textures_.size() != old_qr_texture_count) {
Log(LogLevel::kInfo, "QrTextures pruned from "
+ std::to_string(old_qr_texture_count) + " to "
+ std::to_string(qr_textures_.size()));
Log(LogName::kBaAssets, LogLevel::kInfo,
"QrTextures pruned from " + std::to_string(old_qr_texture_count)
+ " to " + std::to_string(qr_textures_.size()));
}
if (meshes_.size() != old_mesh_count) {
Log(LogLevel::kInfo, "Meshes pruned from "
+ std::to_string(old_mesh_count) + " to "
+ std::to_string(meshes_.size()));
Log(LogName::kBaAssets, LogLevel::kInfo,
"Meshes pruned from " + std::to_string(old_mesh_count) + " to "
+ std::to_string(meshes_.size()));
}
if (collision_meshes_.size() != old_collision_mesh_count) {
Log(LogLevel::kInfo, "CollisionMeshes pruned from "
+ std::to_string(old_collision_mesh_count)
+ " to "
+ std::to_string(collision_meshes_.size()));
Log(LogName::kBaAssets, LogLevel::kInfo,
"CollisionMeshes pruned from "
+ std::to_string(old_collision_mesh_count) + " to "
+ std::to_string(collision_meshes_.size()));
}
if (sounds_.size() != old_sound_count) {
Log(LogLevel::kInfo, "Sounds pruned from "
+ std::to_string(old_sound_count) + " to "
+ std::to_string(sounds_.size()));
Log(LogName::kBaAssets, LogLevel::kInfo,
"Sounds pruned from " + std::to_string(old_sound_count) + " to "
+ std::to_string(sounds_.size()));
}
}
}
@ -1164,11 +1164,11 @@ auto Assets::FindAssetFile(FileType type, const std::string& name)
// We wanna fail gracefully for some types.
if (type == FileType::kSound && name != "blank") {
Log(LogLevel::kError,
Log(LogName::kBaAssets, LogLevel::kError,
"Unable to load audio: '" + name + "'; trying fallback...");
return FindAssetFile(type, "blank");
} else if (type == FileType::kTexture && name != "white") {
Log(LogLevel::kError,
Log(LogName::kBaAssets, LogLevel::kError,
"Unable to load texture: '" + name + "'; trying fallback...");
return FindAssetFile(type, "white");
}
@ -1228,7 +1228,8 @@ void Assets::AddPackage(const std::string& name, const std::string& path) {
assert(g_base->InLogicThread());
if (g_buildconfig.debug_build()) {
if (packages_.find(name) != packages_.end()) {
Log(LogLevel::kWarning, "adding duplicate package: '" + name + "'");
Log(LogName::kBaAssets, LogLevel::kWarning,
"adding duplicate package: '" + name + "'");
}
}
packages_[name] = path;
@ -1386,7 +1387,7 @@ auto DoCompileResourceString(cJSON* obj) -> std::string {
printed = true;
char* c = cJSON_Print(obj);
BA_LOG_ONCE(
LogLevel::kError,
LogName::kBaAssets, LogLevel::kError,
"found long key 'resource' in raw lstr json: " + std::string(c));
free(c);
}
@ -1406,7 +1407,7 @@ auto DoCompileResourceString(cJSON* obj) -> std::string {
printed = true;
char* c = cJSON_Print(obj);
BA_LOG_ONCE(
LogLevel::kError,
LogName::kBaAssets, LogLevel::kError,
"found long key 'fallback' in raw lstr json: " + std::string(c));
free(c);
}
@ -1431,7 +1432,7 @@ auto DoCompileResourceString(cJSON* obj) -> std::string {
printed = true;
char* c = cJSON_Print(obj);
BA_LOG_ONCE(
LogLevel::kError,
LogName::kBaAssets, LogLevel::kError,
"found long key 'translate' in raw lstr json: " + std::string(c));
free(c);
}
@ -1470,7 +1471,7 @@ auto DoCompileResourceString(cJSON* obj) -> std::string {
printed = true;
char* c = cJSON_Print(obj);
BA_LOG_ONCE(
LogLevel::kError,
LogName::kBaAssets, LogLevel::kError,
"found long key 'value' in raw lstr json: " + std::string(c));
free(c);
}
@ -1501,8 +1502,9 @@ auto DoCompileResourceString(cJSON* obj) -> std::string {
if (!printed) {
printed = true;
char* c = cJSON_Print(obj);
BA_LOG_ONCE(LogLevel::kError, "found long key 'subs' in raw lstr json: "
+ std::string(c));
BA_LOG_ONCE(
LogName::kBaAssets, LogLevel::kError,
"found long key 'subs' in raw lstr json: " + std::string(c));
free(c);
}
}
@ -1571,8 +1573,9 @@ auto Assets::CompileResourceString(const std::string& s, const std::string& loc,
cJSON* root = cJSON_Parse(s.c_str());
if (root == nullptr) {
Log(LogLevel::kError, "CompileResourceString failed (loc " + loc
+ "); invalid json: '" + s + "'");
Log(LogName::kBaAssets, LogLevel::kError,
"CompileResourceString failed (loc " + loc + "); invalid json: '" + s
+ "'");
*valid = false;
return "";
}
@ -1581,8 +1584,9 @@ auto Assets::CompileResourceString(const std::string& s, const std::string& loc,
result = DoCompileResourceString(root);
*valid = true;
} catch (const std::exception& e) {
Log(LogLevel::kError, "CompileResourceString failed (loc " + loc + "): "
+ std::string(e.what()) + "; str='" + s + "'");
Log(LogName::kBaAssets, LogLevel::kError,
"CompileResourceString failed (loc " + loc
+ "): " + std::string(e.what()) + "; str='" + s + "'");
result = "<error>";
*valid = false;
}

View File

@ -56,7 +56,7 @@ void AssetsServer::PushBeginWriteReplayCall(uint16_t protocol_version) {
// We only allow writing one replay at once; make sure that's actually
// the case.
if (writing_replay_) {
Log(LogLevel::kError,
Log(LogName::kBaAssets, LogLevel::kError,
"AssetsServer got BeginWriteReplayCall while already writing");
WriteReplayMessages();
if (replay_out_file_) {
@ -76,7 +76,7 @@ void AssetsServer::PushBeginWriteReplayCall(uint16_t protocol_version) {
replay_bytes_written_ = 0;
if (!replay_out_file_) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"unable to open output-stream file: '" + file_path + "'");
} else {
// Write file id and protocol-version.
@ -88,8 +88,9 @@ void AssetsServer::PushBeginWriteReplayCall(uint16_t protocol_version) {
|| (fwrite(&version, sizeof(version), 1, replay_out_file_) != 1)) {
fclose(replay_out_file_);
replay_out_file_ = nullptr;
Log(LogLevel::kError, "error writing replay file header: "
+ g_core->platform->GetErrnoString());
Log(LogName::kBa, LogLevel::kError,
"error writing replay file header: "
+ g_core->platform->GetErrnoString());
}
replay_bytes_written_ = 5;
}
@ -109,7 +110,7 @@ void AssetsServer::PushAddMessageToReplayCall(
// Sanity check.
if (!writing_replay_) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"AssetsServer got AddMessageToReplayCall while not writing replay");
replays_broken_ = true;
return;
@ -120,7 +121,7 @@ void AssetsServer::PushAddMessageToReplayCall(
// If we've got too much data built up (lets go with 10 megs for now),
// abort.
if (replay_message_bytes_ > 10000000) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"replay output buffer exceeded 10 megs; aborting replay");
fclose(replay_out_file_);
replay_out_file_ = nullptr;
@ -142,7 +143,8 @@ void AssetsServer::PushEndWriteReplayCall() {
// Sanity check.
if (!writing_replay_) {
Log(LogLevel::kError, "_finishWritingReplay called while not writing");
Log(LogName::kBa, LogLevel::kError,
"_finishWritingReplay called while not writing");
replays_broken_ = true;
return;
}
@ -179,8 +181,9 @@ void AssetsServer::WriteReplayMessages() {
if (fwrite(&len8, 1, 1, replay_out_file_) != 1) {
fclose(replay_out_file_);
replay_out_file_ = nullptr;
Log(LogLevel::kError, "error writing replay file: "
+ g_core->platform->GetErrnoString());
Log(LogName::kBaAudio, LogLevel::kError,
"error writing replay file: "
+ g_core->platform->GetErrnoString());
return;
}
}
@ -191,16 +194,18 @@ void AssetsServer::WriteReplayMessages() {
if (fwrite(&len16, 2, 1, replay_out_file_) != 1) {
fclose(replay_out_file_);
replay_out_file_ = nullptr;
Log(LogLevel::kError, "error writing replay file: "
+ g_core->platform->GetErrnoString());
Log(LogName::kBaAudio, LogLevel::kError,
"error writing replay file: "
+ g_core->platform->GetErrnoString());
return;
}
} else {
if (fwrite(&len32, 4, 1, replay_out_file_) != 1) {
fclose(replay_out_file_);
replay_out_file_ = nullptr;
Log(LogLevel::kError, "error writing replay file: "
+ g_core->platform->GetErrnoString());
Log(LogName::kBaAudio, LogLevel::kError,
"error writing replay file: "
+ g_core->platform->GetErrnoString());
return;
}
}
@ -211,7 +216,7 @@ void AssetsServer::WriteReplayMessages() {
if (result != 1) {
fclose(replay_out_file_);
replay_out_file_ = nullptr;
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"error writing replay file: " + g_core->platform->GetErrnoString());
return;
}

View File

@ -62,8 +62,9 @@ static auto LoadOgg(const char* file_name, std::vector<char>* buffer,
f = g_core->platform->FOpen(file_name, "rb");
if (f == nullptr) {
fallback = true;
Log(LogLevel::kError, std::string("Can't open sound file '") + file_name
+ "' for reading...");
Log(LogName::kBaAudio, LogLevel::kError,
std::string("Can't open sound file '") + file_name
+ "' for reading...");
// Attempt a fallback standin; if that doesn't work, throw in the towel.
file_name = "data/global/audio/blank.ogg";
@ -83,7 +84,7 @@ static auto LoadOgg(const char* file_name, std::vector<char>* buffer,
// Try opening the given file
if (ov_open_callbacks(f, &ogg_file, nullptr, 0, callbacks) != 0) {
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
std::string("Error decoding sound file '") + file_name + "'");
fclose(f);
@ -207,9 +208,9 @@ static void LoadCachedOgg(const char* file_name, std::vector<char>* buffer,
// with invalid formats of 0 once. Report and ignore if we see
// something like that.
if (*format != AL_FORMAT_MONO16 && *format != AL_FORMAT_STEREO16) {
Log(LogLevel::kError, std::string("Ignoring invalid audio cache of ")
+ file_name + " with format "
+ std::to_string(*format));
Log(LogName::kBaAudio, LogLevel::kError,
std::string("Ignoring invalid audio cache of ") + file_name
+ " with format " + std::to_string(*format));
} else {
return; // SUCCESS!!!!
}

View File

@ -82,7 +82,7 @@ TextureAsset::TextureAsset(const std::string& qr_url) : is_qr_code_(true) {
"QR code url byte length %zu exceeds soft-limit of %zu;"
" please use shorter urls. (url=%s)",
qr_url.size(), soft_limit, qr_url.c_str());
Log(LogLevel::kWarning, buffer);
Log(LogName::kBaAssets, LogLevel::kWarning, buffer);
}
file_name_ = qr_url;
valid_ = true;

View File

@ -18,14 +18,15 @@ namespace ballistica::base {
void _check_al_error(const char* file, int line) {
if (g_base->audio_server->paused()) {
Log(LogLevel::kError, Utils::BaseName(file) + ":" + std::to_string(line)
+ ": Checking OpenAL error while paused.");
Log(LogName::kBaAudio, LogLevel::kError,
Utils::BaseName(file) + ":" + std::to_string(line)
+ ": Checking OpenAL error while paused.");
}
ALenum al_err = alGetError();
if (al_err != AL_NO_ERROR) {
Log(LogLevel::kError, Utils::BaseName(file) + ":" + std::to_string(line)
+ ": OpenAL Error: " + GetALErrorString(al_err)
+ ";");
Log(LogName::kBaAudio, LogLevel::kError,
Utils::BaseName(file) + ":" + std::to_string(line)
+ ": OpenAL Error: " + GetALErrorString(al_err) + ";");
}
}

View File

@ -166,19 +166,19 @@ auto Audio::SafePlaySysSound(SysSoundID sound_id) -> std::optional<uint32_t> {
return {};
}
if (!g_base->InLogicThread()) {
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"Audio::SafePlaySysSound called from non-logic thread. id="
+ std::to_string(static_cast<int>(sound_id)));
return {};
}
if (!g_base->assets->sys_assets_loaded()) {
Log(LogLevel::kWarning,
Log(LogName::kBaAudio, LogLevel::kWarning,
"Audio::SafePlaySysSound called before sys assets loaded. id="
+ std::to_string(static_cast<int>(sound_id)));
return {};
}
if (!g_base->assets->IsValidSysSound(sound_id)) {
Log(LogLevel::kWarning,
Log(LogName::kBaAudio, LogLevel::kWarning,
"Audio::SafePlaySysSound called with invalid sound_id. id="
+ std::to_string(static_cast<int>(sound_id)));
return {};

View File

@ -179,8 +179,9 @@ static void ALEventCallback_(ALenum eventType, ALuint object, ALuint param,
[] { g_base->audio_server->OnDeviceDisconnected(); });
}
} else {
Log(LogLevel::kWarning, "Got unexpected OpenAL callback event "
+ std::to_string(static_cast<int>(eventType)));
Log(LogName::kBaAudio, LogLevel::kWarning,
"Got unexpected OpenAL callback event "
+ std::to_string(static_cast<int>(eventType)));
}
}
@ -244,7 +245,7 @@ void AudioServer::OnAppStartInThread_() {
if (g_core->platform->GetOSVersionString().compare(0, prefix2.size(),
prefix2)
== 0) {
Log(LogLevel::kInfo,
Log(LogName::kBaAudio, LogLevel::kInfo,
"Xiaomi Android 11 detected; using OpenSL instead of AAudio.");
g_core->platform->SetEnv("BA_OBOE_USE_OPENSLES", "1");
}
@ -260,7 +261,8 @@ void AudioServer::OnAppStartInThread_() {
ALboolean enumeration =
alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT");
if (enumeration == AL_FALSE) {
Log(LogLevel::kError, "OpenAL enumeration extensions missing.");
Log(LogName::kBaAudio, LogLevel::kError,
"OpenAL enumeration extensions missing.");
} else {
const ALCchar* devices =
alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
@ -298,7 +300,7 @@ void AudioServer::OnAppStartInThread_() {
if (!device) {
if (g_buildconfig.ostype_android()) {
std::scoped_lock lock(openalsoft_android_log_mutex_);
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"------------------------"
" OPENALSOFT-FATAL-ERROR-LOG-BEGIN ----------------------\n"
+ openalsoft_android_log_
@ -315,11 +317,11 @@ void AudioServer::OnAppStartInThread_() {
// Android special case: if we fail, try again after a few seconds.
if (!impl_->alc_context && g_buildconfig.ostype_android()) {
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"Failed creating AL context; waiting and trying again.");
{
std::scoped_lock lock(openalsoft_android_log_mutex_);
Log(LogLevel::kWarning,
Log(LogName::kBaAudio, LogLevel::kWarning,
"------------------------"
" OPENALSOFT-ERROR-LOG-BEGIN ----------------------\n"
+ openalsoft_android_log_
@ -334,7 +336,7 @@ void AudioServer::OnAppStartInThread_() {
if (!device) {
std::scoped_lock lock(openalsoft_android_log_mutex_);
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"------------------------"
" OPENALSOFT-FATAL-ERROR-LOG-BEGIN ----------------------\n"
+ openalsoft_android_log_
@ -346,17 +348,18 @@ void AudioServer::OnAppStartInThread_() {
impl_->alc_context = alcCreateContext(device, nullptr);
if (impl_->alc_context) {
// For now want to explicitly know if this works.
Log(LogLevel::kWarning, "Backup AL context creation successful!");
Log(LogName::kBaAudio, LogLevel::kWarning,
"Backup AL context creation successful!");
}
}
// Android special case: if we fail, try OpenSL back-end.
if (!impl_->alc_context && g_buildconfig.ostype_android()) {
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"Failed second time creating AL context; trying OpenSL backend.");
{
std::scoped_lock lock(openalsoft_android_log_mutex_);
Log(LogLevel::kWarning,
Log(LogName::kBaAudio, LogLevel::kWarning,
"------------------------"
" OPENALSOFT-ERROR-LOG-BEGIN ----------------------\n"
+ openalsoft_android_log_
@ -370,7 +373,7 @@ void AudioServer::OnAppStartInThread_() {
alGetError(); // Clear any errors.
if (!device) {
std::scoped_lock lock(openalsoft_android_log_mutex_);
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"------------------------"
" OPENALSOFT-FATAL-ERROR-LOG-BEGIN ----------------------\n"
+ openalsoft_android_log_
@ -382,7 +385,8 @@ void AudioServer::OnAppStartInThread_() {
impl_->alc_context = alcCreateContext(device, nullptr);
if (impl_->alc_context) {
// For now want to explicitly know if this works.
Log(LogLevel::kWarning, "Backup AL context creation 2 successful!");
Log(LogName::kBaAudio, LogLevel::kWarning,
"Backup AL context creation 2 successful!");
}
}
@ -390,7 +394,7 @@ void AudioServer::OnAppStartInThread_() {
if (!impl_->alc_context) {
if (g_buildconfig.ostype_android()) {
std::scoped_lock lock(openalsoft_android_log_mutex_);
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"------------------------"
" OPENALSOFT-FATAL-ERROR-LOG-BEGIN ----------------------\n"
+ openalsoft_android_log_
@ -459,8 +463,9 @@ void AudioServer::OnAppStartInThread_() {
sound_source_refs_.push_back(s);
sources_.push_back(&(*s));
} else {
Log(LogLevel::kError, "Made " + std::to_string(i) + " sources; (wanted "
+ std::to_string(target_source_count) + ").");
Log(LogName::kBaAudio, LogLevel::kError,
"Made " + std::to_string(i) + " sources; (wanted "
+ std::to_string(target_source_count) + ").");
break;
}
}
@ -498,20 +503,23 @@ void AudioServer::CompleteShutdown_() {
#if BA_ENABLE_AUDIO
ALCboolean check = alcMakeContextCurrent(nullptr);
if (!check) {
Log(LogLevel::kWarning, "Error on alcMakeContextCurrent at shutdown.");
Log(LogName::kBaAudio, LogLevel::kWarning,
"Error on alcMakeContextCurrent at shutdown.");
}
auto* device = alcGetContextsDevice(impl_->alc_context);
if (!device) {
Log(LogLevel::kWarning, "Unable to get ALCdevice at shutdown.");
Log(LogName::kBaAudio, LogLevel::kWarning,
"Unable to get ALCdevice at shutdown.");
} else {
alcDestroyContext(impl_->alc_context);
ALenum err = alcGetError(device);
if (err != ALC_NO_ERROR) {
Log(LogLevel::kWarning, "Error on AL shutdown.");
Log(LogName::kBaAudio, LogLevel::kWarning, "Error on AL shutdown.");
}
check = alcCloseDevice(device);
if (!check) {
Log(LogLevel::kWarning, "Error on alcCloseDevice at shutdown.");
Log(LogName::kBaAudio, LogLevel::kWarning,
"Error on alcCloseDevice at shutdown.");
}
}
#endif
@ -534,7 +542,7 @@ struct AudioServer::SoundFadeNode_ {
void AudioServer::SetSuspended_(bool suspend) {
if (!suspended_) {
if (!suspend) {
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"Got audio unsuspend request when already unsuspended.");
} else {
#if BA_OSTYPE_IOS_TVOS
@ -557,7 +565,7 @@ void AudioServer::SetSuspended_(bool suspend) {
+ std::to_string(g_core->GetAppTimeSeconds()));
alcDevicePauseSOFT(device);
} catch (const std::exception& e) {
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"Error in alcDevicePauseSOFT at time "
+ std::to_string(g_core->GetAppTimeSeconds())
+ "( playing since "
@ -565,7 +573,8 @@ void AudioServer::SetSuspended_(bool suspend) {
+ "): " + g_core->platform->DemangleCXXSymbol(typeid(e).name())
+ " " + e.what());
} catch (...) {
Log(LogLevel::kError, "Unknown error in alcDevicePauseSOFT");
Log(LogName::kBaAudio, LogLevel::kError,
"Unknown error in alcDevicePauseSOFT");
}
#endif
@ -574,7 +583,7 @@ void AudioServer::SetSuspended_(bool suspend) {
} else {
// Unsuspend if requested.
if (suspend) {
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"Got audio suspend request when already suspended.");
} else {
#if BA_OSTYPE_IOS_TVOS
@ -599,13 +608,14 @@ void AudioServer::SetSuspended_(bool suspend) {
+ std::to_string(g_core->GetAppTimeSeconds()));
alcDeviceResumeSOFT(device);
} catch (const std::exception& e) {
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"Error in alcDeviceResumeSOFT at time "
+ std::to_string(g_core->GetAppTimeSeconds()) + ": "
+ g_core->platform->DemangleCXXSymbol(typeid(e).name()) + " "
+ e.what());
} catch (...) {
Log(LogLevel::kError, "Unknown error in alcDeviceResumeSOFT");
Log(LogName::kBaAudio, LogLevel::kError,
"Unknown error in alcDeviceResumeSOFT");
}
#endif
last_started_playing_time_ = g_core->GetAppTimeSeconds();
@ -777,7 +787,7 @@ void AudioServer::UpdateAvailableSources_() {
// that probably means somebody's grabbing a source but never
// resubmitting it.
if (t - i->client_source()->last_lock_time() > 10000) {
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"Client audio source has been locked for too long; "
"probably leaked. (debug id "
+ std::to_string(i->client_source()->lock_debug_id()) + ")");
@ -926,7 +936,8 @@ void AudioServer::ProcessDeviceDisconnects_(seconds_t real_time_seconds) {
if (connected == 0
&& real_time_seconds - last_reset_attempt_time_ >= retry_interval) {
Log(LogLevel::kInfo, "OpenAL device disconnected; resetting...");
Log(LogName::kBaAudio, LogLevel::kInfo,
"OpenAL device disconnected; resetting...");
if (g_buildconfig.ostype_android()) {
std::scoped_lock lock(openalsoft_android_log_mutex_);
openalsoft_android_log_ +=
@ -995,7 +1006,7 @@ void AudioServer::ProcessDeviceDisconnects_(seconds_t real_time_seconds) {
shipped_reconnect_logs_ = true;
if (g_buildconfig.ostype_android()) {
std::scoped_lock lock(openalsoft_android_log_mutex_);
Log(LogLevel::kWarning,
Log(LogName::kBaAudio, LogLevel::kWarning,
"Have been disconnected for a while; dumping OpenAL log.\n"
"------------------------"
" OPENALSOFT-RECONNECT-LOG-BEGIN ----------------------\n"
@ -1153,8 +1164,9 @@ AudioServer::ThreadSource_::ThreadSource_(AudioServer* audio_server_in,
ALenum err = alGetError();
valid_ = (err == AL_NO_ERROR);
if (!valid_) {
Log(LogLevel::kError, std::string("AL Error ") + GetALErrorString(err)
+ " on source creation.");
Log(LogName::kBaAudio, LogLevel::kError,
std::string("AL Error ") + GetALErrorString(err)
+ " on source creation.");
} else {
// In vr mode we keep the microphone a bit closer to the camera
// for realism purposes, so we need stuff louder in general.
@ -1347,7 +1359,7 @@ void AudioServer::ThreadSource_::SetPosition(float x, float y, float z) {
z = 500;
}
if (oob) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaAudio, LogLevel::kError,
"AudioServer::ThreadSource::SetPosition"
" got out-of-bounds value.");
}

View File

@ -42,7 +42,8 @@ void AudioSource::SetPosition(float x, float y, float z) {
assert(client_queue_size_ > 0);
#if BA_DEBUG_BUILD
if (std::isnan(x) || std::isnan(y) || std::isnan(z)) {
Log(LogLevel::kError, "Got nan value in AudioSource::SetPosition.");
Log(LogName::kBaAudio, LogLevel::kError,
"Got nan value in AudioSource::SetPosition.");
}
#endif
g_base->audio_server->PushSourceSetPositionCall(play_id_, Vector3f(x, y, z));

View File

@ -89,9 +89,9 @@ void AudioStreamer::Update() {
// A fun anomaly in the linux version; we sometimes get more
// "processed" buffers than we have queued.
if (queued < processed) {
Log(LogLevel::kError, "Streamer oddness: queued(" + std::to_string(queued)
+ "); processed(" + std::to_string(processed)
+ ")");
Log(LogName::kBaAudio, LogLevel::kError,
"Streamer oddness: queued(" + std::to_string(queued) + "); processed("
+ std::to_string(processed) + ")");
processed = queued;
}

View File

@ -93,7 +93,7 @@ void OggStream::DoStream(char* pcm, int* size, unsigned int* rate) {
static bool reported_error = false;
if (!reported_error) {
reported_error = true;
Log(LogLevel::kError,
Log(LogName::kBaAudio, LogLevel::kError,
"Error streaming ogg file: '" + file_name() + "'.");
}
if (loops()) {

View File

@ -31,10 +31,10 @@
#include "ballistica/base/support/plus_soft.h"
#include "ballistica/base/support/stdio_console.h"
#include "ballistica/base/ui/ui_delegate.h"
#include "ballistica/core/python/core_python.h"
#include "ballistica/shared/foundation/event_loop.h"
#include "ballistica/shared/foundation/logging.h"
#include "ballistica/shared/generic/utils.h"
#include "ballistica/shared/math/vector4f.h"
#include "ballistica/shared/python/python_command.h"
namespace ballistica::base {
@ -125,11 +125,6 @@ void BaseFeatureSet::OnModuleExec(PyObject* module) {
FatalError("babase._env.on_native_module_import() call failed.");
}
// ..and because Python is now feeding us logs, we can push any logs
// through that we've been holding on to and start forwarding log calls as
// they happen.
g_core->python->EnablePythonLoggingCalls();
// A marker we pop down at the very end so other modules can run sanity
// checks to make sure we aren't importing them reciprocally when they
// import us.
@ -160,7 +155,7 @@ void BaseFeatureSet::SuccessScreenMessage() {
python->objs().Get(BasePython::ObjID::kSuccessMessageCall).Call();
});
} else {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"SuccessScreenMessage called without logic event_loop in place.");
}
}
@ -171,7 +166,7 @@ void BaseFeatureSet::ErrorScreenMessage() {
python->objs().Get(BasePython::ObjID::kErrorMessageCall).Call();
});
} else {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"ErrorScreenMessage called without logic event_loop in place.");
}
}
@ -186,7 +181,8 @@ auto BaseFeatureSet::GetV2AccountID() -> std::optional<std::string> {
}
return result.ValueAsString();
} else {
Log(LogLevel::kError, "GetV2AccountID() py call errored.");
Log(LogName::kBaAccount, LogLevel::kError,
"GetV2AccountID() py call errored.");
return {};
}
}
@ -219,7 +215,7 @@ void BaseFeatureSet::StartApp() {
// Read in ba.app.config for anyone who wants to start looking at it
// (though we don't explicitly ask anyone to apply it until later).
python->ReadConfig();
// python->ReadConfig();
// Allow our subsystems to start doing work in their own threads and
// communicating with other subsystems. Note that we may still want to run
@ -262,7 +258,7 @@ void BaseFeatureSet::StartApp() {
char buffer[128];
snprintf(buffer, sizeof(buffer),
"StartApp() took too long (%.2lf seconds).", duration);
Log(LogLevel::kWarning, buffer);
Log(LogName::kBa, LogLevel::kWarning, buffer);
}
}
@ -271,7 +267,7 @@ void BaseFeatureSet::SuspendApp() {
assert(g_core->InMainThread());
if (app_suspended_) {
Log(LogLevel::kWarning,
Log(LogName::kBa, LogLevel::kWarning,
"AppAdapter::SuspendApp() called with app already suspended.");
return;
}
@ -313,7 +309,7 @@ void BaseFeatureSet::SuspendApp() {
// running_loop_count = loops.size();
if (running_loops.empty()) {
if (g_buildconfig.debug_build()) {
Log(LogLevel::kDebug,
Log(LogName::kBa, LogLevel::kDebug,
"SuspendApp() completed in "
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()
- start_time)
@ -374,7 +370,7 @@ void BaseFeatureSet::SuspendApp() {
}
msg += ").";
Log(LogLevel::kError, msg);
Log(LogName::kBa, LogLevel::kError, msg);
}
void BaseFeatureSet::UnsuspendApp() {
@ -382,7 +378,7 @@ void BaseFeatureSet::UnsuspendApp() {
assert(g_core->InMainThread());
if (!app_suspended_) {
Log(LogLevel::kWarning,
Log(LogName::kBa, LogLevel::kWarning,
"AppAdapter::UnsuspendApp() called with app not in suspendedstate.");
return;
}
@ -400,7 +396,7 @@ void BaseFeatureSet::UnsuspendApp() {
g_base->networking->OnAppUnsuspend();
if (g_buildconfig.debug_build()) {
Log(LogLevel::kDebug,
Log(LogName::kBa, LogLevel::kDebug,
"UnsuspendApp() completed in "
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()
- start_time)
@ -431,7 +427,7 @@ void BaseFeatureSet::LogVersionInfo_() {
snprintf(buffer, sizeof(buffer), "BallisticaKit %s build %d.",
kEngineVersion, kEngineBuildNumber);
}
Log(LogLevel::kInfo, buffer);
Log(LogName::kBa, LogLevel::kInfo, buffer);
}
void BaseFeatureSet::set_app_mode(AppMode* mode) {
@ -440,7 +436,7 @@ void BaseFeatureSet::set_app_mode(AppMode* mode) {
// Redundant sets should not happen (make an exception here for empty mode
// since that's in place before any app mode is officially set).
if (mode == app_mode_ && mode != EmptyAppMode::GetSingleton()) {
Log(LogLevel::kWarning,
Log(LogName::kBa, LogLevel::kWarning,
"set_app_mode called with already-current app-mode; unexpected.");
}
@ -568,7 +564,8 @@ auto BaseFeatureSet::GetAppInstanceUUID() -> const std::string& {
if (!have_app_instance_uuid) {
// As an emergency fallback simply use a single random number. We
// should probably simply disallow this before Python is up.
Log(LogLevel::kWarning, "GetSessionUUID() using rand fallback.");
Log(LogName::kBa, LogLevel::kWarning,
"GetSessionUUID() using rand fallback.");
srand(static_cast<unsigned int>(
core::CorePlatform::GetCurrentMillisecs())); // NOLINT
app_instance_uuid =
@ -576,7 +573,8 @@ auto BaseFeatureSet::GetAppInstanceUUID() -> const std::string& {
have_app_instance_uuid = true;
}
if (app_instance_uuid.size() >= 100) {
Log(LogLevel::kWarning, "session id longer than it should be.");
Log(LogName::kBa, LogLevel::kWarning,
"session id longer than it should be.");
}
}
return app_instance_uuid;
@ -668,6 +666,7 @@ void BaseFeatureSet::DoV1CloudLog(const std::string& msg) {
static bool warned = false;
if (!warned) {
warned = true;
printf("MSG %s\n", msg.c_str());
printf(
"WARNING: V1CloudLog called before babase fully imported; "
"ignoring.\n");
@ -725,8 +724,9 @@ void BaseFeatureSet::DoV1CloudLog(const std::string& msg) {
plus()->DirectSendV1CloudLogs(logprefix, logsuffix, false, nullptr);
}
void BaseFeatureSet::PushDevConsolePrintCall(const std::string& msg) {
ui->PushDevConsolePrintCall(msg);
void BaseFeatureSet::PushDevConsolePrintCall(const std::string& msg,
float scale, Vector4f color) {
ui->PushDevConsolePrintCall(msg, scale, color);
}
PyObject* BaseFeatureSet::GetPyExceptionType(PyExcType exctype) {
@ -833,7 +833,7 @@ void BaseFeatureSet::DoPushObjCall(const PythonObjectSetBase* objset, int id) {
});
} else {
BA_LOG_ONCE(
LogLevel::kError,
LogName::kBa, LogLevel::kError,
"BaseFeatureSet::DoPushObjCall called before event loop created.");
}
}
@ -968,8 +968,9 @@ void BaseFeatureSet::SetAppActive(bool active) {
// Issue a gentle warning if they are feeding us the same state twice in a
// row; might imply faulty logic on an app-adapter or whatnot.
if (app_active_set_ && app_active_ == active) {
Log(LogLevel::kWarning, "SetAppActive called with state "
+ std::to_string(active) + " twice in a row.");
Log(LogName::kBa, LogLevel::kWarning,
"SetAppActive called with state " + std::to_string(active)
+ " twice in a row.");
}
app_active_set_ = true;
app_active_ = active;

View File

@ -731,7 +731,8 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
-> PyObject* override;
auto FeatureSetFromData(PyObject* obj) -> FeatureSetNativeComponent* override;
void DoV1CloudLog(const std::string& msg) override;
void PushDevConsolePrintCall(const std::string& msg) override;
void PushDevConsolePrintCall(const std::string& msg, float scale,
Vector4f color) override;
auto GetPyExceptionType(PyExcType exctype) -> PyObject* override;
auto PrintPythonStackTrace() -> bool override;
auto GetPyLString(PyObject* obj) -> std::string override;

View File

@ -72,8 +72,8 @@ void BGDynamics::Step(const Vector3f& cam_pos, int step_millisecs) {
return;
}
// Pass a newly allocated raw pointer to the bg-dynamics thread; it takes care
// of disposing it when done.
// Pass a newly allocated raw pointer to the bg-dynamics thread; it takes
// care of disposing it when done.
auto d = Object::NewDeferred<BGDynamicsServer::StepData>();
d->graphics_quality = Graphics::GraphicsQualityFromRequest(
g_base->graphics->settings()->graphics_quality,

View File

@ -1372,7 +1372,7 @@ void BGDynamicsServer::Emit(const BGDynamicsEmission& def) {
}
default: {
int t = static_cast<int>(def.emit_type);
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBa, LogLevel::kError,
"Invalid bg-dynamics emit type: " + std::to_string(t));
break;
}
@ -2361,9 +2361,9 @@ void BGDynamicsServer::Step(StepData* step_data) {
// Math sanity check.
if (step_count_ < 0) {
BA_LOG_ONCE(LogLevel::kWarning, "BGDynamics step_count too low ("
+ std::to_string(step_count_)
+ "); should not happen.");
BA_LOG_ONCE(LogName::kBaGraphics, LogLevel::kWarning,
"BGDynamics step_count too low (" + std::to_string(step_count_)
+ "); should not happen.");
}
}
@ -2376,9 +2376,9 @@ void BGDynamicsServer::PushStep(StepData* data) {
// Client thread should stop feeding us if we get clogged up.
if (step_count_ > 5) {
BA_LOG_ONCE(LogLevel::kWarning, "BGDynamics step_count too high ("
+ std::to_string(step_count_)
+ "); should not happen.");
BA_LOG_ONCE(LogName::kBa, LogLevel::kWarning,
"BGDynamics step_count too high (" + std::to_string(step_count_)
+ "); should not happen.");
}
event_loop()->PushCall([this, data] { Step(data); });

View File

@ -80,7 +80,7 @@ class RendererGL::MeshAssetDataGL : public MeshAssetRendererData {
}
case 4: {
BA_LOG_ONCE(
LogLevel::kWarning,
LogName::kBaGraphics, LogLevel::kWarning,
"GL WARNING - USING 32 BIT INDICES WHICH WONT WORK IN ES2!!");
elem_count_ = static_cast<uint32_t>(model.indices32().size());
index_type_ = GL_UNSIGNED_INT;

View File

@ -126,7 +126,7 @@ class RendererGL::MeshDataGL : public MeshRendererData {
dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
index_state_ = data->state;
have_index_data_ = true;
BA_LOG_ONCE(LogLevel::kWarning,
BA_LOG_ONCE(LogName::kBaGraphics, LogLevel::kWarning,
"GL WARNING - USING 32 BIT INDICES WHICH WONT WORK IN ES2!!");
index_type_ = GL_UNSIGNED_INT;
}

View File

@ -86,7 +86,7 @@ class RendererGL::ProgramBlurGL : public RendererGL::ProgramGL {
s += "}";
if (flags & SHD_DEBUG_PRINT)
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
return s;
}
@ -121,7 +121,7 @@ class RendererGL::ProgramBlurGL : public RendererGL::ProgramGL {
"(colorTex,vUV8));\n"
"}";
if (flags & SHD_DEBUG_PRINT) {
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
}
return s;

View File

@ -49,7 +49,7 @@ class RendererGL::ShaderGL : public Object {
const char* renderer = (const char*)glGetString(GL_RENDERER);
// Let's not crash here. We have a better chance of calling home this
// way and theres a chance the game will still be playable.
Log(LogLevel::kError,
Log(LogName::kBaGraphics, LogLevel::kError,
std::string("Compile failed for ") + GetTypeName()
+ " shader:\n------------SOURCE BEGIN-------------\n" + src_fin
+ "\n-----------SOURCE END-------------\n" + GetInfo()
@ -65,7 +65,7 @@ class RendererGL::ShaderGL : public Object {
const char* version = (const char*)glGetString(GL_VERSION);
const char* vendor = (const char*)glGetString(GL_VENDOR);
const char* renderer = (const char*)glGetString(GL_RENDERER);
Log(LogLevel::kError,
Log(LogName::kBaGraphics, LogLevel::kError,
std::string("WARNING: info returned for ") + GetTypeName()
+ " shader:\n------------SOURCE BEGIN-------------\n" + src_fin
+ "\n-----------SOURCE END-------------\n" + info
@ -166,7 +166,7 @@ class RendererGL::ProgramGL {
GLint linkStatus;
glGetProgramiv(program_, GL_LINK_STATUS, &linkStatus);
if (linkStatus == GL_FALSE) {
Log(LogLevel::kError,
Log(LogName::kBaGraphics, LogLevel::kError,
"Link failed for program '" + name_ + "':\n" + GetInfo());
} else {
assert(linkStatus == GL_TRUE);
@ -176,8 +176,9 @@ class RendererGL::ProgramGL {
&& (strstr(info.c_str(), "error:") || strstr(info.c_str(), "warning:")
|| strstr(info.c_str(), "Error:")
|| strstr(info.c_str(), "Warning:"))) {
Log(LogLevel::kError, "WARNING: program using frag shader '" + name_
+ "' returned info:\n" + info);
Log(LogName::kBaGraphics, LogLevel::kError,
"WARNING: program using frag shader '" + name_
+ "' returned info:\n" + info);
}
}
@ -314,9 +315,9 @@ class RendererGL::ProgramGL {
assert(IsBound());
int c = glGetUniformLocation(program_, tex_name);
if (c == -1) {
Log(LogLevel::kError, "ShaderGL: " + name_
+ ": Can't set texture unit for texture '"
+ tex_name + "'");
Log(LogName::kBaGraphics, LogLevel::kError,
"ShaderGL: " + name_ + ": Can't set texture unit for texture '"
+ tex_name + "'");
BA_DEBUG_CHECK_GL_ERROR;
} else {
glUniform1i(c, unit);

View File

@ -235,7 +235,7 @@ class RendererGL::ProgramObjectGL : public RendererGL::ProgramGL {
}
s += "}";
if (flags & SHD_DEBUG_PRINT)
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
return s;
}
@ -321,7 +321,7 @@ class RendererGL::ProgramObjectGL : public RendererGL::ProgramGL {
s += "}";
if (flags & SHD_DEBUG_PRINT)
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
return s;
}

View File

@ -158,7 +158,7 @@ class RendererGL::ProgramPostProcessGL : public RendererGL::ProgramGL {
s += "}";
if (flags & SHD_DEBUG_PRINT)
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
return s;
}
@ -306,7 +306,7 @@ class RendererGL::ProgramPostProcessGL : public RendererGL::ProgramGL {
s += "}";
if (flags & SHD_DEBUG_PRINT)
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
return s;
}

View File

@ -54,7 +54,7 @@ class RendererGL::ProgramShieldGL : public RendererGL::ProgramGL {
s += "}";
if (flags & SHD_DEBUG_PRINT)
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
return s;
}
@ -114,7 +114,7 @@ class RendererGL::ProgramShieldGL : public RendererGL::ProgramGL {
//" " BA_GLSL_FRAGCOLOR " = vec4(vec3(depth),1);\n"
if (flags & SHD_DEBUG_PRINT)
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
return s;
}

View File

@ -234,7 +234,7 @@ class RendererGL::ProgramSimpleGL : public RendererGL::ProgramGL {
"}";
if (flags & SHD_DEBUG_PRINT) {
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
}
@ -383,7 +383,7 @@ class RendererGL::ProgramSimpleGL : public RendererGL::ProgramGL {
s += "}";
if (flags & SHD_DEBUG_PRINT) {
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
}

View File

@ -114,7 +114,7 @@ class RendererGL::ProgramSmokeGL : public RendererGL::ProgramGL {
s += "}";
if (flags & SHD_DEBUG_PRINT)
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
return s;
}
@ -160,7 +160,7 @@ class RendererGL::ProgramSmokeGL : public RendererGL::ProgramGL {
s += "}";
if (flags & SHD_DEBUG_PRINT)
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
return s;
}

View File

@ -9,6 +9,7 @@
#include "ballistica/base/graphics/gl/program/program_gl.h"
#include "ballistica/base/graphics/gl/renderer_gl.h"
#include "ballistica/base/graphics/graphics.h"
namespace ballistica::base {
@ -121,7 +122,7 @@ class RendererGL::ProgramSpriteGL : public RendererGL::ProgramGL {
s += "}";
if (flags & SHD_DEBUG_PRINT) {
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nVertex code for shader '" + GetName(flags) + "':\n\n" + s);
}
return s;
@ -163,7 +164,7 @@ class RendererGL::ProgramSpriteGL : public RendererGL::ProgramGL {
}
s += "}";
if (flags & SHD_DEBUG_PRINT) {
Log(LogLevel::kInfo,
Log(LogName::kBaGraphics, LogLevel::kInfo,
"\nFragment code for shader '" + GetName(flags) + "':\n\n" + s);
}
return s;

View File

@ -60,7 +60,7 @@ class RendererGL::RenderTargetGL : public RenderTarget {
// this needs to be on for glClear to work on depth.
if (!renderer_->depth_writing_enabled_) {
BA_LOG_ONCE(
LogLevel::kWarning,
LogName::kBaGraphics, LogLevel::kWarning,
"RendererGL: depth-writing not enabled when clearing depth");
}
clear_mask |= GL_DEPTH_BUFFER_BIT;

View File

@ -90,7 +90,7 @@ void RendererGL::CheckGLError(const char* file, int line) {
BA_PRECONDITION_FATAL(vendor);
const char* renderer = (const char*)glGetString(GL_RENDERER);
BA_PRECONDITION_FATAL(renderer);
Log(LogLevel::kError,
Log(LogName::kBaGraphics, LogLevel::kError,
"OpenGL Error at " + std::string(file) + " line " + std::to_string(line)
+ ": " + GLErrorToString(err) + "\nrenderer: " + renderer
+ "\nvendor: " + vendor + "\nversion: " + version
@ -174,7 +174,7 @@ void RendererGL::CheckGLVersion() {
if (gl_is_es()) {
// GL ES version strings start with 'OpenGL ES X' with X being version.
const char* prefix = "OpenGL ES ";
int prefixlen = strlen(prefix);
auto prefixlen = strlen(prefix);
BA_PRECONDITION_FATAL(!strncmp(version_str, prefix, prefixlen));
if (version_str[prefixlen] != '3') {
FatalError(
@ -223,11 +223,9 @@ void RendererGL::CheckGLCapabilities_() {
basestr = "OpenGL";
}
if (g_buildconfig.debug_build()) {
Log(LogLevel::kInfo, std::string("Using ") + basestr + " (vendor: " + vendor
+ ", renderer: " + renderer
+ ", version: " + version_str + ").");
}
Log(LogName::kBaGraphics, LogLevel::kInfo,
std::string("Using ") + basestr + " (vendor: " + vendor
+ ", renderer: " + renderer + ", version: " + version_str + ").");
// Build a vector of extensions. Newer GLs give us extensions as lists
// already, but on older ones we may need to break a single string apart
@ -246,7 +244,8 @@ void RendererGL::CheckGLCapabilities_() {
extensions.push_back(extension);
}
} else {
Log(LogLevel::kWarning, "Falling back on legacy GL_EXTENSIONS parsing.");
Log(LogName::kBaGraphics, LogLevel::kWarning,
"Falling back on legacy GL_EXTENSIONS parsing.");
// Fall back on parsing the single giant string if need be.
// (Can probably kill this).
auto* ex = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
@ -292,7 +291,8 @@ void RendererGL::CheckGLCapabilities_() {
c_types.push_back(TextureCompressionType::kETC1);
} else {
if (g_buildconfig.ostype_android()) {
Log(LogLevel::kError, "Android device missing ETC1 support.");
Log(LogName::kBaGraphics, LogLevel::kError,
"Android device missing ETC1 support.");
}
}
@ -360,7 +360,8 @@ void RendererGL::CheckGLCapabilities_() {
&samples[0]);
msaa_max_samples_rgb565_ = samples[0];
} else {
BA_LOG_ONCE(LogLevel::kError, "Got 0 samplecounts for RGB565");
BA_LOG_ONCE(LogName::kBaGraphics, LogLevel::kError,
"Got 0 samplecounts for RGB565");
msaa_max_samples_rgb565_ = 0;
}
@ -374,7 +375,8 @@ void RendererGL::CheckGLCapabilities_() {
&samples[0]);
msaa_max_samples_rgb8_ = samples[0];
} else {
BA_LOG_ONCE(LogLevel::kError, "Got 0 samplecounts for RGB8");
BA_LOG_ONCE(LogName::kBaGraphics, LogLevel::kError,
"Got 0 samplecounts for RGB8");
msaa_max_samples_rgb8_ = 0;
}
} else {
@ -2385,7 +2387,7 @@ void RendererGL::UpdateVignetteTex_(bool force) {
if (err != GL_NO_ERROR) {
static bool reported = false;
if (!reported) {
Log(LogLevel::kError,
Log(LogName::kBaGraphics, LogLevel::kError,
"32-bit vignette creation failed; falling back to 16.");
reported = true;
}
@ -2443,7 +2445,8 @@ void RendererGL::UpdateVignetteTex_(bool force) {
auto RendererGL::GetFunkyDepthIssue_() -> bool {
if (!funky_depth_issue_set_) {
BA_LOG_ONCE(LogLevel::kError, "fetching funky depth issue but not set");
BA_LOG_ONCE(LogName::kBaGraphics, LogLevel::kError,
"fetching funky depth issue but not set");
}
return funky_depth_issue_;
}

View File

@ -27,7 +27,8 @@ class RendererGL::TextureDataGL : public TextureAssetRendererData {
~TextureDataGL() override {
if (!g_base->app_adapter->InGraphicsContext()) {
Log(LogLevel::kError, "TextureDataGL dying outside of graphics thread.");
Log(LogName::kBaGraphics, LogLevel::kError,
"TextureDataGL dying outside of graphics thread.");
} else {
// If we're currently bound as anything, clear that out (otherwise a
// new texture with that same ID won't be bindable).

View File

@ -204,7 +204,7 @@ auto Graphics::TextureQualityFromAppConfig() -> TextureQualityRequest {
} else if (texqualstr == "Low") {
texture_quality_requested = TextureQualityRequest::kLow;
} else {
Log(LogLevel::kError,
Log(LogName::kBaGraphics, LogLevel::kError,
"Invalid texture quality: '" + texqualstr + "'; defaulting to low.");
texture_quality_requested = TextureQualityRequest::kLow;
}
@ -221,7 +221,8 @@ auto Graphics::VSyncFromAppConfig() -> VSyncRequest {
} else if (v_sync == "Never") {
return VSyncRequest::kNever;
}
Log(LogLevel::kError, "Invalid 'Vertical Sync' value: '" + v_sync + "'");
Log(LogName::kBaGraphics, LogLevel::kError,
"Invalid 'Vertical Sync' value: '" + v_sync + "'");
return VSyncRequest::kNever;
}
@ -240,7 +241,7 @@ auto Graphics::GraphicsQualityFromAppConfig() -> GraphicsQualityRequest {
} else if (gqualstr == "Low") {
graphics_quality_requested = GraphicsQualityRequest::kLow;
} else {
Log(LogLevel::kError,
Log(LogName::kBaGraphics, LogLevel::kError,
"Invalid graphics quality: '" + gqualstr + "'; defaulting to auto.");
graphics_quality_requested = GraphicsQualityRequest::kAuto;
}
@ -627,7 +628,7 @@ void Graphics::FadeScreen(bool to, millisecs_t time, PyObject* endcall) {
// (otherwise, overlapping fades can cause things to get lost)
if (fade_end_call_.Exists()) {
if (g_buildconfig.debug_build()) {
Log(LogLevel::kWarning,
Log(LogName::kBaGraphics, LogLevel::kWarning,
"2 fades overlapping; running first fade-end-call early.");
}
fade_end_call_->Schedule();
@ -861,7 +862,7 @@ void Graphics::BuildAndPushFrameDef() {
if (g_core->vr_mode()) {
if (frame_def->GetOverlayFlatPass()->HasDrawCommands()) {
if (!g_base->ui->MainMenuVisible()) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaGraphics, LogLevel::kError,
"Drawing in overlay pass in VR mode with no UI present; "
"shouldn't happen!");
}
@ -1015,7 +1016,7 @@ void Graphics::DrawFades(FrameDef* frame_def) {
// TEMP HACK - don't trigger this while inactive.
// Need to make overall fade logic smarter.
if (faded_time > 15000 && g_base->app_active()) {
Log(LogLevel::kError, "FORCE-ENDING STUCK FADE");
Log(LogName::kBaGraphics, LogLevel::kError, "FORCE-ENDING STUCK FADE");
fade_out_ = false;
fade_ = 1.0f;
fade_time_ = 1000;
@ -1513,8 +1514,9 @@ void Graphics::DrawRadialMeter(MeshIndexedSimpleFull* m, float amt) {
void Graphics::OnScreenSizeChange() {}
void Graphics::CalcVirtualRes_(float* x, float* y) {
assert(g_base);
void Graphics::GetBaseVirtualRes(float* x, float* y) {
assert(x);
assert(y);
float base_virtual_res_x;
float base_virtual_res_y;
if (g_base->ui->scale() == UIScale::kSmall) {
@ -1524,6 +1526,15 @@ void Graphics::CalcVirtualRes_(float* x, float* y) {
base_virtual_res_x = kBaseVirtualResX;
base_virtual_res_y = kBaseVirtualResY;
}
*x = base_virtual_res_x;
*y = base_virtual_res_y;
}
void Graphics::CalcVirtualRes_(float* x, float* y) {
assert(g_base);
float base_virtual_res_x;
float base_virtual_res_y;
GetBaseVirtualRes(&base_virtual_res_x, &base_virtual_res_y);
float x_in = *x;
float y_in = *y;
@ -1662,7 +1673,7 @@ auto Graphics::ReflectionTypeFromString(const std::string& s)
void Graphics::LanguageChanged() {
assert(g_base && g_base->InLogicThread());
if (building_frame_def_) {
Log(LogLevel::kWarning,
Log(LogName::kBa, LogLevel::kWarning,
"Graphics::LanguageChanged() called during draw; should not happen.");
}
screenmessages->ClearScreenMessageTranslations();
@ -1683,8 +1694,9 @@ auto Graphics::GraphicsQualityFromRequest(GraphicsQualityRequest request,
case GraphicsQualityRequest::kAuto:
return auto_val;
default:
Log(LogLevel::kError, "Unhandled GraphicsQualityRequest value: "
+ std::to_string(static_cast<int>(request)));
Log(LogName::kBa, LogLevel::kError,
"Unhandled GraphicsQualityRequest value: "
+ std::to_string(static_cast<int>(request)));
return GraphicsQuality::kLow;
}
}
@ -1702,8 +1714,9 @@ auto Graphics::TextureQualityFromRequest(TextureQualityRequest request,
case TextureQualityRequest::kAuto:
return auto_val;
default:
Log(LogLevel::kError, "Unhandled TextureQualityRequest value: "
+ std::to_string(static_cast<int>(request)));
Log(LogName::kBaGraphics, LogLevel::kError,
"Unhandled TextureQualityRequest value: "
+ std::to_string(static_cast<int>(request)));
return TextureQuality::kLow;
}
}
@ -1747,13 +1760,8 @@ void Graphics::DrawUIBounds(RenderPass* pass) {
auto xf = c.ScopedTransform();
float width, height;
if (g_base->ui->scale() == UIScale::kSmall) {
width = kBaseVirtualResSmallX;
height = kBaseVirtualResSmallY;
} else {
width = kBaseVirtualResX;
height = kBaseVirtualResY;
}
GetBaseVirtualRes(&width, &height);
// Slight offset in z to reduce z fighting.
c.Translate(0.5f * pass->virtual_width(), 0.5f * pass->virtual_height(),

View File

@ -153,6 +153,7 @@ class Graphics {
}
void DrawUIBounds(RenderPass* pass);
static void GetBaseVirtualRes(float* x, float* y);
// Enable progress bar drawing locally.
void EnableProgressBar(bool fade_in);

View File

@ -178,7 +178,7 @@ auto GraphicsServer::WaitForRenderFrameDef_() -> FrameDef* {
millisecs_t t = g_core->GetAppTimeMillisecs() - start_time;
if (t >= 1000) {
if (g_buildconfig.debug_build()) {
Log(LogLevel::kWarning,
Log(LogName::kBaGraphics, LogLevel::kWarning,
"GraphicsServer: timed out at " + std::to_string(t)
+ "ms waiting for logic thread to send us a FrameDef.");
}
@ -266,7 +266,8 @@ void GraphicsServer::ReloadLostRenderer() {
assert(g_base->app_adapter->InGraphicsContext());
if (!renderer_) {
Log(LogLevel::kError, "No renderer on GraphicsServer::ReloadLostRenderer.");
Log(LogName::kBaGraphics, LogLevel::kError,
"No renderer on GraphicsServer::ReloadLostRenderer.");
return;
}
@ -323,11 +324,12 @@ void GraphicsServer::set_renderer(Renderer* renderer) {
void GraphicsServer::LoadRenderer() {
assert(g_base->app_adapter->InGraphicsContext());
if (!renderer_) {
Log(LogLevel::kError, "LoadRenderer() called with no renderer present.");
Log(LogName::kBaGraphics, LogLevel::kError,
"LoadRenderer() called with no renderer present.");
return;
}
if (renderer_loaded_) {
Log(LogLevel::kError,
Log(LogName::kBaGraphics, LogLevel::kError,
"LoadRenderer() called with an already-loaded renderer present.");
return;
}
@ -369,11 +371,12 @@ void GraphicsServer::LoadRenderer() {
void GraphicsServer::UnloadRenderer() {
assert(g_base->app_adapter->InGraphicsContext());
if (!renderer_) {
Log(LogLevel::kError, "UnloadRenderer() called with no renderer present.");
Log(LogName::kBaGraphics, LogLevel::kError,
"UnloadRenderer() called with no renderer present.");
return;
}
if (!renderer_loaded_) {
Log(LogLevel::kError,
Log(LogName::kBaGraphics, LogLevel::kError,
"UnloadRenderer() called with an already unloaded renderer present.");
return;
}
@ -532,7 +535,7 @@ void GraphicsServer::PushRemoveRenderHoldCall() {
assert(render_hold_);
render_hold_--;
if (render_hold_ < 0) {
Log(LogLevel::kError, "RenderHold < 0");
Log(LogName::kBaGraphics, LogLevel::kError, "RenderHold < 0");
render_hold_ = 0;
}
});

View File

@ -17,7 +17,8 @@ class MeshData {
: type_(type), draw_type_(draw_type) {}
virtual ~MeshData() {
if (renderer_data_) {
Log(LogLevel::kError, "MeshData going down with rendererData intact!");
Log(LogName::kBaGraphics, LogLevel::kError,
"MeshData going down with rendererData intact!");
}
}
std::list<MeshData*>::iterator iterator_;

View File

@ -76,7 +76,7 @@ class MeshIndexedBase : public Mesh {
// For use by subclasses in their IsValid() overrides
auto IndexSizeIsValid(size_t data_size) const -> bool {
if (index_data_size() == 2 && data_size > 65535) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaGraphics, LogLevel::kError,
"Got mesh data with > 65535 elems and 16 bit indices: "
+ GetObjectDescription()
+ ". This case requires 32 bit indices.");

View File

@ -32,7 +32,7 @@ class MeshIndexedStaticDynamic : public MeshIndexedBase {
// Static and dynamic data sizes should always match, right?
if (static_data_->elements.size() != dynamic_data_->elements.size()) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaGraphics, LogLevel::kError,
"Mesh static and dynamic data sizes do not match");
return false;
}

View File

@ -13,7 +13,8 @@ NinePatchMesh::NinePatchMesh(float x, float y, float z, float width,
|| (border_bottom + border_top) > 1.0f)
|| (border_left < 0.0f || border_right < 0.0f
|| (border_left + border_right) > 1.0f)) {
BA_LOG_ONCE(LogLevel::kWarning, "Invalid nine-patch values provided.");
BA_LOG_ONCE(LogName::kBaGraphics, LogLevel::kWarning,
"Invalid nine-patch values provided.");
}
}
// Statically allocate enough for a full 9 patches even though we may

View File

@ -24,7 +24,7 @@ class RenderTarget : public Object {
void DrawBegin(bool clear,
const Vector4f& clear_color = {0.0f, 0.0f, 0.0f, 1.0f}) {
DrawBegin(clear, clear_color.x, clear_color.y, clear_color.z,
clear_color.w);
clear_color.a);
}
void OnScreenSizeChange();

View File

@ -152,7 +152,7 @@ void ScreenMessages::DrawMiscOverlays(FrameDef* frame_def) {
if (i->translation_dirty) {
BA_LOG_ONCE(
LogLevel::kWarning,
LogName::kBaGraphics, LogLevel::kWarning,
"Found dirty translation on screenmessage draw pass 1; raw="
+ i->s_raw);
}
@ -261,7 +261,7 @@ void ScreenMessages::DrawMiscOverlays(FrameDef* frame_def) {
}
if (i->translation_dirty) {
BA_LOG_ONCE(
LogLevel::kWarning,
LogName::kBaGraphics, LogLevel::kWarning,
"Found dirty translation on screenmessage draw pass 2; raw="
+ i->s_raw);
}
@ -495,7 +495,7 @@ void ScreenMessages::ClearScreenMessageTranslations() {
auto ScreenMessages::ScreenMessageEntry::GetText() -> TextGroup& {
if (translation_dirty) {
BA_LOG_ONCE(
LogLevel::kWarning,
LogName::kBaGraphics, LogLevel::kWarning,
"Found dirty translation on screenmessage GetText; raw=" + s_raw);
}
if (!s_mesh_.Exists()) {

View File

@ -349,7 +349,8 @@ TextGraphics::TextGraphics() {
if (g.tex_max_x > 1.0f || g.tex_max_x < 0.0f || g.tex_min_x > 1.0
|| g.tex_min_x < 0.0f || g.tex_max_y > 1.0f || g.tex_max_y < 0.0
|| g.tex_min_y > 1.0f || g.tex_min_y < 0.0f) {
BA_LOG_ONCE(LogLevel::kWarning, "glyph bounds error");
BA_LOG_ONCE(LogName::kBaGraphics, LogLevel::kWarning,
"glyph bounds error");
}
}
}
@ -1042,7 +1043,7 @@ void TextGraphics::GetOSTextSpanBoundsAndWidth(const std::string& s, Rect* r,
g_core->platform->GetTextBoundsAndWidth(s, &entry->r, &entry->width);
} else {
BA_LOG_ONCE(
LogLevel::kError,
LogName::kBaGraphics, LogLevel::kError,
"FIXME: GetOSTextSpanBoundsAndWidth unimplemented on this platform");
r->l = 0.0f;
r->r = 1.0f;

View File

@ -289,7 +289,7 @@ auto JoystickInput::GetButtonName(int index) -> std::string {
JoystickInput::~JoystickInput() {
if (!g_base->InLogicThread()) {
Log(LogLevel::kError, "Joystick dying in wrong thread.");
Log(LogName::kBaInput, LogLevel::kError, "Joystick dying in wrong thread.");
}
// Kill our child if need be.
@ -311,7 +311,7 @@ JoystickInput::~JoystickInput() {
[joystick] { SDL_JoystickClose(joystick); });
sdl_joystick_ = nullptr;
#else
Log(LogLevel::kError,
Log(LogName::kBaInput, LogLevel::kError,
"sdl_joystick_ set in non-sdl-joystick build destructor.");
#endif // BA_ENABLE_SDL_JOYSTICKS
}
@ -654,7 +654,7 @@ void JoystickInput::HandleSDLEvent(const SDL_Event* e) {
hat_held_ = true;
break;
default:
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaInput, LogLevel::kError,
"Invalid hat value: "
+ std::to_string(static_cast<int>(e->jhat.value)));
break;
@ -1231,7 +1231,7 @@ void JoystickInput::UpdateMapping() {
auto* cl{g_base->HaveClassic() ? g_base->classic() : nullptr};
if (!cl) {
Log(LogLevel::kWarning,
Log(LogName::kBaInput, LogLevel::kWarning,
"Classic not present; can't config joystick mapping.");
}

View File

@ -852,7 +852,7 @@ void TouchInput::UpdateMapping() {
} else if (touch_movement_type == "joystick") {
movement_control_type_ = TouchInput::MovementControlType::kJoystick;
} else {
Log(LogLevel::kError,
Log(LogName::kBaInput, LogLevel::kError,
"Invalid touch-movement-type: " + touch_movement_type);
movement_control_type_ = TouchInput::MovementControlType::kSwipe;
}
@ -863,7 +863,8 @@ void TouchInput::UpdateMapping() {
} else if (touch_action_type == "buttons") {
action_control_type_ = TouchInput::ActionControlType::kButtons;
} else {
Log(LogLevel::kError, "Invalid touch-action-type: " + touch_action_type);
Log(LogName::kBaInput, LogLevel::kError,
"Invalid touch-action-type: " + touch_action_type);
action_control_type_ = TouchInput::ActionControlType::kSwipe;
}

View File

@ -34,7 +34,7 @@ void Input::PushCreateKeyboardInputDevices() {
void Input::CreateKeyboardInputDevices_() {
assert(g_base->InLogicThread());
if (keyboard_input_ != nullptr || keyboard_input_2_ != nullptr) {
Log(LogLevel::kError,
Log(LogName::kBaInput, LogLevel::kError,
"CreateKeyboardInputDevices called with existing kbs.");
return;
}
@ -53,7 +53,7 @@ void Input::PushDestroyKeyboardInputDevices() {
void Input::DestroyKeyboardInputDevices_() {
assert(g_base->InLogicThread());
if (keyboard_input_ == nullptr || keyboard_input_2_ == nullptr) {
Log(LogLevel::kError,
Log(LogName::kBaInput, LogLevel::kError,
"DestroyKeyboardInputDevices called with null kb(s).");
return;
}
@ -558,7 +558,7 @@ void Input::StepDisplayTime() {
// If input has been locked an excessively long amount of time, unlock it.
if (input_lock_count_temp_) {
if (real_time - last_input_temp_lock_time_ > 10000) {
Log(LogLevel::kError,
Log(LogName::kBaInput, LogLevel::kError,
"Input has been temp-locked for 10 seconds; unlocking.");
input_lock_count_temp_ = 0;
PrintLockLabels_();
@ -664,7 +664,7 @@ void Input::UnlockAllInput(bool permanent, const std::string& label) {
input_lock_count_temp_--;
input_unlock_temp_labels_.push_back(label);
if (input_lock_count_temp_ < 0) {
Log(LogLevel::kWarning,
Log(LogName::kBaInput, LogLevel::kWarning,
"temp input unlock at time "
+ std::to_string(g_core->GetAppTimeMillisecs())
+ " with no active lock: '" + label + "'");
@ -719,7 +719,7 @@ void Input::PrintLockLabels_() {
s += "\n " + std::to_string(num++) + ": " + recent_input_locks_unlock;
}
Log(LogLevel::kError, s);
Log(LogName::kBaInput, LogLevel::kError, s);
}
void Input::PushTextInputEvent(const std::string& text) {
@ -757,7 +757,8 @@ void Input::PushTextInputEvent(const std::string& text) {
// platforms) but make a stink if they sent us something that we can't
// at least translate to unicode.
if (!Utils::IsValidUTF8(text)) {
Log(LogLevel::kWarning, "PushTextInputEvent passed invalid utf-8 text.");
Log(LogName::kBaInput, LogLevel::kWarning,
"PushTextInputEvent passed invalid utf-8 text.");
return;
}
@ -844,7 +845,8 @@ void Input::CaptureKeyboardInput(HandleKeyPressCall* press_call,
HandleKeyReleaseCall* release_call) {
assert(g_base->InLogicThread());
if (keyboard_input_capture_press_ || keyboard_input_capture_release_) {
Log(LogLevel::kError, "Setting key capture redundantly.");
Log(LogName::kBaInput, LogLevel::kError,
"Setting key capture redundantly.");
}
keyboard_input_capture_press_ = press_call;
keyboard_input_capture_release_ = release_call;
@ -859,7 +861,8 @@ void Input::ReleaseKeyboardInput() {
void Input::CaptureJoystickInput(HandleJoystickEventCall* call) {
assert(g_base->InLogicThread());
if (joystick_input_capture_) {
Log(LogLevel::kError, "Setting joystick capture redundantly.");
Log(LogName::kBaInput, LogLevel::kError,
"Setting joystick capture redundantly.");
}
joystick_input_capture_ = call;
}
@ -930,7 +933,7 @@ void Input::HandleKeyPress_(const SDL_Keysym& keysym) {
count++;
if (count > 10) {
BA_LOG_ONCE(
LogLevel::kWarning,
LogName::kBaInput, LogLevel::kWarning,
"Input::HandleKeyPress_ seems to be getting passed repeat key"
" press events. Only initial press events should be passed.");
}
@ -1442,7 +1445,7 @@ void Input::HandleTouchEvent_(const TouchEvent& e) {
// overall multitouch gesture, it should always be winding up as our
// single_touch_.
if (e.type == TouchEvent::Type::kDown && single_touch_ != nullptr) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaInput, LogLevel::kError,
"Got touch labeled first but will not be our single.");
}
@ -1452,7 +1455,7 @@ void Input::HandleTouchEvent_(const TouchEvent& e) {
if ((e.type == TouchEvent::Type::kUp
|| e.type == TouchEvent::Type::kCanceled)
&& single_touch_ != nullptr && single_touch_ != e.touch) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaInput, LogLevel::kError,
"Last touch coming up is not single touch!");
}
}
@ -1567,7 +1570,7 @@ void Input::LsInputDevices() {
++index;
}
Log(LogLevel::kInfo, out);
Log(LogName::kBaInput, LogLevel::kInfo, out);
}
auto Input::ShouldAllowInputInAttractMode_(InputDevice* device) const -> bool {

View File

@ -73,7 +73,7 @@ void RemoteAppServer::HandleData(int socket, uint8_t* buffer, size_t amt,
}
case BA_PACKET_REMOTE_ID_REQUEST: {
if (amt < 5 || amt > 127) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaInput, LogLevel::kError,
"Received invalid BA_PACKET_REMOTE_ID_REQUEST of length "
+ std::to_string(amt));
break;
@ -214,7 +214,8 @@ void RemoteAppServer::HandleData(int socket, uint8_t* buffer, size_t amt,
// Each state is 2 bytes. So make sure our length adds up.
if (amt != 4 + state_count * 3) {
BA_LOG_ONCE(LogLevel::kError, "Invalid state packet");
BA_LOG_ONCE(LogName::kBaInput, LogLevel::kError,
"Invalid state packet");
return;
}
RemoteAppClient* client = clients_ + joystick_id;

View File

@ -384,7 +384,7 @@ void Logic::OnAppModeChanged() {
// long sleep we're currently in the middle of.
if (g_core->HeadlessMode()) {
if (debug_log_display_time_) {
Log(LogLevel::kDebug,
Log(LogName::kBa, LogLevel::kDebug,
"Resetting headless display step timer due to app-mode change.");
}
assert(headless_display_time_step_timer_);
@ -419,7 +419,7 @@ void Logic::UpdateDisplayTimeForHeadlessMode_() {
char buffer[256];
snprintf(buffer, sizeof(buffer), "stepping display-time at app-time %.4f",
static_cast<double>(app_time_microsecs) / 1000000.0);
Log(LogLevel::kDebug, buffer);
Log(LogName::kBa, LogLevel::kDebug, buffer);
}
}
@ -441,7 +441,7 @@ void Logic::PostUpdateDisplayTimeForHeadlessMode_() {
snprintf(buffer, sizeof(buffer),
"will try to sleep for %.4f at app-time %.4f (until %.4f)",
sleepsecs, apptimesecs, apptimesecs + sleepsecs);
Log(LogLevel::kDebug, buffer);
Log(LogName::kBa, LogLevel::kDebug, buffer);
}
auto sleep_microsecs = headless_display_step_microsecs;
@ -548,7 +548,7 @@ void Logic::UpdateDisplayTimeForFrameDraw_() {
snprintf(buffer, sizeof(buffer),
"trailing_dist %.6f > trail_buffer %.6f; will offset %.6f).",
trailing_dist, trail_buffer, offs);
Log(LogLevel::kDebug, buffer);
Log(LogName::kBa, LogLevel::kDebug, buffer);
}
display_time_increment_ = display_time_increment_ + offs;
}
@ -559,7 +559,7 @@ void Logic::UpdateDisplayTimeForFrameDraw_() {
"final %.5f current(%s) %.5f sample %.5f chaos %.5f",
display_time_increment_, use_avg ? "avg" : "sample", used,
this_increment, chaos);
Log(LogLevel::kDebug, buffer);
Log(LogName::kBa, LogLevel::kDebug, buffer);
}
}
@ -660,7 +660,7 @@ void Logic::SetAppTimerLength(int timer_id, microsecs_t length) {
if (t) {
t->SetLength(length);
} else {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"Logic::SetAppTimerLength() called on nonexistent timer.");
}
}
@ -687,7 +687,7 @@ void Logic::SetDisplayTimerLength(int timer_id, microsecs_t length) {
if (t) {
t->SetLength(length);
} else {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"Logic::SetDisplayTimerLength() called on nonexistent timer.");
}
}

View File

@ -61,8 +61,9 @@ void NetworkReader::OnAppUnsuspend() {
void NetworkReader::PokeSelf_() {
int sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd < 0) {
Log(LogLevel::kError, "Unable to create sleep ping socket; errno "
+ g_core->platform->GetSocketErrorString());
Log(LogName::kBaNetworking, LogLevel::kError,
"Unable to create sleep ping socket; errno "
+ g_core->platform->GetSocketErrorString());
} else {
struct sockaddr_in serv_addr{};
memset(&serv_addr, 0, sizeof(serv_addr));
@ -71,8 +72,9 @@ void NetworkReader::PokeSelf_() {
serv_addr.sin_port = 0; // any
int bresult = ::bind(sd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if (bresult == 1) {
Log(LogLevel::kError, "Unable to bind sleep socket: "
+ g_core->platform->GetSocketErrorString());
Log(LogName::kBaNetworking, LogLevel::kError,
"Unable to bind sleep socket: "
+ g_core->platform->GetSocketErrorString());
} else {
struct sockaddr_in t_addr{};
memset(&t_addr, 0, sizeof(t_addr));
@ -83,8 +85,9 @@ void NetworkReader::PokeSelf_() {
ssize_t sresult =
sendto(sd, b, 1, 0, (struct sockaddr*)(&t_addr), sizeof(t_addr));
if (sresult == -1) {
Log(LogLevel::kError, "Error on sleep self-sendto: "
+ g_core->platform->GetSocketErrorString());
Log(LogName::kBaNetworking, LogLevel::kError,
"Error on sleep self-sendto: "
+ g_core->platform->GetSocketErrorString());
}
}
g_core->platform->CloseSocket(sd);
@ -115,7 +118,7 @@ void NetworkReader::DoPoll_(bool* can_read_4, bool* can_read_6) {
// Aint no thang.
} else {
// Let's complain for anything else though.
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Error on select: " + g_core->platform->GetSocketErrorString());
}
} else {
@ -123,7 +126,8 @@ void NetworkReader::DoPoll_(bool* can_read_4, bool* can_read_6) {
*can_read_6 = index_6 != -1 && fds[index_6].revents & POLLIN;
}
} else {
BA_LOG_ONCE(LogLevel::kError, "DoPoll called with neither sd4 or sd6 set.");
BA_LOG_ONCE(LogName::kBaNetworking, LogLevel::kError,
"DoPoll called with neither sd4 or sd6 set.");
}
}
@ -167,7 +171,7 @@ void NetworkReader::DoSelect_(bool* can_read_4, bool* can_read_6) {
// Aint no thang.
} else {
// Let's complain for anything else though.
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Error on select: " + g_core->platform->GetSocketErrorString());
}
} else {
@ -235,7 +239,7 @@ auto NetworkReader::RunThread_() -> int {
recvfrom(sd, buffer, sizeof(buffer), 0,
reinterpret_cast<sockaddr*>(&from), &from_size);
if (rresult == 0) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"NetworkReader Recv got length 0; this shouldn't "
"happen");
} else if (rresult == -1) {
@ -384,7 +388,7 @@ void NetworkReader::PushIncomingUDPPacketCall_(const std::vector<uint8_t>& data,
// these are unreliable messages so its ok to just drop them.
if (!g_base->logic->event_loop()->CheckPushSafety()) {
BA_LOG_ONCE(
LogLevel::kError,
LogName::kBaNetworking, LogLevel::kError,
"Ignoring excessive udp-connection input packets; (could this be a "
"flood attack?).");
return;
@ -413,8 +417,9 @@ void NetworkReader::OpenSockets_() {
sd4_ = socket(AF_INET, SOCK_DGRAM, 0);
if (sd4_ < 0) {
Log(LogLevel::kError, "Unable to open host socket; errno "
+ g_core->platform->GetSocketErrorString());
Log(LogName::kBaNetworking, LogLevel::kError,
"Unable to open host socket; errno "
+ g_core->platform->GetSocketErrorString());
} else {
g_core->platform->SetSocketNonBlocking(sd4_);
@ -465,8 +470,9 @@ void NetworkReader::OpenSockets_() {
// available everywhere (win XP, etc) so let's do this for now.
sd6_ = socket(AF_INET6, SOCK_DGRAM, 0);
if (sd6_ < 0) {
Log(LogLevel::kError, "Unable to open ipv6 socket: "
+ g_core->platform->GetSocketErrorString());
Log(LogName::kBaNetworking, LogLevel::kError,
"Unable to open ipv6 socket: "
+ g_core->platform->GetSocketErrorString());
} else {
// Since we're explicitly creating both a v4 and v6 socket, tell the v6
// to *not* do both itself (not sure if this is necessary; on mac it
@ -475,7 +481,8 @@ void NetworkReader::OpenSockets_() {
if (setsockopt(sd6_, IPPROTO_IPV6, IPV6_V6ONLY,
reinterpret_cast<char*>(&on), sizeof(on))
== -1) {
Log(LogLevel::kError, "Error setting socket as ipv6-only");
Log(LogName::kBaNetworking, LogLevel::kError,
"Error setting socket as ipv6-only");
}
g_core->platform->SetSocketNonBlocking(sd6_);
@ -522,9 +529,9 @@ void NetworkReader::OpenSockets_() {
+ std::to_string(initial_requested_port)
+ "; some network functionality may fail.",
{1, 0.5f, 0});
Log(LogLevel::kWarning, "Unable to bind udp port "
+ std::to_string(initial_requested_port)
+ "; some network functionality may fail.");
Log(LogName::kBaNetworking, LogLevel::kWarning,
"Unable to bind udp port " + std::to_string(initial_requested_port)
+ "; some network functionality may fail.");
}
}

View File

@ -24,7 +24,7 @@ void NetworkWriter::PushSendToCall(const std::vector<uint8_t>& msg,
// Avoid buffer-full errors if something is causing us to write too often;
// these are unreliable messages so its ok to just drop them.
if (!event_loop()->CheckPushSafety()) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaNetworking, LogLevel::kError,
"Excessive send-to calls in net-write-module.");
return;
}

View File

@ -116,7 +116,7 @@ void BasePlatformApple::LoginAdapterGetSignInToken(
if (login_type == "game_center") {
BallisticaKit::GameCenterContext::getSignInToken(attempt_id);
} else {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"Got unexpected get-sign-in-token login-type: " + login_type);
}
#else
@ -130,7 +130,7 @@ void BasePlatformApple::LoginAdapterBackEndActiveChange(
if (login_type == "game_center") {
BallisticaKit::GameCenterContext::backEndActiveChange(active);
} else {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"Got unexpected back-end-active-change login-type: " + login_type);
}
#else

View File

@ -104,12 +104,12 @@ void BasePlatform::DoPurchase(const std::string& item) {
}
void BasePlatform::RestorePurchases() {
Log(LogLevel::kError, "RestorePurchases() unimplemented");
Log(LogName::kBa, LogLevel::kError, "RestorePurchases() unimplemented");
}
void BasePlatform::PurchaseAck(const std::string& purchase,
const std::string& order_id) {
Log(LogLevel::kError, "PurchaseAck() unimplemented");
Log(LogName::kBa, LogLevel::kError, "PurchaseAck() unimplemented");
}
void BasePlatform::OpenURL(const std::string& url) {
@ -134,7 +134,7 @@ void BasePlatform::OverlayWebBrowserOpenURL(const std::string& url) {
std::scoped_lock lock(web_overlay_mutex_);
if (web_overlay_open_) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"OverlayWebBrowserOnClose called with already existing overlay.");
return;
}
@ -155,7 +155,7 @@ auto BasePlatform::OverlayWebBrowserIsOpen() -> bool {
void BasePlatform::OverlayWebBrowserOnClose() {
std::scoped_lock lock(web_overlay_mutex_);
if (!web_overlay_open_) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"OverlayWebBrowserOnClose called with no known overlay.");
}
web_overlay_open_ = false;
@ -174,12 +174,13 @@ void BasePlatform::OverlayWebBrowserClose() {
}
void BasePlatform::DoOverlayWebBrowserOpenURL(const std::string& url) {
Log(LogLevel::kError, "DoOpenURLInOverlayBrowser unimplemented");
Log(LogName::kBa, LogLevel::kError,
"DoOpenURLInOverlayBrowser unimplemented");
}
void BasePlatform::DoOverlayWebBrowserClose() {
// As a default, use Python's webbrowser module functionality.
Log(LogLevel::kError, "DoOverlayWebBrowserClose unimplemented");
Log(LogName::kBa, LogLevel::kError, "DoOverlayWebBrowserClose unimplemented");
}
#if !BA_OSTYPE_WINDOWS
@ -188,7 +189,7 @@ static void HandleSIGINT(int s) {
g_base->logic->event_loop()->PushCall(
[] { g_base->logic->HandleInterruptSignal(); });
} else {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"SigInt handler called before g_base->logic->event_loop exists.");
}
}
@ -197,7 +198,7 @@ static void HandleSIGTERM(int s) {
g_base->logic->event_loop()->PushCall(
[] { g_base->logic->HandleTerminateSignal(); });
} else {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"SigInt handler called before g_base->logic->event_loop exists.");
}
}
@ -276,17 +277,18 @@ void BasePlatform::StringEditorCancel() {
void BasePlatform::DoInvokeStringEditor(const std::string& title,
const std::string& value,
std::optional<int> max_chars) {
Log(LogLevel::kError, "FIXME: DoInvokeStringEditor() unimplemented");
Log(LogName::kBa, LogLevel::kError,
"FIXME: DoInvokeStringEditor() unimplemented");
}
auto BasePlatform::SupportsOpenDirExternally() -> bool { return false; }
void BasePlatform::OpenDirExternally(const std::string& path) {
Log(LogLevel::kError, "OpenDirExternally() unimplemented");
Log(LogName::kBa, LogLevel::kError, "OpenDirExternally() unimplemented");
}
void BasePlatform::OpenFileExternally(const std::string& path) {
Log(LogLevel::kError, "OpenFileExternally() unimplemented");
Log(LogName::kBa, LogLevel::kError, "OpenFileExternally() unimplemented");
}
auto BasePlatform::SafeStdinFGetS(char* s, int n, FILE* iop) -> char* {

View File

@ -23,8 +23,9 @@ void BasePlatformLinux::OpenDirExternally(const std::string& path) {
std::string cmd = std::string("xdg-open \"") + path + "\"";
int result = system(cmd.c_str());
if (result != 0) {
Log(LogLevel::kError, "Got return value " + std::to_string(result)
+ " on xdg-open cmd '" + cmd + "'");
Log(LogName::kBa, LogLevel::kError,
"Got return value " + std::to_string(result) + " on xdg-open cmd '"
+ cmd + "'");
}
}
@ -32,8 +33,9 @@ void BasePlatformLinux::OpenFileExternally(const std::string& path) {
std::string cmd = std::string("xdg-open \"") + path + "\"";
int result = system(cmd.c_str());
if (result != 0) {
Log(LogLevel::kError, "Got return value " + std::to_string(result)
+ " on xdg-open cmd '" + cmd + "'");
Log(LogName::kBa, LogLevel::kError,
"Got return value " + std::to_string(result) + " on xdg-open cmd '"
+ cmd + "'");
}
}

View File

@ -348,7 +348,7 @@ static const char* GetScancodeName(SDL_Scancode scancode) {
const char* name;
if (static_cast<int>(scancode) < SDL_SCANCODE_UNKNOWN
|| scancode >= SDL_NUM_SCANCODES) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaInput, LogLevel::kError,
"GetScancodeName passed invalid scancode "
+ std::to_string(static_cast<int>(scancode)));
return "";

View File

@ -36,7 +36,7 @@ void BasePlatformWindows::DoOpenURL(const std::string& url) {
// This should return > 32 on success.
if (r <= 32) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"Error " + std::to_string(r) + " opening URL '" + url + "'");
}
}
@ -49,7 +49,8 @@ BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) {
g_base->logic->event_loop()->PushCall(
[] { g_base->logic->HandleInterruptSignal(); });
} else {
Log(LogLevel::kError, "SigInt handler called before g_logic exists.");
Log(LogName::kBa, LogLevel::kError,
"SigInt handler called before g_logic exists.");
}
return TRUE;
@ -61,7 +62,7 @@ BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) {
void BasePlatformWindows::SetupInterruptHandling() {
// Set up Ctrl-C handling.
if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
Log(LogLevel::kError, "Error on SetConsoleCtrlHandler()");
Log(LogName::kBa, LogLevel::kError, "Error on SetConsoleCtrlHandler()");
}
}
@ -73,8 +74,9 @@ void BasePlatformWindows::OpenDirExternally(const std::string& path) {
core::CorePlatformWindows::UTF8Decode(path).c_str(), nullptr,
SW_SHOWNORMAL));
if (r <= 32) {
Log(LogLevel::kError, "Error " + std::to_string(r)
+ " on open_dir_externally for '" + path + "'");
Log(LogName::kBa, LogLevel::kError,
"Error " + std::to_string(r) + " on open_dir_externally for '" + path
+ "'");
}
}
@ -84,8 +86,9 @@ void BasePlatformWindows::OpenFileExternally(const std::string& path) {
core::CorePlatformWindows::UTF8Decode(path).c_str(), nullptr,
SW_SHOWNORMAL));
if (r <= 32) {
Log(LogLevel::kError, "Error " + std::to_string(r)
+ " on open_file_externally for '" + path + "'");
Log(LogName::kBa, LogLevel::kError,
"Error " + std::to_string(r) + " on open_file_externally for '" + path
+ "'");
}
}

View File

@ -106,27 +106,8 @@ void BasePython::SoftImportClassic() {
}
}
// void BasePython::SoftImportUIV1() {
// // To keep our init order clean, we want to root out any attempted uses
// // of this before _babase/babase has been fully imported.
// assert(g_base);
// assert(g_base->IsBaseCompletelyImported());
// auto gil{Python::ScopedInterpreterLock()};
// auto result = PythonRef::StolenSoft(PyImport_ImportModule("_bauiv1"));
// if (!result.Exists()) {
// // Ignore any errors here for now. All that will matter is whether plus
// // gave us its interface.
// PyErr_Clear();
// }
// }
void BasePython::ReadConfig() {
auto gil{Python::ScopedInterpreterLock()};
// Read the config file and store the config dict for easy access.
objs().Get(ObjID::kAppReadConfigCall).Call();
objs_.Store(ObjID::kConfig, *objs().Get(ObjID::kApp).GetAttr("config"));
assert(PyDict_Check(*objs().Get(ObjID::kConfig)));
void BasePython::SetConfig(PyObject* config) {
objs_.Store(ObjID::kConfig, config);
}
void BasePython::Reset() {
@ -360,7 +341,7 @@ auto BasePython::GetRawConfigValue(const char* name, float default_value)
try {
return Python::GetPyFloat(value);
} catch (const std::exception&) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"expected a float for config value '" + std::string(name) + "'");
return default_value;
}
@ -382,7 +363,7 @@ auto BasePython::GetRawConfigValue(const char* name,
}
return Python::GetPyFloat(value);
} catch (const std::exception&) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"expected a float for config value '" + std::string(name) + "'");
return default_value;
}
@ -399,7 +380,7 @@ auto BasePython::GetRawConfigValue(const char* name, int default_value) -> int {
try {
return static_cast_check_fit<int>(Python::GetPyInt64(value));
} catch (const std::exception&) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"Expected an int value for config value '" + std::string(name) + "'.");
return default_value;
}
@ -417,7 +398,7 @@ auto BasePython::GetRawConfigValue(const char* name, bool default_value)
try {
return Python::GetPyBool(value);
} catch (const std::exception&) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"Expected a bool value for config value '" + std::string(name) + "'.");
return default_value;
}
@ -525,7 +506,7 @@ auto BasePython::GetResource(const char* key, const char* fallback_resource,
try {
return g_base->python->GetPyLString(results.Get());
} catch (const std::exception&) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"GetResource failed for '" + std::string(key) + "'");
// Hmm; I guess let's just return the key to help identify/fix the
@ -533,7 +514,8 @@ auto BasePython::GetResource(const char* key, const char* fallback_resource,
return std::string("<res-err: ") + key + ">";
}
} else {
Log(LogLevel::kError, "GetResource failed for '" + std::string(key) + "'");
Log(LogName::kBa, LogLevel::kError,
"GetResource failed for '" + std::string(key) + "'");
}
// Hmm; I guess let's just return the key to help identify/fix the issue?..
@ -553,12 +535,12 @@ auto BasePython::GetTranslation(const char* category, const char* s)
try {
return g_base->python->GetPyLString(results.Get());
} catch (const std::exception&) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"GetTranslation failed for '" + std::string(category) + "'");
return "";
}
} else {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"GetTranslation failed for category '" + std::string(category) + "'");
}
return "";
@ -574,7 +556,7 @@ void BasePython::RunDeepLink(const std::string& url) {
.Get(base::BasePython::ObjID::kAppHandleDeepLinkCall)
.Call(args);
} else {
Log(LogLevel::kError, "Error on deep-link call");
Log(LogName::kBa, LogLevel::kError, "Error on deep-link call");
}
}
@ -595,7 +577,8 @@ auto BasePython::CanPyStringEditAdapterBeReplaced(PyObject* o) -> bool {
.Get(BasePython::ObjID::kStringEditAdapterCanBeReplacedCall)
.Call(args);
if (!result.Exists()) {
Log(LogLevel::kError, "Error getting StringEdit valid state.");
Log(LogName::kBa, LogLevel::kError,
"Error getting StringEdit valid state.");
return false;
}
if (result.Get() == Py_True) {
@ -604,7 +587,8 @@ auto BasePython::CanPyStringEditAdapterBeReplaced(PyObject* o) -> bool {
if (result.Get() == Py_False) {
return false;
}
Log(LogLevel::kError, "Got unexpected value for StringEdit valid.");
Log(LogName::kBa, LogLevel::kError,
"Got unexpected value for StringEdit valid.");
return false;
}

View File

@ -75,7 +75,6 @@ class BasePython {
kEmptyCall,
kPrintTraceCall,
kToggleFullscreenCall,
kAppReadConfigCall,
kUIRemotePressCall,
kRemoveInGameAdsMessageCall,
kAppOnNativeStartCall,
@ -124,7 +123,8 @@ class BasePython {
void AddPythonClasses(PyObject* module);
void ImportPythonObjs();
void ImportPythonAppObjs();
void ReadConfig();
void SetConfig(PyObject* config);
// void ReadConfig();
const auto& objs() { return objs_; }

View File

@ -275,7 +275,7 @@ static auto PyPushCall(PyObject* self, PyObject* args, PyObject* keywds)
// Warn the user not to use this from the logic thread since it doesnt
// save/restore context.
if (!suppress_warning && g_base->InLogicThread()) {
Log(LogLevel::kWarning,
Log(LogName::kBa, LogLevel::kWarning,
"babase.pushcall() called from the logic thread with "
"from_other_thread set to true (call "
+ Python::ObjToString(call_obj) + " at "
@ -802,13 +802,15 @@ static PyMethodDef PyEnvDef = {
static auto PyEmitLog(PyObject* self, PyObject* args, PyObject* keywds)
-> PyObject* {
BA_PYTHON_TRY;
static const char* kwlist[] = {"name", "level", "message", nullptr};
static const char* kwlist[] = {"name", "level", "timestamp", "message",
nullptr};
const char* name;
const char* levelstr;
const char* message;
if (!PyArg_ParseTupleAndKeywords(args, keywds, "sss",
double timestamp;
if (!PyArg_ParseTupleAndKeywords(args, keywds, "ssds",
const_cast<char**>(kwlist), &name, &levelstr,
&message)) {
&timestamp, &message)) {
return nullptr;
}
@ -829,7 +831,7 @@ static auto PyEmitLog(PyObject* self, PyObject* args, PyObject* keywds)
fprintf(stderr, "Invalid log level to emit_log(): %s\n", levelstr);
level = LogLevel::kInfo;
}
Logging::EmitLog(name, level, message);
Logging::EmitLog(name, level, timestamp, message);
Py_RETURN_NONE;
BA_PYTHON_CATCH;
@ -840,7 +842,8 @@ static PyMethodDef PyEmitLogDef = {
(PyCFunction)PyEmitLog, // method
METH_VARARGS | METH_KEYWORDS, // flags
"emit_log(name: str, level: str, message: str) -> None\n"
"emit_log(name: str, level: str, timestamp: float, message: str)"
" -> None\n"
"\n"
"(internal)\n"
"\n"

View File

@ -190,7 +190,7 @@ static auto PyScreenMessage(PyObject* self, PyObject* args, PyObject* keywds)
color = BasePython::GetPyVector3f(color_obj);
}
if (log) {
Log(LogLevel::kInfo, message_str);
Log(LogName::kBa, LogLevel::kInfo, message_str);
}
// This version simply displays it locally.

View File

@ -110,7 +110,7 @@ static auto PySetUIScale(PyObject* self, PyObject* args, PyObject* keywds)
const char* scalestr;
static const char* kwlist[] = {"scale", nullptr};
PyObject* input_device_id_obj = Py_None;
// PyObject* input_device_id_obj = Py_None;
if (!PyArg_ParseTupleAndKeywords(args, keywds, "s",
const_cast<char**>(kwlist), &scalestr)) {
return nullptr;
@ -328,7 +328,8 @@ static auto PySetUpSigInt(PyObject* self) -> PyObject* {
if (g_base) {
g_base->platform->SetupInterruptHandling();
} else {
Log(LogLevel::kError, "setup_sigint called before g_base exists.");
Log(LogName::kBa, LogLevel::kError,
"setup_sigint called before g_base exists.");
}
Py_RETURN_NONE;
BA_PYTHON_CATCH;
@ -1578,13 +1579,14 @@ static auto PyDevConsoleAddButton(PyObject* self, PyObject* args) -> PyObject* {
float label_scale;
float corner_radius;
const char* style;
if (!PyArg_ParseTuple(args, "sffffOsffs", &label, &x, &y, &width, &height,
&call, &h_anchor, &label_scale, &corner_radius,
&style)) {
int disabled;
if (!PyArg_ParseTuple(args, "sffffOsffsp", &label, &x, &y, &width, &height,
&call, &h_anchor, &label_scale, &corner_radius, &style,
&disabled)) {
return nullptr;
}
dev_console->AddButton(label, x, y, width, height, call, h_anchor,
label_scale, corner_radius, style);
label_scale, corner_radius, style, disabled);
Py_RETURN_NONE;
BA_PYTHON_CATCH;
}
@ -1605,6 +1607,7 @@ static PyMethodDef PyDevConsoleAddButtonDef = {
" label_scale: float,\n"
" corner_radius: float,\n"
" style: str,\n"
" disabled: bool,\n"
") -> None\n"
"\n"
"(internal)",
@ -1970,6 +1973,26 @@ static PyMethodDef PyGetDrawUIBoundsDef = {
"(internal)",
};
// -------------------------- get_initial_app_config ---------------------------
static auto PyGetInitialAppConfig(PyObject* self) -> PyObject* {
BA_PYTHON_TRY;
return g_core->HandOverInitialAppConfig();
BA_PYTHON_CATCH;
}
static PyMethodDef PyGetInitialAppConfigDef = {
"get_initial_app_config", // name
(PyCFunction)PyGetInitialAppConfig, // method
METH_NOARGS, // flags
"get_initial_app_config() -> dict\n"
"\n"
"(internal)",
};
// --------------------------- set_draw_ui_bounds -----------------------------
static auto PySetDrawUIBounds(PyObject* self, PyObject* args, PyObject* keywds)
@ -2020,6 +2043,53 @@ static PyMethodDef PyPushBackPressDef = {
"(internal)",
};
// ---------------------------- set_app_config ---------------------------------
static auto PySetAppConfig(PyObject* self, PyObject* args) -> PyObject* {
BA_PYTHON_TRY;
PyObject* config_obj;
if (!PyArg_ParseTuple(args, "O", &config_obj)) {
return nullptr;
}
BA_PRECONDITION(PyDict_Check(config_obj));
g_base->python->SetConfig(config_obj);
Py_RETURN_NONE;
BA_PYTHON_CATCH;
}
static PyMethodDef PySetAppConfigDef = {
"set_app_config", // name
PySetAppConfig, // method
METH_VARARGS, // flags
"set_app_config(config: dict) -> None\n"
"\n"
"(internal)",
};
// --------------------- update_internal_logger_levels -------------------------
static auto PyUpdateInternalLoggerLevels(PyObject* self) -> PyObject* {
BA_PYTHON_TRY;
g_core->UpdateInternalLoggerLevels();
Py_RETURN_NONE;
BA_PYTHON_CATCH;
}
static PyMethodDef PyUpdateInternalLoggerLevelsDef = {
"update_internal_logger_levels", // name
(PyCFunction)PyUpdateInternalLoggerLevels, // method
METH_NOARGS, // flags
"update_internal_logger_levels() -> None\n"
"\n"
"Update the native layer to re-cache Python logger levels.\n"
"\n"
"The native layer caches logger levels so it can efficiently\n"
"avoid making Python log calls for disabled logger levels. If any\n"
"logger levels are changed at runtime, call this method after to\n"
"instruct the native layer to regenerate its cache so the change\n"
"is properly reflected in logs originating from the native layer."};
// -----------------------------------------------------------------------------
auto PythonMoethodsBase3::GetMethods() -> std::vector<PyMethodDef> {
@ -2095,6 +2165,9 @@ auto PythonMoethodsBase3::GetMethods() -> std::vector<PyMethodDef> {
PyPushBackPressDef,
PyGetDrawUIBoundsDef,
PySetDrawUIBoundsDef,
PyGetInitialAppConfigDef,
PySetAppConfigDef,
PyUpdateInternalLoggerLevelsDef,
};
}

View File

@ -24,12 +24,14 @@
#include "ballistica/base/ui/ui.h"
#include "ballistica/shared/foundation/event_loop.h"
#include "ballistica/shared/generic/utils.h"
#include "ballistica/shared/math/vector4f.h"
#include "ballistica/shared/python/python_command.h"
namespace ballistica::base {
// How much of the screen the console covers when it is at full size.
const float kDevConsoleSize{0.9f};
const float kDevConsoleFullSizeCoverage{0.9f};
const float kDevConsoleMiniSize{100.0f};
const int kDevConsoleLineLimit{80};
const int kDevConsoleStringBreakUpSize{1950};
const float kDevConsoleTabButtonCornerRadius{16.0f};
@ -99,32 +101,32 @@ static auto IsValidHungryChar_(uint32_t this_char) -> bool {
|| (this_char >= 48 && this_char <= 57) || this_char == '_');
}
static void DrawRect(RenderPass* pass, Mesh* mesh, float bottom, float x,
float y, float width, float height,
const Vector3f& bgcolor) {
static void DrawRect(RenderPass* pass, Mesh* mesh, float x, float y,
float width, float height, const Vector3f& bgcolor,
float alpha = 1.0f) {
SimpleComponent c(pass);
c.SetTransparent(true);
c.SetColor(bgcolor.x, bgcolor.y, bgcolor.z, 1.0f);
c.SetColor(bgcolor.x, bgcolor.y, bgcolor.z, alpha);
c.SetTexture(g_base->assets->SysTexture(SysTextureID::kCircle));
// Draw mesh bg.
if (mesh) {
auto xf = c.ScopedTransform();
c.Translate(x, y + bottom, kDevConsoleZDepth);
c.Translate(x, y, kDevConsoleZDepth);
c.DrawMesh(mesh);
}
}
static void DrawText(RenderPass* pass, TextGroup* tgrp, float tscale,
float bottom, float x, float y, const Vector3f& fgcolor) {
static void DrawText(RenderPass* pass, TextGroup* tgrp, float tscale, float x,
float y, const Vector3f& fgcolor, float alpha = 1.0f) {
SimpleComponent c(pass);
c.SetTransparent(true);
// Draw text.
{
auto xf = c.ScopedTransform();
c.Translate(x, y + bottom, kDevConsoleZDepth);
c.Translate(x, y, kDevConsoleZDepth);
c.Scale(tscale, tscale, 1.0f);
int elem_count = tgrp->GetElementCount();
c.SetColor(fgcolor.x, fgcolor.y, fgcolor.z, 1.0f);
c.SetColor(fgcolor.x, fgcolor.y, fgcolor.z, alpha);
c.SetFlatness(1.0f);
for (int e = 0; e < elem_count; e++) {
c.SetTexture(tgrp->GetElementTexture(e));
@ -186,7 +188,8 @@ class DevConsole::Text_ : public DevConsole::Widget_ {
void Draw(RenderPass* pass, float bottom) override {
auto fgcolor = Vector3f{0.8f, 0.7f, 0.8f};
DrawText(pass, &text_group, scale, bottom, x + XOffs(h_attach), y, fgcolor);
DrawText(pass, &text_group, scale, x + XOffs(h_attach), bottom + y,
fgcolor);
}
};
@ -203,11 +206,12 @@ class DevConsole::Button_ : public DevConsole::Widget_ {
TextGroup text_group;
float text_scale;
DevButtonStyle_ style;
bool disabled;
template <typename F>
Button_(const std::string& label, float text_scale, DevConsoleHAnchor_ attach,
float x, float y, float width, float height, float corner_radius,
DevButtonStyle_ style, const F& lambda)
DevButtonStyle_ style, bool disabled, const F& lambda)
: attach{attach},
x{x},
y{y},
@ -216,6 +220,7 @@ class DevConsole::Button_ : public DevConsole::Widget_ {
call{NewLambdaRunnable(lambda)},
text_scale{text_scale},
style{style},
disabled{disabled},
mesh(0.0f, 0.0f, 0.0f, width, height,
NinePatchMesh::BorderForRadius(corner_radius, width, height),
NinePatchMesh::BorderForRadius(corner_radius, height, width),
@ -232,7 +237,9 @@ class DevConsole::Button_ : public DevConsole::Widget_ {
auto HandleMouseDown(float mx, float my) -> bool override {
if (InUs(mx, my)) {
pressed = true;
if (!disabled) {
pressed = true;
}
return true;
}
return false;
@ -266,9 +273,11 @@ class DevConsole::Button_ : public DevConsole::Widget_ {
bgcolor =
pressed ? Vector3f{0.8f, 0.7f, 0.8f} : Vector3f{0.25, 0.2f, 0.3f};
}
DrawRect(pass, &mesh, bottom, x + XOffs(attach), y, width, height, bgcolor);
DrawText(pass, &text_group, text_scale, bottom,
x + XOffs(attach) + width * 0.5f, y + height * 0.5f, fgcolor);
float alpha = disabled ? 0.3f : 1.0f;
DrawRect(pass, &mesh, x + XOffs(attach), bottom + y, width, height, bgcolor,
alpha);
DrawText(pass, &text_group, text_scale, x + XOffs(attach) + width * 0.5f,
bottom + y + height * 0.5f, fgcolor, alpha);
}
};
@ -336,12 +345,12 @@ class DevConsole::ToggleButton_ : public DevConsole::Widget_ {
}
void Draw(RenderPass* pass, float bottom) override {
DrawRect(pass, &mesh, bottom, x + XOffs(attach), y, width, height,
DrawRect(pass, &mesh, x + XOffs(attach), bottom + y, width, height,
pressed ? Vector3f{0.5f, 0.2f, 1.0f}
: on ? Vector3f{0.5f, 0.4f, 0.6f}
: Vector3f{0.25, 0.2f, 0.3f});
DrawText(pass, &text_group, text_scale, bottom,
x + XOffs(attach) + width * 0.5f, y + height * 0.5f,
DrawText(pass, &text_group, text_scale, x + XOffs(attach) + width * 0.5f,
bottom + y + height * 0.5f,
pressed ? Vector3f{1.0f, 1.0f, 1.0f}
: on ? Vector3f{1.0f, 1.0f, 1.0f}
: Vector3f{0.8f, 0.7f, 0.8f});
@ -417,12 +426,12 @@ class DevConsole::TabButton_ : public DevConsole::Widget_ {
}
void Draw(RenderPass* pass, float bottom) override {
DrawRect(pass, &mesh, bottom, x + XOffs(attach), y, width, height,
DrawRect(pass, &mesh, x + XOffs(attach), bottom + y, width, height,
pressed ? Vector3f{0.4f, 0.2f, 0.8f}
: selected ? Vector3f{0.4f, 0.3f, 0.4f}
: Vector3f{0.25, 0.2f, 0.3f});
DrawText(pass, &text_group, text_scale, bottom,
x + XOffs(attach) + width * 0.5f, y + height * 0.5f,
DrawText(pass, &text_group, text_scale, x + XOffs(attach) + width * 0.5f,
bottom + y + height * 0.5f,
pressed ? Vector3f{1.0f, 1.0f, 1.0f}
: selected ? Vector3f{1.0f, 1.0f, 1.0f}
: Vector3f{0.6f, 0.5f, 0.6f});
@ -431,10 +440,16 @@ class DevConsole::TabButton_ : public DevConsole::Widget_ {
class DevConsole::OutputLine_ {
public:
OutputLine_(std::string s_in, double c)
: creation_time(c), s(std::move(s_in)) {}
double creation_time;
OutputLine_(std::string s_in, double creation_time, float scale,
Vector4f color)
: creation_time(creation_time),
s(std::move(s_in)),
scale(scale),
color(color) {}
std::string s;
double creation_time;
float scale;
Vector4f color;
auto GetText() -> TextGroup& {
if (!s_mesh_.Exists()) {
s_mesh_ = Object::New<TextGroup>();
@ -555,7 +570,8 @@ void DevConsole::AddText(const char* text, float x, float y,
void DevConsole::AddButton(const char* label, float x, float y, float width,
float height, PyObject* call,
const char* h_anchor_str, float label_scale,
float corner_radius, const char* style_str) {
float corner_radius, const char* style_str,
bool disabled) {
assert(g_base->InLogicThread());
auto style = DevButtonStyleFromStr_(style_str);
@ -563,7 +579,7 @@ void DevConsole::AddButton(const char* label, float x, float y, float width,
widgets_.emplace_back(std::make_unique<Button_>(
label, label_scale, h_anchor, x, y, width, height, corner_radius, style,
[this, callref = PythonRef::Acquired(call)] {
disabled, [this, callref = PythonRef::Acquired(call)] {
if (callref.Get() != Py_None) {
callref.Call();
}
@ -574,7 +590,7 @@ void DevConsole::AddPythonTerminal() {
float bs = BaseScale();
widgets_.emplace_back(std::make_unique<Button_>(
"Exec", 0.5f * bs, DevConsoleHAnchor_::kRight, -33.0f * bs, 15.95f * bs,
32.0f * bs, 13.0f * bs, 2.0 * bs, DevButtonStyle_::kNormal,
32.0f * bs, 13.0f * bs, 2.0 * bs, DevButtonStyle_::kNormal, false,
[this] { Exec(); }));
python_terminal_visible_ = true;
}
@ -632,7 +648,11 @@ auto DevConsole::Width() -> float {
}
auto DevConsole::Height() -> float {
return g_base->graphics->screen_virtual_height() - Bottom_();
if (state_ == State_::kMini) {
return kDevConsoleMiniSize;
}
return g_base->graphics->screen_virtual_height()
* kDevConsoleFullSizeCoverage;
}
void DevConsole::HandleMouseUp(int button, float x, float y) {
@ -678,7 +698,7 @@ void DevConsole::InvokeStringEditor_() {
.Get(BasePython::ObjID::kDevConsoleStringEditAdapterClass)
.Call();
if (!result.Exists()) {
Log(LogLevel::kError, "Error invoking string edit dialog.");
Log(LogName::kBa, LogLevel::kError, "Error invoking string edit dialog.");
return;
}
@ -1037,12 +1057,11 @@ auto DevConsole::HandleKeyRelease(const SDL_Keysym* keysym) -> bool {
void DevConsole::Exec() {
BA_PRECONDITION(g_base->InLogicThread());
if (!input_enabled_) {
Log(LogLevel::kWarning, "Console input is not allowed yet.");
Log(LogName::kBa, LogLevel::kWarning, "Console input is not allowed yet.");
return;
}
input_history_position_ = 0;
if (input_string_ == "clear") {
last_line_.clear();
output_lines_.clear();
} else {
SubmitPythonCommand_(input_string_);
@ -1077,7 +1096,7 @@ void DevConsole::SubmitPythonCommand_(const std::string& command) {
if (cmd.CanEval()) {
auto obj = cmd.Eval(true, nullptr, nullptr);
if (obj.Exists() && obj.Get() != Py_None) {
Print(obj.Repr() + "\n");
Print(obj.Repr(), 1.0f, kVector4f1);
}
} else {
// Not eval-able; just exec it.
@ -1129,23 +1148,21 @@ void DevConsole::ToggleState() {
transition_start_ = g_base->logic->display_time();
}
void DevConsole::Print(const std::string& s_in) {
void DevConsole::Print(const std::string& s_in, float scale, Vector4f color) {
assert(g_base->InLogicThread());
std::string s = Utils::GetValidUTF8(s_in.c_str(), "cspr");
last_line_ += s;
std::vector<std::string> broken_up;
g_base->text_graphics->BreakUpString(
last_line_.c_str(), kDevConsoleStringBreakUpSize, &broken_up);
s.c_str(), kDevConsoleStringBreakUpSize / scale, &broken_up);
// Spit out all completed lines and keep the last one as lastline.
for (size_t i = 0; i < broken_up.size() - 1; i++) {
output_lines_.emplace_back(broken_up[i], g_base->logic->display_time());
// Spit out all lines.
for (size_t i = 0; i < broken_up.size(); i++) {
output_lines_.emplace_back(broken_up[i], g_base->logic->display_time(),
scale, color);
if (output_lines_.size() > kDevConsoleLineLimit) {
output_lines_.pop_front();
}
}
last_line_ = broken_up[broken_up.size() - 1];
last_line_mesh_dirty_ = true;
}
auto DevConsole::Bottom_() const -> float {
@ -1160,30 +1177,29 @@ auto DevConsole::Bottom_() const -> float {
// dev-consoles are not meant to be especially pretty and I think it is
// more important for them to be able to be written to a known hard-coded
// mini-size.
float mini_size = 100.0f;
//
// Now that we have tabs and drop-shadows hanging down, we have to
// overshoot the top of the screen when transitioning out.
float top_buffer = 100.0f;
if (state_ == State_::kMini) {
bottom = vh - mini_size;
bottom = vh - kDevConsoleMiniSize;
} else {
bottom = vh - vh * kDevConsoleSize;
bottom = vh * (1.0f - kDevConsoleFullSizeCoverage);
}
if (g_base->logic->display_time() - transition_start_ < kTransitionSeconds) {
float from_height;
if (state_prev_ == State_::kMini) {
from_height = vh - mini_size;
from_height = vh - kDevConsoleMiniSize;
} else if (state_prev_ == State_::kFull) {
from_height = vh - vh * kDevConsoleSize;
from_height = vh - vh * kDevConsoleFullSizeCoverage;
} else {
from_height = vh + top_buffer;
}
float to_height;
if (state_ == State_::kMini) {
to_height = vh - mini_size;
to_height = vh - kDevConsoleMiniSize;
} else if (state_ == State_::kFull) {
to_height = vh - vh * kDevConsoleSize;
to_height = vh - vh * kDevConsoleFullSizeCoverage;
} else {
to_height = vh + top_buffer;
}
@ -1205,6 +1221,31 @@ void DevConsole::Draw(FrameDef* frame_def) {
return;
}
// If the virtual screen size has changed, refresh.
auto screen_virtual_width{g_base->graphics->screen_virtual_width()};
auto screen_virtual_height{g_base->graphics->screen_virtual_height()};
if (last_virtual_res_x_ < 0.0f) {
// First time through, just grab current value; don't refresh.
last_virtual_res_x_ = screen_virtual_width;
last_virtual_res_y_ = screen_virtual_height;
} else {
// Otherwise if virtual res changed and its been long enough, refresh.
auto display_time{g_base->logic->display_time()};
double update_interval{0.2};
if (display_time > last_virtual_res_change_time_ + update_interval
&& (last_virtual_res_x_ != screen_virtual_width
|| last_virtual_res_y_ != screen_virtual_height)) {
last_virtual_res_x_ = screen_virtual_width;
last_virtual_res_y_ = screen_virtual_height;
last_virtual_res_change_time_ = display_time;
g_base->logic->event_loop()->PushCall([this] {
RefreshTabButtons_();
RefreshTabContents_();
});
}
}
float bottom = Bottom_();
float border_height{3.0f};
@ -1355,7 +1396,6 @@ void DevConsole::Draw(FrameDef* frame_def) {
{
SimpleComponent c(pass);
c.SetTransparent(true);
c.SetColor(1, 1, 1, 1);
c.SetFlatness(1.0f);
float draw_scale = 0.64f;
float v_inc = 18.0f;
@ -1363,38 +1403,19 @@ void DevConsole::Draw(FrameDef* frame_def) {
* (g_base->graphics->screen_virtual_width()
- (kDevConsoleStringBreakUpSize * draw_scale));
float v = bottom + 32.0f * bs;
if (!last_line_.empty()) {
if (last_line_mesh_dirty_) {
if (!last_line_mesh_group_.Exists()) {
last_line_mesh_group_ = Object::New<TextGroup>();
}
last_line_mesh_group_->SetText(last_line_);
last_line_mesh_dirty_ = false;
}
int elem_count = last_line_mesh_group_->GetElementCount();
for (int e = 0; e < elem_count; e++) {
c.SetTexture(last_line_mesh_group_->GetElementTexture(e));
{
auto xf = c.ScopedTransform();
c.Translate(h, v + 2, kDevConsoleZDepth);
c.Scale(draw_scale, draw_scale);
c.DrawMesh(last_line_mesh_group_->GetElementMesh(e));
}
}
v += v_inc;
}
for (auto i = output_lines_.rbegin(); i != output_lines_.rend(); i++) {
int elem_count = i->GetText().GetElementCount();
for (int e = 0; e < elem_count; e++) {
c.SetColor(i->color.x, i->color.y, i->color.z, i->color.a);
c.SetTexture(i->GetText().GetElementTexture(e));
{
auto xf = c.ScopedTransform();
c.Translate(h, v + 2, kDevConsoleZDepth);
c.Scale(draw_scale, draw_scale);
c.Scale(draw_scale * i->scale, draw_scale * i->scale);
c.DrawMesh(i->GetText().GetElementMesh(e));
}
}
v += v_inc;
v += v_inc * i->scale;
if (v > pass->virtual_height() + v_inc) {
break;
}

View File

@ -10,6 +10,7 @@
#include "ballistica/base/graphics/mesh/image_mesh.h"
#include "ballistica/base/graphics/text/text_group.h"
#include "ballistica/shared/foundation/object.h"
#include "ballistica/shared/math/vector4f.h"
#include "ballistica/shared/python/python_ref.h"
namespace ballistica::base {
@ -36,7 +37,7 @@ class DevConsole {
auto PasteFromClipboard() -> bool;
/// Print text to the console.
void Print(const std::string& s_in);
void Print(const std::string& s_in, float scale, Vector4f color);
void Draw(FrameDef* frame_def);
void StepDisplayTime();
@ -58,7 +59,7 @@ class DevConsole {
void AddButton(const char* label, float x, float y, float width, float height,
PyObject* call, const char* h_anchor_str, float label_scale,
float corner_radius, const char* style_str);
float corner_radius, const char* style_str, bool disabled);
void AddText(const char* text, float x, float y, const char* h_anchor_str,
const char* h_align_str, const char* v_align_str, float scale);
void AddPythonTerminal();
@ -96,12 +97,14 @@ class DevConsole {
State_ state_prev_{State_::kInactive};
bool input_text_dirty_{true};
bool input_enabled_{};
bool last_line_mesh_dirty_{true};
bool python_terminal_visible_{};
bool python_terminal_pressed_{};
bool refresh_pending_{};
bool carat_dirty_{true};
float carat_x_{};
float last_virtual_res_x_{-1.0f};
float last_virtual_res_y_{-1.0f};
seconds_t last_virtual_res_change_time_{};
seconds_t transition_start_{};
millisecs_t last_carat_x_change_time_{};
ImageMesh bg_mesh_;
@ -111,7 +114,6 @@ class DevConsole {
TextGroup title_text_group_;
TextGroup prompt_text_group_;
TextGroup input_text_group_;
std::string last_line_;
std::string input_string_;
std::list<std::string> tabs_;
std::string active_tab_;
@ -120,7 +122,6 @@ class DevConsole {
std::list<OutputLine_> output_lines_;
std::vector<std::unique_ptr<Widget_> > widgets_;
std::vector<std::unique_ptr<Widget_> > tab_buttons_;
Object::Ref<TextGroup> last_line_mesh_group_;
Object::Ref<Repeater> key_repeater_;
Object::Ref<NinePatchMesh> carat_mesh_;
Object::Ref<NinePatchMesh> carat_glow_mesh_;

View File

@ -18,6 +18,7 @@
#include "ballistica/shared/foundation/event_loop.h"
#include "ballistica/shared/foundation/macros.h"
#include "ballistica/shared/generic/utils.h"
#include "ballistica/shared/math/vector4f.h"
namespace ballistica::base {
@ -165,13 +166,13 @@ void UI::OnAppStart() {
if (force_scale_) {
if (scale_ == UIScale::kSmall) {
ScreenMessage("FORCING SMALL UI FOR TESTING", Vector3f(1, 0, 0));
Log(LogLevel::kInfo, "FORCING SMALL UI FOR TESTING");
Log(LogName::kBa, LogLevel::kInfo, "FORCING SMALL UI FOR TESTING");
} else if (scale_ == UIScale::kMedium) {
ScreenMessage("FORCING MEDIUM UI FOR TESTING", Vector3f(1, 0, 0));
Log(LogLevel::kInfo, "FORCING MEDIUM UI FOR TESTING");
Log(LogName::kBa, LogLevel::kInfo, "FORCING MEDIUM UI FOR TESTING");
} else if (scale_ == UIScale::kLarge) {
ScreenMessage("FORCING LARGE UI FOR TESTING", Vector3f(1, 0, 0));
Log(LogLevel::kInfo, "FORCING LARGE UI FOR TESTING");
Log(LogName::kBa, LogLevel::kInfo, "FORCING LARGE UI FOR TESTING");
} else {
FatalError("Unhandled scale.");
}
@ -576,7 +577,8 @@ void UI::ShowURL(const std::string& url) {
g_base->logic->event_loop()->PushCall(
[ui_delegate, url] { ui_delegate->DoShowURL(url); });
} else {
Log(LogLevel::kWarning, "UI::ShowURL called without ui_delegate present.");
Log(LogName::kBa, LogLevel::kWarning,
"UI::ShowURL called without ui_delegate present.");
}
}
@ -621,7 +623,8 @@ void UI::SetUIDelegate(base::UIDelegateInterface* delegate) {
}
}
void UI::PushDevConsolePrintCall(const std::string& msg) {
void UI::PushDevConsolePrintCall(const std::string& msg, float scale,
Vector4f color) {
// Completely ignore this stuff in headless mode.
if (g_core->HeadlessMode()) {
return;
@ -630,12 +633,14 @@ void UI::PushDevConsolePrintCall(const std::string& msg) {
// printed. Otherwise store it for the console to grab when it's ready.
if (auto* event_loop = g_base->logic->event_loop()) {
if (dev_console_ != nullptr) {
event_loop->PushCall([this, msg] { dev_console_->Print(msg); });
event_loop->PushCall([this, msg, scale, color] {
dev_console_->Print(msg, scale, color);
});
return;
}
}
// Didn't send a print; store for later.
dev_console_startup_messages_ += msg;
dev_console_startup_messages_.emplace_back(msg, scale, color);
}
void UI::OnAssetsAvailable() {
@ -648,7 +653,10 @@ void UI::OnAssetsAvailable() {
// Print any messages that have built up.
if (!dev_console_startup_messages_.empty()) {
dev_console_->Print(dev_console_startup_messages_);
for (auto&& entry : dev_console_startup_messages_) {
dev_console_->Print(std::get<0>(entry), std::get<1>(entry),
std::get<2>(entry));
}
dev_console_startup_messages_.clear();
}
}

View File

@ -3,11 +3,13 @@
#ifndef BALLISTICA_BASE_UI_UI_H_
#define BALLISTICA_BASE_UI_UI_H_
#include <list>
#include <string>
#include <vector>
#include "ballistica/base/graphics/support/frame_def.h"
#include "ballistica/base/ui/widget_message.h"
#include "ballistica/shared/math/vector4f.h"
// Predeclare a few things from ui_v1.
namespace ballistica::ui_v1 {
@ -123,7 +125,8 @@ class UI {
auto* dev_console() const { return dev_console_; }
void PushDevConsolePrintCall(const std::string& msg);
void PushDevConsolePrintCall(const std::string& msg, float scale,
Vector4f color);
auto* delegate() const { return delegate_; }
@ -154,7 +157,8 @@ class UI {
OperationContext* operation_context_{};
base::UIDelegateInterface* delegate_{};
DevConsole* dev_console_{};
std::string dev_console_startup_messages_;
std::list<std::tuple<std::string, float, Vector4f>>
dev_console_startup_messages_;
millisecs_t last_input_device_use_time_{};
millisecs_t last_widget_input_reject_err_sound_time_{};
UIScale scale_{UIScale::kLarge};

View File

@ -151,9 +151,9 @@ auto ClassicFeatureSet::GetV1AccountLoginStateString() -> std::string {
out = "signing_in";
break;
default:
Log(LogLevel::kError, "Unknown V1LoginState '"
+ std::to_string(static_cast<int>(state))
+ "'");
Log(LogName::kBaAccount, LogLevel::kError,
"Unknown V1LoginState '" + std::to_string(static_cast<int>(state))
+ "'");
out = "signed_out";
break;
}

View File

@ -128,9 +128,10 @@ void ClassicAppMode::Reset_() {
// If all is well our sessions should all be dead at this point.
if (g_scene_v1->session_count != 0) {
Log(LogLevel::kError, "SceneV1 session count is non-zero ("
+ std::to_string(g_scene_v1->session_count)
+ ") on ClassicAppMode::Reset_().");
Log(LogName::kBa, LogLevel::kError,
"SceneV1 session count is non-zero ("
+ std::to_string(g_scene_v1->session_count)
+ ") on ClassicAppMode::Reset_().");
}
// Reset the engine itself to a default state.
@ -159,15 +160,16 @@ void ClassicAppMode::HostScanCycle() {
scan_socket_ = socket(AF_INET, SOCK_DGRAM, 0);
if (scan_socket_ == -1) {
Log(LogLevel::kError, "Error opening scan socket: "
+ g_core->platform->GetSocketErrorString()
+ ".");
Log(LogName::kBaNetworking, LogLevel::kError,
"Error opening scan socket: "
+ g_core->platform->GetSocketErrorString() + ".");
return;
}
// Since this guy lives in the logic-thread we need it to not block.
if (!g_core->platform->SetSocketNonBlocking(scan_socket_)) {
Log(LogLevel::kError, "Error setting socket non-blocking.");
Log(LogName::kBaNetworking, LogLevel::kError,
"Error setting socket non-blocking.");
g_core->platform->CloseSocket(scan_socket_);
scan_socket_ = -1;
return;
@ -182,7 +184,7 @@ void ClassicAppMode::HostScanCycle() {
int result =
::bind(scan_socket_, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if (result == 1) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Error binding socket: " + g_core->platform->GetSocketErrorString()
+ ".");
g_core->platform->CloseSocket(scan_socket_);
@ -196,9 +198,9 @@ void ClassicAppMode::HostScanCycle() {
sizeof(op_val));
if (result != 0) {
Log(LogLevel::kError, "Error enabling broadcast for scan-socket: "
+ g_core->platform->GetSocketErrorString()
+ ".");
Log(LogName::kBaNetworking, LogLevel::kError,
"Error enabling broadcast for scan-socket: "
+ g_core->platform->GetSocketErrorString() + ".");
g_core->platform->CloseSocket(scan_socket_);
scan_socket_ = -1;
return;
@ -230,8 +232,9 @@ void ClassicAppMode::HostScanCycle() {
case ENETUNREACH:
break;
default:
Log(LogLevel::kError, "Error on scanSocket sendto: "
+ g_core->platform->GetSocketErrorString());
Log(LogName::kBaNetworking, LogLevel::kError,
"Error on scan-socket sendto: "
+ g_core->platform->GetSocketErrorString());
}
}
}
@ -253,8 +256,9 @@ void ClassicAppMode::HostScanCycle() {
case EWOULDBLOCK:
break;
default:
Log(LogLevel::kError, "Error: recvfrom error: "
+ g_core->platform->GetSocketErrorString());
Log(LogName::kBaNetworking, LogLevel::kError,
"Error: recvfrom error: "
+ g_core->platform->GetSocketErrorString());
break;
}
break;
@ -311,11 +315,11 @@ void ClassicAppMode::HostScanCycle() {
PruneScanResults_();
}
} else {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Got invalid BA_PACKET_HOST_QUERY_RESPONSE packet");
}
} else {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Got invalid BA_PACKET_HOST_QUERY_RESPONSE packet");
}
}
@ -388,7 +392,7 @@ bool ClassicAppMode::HasConnectionToClients() const {
auto ClassicAppMode::GetActiveOrWarn() -> ClassicAppMode* {
auto* val{GetActive()};
if (val == nullptr) {
Log(LogLevel::kWarning,
Log(LogName::kBa, LogLevel::kWarning,
"Attempting to access ClassicAppMode while it is inactive.");
}
return val;
@ -515,6 +519,16 @@ void ClassicAppMode::StepDisplayTime() {
}
legacy_display_time_millisecs_prev_ = legacy_display_time_millisecs_;
// Special case: due to things like app-mode-switches our
// prev-display-time-millisecs may be way in the past which
// can give us huge step values. So if this value is much bigger
// than the direct conversion of display_time_increment, clamp it.
auto milliseconds_inc_max =
static_cast<int>(g_base->logic->display_time_increment() * 1000.0 * 1.5);
if (legacy_display_time_millisecs_inc > milliseconds_inc_max) {
legacy_display_time_millisecs_inc = milliseconds_inc_max;
}
UpdateKickVote_();
HandleQuitOnIdle_();
@ -559,8 +573,9 @@ void ClassicAppMode::StepDisplayTime() {
// Complain when our full update takes longer than 1/60th second.
if (duration > (1000 / 60)) {
Log(LogLevel::kInfo, "Logic::StepDisplayTime update took too long ("
+ std::to_string(duration) + " ms).");
Log(LogName::kBa, LogLevel::kInfo,
"Logic::StepDisplayTime update took too long ("
+ std::to_string(duration) + " ms).");
// Limit these if we want (not doing so for now).
next_long_update_report_time_ = app_time;
@ -624,7 +639,7 @@ void ClassicAppMode::UpdateGameRoster() {
for (auto&& p : hs->players()) {
auto* delegate = p->input_device_delegate();
if (delegate == nullptr || !delegate->InputDeviceExists()) {
BA_LOG_ONCE(LogLevel::kWarning,
BA_LOG_ONCE(LogName::kBa, LogLevel::kWarning,
"Found player with no/invalid input-device-delegate in "
"UpdateGameRoster.");
continue;
@ -1215,7 +1230,7 @@ void ClassicAppMode::PruneSessions_() {
try {
i.Clear();
} catch (const std::exception& e) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"Exception killing Session: " + std::string(e.what()));
}
have_dead_session = true;
@ -1403,7 +1418,8 @@ void ClassicAppMode::HandleQuitOnIdle_() {
if (!idle_exiting_ && idle_seconds > (idle_exit_minutes_.value() * 60.0f)) {
idle_exiting_ = true;
Log(LogLevel::kInfo, "Quitting due to reaching idle-exit-minutes.");
Log(LogName::kBa, LogLevel::kInfo,
"Quitting due to reaching idle-exit-minutes.");
g_base->logic->event_loop()->PushCall([] { g_base->logic->Shutdown(); });
}
}
@ -1462,7 +1478,8 @@ void ClassicAppMode::HandleGameQuery(const char* buffer, size_t size,
BA_PRECONDITION_FATAL(!usid.empty());
if (usid.size() > 100) {
Log(LogLevel::kError, "had to truncate session-id; shouldn't happen");
Log(LogName::kBa, LogLevel::kError,
"had to truncate session-id; shouldn't happen");
usid.resize(100);
}
if (usid.empty()) {
@ -1488,8 +1505,9 @@ void ClassicAppMode::HandleGameQuery(const char* buffer, size_t size,
g_base->network_writer->PushSendToCall(msg_buffer, SockAddr(*from));
} else {
Log(LogLevel::kError, "Got invalid game-query packet of len "
+ std::to_string(size) + "; expected 5.");
Log(LogName::kBaNetworking, LogLevel::kError,
"Got invalid game-query packet of len " + std::to_string(size)
+ "; expected 5.");
}
}

View File

@ -10,6 +10,7 @@
#include "ballistica/core/platform/core_platform.h"
#include "ballistica/core/python/core_python.h"
#include "ballistica/shared/foundation/macros.h"
#include "ballistica/shared/foundation/types.h"
#include "ballistica/shared/generic/runnable.h"
@ -29,14 +30,14 @@ auto CoreFeatureSet::Import(const CoreConfig* config) -> CoreFeatureSet* {
"call.");
}
if (g_core == nullptr) {
DoImport(*config);
DoImport_(*config);
}
} else {
// If no config is passed, use a default. If the user wants env vars
// or anything else factored in, they should do so themselves in the
// config they pass (CoreConfig::ForEnvVars(), etc.).
if (g_core == nullptr) {
DoImport({});
DoImport_({});
}
}
} else {
@ -57,23 +58,23 @@ auto CoreFeatureSet::Import(const CoreConfig* config) -> CoreFeatureSet* {
// between monolithic and modular.
std::vector<std::string> argbuffer;
std::vector<char*> argv = CorePython::FetchPythonArgs(&argbuffer);
DoImport(CoreConfig::ForArgsAndEnvVars(static_cast<int>(argv.size()),
argv.data()));
DoImport_(CoreConfig::ForArgsAndEnvVars(static_cast<int>(argv.size()),
argv.data()));
} else {
// Not using Python sys args but we still want to process env vars.
DoImport(CoreConfig::ForEnvVars());
DoImport_(CoreConfig::ForEnvVars());
}
}
}
return g_core;
}
void CoreFeatureSet::DoImport(const CoreConfig& config) {
void CoreFeatureSet::DoImport_(const CoreConfig& config) {
millisecs_t start_millisecs = CorePlatform::GetCurrentMillisecs();
assert(g_core == nullptr);
g_core = new CoreFeatureSet(config);
g_core->PostInit();
g_core->PostInit_();
// Slightly hacky: have to report our begin time after the fact since core
// didn't exist before. Can at least add an offset to give an accurate
@ -97,16 +98,16 @@ CoreFeatureSet::CoreFeatureSet(CoreConfig config)
assert(g_core == nullptr);
}
void CoreFeatureSet::PostInit() {
void CoreFeatureSet::PostInit_() {
// Some of this stuff might access g_core so we run most of our init
// *after* assigning our singleton to be safe.
// Should migrate this to classic.
set_legacy_user_agent_string(platform->GetLegacyUserAgentString());
RunSanityChecks();
RunSanityChecks_();
build_src_dir_ = CalcBuildSrcDir();
build_src_dir_ = CalcBuildSrcDir_();
// On monolithic builds we need to bring up Python itself.
if (g_buildconfig.monolithic_build()) {
@ -119,13 +120,9 @@ void CoreFeatureSet::PostInit() {
// Grab whatever Python stuff we use.
python->ImportPythonObjs();
// Normally we wait until later to start pushing logs through to Python
// (so that our log handling system is fully bootstrapped), but
// technically we can push our log calls out to Python any time now since
// we grabbed the logging calls above. Do so immediately here if asked.
if (!core_config_.hold_early_logs) {
python->EnablePythonLoggingCalls();
}
// We grabbed all our log handles/etc. above, so we can start piping logs
// through to Python now.
python->EnablePythonLoggingCalls();
}
auto CoreFeatureSet::core_config() const -> const CoreConfig& {
@ -167,6 +164,16 @@ void CoreFeatureSet::ApplyBaEnvConfig() {
ba_env_site_python_dir_ =
envcfg.GetAttr("site_python_dir").ValueAsOptionalString();
ba_env_launch_timestamp_ = envcfg.GetAttr("launch_time").ValueAsDouble();
auto appcfg = envcfg.GetAttr("initial_app_config");
initial_app_config_ = appcfg.NewRef();
// This is also a reasonable time to grab initial logger levels that baenv
// likely mucked with. For any changes after this to make it to the native
// layer, babase.update_internal_logger_levels() must be called.
UpdateInternalLoggerLevels();
// Consider app-python-dir to be 'custom' if baenv provided a value for it
// AND that value differs from baenv's default.
auto standard_app_python_dir =
@ -183,6 +190,10 @@ void CoreFeatureSet::ApplyBaEnvConfig() {
}
}
void CoreFeatureSet::UpdateInternalLoggerLevels() {
python->UpdateInternalLoggerLevels(log_levels_);
}
auto CoreFeatureSet::GetAppPythonDirectory() -> std::optional<std::string> {
BA_PRECONDITION(have_ba_env_vals_);
return ba_env_app_python_dir_;
@ -209,7 +220,7 @@ auto CoreFeatureSet::GetSitePythonDirectory() -> std::optional<std::string> {
return ba_env_site_python_dir_;
}
auto CoreFeatureSet::CalcBuildSrcDir() -> std::string {
auto CoreFeatureSet::CalcBuildSrcDir_() -> std::string {
// Let's grab a string of the portion of __FILE__ before our project root.
// We can use it to make error messages/etc. more pretty by stripping out
// all but sub-project paths.
@ -217,14 +228,15 @@ auto CoreFeatureSet::CalcBuildSrcDir() -> std::string {
auto* f_end = strstr(f, "src" BA_DIRSLASH "ballistica" BA_DIRSLASH
"core" BA_DIRSLASH "core.cc");
if (!f_end) {
Log(LogLevel::kWarning, "Unable to calc build source dir from __FILE__.");
Log(LogName::kBa, LogLevel::kWarning,
"Unable to calc build source dir from __FILE__.");
return "";
} else {
return std::string(f).substr(0, f_end - f);
}
}
void CoreFeatureSet::RunSanityChecks() {
void CoreFeatureSet::RunSanityChecks_() {
// Sanity check: make sure asserts are stripped out of release builds
// (NDEBUG should do this).
#if !BA_DEBUG_BUILD
@ -267,11 +279,11 @@ void CoreFeatureSet::RunSanityChecks() {
// from. Use this to adjust the filtering as necessary so the resulting
// type name matches what is expected.
if (explicit_bool(false)) {
Log(LogLevel::kError, "static_type_name check; name is '"
+ static_type_name<decltype(g_core)>()
+ "' debug_full is '"
+ static_type_name<decltype(g_core)>(true) + "'");
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"static_type_name check; name is '"
+ static_type_name<decltype(g_core)>() + "' debug_full is '"
+ static_type_name<decltype(g_core)>(true) + "'");
Log(LogName::kBa, LogLevel::kError,
"static_type_name check; name is '"
+ static_type_name<decltype(testrunnable)>() + "' debug_full is '"
+ static_type_name<decltype(testrunnable)>(true) + "'");
@ -293,13 +305,16 @@ auto CoreFeatureSet::SoftImportBase() -> BaseSoftInterface* {
}
void CoreFeatureSet::LifecycleLog(const char* msg, double offset_seconds) {
if (!core_config_.lifecycle_log) {
// Early out to avoid work if we won't show anyway.
if (!LogLevelEnabled(LogName::kBaLifecycle, LogLevel::kDebug)) {
return;
}
// We include time-since-start as part of the message here.
char buffer[128];
snprintf(buffer, sizeof(buffer), "LIFE: %s @ %.3fs.", msg,
snprintf(buffer, sizeof(buffer), "%s @ %.3fs.", msg,
g_core->GetAppTimeSeconds() + offset_seconds);
Log(LogLevel::kInfo, buffer);
Log(LogName::kBaLifecycle, LogLevel::kDebug, buffer);
}
auto CoreFeatureSet::HeadlessMode() -> bool {
@ -308,29 +323,27 @@ auto CoreFeatureSet::HeadlessMode() -> bool {
return g_buildconfig.headless_build();
}
// auto CoreFeatureSet::vr_mode() -> bool { return core_config_.vr_mode; }
static void WaitThenDie(millisecs_t wait, const std::string& action) {
CorePlatform::SleepMillisecs(wait);
FatalError("Timed out waiting for " + action + ".");
}
auto CoreFeatureSet::GetAppTimeMillisecs() -> millisecs_t {
UpdateAppTime();
UpdateAppTime_();
return app_time_microsecs_ / 1000;
}
auto CoreFeatureSet::GetAppTimeMicrosecs() -> microsecs_t {
UpdateAppTime();
UpdateAppTime_();
return app_time_microsecs_;
}
auto CoreFeatureSet::GetAppTimeSeconds() -> seconds_t {
UpdateAppTime();
UpdateAppTime_();
return static_cast<seconds_t>(app_time_microsecs_) / 1000000;
}
void CoreFeatureSet::UpdateAppTime() {
void CoreFeatureSet::UpdateAppTime_() {
microsecs_t t = CorePlatform::GetCurrentMicrosecs();
// If we're at a different time than our last query, do our funky math.
@ -356,15 +369,6 @@ void CoreFeatureSet::UpdateAppTime() {
}
}
// void CoreFeatureSet::UpdateMainThreadID() {
// auto current_id = std::this_thread::get_id();
// // This gets called a lot and it may happen before we are spun up, so just
// // ignore it in that case.
// main_thread_id = current_id;
// main_event_loop_->set_thread_id(current_id);
// }
void CoreFeatureSet::StartSuicideTimer(const std::string& action,
millisecs_t delay) {
if (!started_suicide_) {
@ -433,4 +437,14 @@ auto CoreFeatureSet::CurrentThreadName() -> std::string {
#endif
}
auto CoreFeatureSet::HandOverInitialAppConfig() -> PyObject* {
BA_PRECONDITION(initial_app_config_);
// Don't decrement the refcount on the pointer we're holding; just clear
// and return it, effectively handing over the ref.
auto* out{initial_app_config_};
initial_app_config_ = nullptr;
return out;
}
} // namespace ballistica::core

View File

@ -3,7 +3,6 @@
#ifndef BALLISTICA_CORE_CORE_H_
#define BALLISTICA_CORE_CORE_H_
#include <list>
#include <mutex>
#include <string>
#include <thread>
@ -186,13 +185,36 @@ class CoreFeatureSet {
void set_event_loops_suspended(bool val) { event_loops_suspended_ = val; }
static auto CurrentThreadName() -> std::string;
auto HandOverInitialAppConfig() -> PyObject*;
/// Grab current Python logging levels for all logs we use internally. If
/// any changes are made at runtime to Python logging levels that we use,
/// this should be called after.
void UpdateInternalLoggerLevels();
/// Check whether a certain log name/level combo will be shown. It is much
/// more efficient to gate log calls using this (especially frequent or
/// debug ones) rather than letting the Python layer do the gating. Be
/// aware, however, that UpdateInternalLoggerLevels() must be called after
/// making any changes to Python logger levels to keep this internal
/// system up to date.
auto LogLevelEnabled(LogName name, LogLevel level) -> bool {
return log_levels_[static_cast<int>(name)] <= level;
}
auto ba_env_launch_timestamp() {
// Make sure we set this before accessing it.
assert(ba_env_launch_timestamp_ > 0.0);
return ba_env_launch_timestamp_;
}
private:
explicit CoreFeatureSet(CoreConfig config);
static void DoImport(const CoreConfig& config);
static auto CalcBuildSrcDir() -> std::string;
void RunSanityChecks();
void UpdateAppTime();
void PostInit();
static void DoImport_(const CoreConfig& config);
static auto CalcBuildSrcDir_() -> std::string;
void RunSanityChecks_();
void UpdateAppTime_();
void PostInit_();
// Note to self: don't use single bits for these as they may be owned by
// different threads.
@ -203,7 +225,9 @@ class CoreFeatureSet {
bool vr_mode_{};
bool using_custom_app_python_dir_{};
bool engine_done_{};
LogLevel log_levels_[static_cast<int>(LogName::kLast)]{};
PyObject* initial_app_config_{};
std::thread::id main_thread_id_{};
CoreConfig core_config_;
std::string build_src_dir_;
@ -217,6 +241,7 @@ class CoreFeatureSet {
std::optional<std::string> ba_env_user_python_dir_;
std::optional<std::string> ba_env_site_python_dir_;
std::string ba_env_data_dir_;
double ba_env_launch_timestamp_{-1.0};
std::mutex thread_info_map_mutex_;
std::unordered_map<std::thread::id, std::string> thread_info_map_;
};

View File

@ -178,10 +178,10 @@ auto CorePlatform::GetLegacyDeviceUUID() -> const std::string& {
if (FILE* f2 = FOpen(path.c_str(), "wb")) {
size_t result = fwrite(val.c_str(), val.size(), 1, f2);
if (result != 1)
Log(LogLevel::kError, "unable to write bsuuid file.");
Log(LogName::kBa, LogLevel::kError, "unable to write bsuuid file.");
fclose(f2);
} else {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"unable to open bsuuid file for writing: '" + path + "'");
}
}
@ -192,7 +192,8 @@ auto CorePlatform::GetLegacyDeviceUUID() -> const std::string& {
}
auto CorePlatform::GetDeviceV1AccountUUIDPrefix() -> std::string {
Log(LogLevel::kError, "GetDeviceV1AccountUUIDPrefix() unimplemented");
Log(LogName::kBa, LogLevel::kError,
"GetDeviceV1AccountUUIDPrefix() unimplemented");
return "u";
}
@ -248,10 +249,12 @@ void CorePlatform::SetLowLevelConfigValue(const char* key, int value) {
if (f) {
size_t result = fwrite(out.c_str(), out.size(), 1, f);
if (result != 1)
Log(LogLevel::kError, "unable to write low level config file.");
Log(LogName::kBa, LogLevel::kError,
"unable to write low level config file.");
fclose(f);
} else {
Log(LogLevel::kError, "unable to open low level config file for writing.");
Log(LogName::kBa, LogLevel::kError,
"unable to open low level config file for writing.");
}
}
@ -425,7 +428,7 @@ auto CorePlatform::GetLocale() -> std::string {
return lang;
} else {
if (!g_buildconfig.headless_build()) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBa, LogLevel::kError,
"No LANG value available; defaulting to en_US");
}
return "en_US";
@ -688,7 +691,7 @@ auto CorePlatform::ConvertIncomingLeaderboardScore(
void CorePlatform::SubmitScore(const std::string& game,
const std::string& version, int64_t score) {
Log(LogLevel::kError, "FIXME: SubmitScore() unimplemented");
Log(LogName::kBa, LogLevel::kError, "FIXME: SubmitScore() unimplemented");
}
void CorePlatform::ReportAchievement(const std::string& achievement) {}
@ -701,7 +704,8 @@ auto CorePlatform::HaveLeaderboard(const std::string& game,
void CorePlatform::ShowGameServiceUI(const std::string& show,
const std::string& game,
const std::string& game_version) {
Log(LogLevel::kError, "FIXME: ShowGameServiceUI() unimplemented");
Log(LogName::kBa, LogLevel::kError,
"FIXME: ShowGameServiceUI() unimplemented");
}
void CorePlatform::AndroidSetResString(const std::string& res) {
@ -729,7 +733,7 @@ auto CorePlatform::DemangleCXXSymbol(const std::string& s) -> std::string {
abi::__cxa_demangle(s.c_str(), nullptr, nullptr, &demangle_status);
if (demangled_name != nullptr) {
if (demangle_status != 0) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBa, LogLevel::kError,
"__cxa_demangle got buffer but non-zero status; unexpected");
}
std::string retval = demangled_name;
@ -744,25 +748,28 @@ auto CorePlatform::DemangleCXXSymbol(const std::string& s) -> std::string {
}
void CorePlatform::ResetAchievements() {
Log(LogLevel::kError, "ResetAchievements() unimplemented");
Log(LogName::kBa, LogLevel::kError, "ResetAchievements() unimplemented");
}
void CorePlatform::RunEvents() {}
void CorePlatform::MusicPlayerPlay(PyObject* target) {
Log(LogLevel::kError, "MusicPlayerPlay() unimplemented on this platform");
Log(LogName::kBa, LogLevel::kError,
"MusicPlayerPlay() unimplemented on this platform");
}
void CorePlatform::MusicPlayerStop() {
Log(LogLevel::kError, "MusicPlayerStop() unimplemented on this platform");
Log(LogName::kBa, LogLevel::kError,
"MusicPlayerStop() unimplemented on this platform");
}
void CorePlatform::MusicPlayerShutdown() {
Log(LogLevel::kError, "MusicPlayerShutdown() unimplemented on this platform");
Log(LogName::kBa, LogLevel::kError,
"MusicPlayerShutdown() unimplemented on this platform");
}
void CorePlatform::MusicPlayerSetVolume(float volume) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"MusicPlayerSetVolume() unimplemented on this platform");
}
@ -785,7 +792,7 @@ void CorePlatform::SubmitAnalyticsCounts() {}
void CorePlatform::SetPlatformMiscReadVals(const std::string& vals) {}
void CorePlatform::ShowAd(const std::string& purpose) {
Log(LogLevel::kError, "ShowAd() unimplemented");
Log(LogName::kBa, LogLevel::kError, "ShowAd() unimplemented");
}
auto CorePlatform::GetHasAds() -> bool { return false; }
@ -796,7 +803,7 @@ auto CorePlatform::GetHasVideoAds() -> bool {
}
void CorePlatform::SignInV1(const std::string& account_type) {
Log(LogLevel::kError, "SignInV1() unimplemented");
Log(LogName::kBa, LogLevel::kError, "SignInV1() unimplemented");
}
void CorePlatform::V1LoginDidChange() {
@ -804,33 +811,35 @@ void CorePlatform::V1LoginDidChange() {
}
void CorePlatform::SignOutV1() {
Log(LogLevel::kError, "SignOutV1() unimplemented");
Log(LogName::kBa, LogLevel::kError, "SignOutV1() unimplemented");
}
void CorePlatform::MacMusicAppInit() {
Log(LogLevel::kError, "MacMusicAppInit() unimplemented");
Log(LogName::kBa, LogLevel::kError, "MacMusicAppInit() unimplemented");
}
auto CorePlatform::MacMusicAppGetVolume() -> int {
Log(LogLevel::kError, "MacMusicAppGetVolume() unimplemented");
Log(LogName::kBa, LogLevel::kError, "MacMusicAppGetVolume() unimplemented");
return 0;
}
void CorePlatform::MacMusicAppSetVolume(int volume) {
Log(LogLevel::kError, "MacMusicAppSetVolume() unimplemented");
Log(LogName::kBa, LogLevel::kError, "MacMusicAppSetVolume() unimplemented");
}
void CorePlatform::MacMusicAppStop() {
Log(LogLevel::kError, "MacMusicAppStop() unimplemented");
Log(LogName::kBa, LogLevel::kError, "MacMusicAppStop() unimplemented");
}
auto CorePlatform::MacMusicAppPlayPlaylist(const std::string& playlist)
-> bool {
Log(LogLevel::kError, "MacMusicAppPlayPlaylist() unimplemented");
Log(LogName::kBa, LogLevel::kError,
"MacMusicAppPlayPlaylist() unimplemented");
return false;
}
auto CorePlatform::MacMusicAppGetPlaylists() -> std::list<std::string> {
Log(LogLevel::kError, "MacMusicAppGetPlaylists() unimplemented");
Log(LogName::kBa, LogLevel::kError,
"MacMusicAppGetPlaylists() unimplemented");
return {};
}
@ -935,8 +944,9 @@ auto CorePlatform::SetSocketNonBlocking(int sd) -> bool {
#else
int result = fcntl(sd, F_SETFL, O_NONBLOCK);
if (result != 0) {
Log(LogLevel::kError, "Error setting non-blocking socket: "
+ g_core->platform->GetSocketErrorString());
Log(LogName::kBa, LogLevel::kError,
"Error setting non-blocking socket: "
+ g_core->platform->GetSocketErrorString());
return false;
}
return true;
@ -1069,6 +1079,12 @@ auto CorePlatform::GetCurrentMicrosecs() -> millisecs_t {
.count();
}
auto CorePlatform::GetSecondsSinceEpoch() -> double {
return std::chrono::duration<double>(
std::chrono::system_clock::now().time_since_epoch())
.count();
}
auto CorePlatform::GetCurrentWholeSeconds() -> int64_t {
return std::chrono::time_point_cast<std::chrono::seconds>(
std::chrono::steady_clock::now())

View File

@ -369,6 +369,9 @@ class CorePlatform {
/// to not go backwards.
static auto GetCurrentWholeSeconds() -> int64_t;
/// Return seconds since the epoch; same as Python's time.time().
static auto GetSecondsSinceEpoch() -> double;
static void SleepSeconds(seconds_t duration);
static void SleepMillisecs(millisecs_t duration);
static void SleepMicrosecs(microsecs_t duration);

View File

@ -919,7 +919,8 @@ auto CorePlatformWindows::GetEnv(const std::string& name)
// This should always succeed at this point; make noise if not.
if (result == 0 || result > big_buffer.size()) {
Log(LogLevel::kError, "GetEnv to allocated buffer failed; unexpected.");
Log(LogName::kBa, LogLevel::kError,
"GetEnv to allocated buffer failed; unexpected.");
return {};
}
return UTF8Encode(big_buffer.data());
@ -997,14 +998,15 @@ std::vector<uint32_t> CorePlatformWindows::GetBroadcastAddrs() {
pIPAddrTable = static_cast<MIB_IPADDRTABLE*>(MALLOC(dwSize));
}
if (pIPAddrTable == nullptr) {
Log(LogLevel::kError, "Memory allocation failed for GetIpAddrTable\n");
Log(LogName::kBa, LogLevel::kError,
"Memory allocation failed for GetIpAddrTable\n");
err = true;
}
if (!err) {
// Make a second call to GetIpAddrTable to get the actual data we want
if ((dwRetVal = GetIpAddrTable(pIPAddrTable, &dwSize, 0)) != NO_ERROR) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"GetIpAddrTable failed with error " + std::to_string(dwRetVal));
err = true;
}
@ -1040,8 +1042,9 @@ bool CorePlatformWindows::SetSocketNonBlocking(int sd) {
unsigned long dataval = 1; // NOLINT (func signature wants long)
int result = ioctlsocket(sd, FIONBIO, &dataval);
if (result != 0) {
Log(LogLevel::kError, "Error setting non-blocking socket: "
+ g_core->platform->GetSocketErrorString());
Log(LogName::kBa, LogLevel::kError,
"Error setting non-blocking socket: "
+ g_core->platform->GetSocketErrorString());
return false;
}
return true;

View File

@ -4,10 +4,12 @@
#include <cstdio>
#include <string>
#include <utility>
#include <vector>
#include "ballistica/core/mgen/python_modules_monolithic.h"
#include "ballistica/core/platform/core_platform.h"
#include "ballistica/shared/foundation/macros.h"
#include "ballistica/shared/python/python.h"
#include "ballistica/shared/python/python_command.h"
@ -174,18 +176,38 @@ void CorePython::EnablePythonLoggingCalls() {
}
auto gil{Python::ScopedInterpreterLock()};
assert(objs().Exists(ObjID::kLoggingDebugCall));
assert(objs().Exists(ObjID::kLoggingInfoCall));
assert(objs().Exists(ObjID::kLoggingWarningCall));
assert(objs().Exists(ObjID::kLoggingErrorCall));
assert(objs().Exists(ObjID::kLoggingCriticalCall));
// Make sure we've got all our logging Python bits we need.
assert(objs().Exists(ObjID::kLoggingLevelDebug));
assert(objs().Exists(ObjID::kLoggingLevelInfo));
assert(objs().Exists(ObjID::kLoggingLevelWarning));
assert(objs().Exists(ObjID::kLoggingLevelError));
assert(objs().Exists(ObjID::kLoggingLevelCritical));
assert(objs().Exists(ObjID::kLoggerRoot));
assert(objs().Exists(ObjID::kLoggerRootLogCall));
assert(objs().Exists(ObjID::kLoggerBa));
assert(objs().Exists(ObjID::kLoggerBaLogCall));
assert(objs().Exists(ObjID::kLoggerBaAccount));
assert(objs().Exists(ObjID::kLoggerBaAccountLogCall));
assert(objs().Exists(ObjID::kLoggerBaAudio));
assert(objs().Exists(ObjID::kLoggerBaAudioLogCall));
assert(objs().Exists(ObjID::kLoggerBaGraphics));
assert(objs().Exists(ObjID::kLoggerBaGraphicsLogCall));
assert(objs().Exists(ObjID::kLoggerBaLifecycle));
assert(objs().Exists(ObjID::kLoggerBaLifecycleLogCall));
assert(objs().Exists(ObjID::kLoggerBaAssets));
assert(objs().Exists(ObjID::kLoggerBaAssetsLogCall));
assert(objs().Exists(ObjID::kLoggerBaInput));
assert(objs().Exists(ObjID::kLoggerBaInputLogCall));
assert(objs().Exists(ObjID::kLoggerBaNetworking));
assert(objs().Exists(ObjID::kLoggerBaNetworkingLogCall));
// Push any early log calls we've been holding on to along to Python.
{
std::scoped_lock lock(early_log_lock_);
python_logging_calls_enabled_ = true;
for (auto&& entry : early_logs_) {
LoggingCall(entry.first, "[HELD] " + entry.second);
LoggingCall(std::get<0>(entry), std::get<1>(entry),
"[HELD] " + std::get<2>(entry));
}
early_logs_.clear();
}
@ -214,6 +236,72 @@ void CorePython::ImportPythonObjs() {
}
}
void CorePython::UpdateInternalLoggerLevels(LogLevel* log_levels) {
assert(python_logging_calls_enabled_);
assert(Python::HaveGIL());
const int log_level_debug{10};
const int log_level_info{20};
const int log_level_warning{30};
const int log_level_error{40};
const int log_level_critical{50};
assert(log_level_debug == objs().Get(ObjID::kLoggingLevelDebug).ValueAsInt());
assert(log_level_info == objs().Get(ObjID::kLoggingLevelInfo).ValueAsInt());
assert(log_level_warning
== objs().Get(ObjID::kLoggingLevelWarning).ValueAsInt());
assert(log_level_error == objs().Get(ObjID::kLoggingLevelError).ValueAsInt());
assert(log_level_critical
== objs().Get(ObjID::kLoggingLevelCritical).ValueAsInt());
std::pair<LogName, ObjID> pairs[] = {
{LogName::kRoot, ObjID::kLoggerRoot},
{LogName::kBa, ObjID::kLoggerBa},
{LogName::kBaAccount, ObjID::kLoggerBaAccount},
{LogName::kBaAudio, ObjID::kLoggerBaAudio},
{LogName::kBaGraphics, ObjID::kLoggerBaGraphics},
{LogName::kBaLifecycle, ObjID::kLoggerBaLifecycle},
{LogName::kBaAssets, ObjID::kLoggerBaAssets},
{LogName::kBaInput, ObjID::kLoggerBaInput},
{LogName::kBaNetworking, ObjID::kLoggerBaNetworking},
};
int count{};
for (const auto& pair : pairs) {
count++;
auto logname{pair.first};
auto objid{pair.second};
auto out{objs().Get(objid).GetAttr("getEffectiveLevel").Call()};
assert(out.Exists());
auto outval{static_cast<int>(out.ValueAsInt())};
switch (outval) {
case log_level_debug:
log_levels[static_cast<int>(logname)] = LogLevel::kDebug;
break;
case log_level_info:
log_levels[static_cast<int>(logname)] = LogLevel::kInfo;
break;
case log_level_warning:
log_levels[static_cast<int>(logname)] = LogLevel::kWarning;
break;
case log_level_error:
log_levels[static_cast<int>(logname)] = LogLevel::kError;
break;
case log_level_critical:
log_levels[static_cast<int>(logname)] = LogLevel::kCritical;
break;
default:
fprintf(stderr, "Found unexpected resolved logging level %d\n", outval);
}
}
// Sanity check: Make sure we covered our full set of LogNames.
if (count != static_cast<int>(LogName::kLast)) {
fprintf(stderr,
"WARNING: UpdateInternalLoggerLevels does not seem to be covering "
"all log names.\n");
}
}
void CorePython::SoftImportBase() {
auto gil{Python::ScopedInterpreterLock()};
auto result = PythonRef::StolenSoft(PyImport_ImportModule("_babase"));
@ -296,23 +384,25 @@ void CorePython::MonolithicModeBaEnvConfigure() {
g_core->LifecycleLog("baenv.configure() end");
}
void CorePython::LoggingCall(LogLevel loglevel, const std::string& msg) {
// If we're not yet sending logs to Python, store this one away until we are.
void CorePython::LoggingCall(LogName logname, LogLevel loglevel,
const std::string& msg) {
// If we're not yet sending logs to Python, store this one away until we
// are.
if (!python_logging_calls_enabled_) {
std::scoped_lock lock(early_log_lock_);
early_logs_.emplace_back(loglevel, msg);
early_logs_.emplace_back(logname, loglevel, msg);
// UPDATE - trying to disable this for now to make the concept of delayed
// logs a bit less scary. Perhaps we can update fatal-error to dump these or
// have a mode to immediate-print them as needed.
// UPDATE - trying to disable this for now to make the concept of
// delayed logs a bit less scary. Perhaps we can update fatal-error to
// dump these or have a mode to immediate-print them as needed.
if (explicit_bool(false)) {
// There's a chance that we're going down in flames and this log
// might be useful to see even if we never get a chance to chip it to
// There's a chance that we're going down in flames and this log might
// be useful to see even if we never get a chance to chip it to
// Python. So let's make an attempt to get it at least seen now in
// whatever way we can. (platform display-log call and stderr).
const char* errmsg{
"CorePython::LoggingCall() called before Python"
" logging available."};
"CorePython::LoggingCall() called before Python logging "
"available."};
if (g_core->platform) {
g_core->platform->EmitPlatformLog("root", LogLevel::kError, errmsg);
g_core->platform->EmitPlatformLog("root", loglevel, msg);
@ -322,42 +412,93 @@ void CorePython::LoggingCall(LogLevel loglevel, const std::string& msg) {
return;
}
// Ok; seems we've got Python calls. Run the right one for our log level.
ObjID logcallobj;
switch (loglevel) {
case LogLevel::kDebug:
logcallobj = ObjID::kLoggingDebugCall;
break;
case LogLevel::kInfo:
logcallobj = ObjID::kLoggingInfoCall;
break;
case LogLevel::kWarning:
logcallobj = ObjID::kLoggingWarningCall;
break;
case LogLevel::kError:
logcallobj = ObjID::kLoggingErrorCall;
break;
case LogLevel::kCritical:
logcallobj = ObjID::kLoggingCriticalCall;
break;
default:
logcallobj = ObjID::kLoggingInfoCall;
fprintf(stderr, "Unexpected LogLevel %d\n", static_cast<int>(loglevel));
break;
}
// Make sure we're good to go from any thread.
Python::ScopedInterpreterLock lock;
PythonRef args(Py_BuildValue("(s)", msg.c_str()), PythonRef::kSteal);
ObjID logcallobj;
bool handled{};
switch (logname) {
case LogName::kRoot:
logcallobj = ObjID::kLoggerRootLogCall;
handled = true;
break;
case LogName::kBa:
logcallobj = ObjID::kLoggerBaLogCall;
handled = true;
break;
case LogName::kBaAccount:
logcallobj = ObjID::kLoggerBaAccountLogCall;
handled = true;
break;
case LogName::kBaAudio:
logcallobj = ObjID::kLoggerBaAudioLogCall;
handled = true;
break;
case LogName::kBaGraphics:
logcallobj = ObjID::kLoggerBaGraphicsLogCall;
handled = true;
break;
case LogName::kBaAssets:
logcallobj = ObjID::kLoggerBaAssetsLogCall;
handled = true;
break;
case LogName::kBaInput:
logcallobj = ObjID::kLoggerBaInputLogCall;
handled = true;
break;
case LogName::kBaNetworking:
logcallobj = ObjID::kLoggerBaNetworkingLogCall;
handled = true;
break;
case LogName::kBaLifecycle:
logcallobj = ObjID::kLoggerBaLifecycleLogCall;
handled = true;
break;
case LogName::kLast:
logcallobj = ObjID::kLoggerRootLogCall;
break;
}
// Handle this here instead of via default clause so we get warnings about
// new unhandled enum values.
if (!handled) {
logcallobj = ObjID::kLoggerRootLogCall;
fprintf(stderr, "Unexpected LogName %d\n", static_cast<int>(logname));
}
ObjID loglevelobjid;
switch (loglevel) {
case LogLevel::kDebug:
loglevelobjid = ObjID::kLoggingLevelDebug;
break;
case LogLevel::kInfo:
loglevelobjid = ObjID::kLoggingLevelInfo;
break;
case LogLevel::kWarning:
loglevelobjid = ObjID::kLoggingLevelWarning;
break;
case LogLevel::kError:
loglevelobjid = ObjID::kLoggingLevelError;
break;
case LogLevel::kCritical:
loglevelobjid = ObjID::kLoggingLevelCritical;
break;
default:
loglevelobjid = ObjID::kLoggingLevelInfo;
fprintf(stderr, "Unexpected LogLevel %d\n", static_cast<int>(loglevel));
break;
}
PythonRef args(
Py_BuildValue("(Os)", objs().Get(loglevelobjid).Get(), msg.c_str()),
PythonRef::kSteal);
objs().Get(logcallobj).Call(args);
}
auto CorePython::WasModularMainCalled() -> bool {
assert(!g_buildconfig.monolithic_build());
// This gets called in modular builds before anything is inited, so we need to
// avoid using anything from g_core or whatnot here; only raw Python stuff.
// This gets called in modular builds before anything is inited, so we need
// to avoid using anything from g_core or whatnot here; only raw Python
// stuff.
PyObject* baenv = PyImport_ImportModule("baenv");
if (!baenv) {
@ -394,8 +535,9 @@ auto CorePython::WasModularMainCalled() -> bool {
auto CorePython::FetchPythonArgs(std::vector<std::string>* buffer)
-> std::vector<char*> {
// This gets called in modular builds before anything is inited, so we need to
// avoid using anything from g_core or whatnot here; only raw Python stuff.
// This gets called in modular builds before anything is inited, so we need
// to avoid using anything from g_core or whatnot here; only raw Python
// stuff.
assert(buffer && buffer->empty());
PyObject* sys = PyImport_ImportModule("sys");

View File

@ -24,11 +24,29 @@ class CorePython {
kJsonDumpsCall,
kJsonLoadsCall,
kEmptyTuple,
kLoggingDebugCall,
kLoggingInfoCall,
kLoggingWarningCall,
kLoggingErrorCall,
kLoggingCriticalCall,
kLoggingLevelDebug,
kLoggingLevelInfo,
kLoggingLevelWarning,
kLoggingLevelError,
kLoggingLevelCritical,
kLoggerRoot,
kLoggerRootLogCall,
kLoggerBa,
kLoggerBaLogCall,
kLoggerBaAccount,
kLoggerBaAccountLogCall,
kLoggerBaAudio,
kLoggerBaAudioLogCall,
kLoggerBaGraphics,
kLoggerBaGraphicsLogCall,
kLoggerBaLifecycle,
kLoggerBaLifecycleLogCall,
kLoggerBaAssets,
kLoggerBaAssetsLogCall,
kLoggerBaInput,
kLoggerBaInputLogCall,
kLoggerBaNetworking,
kLoggerBaNetworkingLogCall,
kPrependSysPathCall,
kBaEnvConfigureCall,
kBaEnvGetConfigCall,
@ -49,10 +67,11 @@ class CorePython {
/// Can be called from any thread at any time. If called before Python
/// logging is available, logs locally using Logging::EmitPlatformLog()
/// (with an added warning).
void LoggingCall(LogLevel loglevel, const std::string& msg);
void LoggingCall(LogName logname, LogLevel loglevel, const std::string& msg);
void ImportPythonObjs();
void VerifyPythonEnvironment();
void SoftImportBase();
void UpdateInternalLoggerLevels(LogLevel* log_levels);
static auto WasModularMainCalled() -> bool;
@ -70,7 +89,7 @@ class CorePython {
// go here. They all get shipped at once as soon as it is possible.
bool python_logging_calls_enabled_{};
std::mutex early_log_lock_;
std::list<std::pair<LogLevel, std::string>> early_logs_;
std::list<std::tuple<LogName, LogLevel, std::string>> early_logs_;
};
} // namespace ballistica::core

View File

@ -33,7 +33,8 @@ class BaseSoftInterface {
virtual auto FeatureSetFromData(PyObject* obj)
-> FeatureSetNativeComponent* = 0;
virtual void DoV1CloudLog(const std::string& msg) = 0;
virtual void PushDevConsolePrintCall(const std::string& msg) = 0;
virtual void PushDevConsolePrintCall(const std::string& msg, float scale,
Vector4f color) = 0;
virtual auto GetPyExceptionType(PyExcType exctype) -> PyObject* = 0;
virtual auto PrintPythonStackTrace() -> bool = 0;
virtual auto GetPyLString(PyObject* obj) -> std::string = 0;

View File

@ -78,11 +78,15 @@ static auto ParseArgValue(int argc, char** argv, int* i, const char* arg_long,
}
void CoreConfig::ApplyEnvVars() {
if (auto* envval = getenv("BA_LIFECYCLE_LOG")) {
if (!strcmp(envval, "1")) {
lifecycle_log = true;
}
}
// TODO(ericf): This is now simply a log level. If we want to allow
// controlling log-levels via env-vars we should come up with a unified
// system for that.
// if (auto* envval = getenv("BA_LIFECYCLE_LOG")) {
// if (!strcmp(envval, "1")) {
// lifecycle_log = true;
// }
// }
if (auto* envval = getenv("BA_DEBUGGER_ATTACHED")) {
if (!strcmp(envval, "1")) {
debugger_attached = true;

View File

@ -30,14 +30,7 @@ class CoreConfig {
bool vr_mode{};
/// Log various stages/times in the bootstrapping process.
bool lifecycle_log{};
/// Normally early C++ Log() calls are held until babase has been imported
/// so that when they are pushed out to the Python logging calls they are
/// properly routed through the full engine. If you are not using babase
/// or are trying to debug early issues you can flip this off to push
/// things to Python as soon as technically possible.
bool hold_early_logs{true};
// bool lifecycle_log{};
/// Let the engine know there's a debugger attached so it should do things
/// like abort() instead of exiting with error codes.

View File

@ -156,7 +156,7 @@ void Connection::HandleGamePacketCompressed(const std::vector<uint8_t>& data) {
try {
data_decompressed = g_base->huffman->decompress(data);
} catch (const std::exception& e) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
std::string("Error in huffman decompression for packet: ") + e.what());
// Hmmm i guess lets just ignore this packet and keep on trucking?.. or
@ -176,7 +176,7 @@ void Connection::HandleGamePacket(const std::vector<uint8_t>& data) {
switch (data[0]) {
case BA_SCENEPACKET_KEEPALIVE: {
if (data.size() != 4) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaNetworking, LogLevel::kError,
"Error: got invalid BA_SCENEPACKET_KEEPALIVE packet.");
return;
}
@ -190,7 +190,8 @@ void Connection::HandleGamePacket(const std::vector<uint8_t>& data) {
// Expect 1 byte type, 2 byte num, 3 byte acks, at least 1 byte payload.
if (data.size() < 7) {
Log(LogLevel::kError, "Got invalid BA_PACKET_STATE packet.");
Log(LogName::kBaNetworking, LogLevel::kError,
"Got invalid BA_PACKET_STATE packet.");
return;
}
uint16_t num;
@ -221,7 +222,8 @@ void Connection::HandleGamePacket(const std::vector<uint8_t>& data) {
// Expect 1 byte type, 2 byte num, 2 byte unreliable-num, 3 byte acks,
// at least 1 byte payload.
if (data.size() < 9) {
Log(LogLevel::kError, "Got invalid BA_PACKET_STATE_UNRELIABLE packet.");
Log(LogName::kBaNetworking, LogLevel::kError,
"Got invalid BA_PACKET_STATE_UNRELIABLE packet.");
return;
}
uint16_t num, num_unreliable;
@ -242,8 +244,9 @@ void Connection::HandleGamePacket(const std::vector<uint8_t>& data) {
}
default:
Log(LogLevel::kError, "Connection got unknown packet type: "
+ std::to_string(static_cast<int>(data[0])));
Log(LogName::kBaNetworking, LogLevel::kError,
"Connection got unknown packet type: "
+ std::to_string(static_cast<int>(data[0])));
break;
}
}
@ -325,7 +328,7 @@ void Connection::SendReliableMessage(const std::vector<uint8_t>& data) {
void Connection::SendUnreliableMessage(const std::vector<uint8_t>& data) {
// For now we just silently drop anything bigger than our max packet size.
if (data.size() + 8 > kMaxPacketSize) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaNetworking, LogLevel::kError,
"Error: Dropping outgoing unreliable packet of size "
+ std::to_string(data.size()) + ".");
return;
@ -438,11 +441,12 @@ void Connection::HandleMessagePacket(const std::vector<uint8_t>& buffer) {
multipart_buffer_.resize(old_size + (buffer.size() - 1));
memcpy(&(multipart_buffer_[old_size]), &(buffer[1]), buffer.size() - 1);
} else {
Log(LogLevel::kError, "got invalid BA_MESSAGE_MULTIPART");
Log(LogName::kBaNetworking, LogLevel::kError,
"got invalid BA_MESSAGE_MULTIPART");
}
if (buffer[0] == BA_MESSAGE_MULTIPART_END) {
if (multipart_buffer_[0] == BA_MESSAGE_MULTIPART) {
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaNetworking, LogLevel::kError,
"nested multipart message detected; kicking");
Error("");
}
@ -487,7 +491,7 @@ void Connection::SendGamePacket(const std::vector<uint8_t>& data) {
&& data[0] != BA_SCENEPACKET_HANDSHAKE_RESPONSE) {
if (explicit_bool(false)) {
BA_LOG_ONCE(
LogLevel::kError,
LogName::kBaNetworking, LogLevel::kError,
"SendGamePacket() called before can_communicate set ("
+ g_core->platform->DemangleCXXSymbol(typeid(*this).name())
+ " ptype " + std::to_string(static_cast<int>(data[0])) + ")");

View File

@ -31,7 +31,7 @@ void ConnectionSet::RegisterClientController(ClientControllerInterface* c) {
// This shouldn't happen, but if there's already a controller registered,
// detach all clients from it.
if (client_controller_) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"RegisterClientController() called "
"but already have a controller; bad.");
for (auto&& i : connections_to_clients_) {
@ -214,7 +214,7 @@ auto ConnectionSet::GetConnectionsToClients()
if (connections_to_client.second.Exists()) {
connections.push_back(connections_to_client.second.Get());
} else {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"HAVE NONEXISTENT CONNECTION_TO_CLIENT IN LIST; UNEXPECTED");
}
}
@ -274,7 +274,7 @@ void ConnectionSet::SendScreenMessageToAll(const std::string& s, float r,
void ConnectionSet::PrepareForLaunchHostSession() {
// If for some reason we're still attached to a host, kill the connection.
if (connection_to_host_.Exists()) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Had host-connection during LaunchHostSession(); shouldn't happen.");
connection_to_host_->RequestDisconnect();
connection_to_host_.Clear();
@ -320,8 +320,9 @@ auto ConnectionSet::DisconnectClient(int client_id, int ban_seconds) -> bool {
return false;
}
if (client_id > 255) {
Log(LogLevel::kError, "DisconnectClient got client_id > 255 ("
+ std::to_string(client_id) + ")");
Log(LogName::kBaNetworking, LogLevel::kError,
"DisconnectClient got client_id > 255 (" + std::to_string(client_id)
+ ")");
} else {
std::vector<uint8_t> msg_out(2);
msg_out[0] = BA_MESSAGE_KICK_VOTE;
@ -409,7 +410,7 @@ void ConnectionSet::UnregisterClientController(ClientControllerInterface* c) {
// This shouldn't happen.
if (client_controller_ != c) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"UnregisterClientController() called with a non-registered "
"controller");
return;
@ -675,7 +676,8 @@ void ConnectionSet::HandleIncomingUDPPacket(const std::vector<uint8_t>& data_in,
msg_out[0] = BA_PACKET_CLIENT_DENY;
msg_out[1] = request_id;
g_base->network_writer->PushSendToCall(msg_out, addr);
Log(LogLevel::kError, "All client slots full; really?..");
Log(LogName::kBaNetworking, LogLevel::kError,
"All client slots full; really?..");
break;
}
connection_to_client = Object::New<ConnectionToClientUDP>(
@ -717,7 +719,7 @@ auto ConnectionSet::VerifyClientAddr(uint8_t client_id, const SockAddr& addr)
if (addr == connection_to_client_udp->addr()) {
return true;
}
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaNetworking, LogLevel::kError,
"VerifyClientAddr() found mismatch for client "
+ std::to_string(client_id) + ".");
return false;
@ -730,7 +732,7 @@ void ConnectionSet::SetClientInfoFromMasterServer(
const std::string& client_token, PyObject* info_obj) {
// NOLINTNEXTLINE (python doing bitwise math on signed int)
if (!PyDict_Check(info_obj)) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"got non-dict for master-server client info for token " + client_token
+ ": " + Python::ObjToString(info_obj));
return;

View File

@ -144,7 +144,8 @@ void ConnectionToClient::HandleGamePacket(const std::vector<uint8_t>& data) {
}
if (data.empty()) {
Log(LogLevel::kError, "ConnectionToClient got data size 0.");
Log(LogName::kBaNetworking, LogLevel::kError,
"ConnectionToClient got data size 0.");
return;
}
@ -157,7 +158,8 @@ void ConnectionToClient::HandleGamePacket(const std::vector<uint8_t>& data) {
case BA_SCENEPACKET_HANDSHAKE_RESPONSE: {
// We sent the client a handshake and they're responding.
if (data.size() < 3) {
Log(LogLevel::kError, "got invalid BA_SCENEPACKET_HANDSHAKE_RESPONSE");
Log(LogName::kBaNetworking, LogLevel::kError,
"got invalid BA_SCENEPACKET_HANDSHAKE_RESPONSE");
return;
}
@ -350,7 +352,8 @@ void ConnectionToClient::SendScreenMessage(const std::string& s, float r,
void ConnectionToClient::HandleMessagePacket(
const std::vector<uint8_t>& buffer) {
if (buffer.empty()) {
Log(LogLevel::kError, "Got invalid HandleMessagePacket.");
Log(LogName::kBaNetworking, LogLevel::kError,
"Got invalid HandleMessagePacket.");
return;
}
@ -404,7 +407,8 @@ void ConnectionToClient::HandleMessagePacket(
if (b) {
build_number_ = b->valueint;
} else {
Log(LogLevel::kError, "No buildnumber in clientinfo msg.");
Log(LogName::kBaNetworking, LogLevel::kError,
"No buildnumber in clientinfo msg.");
}
// Grab their token (we use this to ask the
@ -413,7 +417,8 @@ void ConnectionToClient::HandleMessagePacket(
if (t) {
token_ = t->valuestring;
} else {
Log(LogLevel::kError, "No token in clientinfo msg.");
Log(LogName::kBaNetworking, LogLevel::kError,
"No token in clientinfo msg.");
}
// Newer clients also pass a peer-hash, which
@ -432,7 +437,7 @@ void ConnectionToClient::HandleMessagePacket(
}
cJSON_Delete(info);
} else {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Got invalid json in clientinfo message: '"
+ std::string(reinterpret_cast<const char*>(&(buffer[1])))
+ "'.");
@ -473,7 +478,7 @@ void ConnectionToClient::HandleMessagePacket(
// we support for game streams vs client-connections. We could disallow
// connections to/from these older peers while still allowing old replays
// to play back.
BA_LOG_ONCE(LogLevel::kError,
BA_LOG_ONCE(LogName::kBaNetworking, LogLevel::kError,
"Received old pre-json player profiles msg; ignoring.");
break;
}
@ -501,7 +506,7 @@ void ConnectionToClient::HandleMessagePacket(
// spamming before we can verify their identities)
if (appmode->require_client_authentication()
&& !got_info_from_master_server_) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Ignoring chat message from peer with no client info.");
SendScreenMessage(R"({"r":"loadingTryAgainText"})", 1, 0, 0);
} else if (last_chat_times_.size() >= 5) {
@ -599,7 +604,8 @@ void ConnectionToClient::HandleMessagePacket(
GetClientInputDevice(buffer[1])) {
int count = static_cast<int>((buffer.size() - 2) / 5);
if ((buffer.size() - 2) % 5 != 0) {
Log(LogLevel::kError, "Error: invalid player-input-commands packet");
Log(LogName::kBaNetworking, LogLevel::kError,
"Error: invalid player-input-commands packet");
break;
}
int index = 2;
@ -617,7 +623,8 @@ void ConnectionToClient::HandleMessagePacket(
case BA_MESSAGE_REMOVE_REMOTE_PLAYER: {
last_remove_player_time_ = g_core->GetAppTimeMillisecs();
if (buffer.size() != 2) {
Log(LogLevel::kError, "Error: invalid remove-remote-player packet");
Log(LogName::kBaNetworking, LogLevel::kError,
"Error: invalid remove-remote-player packet");
break;
}
if (ClientInputDevice* cid = GetClientInputDevice(buffer[1])) {
@ -632,7 +639,7 @@ void ConnectionToClient::HandleMessagePacket(
host_session->RemovePlayer(player);
}
} else {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Unable to get ClientInputDevice for remove-remote-player msg.");
}
}
@ -641,7 +648,8 @@ void ConnectionToClient::HandleMessagePacket(
case BA_MESSAGE_REQUEST_REMOTE_PLAYER: {
if (buffer.size() != 2) {
Log(LogLevel::kError, "Error: invalid remote-player-request packet");
Log(LogName::kBaNetworking, LogLevel::kError,
"Error: invalid remote-player-request packet");
break;
}
@ -652,7 +660,7 @@ void ConnectionToClient::HandleMessagePacket(
// It should have one of our special client delegates attached.
auto* cid_d = dynamic_cast<ClientInputDeviceDelegate*>(&cid->delegate());
if (!cid_d) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Can't get client-input-device-delegate in request-remote-player "
"msg.");
break;
@ -676,7 +684,7 @@ void ConnectionToClient::HandleMessagePacket(
} else {
// Either timed out or have info; let the request go through.
if (still_waiting_for_auth) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Allowing player-request without client\'s master-server "
"info (build "
+ std::to_string(build_number_) + ")");
@ -685,7 +693,7 @@ void ConnectionToClient::HandleMessagePacket(
}
}
} else {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"ConnectionToClient got remote player"
" request but have no host session");
}
@ -699,9 +707,9 @@ void ConnectionToClient::HandleMessagePacket(
if (multipart_buffer_size() > 50000) {
// Its not actually unknown but shhh don't tell the hackers...
SendScreenMessage(R"({"r":"errorUnknownText"})", 1, 0, 0);
Log(LogLevel::kError, "Client data limit exceeded by '"
+ peer_spec().GetShortName()
+ "'; kicking.");
Log(LogName::kBaNetworking, LogLevel::kError,
"Client data limit exceeded by '" + peer_spec().GetShortName()
+ "'; kicking.");
appmode->BanPlayer(peer_spec(), 1000 * 60);
Error("");
return;
@ -792,8 +800,9 @@ void ConnectionToClient::HandleMasterServerClientInfo(PyObject* info_obj) {
"{\"t\":[\"serverResponses\","
"\"Your account was rejected. Are you signed in?\"]}",
1, 0, 0);
Log(LogLevel::kError, "Master server found no valid account for '"
+ peer_spec().GetShortName() + "'; kicking.");
Log(LogName::kBaNetworking, LogLevel::kError,
"Master server found no valid account for '"
+ peer_spec().GetShortName() + "'; kicking.");
// Not benning anymore. People were exploiting this by impersonating
// other players using their public ids to get them banned from

View File

@ -72,7 +72,8 @@ void ConnectionToClientUDP::HandleGamePacket(
void ConnectionToClientUDP::Die() {
if (did_die_) {
Log(LogLevel::kError, "Posting multiple die messages; probably not good.");
Log(LogName::kBaNetworking, LogLevel::kError,
"Posting multiple die messages; probably not good.");
return;
}
// this will actually clear the object..

View File

@ -250,7 +250,7 @@ void ConnectionToHost::HandleGamePacket(const std::vector<uint8_t>& data) {
g_base->python->GetRawConfigValue("Player Profiles");
PythonRef empty_dict;
if (!profiles) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"No profiles found; sending empty list to host");
empty_dict.Steal(PyDict_New());
profiles = empty_dict.Get();
@ -265,7 +265,7 @@ void ConnectionToHost::HandleGamePacket(const std::vector<uint8_t>& data) {
.Get(core::CorePython::ObjID::kJsonDumpsCall)
.Call(args, keywds);
if (!results.Exists()) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Error getting json dump of local profiles");
} else {
try {
@ -276,14 +276,14 @@ void ConnectionToHost::HandleGamePacket(const std::vector<uint8_t>& data) {
memcpy(&(msg[1]), &s[0], s.size());
SendReliableMessage(msg);
} catch (const std::exception& e) {
Log(LogLevel::kError,
std::string("exc sending player profiles to host: ")
Log(LogName::kBaNetworking, LogLevel::kError,
std::string("Error sending player profiles to host: ")
+ e.what());
}
}
}
} else {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Connected to old protocol; can't send player profiles");
}
}
@ -311,7 +311,8 @@ void ConnectionToHost::HandleMessagePacket(const std::vector<uint8_t>& buffer) {
assert(g_base->InLogicThread());
if (buffer.empty()) {
Log(LogLevel::kError, "Got invalid HandleMessagePacket");
Log(LogName::kBaNetworking, LogLevel::kError,
"Got invalid HandleMessagePacket");
return;
}
@ -335,7 +336,8 @@ void ConnectionToHost::HandleMessagePacket(const std::vector<uint8_t>& buffer) {
if (b) {
build_number_ = b->valueint;
} else {
Log(LogLevel::kError, "no buildnumber in hostinfo msg");
Log(LogName::kBaNetworking, LogLevel::kError,
"no buildnumber in hostinfo msg");
}
// Party name.
cJSON* n = cJSON_GetObjectItem(info, "n");
@ -344,7 +346,8 @@ void ConnectionToHost::HandleMessagePacket(const std::vector<uint8_t>& buffer) {
}
cJSON_Delete(info);
} else {
Log(LogLevel::kError, "got invalid json in hostinfo message");
Log(LogName::kBaNetworking, LogLevel::kError,
"got invalid json in hostinfo message");
}
}
got_host_info_ = true;
@ -440,7 +443,8 @@ void ConnectionToHost::HandleMessagePacket(const std::vector<uint8_t>& buffer) {
case BA_MESSAGE_ATTACH_REMOTE_PLAYER_2: {
// New-style packet which includes a 32-bit player_id.
if (buffer.size() != 6) {
Log(LogLevel::kError, "Invalid attach-remote-player-2 msg");
Log(LogName::kBaNetworking, LogLevel::kError,
"Invalid attach-remote-player-2 msg");
break;
}
@ -457,7 +461,7 @@ void ConnectionToHost::HandleMessagePacket(const std::vector<uint8_t>& buffer) {
delegate->AttachToRemotePlayer(this,
static_cast_check_fit<int>(player_id));
} else {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"InputDevice does not have a SceneV1 delegate as expected "
"(loc1).");
}
@ -476,7 +480,8 @@ void ConnectionToHost::HandleMessagePacket(const std::vector<uint8_t>& buffer) {
// public servers.
// TODO(ericf): can remove this once back-compat-protocol > 29.
if (buffer.size() != 3) {
Log(LogLevel::kError, "Invalid attach-remote-player msg.");
Log(LogName::kBaNetworking, LogLevel::kError,
"Invalid attach-remote-player msg.");
break;
}
@ -490,7 +495,7 @@ void ConnectionToHost::HandleMessagePacket(const std::vector<uint8_t>& buffer) {
&input_device->delegate())) {
delegate->AttachToRemotePlayer(this, buffer[2]);
} else {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"InputDevice does not have a SceneV1 delegate as expected "
"(loc2).");
}
@ -508,7 +513,8 @@ void ConnectionToHost::HandleMessagePacket(const std::vector<uint8_t>& buffer) {
case BA_MESSAGE_DETACH_REMOTE_PLAYER: {
if (buffer.size() != 2) {
Log(LogLevel::kError, "Invalid detach-remote-player msg");
Log(LogName::kBaNetworking, LogLevel::kError,
"Invalid detach-remote-player msg");
break;
}
// Server is telling us that our local input device is no longer
@ -532,7 +538,7 @@ void ConnectionToHost::HandleMessagePacket(const std::vector<uint8_t>& buffer) {
// be cleared out at this point. Just complain if that's not
// the case.
if (connection_to_host != nullptr) {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"InputDevice does not have a SceneV1 delegate as expected "
"(loc3).");
}

View File

@ -125,7 +125,8 @@ void ConnectionToHostUDP::Update() {
// departure before doing this when possible.
void ConnectionToHostUDP::Die() {
if (did_die_) {
Log(LogLevel::kError, "Posting multiple die messages; probably not good.");
Log(LogName::kBaNetworking, LogLevel::kError,
"Posting multiple die messages; probably not good.");
return;
}
if (auto* appmode = classic::ClassicAppMode::GetActiveOrWarn()) {
@ -133,7 +134,7 @@ void ConnectionToHostUDP::Die() {
appmode->connections()->PushDisconnectedFromHostCall();
did_die_ = true;
} else {
Log(LogLevel::kError,
Log(LogName::kBaNetworking, LogLevel::kError,
"Running update for non-current host-connection; shouldn't "
"happen.");
}

View File

@ -136,14 +136,14 @@ class Dynamics::Impl_ {
Dynamics::Dynamics(Scene* scene_in)
: scene_(scene_in),
collision_cache_(new base::CollisionCache()),
collision_cache_(std::make_unique<base::CollisionCache>()),
impl_(std::make_unique<Impl_>(this)) {
ResetODE_();
}
Dynamics::~Dynamics() {
if (in_process_) {
Log(LogLevel::kError,
Log(LogName::kBa, LogLevel::kError,
"Dynamics going down within Process() call;"
" should not happen.");
}

Some files were not shown because too many files have changed in this diff Show More