diff --git a/.efrocachemap b/.efrocachemap
index 0dbbf889..59e45678 100644
--- a/.efrocachemap
+++ b/.efrocachemap
@@ -421,7 +421,7 @@
"build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26",
"build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8",
"build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55",
- "build/assets/ba_data/data/langdata.json": "4fd17a2a848bce15a45feafb1bb16643",
+ "build/assets/ba_data/data/langdata.json": "c3b61c805a025a3d8667231004ccf2c7",
"build/assets/ba_data/data/languages/arabic.json": "5c27239be3d4f8daefd9f3bd7e99ff8d",
"build/assets/ba_data/data/languages/belarussian.json": "0a2b0ae82298cec42764558b5b49e4dd",
"build/assets/ba_data/data/languages/chinese.json": "fcd59e90c12e8106ce418b65b97b3db6",
@@ -430,31 +430,31 @@
"build/assets/ba_data/data/languages/czech.json": "15be4fd59895135bad0265f79b362d5b",
"build/assets/ba_data/data/languages/danish.json": "8e57db30c5250df2abff14a822f83ea7",
"build/assets/ba_data/data/languages/dutch.json": "b0900d572c9141897d53d6574c471343",
- "build/assets/ba_data/data/languages/english.json": "14e00f19f17c647d0a994666d5fe2991",
+ "build/assets/ba_data/data/languages/english.json": "4af8c7fd2a8cd8a4600b99bff6e1d633",
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
- "build/assets/ba_data/data/languages/filipino.json": "31a31ec3aff1464e46ce047bc2dd6e45",
+ "build/assets/ba_data/data/languages/filipino.json": "4a79d212995b5417e7b29c10478ed160",
"build/assets/ba_data/data/languages/french.json": "ee2a81129519d7030a617308da8c9195",
"build/assets/ba_data/data/languages/german.json": "eaf3f1bf633566de133c61f4f5377e62",
- "build/assets/ba_data/data/languages/gibberish.json": "9c35571f89e6cf3bd6d40be4c5026f29",
+ "build/assets/ba_data/data/languages/gibberish.json": "e8155eeaa18bb99c2fa8889ca7047aae",
"build/assets/ba_data/data/languages/greek.json": "ad3c0d38f34d809824892d6f22808dbf",
"build/assets/ba_data/data/languages/hindi.json": "bb3548531daf7bc7fee4a28d48228c32",
"build/assets/ba_data/data/languages/hungarian.json": "6b08fea24b72cc805ed0dc59e11c4cd6",
"build/assets/ba_data/data/languages/indonesian.json": "9103845242b572aa8ba48e24f81ddb68",
- "build/assets/ba_data/data/languages/italian.json": "abac9bc027257fdb757c5c1dc4686a47",
+ "build/assets/ba_data/data/languages/italian.json": "ff3b100e21aacd9d883d8f618843cdfd",
"build/assets/ba_data/data/languages/korean.json": "4e3524327a0174250aff5e1ef4c0c597",
"build/assets/ba_data/data/languages/malay.json": "f6ce0426d03a62612e3e436ed5d1be1f",
- "build/assets/ba_data/data/languages/persian.json": "540e411ec780153a046b5aae8581d155",
- "build/assets/ba_data/data/languages/polish.json": "2795e44a1b19c814b6541989a13d4bb9",
+ "build/assets/ba_data/data/languages/persian.json": "b1c794d266ebd3d07fc29cb86f2fc40e",
+ "build/assets/ba_data/data/languages/polish.json": "fecaa70e2b8ec46dc78767ad1bba3602",
"build/assets/ba_data/data/languages/portuguese.json": "3fac849a4e9e790b64727cd26f73fe6d",
"build/assets/ba_data/data/languages/romanian.json": "b3e46efd6f869dbd78014570e037c290",
"build/assets/ba_data/data/languages/russian.json": "5463543e108c4fa9be924f23adef6028",
"build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69",
"build/assets/ba_data/data/languages/slovak.json": "3c08c748c96c71bd9e1d7291fb8817b6",
- "build/assets/ba_data/data/languages/spanish.json": "09c410abc893c0e12e3403c109fa8a14",
+ "build/assets/ba_data/data/languages/spanish.json": "e26abe27bec6709a925cb5c348ab4bbc",
"build/assets/ba_data/data/languages/swedish.json": "5142a96597d17d8344be96a603da64ac",
"build/assets/ba_data/data/languages/tamil.json": "b9fcc523639f55e05c7f4e7914f3321a",
"build/assets/ba_data/data/languages/thai.json": "1d665629361f302693dead39de8fa945",
- "build/assets/ba_data/data/languages/turkish.json": "1e8b29e1d161ec0d86f421a3d0c6f5d1",
+ "build/assets/ba_data/data/languages/turkish.json": "8c36a8d6d4265085d9698996cd3a18cd",
"build/assets/ba_data/data/languages/ukrainian.json": "76ad64cb4911c8d5a3e4815b865ce5bd",
"build/assets/ba_data/data/languages/venetian.json": "96e7607b0aa79b7eb48cac8df77e8e65",
"build/assets/ba_data/data/languages/vietnamese.json": "b175cd0f01d0433355f144aeaa333409",
@@ -4038,53 +4038,53 @@
"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": "e28ff1caeb376f2a234b9f51c733bef7",
- "build/prefab/full/linux_arm64_gui/release/ballisticakit": "a67a6b81606bccc00b971ebc04222f3b",
- "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "1de6275e914452db924313823aac146b",
- "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "ff1bdc7548cd5b849aebaa5c8b436094",
- "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "53feb25cf6dfa161297f2acc9712e730",
- "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "06690b5a58948a08d77f6f1f453689d5",
- "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "a0e81c01bfe89ea84b46b5d3e837b66c",
- "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "264f040b65175d60d60c422c38eb3fe3",
- "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "8ecf39b3b7d0213502c2ac3b3ef0a3aa",
- "build/prefab/full/mac_arm64_gui/release/ballisticakit": "cc3700d575490ebca46554a28e2b5b9e",
- "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "d832c76ab6134aacf310860a77c368b6",
- "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "1981d6e2fa2bd92a958ab428aa9c8168",
- "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "5fa23b42c258f2de7b56bfc33d28eea0",
- "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "c0ad0287a567fae78d38e1493237bd60",
- "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "d6a19b286723659b90a8127de2997470",
- "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "a1380b1583ec65483549d1fa7272fc8b",
- "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "8e5c3b61bdd8a4c327b968e33af6a669",
- "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "3496262d1e007002ca2f3c9910813cc0",
- "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "cc145432211fab7fc3ae4e810bedcb9e",
- "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "953423de186d95b7c2da25e34339180d",
- "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "4a1fae6644ebb001502731a0c60a326c",
- "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "49db614d5053363664be583968e9a550",
- "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "4a1fae6644ebb001502731a0c60a326c",
- "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "49db614d5053363664be583968e9a550",
- "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "3b1aa4ec403810628292cc65165c802f",
- "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "86c800db31a55152d8830b764a9adaf1",
- "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "3b1aa4ec403810628292cc65165c802f",
- "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "86c800db31a55152d8830b764a9adaf1",
- "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "c875fe377f351cc17d40c796455ed103",
- "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "ffda098d44a350f269052acc2c64ad48",
- "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "c875fe377f351cc17d40c796455ed103",
- "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "ffda098d44a350f269052acc2c64ad48",
- "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "249d18cf8428a1c9972c3cb475de022d",
- "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "451c4ed44338c1efe77a847a7f427d59",
- "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "ee7d72a8c6db14dd609381faa4d7136a",
- "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "451c4ed44338c1efe77a847a7f427d59",
- "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "1f85da8cd779b81a27ce9b84f9bc564f",
- "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "3e1e2019dc31bbcac37834dbb1cef671",
- "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "d7cf6b99fc1063ef10ab5e1e79f190b0",
- "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "0d9abc6d5022e3900aa2fcfa488713dd",
- "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "289d3f90ac4c8854cf2ca3dc9c5aa3f5",
- "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "dc50468550b03d7550c9c895dceeb3df",
- "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "434c5315ae3423b0c02ab47c5ca4bb03",
- "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "fe772014f43efe58f3182419643b5e88",
+ "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "a02c0c36c3f6675bb6855bc009176cf6",
+ "build/prefab/full/linux_arm64_gui/release/ballisticakit": "064b003f05853087280802eb7da577c2",
+ "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "f3f576881a72a96c826fb91aef38bbba",
+ "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "2cb3a255494ed8575577c95445dee26c",
+ "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "869b386a10c8f3d566ec40218958381e",
+ "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "d70f116e1ca60f6c44d783ef66e1c345",
+ "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "1433260031956dbd74de55bc074ed276",
+ "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "cc956f6ae9866f6d43a6852a8031be5b",
+ "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "cedf3be30b1012e5deb2c3c61ba2a79c",
+ "build/prefab/full/mac_arm64_gui/release/ballisticakit": "ab87e28b76c5f6ee7f02af49ff5b207d",
+ "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "e3513bdf018e9f13e19716d2d8f39dec",
+ "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "2fd7e3ab633aa1a565de3981140f747d",
+ "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "9cf5e9821656166dd6e1c6790309bf9e",
+ "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "d5c1a8797d47c103be00358f0a78436d",
+ "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "f25132a18087448dcf14fb90cc952bb6",
+ "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "acba42eeb6a128524017dab75bae2263",
+ "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "4091cee5bc141b8a6db283d8e69c11eb",
+ "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "9b4af2d42877b890d36d8e4cd5142af9",
+ "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "8902a19b82bef589cd9dc7b294a04b7e",
+ "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "5239aca25076e3492666ade56ba61fca",
+ "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "a06bb7921cd8f951aae499154603145c",
+ "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "98c206cc02eb43b219c15a782f816e00",
+ "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "a06bb7921cd8f951aae499154603145c",
+ "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "98c206cc02eb43b219c15a782f816e00",
+ "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "72c5a907a8ba413ca9844d95837a5485",
+ "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "c9f768f18c948d36fe5c76e545549076",
+ "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "72c5a907a8ba413ca9844d95837a5485",
+ "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "c9f768f18c948d36fe5c76e545549076",
+ "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "2054806fac24a166edd01d2705f3531d",
+ "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "bccc5000405615475847ebefcbc168fc",
+ "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "2054806fac24a166edd01d2705f3531d",
+ "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "bccc5000405615475847ebefcbc168fc",
+ "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "c8b8c161254214e912b2f80b514447e9",
+ "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "7e7909e96fc13469c5e7f29b1eb56898",
+ "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "8039d71c9e8d9e9359aef23f4bbf99da",
+ "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "7e7909e96fc13469c5e7f29b1eb56898",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "6abd2da165375cd1ad163aee11d177ff",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "7cd96c8d0dba6d0ddf86f86238ee30f0",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "2d04ca0901dc47d50c64b0ea1bbb1b5b",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "7ab7cb07acd3527a9c95f3cca340488b",
+ "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "13ba788f64a3ab7787396590d539e4c3",
+ "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "2cd2cb6a2fb009df90b7540426fde687",
+ "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "b95111371bc3485e0c95eadaa7424dd1",
+ "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "809bf7b07895aa406f4564130ae22e09",
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
- "src/assets/ba_data/python/babase/_mgen/enums.py": "b611c090513a21e2fe90e56582724e9d",
- "src/ballistica/base/mgen/pyembed/binding_base.inc": "72bfed2cce8ff19741989dec28302f3f",
+ "src/assets/ba_data/python/babase/_mgen/enums.py": "5548f407d97e380069f6c596c4e36cd7",
+ "src/ballistica/base/mgen/pyembed/binding_base.inc": "efa61468cf098f77cc6a234461d8b86d",
"src/ballistica/base/mgen/pyembed/binding_base_app.inc": "97efb93f4bfd8e8b09f2db24398e29fc",
"src/ballistica/classic/mgen/pyembed/binding_classic.inc": "3ceb412513963f0818ab39c58bf292e3",
"src/ballistica/core/mgen/pyembed/binding_core.inc": "9d0a3c9636138e35284923e0c8311c69",
diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml
index 4be721ff..74cd2518 100644
--- a/.idea/dictionaries/ericf.xml
+++ b/.idea/dictionaries/ericf.xml
@@ -2423,7 +2423,7 @@
pythondevmode
pythondirs
pythondontwritebytecode
- pythonenumsmodule
+ enumspython
pythonhashseed
pythonoptimize
pythonpath
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 05cc8925..8e30188a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-### 1.7.35 (build 21852, api 8, 2024-05-10)
+### 1.7.35 (build 21863, api 8, 2024-05-12)
- Fixed an issue where the engine would block at exit on some version of Linux
until Ctrl-D was pressed in the calling terminal.
- V2 accounts have been around for a while now, so the old V1 device login
@@ -10,6 +10,10 @@
that is the only option. So nice and tidy! When other options such as Google
Play or Game Center are available it is now called 'Sign in with an email
address'.
+- The engine now supports signing in or creating email/password accounts in a
+ pop-up web dialog to avoid taking users out of the app. This currently works
+ on the native (not cmake) Mac build but will probably expand to others in the
+ future.
- The `ba*.app.env.version` `and ba*.app.env.build_number` values are now
`ba*.app.env.engine_version` and `ba*.app.env.engine_build_number`. At this
point any functionality that cares about versions should be looking at engine
@@ -1284,7 +1288,7 @@
before to determine if a browser was available but this seemed to be flaky.
Holler if this is not working well on your device/situation.
- The internal 'fallback' `ba.open_url()` window which shows a url string when a
- system browser is not available now has a qrcode and a copy button (where
+ web browser is not available now has a qrcode and a copy button (where
copy/paste is supported).
- Added a 'force_internal' arg to `ba.open_url()` if you would like to always
use the internal window instead of attempting to open a browser. Now that we
diff --git a/ballisticakit-cmake/.idea/dictionaries/ericf.xml b/ballisticakit-cmake/.idea/dictionaries/ericf.xml
index 9d52b536..32e97f84 100644
--- a/ballisticakit-cmake/.idea/dictionaries/ericf.xml
+++ b/ballisticakit-cmake/.idea/dictionaries/ericf.xml
@@ -1429,7 +1429,7 @@
pyrightconfig
pysitedir
pythondevmode
- pythonenumsmodule
+ enumspython
pythonoptimize
pythonutf
pytype
diff --git a/ballisticakit-cmake/CMakeLists.txt b/ballisticakit-cmake/CMakeLists.txt
index 64df74e8..ce5f81f4 100644
--- a/ballisticakit-cmake/CMakeLists.txt
+++ b/ballisticakit-cmake/CMakeLists.txt
@@ -426,12 +426,12 @@ set(BALLISTICA_SOURCES
${BA_SRC_ROOT}/ballistica/base/python/class/python_class_simple_sound.h
${BA_SRC_ROOT}/ballistica/base/python/class/python_class_vec3.cc
${BA_SRC_ROOT}/ballistica/base/python/class/python_class_vec3.h
- ${BA_SRC_ROOT}/ballistica/base/python/methods/python_methods_app.cc
- ${BA_SRC_ROOT}/ballistica/base/python/methods/python_methods_app.h
- ${BA_SRC_ROOT}/ballistica/base/python/methods/python_methods_graphics.cc
- ${BA_SRC_ROOT}/ballistica/base/python/methods/python_methods_graphics.h
- ${BA_SRC_ROOT}/ballistica/base/python/methods/python_methods_misc.cc
- ${BA_SRC_ROOT}/ballistica/base/python/methods/python_methods_misc.h
+ ${BA_SRC_ROOT}/ballistica/base/python/methods/python_methods_base_1.cc
+ ${BA_SRC_ROOT}/ballistica/base/python/methods/python_methods_base_1.h
+ ${BA_SRC_ROOT}/ballistica/base/python/methods/python_methods_base_2.cc
+ ${BA_SRC_ROOT}/ballistica/base/python/methods/python_methods_base_2.h
+ ${BA_SRC_ROOT}/ballistica/base/python/methods/python_methods_base_3.cc
+ ${BA_SRC_ROOT}/ballistica/base/python/methods/python_methods_base_3.h
${BA_SRC_ROOT}/ballistica/base/python/support/python_context_call.cc
${BA_SRC_ROOT}/ballistica/base/python/support/python_context_call.h
${BA_SRC_ROOT}/ballistica/base/python/support/python_context_call_runnable.h
diff --git a/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj b/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj
index 97c94baf..e04617c4 100644
--- a/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj
+++ b/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj
@@ -418,12 +418,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.filters b/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.filters
index 92b1c44d..25638b88 100644
--- a/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.filters
+++ b/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.filters
@@ -688,22 +688,22 @@
ballistica\base\python\class
-
+
ballistica\base\python\methods
-
+
ballistica\base\python\methods
-
+
ballistica\base\python\methods
-
+
ballistica\base\python\methods
-
+
ballistica\base\python\methods
-
+
ballistica\base\python\methods
diff --git a/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj b/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj
index 6434233d..29dbe54a 100644
--- a/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj
+++ b/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj
@@ -413,12 +413,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.filters b/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.filters
index 92b1c44d..25638b88 100644
--- a/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.filters
+++ b/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.filters
@@ -688,22 +688,22 @@
ballistica\base\python\class
-
+
ballistica\base\python\methods
-
+
ballistica\base\python\methods
-
+
ballistica\base\python\methods
-
+
ballistica\base\python\methods
-
+
ballistica\base\python\methods
-
+
ballistica\base\python\methods
diff --git a/config/projectconfig.json b/config/projectconfig.json
index a9d0a1ee..835fa668 100644
--- a/config/projectconfig.json
+++ b/config/projectconfig.json
@@ -9,7 +9,6 @@
"src/ballistica/base/graphics/texture/dds.h",
"src/ballistica/base/graphics/texture/ktx.cc",
"src/ballistica/core/platform/android/android_gl3.h",
- "src/ballistica/base/platform/apple/app_delegate.h",
"src/ballistica/base/platform/apple/MacMusicApp.h",
"src/ballistica/base/platform/apple/MacMusicAppScriptingBridge.h",
"src/ballistica/core/platform/android/utf8/checked.h",
diff --git a/src/assets/ba_data/python/babase/__init__.py b/src/assets/ba_data/python/babase/__init__.py
index e3f115a7..8b4cce36 100644
--- a/src/assets/ba_data/python/babase/__init__.py
+++ b/src/assets/ba_data/python/babase/__init__.py
@@ -79,6 +79,11 @@ from _babase import (
native_review_request_supported,
native_stack_trace,
open_file_externally,
+ open_url,
+ overlay_web_browser_close,
+ overlay_web_browser_is_open,
+ overlay_web_browser_is_supported,
+ overlay_web_browser_open_url,
print_load_info,
pushcall,
quit,
@@ -285,6 +290,11 @@ __all__ = [
'normalized_color',
'NotFoundError',
'open_file_externally',
+ 'open_url',
+ 'overlay_web_browser_close',
+ 'overlay_web_browser_is_open',
+ 'overlay_web_browser_is_supported',
+ 'overlay_web_browser_open_url',
'Permission',
'PlayerNotFoundError',
'Plugin',
diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py
index 0a8665f6..66245853 100644
--- a/src/assets/ba_data/python/baenv.py
+++ b/src/assets/ba_data/python/baenv.py
@@ -52,7 +52,7 @@ if TYPE_CHECKING:
# Build number and version of the ballistica binary we expect to be
# using.
-TARGET_BALLISTICA_BUILD = 21852
+TARGET_BALLISTICA_BUILD = 21863
TARGET_BALLISTICA_VERSION = '1.7.35'
diff --git a/src/assets/ba_data/python/bauiv1/__init__.py b/src/assets/ba_data/python/bauiv1/__init__.py
index 4f633f30..2e3144ba 100644
--- a/src/assets/ba_data/python/bauiv1/__init__.py
+++ b/src/assets/ba_data/python/bauiv1/__init__.py
@@ -70,6 +70,11 @@ from babase import (
native_review_request_supported,
NotFoundError,
open_file_externally,
+ open_url,
+ overlay_web_browser_close,
+ overlay_web_browser_is_open,
+ overlay_web_browser_is_supported,
+ overlay_web_browser_open_url,
Permission,
Plugin,
PluginSpec,
@@ -106,7 +111,6 @@ from _bauiv1 import (
imagewidget,
is_party_icon_visible,
Mesh,
- open_url,
rowwidget,
scrollwidget,
set_party_icon_always_visible,
@@ -191,6 +195,10 @@ __all__ = [
'NotFoundError',
'open_file_externally',
'open_url',
+ 'overlay_web_browser_close',
+ 'overlay_web_browser_is_open',
+ 'overlay_web_browser_is_supported',
+ 'overlay_web_browser_open_url',
'Permission',
'Plugin',
'PluginSpec',
diff --git a/src/assets/ba_data/python/bauiv1lib/account/settings.py b/src/assets/ba_data/python/bauiv1lib/account/settings.py
index ddddfe4e..4569b9c7 100644
--- a/src/assets/ba_data/python/bauiv1lib/account/settings.py
+++ b/src/assets/ba_data/python/bauiv1lib/account/settings.py
@@ -321,7 +321,10 @@ class AccountSettingsWindow(bui.Window):
show_what_is_v2 = False
# show_what_is_v2 = self._v1_signed_in and v1_account_type == 'V2'
- show_linked_accounts_text = self._v1_signed_in
+ # Phasing this out (for V2 accounts at least).
+ show_linked_accounts_text = (
+ self._v1_signed_in and v1_account_type != 'V2'
+ )
linked_accounts_text_space = 60.0
# Always show achievements except in the game-center case where
@@ -364,7 +367,10 @@ class AccountSettingsWindow(bui.Window):
show_unlink_accounts_button = show_link_accounts_button
unlink_accounts_button_space = 90.0
- show_v2_link_info = self._v1_signed_in and not show_link_accounts_button
+ # Phasing this out.
+ # show_v2_link_info = self._v1_signed_in
+ # and not show_link_accounts_button
+ show_v2_link_info = False
v2_link_info_space = 70.0
legacy_unlink_button_space = 120.0
@@ -373,7 +379,7 @@ class AccountSettingsWindow(bui.Window):
'Local',
'V2',
]
- sign_out_button_space = 70.0
+ sign_out_button_space = 80.0
# We can show cancel if we're either waiting on an adapter to
# provide us with v2 credentials or waiting for those credentials
diff --git a/src/assets/ba_data/python/bauiv1lib/account/v2proxy.py b/src/assets/ba_data/python/bauiv1lib/account/v2proxy.py
index a5a3ae6b..d91f1f04 100644
--- a/src/assets/ba_data/python/bauiv1lib/account/v2proxy.py
+++ b/src/assets/ba_data/python/bauiv1lib/account/v2proxy.py
@@ -4,6 +4,7 @@
from __future__ import annotations
+import time
import logging
from efro.error import CommunicationError
@@ -21,6 +22,7 @@ class V2ProxySignInWindow(bui.Window):
self._height = 550
self._proxyid: str | None = None
self._proxykey: str | None = None
+ self._overlay_web_browser_open = False
assert bui.app.classic is not None
uiscale = bui.app.ui_v1.uiscale
@@ -90,35 +92,37 @@ class V2ProxySignInWindow(bui.Window):
self._message_in_flight = False
self._complete = False
- # self._delay_ticks = 0
- self._connection_wait = 5
+ self._connection_wait_timeout_time = time.monotonic() + 10.0
- # self._update_timer: bui.AppTimer | None = None
self._update_timer = bui.AppTimer(
- 1.23, bui.WeakCall(self._update), repeat=True
+ 0.371, bui.WeakCall(self._update), repeat=True
)
bui.pushcall(bui.WeakCall(self._update))
- # Ask the cloud for a proxy login id.
- # assert bui.app.plus is not None
- # bui.app.plus.cloud.send_message_cb(
- # bacommon.cloud.LoginProxyRequestMessage(),
- # on_response=bui.WeakCall(self._on_proxy_request_response),
- # )
-
def _update(self) -> None:
- # print('hello from update', time.monotonic())
-
- if self._message_in_flight or self._complete:
- return
plus = bui.app.plus
assert plus is not None
+ # If we've opened an overlay web browser, all we do is kill
+ # ourselves when it closes.
+ if self._overlay_web_browser_open:
+ if not bui.overlay_web_browser_is_open():
+ self._overlay_web_browser_open = False
+ self._done()
+ return
+
+ if self._message_in_flight or self._complete:
+ return
+
+ now = time.monotonic()
+
# Spin for a moment if it looks like we have no server
- # connection; it might still be getting on its feed.
- if not plus.cloud.connected and self._connection_wait > 0:
- self._connection_wait -= 1
+ # connection; it might still be getting on its feet.
+ if (
+ not plus.cloud.connected
+ and now < self._connection_wait_timeout_time
+ ):
return
plus.cloud.send_message_cb(
@@ -177,42 +181,51 @@ class V2ProxySignInWindow(bui.Window):
)
self._message_in_flight = False
- # if bool(True) and random.random() < 1.0:
- # response = Exception('dummy')
-
- msaddress = self._get_server_address()
-
# Something went wrong. Show an error message and schedule retry.
if isinstance(response, Exception):
- # addr = msaddress.removeprefix('https://')
- # bui.textwidget(
- # edit=self._state_text,
- # text=f'Unable to connect to {addr}.',
- # color=(1, 0, 0),
- # )
- # bui.textwidget(
- # edit=self._sub_state_text,
- # text='Will retry in a moment...',
- # color=(1, 0, 0),
- # )
- # self._delay_ticks = 3
self._set_error_state(f'response exc ({type(response).__name__})')
self._complete = True
-
- # bui.textwidget(
- # edit=self._state_text,
- # text=bui.Lstr(
- # resource='internal.unavailableNoConnectionText'),
- # color=(1, 0, 0),
- # )
return
self._complete = True
- self._state_text.delete()
+ # Clear out stuff we use to show progress/errors.
self._sub_state_text.delete()
self._sub_state_text2.delete()
+ # If we have overlay-web-browser functionality, bring up
+ # an inline sign-in dialog.
+ if bui.overlay_web_browser_is_supported():
+ bui.textwidget(
+ edit=self._state_text,
+ text=bui.Lstr(resource='pleaseWaitText'),
+ )
+ self._show_overlay_sign_in_ui(response)
+ self._overlay_web_browser_open = True
+ else:
+ # Otherwise just show link-button/qr-code for the sign-in.
+ self._state_text.delete()
+ self._show_standard_sign_in_ui(response)
+
+ # In either case, start querying for results now.
+ self._proxyid = response.proxyid
+ self._proxykey = response.proxykey
+ bui.apptimer(
+ STATUS_CHECK_INTERVAL_SECONDS, bui.WeakCall(self._ask_for_status)
+ )
+
+ def _show_overlay_sign_in_ui(
+ self, response: bacommon.cloud.LoginProxyRequestResponse
+ ) -> None:
+ msaddress = self._get_server_address()
+ address = msaddress + response.url_overlay
+ bui.overlay_web_browser_open_url(address)
+
+ def _show_standard_sign_in_ui(
+ self, response: bacommon.cloud.LoginProxyRequestResponse
+ ) -> None:
+ msaddress = self._get_server_address()
+
# Show link(s) the user can use to sign in.
address = msaddress + response.url
address_pretty = address.removeprefix('https://')
@@ -274,13 +287,6 @@ class V2ProxySignInWindow(bui.Window):
texture=bui.get_qrcode_texture(address),
)
- # Start querying for results.
- self._proxyid = response.proxyid
- self._proxykey = response.proxykey
- bui.apptimer(
- STATUS_CHECK_INTERVAL_SECONDS, bui.WeakCall(self._ask_for_status)
- )
-
def _ask_for_status(self) -> None:
assert self._proxyid is not None
assert self._proxykey is not None
@@ -362,4 +368,9 @@ class V2ProxySignInWindow(bui.Window):
# no-op if our underlying widget is dead or on its way out.
if not self._root_widget or self._root_widget.transitioning_out:
return
+
+ # If we've got an inline browser up, tell it to close.
+ if self._overlay_web_browser_open:
+ bui.overlay_web_browser_close()
+
bui.containerwidget(edit=self._root_widget, transition='out_scale')
diff --git a/src/ballistica/base/app_adapter/app_adapter_apple.cc b/src/ballistica/base/app_adapter/app_adapter_apple.cc
index 515eb046..667e1a0c 100644
--- a/src/ballistica/base/app_adapter/app_adapter_apple.cc
+++ b/src/ballistica/base/app_adapter/app_adapter_apple.cc
@@ -7,7 +7,6 @@
#include "ballistica/base/graphics/graphics.h"
#include "ballistica/base/graphics/graphics_server.h"
#include "ballistica/base/logic/logic.h"
-#include "ballistica/base/platform/apple/apple_utils.h"
#include "ballistica/base/platform/apple/from_swift.h"
#include "ballistica/base/platform/support/min_sdl_key_names.h"
#include "ballistica/base/support/app_config.h"
diff --git a/src/ballistica/base/base.cc b/src/ballistica/base/base.cc
index ea251397..c8919dbd 100644
--- a/src/ballistica/base/base.cc
+++ b/src/ballistica/base/base.cc
@@ -954,13 +954,13 @@ auto BaseFeatureSet::ClipboardGetText() -> std::string {
void BaseFeatureSet::SetAppActive(bool active) {
assert(InMainThread());
- // Note: in some cases I'm seeing repeat active/inactive sets; for example
+ // Note: in some cases I'm seeing repeat active/inactive sets. For example
// on Mac SDL if I hide the app and then click on it in the dock I get a
// 'inactive' for the hide followed by a 'active', 'inactive', 'active' on
// the dock click. So our strategy here to filter that out is just to tell
- // the logic thread that it has changed but have them directly read the
- // shared atomic value, so they should generally skip over flip-flops like
- // that and will just read the final value a few times in a row.
+ // the logic thread that the value has changed but have them directly read
+ // the shared atomic value, so they should generally skip over flip-flops
+ // like that and instead just read the final value a few times in a row.
g_core->platform->LowLevelDebugLog(
"SetAppActive(" + std::to_string(active) + ")@"
diff --git a/src/ballistica/base/platform/apple/base_platform_apple.cc b/src/ballistica/base/platform/apple/base_platform_apple.cc
index aeeb6917..ccb5993d 100644
--- a/src/ballistica/base/platform/apple/base_platform_apple.cc
+++ b/src/ballistica/base/platform/apple/base_platform_apple.cc
@@ -4,7 +4,6 @@
#include "ballistica/base/platform/apple/base_platform_apple.h"
#if BA_XCODE_BUILD
-#include "ballistica/base/platform/apple/apple_utils.h"
#include "ballistica/base/platform/apple/from_swift.h"
#endif
@@ -65,6 +64,51 @@ void BasePlatformApple::DoOpenURL(const std::string& url) {
#endif // BA_XCODE_BUILD
}
+auto BasePlatformApple::OverlayWebBrowserIsSupported() -> bool {
+#if BA_XCODE_BUILD
+#if BA_OSTYPE_MACOS
+ return BallisticaKit::CocoaFromCpp::haveOverlayWebBrowser();
+#else
+ // TODO(ericf): Implement for uikit.
+ return BasePlatform::OverlayWebBrowserIsSupported();
+#endif // BA_OSTYPE_MACOS
+
+#else
+ // Fall back to default for non-xcode apple builds.
+ return BasePlatform::OverlayWebBrowserIsSupported();
+#endif // BA_XCODE_BUILD
+}
+
+void BasePlatformApple::DoOverlayWebBrowserOpenURL(const std::string& url) {
+#if BA_XCODE_BUILD
+#if BA_OSTYPE_MACOS
+ BallisticaKit::CocoaFromCpp::openURLInOverlayWebBrowser(url);
+#else
+ // TODO(ericf): Implement for uikit.
+ BasePlatform::DoOpenURLInOverlayBrowser(url);
+#endif // BA_OSTYPE_MACOS
+
+#else
+ // For non-xcode builds, go with the default (Python webbrowser module).
+ BasePlatform::DoOverlayWebBrowserOpenURL(url);
+#endif // BA_XCODE_BUILD
+}
+
+void BasePlatformApple::DoOverlayWebBrowserClose() {
+#if BA_XCODE_BUILD
+#if BA_OSTYPE_MACOS
+ BallisticaKit::CocoaFromCpp::closeOverlayWebBrowser();
+#else
+ // TODO(ericf): Implement for uikit.
+ BasePlatform::OverlayWebBrowserIsSupported();
+#endif // BA_OSTYPE_MACOS
+
+#else
+ // Fall back to default for non-xcode apple builds.
+ BasePlatform::OverlayWebBrowserIsSupported();
+#endif // BA_XCODE_BUILD
+}
+
void BasePlatformApple::LoginAdapterGetSignInToken(
const std::string& login_type, int attempt_id) {
#if BA_USE_GAME_CENTER
diff --git a/src/ballistica/base/platform/apple/base_platform_apple.h b/src/ballistica/base/platform/apple/base_platform_apple.h
index f6e5362b..7d8c8864 100644
--- a/src/ballistica/base/platform/apple/base_platform_apple.h
+++ b/src/ballistica/base/platform/apple/base_platform_apple.h
@@ -16,6 +16,9 @@ class BasePlatformApple : public BasePlatform {
void PurchaseAck(const std::string& purchase,
const std::string& order_id) override;
void DoOpenURL(const std::string& url) override;
+ auto OverlayWebBrowserIsSupported() -> bool override;
+ void DoOverlayWebBrowserOpenURL(const std::string& url) override;
+ void DoOverlayWebBrowserClose() override;
void LoginAdapterGetSignInToken(const std::string& login_type,
int attempt_id) override;
void LoginAdapterBackEndActiveChange(const std::string& login_type,
diff --git a/src/ballistica/base/platform/base_platform.cc b/src/ballistica/base/platform/base_platform.cc
index 210fbe5f..d07e2ab0 100644
--- a/src/ballistica/base/platform/base_platform.cc
+++ b/src/ballistica/base/platform/base_platform.cc
@@ -9,6 +9,7 @@
#include
#endif
+#include "ballistica/base/app_adapter/app_adapter.h"
#include "ballistica/base/base.h"
#include "ballistica/base/input/input.h"
#include "ballistica/base/logic/logic.h"
@@ -110,42 +111,73 @@ void BasePlatform::PurchaseAck(const std::string& purchase,
}
void BasePlatform::OpenURL(const std::string& url) {
- // DoOpenURL expects to be run in the logic thread.
- g_base->logic->event_loop()->PushCall(
+ // We can be called from any thread, but DoOpenURL expects to be run in
+ // the main thread.
+ g_base->app_adapter->PushMainThreadCall(
[url] { g_base->platform->DoOpenURL(url); });
}
void BasePlatform::DoOpenURL(const std::string& url) {
// As a default, use Python's webbrowser module functionality.
- g_base->python->OpenURLWithWebBrowserModule(url);
-}
-
-auto BasePlatform::HaveOverlayWebBrowser() -> bool { return false; }
-
-void BasePlatform::OpenURLInOverlayWebBrowser(const std::string& url) {
- BA_PRECONDITION(HaveOverlayWebBrowser());
-
- // DoOpenURLInOverlayBrowser expects to be run in the logic thread.
+ // It expects to be run in the logic thread though so we need
+ // to push it over that way.
g_base->logic->event_loop()->PushCall(
- [url] { g_base->platform->DoOpenURLInOverlayBrowser(url); });
+ [url] { g_base->python->OpenURLWithWebBrowserModule(url); });
}
-void BasePlatform::CloseOverlayWebBrowser() {
- BA_PRECONDITION(HaveOverlayWebBrowser());
+auto BasePlatform::OverlayWebBrowserIsSupported() -> bool { return false; }
- // DoCloseOverlayBrowser expects to be run in the logic thread.
- g_base->logic->event_loop()->PushCall(
- [] { g_base->platform->DoCloseOverlayBrowser(); });
+void BasePlatform::OverlayWebBrowserOpenURL(const std::string& url) {
+ BA_PRECONDITION(OverlayWebBrowserIsSupported());
+
+ std::scoped_lock lock(web_overlay_mutex_);
+ if (web_overlay_open_) {
+ Log(LogLevel::kError,
+ "OverlayWebBrowserOnClose called with already existing overlay.");
+ return;
+ }
+ web_overlay_open_ = true;
+
+ // We can be called from any thread, but DoOpenURL expects to be called
+ // from the main thread.
+ g_base->app_adapter->PushMainThreadCall(
+ [url] { g_base->platform->DoOverlayWebBrowserOpenURL(url); });
}
-void BasePlatform::DoOpenURLInOverlayBrowser(const std::string& url) {
- // As a default, use Python's webbrowser module functionality.
+auto BasePlatform::OverlayWebBrowserIsOpen() -> bool {
+ BA_PRECONDITION(OverlayWebBrowserIsSupported());
+ // No reason to lock the mutex here I think.
+ return web_overlay_open_;
+}
+
+void BasePlatform::OverlayWebBrowserOnClose() {
+ std::scoped_lock lock(web_overlay_mutex_);
+ if (!web_overlay_open_) {
+ Log(LogLevel::kError,
+ "OverlayWebBrowserOnClose called with no known overlay.");
+ }
+ web_overlay_open_ = false;
+}
+
+void BasePlatform::OverlayWebBrowserClose() {
+ BA_PRECONDITION(OverlayWebBrowserIsSupported());
+
+ // I don't think theres any point to looking at the opened-state, is
+ // there? This call needs to gracefully handle any state.
+
+ // We can be called from any thread, but DoOverlayWebBrowserClose expects
+ // to be called from the main thread.
+ g_base->app_adapter->PushMainThreadCall(
+ [] { g_base->platform->DoOverlayWebBrowserClose(); });
+}
+
+void BasePlatform::DoOverlayWebBrowserOpenURL(const std::string& url) {
Log(LogLevel::kError, "DoOpenURLInOverlayBrowser unimplemented");
}
-void BasePlatform::DoCloseOverlayBrowser() {
+void BasePlatform::DoOverlayWebBrowserClose() {
// As a default, use Python's webbrowser module functionality.
- Log(LogLevel::kError, "DoCloseOverlayBrowser unimplemented");
+ Log(LogLevel::kError, "DoOverlayWebBrowserClose unimplemented");
}
#if !BA_OSTYPE_WINDOWS
@@ -255,19 +287,6 @@ void BasePlatform::OpenFileExternally(const std::string& path) {
Log(LogLevel::kError, "OpenFileExternally() unimplemented");
}
-void BasePlatform::SafeStdinFGetSInit() {
-#if BA_OSTYPE_WINDOWS
- // Do nothing on Windows. We seem to be ok with blocking reads there.
-#else
-
- // Actually should not be necessary now that we're using poll().
-
- // Set stdin up for non-blocking reads.
- // int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
- // fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
-#endif // BA_OSTYPE_WINDOWS
-}
-
auto BasePlatform::SafeStdinFGetS(char* s, int n, FILE* iop) -> char* {
#if BA_OSTYPE_WINDOWS
// Use plain old vanilla fgets on Windows since blocking stdin reads
diff --git a/src/ballistica/base/platform/base_platform.h b/src/ballistica/base/platform/base_platform.h
index a91867d9..2d864e1a 100644
--- a/src/ballistica/base/platform/base_platform.h
+++ b/src/ballistica/base/platform/base_platform.h
@@ -4,12 +4,19 @@
#define BALLISTICA_BASE_PLATFORM_BASE_PLATFORM_H_
#include
+#include
#include "ballistica/base/base.h"
#include "ballistica/shared/python/python_ref.h"
namespace ballistica::base {
+/// EFRO NOTE: I think everything here should be migrated to app_adapter,
+/// which can then be renamed to app_platform. Having both
+/// base_platform and app_adapter feels redundant. If there is
+/// functionality shared by multiple app_platforms, it can be
+/// implemented as a common base class.
+
/// Most general platform-specific functionality is contained here, to be
/// implemented by platform-specific subclasses. Exceptions to this rule are
/// things such as AppAdapter which are broken out into their own classes so
@@ -35,9 +42,6 @@ class BasePlatform {
virtual void OnScreenSizeChange();
virtual void DoApplyAppConfig();
- /// Prepares stdin reading that won't block process exit.
- virtual void SafeStdinFGetSInit();
-
/// Equivalent of fgets() but modified to not block process exit.
auto SafeStdinFGetS(char* s, int n, FILE* iop) -> char*;
@@ -79,20 +83,27 @@ class BasePlatform {
#pragma mark WEB BROWSER -------------------------------------------------------
- /// Open the provided URL in a browser.
+ /// Open the provided URL in a browser. Can be called from any thread.
void OpenURL(const std::string& url);
/// Do we provide a browser window that can show up over content?
/// This can be used for simple tasks such as signing into accounts
/// without leaving the app. It is assumed that only one overlay browser
/// can exist at a time.
- virtual auto HaveOverlayWebBrowser() -> bool;
+ virtual auto OverlayWebBrowserIsSupported() -> bool;
- /// Open the provided URL in an overlay web browser.
- void OpenURLInOverlayWebBrowser(const std::string& url);
+ /// Open the provided URL in an overlay web browser. Can be called from
+ /// any thread.
+ void OverlayWebBrowserOpenURL(const std::string& url);
- /// Close any open overlay web browser.
- void CloseOverlayWebBrowser();
+ auto OverlayWebBrowserIsOpen() -> bool;
+
+ /// Overlay web browser implementations should call this when they
+ /// close, or if they fail to open. Can be called from any thread.
+ void OverlayWebBrowserOnClose();
+
+ /// Close any open overlay web browser. Can be called from any thread.
+ void OverlayWebBrowserClose();
#pragma mark STRING EDITOR -----------------------------------------------------
@@ -135,16 +146,16 @@ class BasePlatform {
std::optional max_chars);
/// Open the provided URL in a browser. This will always be called in the
- /// logic thread.
+ /// main thread.
virtual void DoOpenURL(const std::string& url);
/// Open the provided URL in the overlay browser. This will always be called
- /// in the logic thread.
- virtual void DoOpenURLInOverlayBrowser(const std::string& url);
+ /// in the main thread.
+ virtual void DoOverlayWebBrowserOpenURL(const std::string& url);
/// Should close any existing overlay web browser. This will always be called
- /// in the logic thread.
- virtual void DoCloseOverlayBrowser();
+ /// in the main thread.
+ virtual void DoOverlayWebBrowserClose();
/// Make a purchase.
virtual void DoPurchase(const std::string& item);
@@ -155,9 +166,11 @@ class BasePlatform {
int SmartGetC_(FILE* stream);
bool ran_base_post_init_{};
+ bool web_overlay_open_{};
PythonRef string_edit_adapter_{};
std::string public_device_uuid_;
std::deque stdin_buffer_;
+ std::mutex web_overlay_mutex_;
};
} // namespace ballistica::base
diff --git a/src/ballistica/base/python/base_python.cc b/src/ballistica/base/python/base_python.cc
index 83f53425..7d78f684 100644
--- a/src/ballistica/base/python/base_python.cc
+++ b/src/ballistica/base/python/base_python.cc
@@ -11,9 +11,9 @@
#include "ballistica/base/python/class/python_class_feature_set_data.h"
#include "ballistica/base/python/class/python_class_simple_sound.h"
#include "ballistica/base/python/class/python_class_vec3.h"
-#include "ballistica/base/python/methods/python_methods_app.h"
-#include "ballistica/base/python/methods/python_methods_graphics.h"
-#include "ballistica/base/python/methods/python_methods_misc.h"
+#include "ballistica/base/python/methods/python_methods_base_1.h"
+#include "ballistica/base/python/methods/python_methods_base_2.h"
+#include "ballistica/base/python/methods/python_methods_base_3.h"
#include "ballistica/shared/python/python_command.h"
#include "ballistica/shared/python/python_module_builder.h"
@@ -26,9 +26,9 @@ extern "C" auto PyInit__babase() -> PyObject* {
auto* builder =
new PythonModuleBuilder("_babase",
{
- PythonMethodsApp::GetMethods(),
- PythonMethodsMisc::GetMethods(),
- PythonMethodsGraphics::GetMethods(),
+ PythonMethodsBase1::GetMethods(),
+ PythonMoethodsBase3::GetMethods(),
+ PythonMethodsBase2::GetMethods(),
},
[](PyObject* module) -> int {
BA_PYTHON_TRY;
@@ -463,17 +463,17 @@ auto BasePython::GetPyEnum_SpecialChar(PyObject* obj) -> SpecialChar {
return GetPyEnum(BasePython::ObjID::kSpecialCharClass, obj);
}
-auto BasePython::GetPyEnum_TimeType(PyObject* obj) -> TimeType {
- return GetPyEnum(BasePython::ObjID::kTimeTypeClass, obj);
-}
+// auto BasePython::GetPyEnum_TimeType(PyObject* obj) -> TimeType {
+// return GetPyEnum(BasePython::ObjID::kTimeTypeClass, obj);
+// }
auto BasePython::GetPyEnum_QuitType(PyObject* obj) -> QuitType {
return GetPyEnum(BasePython::ObjID::kQuitTypeClass, obj);
}
-auto BasePython::GetPyEnum_TimeFormat(PyObject* obj) -> TimeFormat {
- return GetPyEnum(BasePython::ObjID::kTimeFormatClass, obj);
-}
+// auto BasePython::GetPyEnum_TimeFormat(PyObject* obj) -> TimeFormat {
+// return GetPyEnum(BasePython::ObjID::kTimeFormatClass, obj);
+// }
auto BasePython::IsPyEnum_InputType(PyObject* obj) -> bool {
return IsPyEnum(BasePython::ObjID::kInputTypeClass, obj);
diff --git a/src/ballistica/base/python/base_python.h b/src/ballistica/base/python/base_python.h
index e5cf4d50..61237013 100644
--- a/src/ballistica/base/python/base_python.h
+++ b/src/ballistica/base/python/base_python.h
@@ -91,8 +91,6 @@ class BasePython {
kWidgetNotFoundError,
kActivityNotFoundError,
kSessionNotFoundError,
- kTimeFormatClass,
- kTimeTypeClass,
kQuitTypeClass,
kInputTypeClass,
kPermissionClass,
@@ -156,8 +154,8 @@ class BasePython {
static auto GetPyEnum_Permission(PyObject* obj) -> Permission;
static auto GetPyEnum_SpecialChar(PyObject* obj) -> SpecialChar;
- static auto GetPyEnum_TimeType(PyObject* obj) -> TimeType;
- static auto GetPyEnum_TimeFormat(PyObject* obj) -> TimeFormat;
+ // static auto GetPyEnum_TimeType(PyObject* obj) -> TimeType;
+ // static auto GetPyEnum_TimeFormat(PyObject* obj) -> TimeFormat;
static auto IsPyEnum_InputType(PyObject* obj) -> bool;
static auto GetPyEnum_InputType(PyObject* obj) -> InputType;
static auto GetPyEnum_QuitType(PyObject* obj) -> QuitType;
diff --git a/src/ballistica/base/python/methods/python_methods_app.cc b/src/ballistica/base/python/methods/python_methods_base_1.cc
similarity index 99%
rename from src/ballistica/base/python/methods/python_methods_app.cc
rename to src/ballistica/base/python/methods/python_methods_base_1.cc
index 12ddfd05..97d285bb 100644
--- a/src/ballistica/base/python/methods/python_methods_app.cc
+++ b/src/ballistica/base/python/methods/python_methods_base_1.cc
@@ -1,6 +1,6 @@
// Released under the MIT License. See LICENSE for details.
-#include "ballistica/base/python/methods/python_methods_app.h"
+#include "ballistica/base/python/methods/python_methods_base_1.h"
#include "ballistica/base/app_adapter/app_adapter.h"
#include "ballistica/base/app_mode/app_mode_empty.h"
@@ -1697,7 +1697,7 @@ static PyMethodDef PyInvokeMainMenuDef = {
};
// -----------------------------------------------------------------------------
-auto PythonMethodsApp::GetMethods() -> std::vector {
+auto PythonMethodsBase1::GetMethods() -> std::vector {
return {
PyAppNameDef,
PyAppIsActiveDef,
diff --git a/src/ballistica/base/python/methods/python_methods_app.h b/src/ballistica/base/python/methods/python_methods_base_1.h
similarity index 57%
rename from src/ballistica/base/python/methods/python_methods_app.h
rename to src/ballistica/base/python/methods/python_methods_base_1.h
index 558a76ac..06bc930e 100644
--- a/src/ballistica/base/python/methods/python_methods_app.h
+++ b/src/ballistica/base/python/methods/python_methods_base_1.h
@@ -1,7 +1,7 @@
// Released under the MIT License. See LICENSE for details.
-#ifndef BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_APP_H_
-#define BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_APP_H_
+#ifndef BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_BASE_1_H_
+#define BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_BASE_1_H_
#include
@@ -10,11 +10,11 @@
namespace ballistica::base {
/// Python methods related to app functionality.
-class PythonMethodsApp {
+class PythonMethodsBase1 {
public:
static auto GetMethods() -> std::vector;
};
} // namespace ballistica::base
-#endif // BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_APP_H_
+#endif // BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_BASE_1_H_
diff --git a/src/ballistica/base/python/methods/python_methods_graphics.cc b/src/ballistica/base/python/methods/python_methods_base_2.cc
similarity index 83%
rename from src/ballistica/base/python/methods/python_methods_graphics.cc
rename to src/ballistica/base/python/methods/python_methods_base_2.cc
index 68b4b102..f0606522 100644
--- a/src/ballistica/base/python/methods/python_methods_graphics.cc
+++ b/src/ballistica/base/python/methods/python_methods_base_2.cc
@@ -1,6 +1,6 @@
// Released under the MIT License. See LICENSE for details.
-#include "ballistica/base/python/methods/python_methods_graphics.h"
+#include "ballistica/base/python/methods/python_methods_base_2.h"
#include "ballistica/base/app_adapter/app_adapter.h"
#include "ballistica/base/assets/assets.h"
@@ -9,8 +9,10 @@
#include "ballistica/base/graphics/support/screen_messages.h"
#include "ballistica/base/graphics/text/text_graphics.h"
#include "ballistica/base/logic/logic.h"
+#include "ballistica/base/platform/base_platform.h"
#include "ballistica/base/python/base_python.h"
#include "ballistica/base/python/support/python_context_call_runnable.h"
+#include "ballistica/base/ui/ui.h"
#include "ballistica/core/core.h"
#include "ballistica/core/platform/core_platform.h"
#include "ballistica/shared/foundation/macros.h"
@@ -24,6 +26,147 @@ namespace ballistica::base {
#pragma clang diagnostic push
#pragma ide diagnostic ignored "hicpp-signed-bitwise"
+// ------------------------------- open_url ------------------------------------
+
+static auto PyOpenURL(PyObject* self, PyObject* args,
+ PyObject* keywds) -> PyObject* {
+ BA_PYTHON_TRY;
+ const char* address{};
+ int force_fallback{};
+ static const char* kwlist[] = {"address", "force_fallback", nullptr};
+ if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|p",
+ const_cast(kwlist), &address,
+ &force_fallback)) {
+ return nullptr;
+ }
+ if (force_fallback) {
+ g_base->ui->ShowURL(address);
+ } else {
+ g_base->platform->OpenURL(address);
+ }
+ Py_RETURN_NONE;
+ BA_PYTHON_CATCH;
+}
+
+static PyMethodDef PyOpenURLDef = {
+ "open_url", // name
+ (PyCFunction)PyOpenURL, // method
+ METH_VARARGS | METH_KEYWORDS, // flags
+
+ "open_url(address: str, force_fallback: bool = False) -> None\n"
+ "\n"
+ "Open the provided URL.\n"
+ "\n"
+ "Category: **General Utility Functions**\n"
+ "\n"
+ "Attempts to open the provided url in a web-browser. If that is not\n"
+ "possible (or force_fallback is True), instead displays the url as\n"
+ "a string and/or qrcode."};
+
+// --------------------- overlay_web_browser_is_supported ----------------------
+
+static auto PyOverlayWebBrowserIsSupported(PyObject* self, PyObject* args,
+ PyObject* keywds) -> PyObject* {
+ BA_PYTHON_TRY;
+ if (g_base->platform->OverlayWebBrowserIsSupported()) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+ BA_PYTHON_CATCH;
+}
+
+static PyMethodDef PyOverlayWebBrowserIsSupportedDef = {
+ "overlay_web_browser_is_supported", // name
+ (PyCFunction)PyOverlayWebBrowserIsSupported, // method
+ METH_NOARGS, // flags
+
+ "overlay_web_browser_is_supported() -> bool\n"
+ "\n"
+ "Return whether an overlay web browser is supported here.\n"
+ "\n"
+ "Category: **General Utility Functions**\n"
+ "\n"
+ "An overlay web browser is a small dialog that pops up over the top\n"
+ "of the main engine window. It can be used for performing simple\n"
+ "tasks such as sign-ins."};
+
+// --------------------- overlay_web_browser_open_url --------------------------
+
+static auto PyOverlayWebBrowserOpenURL(PyObject* self, PyObject* args,
+ PyObject* keywds) -> PyObject* {
+ BA_PYTHON_TRY;
+ const char* address{};
+ static const char* kwlist[] = {"address", nullptr};
+ if (!PyArg_ParseTupleAndKeywords(args, keywds, "s",
+ const_cast(kwlist), &address)) {
+ return nullptr;
+ }
+ g_base->platform->OverlayWebBrowserOpenURL(address);
+
+ Py_RETURN_NONE;
+ BA_PYTHON_CATCH;
+}
+
+static PyMethodDef PyOverlayWebBrowserOpenURLDef = {
+ "overlay_web_browser_open_url", // name
+ (PyCFunction)PyOverlayWebBrowserOpenURL, // method
+ METH_VARARGS | METH_KEYWORDS, // flags
+
+ "overlay_web_browser_open_url(address: str) -> None\n"
+ "\n"
+ "Open the provided URL in an overlayw web browser.\n"
+ "\n"
+ "Category: **General Utility Functions**\n"
+ "\n"
+ "An overlay web browser is a small dialog that pops up over the top\n"
+ "of the main engine window. It can be used for performing simple\n"
+ "tasks such as sign-ins."};
+
+// --------------------- overlay_web_browser_is_open ----------------------
+
+static auto PyOverlayWebBrowserIsOpen(PyObject* self, PyObject* args,
+ PyObject* keywds) -> PyObject* {
+ BA_PYTHON_TRY;
+ if (g_base->platform->OverlayWebBrowserIsOpen()) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+ BA_PYTHON_CATCH;
+}
+
+static PyMethodDef PyOverlayWebBrowserIsOpenDef = {
+ "overlay_web_browser_is_open", // name
+ (PyCFunction)PyOverlayWebBrowserIsOpen, // method
+ METH_NOARGS, // flags
+
+ "overlay_web_browser_is_open() -> bool\n"
+ "\n"
+ "Return whether an overlay web browser is open currently.\n"
+ "\n"
+ "Category: **General Utility Functions**"};
+
+// ------------------------ overlay_web_browser_close --------------------------
+
+static auto PyOverlayWebBrowserClose(PyObject* self, PyObject* args,
+ PyObject* keywds) -> PyObject* {
+ BA_PYTHON_TRY;
+ g_base->platform->OverlayWebBrowserClose();
+ Py_RETURN_NONE;
+ BA_PYTHON_CATCH;
+}
+
+static PyMethodDef PyOverlayWebBrowserCloseDef = {
+ "overlay_web_browser_close", // name
+ (PyCFunction)PyOverlayWebBrowserClose, // method
+ METH_NOARGS, // flags
+
+ "overlay_web_browser_close() -> bool\n"
+ "\n"
+ "Close any open overlay web browser.\n"
+ "\n"
+ "Category: **General Utility Functions**\n"};
// ---------------------------- screenmessage ----------------------------------
static auto PyScreenMessage(PyObject* self, PyObject* args,
@@ -788,8 +931,13 @@ static PyMethodDef PyShowProgressBarDef = {
// -----------------------------------------------------------------------------
-auto PythonMethodsGraphics::GetMethods() -> std::vector {
+auto PythonMethodsBase2::GetMethods() -> std::vector {
return {
+ PyOpenURLDef,
+ PyOverlayWebBrowserIsSupportedDef,
+ PyOverlayWebBrowserOpenURLDef,
+ PyOverlayWebBrowserIsOpenDef,
+ PyOverlayWebBrowserCloseDef,
PyGetDisplayResolutionDef,
PyGetCameraPositionDef,
PyGetCameraTargetDef,
diff --git a/src/ballistica/base/python/methods/python_methods_graphics.h b/src/ballistica/base/python/methods/python_methods_base_2.h
similarity index 58%
rename from src/ballistica/base/python/methods/python_methods_graphics.h
rename to src/ballistica/base/python/methods/python_methods_base_2.h
index c8f661a1..ece96be4 100644
--- a/src/ballistica/base/python/methods/python_methods_graphics.h
+++ b/src/ballistica/base/python/methods/python_methods_base_2.h
@@ -1,7 +1,7 @@
// Released under the MIT License. See LICENSE for details.
-#ifndef BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_GRAPHICS_H_
-#define BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_GRAPHICS_H_
+#ifndef BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_BASE_2_H_
+#define BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_BASE_2_H_
#include
@@ -10,11 +10,11 @@
namespace ballistica::base {
/// Graphics related individual python methods for our module.
-class PythonMethodsGraphics {
+class PythonMethodsBase2 {
public:
static auto GetMethods() -> std::vector;
};
} // namespace ballistica::base
-#endif // BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_GRAPHICS_H_
+#endif // BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_BASE_2_H_
diff --git a/src/ballistica/base/python/methods/python_methods_misc.cc b/src/ballistica/base/python/methods/python_methods_base_3.cc
similarity index 99%
rename from src/ballistica/base/python/methods/python_methods_misc.cc
rename to src/ballistica/base/python/methods/python_methods_base_3.cc
index 798db3de..6a6aa4d1 100644
--- a/src/ballistica/base/python/methods/python_methods_misc.cc
+++ b/src/ballistica/base/python/methods/python_methods_base_3.cc
@@ -1,6 +1,6 @@
// Released under the MIT License. See LICENSE for details.
-#include "ballistica/base/python/methods/python_methods_misc.h"
+#include "ballistica/base/python/methods/python_methods_base_3.h"
#include
#include
@@ -409,8 +409,9 @@ static PyMethodDef PyGetThreadNameDef = {
// --------------------------------- ehv ---------------------------------------
-// returns an extra hash value that can be incorporated into security checks;
-// this contains things like whether console commands have been run, etc.
+// Returns an extra hash value that can be incorporated into security
+// checks; this contains things like whether console commands have been run,
+// etc.
auto PyExtraHashValue(PyObject* self, PyObject* args,
PyObject* keywds) -> PyObject* {
BA_PYTHON_TRY;
@@ -523,9 +524,9 @@ static PyMethodDef PyContainsPythonDistDef = {
static auto PyDebugPrintPyErr(PyObject* self, PyObject* args) -> PyObject* {
if (PyErr_Occurred()) {
- // we pass zero here to avoid grabbing references to this exception
- // which can cause objects to stick around and trip up our deletion checks
- // (nodes, actors existing after their games have ended)
+ // We pass zero here to avoid grabbing references to this exception
+ // which can cause objects to stick around and trip up our deletion
+ // checks (nodes, actors existing after their games have ended).
PyErr_PrintEx(0);
PyErr_Clear();
}
@@ -1827,7 +1828,7 @@ static PyMethodDef PyGetInputIdleTimeDef = {
};
// -----------------------------------------------------------------------------
-auto PythonMethodsMisc::GetMethods() -> std::vector {
+auto PythonMoethodsBase3::GetMethods() -> std::vector {
return {
PyClipboardIsSupportedDef,
PyClipboardHasTextDef,
diff --git a/src/ballistica/base/python/methods/python_methods_misc.h b/src/ballistica/base/python/methods/python_methods_base_3.h
similarity index 59%
rename from src/ballistica/base/python/methods/python_methods_misc.h
rename to src/ballistica/base/python/methods/python_methods_base_3.h
index d3f0b57c..e781985b 100644
--- a/src/ballistica/base/python/methods/python_methods_misc.h
+++ b/src/ballistica/base/python/methods/python_methods_base_3.h
@@ -1,7 +1,7 @@
// Released under the MIT License. See LICENSE for details.
-#ifndef BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_MISC_H_
-#define BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_MISC_H_
+#ifndef BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_BASE_3_H_
+#define BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_BASE_3_H_
#include
@@ -10,11 +10,11 @@
namespace ballistica::base {
/// Methods that don't have a clear home. Should try to clear this out.
-class PythonMethodsMisc {
+class PythonMoethodsBase3 {
public:
static auto GetMethods() -> std::vector;
};
} // namespace ballistica::base
-#endif // BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_MISC_H_
+#endif // BALLISTICA_BASE_PYTHON_METHODS_PYTHON_METHODS_BASE_3_H_
diff --git a/src/ballistica/base/support/stdio_console.cc b/src/ballistica/base/support/stdio_console.cc
index 521db5a5..fc5a3271 100644
--- a/src/ballistica/base/support/stdio_console.cc
+++ b/src/ballistica/base/support/stdio_console.cc
@@ -33,8 +33,6 @@ void StdioConsole::StartInMainThread_() {
event_loop()->PushCall([this] {
bool stdin_is_terminal = g_core->platform->is_stdin_a_terminal();
- g_base->platform->SafeStdinFGetSInit();
-
while (true) {
// Print a prompt if we're a tty. We send this to the logic thread so
// it happens AFTER the results of the last script-command message we
diff --git a/src/ballistica/base/ui/ui.cc b/src/ballistica/base/ui/ui.cc
index 6c83816e..d57d3118 100644
--- a/src/ballistica/base/ui/ui.cc
+++ b/src/ballistica/base/ui/ui.cc
@@ -567,7 +567,10 @@ void UI::DrawDevConsoleButton_(FrameDef* frame_def) {
void UI::ShowURL(const std::string& url) {
if (auto* ui_delegate = g_base->ui->delegate()) {
- ui_delegate->DoShowURL(url);
+ // We can be called from any thread but DoShowURL expects to be run in
+ // the logic thread.
+ g_base->logic->event_loop()->PushCall(
+ [ui_delegate, url] { ui_delegate->DoShowURL(url); });
} else {
Log(LogLevel::kWarning, "UI::ShowURL called without ui_delegate present.");
}
diff --git a/src/ballistica/base/ui/ui.h b/src/ballistica/base/ui/ui.h
index f30440d7..fa903322 100644
--- a/src/ballistica/base/ui/ui.h
+++ b/src/ballistica/base/ui/ui.h
@@ -54,11 +54,6 @@ class UI {
/// browser). Can be called from any thread.
void ShowURL(const std::string& url);
- /// High level call to request a quit; ideally with a confirmation ui.
- /// When a UI can't be shown, triggers an immediate shutdown. This can be
- /// called from any thread.
- // void ConfirmQuit();
-
/// Return whether there is UI present in either the main or overlay
/// stacks. Generally this implies the focus should be on the UI.
auto MainMenuVisible() const -> bool;
diff --git a/src/ballistica/base/ui/ui_delegate.h b/src/ballistica/base/ui/ui_delegate.h
index c3e89fe5..5bcebc81 100644
--- a/src/ballistica/base/ui/ui_delegate.h
+++ b/src/ballistica/base/ui/ui_delegate.h
@@ -27,8 +27,10 @@ class UIDelegateInterface {
virtual void DoApplyAppConfig() = 0;
virtual void DoHandleDeviceMenuPress(base::InputDevice* device) = 0;
+
+ /// Called by ShowURL(). Will always be called in the logic thread.
virtual void DoShowURL(const std::string& url) = 0;
- // virtual void DoQuitWindow() = 0;
+
virtual auto MainMenuVisible() -> bool = 0;
virtual auto PartyIconVisible() -> bool = 0;
virtual void ActivatePartyIcon() = 0;
diff --git a/src/ballistica/core/platform/core_platform.h b/src/ballistica/core/platform/core_platform.h
index a547faa7..978b5e1a 100644
--- a/src/ballistica/core/platform/core_platform.h
+++ b/src/ballistica/core/platform/core_platform.h
@@ -249,8 +249,8 @@ class CorePlatform {
#pragma mark MUSIC PLAYBACK ----------------------------------------------------
- // FIXME: currently these are wired up on Android; need to generalize
- // to support mac/itunes or other music player types.
+ // FIXME: currently these are wired up on Android; need to generalize to
+ // support mac/itunes or other music player types.
virtual void MusicPlayerPlay(PyObject* target);
virtual void MusicPlayerStop();
virtual void MusicPlayerShutdown();
@@ -263,8 +263,8 @@ class CorePlatform {
// Return whether we have the ability to show *any* ads.
virtual auto GetHasAds() -> bool;
- // Return whether we have the ability to show longer-form video ads (suitable
- // for rewards).
+ // Return whether we have the ability to show longer-form video ads
+ // (suitable for rewards).
virtual auto GetHasVideoAds() -> bool;
#pragma mark GAME SERVICES -----------------------------------------------------
@@ -294,10 +294,10 @@ class CorePlatform {
#pragma mark ERRORS & DEBUGGING ------------------------------------------------
- /// Should return a subclass of NativeStackTrace allocated via new. It
- /// 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.
+ /// Should return a subclass of NativeStackTrace allocated via new. It 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 GetNativeStackTrace() -> NativeStackTrace*;
/// Optionally override fatal error reporting. If true is returned, default
@@ -333,9 +333,10 @@ class CorePlatform {
/// Print a log message to be included in crash logs or other debug
/// mechanisms (example: Crashlytics). V1-cloud-log messages get forwarded
- /// to here as well. It can be useful to call this directly to report extra
- /// details that may help in debugging, as these calls are not considered
- /// 'noteworthy' or presented to the user as standard Log() calls are.
+ /// to here as well. It can be useful to call this directly to report
+ /// extra details that may help in debugging, as these calls are not
+ /// considered 'noteworthy' or presented to the user as standard Log()
+ /// calls are.
void LowLevelDebugLog(const std::string& msg);
#pragma mark MISC --------------------------------------------------------------
@@ -468,7 +469,7 @@ class CorePlatform {
std::string volatile_data_dir_;
std::string replays_dir_;
- // temp.
+ // Temp; should be able to remove this once Swift 5.10 is out.
std::list mac_music_app_playlists_;
};
diff --git a/src/ballistica/scene_v1/scene_v1.h b/src/ballistica/scene_v1/scene_v1.h
index 3cb60954..2d41bbc5 100644
--- a/src/ballistica/scene_v1/scene_v1.h
+++ b/src/ballistica/scene_v1/scene_v1.h
@@ -141,6 +141,26 @@ class SceneSound;
class SceneTexture;
typedef Node* NodeCreateFunc(Scene* sg);
+/// Specifies the type of time for various operations to target/use.
+///
+/// 'sim' time is the local simulation time for an activity or session.
+/// It can proceed at different rates depending on game speed, stops
+/// for pauses, etc.
+///
+/// 'base' is the baseline time for an activity or session. It proceeds
+/// consistently regardless of game speed or pausing, but may stop during
+/// occurrences such as network outages.
+///
+/// 'real' time is mostly based on clock time, with a few exceptions. It may
+/// not advance while the app is backgrounded for instance. (the engine
+/// attempts to prevent single large time jumps from occurring)
+enum class TimeType : uint8_t {
+ kSim,
+ kBase,
+ kReal,
+ kLast // Sentinel.
+};
+
/// Standard messages to send to nodes.
enum class NodeMessageType {
/// Generic flash - no args.
diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc
index e68cd538..7cb51eb9 100644
--- a/src/ballistica/shared/ballistica.cc
+++ b/src/ballistica/shared/ballistica.cc
@@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
namespace ballistica {
// These are set automatically via script; don't modify them here.
-const int kEngineBuildNumber = 21852;
+const int kEngineBuildNumber = 21863;
const char* kEngineVersion = "1.7.35";
const int kEngineApiVersion = 8;
diff --git a/src/ballistica/shared/foundation/types.h b/src/ballistica/shared/foundation/types.h
index a785406f..8a8f45dd 100644
--- a/src/ballistica/shared/foundation/types.h
+++ b/src/ballistica/shared/foundation/types.h
@@ -148,39 +148,6 @@ enum class UIScale : uint8_t {
kLast // Sentinel.
};
-// BA_EXPORT_PYTHON_ENUM
-/// Specifies the type of time for various operations to target/use.
-///
-/// Category: Enums
-///
-/// 'sim' time is the local simulation time for an activity or session.
-/// It can proceed at different rates depending on game speed, stops
-/// for pauses, etc.
-///
-/// 'base' is the baseline time for an activity or session. It proceeds
-/// consistently regardless of game speed or pausing, but may stop during
-/// occurrences such as network outages.
-///
-/// 'real' time is mostly based on clock time, with a few exceptions. It may
-/// not advance while the app is backgrounded for instance. (the engine
-/// attempts to prevent single large time jumps from occurring)
-enum class TimeType : uint8_t {
- kSim,
- kBase,
- kReal,
- kLast // Sentinel.
-};
-
-// BA_EXPORT_PYTHON_ENUM
-/// Specifies the format time values are provided in.
-///
-/// Category: Enums
-enum class TimeFormat : uint8_t {
- kSeconds,
- kMilliseconds,
- kLast // Sentinel.
-};
-
// BA_EXPORT_PYTHON_ENUM
/// Permissions that can be requested from the OS.
///
diff --git a/src/ballistica/ui_v1/python/methods/python_methods_ui_v1.cc b/src/ballistica/ui_v1/python/methods/python_methods_ui_v1.cc
index 95d4132f..e6a7b2be 100644
--- a/src/ballistica/ui_v1/python/methods/python_methods_ui_v1.cc
+++ b/src/ballistica/ui_v1/python/methods/python_methods_ui_v1.cc
@@ -1789,7 +1789,7 @@ static auto PyHScrollWidget(PyObject* self, PyObject* args,
widget = Object::New();
}
- // set applicable values ----------------------------
+ // Set applicable values.
if (size_obj != Py_None) {
Point2D p = Python::GetPyPoint2D(size_obj);
widget->SetWidth(p.x);
@@ -2050,7 +2050,7 @@ static auto PyTextWidget(PyObject* self, PyObject* args,
widget = Object::New();
}
- // Set applicable values ----------------------------
+ // Set applicable values.
if (max_chars_obj != Py_None) {
widget->set_max_chars(
static_cast_check_fit(Python::GetPyInt64(max_chars_obj)));
@@ -2071,7 +2071,7 @@ static auto PyTextWidget(PyObject* self, PyObject* args,
widget->set_auto_select(Python::GetPyBool(autoselect_obj));
}
if (transition_delay_obj != Py_None) {
- // we accept this as seconds; widget takes milliseconds
+ // We accept this as seconds; widget takes milliseconds.
widget->set_transition_delay(1000.0f
* Python::GetPyFloat(transition_delay_obj));
}
@@ -2576,49 +2576,6 @@ static PyMethodDef PyBackPressDef = {
"(internal)",
};
-// ------------------------------- open_url ------------------------------------
-
-static auto PyOpenURL(PyObject* self, PyObject* args,
- PyObject* keywds) -> PyObject* {
- BA_PYTHON_TRY;
- const char* address{};
- int force_internal{0};
- static const char* kwlist[] = {"address", "force_internal", nullptr};
- if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|p",
- const_cast(kwlist), &address,
- &force_internal)) {
- return nullptr;
- }
- // Need to pass a self-contained string to a lambda; not a char*.
- std::string address_s{address};
-
- assert(g_base->app_adapter);
- if (force_internal) {
- g_base->ui->ShowURL(address);
- } else {
- g_base->app_adapter->PushMainThreadCall(
- [address_s] { g_base->platform->OpenURL(address_s); });
- }
- Py_RETURN_NONE;
- BA_PYTHON_CATCH;
-}
-
-static PyMethodDef PyOpenURLDef = {
- "open_url", // name
- (PyCFunction)PyOpenURL, // method
- METH_VARARGS | METH_KEYWORDS, // flags
-
- "open_url(address: str, force_internal: bool = False) -> None\n"
- "\n"
- "Open a provided URL.\n"
- "\n"
- "Category: **General Utility Functions**\n"
- "\n"
- "Open the provided url in a web-browser, or display the URL\n"
- "string in a window if that isn't possible (or if force_internal\n"
- "is True).",
-};
-
// ------------------------ is_party_icon_visible ------------------------------
static auto PyIsPartyIconVisible(PyObject* self) -> PyObject* {
@@ -2697,7 +2654,6 @@ static PyMethodDef PyIsAvailableDef = {
auto PythonMethodsUIV1::GetMethods() -> std::vector {
return {
PyIsPartyIconVisibleDef,
- PyOpenURLDef,
PyBackPressDef,
PyGetSpecialWidgetDef,
PySetPartyWindowOpenDef,
diff --git a/src/ballistica/ui_v1/python/ui_v1_python.cc b/src/ballistica/ui_v1/python/ui_v1_python.cc
index 7843dd6f..b585a962 100644
--- a/src/ballistica/ui_v1/python/ui_v1_python.cc
+++ b/src/ballistica/ui_v1/python/ui_v1_python.cc
@@ -71,16 +71,15 @@ auto UIV1Python::GetPyWidget(PyObject* o) -> Widget* {
}
void UIV1Python::ShowURL(const std::string& url) {
- g_base->logic->event_loop()->PushCall([this, url] {
- assert(g_base->InLogicThread());
- if (objs().Exists(ObjID::kShowURLWindowCall)) {
- base::ScopedSetContext ssc(nullptr);
- PythonRef args(Py_BuildValue("(s)", url.c_str()), PythonRef::kSteal);
- objs().Get(ObjID::kShowURLWindowCall).Call(args);
- } else {
- Log(LogLevel::kError, "ShowURLWindowCall nonexistent.");
- }
- });
+ assert(g_base->InLogicThread());
+
+ if (objs().Exists(ObjID::kShowURLWindowCall)) {
+ base::ScopedSetContext ssc(nullptr);
+ PythonRef args(Py_BuildValue("(s)", url.c_str()), PythonRef::kSteal);
+ objs().Get(ObjID::kShowURLWindowCall).Call(args);
+ } else {
+ Log(LogLevel::kError, "ShowURLWindowCall nonexistent.");
+ }
}
void UIV1Python::HandleDeviceMenuPress(base::InputDevice* device) {
diff --git a/src/ballistica/ui_v1/ui_v1.h b/src/ballistica/ui_v1/ui_v1.h
index e2409d9a..79994412 100644
--- a/src/ballistica/ui_v1/ui_v1.h
+++ b/src/ballistica/ui_v1/ui_v1.h
@@ -85,7 +85,6 @@ class UIV1FeatureSet : public FeatureSetNativeComponent,
static void OnModuleExec(PyObject* module);
void DoHandleDeviceMenuPress(base::InputDevice* device) override;
void DoShowURL(const std::string& url) override;
- // void DoQuitWindow() override;
auto MainMenuVisible() -> bool override;
auto PartyIconVisible() -> bool override;
void ActivatePartyIcon() override;
diff --git a/src/meta/Makefile b/src/meta/Makefile
index 8290ba8b..65c7956b 100644
--- a/src/meta/Makefile
+++ b/src/meta/Makefile
@@ -64,7 +64,7 @@ $(PROJ_SRC_DIR)/ballistica/ui_v1/mgen/pyembed/binding_ui_v1.inc : bauiv1meta/pye
$(PROJ_SRC_DIR)/assets/ba_data/python/babase/_mgen/__init__.py : $(TOOLS_DIR)/batools/pcommands.py
@$(PCOMMAND) gen_python_init_module $@
-$(PROJ_SRC_DIR)/assets/ba_data/python/babase/_mgen/enums.py : $(PROJ_DIR)/src/ballistica/shared/foundation/types.h $(TOOLS_DIR)/batools/pythonenumsmodule.py
+$(PROJ_SRC_DIR)/assets/ba_data/python/babase/_mgen/enums.py : $(PROJ_DIR)/src/ballistica/shared/foundation/types.h $(TOOLS_DIR)/batools/enumspython.py
@$(PCOMMAND) gen_python_enums_module $< $@
# __AUTOGENERATED_PUBLIC_END__
diff --git a/src/meta/babasemeta/pyembed/binding_base.py b/src/meta/babasemeta/pyembed/binding_base.py
index ec06b3d5..f9db5a06 100644
--- a/src/meta/babasemeta/pyembed/binding_base.py
+++ b/src/meta/babasemeta/pyembed/binding_base.py
@@ -72,8 +72,6 @@ values = [
_error.WidgetNotFoundError, # kWidgetNotFoundError
_error.ActivityNotFoundError, # kActivityNotFoundError
_error.SessionNotFoundError, # kSessionNotFoundError
- enums.TimeFormat, # kTimeFormatClass
- enums.TimeType, # kTimeTypeClass
enums.QuitType, # kQuitTypeClass
enums.InputType, # kInputTypeClass
enums.Permission, # kPermissionClass
diff --git a/tools/bacommon/app.py b/tools/bacommon/app.py
index 85a00d98..5f42c898 100644
--- a/tools/bacommon/app.py
+++ b/tools/bacommon/app.py
@@ -15,7 +15,7 @@ if TYPE_CHECKING:
class AppInterfaceIdiom(Enum):
- """A general form-factor or way of experiencing a Ballistica app.
+ """A general form-factor or method of experiencing a Ballistica app.
Note that it is possible for a running app to switch idioms (for
instance if a mobile device or computer is connected to a TV).
@@ -32,11 +32,11 @@ class AppExperience(Enum):
"""A particular experience that can be provided by a Ballistica app.
This is one metric used to isolate different playerbases from
- eachother where there might be no technical barriers doing so.
- For example, a casual one-hand-playable phone game and an augmented
+ each other where there might be no technical barriers doing so. For
+ example, a casual one-hand-playable phone game and an augmented
reality tabletop game may both use the same scene-versions and
networking-protocols and whatnot, but it would make no sense to
- allow players of one join servers for the other. AppExperience can
+ allow players of one to join servers of the other. AppExperience can
be used to keep these player bases separate.
Generally a single Ballistica app targets a single AppExperience.
@@ -47,13 +47,14 @@ class AppExperience(Enum):
visible to client apps designed for that play style.
"""
- # An experience that is supported everywhere. Used
- # for the default empty AppMode when starting the app, etc.
+ # An experience that is supported everywhere. Used for the default
+ # empty AppMode when starting the app, etc.
EMPTY = 'empty'
# The traditional BombSquad experience: multiple players using
- # controllers in a single arena small enough for all action to be
- # viewed on a single screen.
+ # traditional game controllers (or touch screen equivalents) in a
+ # single arena small enough for all action to be viewed on a single
+ # screen.
MELEE = 'melee'
# The traditional BombSquad Remote experience; buttons on a
@@ -72,7 +73,7 @@ class AppArchitecture(Enum):
class AppPlatform(Enum):
- """Overall platform a Ballistica build can be targeting.
+ """Overall platform a Ballistica build is targeting.
Each distinct flavor of an app has a unique combination
of AppPlatform and AppVariant. Generally platform describes
diff --git a/tools/bacommon/cloud.py b/tools/bacommon/cloud.py
index 66d57dd2..8376ef81 100644
--- a/tools/bacommon/cloud.py
+++ b/tools/bacommon/cloud.py
@@ -32,9 +32,12 @@ class LoginProxyRequestMessage(Message):
class LoginProxyRequestResponse(Response):
"""Response to a request for a login proxy."""
- # URL to direct the user to for login.
+ # URL to direct the user to for sign in.
url: Annotated[str, IOAttrs('u')]
+ # URL to use for overlay-web-browser sign ins.
+ url_overlay: Annotated[str, IOAttrs('uo')]
+
# Proxy-Login id for querying results.
proxyid: Annotated[str, IOAttrs('p')]
diff --git a/tools/batools/pythonenumsmodule.py b/tools/batools/enumspython.py
similarity index 93%
rename from tools/batools/pythonenumsmodule.py
rename to tools/batools/enumspython.py
index daaa42c8..0ff660e2 100755
--- a/tools/batools/pythonenumsmodule.py
+++ b/tools/batools/enumspython.py
@@ -1,9 +1,12 @@
# Released under the MIT License. See LICENSE for details.
#
-"""Procedurally regenerates our python enums module.
+"""Generate a Python module containing Enum classes from C++ code.
-This scans core/types.h for tagged C++ enum types and generates corresponding
-python enums for them.
+Note that the general strategy moving forward is the opposite of
+this: to generate C++ code as needed from Python sources. That is
+generally a better direction to go since introspecting Python objects
+or source code ast is more foolproof than the text based parsing we
+are doing here.
"""
from __future__ import annotations
diff --git a/tools/batools/metamakefile.py b/tools/batools/metamakefile.py
index cd3d2b4c..87738c77 100755
--- a/tools/batools/metamakefile.py
+++ b/tools/batools/metamakefile.py
@@ -24,10 +24,10 @@ PROJ_DIR = '../..'
TOOLS_DIR = f'{PROJ_DIR}/tools'
PROJ_SRC_DIR = '..'
-# These should only be used for make targets since they use makefile vars.
-# Our makefile vars have the same names as above.
-# We could inline vars ourself but it's nice to build a makefile that feels
-# like one we'd build by hand.
+# These should only be used for make targets since they use makefile
+# vars. Our makefile vars have the same names as above. We could inline
+# vars ourself but it's nice to build a makefile that feels like one
+# we'd build by hand.
OUT_DIR_ROOT_CPP = '$(PROJ_SRC_DIR)/ballistica'
OUT_DIR_BASE_PYTHON = '$(PROJ_SRC_DIR)/assets/ba_data/python/babase/_mgen'
@@ -91,19 +91,18 @@ class MetaMakefileGenerator:
original = self._existing_data
lines = original.splitlines()
- # We'll generate manifests of all public/private files we generate
- # (not private-internal though).
+ # We'll generate manifests of all public/private files we
+ # generate (not private-internal though).
all_dsts_public: set[str] = set()
all_dsts_private: set[str] = set()
- # print('SRC', lines, '# __AUTOGENERATED_PUBLIC_BEGIN__' in lines)
-
auto_start_public = lines.index('# __AUTOGENERATED_PUBLIC_BEGIN__')
auto_end_public = lines.index('# __AUTOGENERATED_PUBLIC_END__')
auto_start_private = lines.index('# __AUTOGENERATED_PRIVATE_BEGIN__')
auto_end_private = lines.index('# __AUTOGENERATED_PRIVATE_END__')
- # Public targets (stuff with full sources available in public repo).
+ # Public targets (stuff with full sources available in public
+ # repo).
targets: list[Target] = []
pubtargets = targets
self._add_monolithic_register_modules_target(targets)
@@ -123,12 +122,13 @@ class MetaMakefileGenerator:
)
all_dsts_public.update(t.dst for t in targets)
- # Only rewrite the private section in the private repo; otherwise
- # keep the existing one intact.
+ # Only rewrite the private section in the private repo;
+ # otherwise keep the existing one intact.
if public:
our_lines_private = lines[auto_start_private + 1 : auto_end_private]
else:
- # Private targets (but available in public through efrocache).
+ # Private targets (but available in public through
+ # efrocache).
targets = []
our_lines_private_1 = (
_empty_line_if(bool(targets))
@@ -208,8 +208,8 @@ class MetaMakefileGenerator:
return out
all_dsts = set()
for target in targets:
- # We may need to make pipeline adjustments if/when we get filenames
- # with spaces in them.
+ # We may need to make pipeline adjustments if/when we get
+ # filenames with spaces in them.
if ' ' in target.dst:
raise CleanError(
'FIXME: need to account for spaces in filename'
@@ -230,7 +230,7 @@ class MetaMakefileGenerator:
Target(
src=[
'$(PROJ_DIR)/src/ballistica/shared/foundation/types.h',
- '$(TOOLS_DIR)/batools/pythonenumsmodule.py',
+ '$(TOOLS_DIR)/batools/enumspython.py',
],
dst=os.path.join(OUT_DIR_BASE_PYTHON, 'enums.py'),
cmd='$(PCOMMAND) gen_python_enums_module $< $@',
@@ -251,8 +251,8 @@ class MetaMakefileGenerator:
def _add_monolithic_register_modules_target(
self, targets: list[Target]
) -> None:
- # When any of our featuresets configs changes, rebuild our snippet
- # of code that registers them all.
+ # When any of our featuresets configs changes, rebuild our
+ # snippet of code that registers them all.
featureset_fnames = [
n
for n in os.listdir(
@@ -276,8 +276,8 @@ class MetaMakefileGenerator:
) -> None:
featuresets = [f for f in self._featuresets if internal == f.internal]
- # For featureset 'foo_bar', stuff under 'bafoobarmeta' goes
- # into 'ballistica/foo_bar/mgen'.
+ # For featureset 'foo_bar', stuff under 'bafoobarmeta' goes into
+ # 'ballistica/foo_bar/mgen'.
for featureset in featuresets:
entries.append(
(
@@ -344,8 +344,8 @@ class MetaMakefileGenerator:
def _add_pyembed_targets(self, targets: list[Target]) -> None:
entries: list[tuple[str, str]] = []
- # Map stuff from other featureset meta packages to a
- # mgen dir under their C++ root.
+ # Map stuff from other featureset meta packages to a mgen dir
+ # under their C++ root.
self._add_featureset_entries(entries, internal=False)
self._create_featureset_targets(entries, targets, internal=False)
diff --git a/tools/batools/pcommands.py b/tools/batools/pcommands.py
index 757876f7..fef3d776 100644
--- a/tools/batools/pcommands.py
+++ b/tools/batools/pcommands.py
@@ -916,7 +916,7 @@ def android_sdk_utils() -> None:
def gen_python_enums_module() -> None:
"""Update our procedurally generated python enums."""
- from batools.pythonenumsmodule import generate
+ from batools.enumspython import generate
pcommand.disallow_in_batch()