mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-29 02:23:22 +08:00
Cleaned up plugin subsystem
This commit is contained in:
parent
0f9fe41542
commit
05c93cc776
@ -1,6 +1,8 @@
|
||||
### 1.5.27 (20218)
|
||||
- Language functionality has been consolidated into a LanguageSubsystem object at ba.app.lang
|
||||
- ba.get_valid_languages() is now an attr: ba.app.lang.available_languages
|
||||
- Achievement functionality has been consolidated into an AchievementSubsystem object at ba.app.ach
|
||||
- Plugin functionality has been consolidated into a PluginSubsystem obj at ba.app.plugins
|
||||
|
||||
### 1.5.26 (20217)
|
||||
- Simplified licensing header on python scripts.
|
||||
|
||||
@ -20,7 +20,7 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice,
|
||||
set_analytics_screen, charstr, textwidget, time, timer,
|
||||
open_url, widget)
|
||||
from ba._activity import Activity
|
||||
from ba._plugin import PotentialPlugin, Plugin
|
||||
from ba._plugin import PotentialPlugin, Plugin, PluginSubsystem
|
||||
from ba._actor import Actor
|
||||
from ba._player import PlayerInfo, Player, EmptyPlayer, StandLocation
|
||||
from ba._nodeactor import NodeActor
|
||||
|
||||
@ -175,6 +175,7 @@ class App:
|
||||
from ba._language import LanguageSubsystem
|
||||
from ba._ui import UISubsystem
|
||||
from ba._achievement import AchievementSubsystem
|
||||
from ba._plugin import PluginSubsystem
|
||||
|
||||
# Config.
|
||||
self.config_file_healthy = False
|
||||
@ -198,10 +199,6 @@ class App:
|
||||
self.iircade_mode: bool = self._env['iircade_mode']
|
||||
assert isinstance(self.headless_mode, bool)
|
||||
|
||||
# Plugins.
|
||||
self.potential_plugins: List[ba.PotentialPlugin] = []
|
||||
self.active_plugins: Dict[str, ba.Plugin] = {}
|
||||
|
||||
# Misc.
|
||||
self.metascan: Optional[_meta.ScanResults] = None
|
||||
self.tips: List[str] = []
|
||||
@ -241,6 +238,7 @@ class App:
|
||||
self.last_ad_purpose = 'invalid'
|
||||
self.attempted_first_ad = False
|
||||
|
||||
self.plugins = PluginSubsystem()
|
||||
self.music = MusicSubsystem()
|
||||
self.lang = LanguageSubsystem()
|
||||
self.ach = AchievementSubsystem()
|
||||
@ -291,7 +289,6 @@ class App:
|
||||
(internal)"""
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=cyclic-import
|
||||
# pylint: disable=too-many-statements
|
||||
from ba import _apputils
|
||||
from ba import _appconfig
|
||||
from ba import _achievement
|
||||
@ -401,49 +398,13 @@ class App:
|
||||
|
||||
_ba.pushcall(do_auto_sign_in)
|
||||
|
||||
# Load up our plugins and go ahead and call their on_app_launch calls.
|
||||
self.load_plugins()
|
||||
for plugin in self.active_plugins.values():
|
||||
try:
|
||||
plugin.on_app_launch()
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception('Error in plugin on_app_launch()')
|
||||
self.plugins.on_app_launch()
|
||||
|
||||
self.ran_on_app_launch = True
|
||||
|
||||
# from ba._dependency import test_depset
|
||||
# test_depset()
|
||||
|
||||
def load_plugins(self) -> None:
|
||||
"""(internal)"""
|
||||
from ba._general import getclass
|
||||
from ba._plugin import Plugin
|
||||
|
||||
# Note: the plugins we load is purely based on what's enabled
|
||||
# in the app config. Our meta-scan gives us a list of available
|
||||
# plugins, but that is only used to give the user a list of plugins
|
||||
# that they can enable. (we wouldn't want to look at meta-scan here
|
||||
# anyway because it may not be done yet at this point in the launch)
|
||||
plugstates: Dict[str, Dict] = self.config.get('Plugins', {})
|
||||
assert isinstance(plugstates, dict)
|
||||
plugkeys: List[str] = sorted(key for key, val in plugstates.items()
|
||||
if val.get('enabled', False))
|
||||
for plugkey in plugkeys:
|
||||
try:
|
||||
cls = getclass(plugkey, Plugin)
|
||||
except Exception as exc:
|
||||
_ba.log(f"Error loading plugin class '{plugkey}': {exc}",
|
||||
to_server=False)
|
||||
continue
|
||||
try:
|
||||
plugin = cls()
|
||||
assert plugkey not in self.active_plugins
|
||||
self.active_plugins[plugkey] = plugin
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception(f'Error loading plugin: {plugkey}')
|
||||
|
||||
def read_config(self) -> None:
|
||||
"""(internal)"""
|
||||
from ba import _appconfig
|
||||
@ -558,7 +519,6 @@ class App:
|
||||
"""Run when the app resumes from a suspended state."""
|
||||
|
||||
self.music.on_app_resume()
|
||||
|
||||
self.fg_state += 1
|
||||
|
||||
# Mark our cached tourneys as invalid so anyone using them knows
|
||||
@ -657,13 +617,13 @@ class App:
|
||||
|
||||
# If we're still not signed in and have pending codes,
|
||||
# inform the user that they need to sign in to use them.
|
||||
if _ba.app.pending_promo_codes:
|
||||
if self.pending_promo_codes:
|
||||
_ba.screenmessage(
|
||||
Lstr(resource='signInForPromoCodeText'),
|
||||
color=(1, 0, 0))
|
||||
_ba.playsound(_ba.getsound('error'))
|
||||
|
||||
_ba.app.pending_promo_codes.append(code)
|
||||
self.pending_promo_codes.append(code)
|
||||
_ba.timer(6.0, check_pending_codes, timetype=TimeType.REAL)
|
||||
return
|
||||
_ba.screenmessage(Lstr(resource='submittingPromoCodeText'),
|
||||
@ -681,7 +641,7 @@ class App:
|
||||
def _test_https(self) -> None:
|
||||
"""Testing https support.
|
||||
|
||||
(would be nice to get this working on our custom python builds; need
|
||||
(would be nice to get this working on our custom Python builds; need
|
||||
to wrangle certificates somehow).
|
||||
"""
|
||||
import urllib.request
|
||||
|
||||
@ -68,6 +68,7 @@ def handle_scan_results(results: ScanResults) -> None:
|
||||
_ba.log(textwrap.indent(results.errors, 'Error (meta-scan): '))
|
||||
|
||||
# Handle plugins.
|
||||
plugs = _ba.app.plugins
|
||||
config_changed = False
|
||||
found_new = False
|
||||
plugstates: Dict[str, Dict] = _ba.app.config.setdefault('Plugins', {})
|
||||
@ -75,7 +76,7 @@ def handle_scan_results(results: ScanResults) -> None:
|
||||
|
||||
# Create a potential-plugin for each class we found in the scan.
|
||||
for class_path in results.plugins:
|
||||
_ba.app.potential_plugins.append(
|
||||
plugs.potential_plugins.append(
|
||||
PotentialPlugin(display_name=Lstr(value=class_path),
|
||||
class_path=class_path,
|
||||
available=True))
|
||||
@ -90,12 +91,12 @@ def handle_scan_results(results: ScanResults) -> None:
|
||||
enabled = plugstate.get('enabled', False)
|
||||
assert isinstance(enabled, bool)
|
||||
if enabled and class_path not in results.plugins:
|
||||
_ba.app.potential_plugins.append(
|
||||
plugs.potential_plugins.append(
|
||||
PotentialPlugin(display_name=Lstr(value=class_path),
|
||||
class_path=class_path,
|
||||
available=False))
|
||||
|
||||
_ba.app.potential_plugins.sort(key=lambda p: p.class_path)
|
||||
plugs.potential_plugins.sort(key=lambda p: p.class_path)
|
||||
|
||||
if found_new:
|
||||
_ba.screenmessage(Lstr(resource='pluginsDetectedText'),
|
||||
|
||||
@ -6,11 +6,65 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from dataclasses import dataclass
|
||||
import _ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import List, Dict
|
||||
import ba
|
||||
|
||||
|
||||
class PluginSubsystem:
|
||||
"""Subsystem for plugin handling in the app.
|
||||
|
||||
Category: App Classes
|
||||
|
||||
Access the single shared instance of this class at 'ba.app.plugins'.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.potential_plugins: List[ba.PotentialPlugin] = []
|
||||
self.active_plugins: Dict[str, ba.Plugin] = {}
|
||||
|
||||
def on_app_launch(self) -> None:
|
||||
"""Should be called at app launch time."""
|
||||
# Load up our plugins and go ahead and call their on_app_launch calls.
|
||||
self.load_plugins()
|
||||
for plugin in self.active_plugins.values():
|
||||
try:
|
||||
plugin.on_app_launch()
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception('Error in plugin on_app_launch()')
|
||||
|
||||
def load_plugins(self) -> None:
|
||||
"""(internal)"""
|
||||
from ba._general import getclass
|
||||
|
||||
# Note: the plugins we load is purely based on what's enabled
|
||||
# in the app config. Our meta-scan gives us a list of available
|
||||
# plugins, but that is only used to give the user a list of plugins
|
||||
# that they can enable. (we wouldn't want to look at meta-scan here
|
||||
# anyway because it may not be done yet at this point in the launch)
|
||||
plugstates: Dict[str, Dict] = _ba.app.config.get('Plugins', {})
|
||||
assert isinstance(plugstates, dict)
|
||||
plugkeys: List[str] = sorted(key for key, val in plugstates.items()
|
||||
if val.get('enabled', False))
|
||||
for plugkey in plugkeys:
|
||||
try:
|
||||
cls = getclass(plugkey, Plugin)
|
||||
except Exception as exc:
|
||||
_ba.log(f"Error loading plugin class '{plugkey}': {exc}",
|
||||
to_server=False)
|
||||
continue
|
||||
try:
|
||||
plugin = cls()
|
||||
assert plugkey not in self.active_plugins
|
||||
self.active_plugins[plugkey] = plugin
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception(f'Error loading plugin: {plugkey}')
|
||||
|
||||
|
||||
@dataclass
|
||||
class PotentialPlugin:
|
||||
"""Represents a ba.Plugin which can potentially be loaded.
|
||||
|
||||
@ -97,11 +97,11 @@ class PluginSettingsWindow(ba.Window):
|
||||
ba.screenmessage('Still scanning plugins; please try again.',
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
pluglist = ba.app.potential_plugins
|
||||
pluglist = ba.app.plugins.potential_plugins
|
||||
plugstates: Dict[str, Dict] = ba.app.config.setdefault('Plugins', {})
|
||||
assert isinstance(plugstates, dict)
|
||||
for i, availplug in enumerate(pluglist):
|
||||
active = availplug.class_path in ba.app.active_plugins
|
||||
active = availplug.class_path in ba.app.plugins.active_plugins
|
||||
|
||||
plugstate = plugstates.setdefault(availplug.class_path, {})
|
||||
checked = plugstate.get('enabled', False)
|
||||
|
||||
@ -158,6 +158,7 @@
|
||||
<li><a href="#class_ba_MusicPlayer">ba.MusicPlayer</a></li>
|
||||
<li><a href="#class_ba_MusicSubsystem">ba.MusicSubsystem</a></li>
|
||||
<li><a href="#class_ba_Plugin">ba.Plugin</a></li>
|
||||
<li><a href="#class_ba_PluginSubsystem">ba.PluginSubsystem</a></li>
|
||||
<li><a href="#class_ba_PotentialPlugin">ba.PotentialPlugin</a></li>
|
||||
<li><a href="#class_ba_ServerController">ba.ServerController</a></li>
|
||||
<li><a href="#class_ba_UISubsystem">ba.UISubsystem</a></li>
|
||||
@ -4734,6 +4735,31 @@ the type-checker properly identifies the returned value as one.</p>
|
||||
|
||||
<p>Called when the app is being launched.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_PluginSubsystem">ba.PluginSubsystem</a></strong></h3>
|
||||
<p><em><top level class></em>
|
||||
</p>
|
||||
<p>Subsystem for plugin handling in the app.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_App_Classes">App Classes</a></p>
|
||||
|
||||
<p> Access the single shared instance of this class at 'ba.app.plugins'.
|
||||
</p>
|
||||
|
||||
<h3>Methods:</h3>
|
||||
<h5><a href="#method_ba_PluginSubsystem____init__"><constructor></a>, <a href="#method_ba_PluginSubsystem__on_app_launch">on_app_launch()</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_PluginSubsystem____init__"><constructor></a></dt></h4><dd>
|
||||
<p><span>ba.PluginSubsystem()</span></p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_PluginSubsystem__on_app_launch">on_app_launch()</a></dt></h4><dd>
|
||||
<p><span>on_app_launch(self) -> None</span></p>
|
||||
|
||||
<p>Should be called at app launch time.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user