simplifying c++ bootstrapping

This commit is contained in:
Eric 2022-09-11 10:32:02 -07:00
parent b837d3707e
commit 014a996933
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
39 changed files with 319 additions and 346 deletions

View File

@ -3995,50 +3995,50 @@
"assets/src/ba_data/python/ba/_generated/__init__.py": "https://files.ballistica.net/cache/ba1/ee/e8/cad05aa531c7faf7ff7b96db7f6e", "assets/src/ba_data/python/ba/_generated/__init__.py": "https://files.ballistica.net/cache/ba1/ee/e8/cad05aa531c7faf7ff7b96db7f6e",
"assets/src/ba_data/python/ba/_generated/enums.py": "https://files.ballistica.net/cache/ba1/b2/e5/0ee0561e16257a32830645239f34", "assets/src/ba_data/python/ba/_generated/enums.py": "https://files.ballistica.net/cache/ba1/b2/e5/0ee0561e16257a32830645239f34",
"ballisticacore-windows/Generic/BallisticaCore.ico": "https://files.ballistica.net/cache/ba1/89/c0/e32c7d2a35dc9aef57cc73b0911a", "ballisticacore-windows/Generic/BallisticaCore.ico": "https://files.ballistica.net/cache/ba1/89/c0/e32c7d2a35dc9aef57cc73b0911a",
"build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c7/7c/11757954adb7da34c0e8cb6a6470", "build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e4/55/ec1e32f714af2ad914ea2c5e35b0",
"build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/30/4e/361603ee5faf75168ddefd070b44", "build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c2/29/5c9ef7b0c3b068c700835f62abe6",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b6/2e/e3bd12f2c9e7baa173479686485d", "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/60/30/248f57b0e0950c74aef828fe3667",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1e/fe/0f73516a00159f6cd4b4791f010d", "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/62/3c/1b789be64fa12c6dd4609271c0b8",
"build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/60/a4/f6798a377123b4f0ea58067173b9", "build/prefab/full/linux_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ca/bf/66e24379dff682f1fb33d96b8c72",
"build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/60/0d/772009d20e18def687f6b76021f8", "build/prefab/full/linux_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ce/e9/e578aecdd0146a4a242dacbef95d",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ec/98/ca24d22fa6870cf2fa4b1dc81e2a", "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/11/b8/76cf26f61214c4b75e8515f0766a",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ab/71/616a553794306a406be45697895c", "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d8/c0/74a187c3ebddec6313ea6385343d",
"build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/41/14/bae7db8e7361d538096253c36792", "build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/90/74/0e809006cb921253e92b78d87ec8",
"build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/91/5f/d2bfb2b30befdae9270a119d51b5", "build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7c/de/d2ceb7f9d52f78a33792395c4f2e",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d8/07/bd414612e9bf05f2a3c0b531a552", "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/51/71/1a249c35f5a9459322c546b1ec5a",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/49/64/5943868e08758fc103e8ce70f334", "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d5/0a/56f81ecbdc45218159edf9c08aeb",
"build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1a/a9/bae1d4c1840d6e4c1931c529e4f8", "build/prefab/full/mac_x86_64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/25/5d/4569f3ae73cfa0a33427885ef5b4",
"build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/22/a9/75669c9a475fc8080ce422ce2baa", "build/prefab/full/mac_x86_64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/74/2e/c987767fca3cc4b5bb738e259b0a",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e1/87/95cbc6fc53e43e206f43eb3a1c61", "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6b/8a/79e987afa129e07d36486cad1602",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a4/1b/9a6145a32ef40fd3b8357cfbfb30", "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b1/c0/46efd467c46e3ad8ed64d3893e1e",
"build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/6a/a5/5afd24a1043a652af8ae76ec33ea", "build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f8/51/80d6f06fb1579a95f79796e14235",
"build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/dd/3a/71c400bbac9edc5fa7b63e099ae7", "build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/32/6d/9190219d7454f5cc2d75bcaa7084",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/dc/18/7e47d66f054e81314b39c14b26dc", "build/prefab/full/windows_x86_server/debug/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/fc/39/4f03d2ebf27e521d4d8b3cc6313d",
"build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/43/25/36e8e8fc1eac369727f9639bbcf9", "build/prefab/full/windows_x86_server/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/9d/22/8e1aa2c9ac9c589985b7ff6d744f",
"build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e7/25/6fb628f1f5260834692bdeab63b0", "build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d9/e3/5491d9859e329f629adb139e1c02",
"build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/86/d2/d18cbc017a7d64001f96718cc5ed", "build/prefab/lib/linux_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/86/d2/d18cbc017a7d64001f96718cc5ed",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8e/e5/cfbcc97e2b8c7ee46d0422e54380", "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d3/5f/a6501aae21bc6dbda5503cd3ed74",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/06/70/9e5becbdf873ea42fae9541dd123", "build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/06/70/9e5becbdf873ea42fae9541dd123",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0d/18/6a515fce87613b2293a8f7bf1a35", "build/prefab/lib/linux_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/94/19/7c70a5388ab5dc9f8b4cd2a643bd",
"build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a3/47/f46d4455e6ee1ebb397508495d90", "build/prefab/lib/linux_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a3/47/f46d4455e6ee1ebb397508495d90",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/14/49/890119e5ff8800edf3b3cda113df", "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/53/63/891be47740b031ad1e08f6fe9c77",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4c/32/de6296fdbd72d6a82d47a2403efd", "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4c/32/de6296fdbd72d6a82d47a2403efd",
"build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/89/94/c90bb234585a62a097c6f6642e7d", "build/prefab/lib/mac_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e6/be/16d22d7d53a87ad6c9e1b7835950",
"build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/39/2c/773ff4c64734bcd6205080a0563d", "build/prefab/lib/mac_arm64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/39/2c/773ff4c64734bcd6205080a0563d",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0c/18/4a032d351000cf732bb7494d85f7", "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/24/a6/eb221317cdae775c195aa81a2f0c",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4b/9d/be9915b6f1f1a0d83ae11885bd42", "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4b/9d/be9915b6f1f1a0d83ae11885bd42",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/31/d2/e658b66d64c828f85d84a9b0d482", "build/prefab/lib/mac_x86_64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4b/84/6074d1f32482e5a1914aac08747f",
"build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/31/26/5c531133795d1381ced85e519b10", "build/prefab/lib/mac_x86_64_gui/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/31/26/5c531133795d1381ced85e519b10",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/24/4f/c0a11a834ae10e9706bf92879d23", "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0d/75/0044708d9f8af5ba85bbe9709f92",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a3/c6/d9b0509fe23a07de2ccee6ba1fd4", "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a3/c6/d9b0509fe23a07de2ccee6ba1fd4",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/1b/93/23b7d341894fb875acaefe0804c5", "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/16/a1/0283e8d4c813236f30f558fe7152",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/86/e1/65b4096af71168842a99278708da", "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/80/76/3f3b0aa3ee0c39b276d55adf31f5",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/d8/91/3b918141edeaeb3034e558f54246", "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/32/39/1a7d9be4330f5c74f67c6f7e22d8",
"build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/74/ff/12db4137ed498dbbffd892c5000f", "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/1c/c6/59922c32624d3a93be2080c1ff7d",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/41/0a/18695d2503c1062d7b2f47c88380", "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/9f/4e/4e6d977fb3bff4746d3c599e7567",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/2d/59/5bd72f8f691f041059cab3df99d5", "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/7f/28/36b8586b6b139ccb052accc29d2b",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/3b/63/7eeb46b7832e1135e58345866abf", "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/8c/b6/99368c99f9b63242df1f1875b5b5",
"build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/89/e4/0b7890024077f73e328b20b543f5", "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/74/9c/09e7f929fbcf075d41b976200950",
"src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/7d/3e/229a581cb2454ed856f1d8b564a7", "src/ballistica/generated/python_embedded/binding.inc": "https://files.ballistica.net/cache/ba1/7d/3e/229a581cb2454ed856f1d8b564a7",
"src/ballistica/generated/python_embedded/bootstrap.inc": "https://files.ballistica.net/cache/ba1/98/12/571b2160d69d42580e8f31fa6a8d" "src/ballistica/generated/python_embedded/bootstrap.inc": "https://files.ballistica.net/cache/ba1/98/12/571b2160d69d42580e8f31fa6a8d"
} }

View File

