various input and config cleanup

This commit is contained in:
Eric 2023-10-27 15:58:10 -07:00
parent 03675a22a3
commit 1115983bcc
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
19 changed files with 145 additions and 275 deletions

56
.efrocachemap generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -452,7 +452,7 @@ class GamepadAdvancedSettingsWindow(bui.Window):
),
)
bui.apptimer(0, doit)
bui.pushcall(doit)
return btn, btn2
def _inc(

View File

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

View File

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

View File

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

View File

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

View File

@ -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<int>(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<int>(
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<int>(unichars.size())) {
std::vector<uint32_t> covered_char{unichars[carat_char_]};
auto covered_char_str = Utils::UTF8FromUnicode(covered_char);
width =

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 = 21525;
const int kEngineBuildNumber = 21528;
const char* kEngineVersion = "1.7.28";
const int kEngineApiVersion = 8;