From c2e57e6a6bc706723e304c6cb3af56491e024086 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Thu, 9 Apr 2020 18:03:03 +0300 Subject: [PATCH 1/7] fix buy method in StoreBrowserWindow --- assets/src/ba_data/python/bastd/ui/store/browser.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/assets/src/ba_data/python/bastd/ui/store/browser.py b/assets/src/ba_data/python/bastd/ui/store/browser.py index 18ede61f..1b634735 100644 --- a/assets/src/ba_data/python/bastd/ui/store/browser.py +++ b/assets/src/ba_data/python/bastd/ui/store/browser.py @@ -88,7 +88,7 @@ class StoreBrowserWindow(ba.Window): self._request: Any = None self._r = 'store' - self._last_buy_time = None + self._last_buy_time: Optional[Union[float, int]] = None super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + extra_top), @@ -476,7 +476,8 @@ class StoreBrowserWindow(ba.Window): # Prevent pressing buy within a few seconds of the last press # (gives the buttons time to disable themselves and whatnot). curtime = ba.time(ba.TimeType.REAL) - if self._last_buy_time is None or curtime - self._last_buy_time < 2.0: + if self._last_buy_time is not None and (curtime - + self._last_buy_time) < 2.0: ba.playsound(ba.getsound('error')) else: if _ba.get_account_state() != 'signed_in': From 5c299f0062ee59f93445ebad3b61fb175cb0bbbc Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 9 Apr 2020 22:04:58 -0700 Subject: [PATCH 2/7] tidying --- .../ba_data/python/bastd/ui/store/browser.py | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/assets/src/ba_data/python/bastd/ui/store/browser.py b/assets/src/ba_data/python/bastd/ui/store/browser.py index 18ede61f..a066671f 100644 --- a/assets/src/ba_data/python/bastd/ui/store/browser.py +++ b/assets/src/ba_data/python/bastd/ui/store/browser.py @@ -179,7 +179,7 @@ class StoreBrowserWindow(ba.Window): ('minigames', ba.Lstr(resource=self._r + '.miniGamesText')), ('characters', ba.Lstr(resource=self._r + '.charactersText')), ('icons', ba.Lstr(resource=self._r + '.iconsText')), - ] # yapf : disable + ] tab_results = tabs.create_tab_buttons(self._root_widget, tabs_def, @@ -454,16 +454,19 @@ class StoreBrowserWindow(ba.Window): # purchase this. Better to fail now than after we've # paid locally. app = ba.app - serverget('bsAccountPurchaseCheck', { - 'item': item, - 'platform': app.platform, - 'subplatform': app.subplatform, - 'version': app.version, - 'buildNumber': app.build_number, - 'purchaseType': 'ticket' if is_ticket_purchase else 'real' - }, - callback=ba.WeakCall(self._purchase_check_result, item, - is_ticket_purchase)) + serverget( + 'bsAccountPurchaseCheck', + { + 'item': item, + 'platform': app.platform, + 'subplatform': app.subplatform, + 'version': app.version, + 'buildNumber': app.build_number, + 'purchaseType': 'ticket' if is_ticket_purchase else 'real' + }, + callback=ba.WeakCall(self._purchase_check_result, item, + is_ticket_purchase), + ) def buy(self, item: str) -> None: """Attempt to purchase the provided item.""" @@ -537,8 +540,7 @@ class StoreBrowserWindow(ba.Window): sales_raw = _ba.get_account_misc_read_val('sales', {}) sales = {} try: - # look at the current set of sales; filter any with - # time remaining.. + # Look at the current set of sales; filter any with time remaining. for sale_item, sale_info in list(sales_raw.items()): to_end = (datetime.datetime.utcfromtimestamp(sale_info['e']) - datetime.datetime.utcnow()).total_seconds() @@ -548,7 +550,7 @@ class StoreBrowserWindow(ba.Window): 'original_price': sale_info['op'] } except Exception: - ba.print_exception("Error parsing sales") + ba.print_exception("Error parsing sales.") assert self.button_infos is not None for b_type, b_info in self.button_infos.items(): @@ -602,7 +604,8 @@ class StoreBrowserWindow(ba.Window): price_text_right = '' else: price = _ba.get_account_misc_read_val('price.' + b_type, 0) - # color button differently if we cant afford this + + # Color the button differently if we cant afford this. if _ba.get_account_state() == 'signed_in': if _ba.get_account_ticket_count() < price: color = (0.6, 0.61, 0.6) From 64aff1306fef2b8769decb0f9ad0e0b32aaeec2c Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 9 Apr 2020 22:22:41 -0700 Subject: [PATCH 3/7] Fixed ServerCallThread callbacks --- assets/src/ba_data/python/ba/_netutils.py | 14 ++++++++------ .../src/ba_data/python/bastd/ui/store/browser.py | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/assets/src/ba_data/python/ba/_netutils.py b/assets/src/ba_data/python/ba/_netutils.py index ace052dd..8369d335 100644 --- a/assets/src/ba_data/python/ba/_netutils.py +++ b/assets/src/ba_data/python/ba/_netutils.py @@ -87,16 +87,18 @@ class ServerCallThread(threading.Thread): activity) if activity is not None else None def _run_callback(self, arg: Union[None, Dict[str, Any]]) -> None: - # If we were created in an activity context and that activity has - # since died, do nothing (hmm should we be using a context-call - # instead of doing this manually?). - activity = None if self._activity is None else self._activity() - if activity is None or activity.is_expired(): - return + # since died, do nothing. + # FIXME: Should we just be using a ContextCall instead of doing + # this check manually? + if self._activity is not None: + activity = self._activity() + if activity is None or activity.is_expired(): + return # Technically we could do the same check for session contexts, # but not gonna worry about it for now. + assert self._context is not None assert self._callback is not None with self._context: self._callback(arg) diff --git a/assets/src/ba_data/python/bastd/ui/store/browser.py b/assets/src/ba_data/python/bastd/ui/store/browser.py index 87338781..1e0398fc 100644 --- a/assets/src/ba_data/python/bastd/ui/store/browser.py +++ b/assets/src/ba_data/python/bastd/ui/store/browser.py @@ -88,7 +88,7 @@ class StoreBrowserWindow(ba.Window): self._request: Any = None self._r = 'store' - self._last_buy_time: Optional[Union[float, int]] = None + self._last_buy_time: Optional[float] = None super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + extra_top), From dc7538b72e913aa1017f3f6d554111582b5fe834 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 9 Apr 2020 22:53:19 -0700 Subject: [PATCH 4/7] Tidying --- .../python/bastd/activity/coopscorescreen.py | 45 ++++++++----------- assets/src/ba_data/python/bastd/actor/bomb.py | 7 +-- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/assets/src/ba_data/python/bastd/activity/coopscorescreen.py b/assets/src/ba_data/python/bastd/activity/coopscorescreen.py index d97ad1e7..f96ca753 100644 --- a/assets/src/ba_data/python/bastd/activity/coopscorescreen.py +++ b/assets/src/ba_data/python/bastd/activity/coopscorescreen.py @@ -29,6 +29,8 @@ from typing import TYPE_CHECKING import _ba import ba from ba.internal import get_achievements_for_coop_level +from bastd.actor.text import Text +from bastd.actor.zoomtext import ZoomText if TYPE_CHECKING: from typing import Optional, Tuple, List, Dict, Any, Sequence @@ -50,9 +52,6 @@ class CoopScoreScreen(ba.Activity): self.inherits_music = True self.use_fixed_vr_overlay = True - self._tournament_time_remaining = None - self._tournament_time_remaining_text = None - self._do_new_rating: bool = self.session.tournament_id is not None self._score_display_sound = ba.getsound("scoreHit01") @@ -134,6 +133,8 @@ class CoopScoreScreen(ba.Activity): self._name_str: Optional[str] = None self._friends_loading_status: Optional[ba.Actor] = None self._score_loading_status: Optional[ba.Actor] = None + self._tournament_time_remaining: Optional[float] = None + self._tournament_time_remaining_text: Optional[Text] = None self._tournament_time_remaining_text_timer: Optional[ba.Timer] = None self._player_info = settings['player_info'] @@ -288,7 +289,6 @@ class CoopScoreScreen(ba.Activity): ba.open_url(self._score_link) def _ui_error(self) -> None: - from bastd.actor.text import Text with ba.Context(self): self._next_level_error = Text( ba.Lstr(resource='completeThisLevelToProceedText'), @@ -515,8 +515,6 @@ class CoopScoreScreen(ba.Activity): # pylint: disable=too-many-statements # pylint: disable=too-many-branches # pylint: disable=too-many-locals - from bastd.actor.text import Text - from bastd.actor.zoomtext import ZoomText super().on_begin() # Calc whether the level is complete and other stuff. @@ -893,7 +891,6 @@ class CoopScoreScreen(ba.Activity): # pylint: disable=too-many-branches # pylint: disable=too-many-statements # delay a bit if results come in too fast - from bastd.actor.text import Text base_delay = max(0, 1.9 - (ba.time() - self._begin_time)) ts_height = 300 ts_h_offs = -550 @@ -1009,7 +1006,6 @@ class CoopScoreScreen(ba.Activity): # We need to manually run this in the context of our activity # and only if we aren't shutting down. # (really should make the submit_score call handle that stuff itself) - from bastd.actor.text import Text if self.is_expired(): return with ba.Context(self): @@ -1169,10 +1165,9 @@ class CoopScoreScreen(ba.Activity): # pylint: disable=too-many-branches # pylint: disable=too-many-statements from ba.internal import get_tournament_prize_strings - from bastd.actor.text import Text - from bastd.actor.zoomtext import ZoomText assert self._show_info is not None available = (self._show_info['results'] is not None) + if available: error = (self._show_info['results']['error'] if 'error' in self._show_info['results'] else None) @@ -1193,22 +1188,22 @@ class CoopScoreScreen(ba.Activity): Text(ba.Lstr(resource='coopSelectWindow.timeRemainingText'), position=(-360, -70 - 100), color=(1, 1, 1, 0.7), - h_align='center', - v_align='center', - transition='fade_in', + h_align=Text.HAlign.CENTER, + v_align=Text.VAlign.CENTER, + transition=Text.Transition.FADE_IN, scale=0.8, maxwidth=300, transition_delay=2.0).autoretain() - self._tournament_time_remaining_text = Text('', - position=(-360, - -110 - 100), - color=(1, 1, 1, 0.7), - h_align='center', - v_align='center', - transition='fade_in', - scale=1.6, - maxwidth=150, - transition_delay=2.0) + self._tournament_time_remaining_text = Text( + '', + position=(-360, -110 - 100), + color=(1, 1, 1, 0.7), + h_align=Text.HAlign.CENTER, + v_align=Text.VAlign.CENTER, + transition=Text.Transition.FADE_IN, + scale=1.6, + maxwidth=150, + transition_delay=2.0) # If we're a tournament, show prizes. try: @@ -1439,8 +1434,6 @@ class CoopScoreScreen(ba.Activity): ba.timer(0.35, ba.Call(ba.playsound, self.cymbal_sound)) def _show_fail(self) -> None: - from bastd.actor.text import Text - from bastd.actor.zoomtext import ZoomText ZoomText(ba.Lstr(resource='failText'), maxwidth=300, flash=False, @@ -1460,8 +1453,6 @@ class CoopScoreScreen(ba.Activity): ba.timer(0.35, ba.Call(ba.playsound, self._score_display_sound)) def _show_score_val(self, offs_x: float) -> None: - from bastd.actor.text import Text - from bastd.actor.zoomtext import ZoomText assert self._score_type is not None assert self._score is not None ZoomText((str(self._score) if self._score_type == 'points' else diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index 460d97a9..3fcdc682 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -1052,7 +1052,8 @@ class TNTSpawner: self._position = position self._tnt: Optional[Bomb] = None self._update() - # (go with slightly more than 1 second to avoid timer stacking) + + # Go with slightly more than 1 second to avoid timer stacking. self._update_timer = ba.Timer(1.1, ba.WeakCall(self._update), repeat=True) @@ -1062,8 +1063,8 @@ class TNTSpawner: def _update(self) -> None: tnt_alive = self._tnt is not None and self._tnt.node if not tnt_alive: - # respawn if its been long enough.. otherwise just increment our - # how-long-since-we-died value + # Respawn if its been long enough.. otherwise just increment our + # how-long-since-we-died value. if self._tnt is None or self._wait_time >= self._respawn_time: self._tnt = Bomb(position=self._position, bomb_type='tnt') self._wait_time = 0.0 From 103971f65f6247a2899091ce2894c2cc79e9a7fb Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 9 Apr 2020 23:07:35 -0700 Subject: [PATCH 5/7] Tidying and type cleanup --- .idea/dictionaries/ericf.xml | 1 + assets/src/ba_data/python/ba/_gameactivity.py | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index ee3bde6f..0e082cde 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1555,6 +1555,7 @@ spammy sparx spawner + spawners spawnpoints spawnpt spawntype diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 2bced635..c64af244 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -34,6 +34,7 @@ if TYPE_CHECKING: from typing import (List, Optional, Dict, Type, Any, Callable, Sequence, Tuple, Union) from bastd.actor.playerspaz import PlayerSpaz + from bastd.actor.bomb import TNTSpawner import ba @@ -330,7 +331,7 @@ class GameActivity(Activity): self._map_type.preload() self._map: Optional[ba.Map] = None self._powerup_drop_timer: Optional[ba.Timer] = None - self._tnt_spawners: Optional[Dict[int, Any]] = None + self._tnt_spawners: Optional[Dict[int, TNTSpawner]] = None self._tnt_drop_timer: Optional[ba.Timer] = None self.initial_player_info: Optional[List[Dict[str, Any]]] = None self._game_scoreboard_name_text: Optional[ba.Actor] = None @@ -1135,12 +1136,12 @@ class GameActivity(Activity): def _setup_standard_tnt_drops(self) -> None: """Standard tnt drop.""" # pylint: disable=cyclic-import - from bastd.actor import bomb + from bastd.actor.bomb import TNTSpawner for i, point in enumerate(self.map.tnt_points): assert self._tnt_spawners is not None if self._tnt_spawners.get(i) is None: - self._tnt_spawners[i] = bomb.TNTSpawner(point) + self._tnt_spawners[i] = TNTSpawner(point) def setup_standard_time_limit(self, duration: float) -> None: """ From 07f538fb0b3e56a3d9b97c72b65064eda8c5105c Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 10 Apr 2020 00:47:01 -0700 Subject: [PATCH 6/7] Fixed a few return types of internal calls. --- .idea/dictionaries/ericf.xml | 1 + assets/src/ba_data/python/_ba.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index ee3bde6f..2722a296 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1216,6 +1216,7 @@ painttxtattr palmos pandoc + pandroid parsermodule partyqueue partyval diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index af0616e8..dbdae18c 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -1999,7 +1999,7 @@ def get_display_resolution() -> Tuple[int, int]: def get_foreground_host_activity() -> ba.Activity: - """get_foreground_host_activity() -> ba.Activity + """get_foreground_host_activity() -> Optional[ba.Activity] (internal) @@ -2011,7 +2011,7 @@ def get_foreground_host_activity() -> ba.Activity: def get_foreground_host_session() -> ba.Session: - """get_foreground_host_session() -> ba.Session + """get_foreground_host_session() -> Optional[ba.Session] (internal) From 5d9e854eb80a8ffe72bacb82dd9d6ffacf03157f Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 10 Apr 2020 00:57:08 -0700 Subject: [PATCH 7/7] latest binaries, assets, and docs --- docs/ba_module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ba_module.md b/docs/ba_module.md index e6f11c42..37a18cf8 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

last updated on 2020-04-08 for Ballistica version 1.5.0 build 20001

+

last updated on 2020-04-10 for Ballistica version 1.5.0 build 20001

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!