diff --git a/.efrocachemap b/.efrocachemap index 51825131..ab64890f 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4072,26 +4072,26 @@ "build/assets/workspace/ninjafightplug.py": "https://files.ballistica.net/cache/ba1/c5/09/4f10b8a21ba87aa5509cff7a164b", "build/assets/workspace/onslaughtplug.py": "https://files.ballistica.net/cache/ba1/ff/0a/a354984f9c074dab0676ac7e4877", "build/assets/workspace/runaroundplug.py": "https://files.ballistica.net/cache/ba1/2a/1c/9ee5db6d1bceca7fa6638fb8abde", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/9f/12/dae21a272aa0490de4567396de08", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/32/47/00ce97ea67f3639ee7a771c6364f", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/5c/75/16320db2a3bc92aabc01774ba4a1", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/d9/d6/0c254158599c0ba16c04520fb166", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/a1/7b/c9f2464256b5a1f5b46434dc944f", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/2b/ed/20a3b2e758b13110f4598552a467", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/42/ed/4dc2182180b24456edfff90697bc", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/77/8d/f44567ba8706d7a94fe7a10df3eb", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/d8/1f/8bf54c800a593b2a9db9073ed725", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/2d/0c/f89b8327489807b1b82e60d4bfe3", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/b1/ea/71c07dd8b8e1ee4c85c382b6d0c0", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/e4/ca/dfbdf1d55e747f1d4f6a20aef6f0", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/fb/08/305603820ba3f4f1340e8f6657eb", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/5e/19/f4e1ea7efb3aff04066390ade2c7", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/51/4d/d89c3f77f367cc868f83c54cb998", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/4b/0d/1e39c12729c254a30cb7edf355fa", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/1a/de/2fbebe44216e2157b1567e6201ad", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/fc/54/235af99d68d4ea786fa321881f83", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/de/8c/310f113d163d61314e46dfe30823", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/ff/2a/168303f44d5a9f95c35c4dd6403b", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/15/71/e723ff71fedf612f16498328a88d", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/b1/85/72e1668f3fc83880d3b2cdd13eda", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/9f/ea/eb543f13d334795928c155ec5418", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/2c/71/282f5d50668cf03b19a29c253b5b", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/09/e5/70db8646250b8f71527cfe6ce97f", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/63/c8/7552cc275c155749b458459b7e58", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/9a/37/591ec108626a719a2215277b0545", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/1e/66/b7257262a232e79a6b32b6ea42ab", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/d4/ae/94c28c59b20609bbbac29bd791b8", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/23/24/ad58c6a3447820d40c8747bcec63", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/28/fe/81188330558d8b4ffd25f12ef6f2", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/8f/0c/ffededdcd18532e60480359080fc", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/3f/09/dbc27549fbe3bf4a3c732151ab1c", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/12/1e/e9d0d18da4e271f0a8392847ca70", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/84/dd/6616ec89f341981b05c89fff477c", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/72/5f/f715d301c98b23cdec2ef959b137", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/de/7a/8a28d18207cf2dbffb0f4f7f441c", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/84/27/37b074ebd6e625cf6c9b3c18ec2e", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/0e/04/857263b3f061813a73bf9b850f8b", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/a0/8e/97a3105073f32a4fdc665bc5eba2", "build/prefab/lib/linux_arm64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/d4/6a/dd303a200b98a56ba3b100277057", "build/prefab/lib/linux_arm64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/fc/2c/2996c558fb408a548fdd37398c9a", "build/prefab/lib/linux_arm64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/ed/28/b7a72be7ae1bd2b58dda4b6902a0", @@ -4108,14 +4108,14 @@ "build/prefab/lib/mac_x86_64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/71/f6/691482915ad58ea1e953cc23d74c", "build/prefab/lib/mac_x86_64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/b8/2b/6ec8c78980a62e3e0ee4b36ece04", "build/prefab/lib/mac_x86_64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/4e/56/a95c987b2a371759896b037fea86", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/fb/c1/c0b83862890aab10b24b3c39fcf7", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/9f/f8/b2c717e67ecf30e337ba7f8968aa", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/45/02/4e159c2a17f244afddb5eafbce1f", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/30/69/041ab1c77ccd5d7740046ece931a", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/d8/35/3c8a170d5a046e694d64b605d741", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/e7/0f/39d461f8f3832c1105711b965a8c", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/6c/b7/fa45a53f280f7fff6fbf4d9d7dcf", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/97/14/e30f320294f6363ecc0b7fcf2ff8", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/2d/55/0b7f8677e535082c9224259aa9d7", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/63/2f/b4b402d2f3a47dad74a077db036c", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/b6/e4/fffa1b46696ecc804b5a66896359", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/ca/70/e5eec4f437e387d61ceba7f9fffe", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/47/8c/0142dfbee4871619a8d404898eef", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/f8/d9/9facb83ac8c0ef39c97c3211ebd2", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/4d/90/79a005d72aa7a4277d06571dcdb5", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/ff/3a/e319ce586b9cb93ac29282569184", "src/assets/ba_data/python/babase/_mgen/__init__.py": "https://files.ballistica.net/cache/ba1/52/c6/c11130af7b10d6c0321add5518fa", "src/assets/ba_data/python/babase/_mgen/enums.py": "https://files.ballistica.net/cache/ba1/38/c3/1dedd5e74f2508efc5974c8815a1", "src/ballistica/base/mgen/pyembed/binding_base.inc": "https://files.ballistica.net/cache/ba1/d5/4a/0e480a855ce83709bd7f6761107d", diff --git a/CHANGELOG.md b/CHANGELOG.md index cf98f4b1..512e4909 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.20 (build 21037, api 8, 2023-06-01) +### 1.7.20 (build 21038, api 8, 2023-06-02) - This seems like a good time for a `refactoring` release in anticipation of changes coming in 1.8. Basically this means that a lot of things will be diff --git a/src/assets/ba_data/python/babase/_app.py b/src/assets/ba_data/python/babase/_app.py index 86b35f3a..80ee5077 100644 --- a/src/assets/ba_data/python/babase/_app.py +++ b/src/assets/ba_data/python/babase/_app.py @@ -423,7 +423,10 @@ class App: # one, switch. # pylint: disable=unidiomatic-typecheck if type(mode) is not type(self._mode): - if self._mode is not None: + if self._mode is None: + is_initial_mode = True + else: + is_initial_mode = False try: self._mode.on_deactivate() except Exception: @@ -437,6 +440,9 @@ class App: # Hmm; what should we do in this case?... logging.exception('Error activating app-mode %s.', mode) + if is_initial_mode: + _babase.on_initial_app_mode_set() + try: mode.handle_intent(intent) except Exception: @@ -520,6 +526,9 @@ class App: """Called when initially entering the running state.""" assert _babase.in_logic_thread() + # Let the native layer know. + _babase.on_app_running() + # Set a default app-mode-selector. Plugins can then override # this if they want. self.mode_selector = self.DefaultAppModeSelector() @@ -527,7 +536,7 @@ class App: self.plugins.on_app_running() # If 'exec' code was provided to the app, always kick that off - # here. + # here as an intent. exec_cmd = _babase.exec_arg() if exec_cmd is not None: self.set_intent(AppIntentExec(exec_cmd)) diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 00639272..a7c8b2f0 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -30,7 +30,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 21037 +TARGET_BALLISTICA_BUILD = 21038 TARGET_BALLISTICA_VERSION = '1.7.20' _g_env_config: EnvConfig | None = None diff --git a/src/ballistica/base/app/app.cc b/src/ballistica/base/app/app.cc index 835b0447..ac9aec2a 100644 --- a/src/ballistica/base/app/app.cc +++ b/src/ballistica/base/app/app.cc @@ -11,6 +11,8 @@ #include "ballistica/base/networking/network_reader.h" #include "ballistica/base/networking/networking.h" #include "ballistica/base/platform/base_platform.h" +#include "ballistica/base/support/stdio_console.h" +#include "ballistica/base/ui/console.h" #include "ballistica/base/ui/ui.h" #include "ballistica/shared/foundation/event_loop.h" #include "ballistica/shared/python/python.h" @@ -50,6 +52,24 @@ void App::LogicThreadApplyAppConfig() { void App::LogicThreadStepDisplayTime() { assert(g_base->InLogicThread()); } +void App::LogicThreadOnAppRunning() { + assert(g_base && g_base->InLogicThread()); +} + +void App::LogicThreadOnInitialAppModeSet() { + assert(g_core && g_base && g_base->InLogicThread()); + + // We want any sort of raw Python input to only start accepting commands + // once we've got an initial app-mode set. Generally said commands will + // assume we're running in that mode and will fail if run before it is set. + if (auto* console = g_base->console()) { + console->EnableInput(); + } + if (g_base->stdio_console) { + g_base->stdio_console->Start(); + } +} + auto App::ManagesEventLoop() const -> bool { // We have 2 redundant values for essentially the same thing; // should get rid of IsEventPushMode() once we've created diff --git a/src/ballistica/base/app/app.h b/src/ballistica/base/app/app.h index cea2ca1d..a478fc2e 100644 --- a/src/ballistica/base/app/app.h +++ b/src/ballistica/base/app/app.h @@ -126,6 +126,9 @@ class App { auto event_loop() const -> EventLoop* { return event_loop_; } void LogicThreadShutdownComplete(); + void LogicThreadOnAppRunning(); + void LogicThreadOnInitialAppModeSet(); + private: void UpdatePauseResume(); void OnAppPause(); diff --git a/src/ballistica/base/base.cc b/src/ballistica/base/base.cc index ad400a9e..5aa7ecf1 100644 --- a/src/ballistica/base/base.cc +++ b/src/ballistica/base/base.cc @@ -179,9 +179,6 @@ void BaseFeatureSet::StartApp() { assets_server->OnMainThreadStartApp(); g_core->platform->OnMainThreadStartApp(); // FIXME SHOULD NOT NEED THIS app->OnMainThreadStartApp(); - if (stdio_console) { - stdio_console->OnMainThreadStartApp(); - } // Take note that we're now 'running'. Various code such as anything that // pushes messages to threads can watch for this state to avoid crashing @@ -209,7 +206,27 @@ void BaseFeatureSet::LogVersionInfo() { void BaseFeatureSet::set_app_mode(AppMode* mode) { assert(InLogicThread()); - app_mode_ = mode; + if (mode == app_mode_) { + Log(LogLevel::kWarning, + "set_app_mode called with already-current app-mode; unexpected."); + } + try { + // Tear down previous mode (if any). + if (app_mode_) { + // Nothing here yet. + } + + // Set and build up new one. + app_mode_ = mode; + + // App modes each provide their own input-device delegate types. + input->RebuildInputDeviceDelegates(); + } catch (const Exception& exc) { + // Anything going wrong while switching app-modes leaves us in an + // undefined state; don't try to continue. + FatalError(std::string("Error setting native layer app-mode: ") + + exc.what()); + } } auto BaseFeatureSet::AppManagesEventLoop() -> bool { diff --git a/src/ballistica/base/input/input.cc b/src/ballistica/base/input/input.cc index 8ca75965..69d2eaf5 100644 --- a/src/ballistica/base/input/input.cc +++ b/src/ballistica/base/input/input.cc @@ -260,6 +260,18 @@ void Input::PushAddInputDeviceCall(InputDevice* input_device, }); } +void Input::RebuildInputDeviceDelegates() { + assert(g_base->InLogicThread()); + for (auto&& device_ref : input_devices_) { + if (auto* device = device_ref.Get()) { + auto delegate = Object::CompleteDeferred( + g_base->app_mode()->CreateInputDeviceDelegate(device)); + device->set_delegate(delegate); + delegate->set_input_device(device); + } + } +} + void Input::AddInputDevice(InputDevice* device, bool standard_message) { assert(g_base->InLogicThread()); @@ -1018,24 +1030,16 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) { case SDLK_ESCAPE: - if (g_base && g_base->ui->screen_root_widget() - && g_base->ui->root_widget() && g_base->ui->overlay_root_widget()) { - // If there's no dialogs/windows up, ask for a menu owned by the - // keyboard. - if (!g_base->ui->MainMenuVisible()) { - if (keyboard_input_) { - g_base->ui->PushMainMenuPressCall(keyboard_input_); - } - } else { - // Ok there's a UI up.. send along a cancel message. - if (g_base->ui->overlay_root_widget()->HasChildren()) { - g_base->ui->overlay_root_widget()->HandleMessage( - WidgetMessage(WidgetMessage::Type::kCancel)); - } else if (g_base->ui->root_widget()->HasChildren()) { - g_base->ui->root_widget()->HandleMessage( - WidgetMessage(WidgetMessage::Type::kCancel)); - } - } + if (!g_base->ui->MainMenuVisible()) { + // There's no main menu up. Ask for one. + + // Note: keyboard_input_ may be nullptr but escape key should still + // function for menus; it just won't claim ownership. + g_base->ui->PushMainMenuPressCall(keyboard_input_); + } else { + // Ok there *is* a main menu up. Send it a cancel message. + g_base->ui->root_widget()->HandleMessage( + WidgetMessage(WidgetMessage::Type::kCancel)); } handled = true; break; diff --git a/src/ballistica/base/input/input.h b/src/ballistica/base/input/input.h index 38b9cc82..4e265cd2 100644 --- a/src/ballistica/base/input/input.h +++ b/src/ballistica/base/input/input.h @@ -148,6 +148,7 @@ class Input { void CaptureJoystickInput(HandleJoystickEventCall* call); void ReleaseJoystickInput(); + void RebuildInputDeviceDelegates(); private: void UpdateInputDeviceCounts(); diff --git a/src/ballistica/base/python/methods/python_methods_app.cc b/src/ballistica/base/python/methods/python_methods_app.cc index 80d0df3b..4b07d0a6 100644 --- a/src/ballistica/base/python/methods/python_methods_app.cc +++ b/src/ballistica/base/python/methods/python_methods_app.cc @@ -1265,6 +1265,46 @@ static PyMethodDef PyExecArgDef = { "(internal)\n", }; +// ----------------------------- on_app_running -------------------------------- + +static auto PyOnAppRunning(PyObject* self) -> PyObject* { + BA_PYTHON_TRY; + BA_PRECONDITION(g_base && g_base->InLogicThread()); + g_base->app->LogicThreadOnAppRunning(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +static PyMethodDef PyOnAppRunningDef = { + "on_app_running", // name + (PyCFunction)PyOnAppRunning, // method + METH_NOARGS, // flags + + "on_app_running() -> None\n" + "\n" + "(internal)\n", +}; + +// ------------------------ on_initial_app_mode_set ---------------------------- + +static auto PyOnInitialAppModeSet(PyObject* self) -> PyObject* { + BA_PYTHON_TRY; + BA_PRECONDITION(g_base && g_base->InLogicThread()); + g_base->app->LogicThreadOnInitialAppModeSet(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +static PyMethodDef PyOnInitialAppModeSetDef = { + "on_initial_app_mode_set", // name + (PyCFunction)PyOnInitialAppModeSet, // method + METH_NOARGS, // flags + + "on_initial_app_mode_set() -> None\n" + "\n" + "(internal)\n", +}; + // ----------------------------------------------------------------------------- auto PythonMethodsApp::GetMethods() -> std::vector { @@ -1304,6 +1344,8 @@ auto PythonMethodsApp::GetMethods() -> std::vector { PyIsOSPlayingMusicDef, PyLifecycleLogDef, PyExecArgDef, + PyOnAppRunningDef, + PyOnInitialAppModeSetDef, }; } diff --git a/src/ballistica/base/support/stdio_console.cc b/src/ballistica/base/support/stdio_console.cc index 7c84d6e8..cb517419 100644 --- a/src/ballistica/base/support/stdio_console.cc +++ b/src/ballistica/base/support/stdio_console.cc @@ -17,8 +17,17 @@ namespace ballistica::base { StdioConsole::StdioConsole() = default; -void StdioConsole::OnMainThreadStartApp() { - // Ok, we're spinning up an app. +void StdioConsole::Start() { + if (auto* loop = g_core->main_event_loop()) { + loop->PushCall([this] { StartInMainThread(); }); + } else { + Log(LogLevel::kError, + "StdioConsole::Start() called before main_event_loop available."); + } +} + +void StdioConsole::StartInMainThread() { + assert(g_core && g_core->InMainThread()); // Spin up our thread. event_loop_ = new EventLoop(EventLoopID::kStdin); diff --git a/src/ballistica/base/support/stdio_console.h b/src/ballistica/base/support/stdio_console.h index 35e8e806..f2ca1f37 100644 --- a/src/ballistica/base/support/stdio_console.h +++ b/src/ballistica/base/support/stdio_console.h @@ -10,10 +10,11 @@ namespace ballistica::base { class StdioConsole { public: StdioConsole(); - void OnMainThreadStartApp(); + void Start(); auto event_loop() const -> EventLoop* { return event_loop_; } private: + void StartInMainThread(); void PushCommand(const std::string& command); EventLoop* event_loop_{}; std::string pending_input_; diff --git a/src/ballistica/base/ui/console.cc b/src/ballistica/base/ui/console.cc index 45b2ddcb..3c8ec0e1 100644 --- a/src/ballistica/base/ui/console.cc +++ b/src/ballistica/base/ui/console.cc @@ -110,6 +110,12 @@ auto Console::HandleKeyPress(const SDL_Keysym* keysym) -> bool { } case SDLK_KP_ENTER: case SDLK_RETURN: { + if (!input_enabled_) { + Log(LogLevel::kWarning, + "Console input is not allowed until the app reaches the 'running' " + "state."); + break; + } input_history_position_ = 0; if (input_string_ == "clear") { last_line_.clear(); @@ -118,7 +124,9 @@ auto Console::HandleKeyPress(const SDL_Keysym* keysym) -> bool { PushCommand(input_string_); } input_history_.push_front(input_string_); - if (input_history_.size() > 100) input_history_.pop_back(); + if (input_history_.size() > 100) { + input_history_.pop_back(); + } input_string_.resize(0); input_text_dirty_ = true; break; @@ -164,6 +172,11 @@ void Console::PushCommand(const std::string& command) { }); } +void Console::EnableInput() { + assert(g_base->InLogicThread()); + input_enabled_ = true; +} + void Console::ToggleState() { assert(g_base->InLogicThread()); switch (state_) { diff --git a/src/ballistica/base/ui/console.h b/src/ballistica/base/ui/console.h index 3b3332d7..a437b56c 100644 --- a/src/ballistica/base/ui/console.h +++ b/src/ballistica/base/ui/console.h @@ -24,6 +24,7 @@ class Console { void ToggleState(); void Print(const std::string& s_in); void Draw(RenderPass* pass); + void EnableInput(); private: void PushCommand(const std::string& command); @@ -58,6 +59,7 @@ class Console { Object::Ref s_mesh_; }; + bool input_enabled_{}; std::string input_string_; std::list input_history_; int input_history_position_{}; diff --git a/src/ballistica/scene_v1/python/methods/python_methods_input.cc b/src/ballistica/scene_v1/python/methods/python_methods_input.cc index 9e989fc1..fd0c6058 100644 --- a/src/ballistica/scene_v1/python/methods/python_methods_input.cc +++ b/src/ballistica/scene_v1/python/methods/python_methods_input.cc @@ -224,7 +224,10 @@ static auto PyGetUIInputDevice(PyObject* self, PyObject* args, PyObject* keywds) } else { // Perhaps will want to return None in this case once we've got // newer versions of InputDevice; we'll see... - throw Exception("Unexpected input-device type owns the UI."); + throw Exception( + "Unexpected delegate " + + (delegate ? delegate->GetObjectDescription() : "(nullptr)") + + " for ui-input-device " + d->GetObjectDescription() + "."); } } else { Py_RETURN_NONE; @@ -270,7 +273,10 @@ static auto PyGetInputDevice(PyObject* self, PyObject* args, PyObject* keywds) } else { // Perhaps will want to return None in this case once we've got // newer versions of InputDevice; we'll see... - throw Exception("Unexpected input-device type owns the UI."); + throw Exception( + "Unexpected delegate " + + (delegate ? delegate->GetObjectDescription() : "(nullptr)") + + " for input device " + d->GetObjectDescription() + "."); } } else { if (doraise) { diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index e2f957b5..d51236bc 100644 --- a/src/ballistica/shared/ballistica.cc +++ b/src/ballistica/shared/ballistica.cc @@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int { namespace ballistica { // These are set automatically via script; don't modify them here. -const int kEngineBuildNumber = 21037; +const int kEngineBuildNumber = 21038; const char* kEngineVersion = "1.7.20"; auto MonolithicMain(const core::CoreConfig& core_config) -> int { diff --git a/src/ballistica/ui_v1/ui_v1.cc b/src/ballistica/ui_v1/ui_v1.cc index 71bf39c9..d7ce10ab 100644 --- a/src/ballistica/ui_v1/ui_v1.cc +++ b/src/ballistica/ui_v1/ui_v1.cc @@ -75,6 +75,8 @@ void UIV1FeatureSet::DoQuitWindow() { RootUI* UIV1FeatureSet::NewRootUI() { return new RootUI(); } bool UIV1FeatureSet::MainMenuVisible() { + // We consider anything on our screen or overlay stacks to be a 'main menu'. + // Probably need a better name than 'main menu' though. auto* screen_root = g_base->ui->screen_root_widget(); auto* overlay_root = g_base->ui->overlay_root_widget(); return ((screen_root && screen_root->HasChildren())