app-mode related work and bug fixes

This commit is contained in:
Eric 2023-06-02 11:31:14 -07:00
parent 91a0653400
commit cba6986860
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
17 changed files with 190 additions and 61 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -148,6 +148,7 @@ class Input {
void CaptureJoystickInput(HandleJoystickEventCall* call);
void ReleaseJoystickInput();
void RebuildInputDeviceDelegates();
private:
void UpdateInputDeviceCounts();

View File

@ -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<PyMethodDef> {
@ -1304,6 +1344,8 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
PyIsOSPlayingMusicDef,
PyLifecycleLogDef,
PyExecArgDef,
PyOnAppRunningDef,
PyOnInitialAppModeSetDef,
};
}

View File

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

View File

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

View File

@ -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_) {

View File

@ -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<TextGroup> s_mesh_;
};
bool input_enabled_{};
std::string input_string_;
std::list<std::string> input_history_;
int input_history_position_{};

View File

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

View File

@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
namespace ballistica {
// These are set automatically via script; don't modify them here.
const int kEngineBuildNumber = 21037;
const int kEngineBuildNumber = 21038;
const char* kEngineVersion = "1.7.20";
auto MonolithicMain(const core::CoreConfig& core_config) -> int {

View File

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