diff --git a/README.md b/README.md index fe057a9..d625ccc 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,14 @@ There are two different ways the plugin manager can be installed: 1. [Download plugin_manager.py][DownloadLink] to your mods directory (check it out by going into your game's Settings -> Advanced -> Show Mods Folder). This is the recommended way (read next method to know why). + If you're on a newer version of Android (11 or above) and not rooted, it probably won't be possible to copy + mods to game's mods folder. In this case, you can connect your Android phone to a computer and push `plugin_manager.py` + [using `adb`](https://www.xda-developers.com/install-adb-windows-macos-linux/): + ```bash + $ adb push plugin_manager.py /sdcard/Android/data/net.froemling.bombsquad/files/mods/plugin_manager.py + ``` -2. Another way is to add +3. Another way is to add [plugin_manager.py](https://raw.githubusercontent.com/bombsquad-community/plugin-manager/main/plugin_manager.py) to your workspace. However, plugin manager self-updates will fail when installed using this way since the game will overrwrite the updated plugin manager, with the older version from workspace on the next sync. However, you can @@ -193,7 +199,8 @@ That's it! Now you can make a [pull request](../../compare) with both the update will also help us to notify the maintainers of any future breaking changes in plugin manager that could affect 3rd party plugin sources. - [rikkolovescats/sahilp-plugins](https://github.com/rikkolovescats/sahilp-plugins) + - [rikkolovescats/sahilp-plugins](https://github.com/rikkolovescats/sahilp-plugins) + - [Aeliux/arcane](https://github.com/Aeliux/arcane) ## Tests diff --git a/plugins/minigames.json b/plugins/minigames.json index a95fc4f..ae4f540 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -166,6 +166,12 @@ } ], "versions": { + "2.0.0": { + "api_version": 8, + "commit_sha": "1b14789", + "released_on": "02-07-2023", + "md5sum": "cb2a7700dd13febe6f68c3cd979b8b19" + }, "1.1.0": { "api_version": 7, "commit_sha": "40b70fe", diff --git a/plugins/minigames/alliance_elimination.py b/plugins/minigames/alliance_elimination.py index e6f3776..f6d47b5 100644 --- a/plugins/minigames/alliance_elimination.py +++ b/plugins/minigames/alliance_elimination.py @@ -2,23 +2,25 @@ # """Elimination mini-game.""" -# ba_meta require api 7 +# ba_meta require api 8 # (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations from typing import TYPE_CHECKING -import ba -from bastd.actor.spazfactory import SpazFactory -from bastd.actor.scoreboard import Scoreboard +import babase +import bauiv1 as bui +import bascenev1 as bs +from bascenev1lib.actor.spazfactory import SpazFactory +from bascenev1lib.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import (Any, Tuple, Type, List, Sequence, Optional, Union) -class Icon(ba.Actor): +class Icon(bs.Actor): """Creates in in-game icon on screen.""" def __init__(self, @@ -37,10 +39,10 @@ class Icon(ba.Actor): self._show_lives = show_lives self._show_death = show_death self._name_scale = name_scale - self._outline_tex = ba.gettexture('characterIconMask') + self._outline_tex = bs.gettexture('characterIconMask') icon = player.get_icon() - self.node = ba.newnode('image', + self.node = bs.newnode('image', delegate=self, attrs={ 'texture': icon['texture'], @@ -53,12 +55,12 @@ class Icon(ba.Actor): 'absolute_scale': True, 'attach': 'bottomCenter' }) - self._name_text = ba.newnode( + self._name_text = bs.newnode( 'text', owner=self.node, attrs={ - 'text': ba.Lstr(value=player.getname()), - 'color': ba.safecolor(player.team.color), + 'text': babase.Lstr(value=player.getname()), + 'color': babase.safecolor(player.team.color), 'h_align': 'center', 'v_align': 'center', 'vr_depth': 410, @@ -69,7 +71,7 @@ class Icon(ba.Actor): 'v_attach': 'bottom' }) if self._show_lives: - self._lives_text = ba.newnode('text', + self._lives_text = bs.newnode('text', owner=self.node, attrs={ 'text': 'x0', @@ -125,7 +127,7 @@ class Icon(ba.Actor): if not self.node: return if self._show_death: - ba.animate( + bs.animate( self.node, 'opacity', { 0.00: 1.0, 0.05: 0.0, @@ -142,16 +144,16 @@ class Icon(ba.Actor): }) lives = self._player.lives if lives == 0: - ba.timer(0.6, self.update_for_lives) + bs.timer(0.6, self.update_for_lives) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.DieMessage): + if isinstance(msg, bs.DieMessage): self.node.delete() return None return super().handlemessage(msg) -class Player(ba.Player['Team']): +class Player(bs.Player['Team']): """Our player type for this game.""" def __init__(self) -> None: @@ -159,7 +161,7 @@ class Player(ba.Player['Team']): self.icons: List[Icon] = [] -class Team(ba.Team[Player]): +class Team(bs.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: @@ -167,14 +169,14 @@ class Team(ba.Team[Player]): self.spawn_order: List[Player] = [] -# ba_meta export game -class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): +# ba_meta export bascenev1.GameActivity +class AllianceEliminationGame(bs.TeamGameActivity[Player, Team]): """Game type where last player(s) left alive win.""" name = 'Alliance Elimination' description = 'Fight in groups of duo, trio, or more.\nLast remaining alive wins.' - scoreconfig = ba.ScoreConfig(label='Survived', - scoretype=ba.ScoreType.SECONDS, + scoreconfig = bs.ScoreConfig(label='Survived', + scoretype=bs.ScoreType.SECONDS, none_is_winner=True) # Show messages when players die since it's meaningful here. announce_player_deaths = True @@ -183,23 +185,23 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): @classmethod def get_available_settings( - cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + cls, sessiontype: Type[bs.Session]) -> List[babase.Setting]: settings = [ - ba.IntSetting( + bs.IntSetting( 'Lives Per Player', default=1, min_value=1, max_value=10, increment=1, ), - ba.IntSetting( + bs.IntSetting( 'Players Per Team In Arena', default=2, min_value=2, max_value=10, increment=1, ), - ba.IntChoiceSetting( + bs.IntChoiceSetting( 'Time Limit', choices=[ ('None', 0), @@ -211,7 +213,7 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): ], default=0, ), - ba.FloatChoiceSetting( + bs.FloatChoiceSetting( 'Respawn Times', choices=[ ('Shorter', 0.25), @@ -222,27 +224,27 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): ], default=1.0, ), - ba.BoolSetting('Epic Mode', default=False), + bs.BoolSetting('Epic Mode', default=False), ] - if issubclass(sessiontype, ba.DualTeamSession): + if issubclass(sessiontype, bs.DualTeamSession): settings.append( - ba.BoolSetting('Balance Total Lives', default=False)) + bs.BoolSetting('Balance Total Lives', default=False)) return settings @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.DualTeamSession) + def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool: + return issubclass(sessiontype, bs.DualTeamSession) @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('melee') + def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]: + return bs.app.classic.getmaps('melee') def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._start_time: Optional[float] = None - self._vs_text: Optional[ba.Actor] = None - self._round_end_timer: Optional[ba.Timer] = None + self._vs_text: Optional[bs.Actor] = None + self._round_end_timer: Optional[bs.Timer] = None self._epic_mode = bool(settings['Epic Mode']) self._lives_per_player = int(settings['Lives Per Player']) self._time_limit = float(settings['Time Limit']) @@ -253,16 +255,16 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): # Base class overrides: self.slow_motion = self._epic_mode - self.default_music = (ba.MusicType.EPIC - if self._epic_mode else ba.MusicType.SURVIVAL) + self.default_music = (bs.MusicType.EPIC + if self._epic_mode else bs.MusicType.SURVIVAL) def get_instance_description(self) -> Union[str, Sequence]: return 'Last team standing wins.' if isinstance( - self.session, ba.DualTeamSession) else 'Last one standing wins.' + self.session, bs.DualTeamSession) else 'Last one standing wins.' def get_instance_description_short(self) -> Union[str, Sequence]: return 'last team standing wins' if isinstance( - self.session, ba.DualTeamSession) else 'last one standing wins' + self.session, bs.DualTeamSession) else 'last one standing wins' def on_player_join(self, player: Player) -> None: @@ -275,9 +277,9 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): if (self._get_total_team_lives(player.team) == 0 and player.team.survival_seconds is None): player.team.survival_seconds = 0 - ba.screenmessage( - ba.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.getname(full=True))]), + bs.broadcastmessage( + babase.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return @@ -293,11 +295,11 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): def on_begin(self) -> None: super().on_begin() - self._start_time = ba.time() + self._start_time = bs.time() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() - self._vs_text = ba.NodeActor( - ba.newnode('text', + self._vs_text = bs.NodeActor( + bs.newnode('text', attrs={ 'position': (0, 92), 'h_attach': 'center', @@ -308,12 +310,12 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): 'scale': 0.6, 'v_attach': 'bottom', 'color': (0.8, 0.8, 0.3, 1.0), - 'text': ba.Lstr(resource='vsText') + 'text': babase.Lstr(resource='vsText') })) # If balance-team-lives is on, add lives to the smaller team until # total lives match. - if (isinstance(self.session, ba.DualTeamSession) + if (isinstance(self.session, bs.DualTeamSession) and self._balance_total_lives and self.teams[0].players and self.teams[1].players): if self._get_total_team_lives( @@ -333,7 +335,7 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): # We could check game-over conditions at explicit trigger points, # but lets just do the simple thing and poll it. - ba.timer(1.0, self._update, repeat=True) + bs.timer(1.0, self._update, repeat=True) def _update_alliance_mode(self) -> None: # For both teams, find the first player on the spawn order list with @@ -391,10 +393,10 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): nplayers -= 1 test_lives += 1 - def _get_spawn_point(self, player: Player) -> Optional[ba.Vec3]: + def _get_spawn_point(self, player: Player) -> Optional[babase.Vec3]: return None - def spawn_player(self, player: Player) -> ba.Actor: + def spawn_player(self, player: Player) -> bs.Actor: actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) # If we have any icons, update their state. @@ -403,7 +405,7 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): return actor def _print_lives(self, player: Player) -> None: - from bastd.actor import popuptext + from bascenev1lib.actor import popuptext # We get called in a timer so it's possible our player has left/etc. if not player or not player.is_alive() or not player.node: @@ -426,20 +428,20 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): # Update icons in a moment since our team will be gone from the # list then. - ba.timer(0, self._update_icons) + bs.timer(0, self._update_icons) # If the player to leave was the last in spawn order and had # their final turn currently in-progress, mark the survival time # for their team. if self._get_total_team_lives(player.team) == 0: assert self._start_time is not None - player.team.survival_seconds = int(ba.time() - self._start_time) + player.team.survival_seconds = int(bs.time() - self._start_time) def _get_total_team_lives(self, team: Team) -> int: return sum(player.lives for player in team.players) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, ba.PlayerDiedMessage): + if isinstance(msg, bs.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) @@ -447,7 +449,7 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): player.lives -= 1 if player.lives < 0: - ba.print_error( + babase.print_error( "Got lives < 0 in Alliance Elimination; this shouldn't happen.") player.lives = 0 @@ -458,14 +460,14 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): # Play big death sound on our last death # or for every one. if player.lives == 0: - ba.playsound(SpazFactory.get().single_player_death_sound) + SpazFactory.get().single_player_death_sound.play() # If we hit zero lives, we're dead (and our team might be too). if player.lives == 0: # If the whole team is now dead, mark their survival time. if self._get_total_team_lives(player.team) == 0: assert self._start_time is not None - player.team.survival_seconds = int(ba.time() - + player.team.survival_seconds = int(bs.time() - self._start_time) # Put ourself at the back of the spawn order. @@ -493,7 +495,7 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): # the game (allows the dust to settle and draws to occur if deaths # are close enough). if len(self._get_living_teams()) < 2: - self._round_end_timer = ba.Timer(0.5, self.end_game) + self._round_end_timer = bs.Timer(0.5, self.end_game) def _get_living_teams(self) -> List[Team]: return [ @@ -505,7 +507,7 @@ class AllianceEliminationGame(ba.TeamGameActivity[Player, Team]): def end_game(self) -> None: if self.has_ended(): return - results = ba.GameResults() + results = bs.GameResults() self._vs_text = None # Kill our 'vs' if its there. for team in self.teams: results.set_team_score(team, team.survival_seconds) diff --git a/plugins/utilities.json b/plugins/utilities.json index 701e5df..cee50f8 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -335,7 +335,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "0c5ce76", + "released_on": "02-07-2023", + "md5sum": "8b05407fda379d853f5c75677b19fd85" + }, "1.2.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -417,7 +422,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "bf3e61b", + "released_on": "04-07-2023", + "md5sum": "289cc852b7f0ec1b254d08267c9921c2" + }, "1.0.1": { "api_version": 7, "commit_sha": "64e8a5c", @@ -443,7 +453,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "0c5ce76", + "released_on": "02-07-2023", + "md5sum": "bb5d85fb528020e809eaebb17a388e32" + }, "1.0.0": { "api_version": 7, "commit_sha": "ff4de19", @@ -507,7 +522,12 @@ } ], "versions": { - "2.0.0":null, + "2.0.0": { + "api_version": 8, + "commit_sha": "a0239a9", + "released_on": "04-07-2023", + "md5sum": "187a9894158721c8fa1ecee9e3e38e73" + }, "1.0.0": { "api_version": 7, "commit_sha": "41e239c", diff --git a/plugins/utilities/character_chooser.py b/plugins/utilities/character_chooser.py index 9dbe733..da12dbb 100644 --- a/plugins/utilities/character_chooser.py +++ b/plugins/utilities/character_chooser.py @@ -55,7 +55,6 @@ from bascenev1 import _lobby from bascenev1lib.actor.spazappearance import * - def __init__(self, vpos: float, sessionplayer: bs.SessionPlayer, lobby: 'Lobby') -> None: self._deek_sound = bs.getsound('deek') @@ -113,25 +112,25 @@ def __init__(self, vpos: float, sessionplayer: bs.SessionPlayer, self._profilename = self._profilenames[self._profileindex] self._text_node = bs.newnode('text', - delegate=self, - attrs={ - 'position': (-100, self._vpos), - 'maxwidth': 190, - 'shadow': 0.5, - 'vr_depth': -20, - 'h_align': 'left', - 'v_align': 'center', - 'v_attach': 'top' - }) + delegate=self, + attrs={ + 'position': (-100, self._vpos), + 'maxwidth': 190, + 'shadow': 0.5, + 'vr_depth': -20, + 'h_align': 'left', + 'v_align': 'center', + 'v_attach': 'top' + }) bs.animate(self._text_node, 'scale', {0: 0, 0.1: 1.0}) self.icon = bs.newnode('image', - owner=self._text_node, - attrs={ - 'position': (-130, self._vpos + 20), - 'mask_texture': self._mask_texture, - 'vr_depth': -10, - 'attach': 'topCenter' - }) + owner=self._text_node, + attrs={ + 'position': (-130, self._vpos + 20), + 'mask_texture': self._mask_texture, + 'vr_depth': -10, + 'attach': 'topCenter' + }) bs.animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)}) diff --git a/plugins/utilities/easy_connect.py b/plugins/utilities/easy_connect.py index abd2f43..c925515 100644 --- a/plugins/utilities/easy_connect.py +++ b/plugins/utilities/easy_connect.py @@ -15,13 +15,13 @@ # .................___________________________________________ # Have any idea/suggestion/bug report > send message on discord mr.smoothy#5824 -# Download modshttps://bombsquad-community.web.app/mods +# Download modshttps://bombsquad-community.web.app/mods # Discord:- # mr.smoothy#5824 # DONT EDIT ANYTHING WITHOUT PERMISSION -# join Bombsquad Community Server - +# join Bombsquad Community Server - # https://discord.gg/ucyaesh @@ -73,7 +73,6 @@ def is_game_version_lower_than(version): return game_version < version - def updateBannedServersCache(): response = None config = babase.app.config @@ -112,7 +111,7 @@ class _HostLookupThread(threading.Thread): except Exception: result = None babase.pushcall(lambda: self._call(result, self._port), - from_other_thread=True) + from_other_thread=True) def newbuild_favorites_tab(self, region_height: float) -> None: @@ -148,45 +147,45 @@ def newbuild_favorites_tab(self, region_height: float) -> None: # ================= smoothy ============= bui.textwidget(parent=self._container, - position=(90 if uiscale is babase.UIScale.SMALL else 120, btnv + - 120 if uiscale is babase.UIScale.SMALL else btnv+90), - size=(0, 0), - h_align='center', - color=(0.8, 0.8, 0.8), - v_align='top', - text="Auto") + position=(90 if uiscale is babase.UIScale.SMALL else 120, btnv + + 120 if uiscale is babase.UIScale.SMALL else btnv+90), + size=(0, 0), + h_align='center', + color=(0.8, 0.8, 0.8), + v_align='top', + text="Auto") btnv += 50 if uiscale is babase.UIScale.SMALL else 0 bui.buttonwidget(parent=self._container, - size=(30, 30), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv+10), + size=(30, 30), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv+10), - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self.auto_retry_dec, - text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, - label="-", - autoselect=True) + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self.auto_retry_dec, + text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, + label="-", + autoselect=True) self.retry_inter_text = bui.textwidget(parent=self._container, - position=( - 90 if uiscale is babase.UIScale.SMALL else 120, btnv+25), - size=(0, 0), - h_align='center', - color=(0.8, 0.8, 0.8), - v_align='center', - text=str(self.retry_inter) if self.retry_inter > 0.0 else 'off') + position=( + 90 if uiscale is babase.UIScale.SMALL else 120, btnv+25), + size=(0, 0), + h_align='center', + color=(0.8, 0.8, 0.8), + v_align='center', + text=str(self.retry_inter) if self.retry_inter > 0.0 else 'off') bui.buttonwidget(parent=self._container, - size=(30, 30), - position=(125 if uiscale is babase.UIScale.SMALL else 155, - btnv+10), + size=(30, 30), + position=(125 if uiscale is babase.UIScale.SMALL else 155, + btnv+10), - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self.auto_retry_inc, - text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, - label="+", - autoselect=True) + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self.auto_retry_inc, + text_scale=1.3 if uiscale is babase.UIScale.SMALL else 1.2, + label="+", + autoselect=True) btnv -= b_height + b_space_extra @@ -203,31 +202,31 @@ def newbuild_favorites_tab(self, region_height: float) -> None: autoselect=True) if uiscale is babase.UIScale.SMALL and bui.app.ui_v1.use_toolbars: bui.widget(edit=btn1, - left_widget=bui.get_special_widget('back_button')) + left_widget=bui.get_special_widget('back_button')) btnv -= b_height + b_space_extra bui.buttonwidget(parent=self._container, - size=(b_width, b_height), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv), - button_type='square', - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self._on_favorites_edit_press, - text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, - label=babase.Lstr(resource='editText'), - autoselect=True) + size=(b_width, b_height), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorites_edit_press, + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='editText'), + autoselect=True) btnv -= b_height + b_space_extra bui.buttonwidget(parent=self._container, - size=(b_width, b_height), - position=(25 if uiscale is babase.UIScale.SMALL else 40, - btnv), - button_type='square', - color=(0.6, 0.53, 0.63), - textcolor=(0.75, 0.7, 0.8), - on_activate_call=self._on_favorite_delete_press, - text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, - label=babase.Lstr(resource='deleteText'), - autoselect=True) + size=(b_width, b_height), + position=(25 if uiscale is babase.UIScale.SMALL else 40, + btnv), + button_type='square', + color=(0.6, 0.53, 0.63), + textcolor=(0.75, 0.7, 0.8), + on_activate_call=self._on_favorite_delete_press, + text_scale=1.0 if uiscale is babase.UIScale.SMALL else 1.2, + label=babase.Lstr(resource='deleteText'), + autoselect=True) v -= sub_scroll_height + 23 self._scrollwidget = scrlw = bui.scrollwidget( @@ -236,12 +235,12 @@ def newbuild_favorites_tab(self, region_height: float) -> None: size=(sub_scroll_width, sub_scroll_height), claims_left_right=True) bui.widget(edit=self._favorites_connect_button, - right_widget=self._scrollwidget) + right_widget=self._scrollwidget) self._columnwidget = bui.columnwidget(parent=scrlw, - left_border=10, - border=2, - margin=0, - claims_left_right=True) + left_border=10, + border=2, + margin=0, + claims_left_right=True) self._favorite_selected = None self._refresh_favorites() @@ -323,9 +322,8 @@ def _clear(self) -> None: self._stats_button ]: if widget: - + widget.delete() - def update(self, index: int, party: PartyEntry, sub_scroll_width: float, @@ -333,127 +331,128 @@ def update(self, index: int, party: PartyEntry, sub_scroll_width: float, columnwidget: bui.Widget, join_text: bui.Widget, filter_text: bui.Widget, existing_selection: Optional[Selection], tab: PublicGatherTab) -> None: - """Update for the given data.""" - # pylint: disable=too-many-locals + """Update for the given data.""" + # pylint: disable=too-many-locals - # Quick-out: if we've been marked clean for a certain index and - # we're still at that index, we're done. - plus = bui.app.plus - assert plus is not None + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + plus = bui.app.plus + assert plus is not None - # Quick-out: if we've been marked clean for a certain index and - # we're still at that index, we're done. - if party.clean_display_index == index: - return + # Quick-out: if we've been marked clean for a certain index and + # we're still at that index, we're done. + if party.clean_display_index == index: + return - ping_good = plus.get_v1_account_misc_read_val('pingGood', 100) - ping_med = plus.get_v1_account_misc_read_val('pingMed', 500) + ping_good = plus.get_v1_account_misc_read_val('pingGood', 100) + ping_med = plus.get_v1_account_misc_read_val('pingMed', 500) - self._clear() - hpos = 20 - vpos = sub_scroll_height - lineheight * index - 50 - self._name_widget = bui.textwidget( - text=bui.Lstr(value=party.name), + self._clear() + hpos = 20 + vpos = sub_scroll_height - lineheight * index - 50 + self._name_widget = bui.textwidget( + text=bui.Lstr(value=party.name), + parent=columnwidget, + size=(sub_scroll_width * 0.63, 20), + position=(0 + hpos, 4 + vpos), + selectable=True, + on_select_call=bui.WeakCall( + tab.set_public_party_selection, + Selection(party.get_key(), SelectionComponent.NAME), + ), + on_activate_call=bui.WeakCall(tab.on_public_party_activate, party), + click_activate=True, + maxwidth=sub_scroll_width * 0.45, + corner_scale=1.4, + autoselect=True, + color=(1, 1, 1, 0.3 if party.ping is None else 1.0), + h_align='left', + v_align='center', + ) + bui.widget( + edit=self._name_widget, + left_widget=join_text, + show_buffer_top=64.0, + show_buffer_bottom=64.0, + ) + if existing_selection == Selection( + party.get_key(), SelectionComponent.NAME + ): + bui.containerwidget( + edit=columnwidget, selected_child=self._name_widget + ) + if party.stats_addr or True: + url = party.stats_addr.replace( + '${ACCOUNT}', + plus.get_v1_account_misc_read_val_2( + 'resolvedAccountID', 'UNKNOWN' + ), + ) + self._stats_button = bui.buttonwidget( + color=(0.3, 0.6, 0.94), + textcolor=(1.0, 1.0, 1.0), + label='....', parent=columnwidget, - size=(sub_scroll_width * 0.63, 20), - position=(0 + hpos, 4 + vpos), - selectable=True, + autoselect=True, + on_activate_call=bui.Call(bui.open_url, url), on_select_call=bui.WeakCall( tab.set_public_party_selection, - Selection(party.get_key(), SelectionComponent.NAME), + Selection(party.get_key(), SelectionComponent.STATS_BUTTON), ), - on_activate_call=bui.WeakCall(tab.on_public_party_activate, party), - click_activate=True, - maxwidth=sub_scroll_width * 0.45, - corner_scale=1.4, - autoselect=True, - color=(1, 1, 1, 0.3 if party.ping is None else 1.0), - h_align='left', - v_align='center', - ) - bui.widget( - edit=self._name_widget, - left_widget=join_text, - show_buffer_top=64.0, - show_buffer_bottom=64.0, + size=(120, 40), + position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), + scale=0.9, ) + bui.buttonwidget(edit=self._stats_button, on_activate_call=bui.WeakCall( + self.on_stats_click, self._stats_button, party)) if existing_selection == Selection( - party.get_key(), SelectionComponent.NAME + party.get_key(), SelectionComponent.STATS_BUTTON ): bui.containerwidget( - edit=columnwidget, selected_child=self._name_widget + edit=columnwidget, selected_child=self._stats_button ) - if party.stats_addr or True: - url = party.stats_addr.replace( - '${ACCOUNT}', - plus.get_v1_account_misc_read_val_2( - 'resolvedAccountID', 'UNKNOWN' - ), - ) - self._stats_button = bui.buttonwidget( - color=(0.3, 0.6, 0.94), - textcolor=(1.0, 1.0, 1.0), - label='....', - parent=columnwidget, - autoselect=True, - on_activate_call=bui.Call(bui.open_url, url), - on_select_call=bui.WeakCall( - tab.set_public_party_selection, - Selection(party.get_key(), SelectionComponent.STATS_BUTTON), - ), - size=(120, 40), - position=(sub_scroll_width * 0.66 + hpos, 1 + vpos), - scale=0.9, - ) - bui.buttonwidget(edit=self._stats_button, on_activate_call=bui.WeakCall( - self.on_stats_click, self._stats_button, party)) - if existing_selection == Selection( - party.get_key(), SelectionComponent.STATS_BUTTON - ): - bui.containerwidget( - edit=columnwidget, selected_child=self._stats_button - ) - self._size_widget = bui.textwidget( - text=str(party.size) + '/' + str(party.size_max), - parent=columnwidget, - size=(0, 0), - position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), - scale=0.7, - color=(0.8, 0.8, 0.8), - h_align='right', - v_align='center', + self._size_widget = bui.textwidget( + text=str(party.size) + '/' + str(party.size_max), + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.86 + hpos, 20 + vpos), + scale=0.7, + color=(0.8, 0.8, 0.8), + h_align='right', + v_align='center', + ) + + if index == 0: + bui.widget(edit=self._name_widget, up_widget=filter_text) + if self._stats_button: + bui.widget(edit=self._stats_button, up_widget=filter_text) + + self._ping_widget = bui.textwidget( + parent=columnwidget, + size=(0, 0), + position=(sub_scroll_width * 0.94 + hpos, 20 + vpos), + scale=0.7, + h_align='right', + v_align='center', + ) + if party.ping is None: + bui.textwidget( + edit=self._ping_widget, text='-', color=(0.5, 0.5, 0.5) + ) + else: + bui.textwidget( + edit=self._ping_widget, + text=str(int(party.ping)), + color=(0, 1, 0) + if party.ping <= ping_good + else (1, 1, 0) + if party.ping <= ping_med + else (1, 0, 0), ) - if index == 0: - bui.widget(edit=self._name_widget, up_widget=filter_text) - if self._stats_button: - bui.widget(edit=self._stats_button, up_widget=filter_text) + party.clean_display_index = index - self._ping_widget = bui.textwidget( - parent=columnwidget, - size=(0, 0), - position=(sub_scroll_width * 0.94 + hpos, 20 + vpos), - scale=0.7, - h_align='right', - v_align='center', - ) - if party.ping is None: - bui.textwidget( - edit=self._ping_widget, text='-', color=(0.5, 0.5, 0.5) - ) - else: - bui.textwidget( - edit=self._ping_widget, - text=str(int(party.ping)), - color=(0, 1, 0) - if party.ping <= ping_good - else (1, 1, 0) - if party.ping <= ping_med - else (1, 0, 0), - ) - - party.clean_display_index = index def _get_popup_window_scale() -> float: uiscale = bui.app.ui_v1.uiscale @@ -501,7 +500,7 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, url = _party.stats_addr.replace( '${ACCOUNT}', plus.get_v1_account_misc_read_val_2('resolvedAccountID', - 'UNKNOWN')) + 'UNKNOWN')) bui.open_url(url) elif choice == 'connect': PartyQuickConnect(_party.address, _party.port) @@ -614,17 +613,17 @@ class PartyQuickConnect(bui.Window): scale=(1.4 if uiscale is babase.UIScale.SMALL else 1.2 if uiscale is babase.UIScale.MEDIUM else 1.0))) self._cancel_button = bui.buttonwidget(parent=self._root_widget, - scale=1.0, - position=(60, self._height - 80), - size=(50, 50), - label='', - on_activate_call=self.close, - autoselect=True, - color=(0.45, 0.63, 0.15), - icon=bui.gettexture('crossOut'), - iconscale=1.2) + scale=1.0, + position=(60, self._height - 80), + size=(50, 50), + label='', + on_activate_call=self.close, + autoselect=True, + color=(0.45, 0.63, 0.15), + icon=bui.gettexture('crossOut'), + iconscale=1.2) bui.containerwidget(edit=self._root_widget, - cancel_button=self._cancel_button) + cancel_button=self._cancel_button) self.IP = bui.textwidget( parent=self._root_widget, diff --git a/plugins/utilities/pro_unlocker.py b/plugins/utilities/pro_unlocker.py index 389140f..bac3144 100644 --- a/plugins/utilities/pro_unlocker.py +++ b/plugins/utilities/pro_unlocker.py @@ -4,8 +4,23 @@ import _baplus import babase +def is_game_version_lower_than(version): + """ + Returns a boolean value indicating whether the current game + version is lower than the passed version. Useful for addressing + any breaking changes within game versions. + """ + game_version = tuple(map(int, babase.app.version.split("."))) + version = tuple(map(int, version.split("."))) + return game_version < version + + +if is_game_version_lower_than("1.7.20"): + original_get_purchased = _baplus.get_purchased +else: + assert bs.app.plus is not None + original_get_purchased = bs.app.plus.get_purchased -original_get_purchased = _baplus.get_purchased def get_purchased(item): if item.startswith('characters.') or item.startswith('icons.'): @@ -17,5 +32,8 @@ def get_purchased(item): class Unlock(babase.Plugin): def on_app_running(self): babase.app.classic.accounts.have_pro = lambda: True - _baplus.get_purchased = get_purchased - \ No newline at end of file + if is_game_version_lower_than("1.7.20"): + _baplus.get_purchased = get_purchased + else: + assert bs.app.plus is not None + bs.app.plus.get_purchased = get_purchased diff --git a/plugins/utilities/server_switch.py b/plugins/utilities/server_switch.py index ba4ffdc..aacb0fe 100644 --- a/plugins/utilities/server_switch.py +++ b/plugins/utilities/server_switch.py @@ -1,108 +1,575 @@ -# -*- coding: utf-8 -*- -# ba_meta require api 8 -''' -Server Switch Plugin by My.Smoothy -Let you switch recently joined servers very quickly -+ Added button to quicky look into public server list without leaving current game. +# discord @mr.smoothy#5824 + +# ba_meta require api 8 + +from __future__ import annotations +import copy +import time +from typing import TYPE_CHECKING -discord: mr.smoothy -https://discord.gg/ucyaesh -Youtube : Hey Smoothy -Download more mods from -https://bombsquad-community.web.app/mods -''' import babase -import bauiv1lib.mainmenu as bastd_ui_mainmenu import bauiv1 as bui import bascenev1 as bs -current_server_ip = "127.0.0.1" -current_server_port = 43210 -servers = [] -def _refresh_in_game(func): - def wrapper(self, *args, **kwargs): - returnValue = func(self, *args, **kwargs) - uiscale = bui.app.ui_v1.uiscale - bui.containerwidget( - edit=self._root_widget, - size=(self._width*2, self._height), # double the width - scale=( - 2.15 - if uiscale is bui.UIScale.SMALL - else 1.6 - if uiscale is bui.UIScale.MEDIUM - else 1.0 - ), - ) - h = 125 - v = self._height - 60.0 - bui.textwidget( +import _bascenev1 as _bs +import time +import threading +from enum import Enum +from dataclasses import dataclass +if TYPE_CHECKING: + from typing import Any, Optional, Dict, List, Tuple, Type + import bascenev1 as bs + from bauiv1lib.gather import GatherWindow + +from bauiv1lib.confirm import ConfirmWindow + +import bauiv1lib.mainmenu as bastd_ui_mainmenu + +connect = bs.connect_to_party +disconnect = bs.disconnect_from_host + +server = [] + +ip_add = "private" +p_port = 44444 +p_name = "nothing here" + + +def newconnect_to_party(address, port=43210, print_progress=False): + global ip_add + global p_port + dd = _bs.get_connection_to_host_info() + if (dd != {}): + _bs.disconnect_from_host() + + ip_add = address + p_port = port + connect(address, port, print_progress) + else: + + ip_add = address + p_port = port + # print(ip_add,p_port) + connect(ip_add, port, print_progress) + + +def newdisconnect_from_host(): + try: + name = _bs.get_connection_to_host_info()['name'] + global server + global ip_add + global p_port + pojo = {"name": name, "ip": ip_add, "port": p_port} + if pojo not in server: + server.insert(0, pojo) + server = server[:3] + except: + pass + disconnect() + + +def printip(): + bs.screenmessage("ip address is"+ip_add) + + +def new_refresh_in_game( + self, positions: List[Tuple[float, float, + float]]) -> Tuple[float, float, float]: + # pylint: disable=too-many-branches + # pylint: disable=too-many-locals + # pylint: disable=too-many-statements + custom_menu_entries: List[Dict[str, Any]] = [] + session = _bs.get_foreground_host_session() + if session is not None: + try: + custom_menu_entries = session.get_custom_menu_entries() + for cme in custom_menu_entries: + if (not isinstance(cme, dict) or 'label' not in cme + or not isinstance(cme['label'], (str, bs.Lstr)) + or 'call' not in cme or not callable(cme['call'])): + raise ValueError('invalid custom menu entry: ' + + str(cme)) + except Exception: + custom_menu_entries = [] + babase.print_exception( + f'Error getting custom menu entries for {session}') + self._width = 250.0 + self._height = 250.0 if self._input_player else 180.0 + if (self._is_demo or self._is_arcade) and self._input_player: + self._height -= 40 + if not self._have_settings_button: + self._height -= 50 + if self._connected_to_remote_player: + # In this case we have a leave *and* a disconnect button. + self._height += 50 + self._height += 50 * (len(custom_menu_entries)) + uiscale = bui.app.ui_v1.uiscale + bui.containerwidget( + edit=self._root_widget, + size=(self._width*2, self._height), + scale=(2.15 if uiscale is bui.UIScale.SMALL else + 1.6 if uiscale is bui.UIScale.MEDIUM else 1.0)) + h = 125.0 + v = (self._height - 80.0 if self._input_player else self._height - 60) + h_offset = 0 + d_h_offset = 0 + v_offset = -50 + for _i in range(6 + len(custom_menu_entries)): + positions.append((h, v, 1.0)) + v += v_offset + h += h_offset + h_offset += d_h_offset + self._start_button = None + bui.app.pause() + h, v, scale = positions[self._p_index] + bui.textwidget( parent=self._root_widget, draw_controller=None, - text="IP: "+current_server_ip+" PORT: "+str(current_server_port), - position=(h-self._button_width/2 + 130 , v+60), + text="IP: "+ip_add+" PORT: "+str(p_port), + position=(h+self._button_width-80, v+60), h_align='center', v_align='center', size=(20, 60), scale=0.6) - self._public_servers = bui.buttonwidget( - color=(0.8, 0.45, 1), - parent=self._root_widget, - position=(h+self._button_width-10, v+60+20), - size=(self._button_width/4, self._button_height/2), - scale=1.0, - autoselect=self._use_autoselect, - label="~~~", - on_activate_call=bs.Call(public_servers)) - for server in servers: - self._server_button = bui.buttonwidget( - color=(0.8, 0, 1), - parent=self._root_widget, - position=( (h- self._button_width / 2 ) + self._button_width + 20, v), - size=(self._button_width, self._button_height), - scale=1.0, - autoselect=self._use_autoselect, - label=server["name"][0:22], - on_activate_call=bs.Call(bs.connect_to_party, server["ip"], server["port"])) - - v -= 50 - - return returnValue - return wrapper + v_h = v -connect = bs.connect_to_party -def connect_to_party(address, port=43210, print_progress=False): - global current_server_ip - global current_server_port - if (bs.get_connection_to_host_info() != {}): - bs.disconnect_from_host() - current_server_ip = address - current_server_port = port - connect(address, port, print_progress) - babase.apptimer(1, check_connect_status) - -def check_connect_status(): - global servers - global current_server_ip - global current_server_port - if (bs.get_connection_to_host_info() != {}): - if (not bs.get_connection_to_host_info()['name']): - babase.apptimer(1, check_connect_status) - return - new_server = {"name": bs.get_connection_to_host_info()['name'], "ip": current_server_ip, "port": current_server_port} - if new_server not in servers: - servers.append(new_server) - servers = servers[-3:] + global server + + def con(address, port): + global ip_add + global p_port + if (address == ip_add and port == p_port): + self._resume() + else: + _bs.disconnect_from_host() + _bs.connect_to_party(address, port) + if len(server) == 0: + bui.textwidget( + parent=self._root_widget, + draw_controller=None, + text="Nothing in \n recents", + position=(h + self._button_width * scale, v-30), + h_align='center', + v_align='center', + size=(20, 60), + scale=1) + for ser in server: + self._server_button = bui.buttonwidget( + color=(0.8, 0, 1), + parent=self._root_widget, + position=(h + self._button_width * scale - 80, v_h), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=ser["name"][0:22], + + on_activate_call=bs.Call(con, ser["ip"], ser["port"])) + v_h = v_h-50 + + # Player name if applicable. + if self._input_player: + player_name = self._input_player.getname() + h, v, scale = positions[self._p_index] + v += 35 + bui.textwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + color=(1, 1, 1, 0.5), + scale=0.7, + h_align='center', + text=bs.Lstr(value=player_name)) else: - print("connection failed falling back to gather window") - public_servers() + player_name = '' + h, v, scale = positions[self._p_index] + self._p_index += 1 + btn = bui.buttonwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + scale=scale, + label=bs.Lstr(resource=self._r + '.resumeText'), + autoselect=self._use_autoselect, + on_activate_call=self._resume) + bui.containerwidget(edit=self._root_widget, cancel_button=btn) + + # Add any custom options defined by the current game. + for entry in custom_menu_entries: + h, v, scale = positions[self._p_index] + self._p_index += 1 + + # Ask the entry whether we should resume when we call + # it (defaults to true). + resume = bool(entry.get('resume_on_call', True)) + + if resume: + call = bs.Call(self._resume_and_call, entry['call']) + else: + call = bs.Call(entry['call'], bs.WeakCall(self._resume)) + + bui.buttonwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, self._button_height), + scale=scale, + on_activate_call=call, + label=entry['label'], + autoselect=self._use_autoselect) + # Add a 'leave' button if the menu-owner has a player. + if ((self._input_player or self._connected_to_remote_player) + and not (self._is_demo or self._is_arcade)): + h, v, scale = positions[self._p_index] + self._p_index += 1 + btn = bui.buttonwidget(parent=self._root_widget, + position=(h - self._button_width / 2, v), + size=(self._button_width, + self._button_height), + scale=scale, + on_activate_call=self._leave, + label='', + autoselect=self._use_autoselect) + + if (player_name != '' and player_name[0] != '<' + and player_name[-1] != '>'): + txt = bs.Lstr(resource=self._r + '.justPlayerText', + subs=[('${NAME}', player_name)]) + else: + txt = bs.Lstr(value=player_name) + bui.textwidget(parent=self._root_widget, + position=(h, v + self._button_height * + (0.64 if player_name != '' else 0.5)), + size=(0, 0), + text=bs.Lstr(resource=self._r + '.leaveGameText'), + scale=(0.83 if player_name != '' else 1.0), + color=(0.75, 1.0, 0.7), + h_align='center', + v_align='center', + draw_controller=btn, + maxwidth=self._button_width * 0.9) + bui.textwidget(parent=self._root_widget, + position=(h, v + self._button_height * 0.27), + size=(0, 0), + text=txt, + color=(0.75, 1.0, 0.7), + h_align='center', + v_align='center', + draw_controller=btn, + scale=0.45, + maxwidth=self._button_width * 0.9) + return h, v, scale + + +def new_refresh(self) -> None: + # pylint: disable=too-many-branches + # pylint: disable=too-many-locals + # pylint: disable=too-many-statements + global server + print(server) + from bauiv1lib.confirm import QuitWindow + from bauiv1lib.store.button import StoreButton + import bascenev1 as bs + import _bascenev1 as _bs + import bauiv1 as bui + import _baplus + # Clear everything that was there. + children = self._root_widget.get_children() + for child in children: + child.delete() + + self._tdelay = 0.0 + self._t_delay_inc = 0.0 + self._t_delay_play = 0.0 + self._button_width = 200.0 + self._button_height = 45.0 + + self._r = 'mainMenu' + + assert bs.app.classic is not None + app = bs.app.classic + self._have_quit_button = (bui.app.ui_v1.uiscale is bui.UIScale.LARGE + or (app.platform == 'windows' + and app.subplatform == 'oculus')) + + self._have_store_button = not self._in_game + + self._have_settings_button = ( + (not self._in_game or not bui.app.toolbar_test) + and not (self._is_demo or self._is_arcade or self._is_iircade)) + + self._input_device = input_device = _bs.get_ui_input_device() + self._input_player = input_device.player if input_device else None + self._connected_to_remote_player = ( + input_device.is_attached_to_player() + if input_device else False) + + positions: List[Tuple[float, float, float]] = [] + self._p_index = 0 + + if self._in_game: + h, v, scale = self._refresh_in_game(positions) + print("refreshing in GAME", ip_add) + # btn = bui.buttonwidget(parent=self._root_widget, + # position=(80,270), + # size=(100, 90), + # scale=1.2, + # label=ip_add, + # autoselect=None, + # on_activate_call=printip) + bui.textwidget( + parent=self._root_widget, + draw_controller=None, + text="IP: "+ip_add+" PORT: "+str(p_port), + position=(150, 270), + h_align='center', + v_align='center', + size=(20, 60), + scale=1) + self._server_button = bui.buttonwidget( + parent=self._root_widget, + position=(h * 3.2 + 20 - self._button_width * scale, v), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=bs.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + self._server_button2 = bui.buttonwidget( + parent=self._root_widget, + position=(h * 3.2 + 20 - self._button_width * scale, v-50), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=bs.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + self._server_button3 = bui.buttonwidget( + parent=self._root_widget, + position=(h * 3.2 + 20 - self._button_width * scale, v-100), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=bs.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + + else: + h, v, scale = self._refresh_not_in_game(positions) + + if self._have_settings_button: + h, v, scale = positions[self._p_index] + self._p_index += 1 + self._settings_button = bui.buttonwidget( + parent=self._root_widget, + position=(h - self._button_width * 0.5 * scale, v), + size=(self._button_width, self._button_height), + scale=scale, + autoselect=self._use_autoselect, + label=bs.Lstr(resource=self._r + '.settingsText'), + transition_delay=self._tdelay, + on_activate_call=self._settings) + + # Scattered eggs on easter. + if _baplus.get_v1_account_misc_read_val('easter', + False) and not self._in_game: + icon_size = 34 + bui.imagewidget(parent=self._root_widget, + position=(h - icon_size * 0.5 - 15, + v + self._button_height * scale - + icon_size * 0.24 + 1.5), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=bui.gettexture('egg3'), + tilt_scale=0.0) + + self._tdelay += self._t_delay_inc + + if self._in_game: + h, v, scale = positions[self._p_index] + self._p_index += 1 + + # If we're in a replay, we have a 'Leave Replay' button. + if _bs.is_in_replay(): + bui.buttonwidget(parent=self._root_widget, + position=(h - self._button_width * 0.5 * scale, + v), + scale=scale, + size=(self._button_width, self._button_height), + autoselect=self._use_autoselect, + label=bs.Lstr(resource='replayEndText'), + on_activate_call=self._confirm_end_replay) + elif _bs.get_foreground_host_session() is not None: + bui.buttonwidget( + parent=self._root_widget, + position=(h - self._button_width * 0.5 * scale, v), + scale=scale, + size=(self._button_width, self._button_height), + autoselect=self._use_autoselect, + label=bs.Lstr(resource=self._r + '.endGameText'), + on_activate_call=self._confirm_end_game) + # Assume we're in a client-session. + else: + bui.buttonwidget( + parent=self._root_widget, + position=(h - self._button_width * 0.5 * scale, v), + scale=scale, + size=(self._button_width, self._button_height), + autoselect=self._use_autoselect, + label=bs.Lstr(resource=self._r + '.leavePartyText'), + on_activate_call=self._confirm_leave_party) + + self._store_button: Optional[bui.Widget] + if self._have_store_button: + this_b_width = self._button_width + h, v, scale = positions[self._p_index] + self._p_index += 1 + + sbtn = self._store_button_instance = StoreButton( + parent=self._root_widget, + position=(h - this_b_width * 0.5 * scale, v), + size=(this_b_width, self._button_height), + scale=scale, + on_activate_call=bs.WeakCall(self._on_store_pressed), + sale_scale=1.3, + transition_delay=self._tdelay) + self._store_button = store_button = sbtn.get_button() + uiscale = bui.app.ui_v1.uiscale + icon_size = (55 if uiscale is bui.UIScale.SMALL else + 55 if uiscale is bui.UIScale.MEDIUM else 70) + bui.imagewidget( + parent=self._root_widget, + position=(h - icon_size * 0.5, + v + self._button_height * scale - icon_size * 0.23), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=bui.gettexture(self._store_char_tex), + tilt_scale=0.0, + draw_controller=store_button) + + self._tdelay += self._t_delay_inc + else: + self._store_button = None + + self._quit_button: Optional[bui.Widget] + if not self._in_game and self._have_quit_button: + h, v, scale = positions[self._p_index] + self._p_index += 1 + self._quit_button = quit_button = bui.buttonwidget( + parent=self._root_widget, + autoselect=self._use_autoselect, + position=(h - self._button_width * 0.5 * scale, v), + size=(self._button_width, self._button_height), + scale=scale, + label=bs.Lstr(resource=self._r + + ('.quitText' if 'Mac' in + bs.app.classic.legacy_user_agent_string else '.exitGameText')), + on_activate_call=self._quit, + transition_delay=self._tdelay) + + # Scattered eggs on easter. + if _baplus.get_v1_account_misc_read_val('easter', False): + icon_size = 30 + bui.imagewidget(parent=self._root_widget, + position=(h - icon_size * 0.5 + 25, + v + self._button_height * scale - + icon_size * 0.24 + 1.5), + transition_delay=self._tdelay, + size=(icon_size, icon_size), + texture=bui.gettexture('egg1'), + tilt_scale=0.0) + + bui.containerwidget(edit=self._root_widget, + cancel_button=quit_button) + self._tdelay += self._t_delay_inc + else: + self._quit_button = None + + # If we're not in-game, have no quit button, and this is android, + # we want back presses to quit our activity. + if (not self._in_game and not self._have_quit_button + and bs.app.classic.platform == 'android'): + + def _do_quit() -> None: + QuitWindow(swish=True, back=True) + + bui.containerwidget(edit=self._root_widget, + on_cancel_call=_do_quit) + + # Add speed-up/slow-down buttons for replays. + # (ideally this should be part of a fading-out playback bar like most + # media players but this works for now). + if _bs.is_in_replay(): + b_size = 50.0 + b_buffer = 10.0 + t_scale = 0.75 + uiscale = bui.app.ui_v1.uiscale + if uiscale is bui.UIScale.SMALL: + b_size *= 0.6 + b_buffer *= 1.0 + v_offs = -40 + t_scale = 0.5 + elif uiscale is bui.UIScale.MEDIUM: + v_offs = -70 + else: + v_offs = -100 + self._replay_speed_text = bui.textwidget( + parent=self._root_widget, + text=bs.Lstr(resource='watchWindow.playbackSpeedText', + subs=[('${SPEED}', str(1.23))]), + position=(h, v + v_offs + 7 * t_scale), + h_align='center', + v_align='center', + size=(0, 0), + scale=t_scale) + + # Update to current value. + self._change_replay_speed(0) + + # Keep updating in a timer in case it gets changed elsewhere. + self._change_replay_speed_timer = bs.Timer( + 0.25, + bs.WeakCall(self._change_replay_speed, 0), + repeat=True) + btn = bui.buttonwidget(parent=self._root_widget, + position=(h - b_size - b_buffer, + v - b_size - b_buffer + v_offs), + button_type='square', + size=(b_size, b_size), + label='', + autoselect=True, + on_activate_call=bs.Call( + self._change_replay_speed, -1)) + bui.textwidget( + parent=self._root_widget, + draw_controller=btn, + text='-', + position=(h - b_size * 0.5 - b_buffer, + v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), + h_align='center', + v_align='center', + size=(0, 0), + scale=3.0 * t_scale) + btn = bui.buttonwidget( + parent=self._root_widget, + position=(h + b_buffer, v - b_size - b_buffer + v_offs), + button_type='square', + size=(b_size, b_size), + label='', + autoselect=True, + on_activate_call=bs.Call(self._change_replay_speed, 1)) + bui.textwidget( + parent=self._root_widget, + draw_controller=btn, + text='+', + position=(h + b_size * 0.5 + b_buffer, + v - b_size * 0.5 - b_buffer + 5 * t_scale + v_offs), + h_align='center', + v_align='center', + size=(0, 0), + scale=3.0 * t_scale) -def public_servers(origin = None): - from bauiv1lib.gather import GatherWindow - bui.app.ui_v1.set_main_menu_window( GatherWindow(origin_widget=origin).get_root_widget()) # ba_meta export plugin class bySmoothy(babase.Plugin): def __init__(self): - bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = _refresh_in_game(bastd_ui_mainmenu.MainMenuWindow._refresh_in_game) - bs.connect_to_party = connect_to_party - \ No newline at end of file + if babase.env().get("build_number", 0) >= 21140: + bastd_ui_mainmenu.MainMenuWindow._refresh_in_game = new_refresh_in_game + bs.connect_to_party = newconnect_to_party + bs.disconnect_from_host = newdisconnect_from_host + else: + print("Server Switch only works on bs 1.7.20 and above")