diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 4a17c1ae..2304ca94 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -6,6 +6,7 @@ from __future__ import annotations import weakref from typing import TYPE_CHECKING, Generic, TypeVar +import _ba from ba._team import Team from ba._player import Player from ba._error import (print_exception, SessionTeamNotFoundError, @@ -13,7 +14,6 @@ from ba._error import (print_exception, SessionTeamNotFoundError, from ba._dependency import DependencyComponent from ba._general import Call, verify_object_death from ba._messages import UNHANDLED -import _ba if TYPE_CHECKING: from weakref import ReferenceType diff --git a/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py b/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py index 5f50af0f..8aee88b7 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py +++ b/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py @@ -165,6 +165,11 @@ class GameButton: def _update(self) -> None: # pylint: disable=too-many-boolean-expressions from ba.internal import getcampaign + + # In case we stick around after our UI... + if not self._button: + return + game = self._game campaignname, levelname = game.split(':') diff --git a/assets/src/ba_data/python/bastd/ui/gather/__init__.py b/assets/src/ba_data/python/bastd/ui/gather/__init__.py index 253c0629..201e729f 100644 --- a/assets/src/ba_data/python/bastd/ui/gather/__init__.py +++ b/assets/src/ba_data/python/bastd/ui/gather/__init__.py @@ -240,6 +240,7 @@ class GatherWindow(ba.Window): ba.print_exception(f'Error saving state for {self}.') def _restore_state(self) -> None: + # pylint: disable=too-many-branches try: for tab in self._tabs.values(): tab.restore_state() @@ -249,12 +250,25 @@ class GatherWindow(ba.Window): sel_name = winstate.get('sel_name', None) assert isinstance(sel_name, (str, type(None))) current_tab = self.TabID.ABOUT - try: - stored_tab = self.TabID(ba.app.config.get('Gather Tab')) - if stored_tab in self._tab_row.tabs: - current_tab = stored_tab - except ValueError: - pass + gather_tab_val = ba.app.config.get('Gather Tab') + + if bool(False): + # EWWW: normally would just do this, but it seems to result in + # a reference to self sticking around somewhere. (presumably + # in the exception?). Should get to the bottom of this. + try: + stored_tab = self.TabID(gather_tab_val) + if stored_tab in self._tab_row.tabs: + current_tab = stored_tab + except ValueError: + pass + else: + # Falling back to this for now. + tab_vals = {t.value for t in self.TabID} + if gather_tab_val in tab_vals: + stored_tab = self.TabID(gather_tab_val) + if stored_tab in self._tab_row.tabs: + current_tab = stored_tab self._set_tab(current_tab) if sel_name == 'Back': sel = self._back_button @@ -270,7 +284,7 @@ class GatherWindow(ba.Window): sel = self._tab_row.tabs[current_tab].button ba.containerwidget(edit=self._root_widget, selected_child=sel) except Exception: - ba.print_exception(f'Error restoring state for {self}.') + ba.print_exception('Error restoring gather-win state.') def _back(self) -> None: from bastd.ui.mainmenu import MainMenuWindow diff --git a/assets/src/ba_data/python/bastd/ui/gather/nearbytab.py b/assets/src/ba_data/python/bastd/ui/gather/nearbytab.py index 66f500be..ca94557d 100644 --- a/assets/src/ba_data/python/bastd/ui/gather/nearbytab.py +++ b/assets/src/ba_data/python/bastd/ui/gather/nearbytab.py @@ -4,6 +4,7 @@ from __future__ import annotations +import weakref from typing import TYPE_CHECKING import ba @@ -18,8 +19,9 @@ if TYPE_CHECKING: class NetScanner: """Class for scanning for games on the lan.""" - def __init__(self, scrollwidget: ba.Widget, tab_button: ba.Widget, - width: float): + def __init__(self, tab: GatherTab, scrollwidget: ba.Widget, + tab_button: ba.Widget, width: float): + self._tab = weakref.ref(tab) self._scrollwidget = scrollwidget self._tab_button = tab_button self._columnwidget = ba.columnwidget(parent=self._scrollwidget, @@ -46,10 +48,22 @@ class NetScanner: self._last_selected_host = host def _on_activate(self, host: Dict[str, Any]) -> None: + + # Sanity check: make sure our gather window gets freed after this. + tab = self._tab() + if tab: + ba.verify_object_death(tab.window) _ba.connect_to_party(host['address']) def update(self) -> None: """(internal)""" + + # In case our UI was killed from under us. + if not self._columnwidget: + print(f'ERROR: NetScanner running without UI at time' + f' {ba.time(timetype=ba.TimeType.REAL)}.') + return + t_scale = 1.6 for child in self._columnwidget.get_children(): child.delete() @@ -125,7 +139,8 @@ class NearbyGatherTab(GatherTab): 0.5, v), size=(sub_scroll_width, sub_scroll_height)) - self._net_scanner = NetScanner(scrollw, + self._net_scanner = NetScanner(self, + scrollw, tab_button, width=sub_scroll_width) diff --git a/docs/ba_module.md b/docs/ba_module.md index a8dc9b91..aad98319 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -
This page documents the Python classes and functions in the 'ba' module, which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please let me know. Happy modding!