From bf94886aed27062edb566bfd04bb15b124c74331 Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 22 Aug 2023 09:38:15 -0700 Subject: [PATCH] tidying app classes --- .efrocachemap | 88 ++++---- CHANGELOG.md | 2 +- src/assets/ba_data/python/baenv.py | 2 +- src/ballistica/base/app/app.cc | 98 ++------- src/ballistica/base/app/app.h | 45 +---- src/ballistica/base/app/app_headless.cc | 10 +- src/ballistica/base/app/app_headless.h | 2 +- src/ballistica/base/app/app_sdl.cc | 190 +++++++++--------- src/ballistica/base/app/app_sdl.h | 31 ++- src/ballistica/base/app/app_vr.cc | 4 +- src/ballistica/base/app/app_vr.h | 2 +- src/ballistica/base/base.cc | 18 +- src/ballistica/base/base.h | 10 +- src/ballistica/base/graphics/gl/gl_sys.cc | 4 +- src/ballistica/base/graphics/graphics.cc | 5 +- .../base/input/device/joystick_input.cc | 2 +- src/ballistica/base/logic/logic.cc | 2 +- src/ballistica/base/networking/networking.cc | 2 +- src/ballistica/base/platform/base_platform.cc | 12 +- .../base/python/methods/python_methods_app.cc | 10 +- src/ballistica/base/support/plus_soft.h | 3 + src/ballistica/core/support/core_config.cc | 2 +- src/ballistica/core/support/core_config.h | 2 +- src/ballistica/shared/ballistica.cc | 2 +- src/ballistica/shared/foundation/event_loop.h | 6 +- .../python/methods/python_methods_ui_v1.cc | 10 +- src/ballistica/ui_v1/widget/text_widget.cc | 16 +- 27 files changed, 257 insertions(+), 323 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 8a640be6..7fe6fb5f 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4068,50 +4068,50 @@ "build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "60b5c6ab04b194345ff6257b70d69a5c", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "b9c878e7396fd1426c2a99fffd600aab", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "6619693fb688c49e3fd87ef9c9c5211a", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "a1f18844189de4fe40a56f345b33ef62", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "f04b028c0bdfbc84ce1d646977d0c06a", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "8e96e29356cc8157e5aa1cb30e597c78", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "d4cc2f2ed1648c310aba235b30b43c79", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "2c246e46c453d94e60be71f3f0d5eefe", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "7b25f37a94583dfdf277d5d55d4c8ee2", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "2ce3e00ae6d5ff8e65697b68438e213e", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "9a26cab66c09e657c0ac3233b1ecf0d7", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "b20ad6abed43e7bec2de8fa04bff71e2", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "29999f55a9ccb252c621e714a1d15c9c", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "3f75965547ef911e2ad85a7b1786eb43", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "7257acfca19121cc25be53e698c73d9c", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "8b45af314375a63d939a906d9f211bda", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "736b5398e8396be443695e8b2bd572d9", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "56e73294a44f2d1f5bff3f4a9f973c2e", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "5630f2dd810cf19d1c309a579a0febde", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "4c5506d6eb64252f0fb7275e13e3912c", - "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "85ba4e81a1f7ae2cff4b1355eb49904f", - "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "498921f7eb2afd327d4b900cb70e31f9", - "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "85ba4e81a1f7ae2cff4b1355eb49904f", - "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "498921f7eb2afd327d4b900cb70e31f9", - "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "ded5f785236bf64e644ee20041ac8342", - "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "c436a058b7204fa39f22eafc7ca7855f", - "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "ded5f785236bf64e644ee20041ac8342", - "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "c436a058b7204fa39f22eafc7ca7855f", - "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "fe0ba4b21528a557c5a434b8f2eeda41", - "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "7950a02c3d9a1088e9acd4c29bd3cb72", - "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "fe0ba4b21528a557c5a434b8f2eeda41", - "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "7950a02c3d9a1088e9acd4c29bd3cb72", - "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "870d11d339fd1b3acf66cc601ff29c83", - "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "0ab638b6602610bdaf432e3cc2464080", - "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "92394eb19387c363471ce134ac9e6a1b", - "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "0ab638b6602610bdaf432e3cc2464080", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "ac1e455123d1c71aa09a16f1e6c4ecad", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "68323b0304b2158b09d1af9573fc6d85", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "0f9b59502d1faf0b783420f78ee383f0", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "e5df1b61f11ec0e2b7a1b28b22390574", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "4d097132b48f21c218b7129ad4d5f9a4", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "6dc492eb1c9bf2e9e9fb591ea81fa253", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "ad53f8041a683789e5f16d762a3d3b2c", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "5d161b0abe97805381be809c0b5da828", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "6d094a3cd65948896b4c447261e81704", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "430032b34e9b9f85dbf78ef48b72d132", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "b61d8e726e0019cd4109aa5e9533867c", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "2c293043357d79e665bbbea2e5134cff", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "f793ef2f26fa13dad8d35e90c8c141d8", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "5c301636ebf4f824a69d27a0beb11218", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "8ec42bbe83ca4d0734f6e9697525cd7b", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "a88db549342f7b10820e6028eb25b552", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "d767a9da339452eca123eedc1a1613ab", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "fe23ddd3129d3ca1582a51e6ae6bd2f0", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "da61ad34ea9852ee90216b384b9fa810", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "5bcafd99e07f74fb5354d8dc51f9dcd3", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "fbabe1c5a50b4fc288990855109c0f9a", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "1ee18569ef3e9ff79f89d4fe63b1ab48", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "6f5b8dabf7e99183804a325ede1801af", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "85bdeabd281d3b99f3a493e9ea68205f", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "352dee4c52b8f5a41374ba991365f2dd", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "2b4255b6beaeb7792e3e0bb879d1549c", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "b01cff4e97ac0e9abc4552068f6e2816", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "74ee01e9a88eb4ce1acdeef34d30dd49", + "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "bf4e9fe0c457660b45d2e4546b8e32e4", + "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "de7dd11c6a017f9f28dd619b56463e95", + "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "bf4e9fe0c457660b45d2e4546b8e32e4", + "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "de7dd11c6a017f9f28dd619b56463e95", + "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "ee204e8f8b8fc35d68166d0491255f87", + "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "a79f838c7225f4bfb8d572a5caf79b91", + "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "ee204e8f8b8fc35d68166d0491255f87", + "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "a79f838c7225f4bfb8d572a5caf79b91", + "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "c3f22a4373f4179fa694c5de0f68cbb7", + "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "437ad30ef4a8de4c19da41047ea721df", + "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "c3f22a4373f4179fa694c5de0f68cbb7", + "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "437ad30ef4a8de4c19da41047ea721df", + "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "c1fa4493a7afcc41c77a2ddf0697f030", + "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "b2f88f60a0efd2fd8e1dea74ca79e925", + "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "acd5007aba0e74f5d3a3df6e7b3abab6", + "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "b2f88f60a0efd2fd8e1dea74ca79e925", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "77af3a22db2ea65aa1f7b6203363ff40", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "695204948e2b06fd91e05ee3e6a66e0a", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "723e0bd1d1218d2b84f4647638cbdec7", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "8206655af59a053685329b87046ff58d", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "c3ee54fd24061523dc56e983fef53b60", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "70f23230117e24af61cce73a597851ee", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "322f179c3b4ebe52c4cd9da8206e499c", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "6c17bf39253bb5bb3359786ae6f0246e", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318", "src/ballistica/base/mgen/pyembed/binding_base.inc": "eeddad968b176000e31c65be6206a2bc", diff --git a/CHANGELOG.md b/CHANGELOG.md index 06c21f28..d489b07f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.26 (build 21221, api 8, 2023-08-21) +### 1.7.26 (build 21232, api 8, 2023-08-22) - Various general improvements to the pcommand (project command) system. - Modules containing pcommand functions are now named with an 's' - so diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 10c108cf..d9d7eb03 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 = 21221 +TARGET_BALLISTICA_BUILD = 21232 TARGET_BALLISTICA_VERSION = '1.7.26' diff --git a/src/ballistica/base/app/app.cc b/src/ballistica/base/app/app.cc index 376f4f08..4a173f7b 100644 --- a/src/ballistica/base/app/app.cc +++ b/src/ballistica/base/app/app.cc @@ -19,8 +19,7 @@ namespace ballistica::base { -App::App(EventLoop* event_loop) - : event_loop_(event_loop), stress_test_(std::make_unique()) { +App::App() { // We modify some app behavior when run under the server manager. auto* envval = getenv("BA_SERVER_WRAPPER_MANAGED"); server_wrapper_managed_ = (envval && strcmp(envval, "1") == 0); @@ -40,6 +39,8 @@ void App::PostInit() { g_core->platform->GetLegacyUserAgentString()); } +App::~App() = default; + void App::DoLogicThreadApplyAppConfig() { // Note: this gets called in the logic thread since that's where // config reading happens. We should grab whatever values we need @@ -87,7 +88,7 @@ void App::RunRenderUpkeepCycle() { // Pump thread messages (we're being driven by frame-draw callbacks // so this is the only place that it gets done at). - event_loop()->RunSingleCycle(); + g_core->main_event_loop()->RunSingleCycle(); // Now do the general app event cycle for whoever needs to process things. RunEvents(); @@ -132,19 +133,17 @@ void App::LogicThreadShutdownComplete() { assert(g_core->InMainThread()); assert(g_core); - done_ = true; - // Flag our own event loop to exit (or tell the OS to do so for its own). if (ManagesEventLoop()) { - event_loop()->Quit(); + g_core->main_event_loop()->Quit(); } else { g_core->platform->QuitApp(); } } void App::RunEvents() { - // there's probably a better place for this... - stress_test_->Update(); + // There's probably a better place for this. + g_base->stress_test()->Update(); // Give platforms a chance to pump/handle their own events. // @@ -216,22 +215,6 @@ void App::OnAppResume_() { } } -auto App::GetProductPrice(const std::string& product) -> std::string { - std::scoped_lock lock(product_prices_mutex_); - auto i = product_prices_.find(product); - if (i == product_prices_.end()) { - return ""; - } else { - return i->second; - } -} - -void App::SetProductPrice(const std::string& product, - const std::string& price) { - std::scoped_lock lock(product_prices_mutex_); - product_prices_[product] = price; -} - void App::PauseApp() { assert(g_core); assert(g_core->InMainThread()); @@ -309,85 +292,37 @@ void App::PrimeMainThreadEventPump() { // Pump events manually until a screen gets created. // At that point we use frame-draws to drive our event loop. while (!g_base->graphics_server->initial_screen_created()) { - event_loop()->RunSingleCycle(); + g_core->main_event_loop()->RunSingleCycle(); core::CorePlatform::SleepMillisecs(1); } } #pragma mark Push-Calls -// FIXME - move this call to Platform. -void App::PushShowOnlineScoreUICall(const std::string& show, - const std::string& game, - const std::string& game_version) { - event_loop()->PushCall([show, game, game_version] { - assert(g_core->InMainThread()); - g_core->platform->ShowOnlineScoreUI(show, game, game_version); - }); -} - void App::PushPurchaseAckCall(const std::string& purchase, const std::string& order_id) { - event_loop()->PushCall([purchase, order_id] { + g_core->main_event_loop()->PushCall([purchase, order_id] { g_base->platform->PurchaseAck(purchase, order_id); }); } void App::PushPurchaseCall(const std::string& item) { - event_loop()->PushCall([item] { + g_core->main_event_loop()->PushCall([item] { assert(g_core->InMainThread()); g_base->platform->Purchase(item); }); } void App::PushRestorePurchasesCall() { - event_loop()->PushCall([] { + g_core->main_event_loop()->PushCall([] { assert(g_core->InMainThread()); g_base->platform->RestorePurchases(); }); } -void App::PushOpenURLCall(const std::string& url) { - event_loop()->PushCall([url] { g_base->platform->OpenURL(url); }); -} - -void App::PushSubmitScoreCall(const std::string& game, - const std::string& game_version, int64_t score) { - event_loop()->PushCall([game, game_version, score] { - g_core->platform->SubmitScore(game, game_version, score); - }); -} - -void App::PushAchievementReportCall(const std::string& achievement) { - event_loop()->PushCall( - [achievement] { g_core->platform->ReportAchievement(achievement); }); -} - -void App::PushStringEditCall(const std::string& name, const std::string& value, - int max_chars) { - event_loop()->PushCall([name, value, max_chars] { - static millisecs_t last_edit_time = 0; - millisecs_t t = g_core->GetAppTimeMillisecs(); - - // Ignore if too close together. - // (in case second request comes in before first takes effect). - if (t - last_edit_time < 1000) { - return; - } - last_edit_time = t; - assert(g_core->InMainThread()); - g_core->platform->EditText(name, value, max_chars); - }); -} - -void App::PushSetStressTestingCall(bool enable, int player_count) { - event_loop()->PushCall([this, enable, player_count] { - stress_test_->Set(enable, player_count); - }); -} - void App::PushResetAchievementsCall() { - event_loop()->PushCall([] { g_core->platform->ResetAchievements(); }); + g_core->main_event_loop()->PushCall( + [] { g_core->platform->ResetAchievements(); }); } void App::OnMainThreadStartApp() { @@ -416,11 +351,4 @@ void App::OnMainThreadStartApp() { } } -void App::PushCursorUpdate(bool vis) { - event_loop()->PushCall([vis] { - assert(g_core && g_core->InMainThread()); - g_core->platform->SetHardwareCursorVisible(vis); - }); -} - } // namespace ballistica::base diff --git a/src/ballistica/base/app/app.h b/src/ballistica/base/app/app.h index d18de011..9b0cff85 100644 --- a/src/ballistica/base/app/app.h +++ b/src/ballistica/base/app/app.h @@ -3,21 +3,18 @@ #ifndef BALLISTICA_BASE_APP_APP_H_ #define BALLISTICA_BASE_APP_APP_H_ -#include -#include #include -#include #include "ballistica/base/base.h" -#include "ballistica/base/support/stress_test.h" namespace ballistica::base { -/// Encapsulates high level app behavior for regular apps, vr apps, -/// headless apps, etc. +/// Defines app behavior for a particular paradigm (regular gui, vr, +/// headless) and/or top level api (SDL, UIKit, etc.). class App { public: - explicit App(EventLoop* event_loop); + App(); + virtual ~App(); /// Should be run after the instance is created and assigned. Any setup /// that may trigger virtual methods or lookups via global should go here. @@ -29,12 +26,7 @@ class App { /// in our main thread. void DoLogicThreadApplyAppConfig(); - /// Return whether this class runs its own event loop. If true, - /// MonolithicMain() will continuously ask the app for events until the - /// app is quit, at which point MonolithicMain() returns. If false, - /// MonolithicMain returns immediately and it is assumed that the OS - /// handles the app lifecycle and pushes events to the app via - /// callbacks/etc. + /// Return whether this class runs its own event loop. auto ManagesEventLoop() const -> bool; /// Called for non-event-loop apps to give them an opportunity to ensure @@ -85,13 +77,6 @@ class App { /// Called by the graphics-server when drawing completes for a frame. virtual void DidFinishRenderingFrame(FrameDef* frame); - /// Return the price of an IAP product as a human-readable string, or an - /// empty string if not found. FIXME: move this to platform. - auto GetProductPrice(const std::string& product) -> std::string; - void SetProductPrice(const std::string& product, const std::string& price); - - auto done() const -> bool { return done_; } - /// Whether we're running under ballisticakit_server.py /// (affects some app behavior). auto server_wrapper_managed() const -> bool { @@ -102,26 +87,13 @@ class App { // Deferred calls that can be made from other threads. - void PushCursorUpdate(bool vis); - void PushShowOnlineScoreUICall(const std::string& show, - const std::string& game, - const std::string& game_version); - void PushSubmitScoreCall(const std::string& game, - const std::string& game_version, int64_t score); - void PushAchievementReportCall(const std::string& achievement); - void PushOpenURLCall(const std::string& url); - void PushStringEditCall(const std::string& name, const std::string& value, - int max_chars); - void PushSetStressTestingCall(bool enable, int player_count); void PushPurchaseCall(const std::string& item); void PushRestorePurchasesCall(); void PushResetAchievementsCall(); void PushPurchaseAckCall(const std::string& purchase, const std::string& order_id); - auto event_loop() const -> EventLoop* { return event_loop_; } - /// Called by the logic thread when all shutdown-related tasks are done - /// and it is safe to exit the main event loop. + /// Called by the logic thread when all shutdown-related tasks are done. void LogicThreadShutdownComplete(); void LogicThreadOnAppRunning(); @@ -131,16 +103,11 @@ class App { void UpdatePauseResume_(); void OnAppPause_(); void OnAppResume_(); - EventLoop* event_loop_{}; - bool done_{}; bool server_wrapper_managed_{}; bool sys_paused_app_{}; bool actually_paused_{}; - std::unique_ptr stress_test_; millisecs_t last_resize_draw_event_time_{}; millisecs_t last_app_resume_time_{}; - std::unordered_map product_prices_; - std::mutex product_prices_mutex_; }; } // namespace ballistica::base diff --git a/src/ballistica/base/app/app_headless.cc b/src/ballistica/base/app/app_headless.cc index 6399f2d4..faf3f1ac 100644 --- a/src/ballistica/base/app/app_headless.cc +++ b/src/ballistica/base/app/app_headless.cc @@ -9,14 +9,14 @@ namespace ballistica::base { // We could technically use the vanilla App class here since we're not // changing anything. -AppHeadless::AppHeadless(EventLoop* event_loop) : App(event_loop) { +AppHeadless::AppHeadless() { // Handle a few misc things like stress-test updates. // (SDL builds set up a similar timer so we need to also). // This can probably go away at some point. - this->event_loop()->NewTimer(10, true, NewLambdaRunnable([this] { - assert(g_base->app); - g_base->app->RunEvents(); - })); + g_core->main_event_loop()->NewTimer(10, true, NewLambdaRunnable([this] { + assert(g_base->app); + g_base->app->RunEvents(); + })); } } // namespace ballistica::base diff --git a/src/ballistica/base/app/app_headless.h b/src/ballistica/base/app/app_headless.h index 050d8279..77898e90 100644 --- a/src/ballistica/base/app/app_headless.h +++ b/src/ballistica/base/app/app_headless.h @@ -11,7 +11,7 @@ namespace ballistica::base { class AppHeadless : public App { public: - explicit AppHeadless(EventLoop* event_loop); + AppHeadless(); }; } // namespace ballistica::base diff --git a/src/ballistica/base/app/app_sdl.cc b/src/ballistica/base/app/app_sdl.cc index edcc6b0a..c9a14e63 100644 --- a/src/ballistica/base/app/app_sdl.cc +++ b/src/ballistica/base/app/app_sdl.cc @@ -30,15 +30,15 @@ void AppSDL::HandleSDLEvent(const SDL_Event& event) { case SDL_JOYBALLMOTION: case SDL_JOYHATMOTION: { // It seems that joystick connection/disconnection callbacks can fire - // while there are still events for that joystick in the queue. - // So take care to ignore events for no-longer-existing joysticks. + // while there are still events for that joystick in the queue. So + // take care to ignore events for no-longer-existing joysticks. assert(event.jaxis.which == event.jbutton.which && event.jaxis.which == event.jhat.which); if (static_cast(event.jbutton.which) >= sdl_joysticks_.size() || sdl_joysticks_[event.jbutton.which] == nullptr) { return; } - JoystickInput* js = GetSDLJoyStickInput(&event); + JoystickInput* js = GetSDLJoystickInput_(&event); if (js) { if (g_base) { g_base->input->PushJoystickEvent(event, js); @@ -61,6 +61,7 @@ void AppSDL::HandleSDLEvent(const SDL_Event& event) { } break; } + case SDL_MOUSEBUTTONUP: { const SDL_MouseButtonEvent* e = &event.button; @@ -72,6 +73,7 @@ void AppSDL::HandleSDLEvent(const SDL_Event& event) { } break; } + case SDL_MOUSEMOTION: { const SDL_MouseMotionEvent* e = &event.motion; @@ -83,12 +85,14 @@ void AppSDL::HandleSDLEvent(const SDL_Event& event) { } break; } + case SDL_KEYDOWN: { if (g_base) { g_base->input->PushKeyPressEvent(event.key.keysym); } break; } + case SDL_KEYUP: { if (g_base) { g_base->input->PushKeyReleaseEvent(event.key.keysym); @@ -106,8 +110,7 @@ void AppSDL::HandleSDLEvent(const SDL_Event& event) { int scroll_speed; if (g_buildconfig.ostype_android()) { scroll_speed = 1; - } else if (g_buildconfig - .ostype_macos()) { // NOLINT(bugprone-branch-clone) + } else if (g_buildconfig.ostype_macos()) { scroll_speed = 500; } else { scroll_speed = 500; @@ -144,14 +147,16 @@ void AppSDL::HandleSDLEvent(const SDL_Event& event) { // Is there a reason we need to ignore these on ios? // do they even happen there? - // UPDATE: I think the even types are just not defined on our old iOS SDL. + // + // UPDATE: I think the even types are just not defined on our old iOS + // SDL. #if BA_SDL2_BUILD && !BA_OSTYPE_IOS_TVOS && BA_ENABLE_SDL_JOYSTICKS case SDL_JOYDEVICEREMOVED: // In this case we're passed the instance-id of the joystick. - SDLJoystickDisconnected(event.jdevice.which); + SDLJoystickDisconnected_(event.jdevice.which); break; case SDL_JOYDEVICEADDED: - SDLJoystickConnected(event.jdevice.which); + SDLJoystickConnected_(event.jdevice.which); break; #endif @@ -161,8 +166,9 @@ void AppSDL::HandleSDLEvent(const SDL_Event& event) { #if BA_OSTYPE_MACOS && BA_XCODE_BUILD && !BA_HEADLESS_BUILD case SDL_FULLSCREENSWITCH: - // Our custom hacked-up SDL informs *us* when our window enters or exits - // fullscreen. Let's commit this to our config so that we're in sync.. + // Our custom hacked-up SDL informs *us* when our window enters or + // exits fullscreen. Let's commit this to our config so that we're in + // sync.. g_base->python->objs().PushCall( event.user.code ? BasePython::ObjID::kSetConfigFullscreenOnCall : BasePython::ObjID::kSetConfigFullscreenOffCall); @@ -243,8 +249,8 @@ auto FilterSDLEvent(const SDL_Event* event) -> int { } return false; // We handled it; sdl doesn't need to keep it. } else { - // Otherwise just let SDL post it to the normal queue.. we process this - // every now and then to pick these up. + // Otherwise just let SDL post it to the normal queue.. we process + // this every now and then to pick these up. return true; // sdl should keep this. } } catch (const std::exception& e) { @@ -266,8 +272,8 @@ void AppSDL::InitSDL() { assert(g_core); if (g_buildconfig.ostype_macos()) { - // We don't want sdl to translate command/option clicks to different mouse - // buttons dernit. + // We don't want sdl to translate command/option clicks to different + // mouse buttons dernit. g_core->platform->SetEnv("SDL_HAS3BUTTONMOUSE", "1"); } @@ -287,8 +293,8 @@ void AppSDL::InitSDL() { // KILL THIS ONCE MAC SDL1.2 BUILD IS DEAD. // Register our hotplug callbacks in our funky custom mac build. #if BA_OSTYPE_MACOS && BA_XCODE_BUILD && !BA_HEADLESS_BUILD - SDL_JoystickSetHotPlugCallbacks(AppSDL::SDLJoystickConnected, - AppSDL::SDLJoystickDisconnected); + SDL_JoystickSetHotPlugCallbacks(AppSDL::SDLJoystickConnected_, + AppSDL::SDLJoystickDisconnected_); #endif } } @@ -297,7 +303,7 @@ void AppSDL::InitSDL() { // we don't want it. sdl_flags |= SDL_INIT_NOPARACHUTE; - // We want xinput on windows. + // We may or may not want xinput on windows. if (g_buildconfig.ostype_windows()) { if (!g_core->platform->GetLowLevelConfigValue("enablexinput", 1)) { SDL_SetHint(SDL_HINT_XINPUT_ENABLED, "0"); @@ -322,13 +328,14 @@ void AppSDL::InitSDL() { #endif } -AppSDL::AppSDL(EventLoop* event_loop) : App(event_loop) { +AppSDL::AppSDL() { InitSDL(); // If we're not running our own even loop, we set up a filter to intercept - // SDL events the moment they're generated and we process them immediately. - // This way we don't have to poll for events and can be purely callback-based, - // which fits in nicely with most modern event models. + // SDL events the moment they're generated and we process them + // immediately. This way we don't have to poll for events and can be + // purely callback-based, which fits in nicely with most modern event + // models. if (!ManagesEventLoop()) { #if BA_SDL2_BUILD SDL_SetEventFilter(FilterSDL2Event, nullptr); @@ -338,16 +345,36 @@ AppSDL::AppSDL(EventLoop* event_loop) : App(event_loop) { } else { // Otherwise we do the standard old SDL polling stuff. - // Set up a timer to chew through events every now and then. Polling isn't - // super elegant, but is necessary in SDL's case. (SDLWaitEvent() itself is - // pretty much a loop with SDL_PollEvents() followed by SDL_Delay(10) until - // something is returned; In spirit, we're pretty much doing that same - // thing, except that we're free to handle other matters concurrently - // instead of being locked in a delay call. - this->event_loop()->NewTimer(10, true, NewLambdaRunnable([this] { - assert(g_base->app); - g_base->app->RunEvents(); - })); + // Set up a timer to chew through events every now and then. Polling + // isn't super elegant, but is necessary in SDL's case. (SDLWaitEvent() + // itself is pretty much a loop with SDL_PollEvents() followed by + // SDL_Delay(10) until something is returned; In spirit, we're pretty + // much doing that same thing, except that we're free to handle other + // matters concurrently instead of being locked in a delay call. + g_core->main_event_loop()->NewTimer(10, true, NewLambdaRunnable([this] { + assert(g_base->app); + g_base->app->RunEvents(); + })); + } +} + +void AppSDL::OnMainThreadStartApp() { + App::OnMainThreadStartApp(); + + if (!g_core->HeadlessMode() && g_buildconfig.enable_sdl_joysticks()) { + // Add initial sdl joysticks. any added/removed after this will be + // handled via events. (it seems (on mac at least) even the initial ones + // are handled via events, so lets make sure we handle redundant + // joystick connections gracefully. + if (explicit_bool(true)) { + int joystick_count = SDL_NumJoysticks(); + for (int i = 0; i < joystick_count; i++) { + AppSDL::SDLJoystickConnected_(i); + } + + // We want events from joysticks. + SDL_JoystickEventState(SDL_ENABLE); + } } } @@ -356,17 +383,17 @@ void AppSDL::RunEvents() { // Now run all pending SDL events until we run out or we're told to quit. SDL_Event event; - while (SDL_PollEvent(&event) && (!done())) { + while (SDL_PollEvent(&event) && (!g_core->main_event_loop()->done())) { HandleSDLEvent(event); } } void AppSDL::DidFinishRenderingFrame(FrameDef* frame) { App::DidFinishRenderingFrame(frame); - SwapBuffers(); + SwapBuffers_(); } -void AppSDL::DoSwap() { +void AppSDL::DoSwap_() { assert(g_base->InGraphicsThread()); if (g_buildconfig.debug_build()) { @@ -390,11 +417,11 @@ void AppSDL::DoSwap() { if (last_swap_time_ != 0) { millisecs_t diff2 = cur_time - last_swap_time_; if (auto_vsync_) { - UpdateAutoVSync(static_cast(diff2)); + UpdateAutoVSync_(static_cast(diff2)); } - // If we drop to a super-crappy FPS lets take some countermeasures - // such as telling BG-dynamics to kill off some stuff. + // If we drop to a super-crappy FPS lets take some countermeasures such + // as telling BG-dynamics to kill off some stuff. if (diff2 >= 1000 / 20) { too_slow_frame_count_++; } else { @@ -405,23 +432,22 @@ void AppSDL::DoSwap() { if (too_slow_frame_count_ > 10) { too_slow_frame_count_ = 0; - // A common cause of slowness is excessive smoke and bg stuff; - // lets tell the bg dynamics thread to tone it down. + // A common cause of slowness is excessive smoke and bg stuff; lets + // tell the bg dynamics thread to tone it down. g_base->bg_dynamics->TooSlow(); } } last_swap_time_ = cur_time; } -void AppSDL::SwapBuffers() { +void AppSDL::SwapBuffers_() { swap_start_time_ = g_core->GetAppTimeMillisecs(); - assert(event_loop()->ThreadIsCurrent()); - DoSwap(); + assert(g_core->main_event_loop()->ThreadIsCurrent()); + DoSwap_(); - // FIXME: Move this somewhere reasonable. Not here. - // On mac/ios we wanna delay our game-center login until we've drawn a few - // frames, so lets do that here. - // ...hmm; why is that? I don't remember. Should revisit. + // FIXME: Move this somewhere reasonable. Not here. On mac/ios we wanna + // delay our game-center login until we've drawn a few frames, so lets do + // that here. ...hmm; why is that? I don't remember. Should revisit. if (g_buildconfig.use_game_center()) { static int f_count = 0; f_count++; @@ -431,18 +457,18 @@ void AppSDL::SwapBuffers() { } } -void AppSDL::UpdateAutoVSync(int diff) { +void AppSDL::UpdateAutoVSync_(int diff) { assert(auto_vsync_); // If we're currently vsyncing, watch for slow frames. if (vsync_enabled_) { bool should_disable{}; - // Note (March 2023): Currently mac opengl vsync seems broken on recent OSs. - // See discussions: https://github.com/libsdl-org/SDL/issues/4918 - // Since Mac compositor generally avoids tearing anyway, just gonna - // have 'auto' mode disable vsync for now. Explicit enable is still - // available for odd cases where it still may be beneficial. + // Note (March 2023): Currently mac opengl vsync seems broken on recent + // OSs. See discussions: https://github.com/libsdl-org/SDL/issues/4918 + // Since Mac compositor generally avoids tearing anyway, just gonna have + // 'auto' mode disable vsync for now. Explicit enable is still available + // for odd cases where it still may be beneficial. if (g_buildconfig.ostype_macos()) { should_disable = true; } else { @@ -454,12 +480,12 @@ void AppSDL::UpdateAutoVSync(int diff) { smoothing * average_vsync_fps_ + (1.0f - smoothing) * this_fps; } - // FIXME: should not be assuming a 60fps framerate these days. - // If framerate drops significantly below 60, flip vsync off to get a - // better framerate (but *only* if we're pretty sure we can hit 60 with - // it on; otherwise if we're on a 30hz monitor we'll get into a cycle of - // flipping it off and on repeatedly since we slow down a lot with it on - // and then speed up a lot with it off). + // FIXME: should not be assuming a 60fps framerate these days. If + // framerate drops significantly below 60, flip vsync off to get a + // better framerate (but *only* if we're pretty sure we can hit 60 + // with it on; otherwise if we're on a 30hz monitor we'll get into a + // cycle of flipping it off and on repeatedly since we slow down a lot + // with it on and then speed up a lot with it off). if (diff >= 1000 / 40 && average_vsync_fps_ > 55.0f) { vsync_bad_frame_count_++; } else { @@ -479,8 +505,8 @@ void AppSDL::UpdateAutoVSync(int diff) { if (g_buildconfig.ostype_macos()) { should_enable = false; } else { - // Vsync is currently off.. watch for framerate staying consistently high - // and then turn it on again. + // Vsync is currently off; watch for framerate staying consistently + // high and then turn it on again. if (diff <= 1000 / 50) { vsync_good_frame_count_++; } else { @@ -510,34 +536,14 @@ void AppSDL::SetAutoVSync(bool enable) { } } -void AppSDL::OnMainThreadStartApp() { - App::OnMainThreadStartApp(); - - if (!g_core->HeadlessMode() && g_buildconfig.enable_sdl_joysticks()) { - // Add initial sdl joysticks. any added/removed after this will be handled - // via events. (it seems (on mac at least) even the initial ones are handled - // via events, so lets make sure we handle redundant joystick connections - // gracefully. - if (explicit_bool(true)) { - int joystick_count = SDL_NumJoysticks(); - for (int i = 0; i < joystick_count; i++) { - AppSDL::SDLJoystickConnected(i); - } - - // We want events from joysticks. - SDL_JoystickEventState(SDL_ENABLE); - } - } -} - -void AppSDL::SDLJoystickConnected(int device_index) { +void AppSDL::SDLJoystickConnected_(int device_index) { assert(g_core && g_core->InMainThread()); // We add all existing inputs when bootstrapping is complete; we should // never be getting these before that happens. if (!g_base) { Log(LogLevel::kError, - "Unexpected SDLJoystickConnected early in boot sequence."); + "Unexpected SDLJoystickConnected_ early in boot sequence."); return; } @@ -549,24 +555,24 @@ void AppSDL::SDLJoystickConnected(int device_index) { auto* j = Object::NewDeferred(device_index); if (g_buildconfig.sdl2_build() && g_buildconfig.enable_sdl_joysticks()) { int instance_id = SDL_JoystickInstanceID(j->sdl_joystick()); - get()->AddSDLInputDevice(j, instance_id); + Get()->AddSDLInputDevice_(j, instance_id); } else { - get()->AddSDLInputDevice(j, device_index); + Get()->AddSDLInputDevice_(j, device_index); } } } -void AppSDL::SDLJoystickDisconnected(int index) { +void AppSDL::SDLJoystickDisconnected_(int index) { assert(g_core->InMainThread()); assert(index >= 0); - get()->RemoveSDLInputDevice(index); + Get()->RemoveSDLInputDevice_(index); } void AppSDL::SetInitialScreenDimensions(const Vector2f& dimensions) { screen_dimensions_ = dimensions; } -void AppSDL::AddSDLInputDevice(JoystickInput* input, int index) { +void AppSDL::AddSDLInputDevice_(JoystickInput* input, int index) { assert(g_base && g_base->input != nullptr); assert(input != nullptr); assert(g_core->InMainThread()); @@ -581,10 +587,10 @@ void AppSDL::AddSDLInputDevice(JoystickInput* input, int index) { g_base->input->PushAddInputDeviceCall(input, true); } -void AppSDL::RemoveSDLInputDevice(int index) { +void AppSDL::RemoveSDLInputDevice_(int index) { assert(g_core->InMainThread()); assert(index >= 0); - JoystickInput* j = GetSDLJoyStickInput(index); + JoystickInput* j = GetSDLJoystickInput_(index); assert(j); if (static_cast_check_fit(sdl_joysticks_.size()) > index) { sdl_joysticks_[index] = nullptr; @@ -596,7 +602,7 @@ void AppSDL::RemoveSDLInputDevice(int index) { g_base->input->PushRemoveInputDeviceCall(j, true); } -auto AppSDL::GetSDLJoyStickInput(const SDL_Event* e) const -> JoystickInput* { +auto AppSDL::GetSDLJoystickInput_(const SDL_Event* e) const -> JoystickInput* { assert(g_core->InMainThread()); int joy_id; @@ -618,10 +624,10 @@ auto AppSDL::GetSDLJoyStickInput(const SDL_Event* e) const -> JoystickInput* { default: return nullptr; } - return GetSDLJoyStickInput(joy_id); + return GetSDLJoystickInput_(joy_id); } -auto AppSDL::GetSDLJoyStickInput(int sdl_joystick_id) const -> JoystickInput* { +auto AppSDL::GetSDLJoystickInput_(int sdl_joystick_id) const -> JoystickInput* { assert(g_core->InMainThread()); for (auto sdl_joystick : sdl_joysticks_) { if ((sdl_joystick != nullptr) && (*sdl_joystick).sdl_joystick_id() >= 0 diff --git a/src/ballistica/base/app/app_sdl.h b/src/ballistica/base/app/app_sdl.h index 14d6d518..b2c6249c 100644 --- a/src/ballistica/base/app/app_sdl.h +++ b/src/ballistica/base/app/app_sdl.h @@ -15,17 +15,15 @@ namespace ballistica::base { class AppSDL : public App { public: static void InitSDL(); - explicit AppSDL(EventLoop* event_loop); + AppSDL(); void HandleSDLEvent(const SDL_Event& event); void RunEvents() override; void DidFinishRenderingFrame(FrameDef* frame) override; void SetAutoVSync(bool enable); - static void SDLJoystickConnected(int index); - static void SDLJoystickDisconnected(int index); void OnMainThreadStartApp() override; - /// Return g_base->app as a AppSDL. (assumes it actually is one). - static AppSDL* get() { + /// Return g_base->app as an AppSDL. (assumes it actually is one). + static AppSDL* Get() { assert(g_base && g_base->app != nullptr); assert(dynamic_cast(g_base->app) == static_cast(g_base->app)); @@ -34,17 +32,17 @@ class AppSDL : public App { void SetInitialScreenDimensions(const Vector2f& dimensions); private: - // Given an sdl joystick ID, returns our ballistica input for it. - auto GetSDLJoyStickInput(int sdl_joystick_id) const -> JoystickInput*; - + // Given an sdl joystick ID, returns our Ballistica input for it. + auto GetSDLJoystickInput_(int sdl_joystick_id) const -> JoystickInput*; // The same but using sdl events. - auto GetSDLJoyStickInput(const SDL_Event* e) const -> JoystickInput*; - - void DoSwap(); - void SwapBuffers(); - void UpdateAutoVSync(int diff); - void AddSDLInputDevice(JoystickInput* input, int index); - void RemoveSDLInputDevice(int index); + auto GetSDLJoystickInput_(const SDL_Event* e) const -> JoystickInput*; + static void SDLJoystickConnected_(int index); + static void SDLJoystickDisconnected_(int index); + void DoSwap_(); + void SwapBuffers_(); + void UpdateAutoVSync_(int diff); + void AddSDLInputDevice_(JoystickInput* input, int index); + void RemoveSDLInputDevice_(int index); millisecs_t last_swap_time_{}; millisecs_t swap_start_time_{}; int too_slow_frame_count_{}; @@ -54,8 +52,7 @@ class AppSDL : public App { int vsync_good_frame_count_{}; int vsync_bad_frame_count_{}; std::vector sdl_joysticks_; - - /// This is in points; not pixels. + /// This is in points, not pixels. Vector2f screen_dimensions_{1.0f, 1.0f}; }; diff --git a/src/ballistica/base/app/app_vr.cc b/src/ballistica/base/app/app_vr.cc index f9fd6a88..e8556c79 100644 --- a/src/ballistica/base/app/app_vr.cc +++ b/src/ballistica/base/app/app_vr.cc @@ -11,10 +11,10 @@ namespace ballistica::base { -AppVR::AppVR(EventLoop* event_loop) : App(event_loop) {} +AppVR::AppVR() {} void AppVR::PushVRSimpleRemoteStateCall(const VRSimpleRemoteState& state) { - event_loop()->PushCall([this, state] { + g_core->main_event_loop()->PushCall([this, state] { // Convert this to a full hands state, adding in some simple elbow // positioning of our own and left/right. VRHandsState s; diff --git a/src/ballistica/base/app/app_vr.h b/src/ballistica/base/app/app_vr.h index 834a4b89..c1551abe 100644 --- a/src/ballistica/base/app/app_vr.h +++ b/src/ballistica/base/app/app_vr.h @@ -27,7 +27,7 @@ class AppVR : public App { return static_cast(g_base->app); } - explicit AppVR(EventLoop* event_loop); + AppVR(); void PushVRSimpleRemoteStateCall(const VRSimpleRemoteState& state); void VRSetDrawDimensions(int w, int h); void VRPreDraw(); diff --git a/src/ballistica/base/base.cc b/src/ballistica/base/base.cc index a1816840..5c6a4c68 100644 --- a/src/ballistica/base/base.cc +++ b/src/ballistica/base/base.cc @@ -25,6 +25,7 @@ #include "ballistica/base/support/huffman.h" #include "ballistica/base/support/plus_soft.h" #include "ballistica/base/support/stdio_console.h" +#include "ballistica/base/support/stress_test.h" #include "ballistica/base/ui/console.h" #include "ballistica/base/ui/ui.h" #include "ballistica/core/platform/core_platform.h" @@ -47,6 +48,7 @@ BaseFeatureSet::BaseFeatureSet() utils{new Utils()}, logic{new Logic()}, huffman{new Huffman()}, + stress_test_{new StressTest()}, ui{new UI()}, networking{new Networking()}, app{BasePlatform::CreateApp()}, @@ -174,7 +176,7 @@ void BaseFeatureSet::StartApp() { g_core->LifecycleLog("start-app begin (main thread)"); - LogVersionInfo(); + LogVersionInfo_(); // The logic thread (or maybe other things) need to run Python as // we're bringing them up, so let it go for the duration of this call. @@ -222,7 +224,7 @@ void BaseFeatureSet::StartApp() { g_core->LifecycleLog("start-app end (main thread)"); } -void BaseFeatureSet::LogVersionInfo() { +void BaseFeatureSet::LogVersionInfo_() { char buffer[256]; if (g_buildconfig.headless_build()) { snprintf(buffer, sizeof(buffer), "BallisticaKit Headless %s build %d.", @@ -635,24 +637,24 @@ std::string BaseFeatureSet::DoGetContextBaseString() { } void BaseFeatureSet::DoPrintContextAuto() { if (!InLogicThread()) { - PrintContextNonLogicThread(); + PrintContextNonLogicThread_(); } else if (const char* label = Python::ScopedCallLabel::current_label()) { - PrintContextForCallableLabel(label); + PrintContextForCallableLabel_(label); } else if (PythonCommand* cmd = PythonCommand::current_command()) { cmd->PrintContext(); } else if (PythonContextCall* call = PythonContextCall::current_call()) { call->PrintContext(); } else { - PrintContextUnavailable(); + PrintContextUnavailable_(); } } -void BaseFeatureSet::PrintContextNonLogicThread() { +void BaseFeatureSet::PrintContextNonLogicThread_() { std::string s = std::string( " root call: "); PySys_WriteStderr("%s\n", s.c_str()); } -void BaseFeatureSet::PrintContextForCallableLabel(const char* label) { +void BaseFeatureSet::PrintContextForCallableLabel_(const char* label) { assert(InLogicThread()); assert(label); std::string s = std::string(" root call: ") + label + "\n"; @@ -660,7 +662,7 @@ void BaseFeatureSet::PrintContextForCallableLabel(const char* label) { PySys_WriteStderr("%s\n", s.c_str()); } -void BaseFeatureSet::PrintContextUnavailable() { +void BaseFeatureSet::PrintContextUnavailable_() { // (no logic-thread-check here; can be called early or from other threads) std::string s = std::string(" root call: \n"); s += Python::GetContextBaseString(); diff --git a/src/ballistica/base/base.h b/src/ballistica/base/base.h index e467156f..efebb56c 100644 --- a/src/ballistica/base/base.h +++ b/src/ballistica/base/base.h @@ -719,6 +719,7 @@ class BaseFeatureSet : public FeatureSetNativeComponent, auto* console() const { return console_; } auto* app_mode() const { return app_mode_; } + auto* stress_test() const { return stress_test_; } void set_app_mode(AppMode* mode); // Non-const bits (fixme: clean up access to these). @@ -726,16 +727,17 @@ class BaseFeatureSet : public FeatureSetNativeComponent, private: BaseFeatureSet(); - void LogVersionInfo(); - void PrintContextNonLogicThread(); - void PrintContextForCallableLabel(const char* label); - void PrintContextUnavailable(); + void LogVersionInfo_(); + void PrintContextNonLogicThread_(); + void PrintContextForCallableLabel_(const char* label); + void PrintContextUnavailable_(); AppMode* app_mode_; Console* console_{}; PlusSoftInterface* plus_soft_{}; ClassicSoftInterface* classic_soft_{}; UIV1SoftInterface* ui_v1_soft_{}; + StressTest* stress_test_; std::string console_startup_messages_; bool tried_importing_plus_{}; diff --git a/src/ballistica/base/graphics/gl/gl_sys.cc b/src/ballistica/base/graphics/gl/gl_sys.cc index e1bc31a8..9d311dbe 100644 --- a/src/ballistica/base/graphics/gl/gl_sys.cc +++ b/src/ballistica/base/graphics/gl/gl_sys.cc @@ -149,7 +149,7 @@ GLContext::GLContext(int target_res_x, int target_res_y, bool fullscreen) // devices. int win_size_x, win_size_y; SDL_GetWindowSize(sdl_window_, &win_size_x, &win_size_y); - AppSDL::get()->SetInitialScreenDimensions(Vector2f( + AppSDL::Get()->SetInitialScreenDimensions(Vector2f( static_cast(win_size_x), static_cast(win_size_y))); #if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID res_x_ = win_size_x; @@ -188,7 +188,7 @@ GLContext::GLContext(int target_res_x, int target_res_y, bool fullscreen) } res_x_ = surface_->w; res_y_ = surface_->h; - AppSDL::get()->SetInitialScreenDimensions(Vector2f(res_x_, res_y_)); + AppSDL::Get()->SetInitialScreenDimensions(Vector2f(res_x_, res_y_)); SDL_WM_SetCaption("BallisticaKit", "BallisticaKit"); #elif BA_OSTYPE_ANDROID // On Android the Java layer creates a GL setup before even calling us. diff --git a/src/ballistica/base/graphics/graphics.cc b/src/ballistica/base/graphics/graphics.cc index 6594897d..b71c8024 100644 --- a/src/ballistica/base/graphics/graphics.cc +++ b/src/ballistica/base/graphics/graphics.cc @@ -1476,7 +1476,10 @@ void Graphics::DrawCursor(RenderPass* pass, millisecs_t real_time) { || real_time - last_cursor_visibility_event_time_ > 2000) { hardware_cursor_visible_ = new_cursor_visibility; last_cursor_visibility_event_time_ = real_time; - g_base->app->PushCursorUpdate(hardware_cursor_visible_); + g_core->main_event_loop()->PushCall([this] { + assert(g_core && g_core->InMainThread()); + g_core->platform->SetHardwareCursorVisible(hardware_cursor_visible_); + }); } } else { // Draw software cursor. diff --git a/src/ballistica/base/input/device/joystick_input.cc b/src/ballistica/base/input/device/joystick_input.cc index 345b076a..08e46c8b 100644 --- a/src/ballistica/base/input/device/joystick_input.cc +++ b/src/ballistica/base/input/device/joystick_input.cc @@ -307,7 +307,7 @@ JoystickInput::~JoystickInput() { #if BA_ENABLE_SDL_JOYSTICKS assert(g_base->app); auto joystick = sdl_joystick_; - g_base->app->event_loop()->PushCall( + g_core->main_event_loop()->PushCall( [joystick] { SDL_JoystickClose(joystick); }); sdl_joystick_ = nullptr; #else diff --git a/src/ballistica/base/logic/logic.cc b/src/ballistica/base/logic/logic.cc index 10c358f2..e1f065a4 100644 --- a/src/ballistica/base/logic/logic.cc +++ b/src/ballistica/base/logic/logic.cc @@ -137,7 +137,7 @@ void Logic::OnAppShutdown() { // FIXME: Should add a mechanism where we give the above subsystems // a short bit of time to complete shutdown if they need it. // For now just completing instantly. - g_base->app->event_loop()->PushCall( + g_core->main_event_loop()->PushCall( [] { g_base->app->LogicThreadShutdownComplete(); }); } diff --git a/src/ballistica/base/networking/networking.cc b/src/ballistica/base/networking/networking.cc index 7bdd1e76..58e24fad 100644 --- a/src/ballistica/base/networking/networking.cc +++ b/src/ballistica/base/networking/networking.cc @@ -20,7 +20,7 @@ void Networking::DoApplyAppConfig() { // Grab network settings from config and kick them over to the main // thread to be applied. int port = g_base->app_config->Resolve(AppConfig::IntID::kPort); - g_base->app->event_loop()->PushCall([port] { + g_core->main_event_loop()->PushCall([port] { assert(g_core->InMainThread()); g_base->network_reader->SetPort(port); }); diff --git a/src/ballistica/base/platform/base_platform.cc b/src/ballistica/base/platform/base_platform.cc index 3750a9cc..dfcb8499 100644 --- a/src/ballistica/base/platform/base_platform.cc +++ b/src/ballistica/base/platform/base_platform.cc @@ -119,20 +119,20 @@ auto BasePlatform::CreateApp() -> App* { App* app{}; #if BA_HEADLESS_BUILD - app = new AppHeadless(g_core->main_event_loop()); + app = new AppHeadless(); #elif BA_RIFT_BUILD // Rift build can spin up in either VR or regular mode. if (g_core->vr_mode) { - app = new AppVR(g_core->main_event_loop()); + app = new AppVR(); } else { - app = new AppSDL(g_core->main_event_loop()); + app = new AppSDL(); } #elif BA_CARDBOARD_BUILD - app = new AppVR(g_core->main_event_loop()); + app = new AppVR(); #elif BA_SDL_BUILD - app = new AppSDL(g_core->main_event_loop()); + app = new AppSDL(); #else - app = new App(g_core->main_event_loop()); + app = new App(); #endif assert(app); diff --git a/src/ballistica/base/python/methods/python_methods_app.cc b/src/ballistica/base/python/methods/python_methods_app.cc index 34e4a23f..d05342e5 100644 --- a/src/ballistica/base/python/methods/python_methods_app.cc +++ b/src/ballistica/base/python/methods/python_methods_app.cc @@ -9,6 +9,7 @@ #include "ballistica/base/logic/logic.h" #include "ballistica/base/python/base_python.h" #include "ballistica/base/python/support/python_context_call_runnable.h" +#include "ballistica/base/support/stress_test.h" #include "ballistica/base/ui/ui.h" #include "ballistica/core/platform/core_platform.h" #include "ballistica/shared/foundation/event_loop.h" @@ -796,13 +797,14 @@ static PyMethodDef PyEnvDef = { static auto PySetStressTesting(PyObject* self, PyObject* args) -> PyObject* { BA_PYTHON_TRY; - int testing; + int enable; int player_count; - if (!PyArg_ParseTuple(args, "pi", &testing, &player_count)) { + if (!PyArg_ParseTuple(args, "pi", &enable, &player_count)) { return nullptr; } - g_base->app->PushSetStressTestingCall(static_cast(testing), - player_count); + g_core->main_event_loop()->PushCall([enable, player_count] { + g_base->stress_test()->Set(enable, player_count); + }); Py_RETURN_NONE; BA_PYTHON_CATCH; } diff --git a/src/ballistica/base/support/plus_soft.h b/src/ballistica/base/support/plus_soft.h index 16d01544..34daa37d 100644 --- a/src/ballistica/base/support/plus_soft.h +++ b/src/ballistica/base/support/plus_soft.h @@ -42,6 +42,9 @@ class PlusSoftInterface { const std::vector& friends) = 0; virtual void DispatchRemoteAchievementList( const std::set& achs) = 0; + virtual void SetProductPrice(const std::string& product, + const std::string& price) = 0; + virtual void PushAnalyticsCall(const std::string& type, int increment) = 0; virtual void PushPurchaseTransactionCall(const std::string& item, const std::string& receipt, diff --git a/src/ballistica/core/support/core_config.cc b/src/ballistica/core/support/core_config.cc index f18b08e4..e73935f5 100644 --- a/src/ballistica/core/support/core_config.cc +++ b/src/ballistica/core/support/core_config.cc @@ -178,7 +178,7 @@ auto CoreConfig::ForEnvVars() -> CoreConfig { return cfg; } -auto CoreConfig::ForArgsAndEnvVars(int argc, char** argv) -> CoreConfig { +auto CoreConfig::ForArgsAndEnvVars(size_t argc, char** argv) -> CoreConfig { CoreConfig cfg{}; // Apply env-vars first. We want explicit args to override these. diff --git a/src/ballistica/core/support/core_config.h b/src/ballistica/core/support/core_config.h index ddcd5450..3c6f00bb 100644 --- a/src/ballistica/core/support/core_config.h +++ b/src/ballistica/core/support/core_config.h @@ -14,7 +14,7 @@ namespace ballistica::core { /// when initing the core feature-set. class CoreConfig { public: - static auto ForArgsAndEnvVars(int argc, char** argv) -> CoreConfig; + static auto ForArgsAndEnvVars(size_t argc, char** argv) -> CoreConfig; static auto ForEnvVars() -> CoreConfig; diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index a6983b4e..09e3f1a2 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 = 21221; +const int kEngineBuildNumber = 21232; const char* kEngineVersion = "1.7.26"; #if BA_MONOLITHIC_BUILD diff --git a/src/ballistica/shared/foundation/event_loop.h b/src/ballistica/shared/foundation/event_loop.h index a45f5c37..68fb95be 100644 --- a/src/ballistica/shared/foundation/event_loop.h +++ b/src/ballistica/shared/foundation/event_loop.h @@ -100,6 +100,10 @@ class EventLoop { static auto GetStillPausingThreads() -> std::vector; auto paused() { return paused_; } + auto done() -> bool { + assert(source_ == ThreadSource::kWrapMain); + return done_; + } private: struct ThreadMessage_ { @@ -117,7 +121,7 @@ class EventLoop { auto CheckPushRunnableSafety_() -> bool; void SetInternalThreadName_(const std::string& name); void WaitForNextEvent_(bool single_cycle); - void LoopUpkeep_(bool once); + void LoopUpkeep_(bool single_cycle); void LogThreadMessageTally_( std::vector>* log_entries); void PushLocalRunnable_(Runnable* runnable, bool* completion_flag); 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 29b65a6d..53c1b2b6 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 @@ -6,10 +6,12 @@ #include "ballistica/base/app_mode/app_mode.h" #include "ballistica/base/assets/sound_asset.h" #include "ballistica/base/input/input.h" +#include "ballistica/base/platform/base_platform.h" #include "ballistica/base/python/base_python.h" #include "ballistica/base/support/plus_soft.h" #include "ballistica/base/ui/console.h" #include "ballistica/base/ui/ui.h" +#include "ballistica/shared/foundation/event_loop.h" #include "ballistica/ui_v1/python/class/python_class_ui_mesh.h" #include "ballistica/ui_v1/python/class/python_class_ui_sound.h" #include "ballistica/ui_v1/python/class/python_class_ui_texture.h" @@ -2366,7 +2368,10 @@ static auto PyShowOnlineScoreUI(PyObject* self, PyObject* args, if (game_version_obj != Py_None) { game_version = Python::GetPyString(game_version_obj); } - g_base->app->PushShowOnlineScoreUICall(show, game, game_version); + g_core->main_event_loop()->PushCall([show, game, game_version] { + assert(g_core->InMainThread()); + g_core->platform->ShowOnlineScoreUI(show, game, game_version); + }); Py_RETURN_NONE; BA_PYTHON_CATCH; } @@ -2726,7 +2731,8 @@ static auto PyOpenURL(PyObject* self, PyObject* args, PyObject* keywds) if (force_internal) { g_base->ui->ShowURL(address); } else { - g_base->app->PushOpenURLCall(address); + g_core->main_event_loop()->PushCall( + [address] { g_base->platform->OpenURL(address); }); } Py_RETURN_NONE; BA_PYTHON_CATCH; diff --git a/src/ballistica/ui_v1/widget/text_widget.cc b/src/ballistica/ui_v1/widget/text_widget.cc index 34aefa07..2421dbfe 100644 --- a/src/ballistica/ui_v1/widget/text_widget.cc +++ b/src/ballistica/ui_v1/widget/text_widget.cc @@ -13,6 +13,7 @@ #include "ballistica/base/python/support/python_context_call.h" #include "ballistica/base/ui/ui.h" #include "ballistica/core/core.h" +#include "ballistica/shared/foundation/event_loop.h" #include "ballistica/shared/generic/utils.h" #include "ballistica/shared/python/python.h" #include "ballistica/ui_v1/python/ui_v1_python.h" @@ -559,7 +560,20 @@ void TextWidget::BringUpEditDialog() { use_internal_dialog = false; // store ourself as the current text-widget and kick off an edit android_string_edit_widget_ = this; - g_base->app->PushStringEditCall(description_, text_raw_, max_chars_); + g_core->main_event_loop()->PushCall( + [name = description_, value = text_raw_, max_chars = max_chars_] { + static millisecs_t last_edit_time = 0; + millisecs_t t = g_core->GetAppTimeMillisecs(); + + // Ignore if too close together. + // (in case second request comes in before first takes effect). + if (t - last_edit_time < 1000) { + return; + } + last_edit_time = t; + assert(g_core->InMainThread()); + g_core->platform->EditText(name, value, max_chars); + }); } } }