From 014a996933d3f7d3e32328ce4654697eb0c8b88a Mon Sep 17 00:00:00 2001 From: Eric Date: Sun, 11 Sep 2022 10:32:02 -0700 Subject: [PATCH] simplifying c++ bootstrapping --- .efrocachemap | 72 +++++++------- CHANGELOG.md | 3 +- assets/src/ba_data/python/ba/_bootstrap.py | 2 +- src/ballistica/app/app.h | 15 +-- src/ballistica/app/app_config.cc | 9 +- src/ballistica/app/app_config.h | 1 - src/ballistica/assets/assets.cc | 16 +-- src/ballistica/assets/assets_server.cc | 40 ++++++-- src/ballistica/assets/assets_server.h | 15 +-- src/ballistica/audio/audio.cc | 8 +- src/ballistica/audio/audio.h | 29 +++--- src/ballistica/audio/audio_server.cc | 98 +++++++++++-------- src/ballistica/audio/audio_server.h | 77 ++++++++------- src/ballistica/ballistica.cc | 46 +++++---- src/ballistica/ballistica.h | 2 +- src/ballistica/core/context.cc | 8 -- src/ballistica/core/context.h | 2 - src/ballistica/core/thread.cc | 8 +- src/ballistica/core/thread.h | 4 +- src/ballistica/core/types.h | 2 +- src/ballistica/game/game.cc | 32 ++---- src/ballistica/game/game.h | 2 +- src/ballistica/game/host_activity.h | 18 ++-- src/ballistica/game/player.h | 2 +- src/ballistica/game/player_spec.h | 2 +- src/ballistica/game/session/client_session.h | 8 +- src/ballistica/graphics/graphics_server.cc | 5 +- src/ballistica/graphics/graphics_server.h | 23 +++-- src/ballistica/graphics/text/text_graphics.cc | 6 -- src/ballistica/graphics/text/text_graphics.h | 2 - src/ballistica/input/input.cc | 14 +-- src/ballistica/input/input.h | 1 - src/ballistica/networking/network_writer.cc | 6 +- src/ballistica/networking/network_writer.h | 4 +- src/ballistica/networking/networking.cc | 11 +-- src/ballistica/networking/networking.h | 3 +- src/ballistica/platform/platform.cc | 19 ++-- src/ballistica/ui/ui.cc | 47 +++++---- src/ballistica/ui/ui.h | 3 +- 39 files changed, 319 insertions(+), 346 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 64defef2..a8d83350 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -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/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", - "build/prefab/full/linux_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c7/7c/11757954adb7da34c0e8cb6a6470", - "build/prefab/full/linux_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/30/4e/361603ee5faf75168ddefd070b44", - "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/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1e/fe/0f73516a00159f6cd4b4791f010d", - "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/release/ballisticacore": "https://files.ballistica.net/cache/ba1/60/0d/772009d20e18def687f6b76021f8", - "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/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ab/71/616a553794306a406be45697895c", - "build/prefab/full/mac_arm64_gui/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/41/14/bae7db8e7361d538096253c36792", - "build/prefab/full/mac_arm64_gui/release/ballisticacore": "https://files.ballistica.net/cache/ba1/91/5f/d2bfb2b30befdae9270a119d51b5", - "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/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/49/64/5943868e08758fc103e8ce70f334", - "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/release/ballisticacore": "https://files.ballistica.net/cache/ba1/22/a9/75669c9a475fc8080ce422ce2baa", - "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/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a4/1b/9a6145a32ef40fd3b8357cfbfb30", - "build/prefab/full/windows_x86_gui/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/6a/a5/5afd24a1043a652af8ae76ec33ea", - "build/prefab/full/windows_x86_gui/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/dd/3a/71c400bbac9edc5fa7b63e099ae7", - "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/release/dist/BallisticaCoreHeadless.exe": "https://files.ballistica.net/cache/ba1/43/25/36e8e8fc1eac369727f9639bbcf9", - "build/prefab/lib/linux_arm64_gui/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e7/25/6fb628f1f5260834692bdeab63b0", + "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/c2/29/5c9ef7b0c3b068c700835f62abe6", + "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/62/3c/1b789be64fa12c6dd4609271c0b8", + "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/ce/e9/e578aecdd0146a4a242dacbef95d", + "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/d8/c0/74a187c3ebddec6313ea6385343d", + "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/7c/de/d2ceb7f9d52f78a33792395c4f2e", + "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/d5/0a/56f81ecbdc45218159edf9c08aeb", + "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/74/2e/c987767fca3cc4b5bb738e259b0a", + "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/b1/c0/46efd467c46e3ad8ed64d3893e1e", + "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/32/6d/9190219d7454f5cc2d75bcaa7084", + "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/9d/22/8e1aa2c9ac9c589985b7ff6d744f", + "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_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_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_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/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_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_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_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/windows/Debug_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/1b/93/23b7d341894fb875acaefe0804c5", - "build/prefab/lib/windows/Debug_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/86/e1/65b4096af71168842a99278708da", - "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/d8/91/3b918141edeaeb3034e558f54246", - "build/prefab/lib/windows/Debug_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/74/ff/12db4137ed498dbbffd892c5000f", - "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.lib": "https://files.ballistica.net/cache/ba1/41/0a/18695d2503c1062d7b2f47c88380", - "build/prefab/lib/windows/Release_Win32/BallisticaCoreGenericInternal.pdb": "https://files.ballistica.net/cache/ba1/2d/59/5bd72f8f691f041059cab3df99d5", - "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.lib": "https://files.ballistica.net/cache/ba1/3b/63/7eeb46b7832e1135e58345866abf", - "build/prefab/lib/windows/Release_Win32/BallisticaCoreHeadlessInternal.pdb": "https://files.ballistica.net/cache/ba1/89/e4/0b7890024077f73e328b20b543f5", + "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/80/76/3f3b0aa3ee0c39b276d55adf31f5", + "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/1c/c6/59922c32624d3a93be2080c1ff7d", + "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/7f/28/36b8586b6b139ccb052accc29d2b", + "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/74/9c/09e7f929fbcf075d41b976200950", "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" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 41ea3be9..f43b466d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. - Improved logging of missing playlist game types. - 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++ 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. +- Simplified C++ bootstrapping to allocate all globals in one place. ### 1.7.6 (build 20687, api 7, 2022-08-11) - Cleaned up da MetaSubsystem code. diff --git a/assets/src/ba_data/python/ba/_bootstrap.py b/assets/src/ba_data/python/ba/_bootstrap.py index 3b9fd900..f11dce98 100644 --- a/assets/src/ba_data/python/ba/_bootstrap.py +++ b/assets/src/ba_data/python/ba/_bootstrap.py @@ -38,7 +38,7 @@ def bootstrap() -> None: # Give a soft warning if we're being used with a different binary # version than we expect. - expected_build = 20809 + expected_build = 20821 running_build: int = env['build_number'] if running_build != expected_build: print( diff --git a/src/ballistica/app/app.h b/src/ballistica/app/app.h index c3d3546c..babeecd3 100644 --- a/src/ballistica/app/app.h +++ b/src/ballistica/app/app.h @@ -13,24 +13,15 @@ namespace ballistica { -// The first thing the engine does is allocate an instance of this as g_globals. -// 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. +// The first thing the engine does is allocate an instance of this as g_app. class App { public: 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{}; - - /// Program argument values (on applicable platforms). char** argv{}; - bool threads_paused{}; std::unordered_map node_types; std::unordered_map node_types_by_id; diff --git a/src/ballistica/app/app_config.cc b/src/ballistica/app/app_config.cc index b529ec9f..cf6f0b23 100644 --- a/src/ballistica/app/app_config.cc +++ b/src/ballistica/app/app_config.cc @@ -8,8 +8,6 @@ namespace ballistica { -void AppConfig::Init() { new AppConfig(); } - auto AppConfig::Entry::FloatValue() const -> float { throw Exception("not a float entry"); } @@ -137,12 +135,7 @@ class AppConfig::BoolEntry : public AppConfig::Entry { bool default_value_{}; }; -AppConfig::AppConfig() { - // (We're a singleton). - assert(g_app_config == nullptr); - g_app_config = this; - SetupEntries(); -} +AppConfig::AppConfig() { SetupEntries(); } // Clion think all calls of this are unreachable. #pragma clang diagnostic push diff --git a/src/ballistica/app/app_config.h b/src/ballistica/app/app_config.h index 6e3303e7..ed45fdc9 100644 --- a/src/ballistica/app/app_config.h +++ b/src/ballistica/app/app_config.h @@ -94,7 +94,6 @@ class AppConfig { std::string name_; }; - static void Init(); AppConfig(); // Given specific ids, returns resolved values (fastest access). diff --git a/src/ballistica/assets/assets.cc b/src/ballistica/assets/assets.cc index 190be948..734e59e3 100644 --- a/src/ballistica/assets/assets.cc +++ b/src/ballistica/assets/assets.cc @@ -607,20 +607,8 @@ void Assets::MarkComponentForLoad(AssetComponentData* c) { // once it makes it back to us we can delete the ref (in // ClearPendingLoadsDoneList) - auto asset_ptr = new Object::Ref(c); - - 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); - }); + auto asset_ref_ptr = new Object::Ref(c); + g_assets_server->PushPendingPreload(asset_ref_ptr); } #pragma clang diagnostic push diff --git a/src/ballistica/assets/assets_server.cc b/src/ballistica/assets/assets_server.cc index aba5b502..8cd61f89 100644 --- a/src/ballistica/assets/assets_server.cc +++ b/src/ballistica/assets/assets_server.cc @@ -12,21 +12,45 @@ namespace ballistica { -AssetsServer::AssetsServer(Thread* thread) - : thread_(thread), - writing_replay_(false), +AssetsServer::AssetsServer() + : writing_replay_(false), replay_message_bytes_(0), replays_broken_(false), replay_out_file_(nullptr) { + // We're a singleton; make sure we don't already exist. assert(g_assets_server == nullptr); - g_assets_server = this; - // get our thread to give us periodic processing time... - process_timer_ = this->thread()->NewTimer( - 1000, true, NewLambdaRunnable([this] { Process(); })); + // Spin up our thread. + thread_ = new Thread(ThreadIdentifier::kAssets); + 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* 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() { thread()->PushCall([this] { diff --git a/src/ballistica/assets/assets_server.h b/src/ballistica/assets/assets_server.h index 3c831129..f482b966 100644 --- a/src/ballistica/assets/assets_server.h +++ b/src/ballistica/assets/assets_server.h @@ -12,14 +12,17 @@ namespace ballistica { class AssetsServer { public: - explicit AssetsServer(Thread* thread); - ~AssetsServer(); - void PushBeginWriteReplayCall(); - void PushEndWriteReplayCall(); - void PushAddMessageToReplayCall(const std::vector& data); + AssetsServer(); + auto Start() -> void; + auto PushBeginWriteReplayCall() -> void; + auto PushEndWriteReplayCall() -> void; + auto PushAddMessageToReplayCall(const std::vector& data) -> void; + auto PushPendingPreload(Object::Ref* asset_ref_ptr) + -> void; auto thread() const -> Thread* { return thread_; } private: + auto StartInThread() -> void; void Process(); void WriteReplayMessages(); Thread* thread_{}; @@ -32,8 +35,6 @@ class AssetsServer { Timer* process_timer_{}; std::vector*> pending_preloads_; std::vector*> pending_preloads_audio_; - friend struct PreloadRunnable; - friend class Assets; }; } // namespace ballistica diff --git a/src/ballistica/audio/audio.cc b/src/ballistica/audio/audio.cc index 09f43eb5..8f4fef9a 100644 --- a/src/ballistica/audio/audio.cc +++ b/src/ballistica/audio/audio.cc @@ -9,13 +9,7 @@ namespace ballistica { -Audio::Audio() { assert(InLogicThread()); } - -void Audio::Init() { - // Init our singleton. - assert(g_audio == nullptr); - g_audio = new Audio(); -} +Audio::Audio() {} void Audio::Reset() { assert(InLogicThread()); diff --git a/src/ballistica/audio/audio.h b/src/ballistica/audio/audio.h index 3a0b40d0..1cc1f000 100644 --- a/src/ballistica/audio/audio.h +++ b/src/ballistica/audio/audio.h @@ -15,14 +15,15 @@ namespace ballistica { /// used by the game and/or other threads. class Audio { public: - static void Init(); - void Reset(); + Audio(); + 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); - void SetListenerOrientation(const Vector3f& forward, const Vector3f& up); - void SetSoundPitch(float pitch); + auto SetListenerPosition(const Vector3f& p) -> void; + auto SetListenerOrientation(const Vector3f& forward, const Vector3f& up) + -> void; + auto SetSoundPitch(float pitch) -> void; // 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 @@ -41,9 +42,9 @@ class Audio { auto IsSoundPlaying(uint32_t play_id) -> bool; // Simple one-shot play functions. - void PlaySound(SoundData* s, float volume = 1.0f); - void PlaySoundAtPosition(SoundData* sound, float volume, float x, float y, - float z); + auto PlaySound(SoundData* s, float volume = 1.0f) -> void; + auto PlaySoundAtPosition(SoundData* sound, float volume, float x, float y, + float z) -> void; // 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 @@ -51,19 +52,17 @@ class Audio { auto ShouldPlay(SoundData* s) -> bool; // Hmm; shouldn't these be accessed through the Source class? - void PushSourceFadeOutCall(uint32_t play_id, uint32_t time); - void PushSourceStopSoundCall(uint32_t play_id); + auto PushSourceFadeOutCall(uint32_t play_id, uint32_t time) -> void; + 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& { return available_sources_mutex_; } private: - Audio(); - // Flat list of client sources indexed by id. std::vector client_sources_; diff --git a/src/ballistica/audio/audio_server.cc b/src/ballistica/audio/audio_server.cc index 6282e89a..d162c1db 100644 --- a/src/ballistica/audio/audio_server.cc +++ b/src/ballistica/audio/audio_server.cc @@ -30,10 +30,10 @@ extern "C" void opensl_resume_playback(); extern std::string g_rift_audio_device_name; #endif -const int kAudioProcessIntervalNormal = 500; -const int kAudioProcessIntervalFade = 50; -const int kAudioProcessIntervalPendingLoad = 1; -const bool kShowInUseSounds = false; +const int kAudioProcessIntervalNormal{500}; +const int kAudioProcessIntervalFade{50}; +const int kAudioProcessIntervalPendingLoad{1}; +const bool kShowInUseSounds{}; int AudioServer::al_source_count_ = 0; @@ -55,7 +55,7 @@ class AudioServer::ThreadSource : public Object { // not be used. ThreadSource(AudioServer* audio_thread, int id, bool* valid); ~ThreadSource() override; - void Reset() { + auto Reset() -> void { SetIsMusic(false); SetPositional(true); SetPosition(0, 0, 0); @@ -66,18 +66,18 @@ class AudioServer::ThreadSource : public Object { /// Set whether a sound is "music". /// This influences which volume controls affect it. - void SetIsMusic(bool m); + auto SetIsMusic(bool m) -> void; /// Set whether a source is positional. /// A non-positional source's position coords are always relative to the /// listener - ie: 0, 0, 0 will always be centered. - void SetPositional(bool p); - void SetPosition(float x, float y, float z); - void SetGain(float g); - void SetFade(float f); - void SetLooping(bool loop); + auto SetPositional(bool p) -> void; + auto SetPosition(float x, float y, float z) -> void; + auto SetGain(float g) -> void; + auto SetFade(float f) -> void; + auto SetLooping(bool loop) -> void; auto Play(const Object::Ref* s) -> uint32_t; - void Stop(); + auto Stop() -> void; auto play_count() -> uint32_t { return play_count_; } auto is_streamed() const -> bool { return is_streamed_; } 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; } - void UpdatePitch(); - void UpdateVolume(); - void ExecStop(); - void ExecPlay(); - void Update(); + auto UpdatePitch() -> void; + auto UpdateVolume() -> void; + auto ExecStop() -> void; + auto ExecPlay() -> void; + auto Update() -> void; private: - bool looping_ = false; + bool looping_{}; std::unique_ptr client_source_; - float fade_ = 1.0f; - float gain_ = 1.0f; - AudioServer* audio_thread_; - bool valid_ = false; - const Object::Ref* source_sound_ = nullptr; - int id_; - uint32_t play_count_ = 0; - bool is_actually_playing_ = false; - bool want_to_play_ = false; + float fade_{1.0f}; + float gain_{1.0f}; + AudioServer* audio_thread_{}; + bool valid_{}; + const Object::Ref* source_sound_{}; + int id_{}; + uint32_t play_count_{}; + bool is_actually_playing_{}; + bool want_to_play_{}; #if BA_ENABLE_AUDIO - ALuint source_ = 0; + ALuint source_{}; #endif - bool is_streamed_ = false; + bool is_streamed_{}; /// Whether we should be designated as "music" next time we play. - bool is_music_ = false; + bool is_music_{}; /// Whether currently playing as music. - bool current_is_music_ = false; + bool current_is_music_{}; #if BA_ENABLE_AUDIO Object::Ref streamer_; @@ -321,24 +321,34 @@ void AudioServer::PushSetListenerOrientationCall(const Vector3f& forward, }); } -AudioServer::AudioServer(Thread* thread) - : thread_(thread), impl_{new AudioServer::Impl()} { - // we're a singleton... +AudioServer::AudioServer() : impl_{new AudioServer::Impl()} { + // We're a singleton; make sure we don't already exist. assert(g_audio_server == nullptr); - g_audio_server = this; - thread->AddPauseCallback(NewLambdaRunnableRaw([this] { OnThreadPause(); })); - thread->AddResumeCallback(NewLambdaRunnableRaw([this] { OnThreadResume(); })); + // Spin up our thread. + 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. - process_timer_ = thread->NewTimer(kAudioProcessIntervalNormal, true, - NewLambdaRunnable([this] { Process(); })); + process_timer_ = thread()->NewTimer(kAudioProcessIntervalNormal, true, + NewLambdaRunnable([this] { Process(); })); #if BA_ENABLE_AUDIO // 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 // device. @@ -363,7 +373,7 @@ AudioServer::AudioServer(Thread* thread) // These names seem to be things like "OpenAL Soft on FOO" // ..we should be able to search for FOO. if (strstr(device, g_rift_audio_device_name.c_str())) { - alDeviceName = device; + al_device_name = device; } len = strlen(device); device += (len + 1); @@ -376,7 +386,7 @@ AudioServer::AudioServer(Thread* thread) #endif // BA_RIFT_BUILD ALCdevice* device; - device = alcOpenDevice(alDeviceName); + device = alcOpenDevice(al_device_name); BA_PRECONDITION(device); impl_->alc_context_ = alcCreateContext(device, nullptr); BA_PRECONDITION(impl_->alc_context_); @@ -702,7 +712,9 @@ AudioServer::ThreadSource::ThreadSource(AudioServer* audio_thread_in, int id_in, CHECK_AL_ERROR; } *valid_out = valid_; - if (valid_) al_source_count_++; + if (valid_) { + al_source_count_++; + } #endif // BA_ENABLE_AUDIO } diff --git a/src/ballistica/audio/audio_server.h b/src/ballistica/audio/audio_server.h index 75abe5b0..da180dcc 100644 --- a/src/ballistica/audio/audio_server.h +++ b/src/ballistica/audio/audio_server.h @@ -22,45 +22,47 @@ class AudioServer { return play_id >> 16u; } - explicit AudioServer(Thread* o); + AudioServer(); + auto Start() -> void; - void PushSetVolumesCall(float music_volume, float sound_volume); - void PushSetSoundPitchCall(float val); - void PushSetPausedCall(bool pause); + auto PushSetVolumesCall(float music_volume, float sound_volume) -> void; + auto PushSetSoundPitchCall(float val) -> void; + auto PushSetPausedCall(bool pause) -> void; - static void BeginInterruption(); - static void EndInterruption(); + static auto BeginInterruption() -> void; + static auto EndInterruption() -> void; - void PushSetListenerPositionCall(const Vector3f& p); - void PushSetListenerOrientationCall(const Vector3f& forward, - const Vector3f& up); - void PushResetCall(); - void PushHavePendingLoadsCall(); - void PushComponentUnloadCall( - const std::vector*>& components); + auto PushSetListenerPositionCall(const Vector3f& p) -> void; + auto PushSetListenerOrientationCall(const Vector3f& forward, + const Vector3f& up) -> void; + auto PushResetCall() -> void; + auto PushHavePendingLoadsCall() -> void; + auto PushComponentUnloadCall( + const std::vector*>& components) -> void; /// For use by g_game_module(). - void ClearSoundRefDeleteList(); + auto ClearSoundRefDeleteList() -> void; auto paused() const -> bool { return paused_; } // Client sources use these to pass settings to the server. - void PushSourceSetIsMusicCall(uint32_t play_id, bool val); - void PushSourceSetPositionalCall(uint32_t play_id, bool val); - void PushSourceSetPositionCall(uint32_t play_id, const Vector3f& p); - void PushSourceSetGainCall(uint32_t play_id, float val); - void PushSourceSetFadeCall(uint32_t play_id, float val); - void PushSourceSetLoopingCall(uint32_t play_id, bool val); - void PushSourcePlayCall(uint32_t play_id, Object::Ref* sound); - void PushSourceStopCall(uint32_t play_id); - void PushSourceEndCall(uint32_t play_id); + auto PushSourceSetIsMusicCall(uint32_t play_id, bool val) -> void; + auto PushSourceSetPositionalCall(uint32_t play_id, bool val) -> void; + auto PushSourceSetPositionCall(uint32_t play_id, const Vector3f& p) -> void; + auto PushSourceSetGainCall(uint32_t play_id, float val) -> void; + auto PushSourceSetFadeCall(uint32_t play_id, float val) -> void; + auto PushSourceSetLoopingCall(uint32_t play_id, bool val) -> void; + auto PushSourcePlayCall(uint32_t play_id, Object::Ref* sound) + -> void; + 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 // 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. - void StopSound(uint32_t play_id); + auto StopSound(uint32_t play_id) -> void; auto thread() const -> Thread* { return thread_; } @@ -68,16 +70,17 @@ class AudioServer { class ThreadSource; struct Impl; + auto StartInThread() -> void; ~AudioServer(); auto OnThreadPause() -> void; auto OnThreadResume() -> void; - void SetPaused(bool paused); + auto SetPaused(bool paused) -> void; - void SetMusicVolume(float volume); - void SetSoundVolume(float volume); - void SetSoundPitch(float pitch); + auto SetMusicVolume(float volume) -> void; + auto SetSoundVolume(float volume) -> void; + auto SetSoundPitch(float pitch) -> void; auto music_volume() -> float { return music_volume_; } auto sound_volume() -> float { return sound_volume_; } auto sound_pitch() -> float { return sound_pitch_; } @@ -85,22 +88,22 @@ class AudioServer { /// If a sound play id is currently playing, return the sound. auto GetPlayingSound(uint32_t play_id) -> ThreadSource*; - void Reset(); - void Process(); + auto Reset() -> void; + auto Process() -> void; /// Send a component to the audio thread to delete. - void DeleteAssetComponent(AssetComponentData* c); + auto DeleteAssetComponent(AssetComponentData* c) -> void; - void UpdateTimerInterval(); - void UpdateAvailableSources(); - void UpdateMusicPlayState(); - void ProcessSoundFades(); + auto UpdateTimerInterval() -> void; + auto UpdateAvailableSources() -> void; + auto UpdateMusicPlayState() -> void; + auto ProcessSoundFades() -> void; // Some threads such as audio hold onto allocated Media-Component-Refs to keep // 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 // this function. - void AddSoundRefDelete(const Object::Ref* c); + auto AddSoundRefDelete(const Object::Ref* c) -> void; // 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. diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index 57429cf6..3a7053c9 100644 --- a/src/ballistica/ballistica.cc +++ b/src/ballistica/ballistica.cc @@ -4,26 +4,33 @@ #include +#include "ballistica/app/app_config.h" #include "ballistica/app/app_flavor.h" #include "ballistica/assets/assets.h" #include "ballistica/assets/assets_server.h" +#include "ballistica/audio/audio.h" #include "ballistica/audio/audio_server.h" +#include "ballistica/core/context.h" #include "ballistica/core/fatal_error.h" #include "ballistica/core/logging.h" #include "ballistica/core/thread.h" #include "ballistica/dynamics/bg/bg_dynamics_server.h" #include "ballistica/game/v1_account.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/networking/network_writer.h" +#include "ballistica/networking/networking.h" #include "ballistica/platform/platform.h" #include "ballistica/python/python.h" #include "ballistica/scene/scene.h" +#include "ballistica/ui/ui.h" namespace ballistica { // 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"; // Our standalone globals. @@ -40,6 +47,7 @@ Audio* g_audio{}; AudioServer* g_audio_server{}; BGDynamics* g_bg_dynamics{}; BGDynamicsServer* g_bg_dynamics_server{}; +Context* g_context{}; Game* g_game{}; Graphics* g_graphics{}; GraphicsServer* g_graphics_server{}; @@ -49,7 +57,7 @@ Assets* g_assets{}; AssetsServer* g_assets_server{}; NetworkReader* g_network_reader{}; Networking* g_networking{}; -NetworkWriteModule* g_network_writer{}; +NetworkWriter* g_network_writer{}; Platform* g_platform{}; Python* g_python{}; 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 // g_platform for locating OS-specific paths). - assert(g_python == nullptr); g_python = new Python(); // Create a Thread wrapper around the current (main) thread. g_main_thread = new Thread(ThreadIdentifier::kMain, ThreadType::kMain); 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->PostInit(); + g_graphics = g_platform->CreateGraphics(); // 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_utils = new Utils(); g_assets = new Assets(); + g_assets_server = new AssetsServer(); + g_ui = Object::NewUnmanaged(); + g_networking = new Networking(); + g_input = new Input(); + g_app_internal = GetAppInternal(); Scene::Init(); // 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)}; g_app->pausable_threads.push_back(logic_thread); 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. logic_thread->PushCallSynchronous( [logic_thread] { new Game(logic_thread); }); - network_write_thread->PushCallSynchronous([network_write_thread] { - new NetworkWriteModule(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); }); + network_write_thread->PushCallSynchronous( + [network_write_thread] { new NetworkWriter(network_write_thread); }); // Now let the platform spin up any other threads/modules it uses. // (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. // ------------------------------------------------------------------------- + g_audio_server->Start(); + g_assets_server->Start(); + // Let the app and platform do whatever else it wants here such as adding // initial input devices/etc. g_app_flavor->OnBootstrapComplete(); diff --git a/src/ballistica/ballistica.h b/src/ballistica/ballistica.h index 163a5fcf..de4226af 100644 --- a/src/ballistica/ballistica.h +++ b/src/ballistica/ballistica.h @@ -122,7 +122,7 @@ extern Assets* g_assets; extern AssetsServer* g_assets_server; extern Networking* g_networking; extern NetworkReader* g_network_reader; -extern NetworkWriteModule* g_network_writer; +extern NetworkWriter* g_network_writer; extern Platform* g_platform; extern Python* g_python; extern StdInputModule* g_std_input_module; diff --git a/src/ballistica/core/context.cc b/src/ballistica/core/context.cc index d21d96fe..6b6da3fb 100644 --- a/src/ballistica/core/context.cc +++ b/src/ballistica/core/context.cc @@ -8,14 +8,6 @@ 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; diff --git a/src/ballistica/core/context.h b/src/ballistica/core/context.h index abd8a61e..68b0d101 100644 --- a/src/ballistica/core/context.h +++ b/src/ballistica/core/context.h @@ -14,8 +14,6 @@ namespace ballistica { // effects properly apply to the place they came from. class Context { public: - static void Init(); - static auto current() -> const Context& { assert(g_context); diff --git a/src/ballistica/core/thread.cc b/src/ballistica/core/thread.cc index e23d1213..fe7e1650 100644 --- a/src/ballistica/core/thread.cc +++ b/src/ballistica/core/thread.cc @@ -84,7 +84,7 @@ void Thread::WaitForNextEvent(bool single_cycle) { } // While we're waiting, allow other python threads to run. - if (owns_python_) { + if (holds_python_gil_) { g_python->ReleaseGIL(); } @@ -117,7 +117,7 @@ void Thread::WaitForNextEvent(bool single_cycle) { } } - if (owns_python_) { + if (holds_python_gil_) { g_python->AcquireGIL(); } } @@ -357,8 +357,8 @@ auto Thread::ThreadMain() -> int { } } -void Thread::SetOwnsPython() { - owns_python_ = true; +void Thread::SetHoldsPythonGIL() { + holds_python_gil_ = true; g_python->AcquireGIL(); } diff --git a/src/ballistica/core/thread.h b/src/ballistica/core/thread.h index cfc2f0d4..63cfe5f3 100644 --- a/src/ballistica/core/thread.h +++ b/src/ballistica/core/thread.h @@ -44,7 +44,7 @@ class Thread { // Used to quit the main thread. void Quit(); - void SetOwnsPython(); + void SetHoldsPythonGIL(); void SetPaused(bool paused); auto thread_id() const -> std::thread::id { return thread_id_; } @@ -137,7 +137,7 @@ class Thread { std::thread::id thread_id_{}; ThreadIdentifier identifier_{ThreadIdentifier::kInvalid}; millisecs_t last_complaint_time_{}; - bool owns_python_{}; + bool holds_python_gil_{}; // FIXME: Should generalize this to some sort of PlatformThreadData class. #if BA_XCODE_BUILD diff --git a/src/ballistica/core/types.h b/src/ballistica/core/types.h index fcc3ad19..f9ba491e 100644 --- a/src/ballistica/core/types.h +++ b/src/ballistica/core/types.h @@ -123,7 +123,7 @@ class NetClientThread; class NetGraph; class Networking; class NetworkReader; -class NetworkWriteModule; +class NetworkWriter; class Node; class NodeType; class NodeAttribute; diff --git a/src/ballistica/game/game.cc b/src/ballistica/game/game.cc index b2c57cab..db06dd04 100644 --- a/src/ballistica/game/game.cc +++ b/src/ballistica/game/game.cc @@ -73,45 +73,27 @@ Game::Game(Thread* thread) g_game = this; try { - // Spin up some other game-thread-based stuff. - AppConfig::Init(); - assert(g_graphics == nullptr); - g_graphics = g_platform->CreateGraphics(); - TextGraphics::Init(); - Audio::Init(); + // Our thread should hold the Python GIL by default. + // TODO(ericf): It could be better to have each individual Python call + // we make acquire the GIL. Then we're not holding it during long + // bits of C++ logic. + thread->SetHoldsPythonGIL(); + if (!HeadlessMode()) { BGDynamics::Init(); } InitSpecialChars(); - Context::Init(); - // We want to be informed when our thread is pausing. thread->AddPauseCallback(NewLambdaRunnableRaw([this] { OnThreadPause(); })); - // Waaah does UI need to be a bs::Object? - // 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(); - g_ui->PostInit(); - - assert(g_networking == nullptr); - g_networking = new Networking(); - - assert(g_input == nullptr); - g_input = new Input(); - - g_app_internal = GetAppInternal(); + g_ui->LogicThreadInit(); // Init python and apply our settings immediately. // This way we can get started loading stuff in the background // and it'll come in with the correct texture quality etc. 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) { // If anything went wrong, trigger a deferred error. // This way it is more likely we can show a fatal error dialog diff --git a/src/ballistica/game/game.h b/src/ballistica/game/game.h index 5c4cbf7d..5c9e8a87 100644 --- a/src/ballistica/game/game.h +++ b/src/ballistica/game/game.h @@ -324,7 +324,7 @@ class Game { int last_kick_votes_needed_{-1}; Object::WeakRef kick_vote_starter_; Object::WeakRef 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_max_size_{8}; int public_party_player_count_{0}; diff --git a/src/ballistica/game/host_activity.h b/src/ballistica/game/host_activity.h index c42edeb2..d87ad6c1 100644 --- a/src/ballistica/game/host_activity.h +++ b/src/ballistica/game/host_activity.h @@ -87,8 +87,8 @@ class HostActivity : public ContextTarget { auto StepScene() -> void; Object::WeakRef globals_node_; - bool allow_kick_idle_players_ = false; - Timer* step_scene_timer_ = nullptr; + bool allow_kick_idle_players_{}; + Timer* step_scene_timer_{}; std::unordered_map > textures_; std::unordered_map > sounds_; std::unordered_map > datas_; @@ -96,18 +96,18 @@ class HostActivity : public ContextTarget { collide_models_; std::unordered_map > models_; std::list > materials_; - bool shutting_down_ = false; + bool shutting_down_{}; // 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 // that point. std::list > python_calls_; - millisecs_t next_prune_time_ = 0; - bool _started = false; - int out_of_bounds_in_a_row_ = 0; - bool paused_ = false; - float game_speed_ = 0.0f; - millisecs_t base_time_ = 0; + millisecs_t next_prune_time_{}; + bool _started{}; + int out_of_bounds_in_a_row_{}; + bool paused_{}; + float game_speed_{}; + millisecs_t base_time_{}; Object::Ref scene_; Object::WeakRef host_session_; PythonRef py_activity_weak_ref_; diff --git a/src/ballistica/game/player.h b/src/ballistica/game/player.h index 1d416764..d501cda2 100644 --- a/src/ballistica/game/player.h +++ b/src/ballistica/game/player.h @@ -147,7 +147,7 @@ class Player : public Object { // Player's position for use by input devices and whatnot for guides. // 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}; // These should be destructed before the rest of our class goes down, diff --git a/src/ballistica/game/player_spec.h b/src/ballistica/game/player_spec.h index a93af89b..c9d5d225 100644 --- a/src/ballistica/game/player_spec.h +++ b/src/ballistica/game/player_spec.h @@ -16,7 +16,7 @@ namespace ballistica { /// should not know or care about V2 accounts. class PlayerSpec { public: - /// Init an invalid player-spec + /// Create an invalid player-spec. PlayerSpec(); auto operator==(const PlayerSpec& spec) const -> bool; diff --git a/src/ballistica/game/session/client_session.h b/src/ballistica/game/session/client_session.h index 4779a269..e696c707 100644 --- a/src/ballistica/game/session/client_session.h +++ b/src/ballistica/game/session/client_session.h @@ -85,8 +85,8 @@ class ClientSession : public Session { virtual auto OnReset(bool rewind) -> void; virtual auto FetchMessages() -> void {} virtual void Error(const std::string& description); - void End(); - void DumpFullState(SceneStream* out) override; + auto End() -> void; + auto DumpFullState(SceneStream* out) -> void override; /// Reset target base time to equal current. This can be used during command /// 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_; } private: - void ClearSessionObjs(); - void AddCommand(const std::vector& command); + auto ClearSessionObjs() -> void; + auto AddCommand(const std::vector& command) -> void; auto ReadByte() -> uint8_t; auto ReadInt32() -> int32_t; diff --git a/src/ballistica/graphics/graphics_server.cc b/src/ballistica/graphics/graphics_server.cc index 8af8e73f..81dcdc78 100644 --- a/src/ballistica/graphics/graphics_server.cc +++ b/src/ballistica/graphics/graphics_server.cc @@ -30,10 +30,9 @@ void GraphicsServer::FullscreenCheck() { } #endif -GraphicsServer::GraphicsServer(Thread* thread) : thread_(thread) { - // We're a singleton. +GraphicsServer::GraphicsServer() : thread_(g_main_thread) { + // We're a singleton; make sure we don't already exist. assert(g_graphics_server == nullptr); - g_graphics_server = this; // For janky old non-event-push mode, just fall back on a timer for rendering. if (!g_platform->IsEventPushMode()) { diff --git a/src/ballistica/graphics/graphics_server.h b/src/ballistica/graphics/graphics_server.h index 53edecfa..aaa590fa 100644 --- a/src/ballistica/graphics/graphics_server.h +++ b/src/ballistica/graphics/graphics_server.h @@ -18,7 +18,7 @@ namespace ballistica { // Graphics class GraphicsServer { public: - explicit GraphicsServer(Thread* thread); + GraphicsServer(); auto PushSetScreenGammaCall(float gamma) -> void; auto PushSetScreenPixelScaleCall(float pixel_scale) -> void; auto PushSetVSyncCall(bool sync, bool auto_sync) -> void; @@ -61,18 +61,22 @@ class GraphicsServer { // init the modelview matrix to look here auto SetCamera(const Vector3f& eye, const Vector3f& target, const Vector3f& up) -> void; + auto SetOrthoProjection(float left, float right, float bottom, float top, float near, float far) -> void; + auto ModelViewReset() -> void { model_view_matrix_ = kMatrix44fIdentity; model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true; model_view_stack_.clear(); } + auto SetProjectionMatrix(const Matrix44f& p) -> void { projection_matrix_ = p; model_view_projection_matrix_dirty_ = true; projection_matrix_state_++; } + auto projection_matrix_state() -> uint32_t { return projection_matrix_state_; } @@ -85,9 +89,11 @@ class GraphicsServer { light_shadow_projection_matrix_state_++; } } + auto light_shadow_projection_matrix_state() const -> uint32_t { return light_shadow_projection_matrix_state_; } + auto light_shadow_projection_matrix() const -> const Matrix44f& { return light_shadow_projection_matrix_; } @@ -270,6 +276,13 @@ class GraphicsServer { 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 std::unique_ptr gl_context_; #endif @@ -291,7 +304,6 @@ class GraphicsServer { bool fullscreen_enabled_{}; float target_res_x_{800.0f}; float target_res_y_{600.0f}; - Matrix44f model_view_matrix_{kMatrix44fIdentity}; Matrix44f view_world_matrix_{kMatrix44fIdentity}; Matrix44f projection_matrix_{kMatrix44fIdentity}; @@ -314,18 +326,11 @@ class GraphicsServer { std::list mesh_datas_; bool v_sync_{}; 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_{}; Renderer* renderer_{}; FrameDef* frame_def_{}; bool initial_screen_created_{}; int render_hold_{}; -#if BA_OSTYPE_MACOS && BA_XCODE_BUILD - void FullscreenCheck(); -#endif }; } // namespace ballistica diff --git a/src/ballistica/graphics/text/text_graphics.cc b/src/ballistica/graphics/text/text_graphics.cc index fb8de9fb..c0153431 100644 --- a/src/ballistica/graphics/text/text_graphics.cc +++ b/src/ballistica/graphics/text/text_graphics.cc @@ -19,12 +19,6 @@ class TextGraphics::TextSpanBoundsCacheEntry : public Object { std::list>::iterator list_iterator_; }; -void TextGraphics::Init() { - assert(InLogicThread()); - assert(g_text_graphics == nullptr); - g_text_graphics = new TextGraphics(); -} - TextGraphics::TextGraphics() { // Init glyph values for our custom font pages // (just a 5x5 array currently). diff --git a/src/ballistica/graphics/text/text_graphics.h b/src/ballistica/graphics/text/text_graphics.h index b041f2e2..e0ff8bda 100644 --- a/src/ballistica/graphics/text/text_graphics.h +++ b/src/ballistica/graphics/text/text_graphics.h @@ -22,8 +22,6 @@ const float kTextRowHeight = 32.0f; // Encapsulates text-display functionality used by the game thread. class TextGraphics { public: - static void Init(); - TextGraphics(); enum class FontPage { diff --git a/src/ballistica/input/input.cc b/src/ballistica/input/input.cc index 7d3d166d..5ddd187f 100644 --- a/src/ballistica/input/input.cc +++ b/src/ballistica/input/input.cc @@ -318,17 +318,7 @@ static const char* const scancode_names[SDL_NUM_SCANCODES] = { }; #endif // BA_SDL2_BUILD || BA_MINSDL_BUILD -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(); -} +Input::Input() {} void Input::PushCreateKeyboardInputDevices() { g_game->thread()->PushCall([this] { CreateKeyboardInputDevices(); }); @@ -362,8 +352,6 @@ void Input::DestroyKeyboardInputDevices() { keyboard_input_2_ = nullptr; } -Input::~Input() = default; - auto Input::GetInputDevice(int id) -> InputDevice* { if (id < 0 || id >= static_cast(input_devices_.size())) { return nullptr; diff --git a/src/ballistica/input/input.h b/src/ballistica/input/input.h index b2750784..6c02956e 100644 --- a/src/ballistica/input/input.h +++ b/src/ballistica/input/input.h @@ -18,7 +18,6 @@ namespace ballistica { class Input { public: Input(); - virtual ~Input(); // Add an input device. Must be called from the game thread; otherwise use // PushAddInputDeviceCall. diff --git a/src/ballistica/networking/network_writer.cc b/src/ballistica/networking/network_writer.cc index c6a1a269..b2473812 100644 --- a/src/ballistica/networking/network_writer.cc +++ b/src/ballistica/networking/network_writer.cc @@ -8,14 +8,14 @@ namespace ballistica { -NetworkWriteModule::NetworkWriteModule(Thread* thread) : thread_(thread) { +NetworkWriter::NetworkWriter(Thread* thread) : thread_(thread) { // we're a singleton assert(g_network_writer == nullptr); g_network_writer = this; } -void NetworkWriteModule::PushSendToCall(const std::vector& msg, - const SockAddr& addr) { +void NetworkWriter::PushSendToCall(const std::vector& msg, + const SockAddr& addr) { // Avoid buffer-full errors if something is causing us to write too often; // these are unreliable messages so its ok to just drop them. if (!thread()->CheckPushSafety()) { diff --git a/src/ballistica/networking/network_writer.h b/src/ballistica/networking/network_writer.h index 1c8235c6..e88b2ac1 100644 --- a/src/ballistica/networking/network_writer.h +++ b/src/ballistica/networking/network_writer.h @@ -10,10 +10,10 @@ namespace ballistica { // A subsystem handling outbound network traffic. -class NetworkWriteModule { +class NetworkWriter { public: void PushSendToCall(const std::vector& msg, const SockAddr& addr); - explicit NetworkWriteModule(Thread* thread); + explicit NetworkWriter(Thread* thread); auto thread() const -> Thread* { return thread_; } private: diff --git a/src/ballistica/networking/networking.cc b/src/ballistica/networking/networking.cc index 14304ecd..1cfbcbf0 100644 --- a/src/ballistica/networking/networking.cc +++ b/src/ballistica/networking/networking.cc @@ -17,12 +17,7 @@ struct Networking::ScanResultsEntryPriv { millisecs_t last_contact_time{}; }; -Networking::Networking() { - assert(InLogicThread()); - Resume(); -} - -Networking::~Networking() = default; +Networking::Networking() {} // 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 @@ -232,7 +227,9 @@ void Networking::EndHostScanning() { } 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; // Game is going into background or whatnot. Kill any sockets/etc. diff --git a/src/ballistica/networking/networking.h b/src/ballistica/networking/networking.h index 430c6198..76f6766e 100644 --- a/src/ballistica/networking/networking.h +++ b/src/ballistica/networking/networking.h @@ -120,7 +120,6 @@ class Networking { // will do this there. static void SendTo(const std::vector& buffer, const SockAddr& addr); Networking(); - ~Networking(); // Run a cycle of host scanning (basically sending out a broadcast packet to // see who's out there). @@ -147,7 +146,7 @@ class Networking { std::mutex scan_results_mutex_; uint32_t next_scan_query_id_{}; int scan_socket_{-1}; - bool running_{}; + bool running_{true}; }; } // namespace ballistica diff --git a/src/ballistica/platform/platform.cc b/src/ballistica/platform/platform.cc index 45b3855f..6af72aa1 100644 --- a/src/ballistica/platform/platform.cc +++ b/src/ballistica/platform/platform.cc @@ -657,26 +657,31 @@ auto Platform::CreateAppFlavor() -> AppFlavor* { SDLApp::InitSDL(); #endif + AppFlavor* app_flavor{}; + #if BA_HEADLESS_BUILD - return new AppFlavorHeadless(g_main_thread); + app_flavor = new AppFlavorHeadless(g_main_thread); #elif BA_RIFT_BUILD // Rift build can spin up in either VR or regular mode. if (g_app->vr_mode) { - return new AppFlavorVR(g_main_thread); + app_flavor = new AppFlavorVR(g_main_thread); } else { - return new SDLApp(g_main_thread); + app_flavor = new SDLApp(g_main_thread); } #elif BA_CARDBOARD_BUILD - return new AppFlavorVR(g_main_thread); + app_flavor = new AppFlavorVR(g_main_thread); #elif BA_SDL_BUILD - return new SDLApp(g_main_thread); + app_flavor = new SDLApp(g_main_thread); #else - return new AppFlavor(g_main_thread); + app_flavor = new AppFlavor(g_main_thread); #endif + + assert(app_flavor); + app_flavor->PostInit(); + return app_flavor; } auto Platform::CreateGraphics() -> Graphics* { - assert(InLogicThread()); #if BA_VR_BUILD return new VRGraphics(); #else diff --git a/src/ballistica/ui/ui.cc b/src/ballistica/ui/ui.cc index d0cf6d51..9389eb9a 100644 --- a/src/ballistica/ui/ui.cc +++ b/src/ballistica/ui/ui.cc @@ -27,25 +27,19 @@ UI::UI() { // Allow overriding via an environment variable. 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 == std::string("small")) { - force_test_small = true; + scale_ = UIScale::kSmall; + force_scale_ = true; } else if (ui_override == std::string("medium")) { - force_test_medium = true; + scale_ = UIScale::kMedium; + force_scale_ = true; } else if (ui_override == std::string("large")) { - force_test_large = true; + scale_ = UIScale::kLarge; + force_scale_ = true; } } - if (force_test_small) { - scale_ = UIScale::kSmall; - } else if (force_test_medium) { - scale_ = UIScale::kMedium; - } else if (force_test_large) { - scale_ = UIScale::kLarge; - } else { + if (!force_scale_) { // Use automatic val. if (g_buildconfig.iircade_build()) { // NOLINT(bugprone-branch-clone) scale_ = UIScale::kMedium; @@ -56,17 +50,24 @@ UI::UI() { scale_ = g_platform->GetUIScale(); } } +} +auto UI::LogicThreadInit() -> void { + root_ui_ = new RootUI(); // Make sure we know when forced-ui-scale is enabled. - if (force_test_small) { - ScreenMessage("FORCING SMALL UI FOR TESTING", Vector3f(1, 0, 0)); - Log("FORCING SMALL UI FOR TESTING"); - } else if (force_test_medium) { - ScreenMessage("FORCING MEDIUM UI FOR TESTING", Vector3f(1, 0, 0)); - Log("FORCING MEDIUM UI FOR TESTING"); - } else if (force_test_large) { - ScreenMessage("FORCING LARGE UI FOR TESTING", Vector3f(1, 0, 0)); - Log("FORCING LARGE UI FOR TESTING"); + if (force_scale_) { + if (scale_ == UIScale::kSmall) { + ScreenMessage("FORCING SMALL UI FOR TESTING", Vector3f(1, 0, 0)); + Log("FORCING SMALL UI FOR TESTING"); + } else if (scale_ == UIScale::kMedium) { + ScreenMessage("FORCING MEDIUM UI FOR TESTING", Vector3f(1, 0, 0)); + Log("FORCING MEDIUM UI FOR TESTING"); + } else if (scale_ == UIScale::kLarge) { + ScreenMessage("FORCING LARGE UI FOR TESTING", Vector3f(1, 0, 0)); + Log("FORCING LARGE UI FOR TESTING"); + } else { + FatalError("Unhandled scale."); + } } step_scene_timer_ = @@ -75,8 +76,6 @@ UI::UI() { scene_ = Object::New(0); } -auto UI::PostInit() -> void { root_ui_ = new RootUI(); } - // Currently the UI never dies so we don't bother doing a clean tear-down.. // (verifying scene cleanup, etc) UI::~UI() { diff --git a/src/ballistica/ui/ui.h b/src/ballistica/ui/ui.h index f5f5e10a..08dd7228 100644 --- a/src/ballistica/ui/ui.h +++ b/src/ballistica/ui/ui.h @@ -31,7 +31,7 @@ namespace ballistica { class UI : public ContextTarget { public: UI(); - auto PostInit() -> void; + auto LogicThreadInit() -> void; ~UI() override; auto Reset() -> void; @@ -142,6 +142,7 @@ class UI : public ContextTarget { Object::Ref root_widget_; int ui_lock_count_{}; UIScale scale_{UIScale::kLarge}; + bool force_scale_{}; // Media loaded in the UI context. std::unordered_map > textures_;