From 1115983bcc6cef177bb241b8662cdeb68e4d7974 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 27 Oct 2023 15:58:10 -0700 Subject: [PATCH] various input and config cleanup --- .efrocachemap | 56 ++++++------- CHANGELOG.md | 18 ++++- src/assets/.asset_manifest_public.json | 2 - src/assets/Makefile | 2 - src/assets/ba_data/python/babase/_app.py | 16 +--- .../ba_data/python/babase/_appconfig.py | 41 ++-------- src/assets/ba_data/python/baclassic/_input.py | 9 ++- .../ba_data/python/baclassic/_subsystem.py | 9 --- src/assets/ba_data/python/baenv.py | 2 +- .../bascenev1lib/actor/controlsguide.py | 77 ++++++------------ .../ba_data/python/bauiv1lib/configerror.py | 80 ------------------- .../python/bauiv1lib/settings/gamepad.py | 73 ++++++++--------- .../bauiv1lib/settings/gamepadadvanced.py | 2 +- .../python/bauiv1lib/settings/keyboard.py | 8 +- .../base/input/device/joystick_input.cc | 7 +- .../base/input/device/joystick_input.h | 6 +- .../base/python/methods/python_methods_app.cc | 2 +- src/ballistica/base/ui/dev_console.cc | 8 +- src/ballistica/shared/ballistica.cc | 2 +- 19 files changed, 145 insertions(+), 275 deletions(-) delete mode 100644 src/assets/ba_data/python/bauiv1lib/configerror.py diff --git a/.efrocachemap b/.efrocachemap index f7d58d47..95a2a68d 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4056,26 +4056,26 @@ "build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "bd21ea70f4aace3ddd6e86d19ca04707", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "eb9196d69cb13de5c02f8f205396ac8d", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "20e1738da78d266882053a21ad74d2d4", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "f2a2815bbfcbeff6041ade83999132a6", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "21c30ed4e87963efa9bbb401903d9bdd", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "ee324f4377ffe3135f0ce6ad62609281", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "76046cdfbb2ee3a2906b230f347c4361", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "ef80af070e2fecda641469df8828375a", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "7ff933a5f3a8bac754897df4a3e3d723", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "c4d26e212c3c824e25cf5bbf27465f34", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "0ab3966d350a39c39a28fa7b93ef1d08", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "e76707372e761bfd1d3b1d56cb76b91f", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "f1581f72dbfe22cf7ba5be436e80a5a3", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "b52af8580dcd6cac224d840a043be2a4", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "3fb98c6e7c82b533441c437188bbd1ce", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "ba62c05d2486524a2eef989898a4e57f", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "e872cfeade334bf471ce71f536571ff3", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "d688622611dde4d4b3ef0e14f87d0931", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "81887892b133fdf6df2249f8b1265e50", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "9325a017d3382c6979afd0d597727c46", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "637b3e06d6536db39d816e0b5820c0ab", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "e3a0ad82944e80528a227807a9a9ba6d", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "f8252819a3d84a2c3be5e3ed938e5f8b", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "7e8682e4ef71b0d432576ce8f879b3b2", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "eb3a79d46714a2585da45f66ae5352eb", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "1ebb8b160059182d79b586f40f4bb207", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "b51ff49b8e145ebee0d5a3f8c2e517fb", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "9eecb06461e9798439c4d15399b7d28a", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "7ffd1e3961eb68f820ff044f2ba62cf9", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "3ab890f1e4116739bce0e2c141440773", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "d6d47b5b7bf720c0936a53deffe07359", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "0ce0fcd7d19e767db721eb43f58424f7", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "4fac89dcba67096cd2f84f0b687b1880", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "0df3b09ffdf3dc519cea1a3a9fb959d2", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "8eb92b2fa10d56cfee3fd8da179cfda7", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "b0764a6280bfbe926b655df8f946e8e2", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "f69383ecdafab7a37907898fcbf98fa1", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "617e7ca8f4ed3d3f726ba9567a15732e", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "9133fee71d08209b5ac82f772edae5c9", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "1cfd194e81bb849e337b34df43157ba8", "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "476e9cf1fb229a023babd799a6e535f1", "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "cf2a61fae8e8cd757864202a09e71255", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "476e9cf1fb229a023babd799a6e535f1", @@ -4092,14 +4092,14 @@ "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "1920c5412307a78aa658c3366c86b7fc", "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "b257bbc06d82fc912653806c01a42c15", "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "1920c5412307a78aa658c3366c86b7fc", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "7dbcf548c44407baad81a680bf08856e", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "14d512d2c10d74907653e102b5e86592", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "50865a4f46834954473d94ef217a2420", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "6ae64c31cdd77da2ef0c29e7131c9a0c", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "1791fd1babc070e7d6dfb9fe257fc8bf", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "801cb1351809a815f60decd90fe8877c", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "9652a72608a71583785bac7495a5397f", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "5072cccbd6c70f3a2183bd0242ba1f76", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "693493fea9a0068d67d05ac32c53d938", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "0ad9cd9671e260ea90f97a3334a063d0", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "0dc8f56e25b1bb2b67bdb6f1b65c56b6", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "02bfe33e3189d0993aff1884cae95ccf", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "7867875c532b032ace05fef64e278635", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "7dfdd479341808a7301158591caac092", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "3604c049578423bce477d0be543529f4", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "57b11043daad1545cd2abb0c13f43db7", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/enums.py": "28323912b56ec07701eda3d41a6a4101", "src/ballistica/base/mgen/pyembed/binding_base.inc": "6df0f34207346d89a72924249ddd4706", diff --git a/CHANGELOG.md b/CHANGELOG.md index 71a6bcdb..1a6d0354 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.28 (build 21525, api 8, 2023-10-27) +### 1.7.28 (build 21528, api 8, 2023-10-27) - Massively cleaned up code related to rendering and window systems (OpenGL, SDL, etc). This code had been growing into a nasty tangle for 15 years @@ -176,6 +176,22 @@ who never leave the party (Thanks EraOSBeta!). - Fixes an issue where servers could be crashed by flooding them with join requests (Thanks for the heads-up Era!). +- The engine will now ignore empty device config dicts and fall back to + defaults; these could theoretically happen if device config code fails + somewhere and it previously would leave the device mysteriously inoperable. +- The game will now show for controls with no bindings in the in-game + guide and controller/keyboard config screens. +- Fixed a crash that could occur if SDL couldn't find a name for connected + joystick. +- Simplified the app's handling of broken config files. Previously it would do + various complex things such as offering to edit the broken config on desktop + builds, avoiding overwriting broken configs, and automatically loading + previous configs. Now, if it finds a broken config, it will simply back it up + to a .broken file, log an error message, and then start up normally with a + default config. This way, things are more consistent across platforms, and + technical users can still fix and restore their old configs. Note that the app + still also writes .prev configs for extra security, though it no longer uses + them for anything itself. ### 1.7.27 (build 21282, api 8, 2023-08-30) diff --git a/src/assets/.asset_manifest_public.json b/src/assets/.asset_manifest_public.json index 9c4f56a5..4ff9c920 100644 --- a/src/assets/.asset_manifest_public.json +++ b/src/assets/.asset_manifest_public.json @@ -366,7 +366,6 @@ "ba_data/python/bauiv1lib/__pycache__/characterpicker.cpython-311.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/colorpicker.cpython-311.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/config.cpython-311.opt-1.pyc", - "ba_data/python/bauiv1lib/__pycache__/configerror.cpython-311.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/confirm.cpython-311.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/continues.cpython-311.opt-1.pyc", "ba_data/python/bauiv1lib/__pycache__/creditslist.cpython-311.opt-1.pyc", @@ -417,7 +416,6 @@ "ba_data/python/bauiv1lib/characterpicker.py", "ba_data/python/bauiv1lib/colorpicker.py", "ba_data/python/bauiv1lib/config.py", - "ba_data/python/bauiv1lib/configerror.py", "ba_data/python/bauiv1lib/confirm.py", "ba_data/python/bauiv1lib/continues.py", "ba_data/python/bauiv1lib/coop/__init__.py", diff --git a/src/assets/Makefile b/src/assets/Makefile index 5af7a60c..b801f3c5 100644 --- a/src/assets/Makefile +++ b/src/assets/Makefile @@ -341,7 +341,6 @@ SCRIPT_TARGETS_PY_PUBLIC = \ $(BUILD_DIR)/ba_data/python/bauiv1lib/characterpicker.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/colorpicker.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/config.py \ - $(BUILD_DIR)/ba_data/python/bauiv1lib/configerror.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/confirm.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/continues.py \ $(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__init__.py \ @@ -615,7 +614,6 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ $(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/characterpicker.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/colorpicker.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/config.cpython-311.opt-1.pyc \ - $(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/configerror.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/confirm.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/continues.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__pycache__/__init__.cpython-311.opt-1.pyc \ diff --git a/src/assets/ba_data/python/babase/_app.py b/src/assets/ba_data/python/babase/_app.py index c22aee9f..b014d677 100644 --- a/src/assets/ba_data/python/babase/_app.py +++ b/src/assets/ba_data/python/babase/_app.py @@ -184,7 +184,6 @@ class App: # foregrounded; can be a simple way to determine if network data # should be refreshed/etc. self.fg_state = 0 - self.config_file_healthy: bool = False self._subsystems: list[AppSubsystem] = [] self._native_bootstrapping_completed = False @@ -433,7 +432,7 @@ class App: """(internal)""" from babase._appconfig import read_app_config - self._config, self.config_file_healthy = read_app_config() + self._config = read_app_config() def handle_deep_link(self, url: str) -> None: """Handle a deep link URL.""" @@ -583,19 +582,6 @@ class App: self._aioloop = _asyncio.setup_asyncio() self.health_monitor = AppHealthMonitor() - # Only proceed if our config file is healthy so we don't - # overwrite a broken one or whatnot and wipe out data. - if not self.config_file_healthy: - if self.classic is not None: - handled = self.classic.show_config_error_window() - if handled: - return - - # For now on other systems we just overwrite the bum config. - # At this point settings are already set; lets just commit - # them to disk. - _appconfig.commit_app_config(force=True) - # __FEATURESET_APP_SUBSYSTEM_CREATE_BEGIN__ # This section generated by batools.appmodule; do not edit. diff --git a/src/assets/ba_data/python/babase/_appconfig.py b/src/assets/ba_data/python/babase/_appconfig.py index f34ff8ab..92efc73c 100644 --- a/src/assets/ba_data/python/babase/_appconfig.py +++ b/src/assets/ba_data/python/babase/_appconfig.py @@ -101,15 +101,13 @@ class AppConfig(dict): self.commit() -def read_app_config() -> tuple[AppConfig, bool]: +def read_app_config() -> AppConfig: """Read the app config.""" import os import json - config_file_healthy = False - - # NOTE: it is assumed that this only gets called once and the - # config object will not change from here on out + # NOTE: it is assumed that this only gets called once and the config + # object will not change from here on out config_file_path = _babase.app.env.config_file_path config_contents = '' try: @@ -119,20 +117,16 @@ def read_app_config() -> tuple[AppConfig, bool]: config = AppConfig(json.loads(config_contents)) else: config = AppConfig() - config_file_healthy = True except Exception: logging.exception( - "Error reading config file at time %.3f: '%s'.", + "Error reading config file '%s' at time %.3f.\n" + "Backing up broken config to'%s.broken'.", + config_file_path, _babase.apptime(), config_file_path, ) - # Whenever this happens lets back up the broken one just in case it - # gets overwritten accidentally. - logging.info( - "Backing up current config file to '%s.broken'", config_file_path - ) try: import shutil @@ -141,23 +135,10 @@ def read_app_config() -> tuple[AppConfig, bool]: logging.exception('Error copying broken config.') config = AppConfig() - # Now attempt to read one of our 'prev' backup copies. - prev_path = config_file_path + '.prev' - try: - if os.path.exists(prev_path): - with open(prev_path, encoding='utf-8') as infile: - config_contents = infile.read() - config = AppConfig(json.loads(config_contents)) - else: - config = AppConfig() - config_file_healthy = True - logging.info('Successfully read backup config.') - except Exception: - logging.exception('Error reading prev backup config.') - return config, config_file_healthy + return config -def commit_app_config(force: bool = False) -> None: +def commit_app_config() -> None: """Commit the config to persistent storage. Category: **General Utility Functions** @@ -167,10 +148,4 @@ def commit_app_config(force: bool = False) -> None: plus = _babase.app.plus assert plus is not None - if not _babase.app.config_file_healthy and not force: - logging.warning( - 'Current config file is broken; ' - 'skipping write to avoid losing settings.' - ) - return plus.mark_config_dirty() diff --git a/src/assets/ba_data/python/baclassic/_input.py b/src/assets/ba_data/python/baclassic/_input.py index e3cc0546..6d60b50a 100644 --- a/src/assets/ba_data/python/baclassic/_input.py +++ b/src/assets/ba_data/python/baclassic/_input.py @@ -40,7 +40,14 @@ def get_input_device_mapped_value( mapping = ccfgs[devicename][unique_id] elif 'default' in ccfgs[devicename]: mapping = ccfgs[devicename]['default'] - if mapping is not None: + + # We now use the config mapping *only* if it is not empty. + # There have been cases of config writing code messing up + # and leaving empty dicts in the app config, which currently + # leaves the device unusable. Alternatively, we'd perhaps + # want to fall back to defaults for individual missing + # values, but that is a bigger change we can make later. + if isinstance(mapping, dict) and mapping: return mapping.get(name, -1) if platform == 'windows': diff --git a/src/assets/ba_data/python/baclassic/_subsystem.py b/src/assets/ba_data/python/baclassic/_subsystem.py index 757661fc..f8aba3bc 100644 --- a/src/assets/ba_data/python/baclassic/_subsystem.py +++ b/src/assets/ba_data/python/baclassic/_subsystem.py @@ -627,15 +627,6 @@ class ClassicSubsystem(babase.AppSubsystem): """(internal)""" return bascenev1.get_foreground_host_activity() - def show_config_error_window(self) -> bool: - """(internal)""" - if self.platform in ('mac', 'linux', 'windows'): - from bauiv1lib.configerror import ConfigErrorWindow - - babase.pushcall(ConfigErrorWindow) - return True - return False - def value_test( self, arg: str, diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 1dd9e557..55329257 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -52,7 +52,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 21525 +TARGET_BALLISTICA_BUILD = 21528 TARGET_BALLISTICA_VERSION = '1.7.28' diff --git a/src/assets/ba_data/python/bascenev1lib/actor/controlsguide.py b/src/assets/ba_data/python/bascenev1lib/actor/controlsguide.py index 18854e5d..e29245b6 100644 --- a/src/assets/ba_data/python/bascenev1lib/actor/controlsguide.py +++ b/src/assets/ba_data/python/bascenev1lib/actor/controlsguide.py @@ -264,10 +264,19 @@ class ControlsGuide(bs.Actor): bs.timer(delay, bs.WeakCall(self._start_updating)) @staticmethod - def _meaningful_button_name(device: bs.InputDevice, button: int) -> str: + def _meaningful_button_name( + device: bs.InputDevice, button_name: str + ) -> str: """Return a flattened string button name; empty for non-meaningful.""" if not device.has_meaningful_button_names: return '' + assert bs.app.classic is not None + button = bs.app.classic.get_input_device_mapped_value( + device, button_name + ) + # -1 means unset; let's show that. + if button == -1: + return bs.Lstr(resource='configGamepadWindow.unsetText').evaluate() return device.get_button_name(button).evaluate() def _start_updating(self) -> None: @@ -289,10 +298,10 @@ class ControlsGuide(bs.Actor): def _check_fade_in(self) -> None: assert bs.app.classic is not None - # If we have a touchscreen, we only fade in if we have a player with - # an input device that is *not* the touchscreen. - # (otherwise it is confusing to see the touchscreen buttons right - # next to our display buttons) + # If we have a touchscreen, we only fade in if we have a player + # with an input device that is *not* the touchscreen. Otherwise + # it is confusing to see the touchscreen buttons right next to + # our display buttons. touchscreen: bs.InputDevice | None = bs.getinputdevice( 'TouchScreen', '#1', doraise=False ) @@ -318,15 +327,7 @@ class ControlsGuide(bs.Actor): 'buttonBomb', 'buttonPickUp', ): - if ( - self._meaningful_button_name( - device, - bs.app.classic.get_input_device_mapped_value( - device, name - ), - ) - != '' - ): + if self._meaningful_button_name(device, name) != '': fade_in = True break if fade_in: @@ -401,58 +402,30 @@ class ControlsGuide(bs.Actor): # We only care about movement buttons in the case of keyboards. if all_keyboards: right_button_names.add( - device.get_button_name( - classic.get_input_device_mapped_value( - device, 'buttonRight' - ) - ) + self._meaningful_button_name(device, 'buttonRight') ) left_button_names.add( - device.get_button_name( - classic.get_input_device_mapped_value( - device, 'buttonLeft' - ) - ) + self._meaningful_button_name(device, 'buttonLeft') ) down_button_names.add( - device.get_button_name( - classic.get_input_device_mapped_value( - device, 'buttonDown' - ) - ) + self._meaningful_button_name(device, 'buttonDown') ) up_button_names.add( - device.get_button_name( - classic.get_input_device_mapped_value( - device, 'buttonUp' - ) - ) + self._meaningful_button_name(device, 'buttonUp') ) # Ignore empty values; things like the remote app or # wiimotes can return these. - bname = self._meaningful_button_name( - device, - classic.get_input_device_mapped_value(device, 'buttonPunch'), - ) + bname = self._meaningful_button_name(device, 'buttonPunch') if bname != '': punch_button_names.add(bname) - bname = self._meaningful_button_name( - device, - classic.get_input_device_mapped_value(device, 'buttonJump'), - ) + bname = self._meaningful_button_name(device, 'buttonJump') if bname != '': jump_button_names.add(bname) - bname = self._meaningful_button_name( - device, - classic.get_input_device_mapped_value(device, 'buttonBomb'), - ) + bname = self._meaningful_button_name(device, 'buttonBomb') if bname != '': bomb_button_names.add(bname) - bname = self._meaningful_button_name( - device, - classic.get_input_device_mapped_value(device, 'buttonPickUp'), - ) + bname = self._meaningful_button_name(device, 'buttonPickUp') if bname != '': pickup_button_names.add(bname) @@ -582,8 +555,8 @@ class ControlsGuide(bs.Actor): if msg.immediate: self._die() else: - # If they don't need immediate, - # fade out our nodes and die later. + # If they don't need immediate, fade out our nodes and + # die later. for node in self._nodes: bs.animate(node, 'opacity', {0: node.opacity, 3.0: 0.0}) bs.timer(3.1, bs.WeakCall(self._die)) diff --git a/src/assets/ba_data/python/bauiv1lib/configerror.py b/src/assets/ba_data/python/bauiv1lib/configerror.py deleted file mode 100644 index c64a31d6..00000000 --- a/src/assets/ba_data/python/bauiv1lib/configerror.py +++ /dev/null @@ -1,80 +0,0 @@ -# Released under the MIT License. See LICENSE for details. -# -"""UI for dealing with broken config files.""" - -from __future__ import annotations - -import bauiv1 as bui - - -class ConfigErrorWindow(bui.Window): - """Window for dealing with a broken config.""" - - def __init__(self) -> None: - self._config_file_path = bui.app.env.config_file_path - width = 800 - super().__init__( - bui.containerwidget(size=(width, 400), transition='in_right') - ) - padding = 20 - bui.textwidget( - parent=self._root_widget, - position=(padding, 220 + 60), - size=(width - 2 * padding, 100 - 2 * padding), - h_align='center', - v_align='top', - scale=0.73, - text=( - f'Error reading {bui.appnameupper()} config file' - ':\n\n\nCheck the console' - ' (press ~ twice) for details.\n\nWould you like to quit and' - ' try to fix it by hand\nor overwrite it with defaults?\n\n' - '(high scores, player profiles, etc will be lost if you' - ' overwrite)' - ), - ) - bui.textwidget( - parent=self._root_widget, - position=(padding, 198 + 60), - size=(width - 2 * padding, 100 - 2 * padding), - h_align='center', - v_align='top', - scale=0.5, - text=self._config_file_path, - ) - quit_button = bui.buttonwidget( - parent=self._root_widget, - position=(35, 30), - size=(240, 54), - label='Quit and Edit', - on_activate_call=self._quit, - ) - bui.buttonwidget( - parent=self._root_widget, - position=(width - 370, 30), - size=(330, 54), - label='Overwrite with Defaults', - on_activate_call=self._defaults, - ) - bui.containerwidget( - edit=self._root_widget, - cancel_button=quit_button, - selected_child=quit_button, - ) - - def _quit(self) -> None: - bui.apptimer(0.001, self._edit_and_quit) - bui.lock_all_input() - - def _edit_and_quit(self) -> None: - bui.open_file_externally(self._config_file_path) - bui.apptimer(0.1, bui.quit) - - def _defaults(self) -> None: - bui.containerwidget(edit=self._root_widget, transition='out_left') - bui.getsound('gunCocking').play() - bui.screenmessage('settings reset.', color=(1, 1, 0)) - - # At this point settings are already set; lets just commit them - # to disk. - bui.commit_app_config(force=True) diff --git a/src/assets/ba_data/python/bauiv1lib/settings/gamepad.py b/src/assets/ba_data/python/bauiv1lib/settings/gamepad.py index c9780d15..eeb12dad 100644 --- a/src/assets/ba_data/python/bauiv1lib/settings/gamepad.py +++ b/src/assets/ba_data/python/bauiv1lib/settings/gamepad.py @@ -545,20 +545,25 @@ class GamepadSettingsWindow(bui.Window): if 'analogStickLR' + self._ext in self._settings else 5 if self._is_secondary - else 1 + else None ) sval2 = ( self._settings['analogStickUD' + self._ext] if 'analogStickUD' + self._ext in self._settings else 6 if self._is_secondary - else 2 - ) - return ( - self._input.get_axis_name(sval1) - + ' / ' - + self._input.get_axis_name(sval2) + else None ) + print('got', sval1, sval2) + assert isinstance(sval1, (int, type(None))) + assert isinstance(sval2, (int, type(None))) + if sval1 is not None and sval2 is not None: + return ( + self._input.get_axis_name(sval1) + + ' / ' + + self._input.get_axis_name(sval2) + ) + return bui.Lstr(resource=self._r + '.unsetText') # If they're looking for triggers. if control in ['triggerRun1' + self._ext, 'triggerRun2' + self._ext]: @@ -573,7 +578,7 @@ class GamepadSettingsWindow(bui.Window): return str(1.0) # For dpad buttons: show individual buttons if any are set. - # Otherwise show whichever dpad is set (defaulting to 1). + # Otherwise show whichever dpad is set. dpad_buttons = [ 'buttonLeft' + self._ext, 'buttonRight' + self._ext, @@ -588,24 +593,28 @@ class GamepadSettingsWindow(bui.Window): return bui.Lstr(resource=self._r + '.unsetText') # No dpad buttons - show the dpad number for all 4. - return bui.Lstr( - value='${A} ${B}', - subs=[ - ('${A}', bui.Lstr(resource=self._r + '.dpadText')), - ( - '${B}', - str( - self._settings['dpad' + self._ext] - if 'dpad' + self._ext in self._settings - else 2 - if self._is_secondary - else 1 - ), - ), - ], + dpadnum = ( + self._settings['dpad' + self._ext] + if 'dpad' + self._ext in self._settings + else 2 + if self._is_secondary + else None ) + assert isinstance(dpadnum, (int, type(None))) + if dpadnum is not None: + return bui.Lstr( + value='${A} ${B}', + subs=[ + ('${A}', bui.Lstr(resource=self._r + '.dpadText')), + ( + '${B}', + str(dpadnum), + ), + ], + ) + return bui.Lstr(resource=self._r + '.unsetText') - # other buttons.. + # Other buttons. if control in self._settings: return self._input.get_button_name(self._settings[control]) return bui.Lstr(resource=self._r + '.unsetText') @@ -616,9 +625,7 @@ class GamepadSettingsWindow(bui.Window): event: dict[str, Any], dialog: AwaitGamepadInputWindow, ) -> None: - # pylint: disable=too-many-nested-blocks # pylint: disable=too-many-branches - # pylint: disable=too-many-statements assert self._settings is not None ext = self._ext @@ -648,10 +655,6 @@ class GamepadSettingsWindow(bui.Window): if btn in self._settings: del self._settings[btn] if event['hat'] == (2 if self._is_secondary else 1): - # Exclude value in default case. - if 'dpad' + ext in self._settings: - del self._settings['dpad' + ext] - else: self._settings['dpad' + ext] = event['hat'] # Update the 4 dpad button txt widgets. @@ -680,10 +683,6 @@ class GamepadSettingsWindow(bui.Window): if abs(event['value']) > 0.5: axis = event['axis'] if axis == (5 if self._is_secondary else 1): - # Exclude value in default case. - if 'analogStickLR' + ext in self._settings: - del self._settings['analogStickLR' + ext] - else: self._settings['analogStickLR' + ext] = axis bui.textwidget( edit=self._textwidgets['analogStickLR' + ext], @@ -713,10 +712,6 @@ class GamepadSettingsWindow(bui.Window): lr_axis = 5 if self._is_secondary else 1 if axis != lr_axis: if axis == (6 if self._is_secondary else 2): - # Exclude value in default case. - if 'analogStickUD' + ext in self._settings: - del self._settings['analogStickUD' + ext] - else: self._settings['analogStickUD' + ext] = axis bui.textwidget( edit=self._textwidgets['analogStickLR' + ext], @@ -795,7 +790,7 @@ class GamepadSettingsWindow(bui.Window): ), ) - bui.apptimer(0, doit) + bui.pushcall(doit) return btn def _cancel(self) -> None: diff --git a/src/assets/ba_data/python/bauiv1lib/settings/gamepadadvanced.py b/src/assets/ba_data/python/bauiv1lib/settings/gamepadadvanced.py index ae50be7b..d44300f0 100644 --- a/src/assets/ba_data/python/bauiv1lib/settings/gamepadadvanced.py +++ b/src/assets/ba_data/python/bauiv1lib/settings/gamepadadvanced.py @@ -452,7 +452,7 @@ class GamepadAdvancedSettingsWindow(bui.Window): ), ) - bui.apptimer(0, doit) + bui.pushcall(doit) return btn, btn2 def _inc( diff --git a/src/assets/ba_data/python/bauiv1lib/settings/keyboard.py b/src/assets/ba_data/python/bauiv1lib/settings/keyboard.py index 6f37aabb..60aab600 100644 --- a/src/assets/ba_data/python/bauiv1lib/settings/keyboard.py +++ b/src/assets/ba_data/python/bauiv1lib/settings/keyboard.py @@ -213,6 +213,12 @@ class ConfigKeyboardWindow(bui.Window): scale=1.0, ) + def _pretty_button_name(self, button_name: str) -> bui.Lstr: + button_id = self._settings[button_name] + if button_id == -1: + return bs.Lstr(resource='configGamepadWindow.unsetText') + return self._input.get_button_name(button_id) + def _capture_button( self, pos: tuple[float, float], @@ -250,7 +256,7 @@ class ConfigKeyboardWindow(bui.Window): v_align='top', scale=uiscale, maxwidth=maxwidth, - text=self._input.get_button_name(self._settings[button]), + text=self._pretty_button_name(button), ) bui.buttonwidget( edit=btn, diff --git a/src/ballistica/base/input/device/joystick_input.cc b/src/ballistica/base/input/device/joystick_input.cc index 08ad4148..910f9459 100644 --- a/src/ballistica/base/input/device/joystick_input.cc +++ b/src/ballistica/base/input/device/joystick_input.cc @@ -65,7 +65,12 @@ JoystickInput::JoystickInput(int sdl_joystick_id, // that instead. // #if BA_SDL2_BUILD sdl_joystick_id_ = SDL_JoystickInstanceID(sdl_joystick_); - raw_sdl_joystick_name_ = SDL_JoystickName(sdl_joystick_); + if (auto* name = SDL_JoystickName(sdl_joystick_)) { + raw_sdl_joystick_name_ = name; + } else { + // This can return nullptr if SDL can't find a name. + raw_sdl_joystick_name_ = "Unknown Controller"; + } // Special case: on windows, xinput stuff comes in with unique names // "XInput Controller #3", etc. Let's replace these with simply "XInput diff --git a/src/ballistica/base/input/device/joystick_input.h b/src/ballistica/base/input/device/joystick_input.h index 5748f702..0444bb19 100644 --- a/src/ballistica/base/input/device/joystick_input.h +++ b/src/ballistica/base/input/device/joystick_input.h @@ -126,12 +126,12 @@ class JoystickInput : public InputDevice { bool calibrate_ : 1 {}; bool can_configure_ : 1 {}; - int hat_{}; - int analog_lr_{}; + int hat_{0}; + int analog_lr_{0}; int analog_ud_{1}; // Mappings of ba buttons to SDL buttons. - int jump_button_{}; + int jump_button_{0}; int punch_button_{1}; int bomb_button_{2}; int pickup_button_{3}; diff --git a/src/ballistica/base/python/methods/python_methods_app.cc b/src/ballistica/base/python/methods/python_methods_app.cc index 471c6c08..48db4269 100644 --- a/src/ballistica/base/python/methods/python_methods_app.cc +++ b/src/ballistica/base/python/methods/python_methods_app.cc @@ -602,7 +602,7 @@ static auto PyCommitConfig(PyObject* self, PyObject* args, PyObject* keywds) } fclose(f_out); - // Now backup any existing config to .prev. + // Now move any existing config to .prev. if (g_core->platform->FilePathExists(path)) { // On windows, rename doesn't overwrite existing files.. need to kill // the old explicitly. diff --git a/src/ballistica/base/ui/dev_console.cc b/src/ballistica/base/ui/dev_console.cc index 6940c271..cec733a8 100644 --- a/src/ballistica/base/ui/dev_console.cc +++ b/src/ballistica/base/ui/dev_console.cc @@ -864,7 +864,7 @@ auto DevConsole::HandleKeyPress(const SDL_Keysym* keysym) -> bool { bool found_valid{}; // Move until we've found at least one valid char and the // stop at the first invalid one. - while (carat_char_ < unichars.size()) { + while (carat_char_ < static_cast(unichars.size())) { assert(CaratCharValid_()); auto this_char = unichars[carat_char_]; auto is_valid = IsValidHungryChar_(this_char); @@ -995,8 +995,8 @@ void DevConsole::Exec() { // Just for sanity testing. auto DevConsole::CaratCharValid_() -> bool { return carat_char_ >= 0 - && carat_char_ - <= Utils::UnicodeFromUTF8(input_string_, "fwewffe").size(); + && carat_char_ <= static_cast( + Utils::UnicodeFromUTF8(input_string_, "fwewffe").size()); } void DevConsole::SubmitPythonCommand_(const std::string& command) { @@ -1419,7 +1419,7 @@ void DevConsole::UpdateCarat_() { // Use a base width if we're not covering a char, and use the char's width // if we are. float width = 14.0f; - if (carat_char_ < unichars.size()) { + if (carat_char_ < static_cast(unichars.size())) { std::vector covered_char{unichars[carat_char_]}; auto covered_char_str = Utils::UTF8FromUnicode(covered_char); width = diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index 70294d7f..d7bbd454 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 = 21525; +const int kEngineBuildNumber = 21528; const char* kEngineVersion = "1.7.28"; const int kEngineApiVersion = 8;