mirror of
https://github.com/bombsquad-community/plugin-manager.git
synced 2025-11-07 17:36:00 +00:00
commit
a53477ff02
12 changed files with 1436 additions and 1274 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -11,7 +11,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ["3.10"]
|
python-version: ["3.11"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,13 @@
|
||||||
## Plugin Manager (dd-mm-yyyy)
|
## Plugin Manager (dd-mm-yyyy)
|
||||||
|
|
||||||
|
### 1.0.1 (30-06-2023)
|
||||||
|
|
||||||
|
- Allow specifying branch names in custom sources.
|
||||||
|
|
||||||
|
### 1.0.0 (20-06-2023)
|
||||||
|
|
||||||
|
- Migrate plugin manager's source code to API 8.
|
||||||
|
|
||||||
### 0.3.5 (16-06-2023)
|
### 0.3.5 (16-06-2023)
|
||||||
|
|
||||||
- Replace the "Loading..." text with the exception message in case something goes wrong.
|
- Replace the "Loading..." text with the exception message in case something goes wrong.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
[](https://github.com/bombsquad-community/plugin-manager/actions/workflows/ci.yml)
|
[](https://github.com/bombsquad-community/plugin-manager/actions/workflows/ci.yml)
|
||||||
|
|
||||||
|
**Important:** Please check out the [api7](https://github.com/bombsquad-community/plugin-manager/tree/api7) branch if you're
|
||||||
|
using the game version (1.7.0 <= your game version <= 1.7.19) which uses API 7 plugins.
|
||||||
|
If you're on game version (1.7.20 or a later version) where it uses API 8 plugins, then proceed with the rest of the
|
||||||
|
README here.
|
||||||
|
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
# plugin-manager
|
# plugin-manager
|
||||||
|
|
||||||
A plugin manager for the game - [Bombsquad](https://www.froemling.net/apps/bombsquad). Plugin manager is a plugin in itself,
|
A plugin manager for the game - [Bombsquad](https://www.froemling.net/apps/bombsquad). Plugin manager is a plugin in itself,
|
||||||
|
|
@ -177,6 +184,8 @@ That's it! Now you can make a [pull request](../../compare) with both the update
|
||||||
- Check out [bombsquad-community/sample-plugin-source](https://github.com/bombsquad-community/sample-plugin-source) as an example.
|
- Check out [bombsquad-community/sample-plugin-source](https://github.com/bombsquad-community/sample-plugin-source) as an example.
|
||||||
You can choose to show up plugins from this repository in your plugin manager by adding `bombsquad-community/sample-plugin-source`
|
You can choose to show up plugins from this repository in your plugin manager by adding `bombsquad-community/sample-plugin-source`
|
||||||
as a custom source through the category selection popup window in-game.
|
as a custom source through the category selection popup window in-game.
|
||||||
|
- Plugin manager will default to picking up plugins from the `main` branch of the custom source repository. You
|
||||||
|
can specify a different branch by suffixing the source URI with `@branchname`, such as `bombsquad-community/sample-plugin-source@experimental`.
|
||||||
|
|
||||||
#### Known 3rd Party Plugin Sources
|
#### Known 3rd Party Plugin Sources
|
||||||
|
|
||||||
|
|
|
||||||
12
index.json
12
index.json
|
|
@ -1,6 +1,18 @@
|
||||||
{
|
{
|
||||||
"plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py",
|
"plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py",
|
||||||
"versions": {
|
"versions": {
|
||||||
|
"1.0.1": {
|
||||||
|
"api_version": 8,
|
||||||
|
"commit_sha": "e31a789",
|
||||||
|
"released_on": "29-06-2023",
|
||||||
|
"md5sum": "e54913a789a31f60f18ef24edbfdd130"
|
||||||
|
},
|
||||||
|
"1.0.0": {
|
||||||
|
"api_version": 8,
|
||||||
|
"commit_sha": "0b55bc2",
|
||||||
|
"released_on": "20-06-2023",
|
||||||
|
"md5sum": "98fa2f29c3a2d34b5ff53b7abde7ec64"
|
||||||
|
},
|
||||||
"0.3.5": {
|
"0.3.5": {
|
||||||
"api_version": 7,
|
"api_version": 7,
|
||||||
"commit_sha": "985e486",
|
"commit_sha": "985e486",
|
||||||
|
|
|
||||||
1871
plugin_manager.py
1871
plugin_manager.py
File diff suppressed because it is too large
Load diff
|
|
@ -266,6 +266,12 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": {
|
"versions": {
|
||||||
|
"1.1.0": {
|
||||||
|
"api_version": 8,
|
||||||
|
"commit_sha": "0069f15",
|
||||||
|
"released_on": "08-06-2023",
|
||||||
|
"md5sum": "b8168bd3e6fae96b9339a727bd50842f"
|
||||||
|
},
|
||||||
"1.0.0": {
|
"1.0.0": {
|
||||||
"api_version": 7,
|
"api_version": 7,
|
||||||
"commit_sha": "095a773",
|
"commit_sha": "095a773",
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -223,6 +223,12 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": {
|
"versions": {
|
||||||
|
"2.0.0": {
|
||||||
|
"api_version": 8,
|
||||||
|
"commit_sha": "0b55bc2",
|
||||||
|
"released_on": "20-06-2023",
|
||||||
|
"md5sum": "517fec3938f31627c1cfd2126f1ee9da"
|
||||||
|
},
|
||||||
"1.2.3": {
|
"1.2.3": {
|
||||||
"api_version": 7,
|
"api_version": 7,
|
||||||
"commit_sha": "7753b87",
|
"commit_sha": "7753b87",
|
||||||
|
|
@ -694,6 +700,12 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": {
|
"versions": {
|
||||||
|
"1.1.0": {
|
||||||
|
"api_version": 8,
|
||||||
|
"commit_sha": "5fb8195",
|
||||||
|
"released_on": "28-06-2023",
|
||||||
|
"md5sum": "f6c1105b34d0426327688841d7e89bb9"
|
||||||
|
},
|
||||||
"1.0.1": {
|
"1.0.1": {
|
||||||
"api_version": 7,
|
"api_version": 7,
|
||||||
"commit_sha": "3ef572f",
|
"commit_sha": "3ef572f",
|
||||||
|
|
|
||||||
|
|
@ -6,39 +6,21 @@
|
||||||
# Settings -> Advanced -> Enter Code
|
# Settings -> Advanced -> Enter Code
|
||||||
# to bring up the colorscheme UI.
|
# to bring up the colorscheme UI.
|
||||||
|
|
||||||
# ba_meta require api 7
|
# ba_meta require api 8
|
||||||
import _ba
|
import _babase
|
||||||
import ba
|
import babase
|
||||||
|
import bauiv1 as bui
|
||||||
|
|
||||||
from bastd.ui.colorpicker import ColorPicker
|
from bauiv1lib.colorpicker import ColorPicker
|
||||||
|
|
||||||
original_buttonwidget = ba.buttonwidget
|
original_buttonwidget = bui.buttonwidget
|
||||||
original_containerwidget = ba.containerwidget
|
original_containerwidget = bui.containerwidget
|
||||||
original_checkboxwidget = ba.checkboxwidget
|
original_checkboxwidget = bui.checkboxwidget
|
||||||
# We set this later so we store the overridden method in case the
|
# We set this later so we store the overridden method in case the
|
||||||
# player is using pro-unlocker plugins that override the
|
# player is using pro-unlocker plugins that override the
|
||||||
# `ba.app.accounts.have_pro` method.
|
# `bui.app.classic.accounts.have_pro` method.
|
||||||
original_have_pro = None
|
original_have_pro = None
|
||||||
|
original_add_transaction = bui.app.plus.add_v1_account_transaction
|
||||||
|
|
||||||
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, ba.app.version.split(".")))
|
|
||||||
version = tuple(map(int, version.split(".")))
|
|
||||||
return game_version < version
|
|
||||||
|
|
||||||
|
|
||||||
# Adds backward compatibility for a breaking change released in
|
|
||||||
# game version 1.7.7, which moves `_ba.add_transaction` to
|
|
||||||
# `ba.internal.add_transaction`.
|
|
||||||
if is_game_version_lower_than("1.7.7"):
|
|
||||||
original_add_transaction = _ba.add_transaction
|
|
||||||
else:
|
|
||||||
original_add_transaction = ba.internal.add_transaction
|
|
||||||
|
|
||||||
|
|
||||||
class ColorScheme:
|
class ColorScheme:
|
||||||
|
|
@ -61,24 +43,24 @@ class ColorScheme:
|
||||||
--------
|
--------
|
||||||
+ Apply dark colorscheme:
|
+ Apply dark colorscheme:
|
||||||
|
|
||||||
>>> import _ba
|
>>> import _babase
|
||||||
>>> dark = _ba.ColorScheme((0.2,0.2,0.2), (0.8,0.8,0.8))
|
>>> dark = _babase.ColorScheme((0.2,0.2,0.2), (0.8,0.8,0.8))
|
||||||
>>> dark.apply()
|
>>> dark.apply()
|
||||||
# Reset back to game's default colorscheme
|
# Reset back to game's default colorscheme
|
||||||
>>> dark.disable()
|
>>> dark.disable()
|
||||||
|
|
||||||
+ Colorscheme that modifies only the main colors:
|
+ Colorscheme that modifies only the main colors:
|
||||||
|
|
||||||
>>> import _ba
|
>>> import _babase
|
||||||
>>> bluey = _ba.ColorScheme(color=(0.1,0.3,0.6))
|
>>> bluey = _babase.ColorScheme(color=(0.1,0.3,0.6))
|
||||||
>>> bluey.apply()
|
>>> bluey.apply()
|
||||||
# Reset back to game's default colorscheme
|
# Reset back to game's default colorscheme
|
||||||
>>> bluey.disable()
|
>>> bluey.disable()
|
||||||
|
|
||||||
+ Colorscheme that modifies only the highlight colors:
|
+ Colorscheme that modifies only the highlight colors:
|
||||||
|
|
||||||
>>> import _ba
|
>>> import _babase
|
||||||
>>> reddish = _ba.ColorScheme(highlight=(0.8,0.35,0.35))
|
>>> reddish = _babase.ColorScheme(highlight=(0.8,0.35,0.35))
|
||||||
>>> reddish.apply()
|
>>> reddish.apply()
|
||||||
# Reset back to game's default colorscheme
|
# Reset back to game's default colorscheme
|
||||||
>>> reddish.disable()
|
>>> reddish.disable()
|
||||||
|
|
@ -86,8 +68,8 @@ class ColorScheme:
|
||||||
+ Revert back to game's default colorscheme irrespective of
|
+ Revert back to game's default colorscheme irrespective of
|
||||||
whatever colorscheme is active at the moment:
|
whatever colorscheme is active at the moment:
|
||||||
|
|
||||||
>>> import _ba
|
>>> import _babase
|
||||||
>>> _ba.ColorScheme.disable()
|
>>> _babase.ColorScheme.disable()
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, color=None, highlight=None):
|
def __init__(self, color=None, highlight=None):
|
||||||
|
|
@ -112,13 +94,13 @@ class ColorScheme:
|
||||||
def _apply_color(self):
|
def _apply_color(self):
|
||||||
if self.color is None:
|
if self.color is None:
|
||||||
raise TypeError("Expected color to be an (R,G,B) tuple.")
|
raise TypeError("Expected color to be an (R,G,B) tuple.")
|
||||||
ba.containerwidget = self._custom_containerwidget
|
bui.containerwidget = self._custom_containerwidget
|
||||||
|
|
||||||
def _apply_highlight(self):
|
def _apply_highlight(self):
|
||||||
if self.highlight is None:
|
if self.highlight is None:
|
||||||
raise TypeError("Expected highlight to be an (R,G,B) tuple.")
|
raise TypeError("Expected highlight to be an (R,G,B) tuple.")
|
||||||
ba.buttonwidget = self._custom_buttonwidget
|
bui.buttonwidget = self._custom_buttonwidget
|
||||||
ba.checkboxwidget = self._custom_checkboxwidget
|
bui.checkboxwidget = self._custom_checkboxwidget
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
if self.color:
|
if self.color:
|
||||||
|
|
@ -128,12 +110,12 @@ class ColorScheme:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _disable_color():
|
def _disable_color():
|
||||||
ba.buttonwidget = original_buttonwidget
|
bui.buttonwidget = original_buttonwidget
|
||||||
ba.checkboxwidget = original_checkboxwidget
|
bui.checkboxwidget = original_checkboxwidget
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _disable_highlight():
|
def _disable_highlight():
|
||||||
ba.containerwidget = original_containerwidget
|
bui.containerwidget = original_containerwidget
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def disable(cls):
|
def disable(cls):
|
||||||
|
|
@ -141,10 +123,10 @@ class ColorScheme:
|
||||||
cls._disable_highlight()
|
cls._disable_highlight()
|
||||||
|
|
||||||
|
|
||||||
class ColorSchemeWindow(ba.Window):
|
class ColorSchemeWindow(bui.Window):
|
||||||
def __init__(self, default_colors=((0.41, 0.39, 0.5), (0.5, 0.7, 0.25))):
|
def __init__(self, default_colors=((0.41, 0.39, 0.5), (0.5, 0.7, 0.25))):
|
||||||
self._default_colors = default_colors
|
self._default_colors = default_colors
|
||||||
self._color, self._highlight = ba.app.config.get("ColorScheme", (None, None))
|
self._color, self._highlight = babase.app.config.get("ColorScheme", (None, None))
|
||||||
|
|
||||||
self._last_color = self._color
|
self._last_color = self._color
|
||||||
self._last_highlight = self._highlight
|
self._last_highlight = self._highlight
|
||||||
|
|
@ -157,88 +139,88 @@ class ColorSchemeWindow(ba.Window):
|
||||||
|
|
||||||
# A hack to let players select any RGB color value through the UI,
|
# A hack to let players select any RGB color value through the UI,
|
||||||
# otherwise this is limited only to pro accounts.
|
# otherwise this is limited only to pro accounts.
|
||||||
ba.app.accounts_v1.have_pro = lambda: True
|
bui.app.classic.accounts.have_pro = lambda: True
|
||||||
|
|
||||||
self.draw_ui()
|
self.draw_ui()
|
||||||
|
|
||||||
def draw_ui(self):
|
def draw_ui(self):
|
||||||
# Most of the stuff here for drawing the UI is referred from the
|
# NOTE: Most of the stuff here for drawing the UI is referred from the
|
||||||
# game's bastd/ui/profile/edit.py, and so there could be some
|
# legacy (1.6 < version <= 1.7.19) game's bastd/ui/profile/edit.py, and
|
||||||
# cruft here due to my oversight.
|
# so there could be some cruft here due to my oversight.
|
||||||
uiscale = ba.app.ui.uiscale
|
uiscale = bui.app.ui_v1.uiscale
|
||||||
self._width = width = 480.0 if uiscale is ba.UIScale.SMALL else 380.0
|
self._width = width = 480.0 if uiscale is babase.UIScale.SMALL else 380.0
|
||||||
self._x_inset = x_inset = 40.0 if uiscale is ba.UIScale.SMALL else 0.0
|
self._x_inset = x_inset = 40.0 if uiscale is babase.UIScale.SMALL else 0.0
|
||||||
self._height = height = (
|
self._height = height = (
|
||||||
275.0
|
275.0
|
||||||
if uiscale is ba.UIScale.SMALL
|
if uiscale is babase.UIScale.SMALL
|
||||||
else 288.0
|
else 288.0
|
||||||
if uiscale is ba.UIScale.MEDIUM
|
if uiscale is babase.UIScale.MEDIUM
|
||||||
else 300.0
|
else 300.0
|
||||||
)
|
)
|
||||||
spacing = 40
|
spacing = 40
|
||||||
self._base_scale = (
|
self._base_scale = (
|
||||||
2.05
|
2.05
|
||||||
if uiscale is ba.UIScale.SMALL
|
if uiscale is babase.UIScale.SMALL
|
||||||
else 1.5
|
else 1.5
|
||||||
if uiscale is ba.UIScale.MEDIUM
|
if uiscale is babase.UIScale.MEDIUM
|
||||||
else 1.0
|
else 1.0
|
||||||
)
|
)
|
||||||
top_extra = 15
|
top_extra = 15
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
root_widget=ba.containerwidget(
|
root_widget=bui.containerwidget(
|
||||||
size=(width, height + top_extra),
|
size=(width, height + top_extra),
|
||||||
on_outside_click_call=self.cancel_on_outside_click,
|
on_outside_click_call=self.cancel_on_outside_click,
|
||||||
transition="in_right",
|
transition="in_right",
|
||||||
scale=self._base_scale,
|
scale=self._base_scale,
|
||||||
stack_offset=(0, 15) if uiscale is ba.UIScale.SMALL else (0, 0),
|
stack_offset=(0, 15) if uiscale is babase.UIScale.SMALL else (0, 0),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
cancel_button = ba.buttonwidget(
|
cancel_button = bui.buttonwidget(
|
||||||
parent=self._root_widget,
|
parent=self._root_widget,
|
||||||
position=(52 + x_inset, height - 60),
|
position=(52 + x_inset, height - 60),
|
||||||
size=(155, 60),
|
size=(155, 60),
|
||||||
scale=0.8,
|
scale=0.8,
|
||||||
autoselect=True,
|
autoselect=True,
|
||||||
label=ba.Lstr(resource="cancelText"),
|
label=babase.Lstr(resource="cancelText"),
|
||||||
on_activate_call=self._cancel,
|
on_activate_call=self._cancel,
|
||||||
)
|
)
|
||||||
ba.containerwidget(edit=self._root_widget, cancel_button=cancel_button)
|
bui.containerwidget(edit=self._root_widget, cancel_button=cancel_button)
|
||||||
|
|
||||||
save_button = ba.buttonwidget(
|
save_button = bui.buttonwidget(
|
||||||
parent=self._root_widget,
|
parent=self._root_widget,
|
||||||
position=(width - (177 + x_inset), height - 110),
|
position=(width - (177 + x_inset), height - 110),
|
||||||
size=(155, 60),
|
size=(155, 60),
|
||||||
autoselect=True,
|
autoselect=True,
|
||||||
scale=0.8,
|
scale=0.8,
|
||||||
label=ba.Lstr(resource="saveText"),
|
label=babase.Lstr(resource="saveText"),
|
||||||
)
|
)
|
||||||
ba.widget(edit=save_button, left_widget=cancel_button)
|
bui.widget(edit=save_button, left_widget=cancel_button)
|
||||||
ba.buttonwidget(edit=save_button, on_activate_call=self.save)
|
bui.buttonwidget(edit=save_button, on_activate_call=self.save)
|
||||||
ba.widget(edit=cancel_button, right_widget=save_button)
|
bui.widget(edit=cancel_button, right_widget=save_button)
|
||||||
ba.containerwidget(edit=self._root_widget, start_button=save_button)
|
bui.containerwidget(edit=self._root_widget, start_button=save_button)
|
||||||
|
|
||||||
reset_button = ba.buttonwidget(
|
reset_button = bui.buttonwidget(
|
||||||
parent=self._root_widget,
|
parent=self._root_widget,
|
||||||
position=(width - (177 + x_inset), height - 60),
|
position=(width - (177 + x_inset), height - 60),
|
||||||
size=(155, 60),
|
size=(155, 60),
|
||||||
color=(0.2, 0.5, 0.6),
|
color=(0.2, 0.5, 0.6),
|
||||||
autoselect=True,
|
autoselect=True,
|
||||||
scale=0.8,
|
scale=0.8,
|
||||||
label=ba.Lstr(resource="settingsWindowAdvanced.resetText"),
|
label=babase.Lstr(resource="settingsWindowAdvanced.resetText"),
|
||||||
)
|
)
|
||||||
ba.widget(edit=reset_button, left_widget=reset_button)
|
bui.widget(edit=reset_button, left_widget=reset_button)
|
||||||
ba.buttonwidget(edit=reset_button, on_activate_call=self.reset)
|
bui.buttonwidget(edit=reset_button, on_activate_call=self.reset)
|
||||||
ba.widget(edit=cancel_button, right_widget=reset_button)
|
bui.widget(edit=cancel_button, right_widget=reset_button)
|
||||||
ba.containerwidget(edit=self._root_widget, start_button=reset_button)
|
bui.containerwidget(edit=self._root_widget, start_button=reset_button)
|
||||||
|
|
||||||
v = height - 65.0
|
v = height - 65.0
|
||||||
v -= spacing * 3.0
|
v -= spacing * 3.0
|
||||||
b_size = 80
|
b_size = 80
|
||||||
b_offs = 75
|
b_offs = 75
|
||||||
|
|
||||||
self._color_button = ba.buttonwidget(
|
self._color_button = bui.buttonwidget(
|
||||||
parent=self._root_widget,
|
parent=self._root_widget,
|
||||||
autoselect=True,
|
autoselect=True,
|
||||||
position=(self._width * 0.5 - b_offs - b_size * 0.5, v - 50),
|
position=(self._width * 0.5 - b_offs - b_size * 0.5, v - 50),
|
||||||
|
|
@ -247,23 +229,23 @@ class ColorSchemeWindow(ba.Window):
|
||||||
label="",
|
label="",
|
||||||
button_type="square",
|
button_type="square",
|
||||||
)
|
)
|
||||||
ba.buttonwidget(
|
bui.buttonwidget(
|
||||||
edit=self._color_button, on_activate_call=ba.Call(self._pick_color, "color")
|
edit=self._color_button, on_activate_call=babase.Call(self._pick_color, "color")
|
||||||
)
|
)
|
||||||
ba.textwidget(
|
bui.textwidget(
|
||||||
parent=self._root_widget,
|
parent=self._root_widget,
|
||||||
h_align="center",
|
h_align="center",
|
||||||
v_align="center",
|
v_align="center",
|
||||||
position=(self._width * 0.5 - b_offs, v - 65),
|
position=(self._width * 0.5 - b_offs, v - 65),
|
||||||
size=(0, 0),
|
size=(0, 0),
|
||||||
draw_controller=self._color_button,
|
draw_controller=self._color_button,
|
||||||
text=ba.Lstr(resource="editProfileWindow.colorText"),
|
text=babase.Lstr(resource="editProfileWindow.colorText"),
|
||||||
scale=0.7,
|
scale=0.7,
|
||||||
color=ba.app.ui.title_color,
|
color=bui.app.ui_v1.title_color,
|
||||||
maxwidth=120,
|
maxwidth=120,
|
||||||
)
|
)
|
||||||
|
|
||||||
self._highlight_button = ba.buttonwidget(
|
self._highlight_button = bui.buttonwidget(
|
||||||
parent=self._root_widget,
|
parent=self._root_widget,
|
||||||
autoselect=True,
|
autoselect=True,
|
||||||
position=(self._width * 0.5 + b_offs - b_size * 0.5, v - 50),
|
position=(self._width * 0.5 + b_offs - b_size * 0.5, v - 50),
|
||||||
|
|
@ -273,20 +255,20 @@ class ColorSchemeWindow(ba.Window):
|
||||||
button_type="square",
|
button_type="square",
|
||||||
)
|
)
|
||||||
|
|
||||||
ba.buttonwidget(
|
bui.buttonwidget(
|
||||||
edit=self._highlight_button,
|
edit=self._highlight_button,
|
||||||
on_activate_call=ba.Call(self._pick_color, "highlight"),
|
on_activate_call=babase.Call(self._pick_color, "highlight"),
|
||||||
)
|
)
|
||||||
ba.textwidget(
|
bui.textwidget(
|
||||||
parent=self._root_widget,
|
parent=self._root_widget,
|
||||||
h_align="center",
|
h_align="center",
|
||||||
v_align="center",
|
v_align="center",
|
||||||
position=(self._width * 0.5 + b_offs, v - 65),
|
position=(self._width * 0.5 + b_offs, v - 65),
|
||||||
size=(0, 0),
|
size=(0, 0),
|
||||||
draw_controller=self._highlight_button,
|
draw_controller=self._highlight_button,
|
||||||
text=ba.Lstr(resource="editProfileWindow.highlightText"),
|
text=babase.Lstr(resource="editProfileWindow.highlightText"),
|
||||||
scale=0.7,
|
scale=0.7,
|
||||||
color=ba.app.ui.title_color,
|
color=bui.app.ui_v1.title_color,
|
||||||
maxwidth=120,
|
maxwidth=120,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -306,7 +288,7 @@ class ColorSchemeWindow(ba.Window):
|
||||||
)
|
)
|
||||||
|
|
||||||
def cancel_on_outside_click(self):
|
def cancel_on_outside_click(self):
|
||||||
ba.playsound(ba.getsound("swish"))
|
bui.getsound("swish").play()
|
||||||
self._cancel()
|
self._cancel()
|
||||||
|
|
||||||
def _cancel(self):
|
def _cancel(self):
|
||||||
|
|
@ -314,44 +296,44 @@ class ColorSchemeWindow(ba.Window):
|
||||||
colorscheme = ColorScheme(self._last_color, self._last_highlight)
|
colorscheme = ColorScheme(self._last_color, self._last_highlight)
|
||||||
colorscheme.apply()
|
colorscheme.apply()
|
||||||
# Good idea to revert this back now so we do not break anything else.
|
# Good idea to revert this back now so we do not break anything else.
|
||||||
ba.app.accounts_v1.have_pro = original_have_pro
|
bui.app.classic.accounts.have_pro = original_have_pro
|
||||||
ba.containerwidget(edit=self._root_widget, transition="out_right")
|
bui.containerwidget(edit=self._root_widget, transition="out_right")
|
||||||
|
|
||||||
def reset(self, transition_out=True):
|
def reset(self, transition_out=True):
|
||||||
if transition_out:
|
if transition_out:
|
||||||
ba.playsound(ba.getsound("gunCocking"))
|
bui.getsound("gunCocking").play()
|
||||||
ba.app.config["ColorScheme"] = (None, None)
|
babase.app.config["ColorScheme"] = (None, None)
|
||||||
# Good idea to revert this back now so we do not break anything else.
|
# Good idea to revert this back now so we do not break anything else.
|
||||||
ba.app.accounts_v1.have_pro = original_have_pro
|
bui.app.classic.accounts.have_pro = original_have_pro
|
||||||
ba.app.config.commit()
|
babase.app.config.commit()
|
||||||
ba.containerwidget(edit=self._root_widget, transition="out_right")
|
bui.containerwidget(edit=self._root_widget, transition="out_right")
|
||||||
|
|
||||||
def save(self, transition_out=True):
|
def save(self, transition_out=True):
|
||||||
if transition_out:
|
if transition_out:
|
||||||
ba.playsound(ba.getsound("gunCocking"))
|
bui.getsound("gunCocking").play()
|
||||||
colorscheme = ColorScheme(
|
colorscheme = ColorScheme(
|
||||||
self._color or self._default_colors[0],
|
self._color or self._default_colors[0],
|
||||||
self._highlight or self._default_colors[1],
|
self._highlight or self._default_colors[1],
|
||||||
)
|
)
|
||||||
colorscheme.apply()
|
colorscheme.apply()
|
||||||
# Good idea to revert this back now so we do not break anything else.
|
# Good idea to revert this back now so we do not break anything else.
|
||||||
ba.app.accounts_v1.have_pro = original_have_pro
|
bui.app.classic.accounts.have_pro = original_have_pro
|
||||||
ba.app.config["ColorScheme"] = (
|
babase.app.config["ColorScheme"] = (
|
||||||
self._color or self._default_colors[0],
|
self._color or self._default_colors[0],
|
||||||
self._highlight or self._default_colors[1],
|
self._highlight or self._default_colors[1],
|
||||||
)
|
)
|
||||||
ba.app.config.commit()
|
babase.app.config.commit()
|
||||||
ba.containerwidget(edit=self._root_widget, transition="out_right")
|
bui.containerwidget(edit=self._root_widget, transition="out_right")
|
||||||
|
|
||||||
def _set_color(self, color):
|
def _set_color(self, color):
|
||||||
self._color = color
|
self._color = color
|
||||||
if self._color_button:
|
if self._color_button:
|
||||||
ba.buttonwidget(edit=self._color_button, color=color)
|
bui.buttonwidget(edit=self._color_button, color=color)
|
||||||
|
|
||||||
def _set_highlight(self, color):
|
def _set_highlight(self, color):
|
||||||
self._highlight = color
|
self._highlight = color
|
||||||
if self._highlight_button:
|
if self._highlight_button:
|
||||||
ba.buttonwidget(edit=self._highlight_button, color=color)
|
bui.buttonwidget(edit=self._highlight_button, color=color)
|
||||||
|
|
||||||
def color_picker_selected_color(self, picker, color):
|
def color_picker_selected_color(self, picker, color):
|
||||||
# The `ColorPicker` calls this method in the delegate once a color
|
# The `ColorPicker` calls this method in the delegate once a color
|
||||||
|
|
@ -387,13 +369,7 @@ class CustomTransactions:
|
||||||
self.custom_transactions[transaction_code] = transaction_fn
|
self.custom_transactions[transaction_code] = transaction_fn
|
||||||
|
|
||||||
def enable(self):
|
def enable(self):
|
||||||
# Adds backward compatibility for a breaking change released in
|
bui.app.plus.add_v1_account_transaction = self._handle
|
||||||
# game version 1.7.7, which moves `_ba.add_transaction` to
|
|
||||||
# `ba.internal.add_transaction`.
|
|
||||||
if is_game_version_lower_than("1.7.7"):
|
|
||||||
_ba.add_transaction = self._handle
|
|
||||||
else:
|
|
||||||
ba.internal.add_transaction = self._handle
|
|
||||||
|
|
||||||
|
|
||||||
def launch_colorscheme_selection_window():
|
def launch_colorscheme_selection_window():
|
||||||
|
|
@ -410,7 +386,7 @@ def launch_colorscheme_selection_window():
|
||||||
# has pro-unlocked or not if our plugin runs before the dedicated
|
# has pro-unlocked or not if our plugin runs before the dedicated
|
||||||
# pro-unlocker plugin has been applied.
|
# pro-unlocker plugin has been applied.
|
||||||
global original_have_pro
|
global original_have_pro
|
||||||
original_have_pro = ba.app.accounts_v1.have_pro
|
original_have_pro = bui.app.classic.accounts.have_pro
|
||||||
|
|
||||||
ColorSchemeWindow()
|
ColorSchemeWindow()
|
||||||
|
|
||||||
|
|
@ -420,7 +396,7 @@ def colorscheme_transaction(transaction, *args, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
def load_colorscheme():
|
def load_colorscheme():
|
||||||
color, highlight = ba.app.config.get("ColorScheme", (None, None))
|
color, highlight = babase.app.config.get("ColorScheme", (None, None))
|
||||||
if color and highlight:
|
if color and highlight:
|
||||||
colorscheme = ColorScheme(color, highlight)
|
colorscheme = ColorScheme(color, highlight)
|
||||||
colorscheme.apply()
|
colorscheme.apply()
|
||||||
|
|
@ -429,7 +405,7 @@ def load_colorscheme():
|
||||||
def load_plugin():
|
def load_plugin():
|
||||||
# Allow access to changing colorschemes manually through the in-game
|
# Allow access to changing colorschemes manually through the in-game
|
||||||
# console.
|
# console.
|
||||||
_ba.ColorScheme = ColorScheme
|
_babase.ColorScheme = ColorScheme
|
||||||
# Adds a new advanced code entry named "colorscheme" which can be
|
# Adds a new advanced code entry named "colorscheme" which can be
|
||||||
# entered through Settings -> Advanced -> Enter Code, allowing
|
# entered through Settings -> Advanced -> Enter Code, allowing
|
||||||
# colorscheme modification through a friendly UI.
|
# colorscheme modification through a friendly UI.
|
||||||
|
|
@ -441,7 +417,7 @@ def load_plugin():
|
||||||
|
|
||||||
|
|
||||||
# ba_meta export plugin
|
# ba_meta export plugin
|
||||||
class Main(ba.Plugin):
|
class Main(babase.Plugin):
|
||||||
def on_app_running(self):
|
def on_app_running(self):
|
||||||
load_plugin()
|
load_plugin()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,22 @@
|
||||||
# ba_meta require api 7
|
# ba_meta require api 8
|
||||||
from random import choice, randint
|
from random import choice, randint
|
||||||
from typing import Any, Union
|
from typing import Any, Union
|
||||||
|
|
||||||
# pylint: disable=import-error
|
# pylint: disable=import-error
|
||||||
import _ba
|
import babase
|
||||||
import ba
|
from bascenev1 import (
|
||||||
from bastd.ui.playlist.browser import PlaylistBrowserWindow
|
Session,
|
||||||
|
MultiTeamSession,
|
||||||
|
FreeForAllSession,
|
||||||
|
DualTeamSession,
|
||||||
|
GameActivity,
|
||||||
|
newactivity,
|
||||||
|
new_host_session,
|
||||||
|
)
|
||||||
|
|
||||||
|
from bauiv1 import Widget, UIScale, buttonwidget
|
||||||
|
from bauiv1lib.playlist.browser import PlaylistBrowserWindow
|
||||||
|
from bascenev1lib.activity.multiteamjoin import MultiTeamJoinActivity
|
||||||
|
|
||||||
DEFAULT_TEAM_COLORS = ((0.1, 0.25, 1.0), (1.0, 0.25, 0.2))
|
DEFAULT_TEAM_COLORS = ((0.1, 0.25, 1.0), (1.0, 0.25, 0.2))
|
||||||
DEFAULT_TEAM_NAMES = ("Blue", "Red")
|
DEFAULT_TEAM_NAMES = ("Blue", "Red")
|
||||||
|
|
@ -13,16 +24,16 @@ DEFAULT_TEAM_NAMES = ("Blue", "Red")
|
||||||
|
|
||||||
# More or less copied from game code
|
# More or less copied from game code
|
||||||
# I have no idea what I'm doing here
|
# I have no idea what I'm doing here
|
||||||
class RandomPlaySessionMixin(ba.MultiTeamSession, ba.Session):
|
class RandomPlaySessionMixin(MultiTeamSession, Session):
|
||||||
def __init__(self, playlist) -> None:
|
def __init__(self, playlist) -> None:
|
||||||
"""Set up playlists and launches a ba.Activity to accept joiners."""
|
"""Set up playlists & launch a bascenev1.Activity to accept joiners."""
|
||||||
# pylint: disable=cyclic-import
|
|
||||||
from bastd.activity.multiteamjoin import MultiTeamJoinActivity
|
|
||||||
|
|
||||||
app = _ba.app
|
app = babase.app
|
||||||
|
classic = app.classic
|
||||||
|
assert classic is not None
|
||||||
_cfg = app.config
|
_cfg = app.config
|
||||||
|
|
||||||
super(ba.MultiTeamSession, self).__init__(
|
super(MultiTeamSession, self).__init__(
|
||||||
[],
|
[],
|
||||||
team_names=DEFAULT_TEAM_NAMES,
|
team_names=DEFAULT_TEAM_NAMES,
|
||||||
team_colors=DEFAULT_TEAM_COLORS,
|
team_colors=DEFAULT_TEAM_COLORS,
|
||||||
|
|
@ -30,8 +41,8 @@ class RandomPlaySessionMixin(ba.MultiTeamSession, ba.Session):
|
||||||
max_players=self.get_max_players(),
|
max_players=self.get_max_players(),
|
||||||
)
|
)
|
||||||
|
|
||||||
self._series_length = app.teams_series_length
|
self._series_length: int = classic.teams_series_length
|
||||||
self._ffa_series_length = app.ffa_series_length
|
self._ffa_series_length: int = classic.ffa_series_length
|
||||||
|
|
||||||
self._tutorial_activity_instance = None
|
self._tutorial_activity_instance = None
|
||||||
self._game_number = 0
|
self._game_number = 0
|
||||||
|
|
@ -41,37 +52,37 @@ class RandomPlaySessionMixin(ba.MultiTeamSession, ba.Session):
|
||||||
|
|
||||||
self._current_game_spec: dict[str, Any] | None = None
|
self._current_game_spec: dict[str, Any] | None = None
|
||||||
self._next_game_spec: dict[str, Any] = self._playlist.pull_next()
|
self._next_game_spec: dict[str, Any] = self._playlist.pull_next()
|
||||||
self._next_game: type[ba.GameActivity] = self._next_game_spec["resolved_type"]
|
self._next_game: type[GameActivity] = self._next_game_spec["resolved_type"]
|
||||||
|
|
||||||
self._instantiate_next_game()
|
self._instantiate_next_game()
|
||||||
self.setactivity(_ba.newactivity(MultiTeamJoinActivity))
|
self.setactivity(newactivity(MultiTeamJoinActivity))
|
||||||
|
|
||||||
|
|
||||||
# Classes for Teams autopilot and FFA autopilot
|
# Classes for Teams autopilot and FFA autopilot
|
||||||
# I think they have to be separate in order to comply with `ba.GameActivity.supports_session_type()`
|
# I think they have to be separate in order to comply with `ba.GameActivity.supports_session_type()`
|
||||||
class RandFreeForAllSession(ba.FreeForAllSession, RandomPlaySessionMixin):
|
class RandFreeForAllSession(FreeForAllSession, RandomPlaySessionMixin):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
playlist = RandomPlaylist(ba.FreeForAllSession)
|
playlist = RandomPlaylist(FreeForAllSession)
|
||||||
super(ba.FreeForAllSession, self).__init__(playlist)
|
super(FreeForAllSession, self).__init__(playlist)
|
||||||
|
|
||||||
|
|
||||||
class RandDualTeamSession(ba.DualTeamSession, RandomPlaySessionMixin):
|
class RandDualTeamSession(DualTeamSession, RandomPlaySessionMixin):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
playlist = RandomPlaylist(ba.DualTeamSession)
|
playlist = RandomPlaylist(DualTeamSession)
|
||||||
super(ba.DualTeamSession, self).__init__(playlist)
|
super(DualTeamSession, self).__init__(playlist)
|
||||||
|
|
||||||
|
|
||||||
# The faux playlist that just picks games at random
|
# The faux playlist that just picks games at random
|
||||||
class RandomPlaylist:
|
class RandomPlaylist:
|
||||||
sessiontype: ba.Session
|
sessiontype: Session
|
||||||
all_games: list[ba.GameActivity]
|
all_games: list[GameActivity]
|
||||||
usable_games: list[ba.GameActivity]
|
usable_games: list[GameActivity]
|
||||||
|
|
||||||
last_game: str
|
last_game: str
|
||||||
|
|
||||||
def __init__(self, sessiontype):
|
def __init__(self, sessiontype):
|
||||||
self.sessiontype = sessiontype
|
self.sessiontype = sessiontype
|
||||||
self.usable_games: list[ba.GameActivity] = [
|
self.usable_games: list[GameActivity] = [
|
||||||
gt
|
gt
|
||||||
for gt in RandomPlaylist.all_games
|
for gt in RandomPlaylist.all_games
|
||||||
if gt.supports_session_type(self.sessiontype)
|
if gt.supports_session_type(self.sessiontype)
|
||||||
|
|
@ -90,7 +101,7 @@ class RandomPlaylist:
|
||||||
if game.name == self.last_game:
|
if game.name == self.last_game:
|
||||||
# Don't repeat the same game twice
|
# Don't repeat the same game twice
|
||||||
if has_only_one_game:
|
if has_only_one_game:
|
||||||
# ...but don't freeze the game when there's only one game
|
# ...but don't freeze when there's only one game
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
@ -113,40 +124,42 @@ class RandomPlaylist:
|
||||||
# Hope you don't mind.
|
# Hope you don't mind.
|
||||||
def patched__init__(
|
def patched__init__(
|
||||||
self,
|
self,
|
||||||
sessiontype: type[ba.Session],
|
sessiontype: type[Session],
|
||||||
transition: str | None = "in_right",
|
transition: str | None = "in_right",
|
||||||
origin_widget: ba.Widget | None = None,
|
origin_widget: Widget | None = None,
|
||||||
):
|
):
|
||||||
width = 800
|
width = 800
|
||||||
height = 650
|
height = 650
|
||||||
|
|
||||||
ui_scale = ba.app.ui.uiscale
|
ui_scale = babase.app.ui_v1.uiscale
|
||||||
y_offset = -100 if ui_scale is ba.UIScale.SMALL else 0
|
|
||||||
x_offset = 50 if ui_scale is ba.UIScale.SMALL else 0
|
y_offset = -100 if ui_scale is UIScale.SMALL else 0
|
||||||
|
x_offset = 50 if ui_scale is UIScale.SMALL else 0
|
||||||
|
|
||||||
self.old__init__(sessiontype, transition, origin_widget)
|
self.old__init__(sessiontype, transition, origin_widget)
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
self._quick_game_button = ba.buttonwidget(
|
self._quick_game_button = buttonwidget(
|
||||||
parent=self._root_widget,
|
parent=self._root_widget,
|
||||||
position=(width - 120 * 2 + x_offset, height - 132 + y_offset),
|
position=(width - 120 * 2 + x_offset, height - 132 + y_offset),
|
||||||
autoselect=True,
|
autoselect=True,
|
||||||
size=(120, 60),
|
size=(80, 60),
|
||||||
scale=1.1,
|
scale=1.1,
|
||||||
text_scale=1.2,
|
text_scale=1.2,
|
||||||
label="Random games",
|
label="Random",
|
||||||
on_activate_call=game_starter_factory(sessiontype),
|
on_activate_call=game_starter_factory(sessiontype),
|
||||||
color=(0.54, 0.52, 0.67),
|
color=(0.54, 0.52, 0.67),
|
||||||
textcolor=(0.7, 0.65, 0.7),
|
textcolor=(0.7, 0.65, 0.7),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Returns a function that starts the game
|
# Returns a function that starts the game
|
||||||
def game_starter_factory(sessiontype: type[ba.Session]):
|
|
||||||
|
|
||||||
|
def game_starter_factory(sessiontype: type[Session]):
|
||||||
session: Union[RandFreeForAllSession, RandDualTeamSession] = None
|
session: Union[RandFreeForAllSession, RandDualTeamSession] = None
|
||||||
|
|
||||||
if issubclass(sessiontype, ba.FreeForAllSession):
|
if issubclass(sessiontype, FreeForAllSession):
|
||||||
session = RandFreeForAllSession
|
session = RandFreeForAllSession
|
||||||
elif issubclass(sessiontype, ba.DualTeamSession):
|
elif issubclass(sessiontype, DualTeamSession):
|
||||||
session = RandDualTeamSession
|
session = RandDualTeamSession
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Can't determine session type")
|
raise RuntimeError("Can't determine session type")
|
||||||
|
|
@ -170,18 +183,18 @@ def game_starter_factory(sessiontype: type[ba.Session]):
|
||||||
start()
|
start()
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
_ba.unlock_all_input()
|
babase.unlock_all_input()
|
||||||
_ba.new_host_session(session)
|
new_host_session(session)
|
||||||
|
|
||||||
_ba.fade_screen(False, time=0.25, endcall=has_faded)
|
babase.fade_screen(False, time=0.25, endcall=has_faded)
|
||||||
_ba.lock_all_input()
|
babase.lock_all_input()
|
||||||
ba.app.meta.load_exported_classes(ba.GameActivity, do_start)
|
babase.app.meta.load_exported_classes(GameActivity, do_start)
|
||||||
|
|
||||||
return on_run
|
return on_run
|
||||||
|
|
||||||
|
|
||||||
# ba_meta export plugin
|
# ba_meta export plugin
|
||||||
class RandomPlayPlugin(ba.Plugin):
|
class RandomPlayPlugin(babase.Plugin):
|
||||||
"""
|
"""
|
||||||
A plugin that allows you to play randomly generated FFA or Teams matches by selecting a random minigame and map for each round.
|
A plugin that allows you to play randomly generated FFA or Teams matches by selecting a random minigame and map for each round.
|
||||||
This eliminates the need to set up long playlists to enjoy all your BombSquad content.
|
This eliminates the need to set up long playlists to enjoy all your BombSquad content.
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
|
packaging
|
||||||
GitPython
|
GitPython
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import io
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
from distutils.version import StrictVersion
|
from packaging.version import Version
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
|
@ -33,7 +33,7 @@ class TestPluginManagerMetadata(unittest.TestCase):
|
||||||
versions = list(self.content["versions"].items())
|
versions = list(self.content["versions"].items())
|
||||||
sorted_versions = sorted(
|
sorted_versions = sorted(
|
||||||
versions,
|
versions,
|
||||||
key=lambda version: StrictVersion(version[0]),
|
key=lambda version: Version(version[0]),
|
||||||
reverse=True,
|
reverse=True,
|
||||||
)
|
)
|
||||||
assert sorted_versions == versions
|
assert sorted_versions == versions
|
||||||
|
|
@ -105,7 +105,7 @@ class BaseCategoryMetadataTestCases:
|
||||||
versions = list(plugin_metadata["versions"].items())
|
versions = list(plugin_metadata["versions"].items())
|
||||||
sorted_versions = sorted(
|
sorted_versions = sorted(
|
||||||
versions,
|
versions,
|
||||||
key=lambda version: StrictVersion(version[0]),
|
key=lambda version: Version(version[0]),
|
||||||
reverse=True,
|
reverse=True,
|
||||||
)
|
)
|
||||||
self.assertEqual(sorted_versions, versions)
|
self.assertEqual(sorted_versions, versions)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue