tidying app classes

This commit is contained in:
Eric 2023-08-22 09:38:15 -07:00
parent 16ef618a93
commit bf94886aed
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
27 changed files with 257 additions and 323 deletions

88
.efrocachemap generated
View File

@ -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",

View File

@ -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

View File

@ -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'

View File

@ -19,8 +19,7 @@
namespace ballistica::base {
App::App(EventLoop* event_loop)
: event_loop_(event_loop), stress_test_(std::make_unique<StressTest>()) {
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

View File

@ -3,21 +3,18 @@
#ifndef BALLISTICA_BASE_APP_APP_H_
#define BALLISTICA_BASE_APP_APP_H_
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#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<StressTest> stress_test_;
millisecs_t last_resize_draw_event_time_{};
millisecs_t last_app_resume_time_{};
std::unordered_map<std::string, std::string> product_prices_;
std::mutex product_prices_mutex_;
};
} // namespace ballistica::base

View File

@ -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

View File

@ -11,7 +11,7 @@ namespace ballistica::base {
class AppHeadless : public App {
public:
explicit AppHeadless(EventLoop* event_loop);
AppHeadless();
};
} // namespace ballistica::base

View File

@ -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<size_t>(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<int>(diff2));
UpdateAutoVSync_(static_cast<int>(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<JoystickInput>(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<int>(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

View File

@ -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<AppSDL*>(g_base->app)
== static_cast<AppSDL*>(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<JoystickInput*> sdl_joysticks_;
/// This is in points; not pixels.
/// This is in points, not pixels.
Vector2f screen_dimensions_{1.0f, 1.0f};
};

View File

@ -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;

View File

@ -27,7 +27,7 @@ class AppVR : public App {
return static_cast<AppVR*>(g_base->app);
}
explicit AppVR(EventLoop* event_loop);
AppVR();
void PushVRSimpleRemoteStateCall(const VRSimpleRemoteState& state);
void VRSetDrawDimensions(int w, int h);
void VRPreDraw();

View File

@ -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: <not in logic thread; context_ref unavailable>");
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: <unavailable>\n");
s += Python::GetContextBaseString();

View File

@ -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_{};

View File

@ -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<float>(win_size_x), static_cast<float>(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.

View File

@ -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.

View File

@ -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

View File

@ -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(); });
}

View File

@ -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);
});

View File

@ -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);

View File

@ -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<bool>(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;
}

View File

@ -42,6 +42,9 @@ class PlusSoftInterface {
const std::vector<std::string>& friends) = 0;
virtual void DispatchRemoteAchievementList(
const std::set<std::string>& 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,

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -100,6 +100,10 @@ class EventLoop {
static auto GetStillPausingThreads() -> std::vector<EventLoop*>;
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<std::pair<LogLevel, std::string>>* log_entries);
void PushLocalRunnable_(Runnable* runnable, bool* completion_flag);

View File

@ -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;

View File

@ -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);
});
}
}
}