mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-22 14:59:25 +08:00
tidying app classes
This commit is contained in:
parent
16ef618a93
commit
bf94886aed
88
.efrocachemap
generated
88
.efrocachemap
generated
@ -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",
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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'
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -11,7 +11,7 @@ namespace ballistica::base {
|
||||
|
||||
class AppHeadless : public App {
|
||||
public:
|
||||
explicit AppHeadless(EventLoop* event_loop);
|
||||
AppHeadless();
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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};
|
||||
};
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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_{};
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(); });
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
});
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user