@ -1,4 +1,4 @@
### 1.7.7 (build 20809, api 7, 2022-09-10) ### 1.7.7 (build 20821, api 7, 2022-09-11)
- Added `ba.app.meta.load_exported_classes()` for loading classes discovered by the meta subsystem cleanly in a background thread. - Added `ba.app.meta.load_exported_classes()` for loading classes discovered by the meta subsystem cleanly in a background thread.
- Improved logging of missing playlist game types. - Improved logging of missing playlist game types.
- Some ba.Lstr functionality can now be used in background threads. - Some ba.Lstr functionality can now be used in background threads.
@ -23,6 +23,7 @@
- Renamed C++ App to AppFlavor and AppGlobals to App. - Renamed C++ App to AppFlavor and AppGlobals to App.
- Renamed C++ Media to Assets. - Renamed C++ Media to Assets.
- Removed 'scores to beat' list in coop which was only ever functional in limited cases on the Mac version. Perhaps that feature can reappear in a cross-platform way sometime. - Removed 'scores to beat' list in coop which was only ever functional in limited cases on the Mac version. Perhaps that feature can reappear in a cross-platform way sometime.
- Simplified C++ bootstrapping to allocate all globals in one place.
### 1.7.6 (build 20687, api 7, 2022-08-11) ### 1.7.6 (build 20687, api 7, 2022-08-11)
- Cleaned up da MetaSubsystem code. - Cleaned up da MetaSubsystem code.

View File

