mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-06 07:23:37 +08:00
Merge branch 'efroemling:master' into master
This commit is contained in:
commit
12b8dec9d0
56
.efrocachemap
generated
56
.efrocachemap
generated
@ -4072,26 +4072,26 @@
|
|||||||
"build/assets/workspace/ninjafightplug.py": "https://files.ballistica.net/cache/ba1/c5/09/4f10b8a21ba87aa5509cff7a164b",
|
"build/assets/workspace/ninjafightplug.py": "https://files.ballistica.net/cache/ba1/c5/09/4f10b8a21ba87aa5509cff7a164b",
|
||||||
"build/assets/workspace/onslaughtplug.py": "https://files.ballistica.net/cache/ba1/ff/0a/a354984f9c074dab0676ac7e4877",
|
"build/assets/workspace/onslaughtplug.py": "https://files.ballistica.net/cache/ba1/ff/0a/a354984f9c074dab0676ac7e4877",
|
||||||
"build/assets/workspace/runaroundplug.py": "https://files.ballistica.net/cache/ba1/2a/1c/9ee5db6d1bceca7fa6638fb8abde",
|
"build/assets/workspace/runaroundplug.py": "https://files.ballistica.net/cache/ba1/2a/1c/9ee5db6d1bceca7fa6638fb8abde",
|
||||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/02/08/b2319162d3e45bdbf9b6e60157c8",
|
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/2f/be/56cbff27830a18d6d60ef31c1cdd",
|
||||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/e1/a7/7bd6d0e731eb831b298a4400b835",
|
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/f9/e1/344297c240047057658d77dab2c3",
|
||||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/d4/b1/e6023d13f8d5e90fe9541a290e4b",
|
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/df/1e/0e166ac6bde0400abf6cf238d4f5",
|
||||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/3a/52/3e0cd585d0d6739b01fe8ec9032e",
|
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/cd/5f/62fa669b1054034a39d501ddc8f3",
|
||||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/50/c8/52c1f1c8467ea32056df8928e046",
|
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/a0/c6/17efa1b0fa2d708d6875a57e7d48",
|
||||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/a8/2e/3a4b6faa127cf64ab8a7760433e7",
|
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/ef/ea/806a19fe00441dc382954a3f3080",
|
||||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/d1/57/9ae52124b55a6b1f3f5f4cba7216",
|
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/93/6e/22f7fc9f33056a672f58bfbe8402",
|
||||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/64/5b/fc659b6628076b67f491ca62b174",
|
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/40/e8/03cace193459c0635f1342b28b53",
|
||||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/3f/4d/9711985938fb8bd5041dc55de46e",
|
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/5a/17/125467b6c2b884e96a5f255466a6",
|
||||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/19/3d/c3a7f04293dae053b57fe06ffe3e",
|
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/23/af/cd64e4cdd02aed0f7c55167fb994",
|
||||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/69/56/cc294914a71932cb75beb2bb3094",
|
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/11/bc/b5de2f3ea4f68f420efd8e2f8672",
|
||||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/9e/3c/7804a6c319e322f77135f24999e8",
|
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/8e/b1/7e170050323d9e08a5387fb61728",
|
||||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/a7/4e/a64a4b500335fcdb8ae460a60416",
|
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/12/89/996eb56a1eac10bc5eef98ceb307",
|
||||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/d4/b6/b62a890f316e8a886f49bd576c33",
|
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/4f/61/3ea177ccbfca5b78faacd6106324",
|
||||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/85/2d/328ea96e4729a7f378803c05c60e",
|
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/a0/e8/ec660025b4b61eb3f105fbe3915a",
|
||||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/c6/3e/384a51739fb898ce03e88fd165e9",
|
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/87/9e/f60d6c7c8097e91f1b75432a96fd",
|
||||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/5d/0f/ae0078422cbfa2030501db9bf0b5",
|
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/80/59/9f5d6da1bfc7e8502ff8faf98371",
|
||||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/97/91/9a9b875d865949c9d6e28b327b86",
|
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/87/3e/b431a2c8ff6a6ab647772c2874d8",
|
||||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/90/2c/1520b8c574430c4dd8168aa46a9f",
|
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/1c/09/b6bcc16ecdd3b3bde138a7975f84",
|
||||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/c1/f0/e3ff659748399873acb4ede80ffd",
|
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/3c/9e/aae04414e59968b1200e45dc490a",
|
||||||
"build/prefab/lib/linux_arm64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/58/55/b6ae6dd4f3615fa87bb170a43233",
|
"build/prefab/lib/linux_arm64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/58/55/b6ae6dd4f3615fa87bb170a43233",
|
||||||
"build/prefab/lib/linux_arm64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/b9/f8/37285d0ced7794a82534d13c33ac",
|
"build/prefab/lib/linux_arm64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/b9/f8/37285d0ced7794a82534d13c33ac",
|
||||||
"build/prefab/lib/linux_arm64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/c7/cc/0c5f0afbfa0ddabaea8d5838562a",
|
"build/prefab/lib/linux_arm64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/c7/cc/0c5f0afbfa0ddabaea8d5838562a",
|
||||||
@ -4108,14 +4108,14 @@
|
|||||||
"build/prefab/lib/mac_x86_64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/96/2e/1b0ba43fe24fe9cc223a434db647",
|
"build/prefab/lib/mac_x86_64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/96/2e/1b0ba43fe24fe9cc223a434db647",
|
||||||
"build/prefab/lib/mac_x86_64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/f3/83/581b7df96f6516032a0747b83e15",
|
"build/prefab/lib/mac_x86_64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/f3/83/581b7df96f6516032a0747b83e15",
|
||||||
"build/prefab/lib/mac_x86_64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/6a/6d/7aaf7617929eeff41bc5a574e6c8",
|
"build/prefab/lib/mac_x86_64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/6a/6d/7aaf7617929eeff41bc5a574e6c8",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/c3/00/abea5335d9f30806405451985391",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/cd/49/d11935a48d1d6e2847ab6a51b4fa",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/bf/f6/a0f57ca4714cdada3469795efa70",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/a1/8a/3b50352ea71fa172f5e32fb60005",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/97/ed/00e71906a026a8b16ed733250177",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/f0/3c/9e1731eaebd85e6b70ac00113f0a",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/78/5c/9c421525f6a3ed8890d67c0067c0",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/6d/5e/4fa8e18fb7a5e1d41e214a354081",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/74/33/b42b6e241fa782f6a82292da5fc7",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/25/21/98f151d2018cb4394cf1b533afd8",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/4d/f3/0a55b91570b2d9eb40d75317ae3a",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/23/53/214f66c1cb5aeace50a7ecc94572",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/50/b4/3485d00c1b200dc753a9bef302c3",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/92/54/9be16e024bf4a6bc1015c487402c",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/cb/27/82502b5ccea9a47d368e6f8c8c50",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/42/ae/47ec74d1efe9b02bf7fc88a310fb",
|
||||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "https://files.ballistica.net/cache/ba1/52/c6/c11130af7b10d6c0321add5518fa",
|
"src/assets/ba_data/python/babase/_mgen/__init__.py": "https://files.ballistica.net/cache/ba1/52/c6/c11130af7b10d6c0321add5518fa",
|
||||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "https://files.ballistica.net/cache/ba1/38/c3/1dedd5e74f2508efc5974c8815a1",
|
"src/assets/ba_data/python/babase/_mgen/enums.py": "https://files.ballistica.net/cache/ba1/38/c3/1dedd5e74f2508efc5974c8815a1",
|
||||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "https://files.ballistica.net/cache/ba1/75/9f/bcf597b362c9f2480cb348188bdd",
|
"src/ballistica/base/mgen/pyembed/binding_base.inc": "https://files.ballistica.net/cache/ba1/75/9f/bcf597b362c9f2480cb348188bdd",
|
||||||
|
|||||||
16
CHANGELOG.md
16
CHANGELOG.md
@ -1,4 +1,4 @@
|
|||||||
### 1.7.20 (build 21071, api 8, 2023-06-07)
|
### 1.7.20 (build 21079, api 8, 2023-06-08)
|
||||||
|
|
||||||
- This seems like a good time for a `refactoring` release in anticipation of
|
- This seems like a good time for a `refactoring` release in anticipation of
|
||||||
changes coming in 1.8. Basically this means that a lot of things will be
|
changes coming in 1.8. Basically this means that a lot of things will be
|
||||||
@ -299,6 +299,20 @@
|
|||||||
(thanks for the heads- up SEBASTIAN2059)
|
(thanks for the heads- up SEBASTIAN2059)
|
||||||
- (build 21070) Fixed an issue where teams series would incorrectly end after 1
|
- (build 21070) Fixed an issue where teams series would incorrectly end after 1
|
||||||
round (thanks for the heads up SEBASTIAN2059)
|
round (thanks for the heads up SEBASTIAN2059)
|
||||||
|
- (build 21072) Fixed a crash drawing a terrain node with no texture set.
|
||||||
|
- (build 21073) Stack traces are now implemented under windows so should show up
|
||||||
|
for fatal errors and whatnot. Also fatal error logging now mentions when stack
|
||||||
|
traces are not available.
|
||||||
|
- (build 21074) Added `babase.native_stack_trace()` to fetch native stack traces
|
||||||
|
as strings.
|
||||||
|
- (build 21076) Hopefully fixed a 'file in use' error for `_appstate_dump_tb` on
|
||||||
|
windows. Please holler if you are still seeing this. This file gets written
|
||||||
|
for debugging whenever the logic thread remains unresponsive for several
|
||||||
|
seconds.
|
||||||
|
- (build 21078) Custom system scripts dirs works again (complete copies of app
|
||||||
|
system scripts living in your mods directory under `sys/$(YOUR_APP_VERSION)`.
|
||||||
|
Tools for creating/destroying these setups are now at `babase.modutils` (they
|
||||||
|
had been placed under bauiv1 but that was just silly).
|
||||||
|
|
||||||
### 1.7.19 (build 20997, api 7, 2023-01-19)
|
### 1.7.19 (build 20997, api 7, 2023-01-19)
|
||||||
|
|
||||||
|
|||||||
4
Makefile
4
Makefile
@ -138,13 +138,13 @@ meta-clean:
|
|||||||
# (except for a few things such as localconfig.json).
|
# (except for a few things such as localconfig.json).
|
||||||
clean:
|
clean:
|
||||||
$(CHECK_CLEAN_SAFETY)
|
$(CHECK_CLEAN_SAFETY)
|
||||||
rm -rf build
|
rm -rf build # Handle this part ourself; can confuse git.
|
||||||
git clean -dfx $(ROOT_CLEAN_IGNORES)
|
git clean -dfx $(ROOT_CLEAN_IGNORES)
|
||||||
|
|
||||||
# Show what clean would delete without actually deleting it.
|
# Show what clean would delete without actually deleting it.
|
||||||
clean-list:
|
clean-list:
|
||||||
$(CHECK_CLEAN_SAFETY)
|
$(CHECK_CLEAN_SAFETY)
|
||||||
@echo Would remove build # We do this ourself; not git.
|
@echo Would remove build # Handle this part ourself; can confuse git.
|
||||||
git clean -dnx $(ROOT_CLEAN_IGNORES)
|
git clean -dnx $(ROOT_CLEAN_IGNORES)
|
||||||
|
|
||||||
# Build/update dummy python modules.
|
# Build/update dummy python modules.
|
||||||
|
|||||||
@ -28,6 +28,7 @@
|
|||||||
"ba_data/python/babase/__pycache__/_text.cpython-311.opt-1.pyc",
|
"ba_data/python/babase/__pycache__/_text.cpython-311.opt-1.pyc",
|
||||||
"ba_data/python/babase/__pycache__/_workspace.cpython-311.opt-1.pyc",
|
"ba_data/python/babase/__pycache__/_workspace.cpython-311.opt-1.pyc",
|
||||||
"ba_data/python/babase/__pycache__/internal.cpython-311.opt-1.pyc",
|
"ba_data/python/babase/__pycache__/internal.cpython-311.opt-1.pyc",
|
||||||
|
"ba_data/python/babase/__pycache__/modutils.cpython-311.opt-1.pyc",
|
||||||
"ba_data/python/babase/_accountv2.py",
|
"ba_data/python/babase/_accountv2.py",
|
||||||
"ba_data/python/babase/_app.py",
|
"ba_data/python/babase/_app.py",
|
||||||
"ba_data/python/babase/_appcomponent.py",
|
"ba_data/python/babase/_appcomponent.py",
|
||||||
@ -58,6 +59,7 @@
|
|||||||
"ba_data/python/babase/_text.py",
|
"ba_data/python/babase/_text.py",
|
||||||
"ba_data/python/babase/_workspace.py",
|
"ba_data/python/babase/_workspace.py",
|
||||||
"ba_data/python/babase/internal.py",
|
"ba_data/python/babase/internal.py",
|
||||||
|
"ba_data/python/babase/modutils.py",
|
||||||
"ba_data/python/baclassic/__init__.py",
|
"ba_data/python/baclassic/__init__.py",
|
||||||
"ba_data/python/baclassic/__pycache__/__init__.cpython-311.opt-1.pyc",
|
"ba_data/python/baclassic/__pycache__/__init__.cpython-311.opt-1.pyc",
|
||||||
"ba_data/python/baclassic/__pycache__/_accountv1.cpython-311.opt-1.pyc",
|
"ba_data/python/baclassic/__pycache__/_accountv1.cpython-311.opt-1.pyc",
|
||||||
@ -346,10 +348,8 @@
|
|||||||
"ba_data/python/bauiv1/__init__.py",
|
"ba_data/python/bauiv1/__init__.py",
|
||||||
"ba_data/python/bauiv1/__pycache__/__init__.cpython-311.opt-1.pyc",
|
"ba_data/python/bauiv1/__pycache__/__init__.cpython-311.opt-1.pyc",
|
||||||
"ba_data/python/bauiv1/__pycache__/_hooks.cpython-311.opt-1.pyc",
|
"ba_data/python/bauiv1/__pycache__/_hooks.cpython-311.opt-1.pyc",
|
||||||
"ba_data/python/bauiv1/__pycache__/modutils.cpython-311.opt-1.pyc",
|
|
||||||
"ba_data/python/bauiv1/__pycache__/onscreenkeyboard.cpython-311.opt-1.pyc",
|
"ba_data/python/bauiv1/__pycache__/onscreenkeyboard.cpython-311.opt-1.pyc",
|
||||||
"ba_data/python/bauiv1/_hooks.py",
|
"ba_data/python/bauiv1/_hooks.py",
|
||||||
"ba_data/python/bauiv1/modutils.py",
|
|
||||||
"ba_data/python/bauiv1/onscreenkeyboard.py",
|
"ba_data/python/bauiv1/onscreenkeyboard.py",
|
||||||
"ba_data/python/bauiv1/ui/__init__.py",
|
"ba_data/python/bauiv1/ui/__init__.py",
|
||||||
"ba_data/python/bauiv1/ui/__pycache__/__init__.cpython-311.opt-1.pyc",
|
"ba_data/python/bauiv1/ui/__pycache__/__init__.cpython-311.opt-1.pyc",
|
||||||
|
|||||||
@ -174,6 +174,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
|||||||
$(BUILD_DIR)/ba_data/python/babase/_text.py \
|
$(BUILD_DIR)/ba_data/python/babase/_text.py \
|
||||||
$(BUILD_DIR)/ba_data/python/babase/_workspace.py \
|
$(BUILD_DIR)/ba_data/python/babase/_workspace.py \
|
||||||
$(BUILD_DIR)/ba_data/python/babase/internal.py \
|
$(BUILD_DIR)/ba_data/python/babase/internal.py \
|
||||||
|
$(BUILD_DIR)/ba_data/python/babase/modutils.py \
|
||||||
$(BUILD_DIR)/ba_data/python/baclassic/__init__.py \
|
$(BUILD_DIR)/ba_data/python/baclassic/__init__.py \
|
||||||
$(BUILD_DIR)/ba_data/python/baclassic/_accountv1.py \
|
$(BUILD_DIR)/ba_data/python/baclassic/_accountv1.py \
|
||||||
$(BUILD_DIR)/ba_data/python/baclassic/_achievement.py \
|
$(BUILD_DIR)/ba_data/python/baclassic/_achievement.py \
|
||||||
@ -310,7 +311,6 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
|||||||
$(BUILD_DIR)/ba_data/python/batemplatefs/_subsystem.py \
|
$(BUILD_DIR)/ba_data/python/batemplatefs/_subsystem.py \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1/__init__.py \
|
$(BUILD_DIR)/ba_data/python/bauiv1/__init__.py \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1/_hooks.py \
|
$(BUILD_DIR)/ba_data/python/bauiv1/_hooks.py \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1/modutils.py \
|
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1/onscreenkeyboard.py \
|
$(BUILD_DIR)/ba_data/python/bauiv1/onscreenkeyboard.py \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1/ui/__init__.py \
|
$(BUILD_DIR)/ba_data/python/bauiv1/ui/__init__.py \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__init__.py \
|
$(BUILD_DIR)/ba_data/python/bauiv1lib/__init__.py \
|
||||||
@ -446,6 +446,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
|||||||
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_text.cpython-311.opt-1.pyc \
|
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_text.cpython-311.opt-1.pyc \
|
||||||
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_workspace.cpython-311.opt-1.pyc \
|
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_workspace.cpython-311.opt-1.pyc \
|
||||||
$(BUILD_DIR)/ba_data/python/babase/__pycache__/internal.cpython-311.opt-1.pyc \
|
$(BUILD_DIR)/ba_data/python/babase/__pycache__/internal.cpython-311.opt-1.pyc \
|
||||||
|
$(BUILD_DIR)/ba_data/python/babase/__pycache__/modutils.cpython-311.opt-1.pyc \
|
||||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/__init__.cpython-311.opt-1.pyc \
|
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/__init__.cpython-311.opt-1.pyc \
|
||||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_accountv1.cpython-311.opt-1.pyc \
|
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_accountv1.cpython-311.opt-1.pyc \
|
||||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_achievement.cpython-311.opt-1.pyc \
|
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_achievement.cpython-311.opt-1.pyc \
|
||||||
@ -582,7 +583,6 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
|||||||
$(BUILD_DIR)/ba_data/python/batemplatefs/__pycache__/_subsystem.cpython-311.opt-1.pyc \
|
$(BUILD_DIR)/ba_data/python/batemplatefs/__pycache__/_subsystem.cpython-311.opt-1.pyc \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/__init__.cpython-311.opt-1.pyc \
|
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/__init__.cpython-311.opt-1.pyc \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_hooks.cpython-311.opt-1.pyc \
|
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_hooks.cpython-311.opt-1.pyc \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/modutils.cpython-311.opt-1.pyc \
|
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/onscreenkeyboard.cpython-311.opt-1.pyc \
|
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/onscreenkeyboard.cpython-311.opt-1.pyc \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1/ui/__pycache__/__init__.cpython-311.opt-1.pyc \
|
$(BUILD_DIR)/ba_data/python/bauiv1/ui/__pycache__/__init__.cpython-311.opt-1.pyc \
|
||||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/__init__.cpython-311.opt-1.pyc \
|
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/__init__.cpython-311.opt-1.pyc \
|
||||||
|
|||||||
@ -34,6 +34,7 @@ from _babase import (
|
|||||||
clipboard_get_text,
|
clipboard_get_text,
|
||||||
clipboard_set_text,
|
clipboard_set_text,
|
||||||
in_logic_thread,
|
in_logic_thread,
|
||||||
|
native_stack_trace,
|
||||||
)
|
)
|
||||||
|
|
||||||
from babase._appintent import AppIntent, AppIntentDefault, AppIntentExec
|
from babase._appintent import AppIntent, AppIntentDefault, AppIntentExec
|
||||||
@ -167,6 +168,7 @@ __all__ = [
|
|||||||
'AppMode',
|
'AppMode',
|
||||||
'AppSubsystem',
|
'AppSubsystem',
|
||||||
'screenmessage',
|
'screenmessage',
|
||||||
|
'native_stack_trace',
|
||||||
]
|
]
|
||||||
|
|
||||||
# We want stuff to show up as babase.Foo instead of babase._sub.Foo.
|
# We want stuff to show up as babase.Foo instead of babase._sub.Foo.
|
||||||
|
|||||||
@ -482,9 +482,12 @@ class App:
|
|||||||
from babase import _asyncio
|
from babase import _asyncio
|
||||||
from babase import _appconfig
|
from babase import _appconfig
|
||||||
from babase._apputils import log_dumped_app_state, AppHealthMonitor
|
from babase._apputils import log_dumped_app_state, AppHealthMonitor
|
||||||
|
import babase._env
|
||||||
|
|
||||||
assert _babase.in_logic_thread()
|
assert _babase.in_logic_thread()
|
||||||
|
|
||||||
|
babase._env.on_app_launching()
|
||||||
|
|
||||||
self._aioloop = _asyncio.setup_asyncio()
|
self._aioloop = _asyncio.setup_asyncio()
|
||||||
self.health_monitor = AppHealthMonitor()
|
self.health_monitor = AppHealthMonitor()
|
||||||
|
|
||||||
|
|||||||
@ -234,7 +234,7 @@ def print_corrupt_file_error() -> None:
|
|||||||
_babase.apptimer(2.0, _babase.getsimplesound('error').play)
|
_babase.apptimer(2.0, _babase.getsimplesound('error').play)
|
||||||
|
|
||||||
|
|
||||||
_tbfiles: list[TextIO] = []
|
_tb_held_files: list[TextIO] = []
|
||||||
|
|
||||||
|
|
||||||
@ioprepped
|
@ioprepped
|
||||||
@ -298,11 +298,12 @@ def dump_app_state(
|
|||||||
os.path.dirname(_babase.app.config_file_path), '_appstate_dump_tb'
|
os.path.dirname(_babase.app.config_file_path), '_appstate_dump_tb'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tbfile = open(tbpath, 'w', encoding='utf-8')
|
||||||
|
|
||||||
# faulthandler needs the raw file descriptor to still be valid when
|
# faulthandler needs the raw file descriptor to still be valid when
|
||||||
# it fires, so stuff this into a global var to make sure it doesn't get
|
# it fires, so stuff this into a global var to make sure it doesn't get
|
||||||
# cleaned up.
|
# cleaned up.
|
||||||
tbfile = open(tbpath, 'w', encoding='utf-8')
|
_tb_held_files.append(tbfile)
|
||||||
_tbfiles.append(tbfile)
|
|
||||||
|
|
||||||
if delay > 0.0:
|
if delay > 0.0:
|
||||||
faulthandler.dump_traceback_later(delay, file=tbfile)
|
faulthandler.dump_traceback_later(delay, file=tbfile)
|
||||||
@ -329,6 +330,14 @@ def log_dumped_app_state() -> None:
|
|||||||
os.path.dirname(_babase.app.config_file_path), '_appstate_dump_md'
|
os.path.dirname(_babase.app.config_file_path), '_appstate_dump_md'
|
||||||
)
|
)
|
||||||
if os.path.exists(mdpath):
|
if os.path.exists(mdpath):
|
||||||
|
# We may be hanging on to open file descriptors for use by
|
||||||
|
# faulthandler (see above). If we are, we need to clear them
|
||||||
|
# now or else we'll get 'file in use' errors below when we
|
||||||
|
# try to unlink it on windows.
|
||||||
|
for heldfile in _tb_held_files:
|
||||||
|
heldfile.close()
|
||||||
|
_tb_held_files.clear()
|
||||||
|
|
||||||
with open(mdpath, 'r', encoding='utf-8') as infile:
|
with open(mdpath, 'r', encoding='utf-8') as infile:
|
||||||
metadata = dataclass_from_json(
|
metadata = dataclass_from_json(
|
||||||
DumpedAppStateMetadata, infile.read()
|
DumpedAppStateMetadata, infile.read()
|
||||||
|
|||||||
@ -64,8 +64,8 @@ def on_native_module_import() -> None:
|
|||||||
def setup_env_for_app_run() -> None:
|
def setup_env_for_app_run() -> None:
|
||||||
"""Set stuff such as interrupt handlers for a run of the app."""
|
"""Set stuff such as interrupt handlers for a run of the app."""
|
||||||
import gc
|
import gc
|
||||||
import _babase
|
|
||||||
import baenv
|
import baenv
|
||||||
|
import _babase
|
||||||
|
|
||||||
global _g_babase_app_started # pylint: disable=global-statement
|
global _g_babase_app_started # pylint: disable=global-statement
|
||||||
|
|
||||||
@ -136,6 +136,21 @@ def setup_env_for_app_run() -> None:
|
|||||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||||
|
|
||||||
|
|
||||||
|
def on_app_launching() -> None:
|
||||||
|
"""Called when the app reaches the launching state."""
|
||||||
|
import _babase
|
||||||
|
import baenv
|
||||||
|
|
||||||
|
assert _babase.in_logic_thread()
|
||||||
|
|
||||||
|
# Let the user know if the app python dir is a custom one.
|
||||||
|
if baenv.g_user_system_scripts_dir is not None:
|
||||||
|
_babase.screenmessage(
|
||||||
|
f"Using user system scripts: '{baenv.g_user_system_scripts_dir}'",
|
||||||
|
color=(0.6, 0.6, 1.0),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _feed_logs_to_babase(log_handler: LogHandler) -> None:
|
def _feed_logs_to_babase(log_handler: LogHandler) -> None:
|
||||||
"""Route log/print output to internal ballistica console/etc."""
|
"""Route log/print output to internal ballistica console/etc."""
|
||||||
import _babase
|
import _babase
|
||||||
|
|||||||
@ -7,7 +7,6 @@ from typing import TYPE_CHECKING
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
import _babase
|
import _babase
|
||||||
import _bauiv1
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
@ -50,7 +49,7 @@ def _request_storage_permission() -> bool:
|
|||||||
from babase._mgen.enums import Permission
|
from babase._mgen.enums import Permission
|
||||||
|
|
||||||
if not _babase.have_permission(Permission.STORAGE):
|
if not _babase.have_permission(Permission.STORAGE):
|
||||||
_bauiv1.getsound('error').play()
|
_babase.getsimplesound('error').play()
|
||||||
_babase.screenmessage(
|
_babase.screenmessage(
|
||||||
Lstr(resource='storagePermissionAccessText'), color=(1, 0, 0)
|
Lstr(resource='storagePermissionAccessText'), color=(1, 0, 0)
|
||||||
)
|
)
|
||||||
@ -103,7 +102,7 @@ def show_user_scripts() -> None:
|
|||||||
|
|
||||||
# On a few platforms we try to open the dir in the UI.
|
# On a few platforms we try to open the dir in the UI.
|
||||||
if app.classic is not None and app.classic.platform in ['mac', 'windows']:
|
if app.classic is not None and app.classic.platform in ['mac', 'windows']:
|
||||||
_bauiv1.open_dir_externally(app.python_directory_user)
|
_babase.open_dir_externally(app.python_directory_user)
|
||||||
|
|
||||||
# Otherwise we just print a pretty version of it.
|
# Otherwise we just print a pretty version of it.
|
||||||
else:
|
else:
|
||||||
@ -111,9 +110,9 @@ def show_user_scripts() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def create_user_system_scripts() -> None:
|
def create_user_system_scripts() -> None:
|
||||||
"""Set up a copy of Ballistica system scripts under your user scripts dir.
|
"""Set up a copy of Ballistica app scripts under user scripts dir.
|
||||||
|
|
||||||
(for editing and experiment with)
|
(for editing and experimenting)
|
||||||
"""
|
"""
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
@ -180,7 +179,7 @@ def delete_user_system_scripts() -> None:
|
|||||||
f' scripts. (use babase.quit() to exit the game)'
|
f' scripts. (use babase.quit() to exit the game)'
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
print('User system scripts not found.')
|
print(f"User system scripts not found at '{path}'.")
|
||||||
|
|
||||||
# If the sys path is empty, kill it.
|
# If the sys path is empty, kill it.
|
||||||
dpath = app.python_directory_user + '/sys'
|
dpath = app.python_directory_user + '/sys'
|
||||||
@ -59,7 +59,7 @@ def run_stress_test(
|
|||||||
round_duration: int = 30,
|
round_duration: int = 30,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Run a stress test."""
|
"""Run a stress test."""
|
||||||
from bauiv1 import modutils
|
from babase import modutils
|
||||||
from babase._general import Call
|
from babase._general import Call
|
||||||
|
|
||||||
_babase.screenmessage(
|
_babase.screenmessage(
|
||||||
|
|||||||
@ -28,11 +28,12 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
# Build number and version of the ballistica binary we expect to be
|
# Build number and version of the ballistica binary we expect to be
|
||||||
# using.
|
# using.
|
||||||
TARGET_BALLISTICA_BUILD = 21071
|
TARGET_BALLISTICA_BUILD = 21079
|
||||||
TARGET_BALLISTICA_VERSION = '1.7.20'
|
TARGET_BALLISTICA_VERSION = '1.7.20'
|
||||||
|
|
||||||
_g_env_config: EnvConfig | None = None
|
_g_env_config: EnvConfig | None = None
|
||||||
g_paths_set_failed = False # pylint: disable=invalid-name
|
g_paths_set_failed = False # pylint: disable=invalid-name
|
||||||
|
g_user_system_scripts_dir: str | None = None # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -43,6 +44,7 @@ class EnvConfig:
|
|||||||
data_dir: str
|
data_dir: str
|
||||||
user_python_dir: str | None
|
user_python_dir: str | None
|
||||||
app_python_dir: str | None
|
app_python_dir: str | None
|
||||||
|
standard_app_python_dir: str
|
||||||
site_python_dir: str | None
|
site_python_dir: str | None
|
||||||
log_handler: LogHandler | None
|
log_handler: LogHandler | None
|
||||||
|
|
||||||
@ -76,6 +78,7 @@ def configure(
|
|||||||
affecting where those modules get loaded from.
|
affecting where those modules get loaded from.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
|
# pylint: disable=too-many-locals
|
||||||
|
|
||||||
global _g_env_config # pylint: disable=global-statement
|
global _g_env_config # pylint: disable=global-statement
|
||||||
if _g_env_config is not None:
|
if _g_env_config is not None:
|
||||||
@ -125,6 +128,10 @@ def configure(
|
|||||||
|
|
||||||
# Ok now Python paths.
|
# Ok now Python paths.
|
||||||
|
|
||||||
|
# By default, app-python-dir is simply ba_data/python under
|
||||||
|
# data-dir.
|
||||||
|
standard_app_python_dir = str(Path(data_dir, 'ba_data', 'python'))
|
||||||
|
|
||||||
# If _babase has already been imported, there's not much we can do
|
# If _babase has already been imported, there's not much we can do
|
||||||
# at this point aside from complain and inform for next time.
|
# at this point aside from complain and inform for next time.
|
||||||
if '_babase' in sys.modules:
|
if '_babase' in sys.modules:
|
||||||
@ -141,10 +148,8 @@ def configure(
|
|||||||
# Ok; _babase hasn't been imported yet so we can muck with
|
# Ok; _babase hasn't been imported yet so we can muck with
|
||||||
# Python paths.
|
# Python paths.
|
||||||
|
|
||||||
# By default, app-python-dir is simply ba_data/python under
|
|
||||||
# data-dir.
|
|
||||||
if app_python_dir is None:
|
if app_python_dir is None:
|
||||||
app_python_dir = str(Path(data_dir, 'ba_data', 'python'))
|
app_python_dir = standard_app_python_dir
|
||||||
|
|
||||||
# Likewise site-python-dir defaults to ba_data/python-site-packages.
|
# Likewise site-python-dir defaults to ba_data/python-site-packages.
|
||||||
if site_python_dir is None:
|
if site_python_dir is None:
|
||||||
@ -156,7 +161,18 @@ def configure(
|
|||||||
if user_python_dir is None:
|
if user_python_dir is None:
|
||||||
user_python_dir = str(Path(config_dir, 'mods'))
|
user_python_dir = str(Path(config_dir, 'mods'))
|
||||||
|
|
||||||
# Ok, now add these to sys.path.
|
# Wherever our user_python_dir is, if we find a sys/FOO dir
|
||||||
|
# under it where FOO matches our version, use that as our
|
||||||
|
# app_python_dir.
|
||||||
|
check_dir = os.path.join(
|
||||||
|
user_python_dir, 'sys', TARGET_BALLISTICA_VERSION
|
||||||
|
)
|
||||||
|
if os.path.isdir(check_dir):
|
||||||
|
global g_user_system_scripts_dir # pylint: disable=global-statement
|
||||||
|
g_user_system_scripts_dir = check_dir
|
||||||
|
app_python_dir = check_dir
|
||||||
|
|
||||||
|
# Ok, now apply these to sys.path.
|
||||||
|
|
||||||
# First off, strip out any instances of the path containing this
|
# First off, strip out any instances of the path containing this
|
||||||
# module. We will probably be re-adding the same path in a
|
# module. We will probably be re-adding the same path in a
|
||||||
@ -194,6 +210,7 @@ def configure(
|
|||||||
data_dir=data_dir,
|
data_dir=data_dir,
|
||||||
user_python_dir=user_python_dir,
|
user_python_dir=user_python_dir,
|
||||||
app_python_dir=app_python_dir,
|
app_python_dir=app_python_dir,
|
||||||
|
standard_app_python_dir=standard_app_python_dir,
|
||||||
site_python_dir=site_python_dir,
|
site_python_dir=site_python_dir,
|
||||||
log_handler=log_handler,
|
log_handler=log_handler,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -188,7 +188,7 @@ class AdvancedSettingsWindow(bui.Window):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _preload_modules() -> None:
|
def _preload_modules() -> None:
|
||||||
"""Preload modules we use (called in bg thread)."""
|
"""Preload modules we use (called in bg thread)."""
|
||||||
from bauiv1 import modutils as _unused2
|
from babase import modutils as _unused2
|
||||||
from bauiv1lib import config as _unused1
|
from bauiv1lib import config as _unused1
|
||||||
from bauiv1lib.settings import vrtesting as _unused3
|
from bauiv1lib.settings import vrtesting as _unused3
|
||||||
from bauiv1lib.settings import nettesting as _unused4
|
from bauiv1lib.settings import nettesting as _unused4
|
||||||
@ -235,7 +235,7 @@ class AdvancedSettingsWindow(bui.Window):
|
|||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
|
|
||||||
from bauiv1lib.config import ConfigCheckBox
|
from bauiv1lib.config import ConfigCheckBox
|
||||||
from bauiv1.modutils import show_user_scripts
|
from babase.modutils import show_user_scripts
|
||||||
|
|
||||||
plus = bui.app.plus
|
plus = bui.app.plus
|
||||||
assert plus is not None
|
assert plus is not None
|
||||||
|
|||||||
@ -134,9 +134,7 @@ void BaseFeatureSet::OnModuleExec(PyObject* module) {
|
|||||||
|
|
||||||
void BaseFeatureSet::OnReachedEndOfBaBaseImport() {
|
void BaseFeatureSet::OnReachedEndOfBaBaseImport() {
|
||||||
assert(!base_import_completed_);
|
assert(!base_import_completed_);
|
||||||
|
|
||||||
g_base->python->ImportPythonAppObjs();
|
g_base->python->ImportPythonAppObjs();
|
||||||
|
|
||||||
base_import_completed_ = true;
|
base_import_completed_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,12 +174,12 @@ void BaseFeatureSet::StartApp() {
|
|||||||
// Read the app config.
|
// Read the app config.
|
||||||
g_base->python->ReadConfig();
|
g_base->python->ReadConfig();
|
||||||
|
|
||||||
// Allow our subsystems to start doing work in their own threads
|
// Allow our subsystems to start doing work in their own threads and
|
||||||
// and communicating with other subsystems. Note that we may still
|
// communicating with other subsystems. Note that we may still want to run
|
||||||
// want to run some things serially here and ordering may be important
|
// some things serially here and ordering may be important (for instance
|
||||||
// (for instance we want to give our main thread a chance to register
|
// we want to give our main thread a chance to register all initial input
|
||||||
// all initial input devices with the logic thread before the logic
|
// devices with the logic thread before the logic thread applies the
|
||||||
// thread applies the current config to them).
|
// current config to them).
|
||||||
|
|
||||||
python->OnMainThreadStartApp();
|
python->OnMainThreadStartApp();
|
||||||
logic->OnMainThreadStartApp();
|
logic->OnMainThreadStartApp();
|
||||||
@ -226,6 +224,7 @@ void BaseFeatureSet::set_app_mode(AppMode* mode) {
|
|||||||
Log(LogLevel::kWarning,
|
Log(LogLevel::kWarning,
|
||||||
"set_app_mode called with already-current app-mode; unexpected.");
|
"set_app_mode called with already-current app-mode; unexpected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Tear down previous mode (if any).
|
// Tear down previous mode (if any).
|
||||||
if (app_mode_) {
|
if (app_mode_) {
|
||||||
@ -275,9 +274,9 @@ void BaseFeatureSet::PrimeAppMainThreadEventPump() {
|
|||||||
auto BaseFeatureSet::HavePlus() -> bool {
|
auto BaseFeatureSet::HavePlus() -> bool {
|
||||||
if (!plus_soft_ && !tried_importing_plus_) {
|
if (!plus_soft_ && !tried_importing_plus_) {
|
||||||
python->SoftImportPlus();
|
python->SoftImportPlus();
|
||||||
// Important to set this *after* import attempt, or a second import attempt
|
// Important to set this *after* import attempt, or a second import
|
||||||
// while first is ongoing can insta-fail. Multiple import attempts shouldn't
|
// attempt while first is ongoing can insta-fail. Multiple import
|
||||||
// hurt anything.
|
// attempts shouldn't hurt anything.
|
||||||
tried_importing_plus_ = true;
|
tried_importing_plus_ = true;
|
||||||
}
|
}
|
||||||
return plus_soft_ != nullptr;
|
return plus_soft_ != nullptr;
|
||||||
@ -292,9 +291,9 @@ void BaseFeatureSet::set_plus(PlusSoftInterface* plus) {
|
|||||||
auto BaseFeatureSet::plus() -> PlusSoftInterface* {
|
auto BaseFeatureSet::plus() -> PlusSoftInterface* {
|
||||||
if (!plus_soft_ && !tried_importing_plus_) {
|
if (!plus_soft_ && !tried_importing_plus_) {
|
||||||
python->SoftImportPlus();
|
python->SoftImportPlus();
|
||||||
// Important to set this *after* import attempt, or a second import attempt
|
// Important to set this *after* import attempt, or a second import
|
||||||
// while first is ongoing can insta-fail. Multiple import attempts shouldn't
|
// attempt while first is ongoing can insta-fail. Multiple import
|
||||||
// hurt anything.
|
// attempts shouldn't hurt anything.
|
||||||
tried_importing_plus_ = true;
|
tried_importing_plus_ = true;
|
||||||
}
|
}
|
||||||
if (!plus_soft_) {
|
if (!plus_soft_) {
|
||||||
@ -306,9 +305,9 @@ auto BaseFeatureSet::plus() -> PlusSoftInterface* {
|
|||||||
auto BaseFeatureSet::HaveClassic() -> bool {
|
auto BaseFeatureSet::HaveClassic() -> bool {
|
||||||
if (!classic_soft_ && !tried_importing_classic_) {
|
if (!classic_soft_ && !tried_importing_classic_) {
|
||||||
python->SoftImportClassic();
|
python->SoftImportClassic();
|
||||||
// Important to set this *after* import attempt, or a second import attempt
|
// Important to set this *after* import attempt, or a second import
|
||||||
// while first is ongoing can insta-fail. Multiple import attempts shouldn't
|
// attempt while first is ongoing can insta-fail. Multiple import
|
||||||
// hurt anything.
|
// attempts shouldn't hurt anything.
|
||||||
tried_importing_classic_ = true;
|
tried_importing_classic_ = true;
|
||||||
}
|
}
|
||||||
return classic_soft_ != nullptr;
|
return classic_soft_ != nullptr;
|
||||||
@ -318,9 +317,9 @@ auto BaseFeatureSet::HaveClassic() -> bool {
|
|||||||
auto BaseFeatureSet::classic() -> ClassicSoftInterface* {
|
auto BaseFeatureSet::classic() -> ClassicSoftInterface* {
|
||||||
if (!classic_soft_ && !tried_importing_classic_) {
|
if (!classic_soft_ && !tried_importing_classic_) {
|
||||||
python->SoftImportClassic();
|
python->SoftImportClassic();
|
||||||
// Important to set this *after* import attempt, or a second import attempt
|
// Important to set this *after* import attempt, or a second import
|
||||||
// while first is ongoing can insta-fail. Multiple import attempts shouldn't
|
// attempt while first is ongoing can insta-fail. Multiple import
|
||||||
// hurt anything.
|
// attempts shouldn't hurt anything.
|
||||||
tried_importing_classic_ = true;
|
tried_importing_classic_ = true;
|
||||||
}
|
}
|
||||||
if (!classic_soft_) {
|
if (!classic_soft_) {
|
||||||
@ -337,9 +336,9 @@ void BaseFeatureSet::set_classic(ClassicSoftInterface* classic) {
|
|||||||
auto BaseFeatureSet::HaveUIV1() -> bool {
|
auto BaseFeatureSet::HaveUIV1() -> bool {
|
||||||
if (!ui_v1_soft_ && !tried_importing_ui_v1_) {
|
if (!ui_v1_soft_ && !tried_importing_ui_v1_) {
|
||||||
python->SoftImportUIV1();
|
python->SoftImportUIV1();
|
||||||
// Important to set this *after* import attempt, or a second import attempt
|
// Important to set this *after* import attempt, or a second import
|
||||||
// while first is ongoing can insta-fail. Multiple import attempts shouldn't
|
// attempt while first is ongoing can insta-fail. Multiple import
|
||||||
// hurt anything.
|
// attempts shouldn't hurt anything.
|
||||||
tried_importing_ui_v1_ = true;
|
tried_importing_ui_v1_ = true;
|
||||||
}
|
}
|
||||||
return ui_v1_soft_ != nullptr;
|
return ui_v1_soft_ != nullptr;
|
||||||
@ -349,9 +348,9 @@ auto BaseFeatureSet::HaveUIV1() -> bool {
|
|||||||
auto BaseFeatureSet::ui_v1() -> UIV1SoftInterface* {
|
auto BaseFeatureSet::ui_v1() -> UIV1SoftInterface* {
|
||||||
if (!ui_v1_soft_ && !tried_importing_ui_v1_) {
|
if (!ui_v1_soft_ && !tried_importing_ui_v1_) {
|
||||||
python->SoftImportUIV1();
|
python->SoftImportUIV1();
|
||||||
// Important to set this *after* import attempt, or a second import attempt
|
// Important to set this *after* import attempt, or a second import
|
||||||
// while first is ongoing can insta-fail. Multiple import attempts shouldn't
|
// attempt while first is ongoing can insta-fail. Multiple import
|
||||||
// hurt anything.
|
// attempts shouldn't hurt anything.
|
||||||
tried_importing_ui_v1_ = true;
|
tried_importing_ui_v1_ = true;
|
||||||
}
|
}
|
||||||
if (!ui_v1_soft_) {
|
if (!ui_v1_soft_) {
|
||||||
@ -380,8 +379,8 @@ auto BaseFeatureSet::GetAppInstanceUUID() -> const std::string& {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!have_app_instance_uuid) {
|
if (!have_app_instance_uuid) {
|
||||||
// As an emergency fallback simply use a single random number.
|
// As an emergency fallback simply use a single random number. We
|
||||||
// We should probably simply disallow this before Python is up.
|
// should probably simply disallow this before Python is up.
|
||||||
Log(LogLevel::kWarning, "GetSessionUUID() using rand fallback.");
|
Log(LogLevel::kWarning, "GetSessionUUID() using rand fallback.");
|
||||||
srand(static_cast<unsigned int>(
|
srand(static_cast<unsigned int>(
|
||||||
core::CorePlatform::GetCurrentMillisecs())); // NOLINT
|
core::CorePlatform::GetCurrentMillisecs())); // NOLINT
|
||||||
|
|||||||
@ -47,7 +47,11 @@ static PyMethodDef PyAppNameDef = {
|
|||||||
static auto PyRunApp(PyObject* self) -> PyObject* {
|
static auto PyRunApp(PyObject* self) -> PyObject* {
|
||||||
BA_PYTHON_TRY;
|
BA_PYTHON_TRY;
|
||||||
|
|
||||||
printf("WOULD RUN!\n");
|
FatalError("NOT WORKING YET; COME BACK SOON.");
|
||||||
|
|
||||||
|
assert(g_base);
|
||||||
|
g_base->RunAppToCompletion();
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
BA_PYTHON_CATCH;
|
BA_PYTHON_CATCH;
|
||||||
}
|
}
|
||||||
@ -203,6 +207,10 @@ static auto PyPushCall(PyObject* self, PyObject* args, PyObject* keywds)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!g_base->logic->event_loop()) {
|
||||||
|
throw Exception("pushcall cannot be used before start-app is called.");
|
||||||
|
}
|
||||||
|
|
||||||
// 'raw' mode does no thread checking and no context saves/restores.
|
// 'raw' mode does no thread checking and no context saves/restores.
|
||||||
if (raw) {
|
if (raw) {
|
||||||
assert(Python::HaveGIL());
|
assert(Python::HaveGIL());
|
||||||
|
|||||||
@ -1383,6 +1383,65 @@ static PyMethodDef PyUnlockAllInputDef = {
|
|||||||
"Resumes normal keyboard, mouse, and gamepad event processing.",
|
"Resumes normal keyboard, mouse, and gamepad event processing.",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --------------------------- native_stack_trace ------------------------------
|
||||||
|
|
||||||
|
static auto PyNativeStackTrace(PyObject* self) -> PyObject* {
|
||||||
|
BA_PYTHON_TRY;
|
||||||
|
assert(g_core);
|
||||||
|
auto* trace = g_core->platform->GetStackTrace();
|
||||||
|
if (!trace) {
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
auto out = trace->FormatForDisplay();
|
||||||
|
delete trace;
|
||||||
|
return PyUnicode_FromString(out.c_str());
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
BA_PYTHON_CATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef PyNativeStackTraceDef = {
|
||||||
|
"native_stack_trace", // name
|
||||||
|
(PyCFunction)PyNativeStackTrace, // method
|
||||||
|
METH_NOARGS, // flags
|
||||||
|
|
||||||
|
"native_stack_trace() -> str | None\n"
|
||||||
|
"\n"
|
||||||
|
"Return a native stack trace as a string, or None if not available.\n"
|
||||||
|
"\n"
|
||||||
|
"Category: **General Utility Functions**\n"
|
||||||
|
"\n"
|
||||||
|
"Stack traces contain different data and formatting across platforms.\n"
|
||||||
|
"Only use them for debugging.",
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------- open_dir_externally ------------------------------
|
||||||
|
|
||||||
|
static auto PyOpenDirExternally(PyObject* self, PyObject* args,
|
||||||
|
PyObject* keywds) -> PyObject* {
|
||||||
|
BA_PYTHON_TRY;
|
||||||
|
char* path = nullptr;
|
||||||
|
static const char* kwlist[] = {"path", nullptr};
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, keywds, "s",
|
||||||
|
const_cast<char**>(kwlist), &path)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
g_core->platform->OpenDirExternally(path);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
BA_PYTHON_CATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef PyOpenDirExternallyDef = {
|
||||||
|
"open_dir_externally", // name
|
||||||
|
(PyCFunction)PyOpenDirExternally, // method
|
||||||
|
METH_VARARGS | METH_KEYWORDS, // flags
|
||||||
|
|
||||||
|
"open_dir_externally(path: str) -> None\n"
|
||||||
|
"\n"
|
||||||
|
"(internal)\n"
|
||||||
|
"\n"
|
||||||
|
"Open the provided dir in the default external app.",
|
||||||
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
auto PythonMethodsMisc::GetMethods() -> std::vector<PyMethodDef> {
|
auto PythonMethodsMisc::GetMethods() -> std::vector<PyMethodDef> {
|
||||||
@ -1436,6 +1495,8 @@ auto PythonMethodsMisc::GetMethods() -> std::vector<PyMethodDef> {
|
|||||||
PySetUpSigIntDef,
|
PySetUpSigIntDef,
|
||||||
PyGetSimpleSoundDef,
|
PyGetSimpleSoundDef,
|
||||||
PyHasTouchScreenDef,
|
PyHasTouchScreenDef,
|
||||||
|
PyNativeStackTraceDef,
|
||||||
|
PyOpenDirExternallyDef,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -123,10 +123,10 @@ void CoreFeatureSet::PostInit() {
|
|||||||
// We can use it to make error messages/etc. more pretty by stripping out
|
// We can use it to make error messages/etc. more pretty by stripping out
|
||||||
// all but sub-project paths.
|
// all but sub-project paths.
|
||||||
const char* f = __FILE__;
|
const char* f = __FILE__;
|
||||||
auto* f_end = strstr(
|
auto* f_end = strstr(f, "src" BA_DIRSLASH "ballistica" BA_DIRSLASH
|
||||||
f, "src" BA_DIRSLASH "ballistica" BA_DIRSLASH "app" BA_DIRSLASH "app.cc");
|
"core" BA_DIRSLASH "core.cc");
|
||||||
if (!f) {
|
if (!f_end) {
|
||||||
Log(LogLevel::kWarning, "Unable to calc project dir from __FILE__.");
|
Log(LogLevel::kWarning, "Unable to calc build source dir from __FILE__.");
|
||||||
} else {
|
} else {
|
||||||
build_src_dir_ = std::string(f).substr(0, f_end - f);
|
build_src_dir_ = std::string(f).substr(0, f_end - f);
|
||||||
}
|
}
|
||||||
@ -146,6 +146,14 @@ void CoreFeatureSet::PostInit() {
|
|||||||
// Grab whatever Python stuff we use.
|
// Grab whatever Python stuff we use.
|
||||||
python->ImportPythonObjs();
|
python->ImportPythonObjs();
|
||||||
|
|
||||||
|
// Normally we wait until babase is imported to push early 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 (!g_core->core_config().hold_early_logs) {
|
||||||
|
python->EnablePythonLoggingCalls();
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: MOVE THIS TO A RUN_APP_TO_COMPLETION() SORT OF PLACE.
|
// FIXME: MOVE THIS TO A RUN_APP_TO_COMPLETION() SORT OF PLACE.
|
||||||
// For now it does the right thing here since all we have is monolithic
|
// For now it does the right thing here since all we have is monolithic
|
||||||
// builds but this will need to account for more situations later.
|
// builds but this will need to account for more situations later.
|
||||||
|
|||||||
@ -251,32 +251,6 @@ auto CorePlatform::GetDefaultVolatileDataDirectory() -> std::string {
|
|||||||
auto CorePlatform::GetAppPythonDirectory() -> std::optional<std::string> {
|
auto CorePlatform::GetAppPythonDirectory() -> std::optional<std::string> {
|
||||||
BA_PRECONDITION(have_ba_env_vals_);
|
BA_PRECONDITION(have_ba_env_vals_);
|
||||||
return ba_env_app_python_dir_;
|
return ba_env_app_python_dir_;
|
||||||
|
|
||||||
// TODO(ericf) - recreate this behavior within baenv.
|
|
||||||
// // If there is a sys/VERSION in the user-python dir we use that.
|
|
||||||
// app_python_dir_ = GetUserPythonDirectoryMonolithicDefault() + BA_DIRSLASH
|
|
||||||
// + "sys" + BA_DIRSLASH + kEngineVersion;
|
|
||||||
|
|
||||||
// // Fall back to our default if that doesn't exist.
|
|
||||||
// if (FilePathExists(app_python_dir_)) {
|
|
||||||
// using_custom_app_python_dir_ = true;
|
|
||||||
// Log(LogLevel::kInfo,
|
|
||||||
// "Using custom app Python path: '"
|
|
||||||
// + (GetUserPythonDirectoryMonolithicDefault() + BA_DIRSLASH +
|
|
||||||
// "sys"
|
|
||||||
// + BA_DIRSLASH + kEngineVersion)
|
|
||||||
// + "'.");
|
|
||||||
|
|
||||||
// } else {
|
|
||||||
// // Special case: if CWD is '.', omit the './' for a prettier path.
|
|
||||||
// app_python_dir_ = std::string("ba_data") + BA_DIRSLASH + "python";
|
|
||||||
// auto data_dir = GetDataDirectoryMonolithicDefault();
|
|
||||||
// if (data_dir != ".") {
|
|
||||||
// app_python_dir_ = data_dir + BA_DIRSLASH + app_python_dir_;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return app_python_dir_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CorePlatform::GetSitePythonDirectory() -> std::optional<std::string> {
|
auto CorePlatform::GetSitePythonDirectory() -> std::optional<std::string> {
|
||||||
@ -1058,10 +1032,10 @@ class PlatformStackTraceExecInfo : public PlatformStackTrace {
|
|||||||
// The stack trace should capture the stack state immediately upon
|
// The stack trace should capture the stack state immediately upon
|
||||||
// construction but should do the bare minimum amount of work to store it. Any
|
// construction but should do the bare minimum amount of work to store it. Any
|
||||||
// expensive operations such as symbolification should be deferred until
|
// expensive operations such as symbolification should be deferred until
|
||||||
// GetDescription().
|
// FormatForDisplay().
|
||||||
PlatformStackTraceExecInfo() { nsize_ = backtrace(array_, kMaxStackLevels); }
|
PlatformStackTraceExecInfo() { nsize_ = backtrace(array_, kMaxStackLevels); }
|
||||||
|
|
||||||
auto GetDescription() noexcept -> std::string override {
|
auto FormatForDisplay() noexcept -> std::string override {
|
||||||
try {
|
try {
|
||||||
std::string s;
|
std::string s;
|
||||||
char** symbols = backtrace_symbols(array_, nsize_);
|
char** symbols = backtrace_symbols(array_, nsize_);
|
||||||
@ -1078,7 +1052,7 @@ class PlatformStackTraceExecInfo : public PlatformStackTrace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto copy() const noexcept -> PlatformStackTrace* override {
|
auto Copy() const noexcept -> PlatformStackTrace* override {
|
||||||
try {
|
try {
|
||||||
auto s = new PlatformStackTraceExecInfo(*this);
|
auto s = new PlatformStackTraceExecInfo(*this);
|
||||||
|
|
||||||
@ -1250,6 +1224,14 @@ void CorePlatform::SetBaEnvVals(const PythonRef& ref) {
|
|||||||
ba_env_site_python_dir_ =
|
ba_env_site_python_dir_ =
|
||||||
ref.GetAttr("site_python_dir").ValueAsOptionalString();
|
ref.GetAttr("site_python_dir").ValueAsOptionalString();
|
||||||
|
|
||||||
|
// Consider app-python-dir 'custom' if baenv provided a value
|
||||||
|
// for it AND that value differs from baenv's default.
|
||||||
|
auto standard_app_python_dir =
|
||||||
|
ref.GetAttr("standard_app_python_dir").ValueAsString();
|
||||||
|
using_custom_app_python_dir_ =
|
||||||
|
ba_env_app_python_dir_.has_value()
|
||||||
|
&& *ba_env_app_python_dir_ != standard_app_python_dir;
|
||||||
|
|
||||||
// Ok, now look for the existence of ba_data in the dir we've got.
|
// Ok, now look for the existence of ba_data in the dir we've got.
|
||||||
auto fullpath = ba_env_data_dir_ + BA_DIRSLASH + "ba_data";
|
auto fullpath = ba_env_data_dir_ + BA_DIRSLASH + "ba_data";
|
||||||
if (!FilePathExists(fullpath)) {
|
if (!FilePathExists(fullpath)) {
|
||||||
|
|||||||
@ -19,18 +19,18 @@ namespace ballistica::core {
|
|||||||
/// trace classes should capture the stack state immediately upon
|
/// trace classes should capture the stack state immediately upon
|
||||||
/// construction but should do the bare minimum amount of work to store it.
|
/// construction but should do the bare minimum amount of work to store it.
|
||||||
/// Any expensive operations such as symbolification should be deferred
|
/// Any expensive operations such as symbolification should be deferred
|
||||||
/// until GetDescription().
|
/// until FormatForDisplay().
|
||||||
class PlatformStackTrace {
|
class PlatformStackTrace {
|
||||||
public:
|
public:
|
||||||
virtual ~PlatformStackTrace() = default;
|
virtual ~PlatformStackTrace() = default;
|
||||||
|
|
||||||
// Return a human readable version of the trace (with symbolification if
|
// Return a human readable version of the trace (with symbolification if
|
||||||
// available).
|
// available).
|
||||||
virtual auto GetDescription() noexcept -> std::string = 0;
|
virtual auto FormatForDisplay() noexcept -> std::string = 0;
|
||||||
|
|
||||||
// Should return a copy of itself allocated via new() (or nullptr if not
|
// Should return a copy of itself allocated via new() (or nullptr if not
|
||||||
// possible).
|
// possible).
|
||||||
virtual auto copy() const noexcept -> PlatformStackTrace* = 0;
|
virtual auto Copy() const noexcept -> PlatformStackTrace* = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This class attempts to abstract away most platform-specific
|
/// This class attempts to abstract away most platform-specific
|
||||||
@ -362,8 +362,10 @@ class CorePlatform {
|
|||||||
|
|
||||||
#pragma mark ERRORS & DEBUGGING ------------------------------------------------
|
#pragma mark ERRORS & DEBUGGING ------------------------------------------------
|
||||||
|
|
||||||
/// Should return a subclass of PlatformStackTrace allocated via new.
|
/// Should return a subclass of PlatformStackTrace allocated via new. It
|
||||||
/// Platforms with no meaningful stack trace functionality can return nullptr.
|
/// is up to the caller to call delete on the returned trace when done
|
||||||
|
/// with it. Platforms with no meaningful stack trace functionality can
|
||||||
|
/// return nullptr.
|
||||||
virtual auto GetStackTrace() -> PlatformStackTrace*;
|
virtual auto GetStackTrace() -> PlatformStackTrace*;
|
||||||
|
|
||||||
// Called during stress testing.
|
// Called during stress testing.
|
||||||
@ -544,7 +546,7 @@ class CorePlatform {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_stdin_a_terminal_{};
|
bool is_stdin_a_terminal_{};
|
||||||
bool using_custom_app_python_dir_{}; // FIXME not wired up currently.
|
bool using_custom_app_python_dir_{};
|
||||||
bool have_has_touchscreen_value_{};
|
bool have_has_touchscreen_value_{};
|
||||||
bool have_touchscreen_{};
|
bool have_touchscreen_{};
|
||||||
bool is_tegra_k1_{};
|
bool is_tegra_k1_{};
|
||||||
|
|||||||
@ -12,6 +12,13 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sysinfoapi.h>
|
#include <sysinfoapi.h>
|
||||||
|
|
||||||
|
/* clang-format off */
|
||||||
|
// Builds fail if this is further up.
|
||||||
|
// This define gives us the unicode version.
|
||||||
|
#define DBGHELP_TRANSLATE_TCHAR
|
||||||
|
#include <dbghelp.h>
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
#pragma comment(lib, "Rpcrt4.lib")
|
#pragma comment(lib, "Rpcrt4.lib")
|
||||||
#pragma comment(lib, "ws2_32.lib")
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
#pragma comment(lib, "iphlpapi.lib")
|
#pragma comment(lib, "iphlpapi.lib")
|
||||||
@ -20,7 +27,9 @@
|
|||||||
#else
|
#else
|
||||||
#pragma comment(lib, "python311.lib")
|
#pragma comment(lib, "python311.lib")
|
||||||
#endif
|
#endif
|
||||||
|
#pragma comment(lib, "DbgHelp.lib")
|
||||||
|
|
||||||
|
// GUI Only Stuff.
|
||||||
#if !BA_HEADLESS_BUILD
|
#if !BA_HEADLESS_BUILD
|
||||||
#pragma comment(lib, "libogg.lib")
|
#pragma comment(lib, "libogg.lib")
|
||||||
#pragma comment(lib, "libvorbis.lib")
|
#pragma comment(lib, "libvorbis.lib")
|
||||||
@ -31,6 +40,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
|
#include "ballistica/shared/generic/utils.h"
|
||||||
#include "ballistica/shared/networking/networking_sys.h"
|
#include "ballistica/shared/networking/networking_sys.h"
|
||||||
|
|
||||||
#if !defined(UNICODE) || !defined(_UNICODE)
|
#if !defined(UNICODE) || !defined(_UNICODE)
|
||||||
@ -39,6 +49,130 @@
|
|||||||
|
|
||||||
namespace ballistica::core {
|
namespace ballistica::core {
|
||||||
|
|
||||||
|
static const int kTraceMaxStackFrames{256};
|
||||||
|
static const int kTraceMaxFunctionNameLength{1024};
|
||||||
|
|
||||||
|
class WinStackTrace : public PlatformStackTrace {
|
||||||
|
public:
|
||||||
|
explicit WinStackTrace(CorePlatformWindows* platform) : platform_{platform} {
|
||||||
|
number_of_frames_ =
|
||||||
|
CaptureStackBackTrace(0, kTraceMaxStackFrames, stack_, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a human readable version of the trace (with symbolification if
|
||||||
|
// available).
|
||||||
|
auto FormatForDisplay() noexcept -> std::string {
|
||||||
|
return platform_->FormatWinStackTraceForDisplay(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should return a copy of itself allocated via new() (or nullptr if not
|
||||||
|
// possible).
|
||||||
|
auto Copy() const noexcept -> PlatformStackTrace* override {
|
||||||
|
try {
|
||||||
|
auto s = new WinStackTrace(*this);
|
||||||
|
|
||||||
|
// Vanilla copy constructor should do the right thing here.
|
||||||
|
assert(s->number_of_frames_ == number_of_frames_
|
||||||
|
&& memcmp(s->stack_, stack_, sizeof(stack_)) == 0);
|
||||||
|
return s;
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
// If this is failing we're in big trouble anyway.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto number_of_frames() const { return number_of_frames_; }
|
||||||
|
auto* stack() const { return stack_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
CorePlatformWindows* platform_;
|
||||||
|
WORD number_of_frames_{};
|
||||||
|
void* stack_[kTraceMaxStackFrames];
|
||||||
|
};
|
||||||
|
|
||||||
|
auto CorePlatformWindows::FormatWinStackTraceForDisplay(
|
||||||
|
WinStackTrace* stack_trace) -> std::string {
|
||||||
|
try {
|
||||||
|
std::string out;
|
||||||
|
|
||||||
|
// Win docs say this is not thread safe so limit to one at a time.
|
||||||
|
std::scoped_lock lock(win_stack_mutex_);
|
||||||
|
|
||||||
|
// Docs say to do this only once.
|
||||||
|
if (!win_sym_inited_) {
|
||||||
|
win_sym_process_ = GetCurrentProcess();
|
||||||
|
SymInitialize(win_sym_process_, NULL, TRUE);
|
||||||
|
win_sym_inited_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[sizeof(SYMBOL_INFO)
|
||||||
|
+ (kTraceMaxFunctionNameLength - 1) * sizeof(TCHAR)];
|
||||||
|
SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(buf);
|
||||||
|
symbol->MaxNameLen = kTraceMaxFunctionNameLength;
|
||||||
|
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||||
|
DWORD64 s_displacement;
|
||||||
|
DWORD l_displacement;
|
||||||
|
IMAGEHLP_LINE64 line;
|
||||||
|
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||||
|
|
||||||
|
std::string build_src_dir = g_core ? g_core->build_src_dir() : "";
|
||||||
|
|
||||||
|
char linebuf[kTraceMaxFunctionNameLength + 128];
|
||||||
|
for (int i = 0; i < stack_trace->number_of_frames(); i++) {
|
||||||
|
DWORD64 address = (DWORD64)(stack_trace->stack()[i]);
|
||||||
|
std::string symbol_name_s;
|
||||||
|
if (SymFromAddr(win_sym_process_, address, &s_displacement, symbol)) {
|
||||||
|
symbol_name_s = UTF8Encode(symbol->Name);
|
||||||
|
if (!Utils::IsValidUTF8(symbol_name_s)) {
|
||||||
|
// Debugging some wonky utf8 I was seeing come through.
|
||||||
|
symbol_name_s = "(got invalid utf8 for symbol name)";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
symbol_name_s = "(unknown symbol name)";
|
||||||
|
}
|
||||||
|
const char* symbol_name = symbol_name_s.c_str();
|
||||||
|
|
||||||
|
if (SymGetLineFromAddr64(win_sym_process_, address, &l_displacement,
|
||||||
|
&line)) {
|
||||||
|
std::string filename_s = UTF8Encode(line.FileName);
|
||||||
|
|
||||||
|
if (!Utils::IsValidUTF8(filename_s)) {
|
||||||
|
// Debugging some wonky utf8 I was seeing come through.
|
||||||
|
filename_s = "(got invalid utf8 for filename)";
|
||||||
|
}
|
||||||
|
const char* filename = filename_s.c_str();
|
||||||
|
|
||||||
|
// If our filename starts with build_src_dir, trim that part
|
||||||
|
// off to make things nice and pretty.
|
||||||
|
if (!build_src_dir.empty()
|
||||||
|
&& !strncmp(filename, build_src_dir.c_str(),
|
||||||
|
build_src_dir.size())) {
|
||||||
|
filename += build_src_dir.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(linebuf, sizeof(linebuf),
|
||||||
|
"%-3d %s in %s: line: %lu: address: 0x%p\n", i, symbol_name,
|
||||||
|
filename, line.LineNumber,
|
||||||
|
reinterpret_cast<void*>(symbol->Address));
|
||||||
|
} else {
|
||||||
|
snprintf(linebuf, sizeof(linebuf),
|
||||||
|
"SymGetLineFromAddr64 returned error code %lu.\n",
|
||||||
|
GetLastError());
|
||||||
|
snprintf(linebuf, sizeof(linebuf), "%-3d %s, address 0x%p.\n", i,
|
||||||
|
symbol_name, reinterpret_cast<void*>(symbol->Address));
|
||||||
|
}
|
||||||
|
out += linebuf;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
return "stack-trace construction failed.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CorePlatformWindows::GetStackTrace() -> PlatformStackTrace* {
|
||||||
|
return new WinStackTrace(this);
|
||||||
|
}
|
||||||
|
|
||||||
// Convert a wide Unicode string to an UTF8 string.
|
// Convert a wide Unicode string to an UTF8 string.
|
||||||
auto CorePlatformWindows::UTF8Encode(const std::wstring& wstr) -> std::string {
|
auto CorePlatformWindows::UTF8Encode(const std::wstring& wstr) -> std::string {
|
||||||
if (wstr.empty()) return std::string();
|
if (wstr.empty()) return std::string();
|
||||||
@ -149,7 +283,7 @@ auto CorePlatformWindows::DoGetConfigDirectoryMonolithicDefault()
|
|||||||
if (result != S_OK) {
|
if (result != S_OK) {
|
||||||
throw Exception("Unable to get user local-app-data dir.");
|
throw Exception("Unable to get user local-app-data dir.");
|
||||||
}
|
}
|
||||||
std::string configdir = UTF8Encode(std::wstring(path)) + "\\BallisticaKit";
|
std::string configdir = UTF8Encode(path) + "\\BallisticaKit";
|
||||||
return configdir;
|
return configdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +366,7 @@ auto CorePlatformWindows::DoAbsPath(const std::string& path,
|
|||||||
// Buffer not big enough. Should handle this case.
|
// Buffer not big enough. Should handle this case.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*outpath = UTF8Encode(std::wstring(abspath));
|
*outpath = UTF8Encode(abspath);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,7 +817,7 @@ std::string CorePlatformWindows::DoGetDeviceName() {
|
|||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
device_name = "BallisticaKit Game";
|
device_name = "BallisticaKit Game";
|
||||||
} else {
|
} else {
|
||||||
device_name = UTF8Encode(std::wstring(computer_name));
|
device_name = UTF8Encode(computer_name);
|
||||||
if (device_name.size() == 0) {
|
if (device_name.size() == 0) {
|
||||||
device_name = "BallisticaKit Game";
|
device_name = "BallisticaKit Game";
|
||||||
}
|
}
|
||||||
@ -704,20 +838,6 @@ void CorePlatformWindows::DisplayLog(const std::string& name, LogLevel level,
|
|||||||
OutputDebugString(UTF8Decode(msg).c_str());
|
OutputDebugString(UTF8Decode(msg).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// (The default SDL handler now covers us)
|
|
||||||
// bool CorePlatformWindows::BlockingFatalErrorDialog(const std::string&
|
|
||||||
// message) {
|
|
||||||
// if (HeadlessMode()) {
|
|
||||||
// return CorePlatform::BlockingFatalErrorDialog(message);
|
|
||||||
// }
|
|
||||||
// MessageBoxA(nullptr, (message.c_str()), "BallisticaKit",
|
|
||||||
// MB_ICONERROR | MB_OK);
|
|
||||||
|
|
||||||
// // Our message-box call is blocking so we can return false here
|
|
||||||
// // and let the app self-terminate at this point.
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
auto CorePlatformWindows::DoGetDataDirectoryMonolithicDefault() -> std::string {
|
auto CorePlatformWindows::DoGetDataDirectoryMonolithicDefault() -> std::string {
|
||||||
wchar_t sz_file_name[MAX_PATH + 1];
|
wchar_t sz_file_name[MAX_PATH + 1];
|
||||||
GetModuleFileName(nullptr, sz_file_name, MAX_PATH + 1);
|
GetModuleFileName(nullptr, sz_file_name, MAX_PATH + 1);
|
||||||
@ -733,7 +853,7 @@ auto CorePlatformWindows::DoGetDataDirectoryMonolithicDefault() -> std::string {
|
|||||||
// If the app path happens to be the current dir, return
|
// If the app path happens to be the current dir, return
|
||||||
// the default of "." which gives us cleaner looking paths in
|
// the default of "." which gives us cleaner looking paths in
|
||||||
// stack traces/etc.
|
// stack traces/etc.
|
||||||
auto out = UTF8Encode(std::wstring(sz_file_name));
|
auto out = UTF8Encode(sz_file_name);
|
||||||
if (out == GetCWD()) {
|
if (out == GetCWD()) {
|
||||||
return CorePlatform::DoGetDataDirectoryMonolithicDefault();
|
return CorePlatform::DoGetDataDirectoryMonolithicDefault();
|
||||||
}
|
}
|
||||||
@ -762,7 +882,7 @@ auto CorePlatformWindows::GetEnv(const std::string& name)
|
|||||||
|
|
||||||
// If it was found and fits in our small static buffer, we're done.
|
// If it was found and fits in our small static buffer, we're done.
|
||||||
if (result <= kStaticBufferSize) {
|
if (result <= kStaticBufferSize) {
|
||||||
return UTF8Encode(std::wstring(buffer));
|
return UTF8Encode(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ok; apparently its big. Allocate a buffer big enough to hold it and try
|
// Ok; apparently its big. Allocate a buffer big enough to hold it and try
|
||||||
@ -777,7 +897,7 @@ auto CorePlatformWindows::GetEnv(const std::string& name)
|
|||||||
Log(LogLevel::kError, "GetEnv to allocated buffer failed; unexpected.");
|
Log(LogLevel::kError, "GetEnv to allocated buffer failed; unexpected.");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return UTF8Encode(std::wstring(big_buffer.data()));
|
return UTF8Encode(big_buffer.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CorePlatformWindows::SetEnv(const std::string& name,
|
void CorePlatformWindows::SetEnv(const std::string& name,
|
||||||
@ -822,7 +942,7 @@ std::string CorePlatformWindows::GetCWD() {
|
|||||||
if (result == nullptr) {
|
if (result == nullptr) {
|
||||||
throw Exception("Error getting CWD; errno=" + std::to_string(errno));
|
throw Exception("Error getting CWD; errno=" + std::to_string(errno));
|
||||||
}
|
}
|
||||||
return UTF8Encode(std::wstring(buffer));
|
return UTF8Encode(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CorePlatformWindows::OpenFileExternally(const std::string& path) {
|
void CorePlatformWindows::OpenFileExternally(const std::string& path) {
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#define BALLISTICA_CORE_PLATFORM_WINDOWS_CORE_PLATFORM_WINDOWS_H_
|
#define BALLISTICA_CORE_PLATFORM_WINDOWS_CORE_PLATFORM_WINDOWS_H_
|
||||||
#if BA_OSTYPE_WINDOWS
|
#if BA_OSTYPE_WINDOWS
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -11,6 +12,8 @@
|
|||||||
|
|
||||||
namespace ballistica::core {
|
namespace ballistica::core {
|
||||||
|
|
||||||
|
class WinStackTrace;
|
||||||
|
|
||||||
class CorePlatformWindows : public CorePlatform {
|
class CorePlatformWindows : public CorePlatform {
|
||||||
public:
|
public:
|
||||||
CorePlatformWindows();
|
CorePlatformWindows();
|
||||||
@ -18,6 +21,7 @@ class CorePlatformWindows : public CorePlatform {
|
|||||||
static auto UTF8Encode(const std::wstring& wstr) -> std::string;
|
static auto UTF8Encode(const std::wstring& wstr) -> std::string;
|
||||||
static auto UTF8Decode(const std::string& str) -> std::wstring;
|
static auto UTF8Decode(const std::string& str) -> std::wstring;
|
||||||
|
|
||||||
|
auto GetStackTrace() -> PlatformStackTrace* override;
|
||||||
auto GetDeviceV1AccountUUIDPrefix() -> std::string override { return "w"; }
|
auto GetDeviceV1AccountUUIDPrefix() -> std::string override { return "w"; }
|
||||||
auto GetDeviceUUIDInputs() -> std::list<std::string> override;
|
auto GetDeviceUUIDInputs() -> std::list<std::string> override;
|
||||||
auto GenerateUUID() -> std::string override;
|
auto GenerateUUID() -> std::string override;
|
||||||
@ -53,6 +57,13 @@ class CorePlatformWindows : public CorePlatform {
|
|||||||
auto GetPlatformName() -> std::string override;
|
auto GetPlatformName() -> std::string override;
|
||||||
auto GetSubplatformName() -> std::string override;
|
auto GetSubplatformName() -> std::string override;
|
||||||
bool have_stdin_stdout_ = false;
|
bool have_stdin_stdout_ = false;
|
||||||
|
|
||||||
|
auto FormatWinStackTraceForDisplay(WinStackTrace* stack_trace) -> std::string;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::mutex win_stack_mutex_;
|
||||||
|
bool win_sym_inited_{};
|
||||||
|
void* win_sym_process_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::core
|
} // namespace ballistica::core
|
||||||
|
|||||||
@ -127,8 +127,7 @@ void CorePython::EnablePythonLoggingCalls() {
|
|||||||
assert(objs().Exists(ObjID::kLoggingErrorCall));
|
assert(objs().Exists(ObjID::kLoggingErrorCall));
|
||||||
assert(objs().Exists(ObjID::kLoggingCriticalCall));
|
assert(objs().Exists(ObjID::kLoggingCriticalCall));
|
||||||
|
|
||||||
// Now that we've grabbed Python logging calls above, we can push any
|
// Push any early log calls we've been holding on to along to Python.
|
||||||
// early log calls along to Python. They're no longer our problem.
|
|
||||||
{
|
{
|
||||||
std::scoped_lock lock(early_log_lock_);
|
std::scoped_lock lock(early_log_lock_);
|
||||||
python_logging_calls_enabled_ = true;
|
python_logging_calls_enabled_ = true;
|
||||||
@ -140,21 +139,12 @@ void CorePython::EnablePythonLoggingCalls() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CorePython::ImportPythonObjs() {
|
void CorePython::ImportPythonObjs() {
|
||||||
// Define a few calls we can use for environment setup.
|
// Grab core Python objs we use.
|
||||||
|
|
||||||
// Grab core stuff that we might need before our _babase module gets spun up
|
|
||||||
// (which is when all the stuff in binding_base gets fetched).
|
|
||||||
// Note: Binding .inc files expect 'ObjID' and 'objs_' to be defined.
|
|
||||||
#include "ballistica/core/mgen/pyembed/binding_core.inc"
|
#include "ballistica/core/mgen/pyembed/binding_core.inc"
|
||||||
|
|
||||||
// Normally we wait until babase is imported to push early logs through to
|
// Also grab a few things we define in env.inc. Normally this sort of
|
||||||
// Python (so that our log handling is fully bootstrapped), but technically
|
// thing would go in _hooks.py in our Python package, but because we are
|
||||||
// we can push things out to Python any time now since we grabbed the logging
|
// core we don't have one, so we have to do it via inline code.
|
||||||
// calls above. Do so if asked.
|
|
||||||
if (!g_core->core_config().hold_early_logs) {
|
|
||||||
EnablePythonLoggingCalls();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
#include "ballistica/core/mgen/pyembed/env.inc"
|
#include "ballistica/core/mgen/pyembed/env.inc"
|
||||||
auto ctx = PythonRef(PyDict_New(), PythonRef::kSteal);
|
auto ctx = PythonRef(PyDict_New(), PythonRef::kSteal);
|
||||||
|
|||||||
@ -229,7 +229,9 @@ void TerrainNode::Draw(base::FrameDef* frame_def) {
|
|||||||
: background_ ? frame_def->beauty_pass_bg()
|
: background_ ? frame_def->beauty_pass_bg()
|
||||||
: frame_def->beauty_pass());
|
: frame_def->beauty_pass());
|
||||||
c.SetWorldSpace(true);
|
c.SetWorldSpace(true);
|
||||||
c.SetTexture(color_texture_->texture_data());
|
if (color_texture_.Exists()) {
|
||||||
|
c.SetTexture(color_texture_->texture_data());
|
||||||
|
}
|
||||||
if (lighting_) {
|
if (lighting_) {
|
||||||
c.SetLightShadow(base::LightShadowType::kTerrain);
|
c.SetLightShadow(base::LightShadowType::kTerrain);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
|
|||||||
namespace ballistica {
|
namespace ballistica {
|
||||||
|
|
||||||
// These are set automatically via script; don't modify them here.
|
// These are set automatically via script; don't modify them here.
|
||||||
const int kEngineBuildNumber = 21071;
|
const int kEngineBuildNumber = 21079;
|
||||||
const char* kEngineVersion = "1.7.20";
|
const char* kEngineVersion = "1.7.20";
|
||||||
|
|
||||||
auto MonolithicMain(const core::CoreConfig& core_config) -> int {
|
auto MonolithicMain(const core::CoreConfig& core_config) -> int {
|
||||||
|
|||||||
@ -43,7 +43,7 @@ Exception::Exception(const Exception& other) noexcept {
|
|||||||
full_description_ = other.full_description_;
|
full_description_ = other.full_description_;
|
||||||
python_type_ = other.python_type_;
|
python_type_ = other.python_type_;
|
||||||
if (other.stack_trace_) {
|
if (other.stack_trace_) {
|
||||||
stack_trace_ = other.stack_trace_->copy();
|
stack_trace_ = other.stack_trace_->Copy();
|
||||||
}
|
}
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
// Hmmm not sure what we should do if this happens;
|
// Hmmm not sure what we should do if this happens;
|
||||||
@ -65,7 +65,7 @@ auto Exception::what() const noexcept -> const char* {
|
|||||||
if (stack_trace_ != nullptr) {
|
if (stack_trace_ != nullptr) {
|
||||||
const_cast<Exception*>(this)->full_description_ =
|
const_cast<Exception*>(this)->full_description_ =
|
||||||
message_ + "\nThrown from " + thread_name_ + " thread:\n"
|
message_ + "\nThrown from " + thread_name_ + " thread:\n"
|
||||||
+ stack_trace_->GetDescription();
|
+ stack_trace_->FormatForDisplay();
|
||||||
} else {
|
} else {
|
||||||
const_cast<Exception*>(this)->full_description_ = message_;
|
const_cast<Exception*>(this)->full_description_ = message_;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,7 +37,7 @@ void FatalError::ReportFatalError(const std::string& message,
|
|||||||
// immediately in order to get the debugger's attention.
|
// immediately in order to get the debugger's attention.
|
||||||
if (g_core && g_core->core_config().debugger_attached) {
|
if (g_core && g_core->core_config().debugger_attached) {
|
||||||
if (!message.empty()) {
|
if (!message.empty()) {
|
||||||
printf("FATAL ERROR: %s\n", message.c_str());
|
printf("FATAL ERROR (debugger mode): %s\n", message.c_str());
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
abort();
|
abort();
|
||||||
@ -72,12 +72,14 @@ void FatalError::ReportFatalError(const std::string& message,
|
|||||||
if (g_core && g_core->platform) {
|
if (g_core && g_core->platform) {
|
||||||
core::PlatformStackTrace* trace{g_core->platform->GetStackTrace()};
|
core::PlatformStackTrace* trace{g_core->platform->GetStackTrace()};
|
||||||
if (trace) {
|
if (trace) {
|
||||||
std::string tracestr = trace->GetDescription();
|
std::string tracestr = trace->FormatForDisplay();
|
||||||
if (!tracestr.empty()) {
|
if (!tracestr.empty()) {
|
||||||
logmsg += ("\nCPP-STACK-TRACE-BEGIN:\n" + tracestr
|
logmsg += ("\nCPP-STACK-TRACE-BEGIN:\n" + tracestr
|
||||||
+ "\nCPP-STACK-TRACE-END");
|
+ "\nCPP-STACK-TRACE-END");
|
||||||
}
|
}
|
||||||
delete trace;
|
delete trace;
|
||||||
|
} else {
|
||||||
|
logmsg += "\n(CPP-STACK-TRACE-UNAVAILABLE)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2799,34 +2799,6 @@ static PyMethodDef PyOpenFileExternallyDef = {
|
|||||||
"Open the provided file in the default external app.",
|
"Open the provided file in the default external app.",
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------- open_dir_externally ------------------------------
|
|
||||||
|
|
||||||
static auto PyOpenDirExternally(PyObject* self, PyObject* args,
|
|
||||||
PyObject* keywds) -> PyObject* {
|
|
||||||
BA_PYTHON_TRY;
|
|
||||||
char* path = nullptr;
|
|
||||||
static const char* kwlist[] = {"path", nullptr};
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "s",
|
|
||||||
const_cast<char**>(kwlist), &path)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
g_core->platform->OpenDirExternally(path);
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
BA_PYTHON_CATCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyMethodDef PyOpenDirExternallyDef = {
|
|
||||||
"open_dir_externally", // name
|
|
||||||
(PyCFunction)PyOpenDirExternally, // method
|
|
||||||
METH_VARARGS | METH_KEYWORDS, // flags
|
|
||||||
|
|
||||||
"open_dir_externally(path: str) -> None\n"
|
|
||||||
"\n"
|
|
||||||
"(internal)\n"
|
|
||||||
"\n"
|
|
||||||
"Open the provided dir in the default external app.",
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------- console_print ---------------------------------
|
// ----------------------------- console_print ---------------------------------
|
||||||
|
|
||||||
static auto PyConsolePrint(PyObject* self, PyObject* args) -> PyObject* {
|
static auto PyConsolePrint(PyObject* self, PyObject* args) -> PyObject* {
|
||||||
@ -2899,7 +2871,6 @@ auto PythonMethodsUIV1::GetMethods() -> std::vector<PyMethodDef> {
|
|||||||
PyGetQRCodeTextureDef,
|
PyGetQRCodeTextureDef,
|
||||||
PyIsPartyIconVisibleDef,
|
PyIsPartyIconVisibleDef,
|
||||||
PyConsolePrintDef,
|
PyConsolePrintDef,
|
||||||
PyOpenDirExternallyDef,
|
|
||||||
PyOpenFileExternallyDef,
|
PyOpenFileExternallyDef,
|
||||||
PyOpenURLDef,
|
PyOpenURLDef,
|
||||||
PyBackPressDef,
|
PyBackPressDef,
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class CoreFeatureSet;
|
|||||||
}
|
}
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
class BaseFeatureSet;
|
class BaseFeatureSet;
|
||||||
class WidgetMessage;
|
struct WidgetMessage;
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|
||||||
namespace ballistica::ui_v1 {
|
namespace ballistica::ui_v1 {
|
||||||
|
|||||||
@ -132,7 +132,11 @@ def _get_namespace_info(lines: list[str], index: int) -> tuple[str, bool]:
|
|||||||
if lines[index].startswith('}'):
|
if lines[index].startswith('}'):
|
||||||
return name, True
|
return name, True
|
||||||
if not (
|
if not (
|
||||||
lines[index].startswith('class ') and lines[index].endswith(';')
|
(
|
||||||
|
lines[index].startswith('class ')
|
||||||
|
or lines[index].startswith('struct ')
|
||||||
|
)
|
||||||
|
and lines[index].endswith(';')
|
||||||
):
|
):
|
||||||
# Found a non-predeclare statement
|
# Found a non-predeclare statement
|
||||||
return name, False
|
return name, False
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user