@ -38,7 +38,7 @@ def bootstrap() -> None:
# Give a soft warning if we're being used with a different binary # Give a soft warning if we're being used with a different binary
# version than we expect. # version than we expect.
expected_build = 20809 expected_build = 20821
running_build: int = env['build_number'] running_build: int = env['build_number']
if running_build != expected_build: if running_build != expected_build:
print( print(

View File

@ -13,24 +13,15 @@
namespace ballistica { namespace ballistica {
// The first thing the engine does is allocate an instance of this as g_globals. // The first thing the engine does is allocate an instance of this as g_app.
// As much as possible, previously static/global values should be moved to here,
// ideally as a temporary measure until they can be placed as non-static members
// in the proper classes.
// Any use of non-trivial global/static values such as class instances should be
// avoided since it can introduce ambiguities during init and teardown.
// For more explanation, see the 'Static and Global Variables' section in the
// Google C++ Style Guide.
class App { class App {
public: public:
App(int argc, char** argv); App(int argc, char** argv);
/// Program argument count (on applicable platforms). // The following are misc values that should be migrated to applicable
// subsystem classes.
int argc{}; int argc{};
/// Program argument values (on applicable platforms).
char** argv{}; char** argv{};
bool threads_paused{}; bool threads_paused{};
std::unordered_map<std::string, NodeType*> node_types; std::unordered_map<std::string, NodeType*> node_types;
std::unordered_map<int, NodeType*> node_types_by_id; std::unordered_map<int, NodeType*> node_types_by_id;

View File

@ -8,8 +8,6 @@
namespace ballistica { namespace ballistica {
void AppConfig::Init() { new AppConfig(); }
auto AppConfig::Entry::FloatValue() const -> float { auto AppConfig::Entry::FloatValue() const -> float {
throw Exception("not a float entry"); throw Exception("not a float entry");
} }
@ -137,12 +135,7 @@ class AppConfig::BoolEntry : public AppConfig::Entry {
bool default_value_{}; bool default_value_{};
}; };
AppConfig::AppConfig() { AppConfig::AppConfig() { SetupEntries(); }
// (We're a singleton).
assert(g_app_config == nullptr);
g_app_config = this;
SetupEntries();
}
// Clion think all calls of this are unreachable. // Clion think all calls of this are unreachable.
#pragma clang diagnostic push #pragma clang diagnostic push

View File

@ -94,7 +94,6 @@ class AppConfig {
std::string name_; std::string name_;
}; };
static void Init();
AppConfig(); AppConfig();
// Given specific ids, returns resolved values (fastest access). // Given specific ids, returns resolved values (fastest access).

View File

@ -607,20 +607,8 @@ void Assets::MarkComponentForLoad(AssetComponentData* c) {
// once it makes it back to us we can delete the ref (in // once it makes it back to us we can delete the ref (in
// ClearPendingLoadsDoneList) // ClearPendingLoadsDoneList)
auto asset_ptr = new Object::Ref<AssetComponentData>(c); auto asset_ref_ptr = new Object::Ref<AssetComponentData>(c);
g_assets_server->PushPendingPreload(asset_ref_ptr);
g_assets_server->thread()->PushCall([asset_ptr] {
assert(InAssetsThread());
// add our pointer to one of the preload lists and shake our preload thread
// to wake it up
if ((**asset_ptr).GetAssetType() == AssetType::kSound) {
g_assets_server->pending_preloads_audio_.push_back(asset_ptr);
} else {
g_assets_server->pending_preloads_.push_back(asset_ptr);
}
g_assets_server->process_timer_->SetLength(0);
});
} }
#pragma clang diagnostic push #pragma clang diagnostic push

View File

@ -12,21 +12,45 @@
namespace ballistica { namespace ballistica {
AssetsServer::AssetsServer(Thread* thread) AssetsServer::AssetsServer()
: thread_(thread), : writing_replay_(false),
writing_replay_(false),
replay_message_bytes_(0), replay_message_bytes_(0),
replays_broken_(false), replays_broken_(false),
replay_out_file_(nullptr) { replay_out_file_(nullptr) {
// We're a singleton; make sure we don't already exist.
assert(g_assets_server == nullptr); assert(g_assets_server == nullptr);
g_assets_server = this;
// get our thread to give us periodic processing time... // Spin up our thread.
process_timer_ = this->thread()->NewTimer( thread_ = new Thread(ThreadIdentifier::kAssets);
1000, true, NewLambdaRunnable([this] { Process(); })); g_app->pausable_threads.push_back(thread_);
} }
AssetsServer::~AssetsServer() = default; auto AssetsServer::Start() -> void {
thread_->PushCallSynchronous([this] { StartInThread(); });
}
auto AssetsServer::StartInThread() -> void {
assert(InAssetsThread());
// get our thread to give us periodic processing time...
process_timer_ =
thread()->NewTimer(1000, true, NewLambdaRunnable([this] { Process(); }));
}
auto AssetsServer::PushPendingPreload(
Object::Ref<AssetComponentData>* asset_ref_ptr) -> void {
thread()->PushCall([this, asset_ref_ptr] {
assert(InAssetsThread());
// Add our pointer to one of the preload lists and shake our preload thread
// to wake it up
if ((**asset_ref_ptr).GetAssetType() == AssetType::kSound) {
pending_preloads_audio_.push_back(asset_ref_ptr);
} else {
pending_preloads_.push_back(asset_ref_ptr);
}
process_timer_->SetLength(0);
});
}
void AssetsServer::PushBeginWriteReplayCall() { void AssetsServer::PushBeginWriteReplayCall() {
thread()->PushCall([this] { thread()->PushCall([this] {

View File

@ -12,14 +12,17 @@ namespace ballistica {
class AssetsServer { class AssetsServer {
public: public:
explicit AssetsServer(Thread* thread); AssetsServer();
~AssetsServer(); auto Start() -> void;
void PushBeginWriteReplayCall(); auto PushBeginWriteReplayCall() -> void;
void PushEndWriteReplayCall(); auto PushEndWriteReplayCall() -> void;
void PushAddMessageToReplayCall(const std::vector<uint8_t>& data); auto PushAddMessageToReplayCall(const std::vector<uint8_t>& data) -> void;
auto PushPendingPreload(Object::Ref<AssetComponentData>* asset_ref_ptr)
-> void;
auto thread() const -> Thread* { return thread_; } auto thread() const -> Thread* { return thread_; }
private: private:
auto StartInThread() -> void;
void Process(); void Process();
void WriteReplayMessages(); void WriteReplayMessages();
Thread* thread_{}; Thread* thread_{};
@ -32,8 +35,6 @@ class AssetsServer {
Timer* process_timer_{}; Timer* process_timer_{};
std::vector<Object::Ref<AssetComponentData>*> pending_preloads_; std::vector<Object::Ref<AssetComponentData>*> pending_preloads_;
std::vector<Object::Ref<AssetComponentData>*> pending_preloads_audio_; std::vector<Object::Ref<AssetComponentData>*> pending_preloads_audio_;
friend struct PreloadRunnable;
friend class Assets;
}; };
} // namespace ballistica } // namespace ballistica

View File

@ -9,13 +9,7 @@
namespace ballistica { namespace ballistica {
Audio::Audio() { assert(InLogicThread()); } Audio::Audio() {}
void Audio::Init() {
// Init our singleton.
assert(g_audio == nullptr);
g_audio = new Audio();
}
void Audio::Reset() { void Audio::Reset() {
assert(InLogicThread()); assert(InLogicThread());

View File

@ -15,14 +15,15 @@ namespace ballistica {
/// used by the game and/or other threads. /// used by the game and/or other threads.
class Audio { class Audio {
public: public:
static void Init(); Audio();
void Reset(); auto Reset() -> void;
void SetVolumes(float music_volume, float sound_volume); auto SetVolumes(float music_volume, float sound_volume) -> void;
void SetListenerPosition(const Vector3f& p); auto SetListenerPosition(const Vector3f& p) -> void;
void SetListenerOrientation(const Vector3f& forward, const Vector3f& up); auto SetListenerOrientation(const Vector3f& forward, const Vector3f& up)
void SetSoundPitch(float pitch); -> void;
auto SetSoundPitch(float pitch) -> void;
// Return a pointer to a locked sound source, or nullptr if they're all busy. // Return a pointer to a locked sound source, or nullptr if they're all busy.
// The sound source will be reset to standard settings (no loop, fade 1, pos // The sound source will be reset to standard settings (no loop, fade 1, pos
@ -41,9 +42,9 @@ class Audio {
auto IsSoundPlaying(uint32_t play_id) -> bool; auto IsSoundPlaying(uint32_t play_id) -> bool;
// Simple one-shot play functions. // Simple one-shot play functions.
void PlaySound(SoundData* s, float volume = 1.0f); auto PlaySound(SoundData* s, float volume = 1.0f) -> void;
void PlaySoundAtPosition(SoundData* sound, float volume, float x, float y, auto PlaySoundAtPosition(SoundData* sound, float volume, float x, float y,
float z); float z) -> void;
// Call this if you want to prevent repeated plays of the same sound. It'll // Call this if you want to prevent repeated plays of the same sound. It'll
// tell you if the sound has been played recently. The one-shot sound-play // tell you if the sound has been played recently. The one-shot sound-play
@ -51,19 +52,17 @@ class Audio {
auto ShouldPlay(SoundData* s) -> bool; auto ShouldPlay(SoundData* s) -> bool;
// Hmm; shouldn't these be accessed through the Source class? // Hmm; shouldn't these be accessed through the Source class?
void PushSourceFadeOutCall(uint32_t play_id, uint32_t time); auto PushSourceFadeOutCall(uint32_t play_id, uint32_t time) -> void;
void PushSourceStopSoundCall(uint32_t play_id); auto PushSourceStopSoundCall(uint32_t play_id) -> void;
void AddClientSource(AudioSource* source); auto AddClientSource(AudioSource* source) -> void;
void MakeSourceAvailable(AudioSource* source); auto MakeSourceAvailable(AudioSource* source) -> void;
auto available_sources_mutex() -> std::mutex& { auto available_sources_mutex() -> std::mutex& {
return available_sources_mutex_; return available_sources_mutex_;
} }
private: private:
Audio();
// Flat list of client sources indexed by id. // Flat list of client sources indexed by id.
std::vector<AudioSource*> client_sources_; std::vector<AudioSource*> client_sources_;

View File

@ -30,10 +30,10 @@ extern "C" void opensl_resume_playback();
extern std::string g_rift_audio_device_name; extern std::string g_rift_audio_device_name;
#endif #endif
const int kAudioProcessIntervalNormal = 500; const int kAudioProcessIntervalNormal{500};
const int kAudioProcessIntervalFade = 50; const int kAudioProcessIntervalFade{50};
const int kAudioProcessIntervalPendingLoad = 1; const int kAudioProcessIntervalPendingLoad{1};
const bool kShowInUseSounds = false; const bool kShowInUseSounds{};
int AudioServer::al_source_count_ = 0; int AudioServer::al_source_count_ = 0;
@ -55,7 +55,7 @@ class AudioServer::ThreadSource : public Object {
// not be used. // not be used.
ThreadSource(AudioServer* audio_thread, int id, bool* valid); ThreadSource(AudioServer* audio_thread, int id, bool* valid);
~ThreadSource() override; ~ThreadSource() override;
void Reset() { auto Reset() -> void {
SetIsMusic(false); SetIsMusic(false);
SetPositional(true); SetPositional(true);
SetPosition(0, 0, 0); SetPosition(0, 0, 0);
@ -66,18 +66,18 @@ class AudioServer::ThreadSource : public Object {
/// Set whether a sound is "music". /// Set whether a sound is "music".
/// This influences which volume controls affect it. /// This influences which volume controls affect it.
void SetIsMusic(bool m); auto SetIsMusic(bool m) -> void;
/// Set whether a source is positional. /// Set whether a source is positional.
/// A non-positional source's position coords are always relative to the /// A non-positional source's position coords are always relative to the
/// listener - ie: 0, 0, 0 will always be centered. /// listener - ie: 0, 0, 0 will always be centered.
void SetPositional(bool p); auto SetPositional(bool p) -> void;
void SetPosition(float x, float y, float z); auto SetPosition(float x, float y, float z) -> void;
void SetGain(float g); auto SetGain(float g) -> void;
void SetFade(float f); auto SetFade(float f) -> void;
void SetLooping(bool loop); auto SetLooping(bool loop) -> void;
auto Play(const Object::Ref<SoundData>* s) -> uint32_t; auto Play(const Object::Ref<SoundData>* s) -> uint32_t;
void Stop(); auto Stop() -> void;
auto play_count() -> uint32_t { return play_count_; } auto play_count() -> uint32_t { return play_count_; }
auto is_streamed() const -> bool { return is_streamed_; } auto is_streamed() const -> bool { return is_streamed_; }
auto current_is_music() const -> bool { return current_is_music_; } auto current_is_music() const -> bool { return current_is_music_; }
@ -93,34 +93,34 @@ class AudioServer::ThreadSource : public Object {
return source_sound_ ? source_sound_->get() : nullptr; return source_sound_ ? source_sound_->get() : nullptr;
} }
void UpdatePitch(); auto UpdatePitch() -> void;
void UpdateVolume(); auto UpdateVolume() -> void;
void ExecStop(); auto ExecStop() -> void;
void ExecPlay(); auto ExecPlay() -> void;
void Update(); auto Update() -> void;
private: private:
bool looping_ = false; bool looping_{};
std::unique_ptr<AudioSource> client_source_; std::unique_ptr<AudioSource> client_source_;
float fade_ = 1.0f; float fade_{1.0f};
float gain_ = 1.0f; float gain_{1.0f};
AudioServer* audio_thread_; AudioServer* audio_thread_{};
bool valid_ = false; bool valid_{};
const Object::Ref<SoundData>* source_sound_ = nullptr; const Object::Ref<SoundData>* source_sound_{};
int id_; int id_{};
uint32_t play_count_ = 0; uint32_t play_count_{};
bool is_actually_playing_ = false; bool is_actually_playing_{};
bool want_to_play_ = false; bool want_to_play_{};
#if BA_ENABLE_AUDIO #if BA_ENABLE_AUDIO
ALuint source_ = 0; ALuint source_{};
#endif #endif
bool is_streamed_ = false; bool is_streamed_{};
/// Whether we should be designated as "music" next time we play. /// Whether we should be designated as "music" next time we play.
bool is_music_ = false; bool is_music_{};
/// Whether currently playing as music. /// Whether currently playing as music.
bool current_is_music_ = false; bool current_is_music_{};
#if BA_ENABLE_AUDIO #if BA_ENABLE_AUDIO
Object::Ref<AudioStreamer> streamer_; Object::Ref<AudioStreamer> streamer_;
@ -321,24 +321,34 @@ void AudioServer::PushSetListenerOrientationCall(const Vector3f& forward,
}); });
} }
AudioServer::AudioServer(Thread* thread) AudioServer::AudioServer() : impl_{new AudioServer::Impl()} {
: thread_(thread), impl_{new AudioServer::Impl()} { // We're a singleton; make sure we don't already exist.
// we're a singleton...
assert(g_audio_server == nullptr); assert(g_audio_server == nullptr);
g_audio_server = this;
thread->AddPauseCallback(NewLambdaRunnableRaw([this] { OnThreadPause(); })); // Spin up our thread.
thread->AddResumeCallback(NewLambdaRunnableRaw([this] { OnThreadResume(); })); thread_ = new Thread(ThreadIdentifier::kAudio);
g_app->pausable_threads.push_back(thread_);
}
auto AudioServer::Start() -> void {
thread_->PushCallSynchronous([this] { StartInThread(); });
}
auto AudioServer::StartInThread() -> void {
assert(InAudioThread());
thread()->AddPauseCallback(NewLambdaRunnableRaw([this] { OnThreadPause(); }));
thread()->AddResumeCallback(
NewLambdaRunnableRaw([this] { OnThreadResume(); }));
// Get our thread to give us periodic processing time. // Get our thread to give us periodic processing time.
process_timer_ = thread->NewTimer(kAudioProcessIntervalNormal, true, process_timer_ = thread()->NewTimer(kAudioProcessIntervalNormal, true,
NewLambdaRunnable([this] { Process(); })); NewLambdaRunnable([this] { Process(); }));
#if BA_ENABLE_AUDIO #if BA_ENABLE_AUDIO
// Bring up OpenAL stuff. // Bring up OpenAL stuff.
{ {
const char* alDeviceName = nullptr; const char* al_device_name = nullptr;
// On the rift build in vr mode we need to make sure we open the rift audio // On the rift build in vr mode we need to make sure we open the rift audio
// device. // device.
@ -363,7 +373,7 @@ AudioServer::AudioServer(Thread* thread)
// These names seem to be things like "OpenAL Soft on FOO" // These names seem to be things like "OpenAL Soft on FOO"
// ..we should be able to search for FOO. // ..we should be able to search for FOO.
if (strstr(device, g_rift_audio_device_name.c_str())) { if (strstr(device, g_rift_audio_device_name.c_str())) {
alDeviceName = device; al_device_name = device;
} }
len = strlen(device); len = strlen(device);
device += (len + 1); device += (len + 1);
@ -376,7 +386,7 @@ AudioServer::AudioServer(Thread* thread)
#endif // BA_RIFT_BUILD #endif // BA_RIFT_BUILD
ALCdevice* device; ALCdevice* device;
device = alcOpenDevice(alDeviceName); device = alcOpenDevice(al_device_name);
BA_PRECONDITION(device); BA_PRECONDITION(device);
impl_->alc_context_ = alcCreateContext(device, nullptr); impl_->alc_context_ = alcCreateContext(device, nullptr);
BA_PRECONDITION(impl_->alc_context_); BA_PRECONDITION(impl_->alc_context_);
@ -702,7 +712,9 @@ AudioServer::ThreadSource::ThreadSource(AudioServer* audio_thread_in, int id_in,
CHECK_AL_ERROR; CHECK_AL_ERROR;
} }
*valid_out = valid_; *valid_out = valid_;
if (valid_) al_source_count_++; if (valid_) {
al_source_count_++;
}
#endif // BA_ENABLE_AUDIO #endif // BA_ENABLE_AUDIO
} }

View File

@ -22,45 +22,47 @@ class AudioServer {
return play_id >> 16u; return play_id >> 16u;
} }
explicit AudioServer(Thread* o); AudioServer();
auto Start() -> void;
void PushSetVolumesCall(float music_volume, float sound_volume); auto PushSetVolumesCall(float music_volume, float sound_volume) -> void;
void PushSetSoundPitchCall(float val); auto PushSetSoundPitchCall(float val) -> void;
void PushSetPausedCall(bool pause); auto PushSetPausedCall(bool pause) -> void;
static void BeginInterruption(); static auto BeginInterruption() -> void;
static void EndInterruption(); static auto EndInterruption() -> void;
void PushSetListenerPositionCall(const Vector3f& p); auto PushSetListenerPositionCall(const Vector3f& p) -> void;
void PushSetListenerOrientationCall(const Vector3f& forward, auto PushSetListenerOrientationCall(const Vector3f& forward,
const Vector3f& up); const Vector3f& up) -> void;
void PushResetCall(); auto PushResetCall() -> void;
void PushHavePendingLoadsCall(); auto PushHavePendingLoadsCall() -> void;
void PushComponentUnloadCall( auto PushComponentUnloadCall(
const std::vector<Object::Ref<AssetComponentData>*>& components); const std::vector<Object::Ref<AssetComponentData>*>& components) -> void;
/// For use by g_game_module(). /// For use by g_game_module().
void ClearSoundRefDeleteList(); auto ClearSoundRefDeleteList() -> void;
auto paused() const -> bool { return paused_; } auto paused() const -> bool { return paused_; }
// Client sources use these to pass settings to the server. // Client sources use these to pass settings to the server.
void PushSourceSetIsMusicCall(uint32_t play_id, bool val); auto PushSourceSetIsMusicCall(uint32_t play_id, bool val) -> void;
void PushSourceSetPositionalCall(uint32_t play_id, bool val); auto PushSourceSetPositionalCall(uint32_t play_id, bool val) -> void;
void PushSourceSetPositionCall(uint32_t play_id, const Vector3f& p); auto PushSourceSetPositionCall(uint32_t play_id, const Vector3f& p) -> void;
void PushSourceSetGainCall(uint32_t play_id, float val); auto PushSourceSetGainCall(uint32_t play_id, float val) -> void;
void PushSourceSetFadeCall(uint32_t play_id, float val); auto PushSourceSetFadeCall(uint32_t play_id, float val) -> void;
void PushSourceSetLoopingCall(uint32_t play_id, bool val); auto PushSourceSetLoopingCall(uint32_t play_id, bool val) -> void;
void PushSourcePlayCall(uint32_t play_id, Object::Ref<SoundData>* sound); auto PushSourcePlayCall(uint32_t play_id, Object::Ref<SoundData>* sound)
void PushSourceStopCall(uint32_t play_id); -> void;
void PushSourceEndCall(uint32_t play_id); auto PushSourceStopCall(uint32_t play_id) -> void;
auto PushSourceEndCall(uint32_t play_id) -> void;
// Fade a playing sound out over the given time. If it is already // Fade a playing sound out over the given time. If it is already
// fading or does not exist, does nothing. // fading or does not exist, does nothing.
void FadeSoundOut(uint32_t play_id, uint32_t time); auto FadeSoundOut(uint32_t play_id, uint32_t time) -> void;
// Stop a sound from playing if it exists. // Stop a sound from playing if it exists.
void StopSound(uint32_t play_id); auto StopSound(uint32_t play_id) -> void;
auto thread() const -> Thread* { return thread_; } auto thread() const -> Thread* { return thread_; }
@ -68,16 +70,17 @@ class AudioServer {
class ThreadSource; class ThreadSource;
struct Impl; struct Impl;
auto StartInThread() -> void;
~AudioServer(); ~AudioServer();
auto OnThreadPause() -> void; auto OnThreadPause() -> void;
auto OnThreadResume() -> void; auto OnThreadResume() -> void;
void SetPaused(bool paused); auto SetPaused(bool paused) -> void;
void SetMusicVolume(float volume); auto SetMusicVolume(float volume) -> void;
void SetSoundVolume(float volume); auto SetSoundVolume(float volume) -> void;
void SetSoundPitch(float pitch); auto SetSoundPitch(float pitch) -> void;
auto music_volume() -> float { return music_volume_; } auto music_volume() -> float { return music_volume_; }
auto sound_volume() -> float { return sound_volume_; } auto sound_volume() -> float { return sound_volume_; }
auto sound_pitch() -> float { return sound_pitch_; } auto sound_pitch() -> float { return sound_pitch_; }
@ -85,22 +88,22 @@ class AudioServer {
/// If a sound play id is currently playing, return the sound. /// If a sound play id is currently playing, return the sound.
auto GetPlayingSound(uint32_t play_id) -> ThreadSource*; auto GetPlayingSound(uint32_t play_id) -> ThreadSource*;
void Reset(); auto Reset() -> void;
void Process(); auto Process() -> void;
/// Send a component to the audio thread to delete. /// Send a component to the audio thread to delete.
void DeleteAssetComponent(AssetComponentData* c); auto DeleteAssetComponent(AssetComponentData* c) -> void;
void UpdateTimerInterval(); auto UpdateTimerInterval() -> void;
void UpdateAvailableSources(); auto UpdateAvailableSources() -> void;
void UpdateMusicPlayState(); auto UpdateMusicPlayState() -> void;
void ProcessSoundFades(); auto ProcessSoundFades() -> void;
// Some threads such as audio hold onto allocated Media-Component-Refs to keep // Some threads such as audio hold onto allocated Media-Component-Refs to keep
// media components alive that they need. Media-Component-Refs, however, must // media components alive that they need. Media-Component-Refs, however, must
// be disposed of in the game thread, so they are passed back to it through // be disposed of in the game thread, so they are passed back to it through
// this function. // this function.
void AddSoundRefDelete(const Object::Ref<SoundData>* c); auto AddSoundRefDelete(const Object::Ref<SoundData>* c) -> void;
// Note: should use unique_ptr for this, but build fails on raspberry pi // Note: should use unique_ptr for this, but build fails on raspberry pi
// (gcc 8.3.0). Works on Ubuntu 9.3 so should try again later. // (gcc 8.3.0). Works on Ubuntu 9.3 so should try again later.

View File

@ -4,26 +4,33 @@
#include <map> #include <map>
#include "ballistica/app/app_config.h"
#include "ballistica/app/app_flavor.h" #include "ballistica/app/app_flavor.h"
#include "ballistica/assets/assets.h" #include "ballistica/assets/assets.h"
#include "ballistica/assets/assets_server.h" #include "ballistica/assets/assets_server.h"
#include "ballistica/audio/audio.h"
#include "ballistica/audio/audio_server.h" #include "ballistica/audio/audio_server.h"
#include "ballistica/core/context.h"
#include "ballistica/core/fatal_error.h" #include "ballistica/core/fatal_error.h"
#include "ballistica/core/logging.h" #include "ballistica/core/logging.h"
#include "ballistica/core/thread.h" #include "ballistica/core/thread.h"
#include "ballistica/dynamics/bg/bg_dynamics_server.h" #include "ballistica/dynamics/bg/bg_dynamics_server.h"
#include "ballistica/game/v1_account.h" #include "ballistica/game/v1_account.h"
#include "ballistica/graphics/graphics_server.h" #include "ballistica/graphics/graphics_server.h"
#include "ballistica/graphics/text/text_graphics.h"
#include "ballistica/input/input.h"
#include "ballistica/internal/app_internal.h" #include "ballistica/internal/app_internal.h"
#include "ballistica/networking/network_writer.h" #include "ballistica/networking/network_writer.h"
#include "ballistica/networking/networking.h"
#include "ballistica/platform/platform.h" #include "ballistica/platform/platform.h"
#include "ballistica/python/python.h" #include "ballistica/python/python.h"
#include "ballistica/scene/scene.h" #include "ballistica/scene/scene.h"
#include "ballistica/ui/ui.h"
namespace ballistica { namespace ballistica {
// These are set automatically via script; don't modify them here. // These are set automatically via script; don't modify them here.
const int kAppBuildNumber = 20809; const int kAppBuildNumber = 20821;
const char* kAppVersion = "1.7.7"; const char* kAppVersion = "1.7.7";
// Our standalone globals. // Our standalone globals.
@ -40,6 +47,7 @@ Audio* g_audio{};
AudioServer* g_audio_server{}; AudioServer* g_audio_server{};
BGDynamics* g_bg_dynamics{}; BGDynamics* g_bg_dynamics{};
BGDynamicsServer* g_bg_dynamics_server{}; BGDynamicsServer* g_bg_dynamics_server{};
Context* g_context{};
Game* g_game{}; Game* g_game{};
Graphics* g_graphics{}; Graphics* g_graphics{};
GraphicsServer* g_graphics_server{}; GraphicsServer* g_graphics_server{};
@ -49,7 +57,7 @@ Assets* g_assets{};
AssetsServer* g_assets_server{}; AssetsServer* g_assets_server{};
NetworkReader* g_network_reader{}; NetworkReader* g_network_reader{};
Networking* g_networking{}; Networking* g_networking{};
NetworkWriteModule* g_network_writer{}; NetworkWriter* g_network_writer{};
Platform* g_platform{}; Platform* g_platform{};
Python* g_python{}; Python* g_python{};
StdInputModule* g_std_input_module{}; StdInputModule* g_std_input_module{};
@ -93,28 +101,35 @@ auto BallisticaMain(int argc, char** argv) -> int {
// Bootstrap our Python environment as early as we can (depends on // Bootstrap our Python environment as early as we can (depends on
// g_platform for locating OS-specific paths). // g_platform for locating OS-specific paths).
assert(g_python == nullptr);
g_python = new Python(); g_python = new Python();
// Create a Thread wrapper around the current (main) thread. // Create a Thread wrapper around the current (main) thread.
g_main_thread = new Thread(ThreadIdentifier::kMain, ThreadType::kMain); g_main_thread = new Thread(ThreadIdentifier::kMain, ThreadType::kMain);
Thread::UpdateMainThreadID(); Thread::UpdateMainThreadID();
// Spin up our specific app variation (VR, headless, regular, etc.) // Spin up our specific app and graphics variations
// (VR, headless, regular, etc.)
g_app_flavor = g_platform->CreateAppFlavor(); g_app_flavor = g_platform->CreateAppFlavor();
g_app_flavor->PostInit(); g_graphics = g_platform->CreateGraphics();
// Various other subsystems. // Various other subsystems.
g_graphics_server = new GraphicsServer();
g_audio = new Audio();
g_audio_server = new AudioServer();
g_context = new Context(nullptr);
g_text_graphics = new TextGraphics();
g_app_config = new AppConfig();
g_v1_account = new V1Account(); g_v1_account = new V1Account();
g_utils = new Utils(); g_utils = new Utils();
g_assets = new Assets(); g_assets = new Assets();
g_assets_server = new AssetsServer();
g_ui = Object::NewUnmanaged<UI>();
g_networking = new Networking();
g_input = new Input();
g_app_internal = GetAppInternal();
Scene::Init(); Scene::Init();
// Spin up our other standard threads. // Spin up our other standard threads.
auto* assets_thread{new Thread(ThreadIdentifier::kAssets)};
g_app->pausable_threads.push_back(assets_thread);
auto* audio_thread{new Thread(ThreadIdentifier::kAudio)};
g_app->pausable_threads.push_back(audio_thread);
auto* logic_thread{new Thread(ThreadIdentifier::kLogic)}; auto* logic_thread{new Thread(ThreadIdentifier::kLogic)};
g_app->pausable_threads.push_back(logic_thread); g_app->pausable_threads.push_back(logic_thread);
auto* network_write_thread{new Thread(ThreadIdentifier::kNetworkWrite)}; auto* network_write_thread{new Thread(ThreadIdentifier::kNetworkWrite)};
@ -123,14 +138,8 @@ auto BallisticaMain(int argc, char** argv) -> int {
// Spin up our subsystems in those threads. // Spin up our subsystems in those threads.
logic_thread->PushCallSynchronous( logic_thread->PushCallSynchronous(
[logic_thread] { new Game(logic_thread); }); [logic_thread] { new Game(logic_thread); });
network_write_thread->PushCallSynchronous([network_write_thread] { network_write_thread->PushCallSynchronous(
new NetworkWriteModule(network_write_thread); [network_write_thread] { new NetworkWriter(network_write_thread); });
});
assets_thread->PushCallSynchronous(
[assets_thread] { new AssetsServer(assets_thread); });
new GraphicsServer(g_main_thread);
audio_thread->PushCallSynchronous(
[audio_thread] { new AudioServer(audio_thread); });
// Now let the platform spin up any other threads/modules it uses. // Now let the platform spin up any other threads/modules it uses.
// (bg-dynamics in non-headless builds, stdin/stdout where applicable, // (bg-dynamics in non-headless builds, stdin/stdout where applicable,
@ -144,6 +153,9 @@ auto BallisticaMain(int argc, char** argv) -> int {
// Phase 2: Set things in motion. // Phase 2: Set things in motion.
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
g_audio_server->Start();
g_assets_server->Start();
// Let the app and platform do whatever else it wants here such as adding // Let the app and platform do whatever else it wants here such as adding
// initial input devices/etc. // initial input devices/etc.
g_app_flavor->OnBootstrapComplete(); g_app_flavor->OnBootstrapComplete();

View File

@ -122,7 +122,7 @@ extern Assets* g_assets;
extern AssetsServer* g_assets_server; extern AssetsServer* g_assets_server;
extern Networking* g_networking; extern Networking* g_networking;
extern NetworkReader* g_network_reader; extern NetworkReader* g_network_reader;
extern NetworkWriteModule* g_network_writer; extern NetworkWriter* g_network_writer;
extern Platform* g_platform; extern Platform* g_platform;
extern Python* g_python; extern Python* g_python;
extern StdInputModule* g_std_input_module; extern StdInputModule* g_std_input_module;

View File

@ -8,14 +8,6 @@
namespace ballistica { namespace ballistica {
// Dynamically allocate this; don't want it torn down on quit.
Context* g_context = nullptr;
void Context::Init() {
assert(!g_context);
g_context = new Context(nullptr);
}
ContextTarget::ContextTarget() = default; ContextTarget::ContextTarget() = default;
ContextTarget::~ContextTarget() = default; ContextTarget::~ContextTarget() = default;

View File

@ -14,8 +14,6 @@ namespace ballistica {
// effects properly apply to the place they came from. // effects properly apply to the place they came from.
class Context { class Context {
public: public:
static void Init();
static auto current() -> const Context& { static auto current() -> const Context& {
assert(g_context); assert(g_context);

View File

@ -84,7 +84,7 @@ void Thread::WaitForNextEvent(bool single_cycle) {
} }
// While we're waiting, allow other python threads to run. // While we're waiting, allow other python threads to run.
if (owns_python_) { if (holds_python_gil_) {
g_python->ReleaseGIL(); g_python->ReleaseGIL();
} }
@ -117,7 +117,7 @@ void Thread::WaitForNextEvent(bool single_cycle) {
} }
} }
if (owns_python_) { if (holds_python_gil_) {
g_python->AcquireGIL(); g_python->AcquireGIL();
} }
} }
@ -357,8 +357,8 @@ auto Thread::ThreadMain() -> int {
} }
} }
void Thread::SetOwnsPython() { void Thread::SetHoldsPythonGIL() {
owns_python_ = true; holds_python_gil_ = true;
g_python->AcquireGIL(); g_python->AcquireGIL();
} }

View File

@ -44,7 +44,7 @@ class Thread {
// Used to quit the main thread. // Used to quit the main thread.
void Quit(); void Quit();
void SetOwnsPython(); void SetHoldsPythonGIL();
void SetPaused(bool paused); void SetPaused(bool paused);
auto thread_id() const -> std::thread::id { return thread_id_; } auto thread_id() const -> std::thread::id { return thread_id_; }
@ -137,7 +137,7 @@ class Thread {
std::thread::id thread_id_{}; std::thread::id thread_id_{};
ThreadIdentifier identifier_{ThreadIdentifier::kInvalid}; ThreadIdentifier identifier_{ThreadIdentifier::kInvalid};
millisecs_t last_complaint_time_{}; millisecs_t last_complaint_time_{};
bool owns_python_{}; bool holds_python_gil_{};
// FIXME: Should generalize this to some sort of PlatformThreadData class. // FIXME: Should generalize this to some sort of PlatformThreadData class.
#if BA_XCODE_BUILD #if BA_XCODE_BUILD

View File

@ -123,7 +123,7 @@ class NetClientThread;
class NetGraph; class NetGraph;
class Networking; class Networking;
class NetworkReader; class NetworkReader;
class NetworkWriteModule; class NetworkWriter;
class Node; class Node;
class NodeType; class NodeType;
class NodeAttribute; class NodeAttribute;

View File

@ -73,45 +73,27 @@ Game::Game(Thread* thread)
g_game = this; g_game = this;
try { try {
// Spin up some other game-thread-based stuff. // Our thread should hold the Python GIL by default.
AppConfig::Init(); // TODO(ericf): It could be better to have each individual Python call
assert(g_graphics == nullptr); // we make acquire the GIL. Then we're not holding it during long
g_graphics = g_platform->CreateGraphics(); // bits of C++ logic.
TextGraphics::Init(); thread->SetHoldsPythonGIL();
Audio::Init();
if (!HeadlessMode()) { if (!HeadlessMode()) {
BGDynamics::Init(); BGDynamics::Init();
} }
InitSpecialChars(); InitSpecialChars();
Context::Init();
// We want to be informed when our thread is pausing. // We want to be informed when our thread is pausing.
thread->AddPauseCallback(NewLambdaRunnableRaw([this] { OnThreadPause(); })); thread->AddPauseCallback(NewLambdaRunnableRaw([this] { OnThreadPause(); }));
// Waaah does UI need to be a bs::Object? g_ui->LogicThreadInit();
// Update: yes it does in order to be a context target.
// (need to be able to create weak-refs to it).
assert(g_ui == nullptr);
g_ui = Object::NewUnmanaged<UI>();
g_ui->PostInit();
assert(g_networking == nullptr);
g_networking = new Networking();
assert(g_input == nullptr);
g_input = new Input();
g_app_internal = GetAppInternal();
// Init python and apply our settings immediately. // Init python and apply our settings immediately.
// This way we can get started loading stuff in the background // This way we can get started loading stuff in the background
// and it'll come in with the correct texture quality etc. // and it'll come in with the correct texture quality etc.
g_python->Reset(true); g_python->Reset(true);
// We're the thread that 'owns' python so we need to wrangle the GIL.
thread->SetOwnsPython();
} catch (const std::exception& e) { } catch (const std::exception& e) {
// If anything went wrong, trigger a deferred error. // If anything went wrong, trigger a deferred error.
// This way it is more likely we can show a fatal error dialog // This way it is more likely we can show a fatal error dialog

View File

@ -324,7 +324,7 @@ class Game {
int last_kick_votes_needed_{-1}; int last_kick_votes_needed_{-1};
Object::WeakRef<ConnectionToClient> kick_vote_starter_; Object::WeakRef<ConnectionToClient> kick_vote_starter_;
Object::WeakRef<ConnectionToClient> kick_vote_target_; Object::WeakRef<ConnectionToClient> kick_vote_target_;
bool public_party_enabled_{false}; bool public_party_enabled_{};
int public_party_size_{1}; // Always count ourself (is that what we want?). int public_party_size_{1}; // Always count ourself (is that what we want?).
int public_party_max_size_{8}; int public_party_max_size_{8};
int public_party_player_count_{0}; int public_party_player_count_{0};

View File

@ -87,8 +87,8 @@ class HostActivity : public ContextTarget {
auto StepScene() -> void; auto StepScene() -> void;
Object::WeakRef<GlobalsNode> globals_node_; Object::WeakRef<GlobalsNode> globals_node_;
bool allow_kick_idle_players_ = false; bool allow_kick_idle_players_{};
Timer* step_scene_timer_ = nullptr; Timer* step_scene_timer_{};
std::unordered_map<std::string, Object::WeakRef<Texture> > textures_; std::unordered_map<std::string, Object::WeakRef<Texture> > textures_;
std::unordered_map<std::string, Object::WeakRef<Sound> > sounds_; std::unordered_map<std::string, Object::WeakRef<Sound> > sounds_;
std::unordered_map<std::string, Object::WeakRef<Data> > datas_; std::unordered_map<std::string, Object::WeakRef<Data> > datas_;
@ -96,18 +96,18 @@ class HostActivity : public ContextTarget {
collide_models_; collide_models_;
std::unordered_map<std::string, Object::WeakRef<Model> > models_; std::unordered_map<std::string, Object::WeakRef<Model> > models_;
std::list<Object::WeakRef<Material> > materials_; std::list<Object::WeakRef<Material> > materials_;
bool shutting_down_ = false; bool shutting_down_{};
// Our list of python calls created in the context of this activity; // Our list of python calls created in the context of this activity;
// we clear them as we are shutting down and ensure nothing runs after // we clear them as we are shutting down and ensure nothing runs after
// that point. // that point.
std::list<Object::WeakRef<PythonContextCall> > python_calls_; std::list<Object::WeakRef<PythonContextCall> > python_calls_;
millisecs_t next_prune_time_ = 0; millisecs_t next_prune_time_{};
bool _started = false; bool _started{};
int out_of_bounds_in_a_row_ = 0; int out_of_bounds_in_a_row_{};
bool paused_ = false; bool paused_{};
float game_speed_ = 0.0f; float game_speed_{};
millisecs_t base_time_ = 0; millisecs_t base_time_{};
Object::Ref<Scene> scene_; Object::Ref<Scene> scene_;
Object::WeakRef<HostSession> host_session_; Object::WeakRef<HostSession> host_session_;
PythonRef py_activity_weak_ref_; PythonRef py_activity_weak_ref_;

View File

@ -147,7 +147,7 @@ class Player : public Object {
// Player's position for use by input devices and whatnot for guides. // Player's position for use by input devices and whatnot for guides.
// FIXME: This info should be acquired through the player node. // FIXME: This info should be acquired through the player node.
bool have_position_{false}; bool have_position_{};
Vector3f position_{0.0f, 0.0f, 0.0f}; Vector3f position_{0.0f, 0.0f, 0.0f};
// These should be destructed before the rest of our class goes down, // These should be destructed before the rest of our class goes down,

View File

@ -16,7 +16,7 @@ namespace ballistica {
/// should not know or care about V2 accounts. /// should not know or care about V2 accounts.
class PlayerSpec { class PlayerSpec {
public: public:
/// Init an invalid player-spec /// Create an invalid player-spec.
PlayerSpec(); PlayerSpec();
auto operator==(const PlayerSpec& spec) const -> bool; auto operator==(const PlayerSpec& spec) const -> bool;

View File

@ -85,8 +85,8 @@ class ClientSession : public Session {
virtual auto OnReset(bool rewind) -> void; virtual auto OnReset(bool rewind) -> void;
virtual auto FetchMessages() -> void {} virtual auto FetchMessages() -> void {}
virtual void Error(const std::string& description); virtual void Error(const std::string& description);
void End(); auto End() -> void;
void DumpFullState(SceneStream* out) override; auto DumpFullState(SceneStream* out) -> void override;
/// Reset target base time to equal current. This can be used during command /// Reset target base time to equal current. This can be used during command
/// buffer underruns to cause playback to pause momentarily instead of /// buffer underruns to cause playback to pause momentarily instead of
@ -95,8 +95,8 @@ class ClientSession : public Session {
auto ResetTargetBaseTime() -> void { target_base_time_ = base_time_; } auto ResetTargetBaseTime() -> void { target_base_time_ = base_time_; }
private: private:
void ClearSessionObjs(); auto ClearSessionObjs() -> void;
void AddCommand(const std::vector<uint8_t>& command); auto AddCommand(const std::vector<uint8_t>& command) -> void;
auto ReadByte() -> uint8_t; auto ReadByte() -> uint8_t;
auto ReadInt32() -> int32_t; auto ReadInt32() -> int32_t;

View File

@ -30,10 +30,9 @@ void GraphicsServer::FullscreenCheck() {
} }
#endif #endif
GraphicsServer::GraphicsServer(Thread* thread) : thread_(thread) { GraphicsServer::GraphicsServer() : thread_(g_main_thread) {
// We're a singleton. // We're a singleton; make sure we don't already exist.
assert(g_graphics_server == nullptr); assert(g_graphics_server == nullptr);
g_graphics_server = this;
// For janky old non-event-push mode, just fall back on a timer for rendering. // For janky old non-event-push mode, just fall back on a timer for rendering.
if (!g_platform->IsEventPushMode()) { if (!g_platform->IsEventPushMode()) {

View File

@ -18,7 +18,7 @@ namespace ballistica {
// Graphics // Graphics
class GraphicsServer { class GraphicsServer {
public: public:
explicit GraphicsServer(Thread* thread); GraphicsServer();
auto PushSetScreenGammaCall(float gamma) -> void; auto PushSetScreenGammaCall(float gamma) -> void;
auto PushSetScreenPixelScaleCall(float pixel_scale) -> void; auto PushSetScreenPixelScaleCall(float pixel_scale) -> void;
auto PushSetVSyncCall(bool sync, bool auto_sync) -> void; auto PushSetVSyncCall(bool sync, bool auto_sync) -> void;
@ -61,18 +61,22 @@ class GraphicsServer {
// init the modelview matrix to look here // init the modelview matrix to look here
auto SetCamera(const Vector3f& eye, const Vector3f& target, auto SetCamera(const Vector3f& eye, const Vector3f& target,
const Vector3f& up) -> void; const Vector3f& up) -> void;
auto SetOrthoProjection(float left, float right, float bottom, float top, auto SetOrthoProjection(float left, float right, float bottom, float top,
float near, float far) -> void; float near, float far) -> void;
auto ModelViewReset() -> void { auto ModelViewReset() -> void {
model_view_matrix_ = kMatrix44fIdentity; model_view_matrix_ = kMatrix44fIdentity;
model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true; model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true;
model_view_stack_.clear(); model_view_stack_.clear();
} }
auto SetProjectionMatrix(const Matrix44f& p) -> void { auto SetProjectionMatrix(const Matrix44f& p) -> void {
projection_matrix_ = p; projection_matrix_ = p;
model_view_projection_matrix_dirty_ = true; model_view_projection_matrix_dirty_ = true;
projection_matrix_state_++; projection_matrix_state_++;
} }
auto projection_matrix_state() -> uint32_t { auto projection_matrix_state() -> uint32_t {
return projection_matrix_state_; return projection_matrix_state_;
} }
@ -85,9 +89,11 @@ class GraphicsServer {
light_shadow_projection_matrix_state_++; light_shadow_projection_matrix_state_++;
} }
} }
auto light_shadow_projection_matrix_state() const -> uint32_t { auto light_shadow_projection_matrix_state() const -> uint32_t {
return light_shadow_projection_matrix_state_; return light_shadow_projection_matrix_state_;
} }
auto light_shadow_projection_matrix() const -> const Matrix44f& { auto light_shadow_projection_matrix() const -> const Matrix44f& {
return light_shadow_projection_matrix_; return light_shadow_projection_matrix_;
} }
@ -270,6 +276,13 @@ class GraphicsServer {
model_world_matrix_dirty_ = false; model_world_matrix_dirty_ = false;
} }
} }
auto SetScreen(bool fullscreen, int width, int height,
TextureQuality texture_quality,
GraphicsQuality graphics_quality,
const std::string& android_res) -> void;
#if BA_OSTYPE_MACOS && BA_XCODE_BUILD
void FullscreenCheck();
#endif
#if BA_ENABLE_OPENGL #if BA_ENABLE_OPENGL
std::unique_ptr<GLContext> gl_context_; std::unique_ptr<GLContext> gl_context_;
#endif #endif
@ -291,7 +304,6 @@ class GraphicsServer {
bool fullscreen_enabled_{}; bool fullscreen_enabled_{};
float target_res_x_{800.0f}; float target_res_x_{800.0f};
float target_res_y_{600.0f}; float target_res_y_{600.0f};
Matrix44f model_view_matrix_{kMatrix44fIdentity}; Matrix44f model_view_matrix_{kMatrix44fIdentity};
Matrix44f view_world_matrix_{kMatrix44fIdentity}; Matrix44f view_world_matrix_{kMatrix44fIdentity};
Matrix44f projection_matrix_{kMatrix44fIdentity}; Matrix44f projection_matrix_{kMatrix44fIdentity};
@ -314,18 +326,11 @@ class GraphicsServer {
std::list<MeshData*> mesh_datas_; std::list<MeshData*> mesh_datas_;
bool v_sync_{}; bool v_sync_{};
bool auto_vsync_{}; bool auto_vsync_{};
auto SetScreen(bool fullscreen, int width, int height,
TextureQuality texture_quality,
GraphicsQuality graphics_quality,
const std::string& android_res) -> void;
Timer* render_timer_{}; Timer* render_timer_{};
Renderer* renderer_{}; Renderer* renderer_{};
FrameDef* frame_def_{}; FrameDef* frame_def_{};
bool initial_screen_created_{}; bool initial_screen_created_{};
int render_hold_{}; int render_hold_{};
#if BA_OSTYPE_MACOS && BA_XCODE_BUILD
void FullscreenCheck();
#endif
}; };
} // namespace ballistica } // namespace ballistica

View File

@ -19,12 +19,6 @@ class TextGraphics::TextSpanBoundsCacheEntry : public Object {
std::list<Object::Ref<TextSpanBoundsCacheEntry>>::iterator list_iterator_; std::list<Object::Ref<TextSpanBoundsCacheEntry>>::iterator list_iterator_;
}; };
void TextGraphics::Init() {
assert(InLogicThread());
assert(g_text_graphics == nullptr);
g_text_graphics = new TextGraphics();
}
TextGraphics::TextGraphics() { TextGraphics::TextGraphics() {
// Init glyph values for our custom font pages // Init glyph values for our custom font pages
// (just a 5x5 array currently). // (just a 5x5 array currently).

View File

@ -22,8 +22,6 @@ const float kTextRowHeight = 32.0f;
// Encapsulates text-display functionality used by the game thread. // Encapsulates text-display functionality used by the game thread.
class TextGraphics { class TextGraphics {
public: public:
static void Init();
TextGraphics(); TextGraphics();
enum class FontPage { enum class FontPage {

View File

@ -318,17 +318,7 @@ static const char* const scancode_names[SDL_NUM_SCANCODES] = {
}; };
#endif // BA_SDL2_BUILD || BA_MINSDL_BUILD #endif // BA_SDL2_BUILD || BA_MINSDL_BUILD
Input::Input() { Input::Input() {}
// We're a singleton.
// assert(g_input == nullptr);
// g_input = this;
assert(InLogicThread());
// Config should have always been read by this point; right?
// assert(g_python);
// UpdateEnabledControllerSubsystems();
}
void Input::PushCreateKeyboardInputDevices() { void Input::PushCreateKeyboardInputDevices() {
g_game->thread()->PushCall([this] { CreateKeyboardInputDevices(); }); g_game->thread()->PushCall([this] { CreateKeyboardInputDevices(); });
@ -362,8 +352,6 @@ void Input::DestroyKeyboardInputDevices() {
keyboard_input_2_ = nullptr; keyboard_input_2_ = nullptr;
} }
Input::~Input() = default;
auto Input::GetInputDevice(int id) -> InputDevice* { auto Input::GetInputDevice(int id) -> InputDevice* {
if (id < 0 || id >= static_cast<int>(input_devices_.size())) { if (id < 0 || id >= static_cast<int>(input_devices_.size())) {
return nullptr; return nullptr;

View File

@ -18,7 +18,6 @@ namespace ballistica {
class Input { class Input {
public: public:
Input(); Input();
virtual ~Input();
// Add an input device. Must be called from the game thread; otherwise use // Add an input device. Must be called from the game thread; otherwise use
// PushAddInputDeviceCall. // PushAddInputDeviceCall.

View File

@ -8,14 +8,14 @@
namespace ballistica { namespace ballistica {
NetworkWriteModule::NetworkWriteModule(Thread* thread) : thread_(thread) { NetworkWriter::NetworkWriter(Thread* thread) : thread_(thread) {
// we're a singleton // we're a singleton
assert(g_network_writer == nullptr); assert(g_network_writer == nullptr);
g_network_writer = this; g_network_writer = this;
} }
void NetworkWriteModule::PushSendToCall(const std::vector<uint8_t>& msg, void NetworkWriter::PushSendToCall(const std::vector<uint8_t>& msg,
const SockAddr& addr) { const SockAddr& addr) {
// Avoid buffer-full errors if something is causing us to write too often; // Avoid buffer-full errors if something is causing us to write too often;
// these are unreliable messages so its ok to just drop them. // these are unreliable messages so its ok to just drop them.
if (!thread()->CheckPushSafety()) { if (!thread()->CheckPushSafety()) {

View File

@ -10,10 +10,10 @@
namespace ballistica { namespace ballistica {
// A subsystem handling outbound network traffic. // A subsystem handling outbound network traffic.
class NetworkWriteModule { class NetworkWriter {
public: public:
void PushSendToCall(const std::vector<uint8_t>& msg, const SockAddr& addr); void PushSendToCall(const std::vector<uint8_t>& msg, const SockAddr& addr);
explicit NetworkWriteModule(Thread* thread); explicit NetworkWriter(Thread* thread);
auto thread() const -> Thread* { return thread_; } auto thread() const -> Thread* { return thread_; }
private: private:

View File

@ -17,12 +17,7 @@ struct Networking::ScanResultsEntryPriv {
millisecs_t last_contact_time{}; millisecs_t last_contact_time{};
}; };
Networking::Networking() { Networking::Networking() {}
assert(InLogicThread());
Resume();
}
Networking::~Networking() = default;
// Note: for now we're making our host-scan network calls directly from the game // Note: for now we're making our host-scan network calls directly from the game
// thread. This is generally not a good idea since it appears that even in // thread. This is generally not a good idea since it appears that even in
@ -232,7 +227,9 @@ void Networking::EndHostScanning() {
} }
void Networking::Pause() { void Networking::Pause() {
if (!running_) Log("Networking::pause() called with running_ already false"); if (!running_) {
Log("Networking::pause() called with running_ already false");
}
running_ = false; running_ = false;
// Game is going into background or whatnot. Kill any sockets/etc. // Game is going into background or whatnot. Kill any sockets/etc.

View File

@ -120,7 +120,6 @@ class Networking {
// will do this there. // will do this there.
static void SendTo(const std::vector<uint8_t>& buffer, const SockAddr& addr); static void SendTo(const std::vector<uint8_t>& buffer, const SockAddr& addr);
Networking(); Networking();
~Networking();
// Run a cycle of host scanning (basically sending out a broadcast packet to // Run a cycle of host scanning (basically sending out a broadcast packet to
// see who's out there). // see who's out there).
@ -147,7 +146,7 @@ class Networking {
std::mutex scan_results_mutex_; std::mutex scan_results_mutex_;
uint32_t next_scan_query_id_{}; uint32_t next_scan_query_id_{};
int scan_socket_{-1}; int scan_socket_{-1};
bool running_{}; bool running_{true};
}; };
} // namespace ballistica } // namespace ballistica

View File

@ -657,26 +657,31 @@ auto Platform::CreateAppFlavor() -> AppFlavor* {
SDLApp::InitSDL(); SDLApp::InitSDL();
#endif #endif
AppFlavor* app_flavor{};
#if BA_HEADLESS_BUILD #if BA_HEADLESS_BUILD
return new AppFlavorHeadless(g_main_thread); app_flavor = new AppFlavorHeadless(g_main_thread);
#elif BA_RIFT_BUILD #elif BA_RIFT_BUILD
// Rift build can spin up in either VR or regular mode. // Rift build can spin up in either VR or regular mode.
if (g_app->vr_mode) { if (g_app->vr_mode) {
return new AppFlavorVR(g_main_thread); app_flavor = new AppFlavorVR(g_main_thread);
} else { } else {
return new SDLApp(g_main_thread); app_flavor = new SDLApp(g_main_thread);
} }
#elif BA_CARDBOARD_BUILD #elif BA_CARDBOARD_BUILD
return new AppFlavorVR(g_main_thread); app_flavor = new AppFlavorVR(g_main_thread);
#elif BA_SDL_BUILD #elif BA_SDL_BUILD
return new SDLApp(g_main_thread); app_flavor = new SDLApp(g_main_thread);
#else #else
return new AppFlavor(g_main_thread); app_flavor = new AppFlavor(g_main_thread);
#endif #endif
assert(app_flavor);
app_flavor->PostInit();
return app_flavor;
} }
auto Platform::CreateGraphics() -> Graphics* { auto Platform::CreateGraphics() -> Graphics* {
assert(InLogicThread());
#if BA_VR_BUILD #if BA_VR_BUILD
return new VRGraphics(); return new VRGraphics();
#else #else

View File

@ -27,25 +27,19 @@ UI::UI() {
// Allow overriding via an environment variable. // Allow overriding via an environment variable.
auto* ui_override = getenv("BA_UI_SCALE"); auto* ui_override = getenv("BA_UI_SCALE");
bool force_test_small{};
bool force_test_medium{};
bool force_test_large{};
if (ui_override) { if (ui_override) {
if (ui_override == std::string("small")) { if (ui_override == std::string("small")) {
force_test_small = true; scale_ = UIScale::kSmall;
force_scale_ = true;
} else if (ui_override == std::string("medium")) { } else if (ui_override == std::string("medium")) {
force_test_medium = true; scale_ = UIScale::kMedium;
force_scale_ = true;
} else if (ui_override == std::string("large")) { } else if (ui_override == std::string("large")) {
force_test_large = true; scale_ = UIScale::kLarge;
force_scale_ = true;
} }
} }
if (force_test_small) { if (!force_scale_) {
scale_ = UIScale::kSmall;
} else if (force_test_medium) {
scale_ = UIScale::kMedium;
} else if (force_test_large) {
scale_ = UIScale::kLarge;
} else {
// Use automatic val. // Use automatic val.
if (g_buildconfig.iircade_build()) { // NOLINT(bugprone-branch-clone) if (g_buildconfig.iircade_build()) { // NOLINT(bugprone-branch-clone)
scale_ = UIScale::kMedium; scale_ = UIScale::kMedium;
@ -56,17 +50,24 @@ UI::UI() {
scale_ = g_platform->GetUIScale(); scale_ = g_platform->GetUIScale();
} }
} }
}
auto UI::LogicThreadInit() -> void {
root_ui_ = new RootUI();
// Make sure we know when forced-ui-scale is enabled. // Make sure we know when forced-ui-scale is enabled.
if (force_test_small) { if (force_scale_) {
ScreenMessage("FORCING SMALL UI FOR TESTING", Vector3f(1, 0, 0)); if (scale_ == UIScale::kSmall) {
Log("FORCING SMALL UI FOR TESTING"); ScreenMessage("FORCING SMALL UI FOR TESTING", Vector3f(1, 0, 0));
} else if (force_test_medium) { Log("FORCING SMALL UI FOR TESTING");
ScreenMessage("FORCING MEDIUM UI FOR TESTING", Vector3f(1, 0, 0)); } else if (scale_ == UIScale::kMedium) {
Log("FORCING MEDIUM UI FOR TESTING"); ScreenMessage("FORCING MEDIUM UI FOR TESTING", Vector3f(1, 0, 0));
} else if (force_test_large) { Log("FORCING MEDIUM UI FOR TESTING");
ScreenMessage("FORCING LARGE UI FOR TESTING", Vector3f(1, 0, 0)); } else if (scale_ == UIScale::kLarge) {
Log("FORCING LARGE UI FOR TESTING"); ScreenMessage("FORCING LARGE UI FOR TESTING", Vector3f(1, 0, 0));
Log("FORCING LARGE UI FOR TESTING");
} else {
FatalError("Unhandled scale.");
}
} }
step_scene_timer_ = step_scene_timer_ =
@ -75,8 +76,6 @@ UI::UI() {
scene_ = Object::New<Scene>(0); scene_ = Object::New<Scene>(0);
} }
auto UI::PostInit() -> void { root_ui_ = new RootUI(); }
// Currently the UI never dies so we don't bother doing a clean tear-down.. // Currently the UI never dies so we don't bother doing a clean tear-down..
// (verifying scene cleanup, etc) // (verifying scene cleanup, etc)
UI::~UI() { UI::~UI() {

View File

@ -31,7 +31,7 @@ namespace ballistica {
class UI : public ContextTarget { class UI : public ContextTarget {
public: public:
UI(); UI();
auto PostInit() -> void; auto LogicThreadInit() -> void;
~UI() override; ~UI() override;
auto Reset() -> void; auto Reset() -> void;
@ -142,6 +142,7 @@ class UI : public ContextTarget {
Object::Ref<RootWidget> root_widget_; Object::Ref<RootWidget> root_widget_;
int ui_lock_count_{}; int ui_lock_count_{};
UIScale scale_{UIScale::kLarge}; UIScale scale_{UIScale::kLarge};
bool force_scale_{};
// Media loaded in the UI context. // Media loaded in the UI context.
std::unordered_map<std::string, Object::WeakRef<Texture> > textures_; std::unordered_map<std::string, Object::WeakRef<Texture> > textures_;