mirror of
https://github.com/imayushsaini/Bombsquad-Ballistica-Modded-Server.git
synced 2025-11-07 17:36:15 +00:00
updating core files 1.7.10
This commit is contained in:
parent
daff57f1e9
commit
b110f8a12a
163 changed files with 4836 additions and 1960 deletions
241
dist/ba_data/python/_bainternal.py
vendored
Normal file
241
dist/ba_data/python/_bainternal.py
vendored
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""A dummy stub module for the real _bainternal.
|
||||
|
||||
The real _bainternal is a compiled extension module and only available
|
||||
in the live engine. This dummy-module allows Pylint/Mypy/etc. to
|
||||
function reasonably well outside of that environment.
|
||||
|
||||
Make sure this file is never included in dirs seen by the engine!
|
||||
|
||||
In the future perhaps this can be a stub (.pyi) file, but we will need
|
||||
to make sure that it works with all our tools (mypy, pylint, pycharm).
|
||||
|
||||
NOTE: This file was autogenerated by batools.dummymodule; do not edit by hand.
|
||||
"""
|
||||
|
||||
# I'm sorry Pylint. I know this file saddens you. Be strong.
|
||||
# pylint: disable=useless-suppression
|
||||
# pylint: disable=unnecessary-pass
|
||||
# pylint: disable=use-dict-literal
|
||||
# pylint: disable=use-list-literal
|
||||
# pylint: disable=unused-argument
|
||||
# pylint: disable=missing-docstring
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=redefined-builtin
|
||||
# pylint: disable=too-many-lines
|
||||
# pylint: disable=redefined-outer-name
|
||||
# pylint: disable=invalid-name
|
||||
# pylint: disable=no-value-for-parameter
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
||||
_T = TypeVar('_T')
|
||||
|
||||
|
||||
def _uninferrable() -> Any:
|
||||
"""Get an "Any" in mypy and "uninferrable" in Pylint."""
|
||||
# pylint: disable=undefined-variable
|
||||
return _not_a_real_variable # type: ignore
|
||||
|
||||
|
||||
def add_transaction(transaction: dict,
|
||||
callback: Callable | None = None) -> None:
|
||||
"""(internal)"""
|
||||
return None
|
||||
|
||||
|
||||
def game_service_has_leaderboard(game: str, config: str) -> bool:
|
||||
"""(internal)
|
||||
|
||||
Given a game and config string, returns whether there is a leaderboard
|
||||
for it on the game service.
|
||||
"""
|
||||
return bool()
|
||||
|
||||
|
||||
def get_master_server_address(source: int = -1, version: int = 1) -> str:
|
||||
"""(internal)
|
||||
|
||||
Return the address of the master server.
|
||||
"""
|
||||
return str()
|
||||
|
||||
|
||||
def get_news_show() -> str:
|
||||
"""(internal)"""
|
||||
return str()
|
||||
|
||||
|
||||
def get_price(item: str) -> str | None:
|
||||
"""(internal)"""
|
||||
return ''
|
||||
|
||||
|
||||
def get_public_login_id() -> str | None:
|
||||
"""(internal)"""
|
||||
return ''
|
||||
|
||||
|
||||
def get_purchased(item: str) -> bool:
|
||||
"""(internal)"""
|
||||
return bool()
|
||||
|
||||
|
||||
def get_purchases_state() -> int:
|
||||
"""(internal)"""
|
||||
return int()
|
||||
|
||||
|
||||
def get_v1_account_display_string(full: bool = True) -> str:
|
||||
"""(internal)"""
|
||||
return str()
|
||||
|
||||
|
||||
def get_v1_account_misc_read_val(name: str, default_value: Any) -> Any:
|
||||
"""(internal)"""
|
||||
return _uninferrable()
|
||||
|
||||
|
||||
def get_v1_account_misc_read_val_2(name: str, default_value: Any) -> Any:
|
||||
"""(internal)"""
|
||||
return _uninferrable()
|
||||
|
||||
|
||||
def get_v1_account_misc_val(name: str, default_value: Any) -> Any:
|
||||
"""(internal)"""
|
||||
return _uninferrable()
|
||||
|
||||
|
||||
def get_v1_account_name() -> str:
|
||||
"""(internal)"""
|
||||
return str()
|
||||
|
||||
|
||||
def get_v1_account_state() -> str:
|
||||
"""(internal)"""
|
||||
return str()
|
||||
|
||||
|
||||
def get_v1_account_state_num() -> int:
|
||||
"""(internal)"""
|
||||
return int()
|
||||
|
||||
|
||||
def get_v1_account_ticket_count() -> int:
|
||||
"""(internal)
|
||||
|
||||
Returns the number of tickets for the current account.
|
||||
"""
|
||||
return int()
|
||||
|
||||
|
||||
def get_v1_account_type() -> str:
|
||||
"""(internal)"""
|
||||
return str()
|
||||
|
||||
|
||||
def get_v2_fleet() -> str:
|
||||
"""(internal)"""
|
||||
return str()
|
||||
|
||||
|
||||
def have_outstanding_transactions() -> bool:
|
||||
"""(internal)"""
|
||||
return bool()
|
||||
|
||||
|
||||
def in_game_purchase(item: str, price: int) -> None:
|
||||
"""(internal)"""
|
||||
return None
|
||||
|
||||
|
||||
def is_blessed() -> bool:
|
||||
"""(internal)"""
|
||||
return bool()
|
||||
|
||||
|
||||
def mark_config_dirty() -> None:
|
||||
"""(internal)
|
||||
|
||||
Category: General Utility Functions
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
def power_ranking_query(callback: Callable, season: Any = None) -> None:
|
||||
"""(internal)"""
|
||||
return None
|
||||
|
||||
|
||||
def purchase(item: str) -> None:
|
||||
"""(internal)"""
|
||||
return None
|
||||
|
||||
|
||||
def report_achievement(achievement: str, pass_to_account: bool = True) -> None:
|
||||
"""(internal)"""
|
||||
return None
|
||||
|
||||
|
||||
def reset_achievements() -> None:
|
||||
"""(internal)"""
|
||||
return None
|
||||
|
||||
|
||||
def restore_purchases() -> None:
|
||||
"""(internal)"""
|
||||
return None
|
||||
|
||||
|
||||
def run_transactions() -> None:
|
||||
"""(internal)"""
|
||||
return None
|
||||
|
||||
|
||||
def sign_in_v1(account_type: str) -> None:
|
||||
"""(internal)
|
||||
|
||||
Category: General Utility Functions
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
def sign_out_v1(v2_embedded: bool = False) -> None:
|
||||
"""(internal)
|
||||
|
||||
Category: General Utility Functions
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
def submit_score(game: str,
|
||||
config: str,
|
||||
name: Any,
|
||||
score: int | None,
|
||||
callback: Callable,
|
||||
friend_callback: Callable | None,
|
||||
order: str = 'increasing',
|
||||
tournament_id: str | None = None,
|
||||
score_type: str = 'points',
|
||||
campaign: str | None = None,
|
||||
level: str | None = None) -> None:
|
||||
"""(internal)
|
||||
|
||||
Submit a score to the server; callback will be called with the results.
|
||||
As a courtesy, please don't send fake scores to the server. I'd prefer
|
||||
to devote my time to improving the game instead of trying to make the
|
||||
score server more mischief-proof.
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
def tournament_query(callback: Callable[[dict | None], None],
|
||||
args: dict) -> None:
|
||||
"""(internal)"""
|
||||
return None
|
||||
16
dist/ba_data/python/ba/__init__.py
vendored
16
dist/ba_data/python/ba/__init__.py
vendored
|
|
@ -13,11 +13,11 @@ from _ba import (
|
|||
Node, SessionPlayer, Sound, Texture, Timer, Vec3, Widget, buttonwidget,
|
||||
camerashake, checkboxwidget, columnwidget, containerwidget, do_once,
|
||||
emitfx, getactivity, getcollidemodel, getmodel, getnodes, getsession,
|
||||
getsound, gettexture, hscrollwidget, imagewidget, log, newactivity,
|
||||
newnode, playsound, printnodes, printobjects, pushcall, quit, rowwidget,
|
||||
safecolor, screenmessage, scrollwidget, set_analytics_screen, charstr,
|
||||
textwidget, time, timer, open_url, widget, clipboard_is_supported,
|
||||
clipboard_has_text, clipboard_get_text, clipboard_set_text, getdata)
|
||||
getsound, gettexture, hscrollwidget, imagewidget, newactivity, newnode,
|
||||
playsound, printnodes, printobjects, pushcall, quit, rowwidget, safecolor,
|
||||
screenmessage, scrollwidget, set_analytics_screen, charstr, textwidget,
|
||||
time, timer, open_url, widget, clipboard_is_supported, clipboard_has_text,
|
||||
clipboard_get_text, clipboard_set_text, getdata, in_logic_thread)
|
||||
from ba._activity import Activity
|
||||
from ba._plugin import PotentialPlugin, Plugin, PluginSubsystem
|
||||
from ba._actor import Actor
|
||||
|
|
@ -99,10 +99,10 @@ __all__ = [
|
|||
'GameTip', 'garbage_collect', 'getactivity', 'getclass', 'getcollidemodel',
|
||||
'getcollision', 'getdata', 'getmaps', 'getmodel', 'getnodes', 'getsession',
|
||||
'getsound', 'gettexture', 'HitMessage', 'hscrollwidget', 'imagewidget',
|
||||
'ImpactDamageMessage', 'InputDevice', 'InputDeviceNotFoundError',
|
||||
'InputType', 'IntChoiceSetting', 'IntSetting',
|
||||
'ImpactDamageMessage', 'in_logic_thread', 'InputDevice',
|
||||
'InputDeviceNotFoundError', 'InputType', 'IntChoiceSetting', 'IntSetting',
|
||||
'is_browser_likely_available', 'is_point_in_box', 'Keyboard',
|
||||
'LanguageSubsystem', 'Level', 'Lobby', 'log', 'Lstr', 'Map', 'Material',
|
||||
'LanguageSubsystem', 'Level', 'Lobby', 'Lstr', 'Map', 'Material',
|
||||
'MetadataSubsystem', 'Model', 'MultiTeamSession', 'MusicPlayer',
|
||||
'MusicPlayMode', 'MusicSubsystem', 'MusicType', 'newactivity', 'newnode',
|
||||
'Node', 'NodeActor', 'NodeNotFoundError', 'normalized_color',
|
||||
|
|
|
|||
42
dist/ba_data/python/ba/_accountv1.py
vendored
42
dist/ba_data/python/ba/_accountv1.py
vendored
|
|
@ -9,6 +9,7 @@ import time
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
from ba import _internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -41,7 +42,7 @@ class AccountV1Subsystem:
|
|||
def do_auto_sign_in() -> None:
|
||||
if _ba.app.headless_mode or _ba.app.config.get(
|
||||
'Auto Account State') == 'Local':
|
||||
_ba.sign_in_v1('Local')
|
||||
_internal.sign_in_v1('Local')
|
||||
|
||||
_ba.pushcall(do_auto_sign_in)
|
||||
|
||||
|
|
@ -108,8 +109,8 @@ class AccountV1Subsystem:
|
|||
|
||||
if data['p']:
|
||||
pro_mult = 1.0 + float(
|
||||
_ba.get_v1_account_misc_read_val('proPowerRankingBoost',
|
||||
0.0)) * 0.01
|
||||
_internal.get_v1_account_misc_read_val('proPowerRankingBoost',
|
||||
0.0)) * 0.01
|
||||
else:
|
||||
pro_mult = 1.0
|
||||
|
||||
|
|
@ -135,12 +136,13 @@ class AccountV1Subsystem:
|
|||
"""(internal)"""
|
||||
# pylint: disable=cyclic-import
|
||||
from ba import _store
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if _internal.get_v1_account_state() != 'signed_in':
|
||||
return []
|
||||
icons = []
|
||||
store_items = _store.get_store_items()
|
||||
for item_name, item in list(store_items.items()):
|
||||
if item_name.startswith('icons.') and _ba.get_purchased(item_name):
|
||||
if item_name.startswith('icons.') and _internal.get_purchased(
|
||||
item_name):
|
||||
icons.append(item['icon'])
|
||||
return icons
|
||||
|
||||
|
|
@ -152,12 +154,13 @@ class AccountV1Subsystem:
|
|||
(internal)
|
||||
"""
|
||||
# This only applies when we're signed in.
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if _internal.get_v1_account_state() != 'signed_in':
|
||||
return
|
||||
|
||||
# If the short version of our account name currently cant be
|
||||
# displayed by the game, cancel.
|
||||
if not _ba.have_chars(_ba.get_v1_account_display_string(full=False)):
|
||||
if not _ba.have_chars(
|
||||
_internal.get_v1_account_display_string(full=False)):
|
||||
return
|
||||
|
||||
config = _ba.app.config
|
||||
|
|
@ -165,7 +168,7 @@ class AccountV1Subsystem:
|
|||
or '__account__' not in config['Player Profiles']):
|
||||
|
||||
# Create a spaz with a nice default purply color.
|
||||
_ba.add_transaction({
|
||||
_internal.add_transaction({
|
||||
'type': 'ADD_PLAYER_PROFILE',
|
||||
'name': '__account__',
|
||||
'profile': {
|
||||
|
|
@ -174,7 +177,7 @@ class AccountV1Subsystem:
|
|||
'highlight': [0.5, 0.25, 1.0]
|
||||
}
|
||||
})
|
||||
_ba.run_transactions()
|
||||
_internal.run_transactions()
|
||||
|
||||
def have_pro(self) -> bool:
|
||||
"""Return whether pro is currently unlocked."""
|
||||
|
|
@ -182,9 +185,9 @@ class AccountV1Subsystem:
|
|||
# Check our tickets-based pro upgrade and our two real-IAP based
|
||||
# upgrades. Also always unlock this stuff in ballistica-core builds.
|
||||
return bool(
|
||||
_ba.get_purchased('upgrades.pro')
|
||||
or _ba.get_purchased('static.pro')
|
||||
or _ba.get_purchased('static.pro_sale')
|
||||
_internal.get_purchased('upgrades.pro')
|
||||
or _internal.get_purchased('static.pro')
|
||||
or _internal.get_purchased('static.pro_sale')
|
||||
or 'ballistica' + 'core' == _ba.appname())
|
||||
|
||||
def have_pro_options(self) -> bool:
|
||||
|
|
@ -199,7 +202,8 @@ class AccountV1Subsystem:
|
|||
# or also if we've been grandfathered in or are using ballistica-core
|
||||
# builds.
|
||||
return self.have_pro() or bool(
|
||||
_ba.get_v1_account_misc_read_val_2('proOptionsUnlocked', False)
|
||||
_internal.get_v1_account_misc_read_val_2('proOptionsUnlocked',
|
||||
False)
|
||||
or _ba.app.config.get('lc14292', 0) > 1)
|
||||
|
||||
def show_post_purchase_message(self) -> None:
|
||||
|
|
@ -221,17 +225,17 @@ class AccountV1Subsystem:
|
|||
from ba._language import Lstr
|
||||
|
||||
# Run any pending promo codes we had queued up while not signed in.
|
||||
if _ba.get_v1_account_state(
|
||||
if _internal.get_v1_account_state(
|
||||
) == 'signed_in' and self.pending_promo_codes:
|
||||
for code in self.pending_promo_codes:
|
||||
_ba.screenmessage(Lstr(resource='submittingPromoCodeText'),
|
||||
color=(0, 1, 0))
|
||||
_ba.add_transaction({
|
||||
_internal.add_transaction({
|
||||
'type': 'PROMO_CODE',
|
||||
'expire_time': time.time() + 5,
|
||||
'code': code
|
||||
})
|
||||
_ba.run_transactions()
|
||||
_internal.run_transactions()
|
||||
self.pending_promo_codes = []
|
||||
|
||||
def add_pending_promo_code(self, code: str) -> None:
|
||||
|
|
@ -242,7 +246,7 @@ class AccountV1Subsystem:
|
|||
# If we're not signed in, queue up the code to run the next time we
|
||||
# are and issue a warning if we haven't signed in within the next
|
||||
# few seconds.
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if _internal.get_v1_account_state() != 'signed_in':
|
||||
|
||||
def check_pending_codes() -> None:
|
||||
"""(internal)"""
|
||||
|
|
@ -259,9 +263,9 @@ class AccountV1Subsystem:
|
|||
return
|
||||
_ba.screenmessage(Lstr(resource='submittingPromoCodeText'),
|
||||
color=(0, 1, 0))
|
||||
_ba.add_transaction({
|
||||
_internal.add_transaction({
|
||||
'type': 'PROMO_CODE',
|
||||
'expire_time': time.time() + 5,
|
||||
'code': code
|
||||
})
|
||||
_ba.run_transactions()
|
||||
_internal.run_transactions()
|
||||
|
|
|
|||
18
dist/ba_data/python/ba/_achievement.py
vendored
18
dist/ba_data/python/ba/_achievement.py
vendored
|
|
@ -6,6 +6,7 @@ from __future__ import annotations
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
from ba import _internal
|
||||
from ba._error import print_exception
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -317,10 +318,13 @@ class AchievementSubsystem:
|
|||
if not ach.complete:
|
||||
|
||||
# Report new achievements to the game-service.
|
||||
_ba.report_achievement(achname)
|
||||
_internal.report_achievement(achname)
|
||||
|
||||
# And to our account.
|
||||
_ba.add_transaction({'type': 'ACHIEVEMENT', 'name': achname})
|
||||
_internal.add_transaction({
|
||||
'type': 'ACHIEVEMENT',
|
||||
'name': achname
|
||||
})
|
||||
|
||||
# Now attempt to show a banner.
|
||||
self.display_achievement_banner(achname)
|
||||
|
|
@ -409,7 +413,7 @@ def _get_ach_mult(include_pro_bonus: bool = False) -> int:
|
|||
|
||||
(just for display; changing this here won't affect actual rewards)
|
||||
"""
|
||||
val: int = _ba.get_v1_account_misc_read_val('achAwardMult', 5)
|
||||
val: int = _internal.get_v1_account_misc_read_val('achAwardMult', 5)
|
||||
assert isinstance(val, int)
|
||||
if include_pro_bonus and _ba.app.accounts_v1.have_pro():
|
||||
val *= 2
|
||||
|
|
@ -496,7 +500,7 @@ class Achievement:
|
|||
# signed in, lets not show them (otherwise we tend to get
|
||||
# confusing 'controller connected' achievements popping up while
|
||||
# waiting to log in which can be confusing).
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if _internal.get_v1_account_state() != 'signed_in':
|
||||
return
|
||||
|
||||
# If we're being freshly complete, display/report it and whatnot.
|
||||
|
|
@ -592,8 +596,8 @@ class Achievement:
|
|||
|
||||
def get_award_ticket_value(self, include_pro_bonus: bool = False) -> int:
|
||||
"""Get the ticket award value for this achievement."""
|
||||
val: int = (_ba.get_v1_account_misc_read_val('achAward.' + self._name,
|
||||
self._award) *
|
||||
val: int = (_internal.get_v1_account_misc_read_val(
|
||||
'achAward.' + self._name, self._award) *
|
||||
_get_ach_mult(include_pro_bonus))
|
||||
assert isinstance(val, int)
|
||||
return val
|
||||
|
|
@ -601,7 +605,7 @@ class Achievement:
|
|||
@property
|
||||
def power_ranking_value(self) -> int:
|
||||
"""Get the power-ranking award value for this achievement."""
|
||||
val: int = _ba.get_v1_account_misc_read_val(
|
||||
val: int = _internal.get_v1_account_misc_read_val(
|
||||
'achLeaguePoints.' + self._name, self._award)
|
||||
assert isinstance(val, int)
|
||||
return val
|
||||
|
|
|
|||
4
dist/ba_data/python/ba/_actor.py
vendored
4
dist/ba_data/python/ba/_actor.py
vendored
|
|
@ -15,7 +15,7 @@ if TYPE_CHECKING:
|
|||
from typing import Any, Literal
|
||||
import ba
|
||||
|
||||
TA = TypeVar('TA', bound='Actor')
|
||||
ActorT = TypeVar('ActorT', bound='Actor')
|
||||
|
||||
|
||||
class Actor:
|
||||
|
|
@ -95,7 +95,7 @@ class Actor:
|
|||
|
||||
return UNHANDLED
|
||||
|
||||
def autoretain(self: TA) -> TA:
|
||||
def autoretain(self: ActorT) -> ActorT:
|
||||
"""Keep this Actor alive without needing to hold a reference to it.
|
||||
|
||||
This keeps the ba.Actor in existence by storing a reference to it
|
||||
|
|
|
|||
21
dist/ba_data/python/ba/_ads.py
vendored
21
dist/ba_data/python/ba/_ads.py
vendored
|
|
@ -7,6 +7,7 @@ import time
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
from ba import _internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any
|
||||
|
|
@ -94,15 +95,15 @@ class AdsSubsystem:
|
|||
launch_count = app.config.get('launchCount', 0)
|
||||
|
||||
# If we're seeing short ads we may want to space them differently.
|
||||
interval_mult = (_ba.get_v1_account_misc_read_val(
|
||||
interval_mult = (_internal.get_v1_account_misc_read_val(
|
||||
'ads.shortIntervalMult', 1.0)
|
||||
if self.last_ad_was_short else 1.0)
|
||||
if self.ad_amt is None:
|
||||
if launch_count <= 1:
|
||||
self.ad_amt = _ba.get_v1_account_misc_read_val(
|
||||
self.ad_amt = _internal.get_v1_account_misc_read_val(
|
||||
'ads.startVal1', 0.99)
|
||||
else:
|
||||
self.ad_amt = _ba.get_v1_account_misc_read_val(
|
||||
self.ad_amt = _internal.get_v1_account_misc_read_val(
|
||||
'ads.startVal2', 1.0)
|
||||
interval = None
|
||||
else:
|
||||
|
|
@ -111,15 +112,17 @@ class AdsSubsystem:
|
|||
# (we reach our threshold faster the longer we've been
|
||||
# playing).
|
||||
base = 'ads' if _ba.has_video_ads() else 'ads2'
|
||||
min_lc = _ba.get_v1_account_misc_read_val(base + '.minLC', 0.0)
|
||||
max_lc = _ba.get_v1_account_misc_read_val(base + '.maxLC', 5.0)
|
||||
min_lc_scale = (_ba.get_v1_account_misc_read_val(
|
||||
min_lc = _internal.get_v1_account_misc_read_val(
|
||||
base + '.minLC', 0.0)
|
||||
max_lc = _internal.get_v1_account_misc_read_val(
|
||||
base + '.maxLC', 5.0)
|
||||
min_lc_scale = (_internal.get_v1_account_misc_read_val(
|
||||
base + '.minLCScale', 0.25))
|
||||
max_lc_scale = (_ba.get_v1_account_misc_read_val(
|
||||
max_lc_scale = (_internal.get_v1_account_misc_read_val(
|
||||
base + '.maxLCScale', 0.34))
|
||||
min_lc_interval = (_ba.get_v1_account_misc_read_val(
|
||||
min_lc_interval = (_internal.get_v1_account_misc_read_val(
|
||||
base + '.minLCInterval', 360))
|
||||
max_lc_interval = (_ba.get_v1_account_misc_read_val(
|
||||
max_lc_interval = (_internal.get_v1_account_misc_read_val(
|
||||
base + '.maxLCInterval', 300))
|
||||
if launch_count < min_lc:
|
||||
lc_amt = 0.0
|
||||
|
|
|
|||
43
dist/ba_data/python/ba/_app.py
vendored
43
dist/ba_data/python/ba/_app.py
vendored
|
|
@ -20,11 +20,13 @@ from ba._meta import MetadataSubsystem
|
|||
from ba._ads import AdsSubsystem
|
||||
from ba._net import NetworkSubsystem
|
||||
from ba._workspace import WorkspaceSubsystem
|
||||
from ba import _internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import asyncio
|
||||
from typing import Any, Callable
|
||||
|
||||
import efro.log
|
||||
import ba
|
||||
from ba._cloud import CloudSubsystem
|
||||
from bastd.actor import spazappearance
|
||||
|
|
@ -48,6 +50,7 @@ class App:
|
|||
# Implementations for these will be filled in by internal libs.
|
||||
accounts_v2: AccountV2Subsystem
|
||||
cloud: CloudSubsystem
|
||||
log_handler: efro.log.LogHandler
|
||||
|
||||
class State(Enum):
|
||||
"""High level state the app can be in."""
|
||||
|
|
@ -91,6 +94,12 @@ class App:
|
|||
assert isinstance(self._env['build_number'], int)
|
||||
return self._env['build_number']
|
||||
|
||||
@property
|
||||
def device_name(self) -> str:
|
||||
"""Name of the device running the game."""
|
||||
assert isinstance(self._env['device_name'], str)
|
||||
return self._env['device_name']
|
||||
|
||||
@property
|
||||
def config_file_path(self) -> str:
|
||||
"""Where the game's config file is stored on disk."""
|
||||
|
|
@ -223,6 +232,7 @@ class App:
|
|||
|
||||
self._launch_completed = False
|
||||
self._initial_login_completed = False
|
||||
self._meta_scan_completed = False
|
||||
self._called_on_app_running = False
|
||||
self._app_paused = False
|
||||
|
||||
|
|
@ -344,6 +354,7 @@ class App:
|
|||
from bastd.actor import spazappearance
|
||||
from ba._generated.enums import TimeType
|
||||
|
||||
assert _ba.in_logic_thread()
|
||||
|
||||
self._aioloop = _asyncio.setup_asyncio()
|
||||
|
||||
|
|
@ -370,12 +381,12 @@ class App:
|
|||
# Non-test, non-debug builds should generally be blessed; warn if not.
|
||||
# (so I don't accidentally release a build that can't play tourneys)
|
||||
if (not self.debug_build and not self.test_build
|
||||
and not _ba.is_blessed()):
|
||||
and not _internal.is_blessed()):
|
||||
_ba.screenmessage('WARNING: NON-BLESSED BUILD', color=(1, 0, 0))
|
||||
|
||||
# If there's a leftover log file, attempt to upload it to the
|
||||
# master-server and/or get rid of it.
|
||||
_apputils.handle_leftover_log_file()
|
||||
_apputils.handle_leftover_v1_cloud_log_file()
|
||||
|
||||
# Only do this stuff if our config file is healthy so we don't
|
||||
# overwrite a broken one or whatnot and wipe out data.
|
||||
|
|
@ -408,7 +419,8 @@ class App:
|
|||
def check_special_offer() -> None:
|
||||
from bastd.ui.specialoffer import show_offer
|
||||
config = self.config
|
||||
if ('pendingSpecialOffer' in config and _ba.get_public_login_id()
|
||||
if ('pendingSpecialOffer' in config
|
||||
and _internal.get_public_login_id()
|
||||
== config['pendingSpecialOffer']['a']):
|
||||
self.special_offer = config['pendingSpecialOffer']['o']
|
||||
show_offer()
|
||||
|
|
@ -416,6 +428,9 @@ class App:
|
|||
if not self.headless_mode:
|
||||
_ba.timer(3.0, check_special_offer, timetype=TimeType.REAL)
|
||||
|
||||
# Get meta-system scanning built-in stuff in the bg.
|
||||
self.meta.start_scan(scan_complete_cb=self.on_meta_scan_complete)
|
||||
|
||||
self.accounts_v2.on_app_launch()
|
||||
self.accounts_v1.on_app_launch()
|
||||
|
||||
|
|
@ -430,17 +445,27 @@ class App:
|
|||
def on_app_running(self) -> None:
|
||||
"""Called when initially entering the running state."""
|
||||
|
||||
self.meta.on_app_running()
|
||||
self.plugins.on_app_running()
|
||||
|
||||
# from ba._dependency import test_depset
|
||||
# test_depset()
|
||||
|
||||
def on_meta_scan_complete(self) -> None:
|
||||
"""Called by meta-scan when it is done doing its thing."""
|
||||
assert _ba.in_logic_thread()
|
||||
self.plugins.on_meta_scan_complete()
|
||||
|
||||
assert not self._meta_scan_completed
|
||||
self._meta_scan_completed = True
|
||||
self._update_state()
|
||||
|
||||
def _update_state(self) -> None:
|
||||
assert _ba.in_logic_thread()
|
||||
|
||||
if self._app_paused:
|
||||
self.state = self.State.PAUSED
|
||||
else:
|
||||
if self._initial_login_completed:
|
||||
if self._initial_login_completed and self._meta_scan_completed:
|
||||
self.state = self.State.RUNNING
|
||||
if not self._called_on_app_running:
|
||||
self._called_on_app_running = True
|
||||
|
|
@ -562,11 +587,11 @@ class App:
|
|||
|
||||
# Kick off a little transaction so we'll hopefully have all the
|
||||
# latest account state when we get back to the menu.
|
||||
_ba.add_transaction({
|
||||
_internal.add_transaction({
|
||||
'type': 'END_SESSION',
|
||||
'sType': str(type(host_session))
|
||||
})
|
||||
_ba.run_transactions()
|
||||
_internal.run_transactions()
|
||||
|
||||
host_session.end()
|
||||
|
||||
|
|
@ -651,5 +676,9 @@ class App:
|
|||
This should also run after a short amount of time if no login
|
||||
has occurred.
|
||||
"""
|
||||
# Tell meta it can start scanning extra stuff that just showed up
|
||||
# (account workspaces).
|
||||
self.meta.start_extra_scan()
|
||||
|
||||
self._initial_login_completed = True
|
||||
self._update_state()
|
||||
|
|
|
|||
9
dist/ba_data/python/ba/_appconfig.py
vendored
9
dist/ba_data/python/ba/_appconfig.py
vendored
|
|
@ -128,12 +128,6 @@ def read_config() -> tuple[AppConfig, bool]:
|
|||
shutil.copyfile(config_file_path, config_file_path + '.broken')
|
||||
except Exception as exc2:
|
||||
print('EXC copying broken config:', exc2)
|
||||
try:
|
||||
_ba.log('broken config contents:\n' +
|
||||
config_contents.replace('\000', '<NULL_BYTE>'),
|
||||
to_stdout=False)
|
||||
except Exception as exc2:
|
||||
print('EXC logging broken config contents:', exc2)
|
||||
config = AppConfig()
|
||||
|
||||
# Now attempt to read one of our 'prev' backup copies.
|
||||
|
|
@ -159,8 +153,9 @@ def commit_app_config(force: bool = False) -> None:
|
|||
|
||||
(internal)
|
||||
"""
|
||||
from ba._internal import mark_config_dirty
|
||||
if not _ba.app.config_file_healthy and not force:
|
||||
print('Current config file is broken; '
|
||||
'skipping write to avoid losing settings.')
|
||||
return
|
||||
_ba.mark_config_dirty()
|
||||
mark_config_dirty()
|
||||
|
|
|
|||
24
dist/ba_data/python/ba/_apputils.py
vendored
24
dist/ba_data/python/ba/_apputils.py
vendored
|
|
@ -50,7 +50,7 @@ def should_submit_debug_info() -> bool:
|
|||
return _ba.app.config.get('Submit Debug Info', True)
|
||||
|
||||
|
||||
def handle_log() -> None:
|
||||
def handle_v1_cloud_log() -> None:
|
||||
"""Called on debug log prints.
|
||||
|
||||
When this happens, we can upload our log to the server
|
||||
|
|
@ -58,6 +58,7 @@ def handle_log() -> None:
|
|||
"""
|
||||
from ba._net import master_server_post
|
||||
from ba._generated.enums import TimeType
|
||||
from ba._internal import get_news_show
|
||||
app = _ba.app
|
||||
app.log_have_new = True
|
||||
if not app.log_upload_timer_started:
|
||||
|
|
@ -73,7 +74,7 @@ def handle_log() -> None:
|
|||
activityname = 'unavailable'
|
||||
|
||||
info = {
|
||||
'log': _ba.getlog(),
|
||||
'log': _ba.get_v1_cloud_log(),
|
||||
'version': app.version,
|
||||
'build': app.build_number,
|
||||
'userAgentString': app.user_agent_string,
|
||||
|
|
@ -82,8 +83,8 @@ def handle_log() -> None:
|
|||
'fatal': 0,
|
||||
'userRanCommands': _ba.has_user_run_commands(),
|
||||
'time': _ba.time(TimeType.REAL),
|
||||
'userModded': _ba.has_user_mods(),
|
||||
'newsShow': _ba.get_news_show(),
|
||||
'userModded': _ba.workspaces_in_use(),
|
||||
'newsShow': get_news_show(),
|
||||
}
|
||||
|
||||
def response(data: Any) -> None:
|
||||
|
|
@ -107,7 +108,7 @@ def handle_log() -> None:
|
|||
def _reset() -> None:
|
||||
app.log_upload_timer_started = False
|
||||
if app.log_have_new:
|
||||
handle_log()
|
||||
handle_v1_cloud_log()
|
||||
|
||||
if not _ba.is_log_full():
|
||||
with _ba.Context('ui'):
|
||||
|
|
@ -117,14 +118,15 @@ def handle_log() -> None:
|
|||
suppress_format_warning=True)
|
||||
|
||||
|
||||
def handle_leftover_log_file() -> None:
|
||||
"""Handle an un-uploaded log from a previous run."""
|
||||
def handle_leftover_v1_cloud_log_file() -> None:
|
||||
"""Handle an un-uploaded v1-cloud-log from a previous run."""
|
||||
try:
|
||||
import json
|
||||
from ba._net import master_server_post
|
||||
|
||||
if os.path.exists(_ba.get_log_file_path()):
|
||||
with open(_ba.get_log_file_path(), encoding='utf-8') as infile:
|
||||
if os.path.exists(_ba.get_v1_cloud_log_file_path()):
|
||||
with open(_ba.get_v1_cloud_log_file_path(),
|
||||
encoding='utf-8') as infile:
|
||||
info = json.loads(infile.read())
|
||||
infile.close()
|
||||
do_send = should_submit_debug_info()
|
||||
|
|
@ -135,7 +137,7 @@ def handle_leftover_log_file() -> None:
|
|||
# lets kill it.
|
||||
if data is not None:
|
||||
try:
|
||||
os.remove(_ba.get_log_file_path())
|
||||
os.remove(_ba.get_v1_cloud_log_file_path())
|
||||
except FileNotFoundError:
|
||||
# Saw this in the wild. The file just existed
|
||||
# a moment ago but I suppose something could have
|
||||
|
|
@ -145,7 +147,7 @@ def handle_leftover_log_file() -> None:
|
|||
master_server_post('bsLog', info, response)
|
||||
else:
|
||||
# If they don't want logs uploaded just kill it.
|
||||
os.remove(_ba.get_log_file_path())
|
||||
os.remove(_ba.get_v1_cloud_log_file_path())
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception('Error handling leftover log file.')
|
||||
|
|
|
|||
4
dist/ba_data/python/ba/_asyncio.py
vendored
4
dist/ba_data/python/ba/_asyncio.py
vendored
|
|
@ -18,7 +18,7 @@ import os
|
|||
if TYPE_CHECKING:
|
||||
import ba
|
||||
|
||||
# Our timer and event loop for the ballistica game thread.
|
||||
# Our timer and event loop for the ballistica logic thread.
|
||||
_asyncio_timer: ba.Timer | None = None
|
||||
_asyncio_event_loop: asyncio.AbstractEventLoop | None = None
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ def setup_asyncio() -> asyncio.AbstractEventLoop:
|
|||
import ba
|
||||
from ba._generated.enums import TimeType
|
||||
|
||||
assert _ba.in_game_thread()
|
||||
assert _ba.in_logic_thread()
|
||||
|
||||
# Create our event-loop. We don't expect there to be one
|
||||
# running on this thread before we do.
|
||||
|
|
|
|||
175
dist/ba_data/python/ba/_bootstrap.py
vendored
Normal file
175
dist/ba_data/python/ba/_bootstrap.py
vendored
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Bootstrapping."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from efro.log import setup_logging, LogLevel
|
||||
import _ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
from efro.log import LogEntry
|
||||
|
||||
_g_did_bootstrap = False # pylint: disable=invalid-name
|
||||
|
||||
|
||||
def bootstrap() -> None:
|
||||
"""Run bootstrapping logic.
|
||||
|
||||
This is the very first ballistica code that runs (aside from imports).
|
||||
It sets up low level environment bits and creates the app instance.
|
||||
"""
|
||||
|
||||
global _g_did_bootstrap # pylint: disable=global-statement, invalid-name
|
||||
if _g_did_bootstrap:
|
||||
raise RuntimeError('Bootstrap has already been called.')
|
||||
_g_did_bootstrap = True
|
||||
|
||||
# The first thing we do is set up our logging system and feed
|
||||
# Python's stdout/stderr into it. Then we can at least debug problems
|
||||
# on systems where native stdout/stderr is not easily accessible
|
||||
# such as Android.
|
||||
log_handler = setup_logging(log_path=None,
|
||||
level=LogLevel.DEBUG,
|
||||
suppress_non_root_debug=True,
|
||||
log_stdout_stderr=True,
|
||||
cache_size_limit=1024 * 1024)
|
||||
|
||||
log_handler.add_callback(_on_log)
|
||||
|
||||
env = _ba.env()
|
||||
|
||||
# Give a soft warning if we're being used with a different binary
|
||||
# version than we expect.
|
||||
expected_build = 20882
|
||||
running_build: int = env['build_number']
|
||||
if running_build != expected_build:
|
||||
print(
|
||||
f'WARNING: These script files are meant to be used with'
|
||||
f' Ballistica build {expected_build}.\n'
|
||||
f' You are running build {running_build}.'
|
||||
f' This might cause the app to error or misbehave.',
|
||||
file=sys.stderr)
|
||||
|
||||
# In bootstrap_monolithic.py we told Python not to handle SIGINT itself
|
||||
# (because that must be done in the main thread). Now we finish the
|
||||
# job by adding our own handler to replace it.
|
||||
|
||||
# Note: I've found we need to set up our C signal handling AFTER
|
||||
# we've told Python to disable its own; otherwise (on Mac at least) it
|
||||
# wipes out our existing C handler.
|
||||
_ba.setup_sigint()
|
||||
|
||||
# Sanity check: we should always be run in UTF-8 mode.
|
||||
if sys.flags.utf8_mode != 1:
|
||||
print(
|
||||
'ERROR: Python\'s UTF-8 mode is not set.'
|
||||
' This will likely result in errors.',
|
||||
file=sys.stderr)
|
||||
|
||||
debug_build = env['debug_build']
|
||||
|
||||
# We expect dev_mode on in debug builds and off otherwise.
|
||||
if debug_build != sys.flags.dev_mode:
|
||||
print(
|
||||
f'WARNING: Mismatch in debug_build {debug_build}'
|
||||
f' and sys.flags.dev_mode {sys.flags.dev_mode}',
|
||||
file=sys.stderr)
|
||||
|
||||
# In embedded situations (when we're providing our own Python) let's
|
||||
# also provide our own root certs so ssl works. We can consider overriding
|
||||
# this in particular embedded cases if we can verify that system certs
|
||||
# are working.
|
||||
# (We also allow forcing this via an env var if the user desires)
|
||||
if (_ba.contains_python_dist()
|
||||
or os.environ.get('BA_USE_BUNDLED_ROOT_CERTS') == '1'):
|
||||
import certifi
|
||||
|
||||
# Let both OpenSSL and requests (if present) know to use this.
|
||||
os.environ['SSL_CERT_FILE'] = os.environ['REQUESTS_CA_BUNDLE'] = (
|
||||
certifi.where())
|
||||
|
||||
# On Windows I'm seeing the following error creating asyncio loops in
|
||||
# background threads with the default proactor setup:
|
||||
# ValueError: set_wakeup_fd only works in main thread of the main
|
||||
# interpreter
|
||||
# So let's explicitly request selector loops.
|
||||
# Interestingly this error only started showing up once I moved
|
||||
# Python init to the main thread; previously the various asyncio
|
||||
# bg thread loops were working fine (maybe something caused them
|
||||
# to default to selector in that case?..
|
||||
if sys.platform == 'win32':
|
||||
import asyncio
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
|
||||
# pylint: disable=c-extension-no-member
|
||||
if not TYPE_CHECKING:
|
||||
import __main__
|
||||
|
||||
# Clear out the standard quit/exit messages since they don't
|
||||
# work for us.
|
||||
del __main__.__builtins__.quit
|
||||
del __main__.__builtins__.exit
|
||||
|
||||
# Also replace standard interactive help with our simplified
|
||||
# one which is more friendly to cloud/in-game console situations.
|
||||
__main__.__builtins__.help = _CustomHelper()
|
||||
|
||||
# Now spin up our App instance and store it on both _ba and ba.
|
||||
from ba._app import App
|
||||
import ba
|
||||
_ba.app = ba.app = App()
|
||||
_ba.app.log_handler = log_handler
|
||||
|
||||
|
||||
class _CustomHelper:
|
||||
"""Replacement 'help' that behaves better for our setup."""
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return 'Type help(object) for help about object.'
|
||||
|
||||
def __call__(self, *args: Any, **kwds: Any) -> Any:
|
||||
# We get an ugly error importing pydoc on our embedded
|
||||
# platforms due to _sysconfigdata_xxx.py not being present
|
||||
# (but then things mostly work). Let's get the ugly error out
|
||||
# of the way explicitly.
|
||||
import sysconfig
|
||||
try:
|
||||
# This errors once but seems to run cleanly after, so let's
|
||||
# get the error out of the way.
|
||||
sysconfig.get_path('stdlib')
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
import pydoc
|
||||
# Disable pager and interactive help since neither works well
|
||||
# with our funky multi-threaded setup or in-game/cloud consoles.
|
||||
# Let's just do simple text dumps.
|
||||
pydoc.pager = pydoc.plainpager
|
||||
if not args and not kwds:
|
||||
print('Interactive help is not available in this environment.\n'
|
||||
'Type help(object) for help about object.')
|
||||
return None
|
||||
return pydoc.help(*args, **kwds)
|
||||
|
||||
|
||||
def _on_log(entry: LogEntry) -> None:
|
||||
|
||||
# Just forward this along to the engine to display in the in-game console,
|
||||
# in the Android log, etc.
|
||||
_ba.display_log(
|
||||
name=entry.name,
|
||||
level=entry.level.name,
|
||||
message=entry.message,
|
||||
)
|
||||
|
||||
# We also want to feed some logs to the old V1-cloud-log system.
|
||||
# Let's go with anything warning or higher as well as the stdout/stderr
|
||||
# log messages that ba.app.log_handler creates for us.
|
||||
if entry.level.value >= LogLevel.WARNING.value or entry.name in ('stdout',
|
||||
'stderr'):
|
||||
_ba.v1_cloud_log(entry.message)
|
||||
43
dist/ba_data/python/ba/_cloud.py
vendored
43
dist/ba_data/python/ba/_cloud.py
vendored
|
|
@ -99,3 +99,46 @@ class CloudSubsystem:
|
|||
Must be called from a background thread.
|
||||
"""
|
||||
raise RuntimeError('Cloud functionality is not available.')
|
||||
|
||||
|
||||
def cloud_console_exec(code: str) -> None:
|
||||
"""Called by the cloud console to run code in the logic thread."""
|
||||
import sys
|
||||
import logging
|
||||
import __main__
|
||||
from ba._generated.enums import TimeType
|
||||
try:
|
||||
|
||||
# First try it as eval.
|
||||
try:
|
||||
evalcode = compile(code, '<console>', 'eval')
|
||||
except SyntaxError:
|
||||
evalcode = None
|
||||
except Exception:
|
||||
# hmm; when we can't compile it as eval will we always get
|
||||
# syntax error?
|
||||
logging.exception(
|
||||
'unexpected error compiling code for cloud-console eval.')
|
||||
evalcode = None
|
||||
if evalcode is not None:
|
||||
# pylint: disable=eval-used
|
||||
value = eval(evalcode, vars(__main__), vars(__main__))
|
||||
# For eval-able statements, print the resulting value if
|
||||
# it is not None (just like standard Python interpreter).
|
||||
if value is not None:
|
||||
print(repr(value), file=sys.stderr)
|
||||
|
||||
# Fall back to exec if we couldn't compile it as eval.
|
||||
else:
|
||||
execcode = compile(code, '<console>', 'exec')
|
||||
# pylint: disable=exec-used
|
||||
exec(execcode, vars(__main__), vars(__main__))
|
||||
except Exception:
|
||||
import traceback
|
||||
apptime = _ba.time(TimeType.REAL)
|
||||
print(f'Exec error at time {apptime:.2f}.', file=sys.stderr)
|
||||
traceback.print_exc()
|
||||
|
||||
# This helps the logging system ship stderr back to the
|
||||
# cloud promptly.
|
||||
sys.stderr.flush()
|
||||
|
|
|
|||
18
dist/ba_data/python/ba/_coopgame.py
vendored
18
dist/ba_data/python/ba/_coopgame.py
vendored
|
|
@ -6,6 +6,7 @@ from __future__ import annotations
|
|||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
import _ba
|
||||
from ba import _internal
|
||||
from ba._gameactivity import GameActivity
|
||||
from ba._general import WeakCall
|
||||
|
||||
|
|
@ -54,19 +55,6 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]):
|
|||
# Preload achievement images in case we get some.
|
||||
_ba.timer(2.0, WeakCall(self._preload_achievements))
|
||||
|
||||
# Let's ask the server for a 'time-to-beat' value.
|
||||
levelname = self._get_coop_level_name()
|
||||
campaign = self.session.campaign
|
||||
assert campaign is not None
|
||||
config_str = (str(len(self.players)) + 'p' + campaign.getlevel(
|
||||
self.settings_raw['name']).get_score_version_string().replace(
|
||||
' ', '_'))
|
||||
_ba.get_scores_to_beat(levelname, config_str,
|
||||
WeakCall(self._on_got_scores_to_beat))
|
||||
|
||||
def _on_got_scores_to_beat(self, scores: list[dict[str, Any]]) -> None:
|
||||
pass
|
||||
|
||||
def _show_standard_scores_to_beat_ui(self,
|
||||
scores: list[dict[str, Any]]) -> None:
|
||||
from efro.util import asserttype
|
||||
|
|
@ -217,10 +205,10 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]):
|
|||
self._achievements_awarded.add(achievement_name)
|
||||
|
||||
# Report new achievements to the game-service.
|
||||
_ba.report_achievement(achievement_name)
|
||||
_internal.report_achievement(achievement_name)
|
||||
|
||||
# ...and to our account.
|
||||
_ba.add_transaction({
|
||||
_internal.add_transaction({
|
||||
'type': 'ACHIEVEMENT',
|
||||
'name': achievement_name
|
||||
})
|
||||
|
|
|
|||
5
dist/ba_data/python/ba/_error.py
vendored
5
dist/ba_data/python/ba/_error.py
vendored
|
|
@ -125,6 +125,11 @@ class WidgetNotFoundError(NotFoundError):
|
|||
"""
|
||||
|
||||
|
||||
# TODO: Should integrate some sort of context printing into our
|
||||
# log handling so we can just use logging.exception() and kill these
|
||||
# two functions.
|
||||
|
||||
|
||||
def print_exception(*args: Any, **keywds: Any) -> None:
|
||||
"""Print info about an exception along with pertinent context state.
|
||||
|
||||
|
|
|
|||
19
dist/ba_data/python/ba/_gameactivity.py
vendored
19
dist/ba_data/python/ba/_gameactivity.py
vendored
|
|
@ -9,6 +9,7 @@ import random
|
|||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
import _ba
|
||||
from ba import _internal
|
||||
from ba._activity import Activity
|
||||
from ba._score import ScoreConfig
|
||||
from ba._language import Lstr
|
||||
|
|
@ -17,6 +18,7 @@ from ba._error import NotFoundError, print_error, print_exception
|
|||
from ba._general import Call, WeakCall
|
||||
from ba._player import PlayerInfo
|
||||
from ba import _map
|
||||
from ba import _store
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable, Sequence
|
||||
|
|
@ -239,11 +241,11 @@ class GameActivity(Activity[PlayerType, TeamType]):
|
|||
self._zoom_message_times: dict[int, float] = {}
|
||||
self._is_waiting_for_continue = False
|
||||
|
||||
self._continue_cost = _ba.get_v1_account_misc_read_val(
|
||||
self._continue_cost = _internal.get_v1_account_misc_read_val(
|
||||
'continueStartCost', 25)
|
||||
self._continue_cost_mult = _ba.get_v1_account_misc_read_val(
|
||||
self._continue_cost_mult = _internal.get_v1_account_misc_read_val(
|
||||
'continuesMult', 2)
|
||||
self._continue_cost_offset = _ba.get_v1_account_misc_read_val(
|
||||
self._continue_cost_offset = _internal.get_v1_account_misc_read_val(
|
||||
'continuesOffset', 0)
|
||||
|
||||
@property
|
||||
|
|
@ -363,11 +365,11 @@ class GameActivity(Activity[PlayerType, TeamType]):
|
|||
if do_continue:
|
||||
_ba.playsound(_ba.getsound('shieldUp'))
|
||||
_ba.playsound(_ba.getsound('cashRegister'))
|
||||
_ba.add_transaction({
|
||||
_internal.add_transaction({
|
||||
'type': 'CONTINUE',
|
||||
'cost': self._continue_cost
|
||||
})
|
||||
_ba.run_transactions()
|
||||
_internal.run_transactions()
|
||||
self._continue_cost = (
|
||||
self._continue_cost * self._continue_cost_mult +
|
||||
self._continue_cost_offset)
|
||||
|
|
@ -390,7 +392,8 @@ class GameActivity(Activity[PlayerType, TeamType]):
|
|||
from ba._generated.enums import TimeType
|
||||
|
||||
try:
|
||||
if _ba.get_v1_account_misc_read_val('enableContinues', False):
|
||||
if _internal.get_v1_account_misc_read_val('enableContinues',
|
||||
False):
|
||||
session = self.session
|
||||
|
||||
# We only support continuing in non-tournament games.
|
||||
|
|
@ -453,7 +456,7 @@ class GameActivity(Activity[PlayerType, TeamType]):
|
|||
# time is left.
|
||||
tournament_id = self.session.tournament_id
|
||||
if tournament_id is not None:
|
||||
_ba.tournament_query(
|
||||
_internal.tournament_query(
|
||||
args={
|
||||
'tournamentIDs': [tournament_id],
|
||||
'source': 'in-game time remaining query'
|
||||
|
|
@ -1159,7 +1162,7 @@ class GameActivity(Activity[PlayerType, TeamType]):
|
|||
else:
|
||||
# If settings doesn't specify a map, pick a random one from the
|
||||
# list of supported ones.
|
||||
unowned_maps = _map.get_unowned_maps()
|
||||
unowned_maps = _store.get_unowned_maps()
|
||||
valid_maps: list[str] = [
|
||||
m for m in self.get_supported_maps(type(self.session))
|
||||
if m not in unowned_maps
|
||||
|
|
|
|||
10
dist/ba_data/python/ba/_general.py
vendored
10
dist/ba_data/python/ba/_general.py
vendored
|
|
@ -31,13 +31,11 @@ class Existable(Protocol):
|
|||
"""Whether this object exists."""
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
ExistableType = TypeVar('ExistableType', bound=Existable)
|
||||
# pylint: enable=invalid-name
|
||||
ExistableT = TypeVar('ExistableT', bound=Existable)
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
def existing(obj: ExistableType | None) -> ExistableType | None:
|
||||
def existing(obj: ExistableT | None) -> ExistableT | None:
|
||||
"""Convert invalid references to None for any ba.Existable object.
|
||||
|
||||
Category: **Gameplay Functions**
|
||||
|
|
@ -251,6 +249,10 @@ class _Call:
|
|||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# Some interaction between our ballistica pylint plugin
|
||||
# and this code is crashing starting on pylint 2.15.0.
|
||||
# This seems to fix things for now.
|
||||
# pylint: disable=all
|
||||
WeakCall = Call
|
||||
Call = Call
|
||||
else:
|
||||
|
|
|
|||
9
dist/ba_data/python/ba/_hooks.py
vendored
9
dist/ba_data/python/ba/_hooks.py
vendored
|
|
@ -16,6 +16,7 @@ from __future__ import annotations
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
from ba import _internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Sequence, Any
|
||||
|
|
@ -24,10 +25,10 @@ if TYPE_CHECKING:
|
|||
|
||||
def finish_bootstrapping() -> None:
|
||||
"""Do final bootstrapping related bits."""
|
||||
assert _ba.in_game_thread()
|
||||
assert _ba.in_logic_thread()
|
||||
|
||||
# Kick off our asyncio event handling, allowing us to use coroutines
|
||||
# in our game thread alongside our internal event handling.
|
||||
# in our logic thread alongside our internal event handling.
|
||||
# setup_asyncio()
|
||||
|
||||
# Ok, bootstrapping is done; time to get the show started.
|
||||
|
|
@ -189,8 +190,8 @@ def unavailable_message() -> None:
|
|||
|
||||
|
||||
def submit_analytics_counts(sval: str) -> None:
|
||||
_ba.add_transaction({'type': 'ANALYTICS_COUNTS', 'values': sval})
|
||||
_ba.run_transactions()
|
||||
_internal.add_transaction({'type': 'ANALYTICS_COUNTS', 'values': sval})
|
||||
_internal.run_transactions()
|
||||
|
||||
|
||||
def set_last_ad_network(sval: str) -> None:
|
||||
|
|
|
|||
3
dist/ba_data/python/ba/_input.py
vendored
3
dist/ba_data/python/ba/_input.py
vendored
|
|
@ -6,6 +6,7 @@ from __future__ import annotations
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
from ba._internal import get_v1_account_display_string
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -639,5 +640,5 @@ def get_last_player_name_from_input_device(device: ba.InputDevice) -> str:
|
|||
if profilename == '_random':
|
||||
profilename = device.get_default_player_name()
|
||||
if profilename == '__account__':
|
||||
profilename = _ba.get_v1_account_display_string()
|
||||
profilename = get_v1_account_display_string()
|
||||
return profilename
|
||||
|
|
|
|||
367
dist/ba_data/python/ba/_internal.py
vendored
Normal file
367
dist/ba_data/python/ba/_internal.py
vendored
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""A soft wrapper around _bainternal.
|
||||
|
||||
This allows code to use _bainternal functionality and get warnings
|
||||
or fallbacks in some cases instead of hard errors. Code that absolutely
|
||||
relies on the presence of _bainternal can just use that module directly.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
# noinspection PyUnresolvedReferences
|
||||
import _bainternal
|
||||
HAVE_INTERNAL = True
|
||||
except ImportError:
|
||||
HAVE_INTERNAL = False
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any
|
||||
|
||||
|
||||
# Code that will function without _bainternal but which should be updated
|
||||
# to account for its absence should call this to draw attention to itself.
|
||||
def _no_bainternal_warning() -> None:
|
||||
import logging
|
||||
logging.warning('INTERNAL CALL RUN WITHOUT INTERNAL PRESENT.')
|
||||
|
||||
|
||||
# Code that won't work without _bainternal should raise these errors.
|
||||
def _no_bainternal_error() -> RuntimeError:
|
||||
raise RuntimeError('_bainternal is not present')
|
||||
|
||||
|
||||
def get_v2_fleet() -> str:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_v2_fleet()
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def get_master_server_address(source: int = -1, version: int = 1) -> str:
|
||||
"""(internal)
|
||||
|
||||
Return the address of the master server.
|
||||
"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_master_server_address(source=source,
|
||||
version=version)
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def is_blessed() -> bool:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.is_blessed()
|
||||
|
||||
# Harmless to always just say no here.
|
||||
return False
|
||||
|
||||
|
||||
def get_news_show() -> str:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_news_show()
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def game_service_has_leaderboard(game: str, config: str) -> bool:
|
||||
"""(internal)
|
||||
|
||||
Given a game and config string, returns whether there is a leaderboard
|
||||
for it on the game service.
|
||||
"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.game_service_has_leaderboard(game=game,
|
||||
config=config)
|
||||
# Harmless to always just say no here.
|
||||
return False
|
||||
|
||||
|
||||
def report_achievement(achievement: str, pass_to_account: bool = True) -> None:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.report_achievement(achievement=achievement,
|
||||
pass_to_account=pass_to_account)
|
||||
return
|
||||
|
||||
# Need to see if this actually still works as expected.. warning for now.
|
||||
_no_bainternal_warning()
|
||||
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def submit_score(game: str,
|
||||
config: str,
|
||||
name: Any,
|
||||
score: int | None,
|
||||
callback: Callable,
|
||||
friend_callback: Callable | None,
|
||||
order: str = 'increasing',
|
||||
tournament_id: str | None = None,
|
||||
score_type: str = 'points',
|
||||
campaign: str | None = None,
|
||||
level: str | None = None) -> None:
|
||||
"""(internal)
|
||||
|
||||
Submit a score to the server; callback will be called with the results.
|
||||
As a courtesy, please don't send fake scores to the server. I'd prefer
|
||||
to devote my time to improving the game instead of trying to make the
|
||||
score server more mischief-proof.
|
||||
"""
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.submit_score(game=game,
|
||||
config=config,
|
||||
name=name,
|
||||
score=score,
|
||||
callback=callback,
|
||||
friend_callback=friend_callback,
|
||||
order=order,
|
||||
tournament_id=tournament_id,
|
||||
score_type=score_type,
|
||||
campaign=campaign,
|
||||
level=level)
|
||||
return
|
||||
# This technically breaks since callback will never be called/etc.
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def tournament_query(callback: Callable[[dict | None], None],
|
||||
args: dict) -> None:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.tournament_query(callback=callback, args=args)
|
||||
return
|
||||
|
||||
# This technically breaks since callback will never be called/etc.
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def power_ranking_query(callback: Callable, season: Any = None) -> None:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.power_ranking_query(callback=callback, season=season)
|
||||
return
|
||||
|
||||
# This technically breaks since callback will never be called/etc.
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def restore_purchases() -> None:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.restore_purchases()
|
||||
return
|
||||
|
||||
# This shouldn't break anything but should try to avoid calling it.
|
||||
_no_bainternal_warning()
|
||||
|
||||
|
||||
def purchase(item: str) -> None:
|
||||
"""(internal)"""
|
||||
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.purchase(item)
|
||||
return
|
||||
|
||||
# This won't break messily but won't function as intended.
|
||||
_no_bainternal_warning()
|
||||
|
||||
|
||||
def get_purchases_state() -> int:
|
||||
"""(internal)"""
|
||||
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_purchases_state()
|
||||
|
||||
# This won't function correctly without internal.
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def get_purchased(item: str) -> bool:
|
||||
"""(internal)"""
|
||||
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_purchased(item)
|
||||
|
||||
# Without internal we can just assume no purchases.
|
||||
return False
|
||||
|
||||
|
||||
def get_price(item: str) -> str | None:
|
||||
"""(internal)"""
|
||||
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_price(item)
|
||||
|
||||
# Without internal we can just assume no prices.
|
||||
return None
|
||||
|
||||
|
||||
def in_game_purchase(item: str, price: int) -> None:
|
||||
"""(internal)"""
|
||||
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.in_game_purchase(item=item, price=price)
|
||||
return
|
||||
|
||||
# Without internal this doesn't function as expected.
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def add_transaction(transaction: dict,
|
||||
callback: Callable | None = None) -> None:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.add_transaction(transaction=transaction, callback=callback)
|
||||
return
|
||||
|
||||
# This won't function correctly without internal (callback never called).
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def reset_achievements() -> None:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.reset_achievements()
|
||||
return
|
||||
|
||||
# Technically doesnt break but won't do anything.
|
||||
_no_bainternal_warning()
|
||||
|
||||
|
||||
def get_public_login_id() -> str | None:
|
||||
"""(internal)"""
|
||||
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_public_login_id()
|
||||
|
||||
# Harmless to return nothing in this case.
|
||||
return None
|
||||
|
||||
|
||||
def have_outstanding_transactions() -> bool:
|
||||
"""(internal)"""
|
||||
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.have_outstanding_transactions()
|
||||
|
||||
# Harmless to return False here.
|
||||
return False
|
||||
|
||||
|
||||
def run_transactions() -> None:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.run_transactions()
|
||||
|
||||
# Harmless no-op in this case.
|
||||
|
||||
|
||||
def get_v1_account_misc_read_val(name: str, default_value: Any) -> Any:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_v1_account_misc_read_val(
|
||||
name=name, default_value=default_value)
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def get_v1_account_misc_read_val_2(name: str, default_value: Any) -> Any:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_v1_account_misc_read_val_2(
|
||||
name=name, default_value=default_value)
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def get_v1_account_misc_val(name: str, default_value: Any) -> Any:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_v1_account_misc_val(name=name,
|
||||
default_value=default_value)
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def get_v1_account_ticket_count() -> int:
|
||||
"""(internal)
|
||||
|
||||
Returns the number of tickets for the current account.
|
||||
"""
|
||||
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_v1_account_ticket_count()
|
||||
return 0
|
||||
|
||||
|
||||
def get_v1_account_state_num() -> int:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_v1_account_state_num()
|
||||
return 0
|
||||
|
||||
|
||||
def get_v1_account_state() -> str:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_v1_account_state()
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def get_v1_account_display_string(full: bool = True) -> str:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_v1_account_display_string(full=full)
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def get_v1_account_type() -> str:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_v1_account_type()
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def get_v1_account_name() -> str:
|
||||
"""(internal)"""
|
||||
if HAVE_INTERNAL:
|
||||
return _bainternal.get_v1_account_name()
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def sign_out_v1(v2_embedded: bool = False) -> None:
|
||||
"""(internal)
|
||||
|
||||
Category: General Utility Functions
|
||||
"""
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.sign_out_v1(v2_embedded=v2_embedded)
|
||||
return
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def sign_in_v1(account_type: str) -> None:
|
||||
"""(internal)
|
||||
|
||||
Category: General Utility Functions
|
||||
"""
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.sign_in_v1(account_type=account_type)
|
||||
return
|
||||
raise _no_bainternal_error()
|
||||
|
||||
|
||||
def mark_config_dirty() -> None:
|
||||
"""(internal)
|
||||
|
||||
Category: General Utility Functions
|
||||
"""
|
||||
if HAVE_INTERNAL:
|
||||
_bainternal.mark_config_dirty()
|
||||
return
|
||||
|
||||
# Note to self - need to fix config writing to not rely on
|
||||
# internal lib.
|
||||
_no_bainternal_warning()
|
||||
16
dist/ba_data/python/ba/_map.py
vendored
16
dist/ba_data/python/ba/_map.py
vendored
|
|
@ -101,22 +101,6 @@ def getmaps(playtype: str) -> list[str]:
|
|||
if playtype in val.get_play_types())
|
||||
|
||||
|
||||
def get_unowned_maps() -> list[str]:
|
||||
"""Return the list of local maps not owned by the current account.
|
||||
|
||||
Category: **Asset Functions**
|
||||
"""
|
||||
from ba import _store
|
||||
unowned_maps: set[str] = set()
|
||||
if not _ba.app.headless_mode:
|
||||
for map_section in _store.get_store_layout()['maps']:
|
||||
for mapitem in map_section['items']:
|
||||
if not _ba.get_purchased(mapitem):
|
||||
m_info = _store.get_store_item(mapitem)
|
||||
unowned_maps.add(m_info['map_type'].name)
|
||||
return sorted(unowned_maps)
|
||||
|
||||
|
||||
def get_map_class(name: str) -> type[ba.Map]:
|
||||
"""Return a map type given a name.
|
||||
|
||||
|
|
|
|||
418
dist/ba_data/python/ba/_meta.py
vendored
418
dist/ba_data/python/ba/_meta.py
vendored
|
|
@ -6,33 +6,50 @@ from __future__ import annotations
|
|||
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
import logging
|
||||
from threading import Thread
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from efro.call import tpartial
|
||||
import _ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import ba
|
||||
from typing import Callable
|
||||
|
||||
# The meta api version of this build of the game.
|
||||
# Only packages and modules requiring this exact api version
|
||||
# will be considered when scanning directories.
|
||||
|
||||
# See: https://ballistica.net/wiki/Meta-Tags
|
||||
CURRENT_API_VERSION = 6 #TODO update it to latest
|
||||
# current API version is 7 , im downgrading it to 6 to support mini games which i cant update to 7 bcoz of encryption
|
||||
# shouldn't be a issue , I manually updated all plugin on_app_launch to on_app_running and that was the only change btw API 6 and 7
|
||||
|
||||
|
||||
# Meta export lines can use these names to represent these classes.
|
||||
# This is purely a convenience; it is possible to use full class paths
|
||||
# instead of these or to make the meta system aware of arbitrary classes.
|
||||
EXPORT_CLASS_NAME_SHORTCUTS: dict[str, str] = {
|
||||
'plugin': 'ba.Plugin',
|
||||
'keyboard': 'ba.Keyboard',
|
||||
'game': 'ba.GameActivity',
|
||||
}
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScanResults:
|
||||
"""Final results from a metadata scan."""
|
||||
games: list[str] = field(default_factory=list)
|
||||
plugins: list[str] = field(default_factory=list)
|
||||
keyboards: list[str] = field(default_factory=list)
|
||||
errors: str = ''
|
||||
warnings: str = ''
|
||||
"""Final results from a meta-scan."""
|
||||
exports: dict[str, list[str]] = field(default_factory=dict)
|
||||
errors: list[str] = field(default_factory=list)
|
||||
warnings: list[str] = field(default_factory=list)
|
||||
|
||||
def exports_of_class(self, cls: type) -> list[str]:
|
||||
"""Return exports of a given class."""
|
||||
return self.exports.get(f'{cls.__module__}.{cls.__qualname__}', [])
|
||||
|
||||
|
||||
class MetadataSubsystem:
|
||||
|
|
@ -44,99 +61,98 @@ class MetadataSubsystem:
|
|||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.scanresults: ScanResults | None = None
|
||||
|
||||
self._scan: DirectoryScan | None = None
|
||||
|
||||
# Can be populated before starting the scan.
|
||||
self.extra_scan_dirs: list[str] = []
|
||||
|
||||
def on_app_running(self) -> None:
|
||||
"""Should be called when the app enters the running state."""
|
||||
# Results populated once scan is complete.
|
||||
self.scanresults: ScanResults | None = None
|
||||
|
||||
# Start scanning for things exposed via ba_meta.
|
||||
self.start_scan()
|
||||
self._scan_complete_cb: Callable[[], None] | None = None
|
||||
|
||||
def start_scan(self) -> None:
|
||||
"""Begin scanning script directories for scripts containing metadata.
|
||||
def start_scan(self, scan_complete_cb: Callable[[], None]) -> None:
|
||||
"""Begin the overall scan.
|
||||
|
||||
Should be called only once at launch."""
|
||||
app = _ba.app
|
||||
if self.scanresults is not None:
|
||||
print('WARNING: meta scan run more than once.')
|
||||
pythondirs = ([app.python_directory_app, app.python_directory_user] +
|
||||
self.extra_scan_dirs)
|
||||
thread = ScanThread(pythondirs)
|
||||
thread.start()
|
||||
This will start scanning built in directories (which for vanilla
|
||||
installs should be the vast majority of the work). This should only
|
||||
be called once.
|
||||
"""
|
||||
assert self._scan_complete_cb is None
|
||||
assert self._scan is None
|
||||
|
||||
def handle_scan_results(self, results: ScanResults) -> None:
|
||||
"""Called in the game thread with results of a completed scan."""
|
||||
self._scan_complete_cb = scan_complete_cb
|
||||
self._scan = DirectoryScan(
|
||||
[_ba.app.python_directory_app, _ba.app.python_directory_user])
|
||||
|
||||
from ba._language import Lstr
|
||||
from ba._plugin import PotentialPlugin
|
||||
Thread(target=self._run_scan_in_bg, daemon=True).start()
|
||||
|
||||
# Warnings generally only get printed locally for users' benefit
|
||||
# (things like out-of-date scripts being ignored, etc.)
|
||||
# Errors are more serious and will get included in the regular log
|
||||
# warnings = results.get('warnings', '')
|
||||
# errors = results.get('errors', '')
|
||||
if results.warnings != '' or results.errors != '':
|
||||
import textwrap
|
||||
_ba.screenmessage(Lstr(resource='scanScriptsErrorText'),
|
||||
color=(1, 0, 0))
|
||||
_ba.playsound(_ba.getsound('error'))
|
||||
if results.warnings != '':
|
||||
_ba.log(textwrap.indent(results.warnings,
|
||||
'Warning (meta-scan): '),
|
||||
to_server=False)
|
||||
if results.errors != '':
|
||||
_ba.log(textwrap.indent(results.errors, 'Error (meta-scan): '))
|
||||
def start_extra_scan(self) -> None:
|
||||
"""Proceed to the extra_scan_dirs portion of the scan.
|
||||
|
||||
# Handle plugins.
|
||||
plugs = _ba.app.plugins
|
||||
config_changed = False
|
||||
found_new = False
|
||||
plugstates: dict[str, dict] = _ba.app.config.setdefault('Plugins', {})
|
||||
assert isinstance(plugstates, dict)
|
||||
This is for parts of the scan that must be delayed until
|
||||
workspace sync completion or other such events. This must be
|
||||
called exactly once.
|
||||
"""
|
||||
assert self._scan is not None
|
||||
self._scan.set_extras(self.extra_scan_dirs)
|
||||
|
||||
# Create a potential-plugin for each class we found in the scan.
|
||||
for class_path in results.plugins:
|
||||
plugs.potential_plugins.append(
|
||||
PotentialPlugin(display_name=Lstr(value=class_path),
|
||||
class_path=class_path,
|
||||
available=True))
|
||||
if class_path not in plugstates:
|
||||
# Go ahead and enable new plugins by default, but we'll
|
||||
# inform the user that they need to restart to pick them up.
|
||||
# they can also disable them in settings so they never load.
|
||||
plugstates[class_path] = {'enabled': True}
|
||||
config_changed = True
|
||||
found_new = True
|
||||
def load_exported_classes(
|
||||
self,
|
||||
cls: type[T],
|
||||
completion_cb: Callable[[list[type[T]]], None],
|
||||
completion_cb_in_bg_thread: bool = False,
|
||||
) -> None:
|
||||
"""High level function to load meta-exported classes.
|
||||
|
||||
# Also add a special one for any plugins set to load but *not* found
|
||||
# in the scan (this way they will show up in the UI so we can disable
|
||||
# them)
|
||||
for class_path, plugstate in plugstates.items():
|
||||
enabled = plugstate.get('enabled', False)
|
||||
assert isinstance(enabled, bool)
|
||||
if enabled and class_path not in results.plugins:
|
||||
plugs.potential_plugins.append(
|
||||
PotentialPlugin(display_name=Lstr(value=class_path),
|
||||
class_path=class_path,
|
||||
available=False))
|
||||
Will wait for scanning to complete if necessary, and will load all
|
||||
registered classes of a particular type in a background thread before
|
||||
calling the passed callback in the logic thread. Errors may be logged
|
||||
to messaged to the user in some way but the callback will be called
|
||||
regardless.
|
||||
To run the completion callback directly in the bg thread where the
|
||||
loading work happens, pass completion_cb_in_bg_thread=True.
|
||||
"""
|
||||
Thread(
|
||||
target=tpartial(self._load_exported_classes, cls, completion_cb,
|
||||
completion_cb_in_bg_thread),
|
||||
daemon=True,
|
||||
).start()
|
||||
|
||||
plugs.potential_plugins.sort(key=lambda p: p.class_path)
|
||||
def _load_exported_classes(
|
||||
self,
|
||||
cls: type[T],
|
||||
completion_cb: Callable[[list[type[T]]], None],
|
||||
completion_cb_in_bg_thread: bool,
|
||||
) -> None:
|
||||
from ba._general import getclass
|
||||
classes: list[type[T]] = []
|
||||
try:
|
||||
classnames = self._wait_for_scan_results().exports_of_class(cls)
|
||||
for classname in classnames:
|
||||
try:
|
||||
classes.append(getclass(classname, cls))
|
||||
except Exception:
|
||||
logging.exception('error importing %s', classname)
|
||||
|
||||
if found_new:
|
||||
_ba.screenmessage(Lstr(resource='pluginsDetectedText'),
|
||||
color=(0, 1, 0))
|
||||
_ba.playsound(_ba.getsound('ding'))
|
||||
except Exception:
|
||||
logging.exception('Error loading exported classes.')
|
||||
|
||||
if config_changed:
|
||||
_ba.app.config.commit()
|
||||
completion_call = tpartial(completion_cb, classes)
|
||||
if completion_cb_in_bg_thread:
|
||||
completion_call()
|
||||
else:
|
||||
_ba.pushcall(completion_call, from_other_thread=True)
|
||||
|
||||
def get_scan_results(self) -> ScanResults:
|
||||
"""Return meta scan results; block if the scan is not yet complete."""
|
||||
def _wait_for_scan_results(self) -> ScanResults:
|
||||
"""Return scan results, blocking if the scan is not yet complete."""
|
||||
if self.scanresults is None:
|
||||
print('WARNING: ba.meta.get_scan_results()'
|
||||
' called before scan completed.'
|
||||
' This can cause hitches.')
|
||||
if _ba.in_logic_thread():
|
||||
logging.warning(
|
||||
'ba.meta._wait_for_scan_results()'
|
||||
' called in logic thread before scan completed;'
|
||||
' this can cause hitches.')
|
||||
|
||||
# Now wait a bit for the scan to complete.
|
||||
# Eventually error though if it doesn't.
|
||||
|
|
@ -148,69 +164,53 @@ class MetadataSubsystem:
|
|||
'timeout waiting for meta scan to complete.')
|
||||
return self.scanresults
|
||||
|
||||
def get_game_types(self) -> list[type[ba.GameActivity]]:
|
||||
"""Return available game types."""
|
||||
from ba._general import getclass
|
||||
from ba._gameactivity import GameActivity
|
||||
gameclassnames = self.get_scan_results().games
|
||||
gameclasses = []
|
||||
for gameclassname in gameclassnames:
|
||||
try:
|
||||
cls = getclass(gameclassname, GameActivity)
|
||||
gameclasses.append(cls)
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception('error importing ' + str(gameclassname))
|
||||
unowned = self.get_unowned_game_types()
|
||||
return [cls for cls in gameclasses if cls not in unowned]
|
||||
|
||||
def get_unowned_game_types(self) -> set[type[ba.GameActivity]]:
|
||||
"""Return present game types not owned by the current account."""
|
||||
def _run_scan_in_bg(self) -> None:
|
||||
"""Runs a scan (for use in background thread)."""
|
||||
try:
|
||||
from ba import _store
|
||||
unowned_games: set[type[ba.GameActivity]] = set()
|
||||
if not _ba.app.headless_mode:
|
||||
for section in _store.get_store_layout()['minigames']:
|
||||
for mname in section['items']:
|
||||
if not _ba.get_purchased(mname):
|
||||
m_info = _store.get_store_item(mname)
|
||||
unowned_games.add(m_info['gametype'])
|
||||
return unowned_games
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception('error calcing un-owned games')
|
||||
return set()
|
||||
|
||||
|
||||
class ScanThread(threading.Thread):
|
||||
"""Thread to scan script dirs for metadata."""
|
||||
|
||||
def __init__(self, dirs: list[str]):
|
||||
super().__init__()
|
||||
self._dirs = dirs
|
||||
|
||||
def run(self) -> None:
|
||||
from ba._general import Call
|
||||
try:
|
||||
scan = DirectoryScan(self._dirs)
|
||||
scan.scan()
|
||||
results = scan.results
|
||||
assert self._scan is not None
|
||||
self._scan.run()
|
||||
results = self._scan.results
|
||||
self._scan = None
|
||||
except Exception as exc:
|
||||
results = ScanResults(errors=f'Scan exception: {exc}')
|
||||
results = ScanResults(errors=[f'Scan exception: {exc}'])
|
||||
|
||||
# Push a call to the game thread to print warnings/errors
|
||||
# or otherwise deal with scan results.
|
||||
_ba.pushcall(Call(_ba.app.meta.handle_scan_results, results),
|
||||
from_other_thread=True)
|
||||
# Place results and tell the logic thread they're ready.
|
||||
self.scanresults = results
|
||||
_ba.pushcall(self._handle_scan_results, from_other_thread=True)
|
||||
|
||||
# We also, however, immediately make results available.
|
||||
# This is because the game thread may be blocked waiting
|
||||
# for them so we can't push a call or we'd get deadlock.
|
||||
_ba.app.meta.scanresults = results
|
||||
def _handle_scan_results(self) -> None:
|
||||
"""Called in the logic thread with results of a completed scan."""
|
||||
from ba._language import Lstr
|
||||
assert _ba.in_logic_thread()
|
||||
|
||||
results = self.scanresults
|
||||
assert results is not None
|
||||
|
||||
# Spit out any warnings/errors that happened.
|
||||
# Warnings generally only get printed locally for users' benefit
|
||||
# (things like out-of-date scripts being ignored, etc.)
|
||||
# Errors are more serious and will get included in the regular log.
|
||||
if results.warnings or results.errors:
|
||||
import textwrap
|
||||
_ba.screenmessage(Lstr(resource='scanScriptsErrorText'),
|
||||
color=(1, 0, 0))
|
||||
_ba.playsound(_ba.getsound('error'))
|
||||
if results.warnings:
|
||||
allwarnings = textwrap.indent('\n'.join(results.warnings),
|
||||
'Warning (meta-scan): ')
|
||||
logging.warning(allwarnings)
|
||||
if results.errors:
|
||||
allerrors = textwrap.indent('\n'.join(results.errors),
|
||||
'Error (meta-scan): ')
|
||||
logging.error(allerrors)
|
||||
|
||||
# Let the game know we're done.
|
||||
assert self._scan_complete_cb is not None
|
||||
self._scan_complete_cb()
|
||||
|
||||
|
||||
class DirectoryScan:
|
||||
"""Handles scanning directories for metadata."""
|
||||
"""Scans directories for metadata."""
|
||||
|
||||
def __init__(self, paths: list[str]):
|
||||
"""Given one or more paths, parses available meta information.
|
||||
|
|
@ -220,9 +220,42 @@ class DirectoryScan:
|
|||
"""
|
||||
|
||||
# Skip non-existent paths completely.
|
||||
self.paths = [Path(p) for p in paths if os.path.isdir(p)]
|
||||
self.base_paths = [Path(p) for p in paths if os.path.isdir(p)]
|
||||
self.extra_paths: list[Path] = []
|
||||
self.extra_paths_set = False
|
||||
self.results = ScanResults()
|
||||
|
||||
def set_extras(self, paths: list[str]) -> None:
|
||||
"""Set extra portion."""
|
||||
# Skip non-existent paths completely.
|
||||
self.extra_paths += [Path(p) for p in paths if os.path.isdir(p)]
|
||||
self.extra_paths_set = True
|
||||
|
||||
def run(self) -> None:
|
||||
"""Do the thing."""
|
||||
for pathlist in [self.base_paths, self.extra_paths]:
|
||||
|
||||
# Spin and wait until extra paths are provided before doing them.
|
||||
if pathlist is self.extra_paths:
|
||||
while not self.extra_paths_set:
|
||||
time.sleep(0.001)
|
||||
|
||||
modules: list[tuple[Path, Path]] = []
|
||||
for path in pathlist:
|
||||
self._get_path_module_entries(path, '', modules)
|
||||
for moduledir, subpath in modules:
|
||||
try:
|
||||
self._scan_module(moduledir, subpath)
|
||||
except Exception:
|
||||
import traceback
|
||||
self.results.warnings.append(
|
||||
f"Error scanning '{subpath}': " +
|
||||
traceback.format_exc())
|
||||
|
||||
# Sort our results
|
||||
for exportlist in self.results.exports.values():
|
||||
exportlist.sort()
|
||||
|
||||
def _get_path_module_entries(self, path: Path, subpath: str | Path,
|
||||
modules: list[tuple[Path, Path]]) -> None:
|
||||
"""Scan provided path and add module entries to provided list."""
|
||||
|
|
@ -237,7 +270,7 @@ class DirectoryScan:
|
|||
entries = []
|
||||
except Exception as exc:
|
||||
# Unexpected; report this.
|
||||
self.results.errors += f'{exc}\n'
|
||||
self.results.errors.append(str(exc))
|
||||
entries = []
|
||||
|
||||
# Now identify python packages/modules out of what we found.
|
||||
|
|
@ -248,24 +281,7 @@ class DirectoryScan:
|
|||
and Path(entry[0], entry[1], '__init__.py').is_file()):
|
||||
modules.append(entry)
|
||||
|
||||
def scan(self) -> None:
|
||||
"""Scan provided paths."""
|
||||
modules: list[tuple[Path, Path]] = []
|
||||
for path in self.paths:
|
||||
self._get_path_module_entries(path, '', modules)
|
||||
for moduledir, subpath in modules:
|
||||
try:
|
||||
self.scan_module(moduledir, subpath)
|
||||
except Exception:
|
||||
import traceback
|
||||
self.results.warnings += ("Error scanning '" + str(subpath) +
|
||||
"': " + traceback.format_exc() +
|
||||
'\n')
|
||||
# Sort our results
|
||||
self.results.games.sort()
|
||||
self.results.plugins.sort()
|
||||
|
||||
def scan_module(self, moduledir: Path, subpath: Path) -> None:
|
||||
def _scan_module(self, moduledir: Path, subpath: Path) -> None:
|
||||
"""Scan an individual module and add the findings to results."""
|
||||
if subpath.name.endswith('.py'):
|
||||
fpath = Path(moduledir, subpath)
|
||||
|
|
@ -279,19 +295,20 @@ class DirectoryScan:
|
|||
lnum: l[1:].split()
|
||||
for lnum, l in enumerate(flines) if '# ba_meta ' in l
|
||||
}
|
||||
toplevel = len(subpath.parts) <= 1
|
||||
required_api = self.get_api_requirement(subpath, meta_lines, toplevel)
|
||||
is_top_level = len(subpath.parts) <= 1
|
||||
required_api = self._get_api_requirement(subpath, meta_lines,
|
||||
is_top_level)
|
||||
|
||||
# Top level modules with no discernible api version get ignored.
|
||||
if toplevel and required_api is None:
|
||||
if is_top_level and required_api is None:
|
||||
return
|
||||
|
||||
# If we find a module requiring a different api version, warn
|
||||
# and ignore.
|
||||
if required_api is not None and required_api < CURRENT_API_VERSION:
|
||||
if required_api is not None and required_api <= CURRENT_API_VERSION:
|
||||
self.results.warnings += (
|
||||
f'Warning: {subpath} requires api {required_api} but'
|
||||
f' we are running {CURRENT_API_VERSION}; ignoring module.\n')
|
||||
f' we are running {CURRENT_API_VERSION}; ignoring module.')
|
||||
return
|
||||
|
||||
# Ok; can proceed with a full scan of this module.
|
||||
|
|
@ -304,11 +321,11 @@ class DirectoryScan:
|
|||
self._get_path_module_entries(moduledir, subpath, submodules)
|
||||
for submodule in submodules:
|
||||
if submodule[1].name != '__init__.py':
|
||||
self.scan_module(submodule[0], submodule[1])
|
||||
self._scan_module(submodule[0], submodule[1])
|
||||
except Exception:
|
||||
import traceback
|
||||
self.results.warnings += (
|
||||
f"Error scanning '{subpath}': {traceback.format_exc()}\n")
|
||||
self.results.warnings.append(
|
||||
f"Error scanning '{subpath}': {traceback.format_exc()}")
|
||||
|
||||
def _process_module_meta_tags(self, subpath: Path, flines: list[str],
|
||||
meta_lines: dict[int, list[str]]) -> None:
|
||||
|
|
@ -317,10 +334,9 @@ class DirectoryScan:
|
|||
# meta_lines is just anything containing '# ba_meta '; make sure
|
||||
# the ba_meta is in the right place.
|
||||
if mline[0] != 'ba_meta':
|
||||
self.results.warnings += (
|
||||
'Warning: ' + str(subpath) +
|
||||
': malformed ba_meta statement on line ' +
|
||||
str(lindex + 1) + '.\n')
|
||||
self.results.warnings.append(
|
||||
f'Warning: {subpath}:'
|
||||
f' malformed ba_meta statement on line {lindex + 1}.')
|
||||
elif (len(mline) == 4 and mline[1] == 'require'
|
||||
and mline[2] == 'api'):
|
||||
# Ignore 'require api X' lines in this pass.
|
||||
|
|
@ -328,31 +344,28 @@ class DirectoryScan:
|
|||
elif len(mline) != 3 or mline[1] != 'export':
|
||||
# Currently we only support 'ba_meta export FOO';
|
||||
# complain for anything else we see.
|
||||
self.results.warnings += (
|
||||
'Warning: ' + str(subpath) +
|
||||
': unrecognized ba_meta statement on line ' +
|
||||
str(lindex + 1) + '.\n')
|
||||
self.results.warnings.append(
|
||||
f'Warning: {subpath}'
|
||||
f': unrecognized ba_meta statement on line {lindex + 1}.')
|
||||
else:
|
||||
# Looks like we've got a valid export line!
|
||||
modulename = '.'.join(subpath.parts)
|
||||
if subpath.name.endswith('.py'):
|
||||
modulename = modulename[:-3]
|
||||
exporttype = mline[2]
|
||||
exporttypestr = mline[2]
|
||||
export_class_name = self._get_export_class_name(
|
||||
subpath, flines, lindex)
|
||||
if export_class_name is not None:
|
||||
classname = modulename + '.' + export_class_name
|
||||
if exporttype == 'game':
|
||||
self.results.games.append(classname)
|
||||
elif exporttype == 'plugin':
|
||||
self.results.plugins.append(classname)
|
||||
elif exporttype == 'keyboard':
|
||||
self.results.keyboards.append(classname)
|
||||
else:
|
||||
self.results.warnings += (
|
||||
'Warning: ' + str(subpath) +
|
||||
': unrecognized export type "' + exporttype +
|
||||
'" on line ' + str(lindex + 1) + '.\n')
|
||||
|
||||
# If export type is one of our shortcuts, sub in the
|
||||
# actual class path. Otherwise assume its a classpath
|
||||
# itself.
|
||||
exporttype = EXPORT_CLASS_NAME_SHORTCUTS.get(exporttypestr)
|
||||
if exporttype is None:
|
||||
exporttype = exporttypestr
|
||||
self.results.exports.setdefault(exporttype,
|
||||
[]).append(classname)
|
||||
|
||||
def _get_export_class_name(self, subpath: Path, lines: list[str],
|
||||
lindex: int) -> str | None:
|
||||
|
|
@ -374,13 +387,12 @@ class DirectoryScan:
|
|||
classname = cbits[0]
|
||||
break # Success!
|
||||
if classname is None:
|
||||
self.results.warnings += (
|
||||
'Warning: ' + str(subpath) + ': class definition not found'
|
||||
' below "ba_meta export" statement on line ' +
|
||||
str(lindexorig + 1) + '.\n')
|
||||
self.results.warnings.append(
|
||||
f'Warning: {subpath}: class definition not found below'
|
||||
f' "ba_meta export" statement on line {lindexorig + 1}.')
|
||||
return classname
|
||||
|
||||
def get_api_requirement(
|
||||
def _get_api_requirement(
|
||||
self,
|
||||
subpath: Path,
|
||||
meta_lines: dict[int, list[str]],
|
||||
|
|
@ -401,15 +413,15 @@ class DirectoryScan:
|
|||
|
||||
# Ok; not successful. lets issue warnings for a few error cases.
|
||||
if len(lines) > 1:
|
||||
self.results.warnings += (
|
||||
'Warning: ' + str(subpath) +
|
||||
': multiple "# ba_meta require api <NUM>" lines found;'
|
||||
' ignoring module.\n')
|
||||
self.results.warnings.append(
|
||||
f'Warning: {subpath}: multiple'
|
||||
' "# ba_meta require api <NUM>" lines found;'
|
||||
' ignoring module.')
|
||||
elif not lines and toplevel and meta_lines:
|
||||
# If we're a top-level module containing meta lines but
|
||||
# no valid "require api" line found, complain.
|
||||
self.results.warnings += (
|
||||
'Warning: ' + str(subpath) +
|
||||
': no valid "# ba_meta require api <NUM>" line found;'
|
||||
' ignoring module.\n')
|
||||
self.results.warnings.append(
|
||||
f'Warning: {subpath}:'
|
||||
' no valid "# ba_meta require api <NUM>" line found;'
|
||||
' ignoring module.')
|
||||
return None
|
||||
|
|
|
|||
8
dist/ba_data/python/ba/_multiteamsession.py
vendored
8
dist/ba_data/python/ba/_multiteamsession.py
vendored
|
|
@ -94,9 +94,11 @@ class MultiTeamSession(Session):
|
|||
playlist = _playlist.get_default_free_for_all_playlist()
|
||||
|
||||
# Resolve types and whatnot to get our final playlist.
|
||||
playlist_resolved = _playlist.filter_playlist(playlist,
|
||||
sessiontype=type(self),
|
||||
add_resolved_type=True)
|
||||
playlist_resolved = _playlist.filter_playlist(
|
||||
playlist,
|
||||
sessiontype=type(self),
|
||||
add_resolved_type=True,
|
||||
name='default teams' if self.use_teams else 'default ffa')
|
||||
|
||||
if not playlist_resolved:
|
||||
raise RuntimeError('Playlist contains no valid games.')
|
||||
|
|
|
|||
11
dist/ba_data/python/ba/_net.py
vendored
11
dist/ba_data/python/ba/_net.py
vendored
|
|
@ -134,15 +134,16 @@ class MasterServerCallThread(threading.Thread):
|
|||
import json
|
||||
|
||||
from efro.error import is_urllib_communication_error
|
||||
from ba import _general
|
||||
from ba._general import Call, utf8_all
|
||||
from ba._internal import get_master_server_address
|
||||
|
||||
response_data: Any = None
|
||||
url: str | None = None
|
||||
try:
|
||||
self._data = _general.utf8_all(self._data)
|
||||
self._data = utf8_all(self._data)
|
||||
_ba.set_thread_name('BA_ServerCallThread')
|
||||
if self._request_type == 'get':
|
||||
url = (_ba.get_master_server_address() + '/' + self._request +
|
||||
url = (get_master_server_address() + '/' + self._request +
|
||||
'?' + urllib.parse.urlencode(self._data))
|
||||
response = urllib.request.urlopen(
|
||||
urllib.request.Request(
|
||||
|
|
@ -150,7 +151,7 @@ class MasterServerCallThread(threading.Thread):
|
|||
context=_ba.app.net.sslcontext,
|
||||
timeout=DEFAULT_REQUEST_TIMEOUT_SECONDS)
|
||||
elif self._request_type == 'post':
|
||||
url = _ba.get_master_server_address() + '/' + self._request
|
||||
url = get_master_server_address() + '/' + self._request
|
||||
response = urllib.request.urlopen(
|
||||
urllib.request.Request(
|
||||
url,
|
||||
|
|
@ -189,7 +190,7 @@ class MasterServerCallThread(threading.Thread):
|
|||
response_data = None
|
||||
|
||||
if self._callback is not None:
|
||||
_ba.pushcall(_general.Call(self._run_callback, response_data),
|
||||
_ba.pushcall(Call(self._run_callback, response_data),
|
||||
from_other_thread=True)
|
||||
|
||||
|
||||
|
|
|
|||
24
dist/ba_data/python/ba/_playlist.py
vendored
24
dist/ba_data/python/ba/_playlist.py
vendored
|
|
@ -5,6 +5,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import logging
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -18,7 +19,8 @@ def filter_playlist(playlist: PlaylistType,
|
|||
sessiontype: type[_session.Session],
|
||||
add_resolved_type: bool = False,
|
||||
remove_unowned: bool = True,
|
||||
mark_unowned: bool = False) -> PlaylistType:
|
||||
mark_unowned: bool = False,
|
||||
name: str = '?') -> PlaylistType:
|
||||
"""Return a filtered version of a playlist.
|
||||
|
||||
Strips out or replaces invalid or unowned game types, makes sure all
|
||||
|
|
@ -28,15 +30,15 @@ def filter_playlist(playlist: PlaylistType,
|
|||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
import _ba
|
||||
from ba import _map
|
||||
from ba import _general
|
||||
from ba import _gameactivity
|
||||
from ba._map import get_filtered_map_name
|
||||
from ba._store import get_unowned_maps, get_unowned_game_types
|
||||
from ba._general import getclass
|
||||
from ba._gameactivity import GameActivity
|
||||
goodlist: list[dict] = []
|
||||
unowned_maps: Sequence[str]
|
||||
if remove_unowned or mark_unowned:
|
||||
unowned_maps = _map.get_unowned_maps()
|
||||
unowned_game_types = _ba.app.meta.get_unowned_game_types()
|
||||
unowned_maps = get_unowned_maps()
|
||||
unowned_game_types = get_unowned_game_types()
|
||||
else:
|
||||
unowned_maps = []
|
||||
unowned_game_types = set()
|
||||
|
|
@ -53,7 +55,7 @@ def filter_playlist(playlist: PlaylistType,
|
|||
del entry['map']
|
||||
|
||||
# Update old map names to new ones.
|
||||
entry['settings']['map'] = _map.get_filtered_map_name(
|
||||
entry['settings']['map'] = get_filtered_map_name(
|
||||
entry['settings']['map'])
|
||||
if remove_unowned and entry['settings']['map'] in unowned_maps:
|
||||
continue
|
||||
|
|
@ -120,8 +122,7 @@ def filter_playlist(playlist: PlaylistType,
|
|||
entry['type'] = (
|
||||
'bastd.game.targetpractice.TargetPracticeGame')
|
||||
|
||||
gameclass = _general.getclass(entry['type'],
|
||||
_gameactivity.GameActivity)
|
||||
gameclass = getclass(entry['type'], GameActivity)
|
||||
|
||||
if remove_unowned and gameclass in unowned_game_types:
|
||||
continue
|
||||
|
|
@ -139,7 +140,8 @@ def filter_playlist(playlist: PlaylistType,
|
|||
entry['settings'][setting.name] = setting.default
|
||||
goodlist.append(entry)
|
||||
except ImportError as exc:
|
||||
print(f'Import failed while scanning playlist: {exc}')
|
||||
logging.warning('Import failed while scanning playlist \'%s\': %s',
|
||||
name, exc)
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception()
|
||||
|
|
|
|||
55
dist/ba_data/python/ba/_plugin.py
vendored
55
dist/ba_data/python/ba/_plugin.py
vendored
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
|
@ -25,6 +26,46 @@ class PluginSubsystem:
|
|||
self.potential_plugins: list[ba.PotentialPlugin] = []
|
||||
self.active_plugins: dict[str, ba.Plugin] = {}
|
||||
|
||||
def on_meta_scan_complete(self) -> None:
|
||||
"""Should be called when meta-scanning is complete."""
|
||||
from ba._language import Lstr
|
||||
|
||||
plugs = _ba.app.plugins
|
||||
config_changed = False
|
||||
found_new = False
|
||||
plugstates: dict[str, dict] = _ba.app.config.setdefault('Plugins', {})
|
||||
assert isinstance(plugstates, dict)
|
||||
|
||||
results = _ba.app.meta.scanresults
|
||||
assert results is not None
|
||||
|
||||
# Create a potential-plugin for each class we found in the scan.
|
||||
for class_path in results.exports_of_class(Plugin):
|
||||
plugs.potential_plugins.append(
|
||||
PotentialPlugin(display_name=Lstr(value=class_path),
|
||||
class_path=class_path,
|
||||
available=True))
|
||||
if class_path not in plugstates:
|
||||
# Go ahead and enable new plugins by default, but we'll
|
||||
# inform the user that they need to restart to pick them up.
|
||||
# they can also disable them in settings so they never load.
|
||||
plugstates[class_path] = {'enabled': True}
|
||||
config_changed = True
|
||||
found_new = True
|
||||
|
||||
plugs.potential_plugins.sort(key=lambda p: p.class_path)
|
||||
|
||||
# Note: these days we complete meta-scan and immediately activate
|
||||
# plugins, so we don't need the message about 'restart to activate'
|
||||
# anymore.
|
||||
if found_new and bool(False):
|
||||
_ba.screenmessage(Lstr(resource='pluginsDetectedText'),
|
||||
color=(0, 1, 0))
|
||||
_ba.playsound(_ba.getsound('ding'))
|
||||
|
||||
if config_changed:
|
||||
_ba.app.config.commit()
|
||||
|
||||
def on_app_running(self) -> None:
|
||||
"""Should be called when the app reaches the running state."""
|
||||
# Load up our plugins and go ahead and call their on_app_running calls.
|
||||
|
|
@ -69,10 +110,7 @@ class PluginSubsystem:
|
|||
from ba._language import Lstr
|
||||
|
||||
# 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)
|
||||
# in the app config. Its not our job to look at meta stuff here.
|
||||
plugstates: dict[str, dict] = _ba.app.config.get('Plugins', {})
|
||||
assert isinstance(plugstates, dict)
|
||||
plugkeys: list[str] = sorted(key for key, val in plugstates.items()
|
||||
|
|
@ -90,8 +128,7 @@ class PluginSubsystem:
|
|||
subs=[('${PLUGIN}', plugkey),
|
||||
('${ERROR}', str(exc))]),
|
||||
color=(1, 0, 0))
|
||||
_ba.log(f"Error loading plugin class '{plugkey}': {exc}",
|
||||
to_server=False)
|
||||
logging.exception("Error loading plugin class '%s'", plugkey)
|
||||
continue
|
||||
try:
|
||||
plugin = cls()
|
||||
|
|
@ -118,10 +155,8 @@ class PluginSubsystem:
|
|||
color=(1, 1, 0),
|
||||
)
|
||||
plugnames = ', '.join(disappeared_plugs)
|
||||
_ba.log(
|
||||
f'{len(disappeared_plugs)} plugin(s) no longer found:'
|
||||
f' {plugnames}.',
|
||||
to_server=False)
|
||||
logging.warning('%d plugin(s) no longer found: %s.',
|
||||
len(disappeared_plugs), plugnames)
|
||||
for goneplug in disappeared_plugs:
|
||||
del _ba.app.config['Plugins'][goneplug]
|
||||
_ba.app.config.commit()
|
||||
|
|
|
|||
21
dist/ba_data/python/ba/_servermode.py
vendored
21
dist/ba_data/python/ba/_servermode.py
vendored
|
|
@ -5,6 +5,7 @@ from __future__ import annotations
|
|||
|
||||
import sys
|
||||
import time
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from efro.terminal import Clr
|
||||
|
|
@ -13,6 +14,8 @@ from bacommon.servermanager import (ServerCommand, StartServerModeCommand,
|
|||
ChatMessageCommand, ScreenMessageCommand,
|
||||
ClientListCommand, KickCommand)
|
||||
import _ba
|
||||
from ba._internal import (add_transaction, run_transactions,
|
||||
get_v1_account_state)
|
||||
from ba._generated.enums import TimeType
|
||||
from ba._freeforallsession import FreeForAllSession
|
||||
from ba._dualteamsession import DualTeamSession
|
||||
|
|
@ -227,7 +230,7 @@ class ServerController:
|
|||
|
||||
def _prepare_to_serve(self) -> None:
|
||||
"""Run in a timer to do prep before beginning to serve."""
|
||||
signed_in = _ba.get_v1_account_state() == 'signed_in'
|
||||
signed_in = get_v1_account_state() == 'signed_in'
|
||||
if not signed_in:
|
||||
|
||||
# Signing in to the local server account should not take long;
|
||||
|
|
@ -247,14 +250,14 @@ class ServerController:
|
|||
if not self._playlist_fetch_sent_request:
|
||||
print(f'{Clr.SBLU}Requesting shared-playlist'
|
||||
f' {self._config.playlist_code}...{Clr.RST}')
|
||||
_ba.add_transaction(
|
||||
add_transaction(
|
||||
{
|
||||
'type': 'IMPORT_PLAYLIST',
|
||||
'code': str(self._config.playlist_code),
|
||||
'overwrite': True
|
||||
},
|
||||
callback=self._on_playlist_fetch_response)
|
||||
_ba.run_transactions()
|
||||
run_transactions()
|
||||
self._playlist_fetch_sent_request = True
|
||||
|
||||
if self._playlist_fetch_got_response:
|
||||
|
|
@ -302,7 +305,7 @@ class ServerController:
|
|||
appcfg = app.config
|
||||
sessiontype = self._get_session_type()
|
||||
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if get_v1_account_state() != 'signed_in':
|
||||
print('WARNING: launch_server_session() expects to run '
|
||||
'with a signed in server account')
|
||||
|
||||
|
|
@ -322,21 +325,21 @@ class ServerController:
|
|||
|
||||
# Need to add this in a transaction instead of just setting
|
||||
# it directly or it will get overwritten by the master-server.
|
||||
_ba.add_transaction({
|
||||
add_transaction({
|
||||
'type': 'ADD_PLAYLIST',
|
||||
'playlistType': ptypename,
|
||||
'playlistName': self._playlist_name,
|
||||
'playlist': self._config.playlist_inline
|
||||
})
|
||||
_ba.run_transactions()
|
||||
run_transactions()
|
||||
|
||||
if self._first_run:
|
||||
curtimestr = time.strftime('%c')
|
||||
_ba.log(
|
||||
startupmsg = (
|
||||
f'{Clr.BLD}{Clr.BLU}{_ba.appnameupper()} {app.version}'
|
||||
f' ({app.build_number})'
|
||||
f' entering server-mode {curtimestr}{Clr.RST}',
|
||||
to_server=False)
|
||||
f' entering server-mode {curtimestr}{Clr.RST}')
|
||||
logging.info(startupmsg)
|
||||
|
||||
if sessiontype is FreeForAllSession:
|
||||
appcfg['Free-for-All Playlist Selection'] = self._playlist_name
|
||||
|
|
|
|||
1
dist/ba_data/python/ba/_session.py
vendored
1
dist/ba_data/python/ba/_session.py
vendored
|
|
@ -615,6 +615,7 @@ class Session:
|
|||
def transitioning_out_activity_was_freed(
|
||||
self, can_show_ad_on_death: bool) -> None:
|
||||
"""(internal)"""
|
||||
# pylint: disable=cyclic-import
|
||||
from ba._apputils import garbage_collect
|
||||
|
||||
# Since things should be generally still right now, it's a good time
|
||||
|
|
|
|||
51
dist/ba_data/python/ba/_store.py
vendored
51
dist/ba_data/python/ba/_store.py
vendored
|
|
@ -7,6 +7,7 @@ from __future__ import annotations
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
from ba import _internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -366,11 +367,11 @@ def get_store_layout() -> dict[str, list[dict[str, Any]]]:
|
|||
'games.ninja_fight', 'games.meteor_shower', 'games.target_practice'
|
||||
]
|
||||
}]
|
||||
if _ba.get_v1_account_misc_read_val('xmas', False):
|
||||
if _internal.get_v1_account_misc_read_val('xmas', False):
|
||||
store_layout['characters'][0]['items'].append('characters.santa')
|
||||
store_layout['characters'][0]['items'].append('characters.wizard')
|
||||
store_layout['characters'][0]['items'].append('characters.cyborg')
|
||||
if _ba.get_v1_account_misc_read_val('easter', False):
|
||||
if _internal.get_v1_account_misc_read_val('easter', False):
|
||||
store_layout['characters'].append({
|
||||
'title': 'store.holidaySpecialText',
|
||||
'items': ['characters.bunny']
|
||||
|
|
@ -401,10 +402,10 @@ def get_clean_price(price_string: str) -> str:
|
|||
def get_available_purchase_count(tab: str | None = None) -> int:
|
||||
"""(internal)"""
|
||||
try:
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if _internal.get_v1_account_state() != 'signed_in':
|
||||
return 0
|
||||
count = 0
|
||||
our_tickets = _ba.get_v1_account_ticket_count()
|
||||
our_tickets = _internal.get_v1_account_ticket_count()
|
||||
store_data = get_store_layout()
|
||||
if tab is not None:
|
||||
tabs = [(tab, store_data[tab])]
|
||||
|
|
@ -425,11 +426,11 @@ def _calc_count_for_tab(tabval: list[dict[str, Any]], our_tickets: int,
|
|||
count: int) -> int:
|
||||
for section in tabval:
|
||||
for item in section['items']:
|
||||
ticket_cost = _ba.get_v1_account_misc_read_val(
|
||||
ticket_cost = _internal.get_v1_account_misc_read_val(
|
||||
'price.' + item, None)
|
||||
if ticket_cost is not None:
|
||||
if (our_tickets >= ticket_cost
|
||||
and not _ba.get_purchased(item)):
|
||||
and not _internal.get_purchased(item)):
|
||||
count += 1
|
||||
return count
|
||||
|
||||
|
|
@ -463,7 +464,7 @@ def get_available_sale_time(tab: str) -> int | None:
|
|||
|
||||
# We start the timer once we get the duration from
|
||||
# the server.
|
||||
start_duration = _ba.get_v1_account_misc_read_val(
|
||||
start_duration = _internal.get_v1_account_misc_read_val(
|
||||
'proSaleDurationMinutes', None)
|
||||
if start_duration is not None:
|
||||
app.pro_sale_start_time = int(
|
||||
|
|
@ -489,12 +490,12 @@ def get_available_sale_time(tab: str) -> int | None:
|
|||
sale_times.append(val)
|
||||
|
||||
# Now look for sales in this tab.
|
||||
sales_raw = _ba.get_v1_account_misc_read_val('sales', {})
|
||||
sales_raw = _internal.get_v1_account_misc_read_val('sales', {})
|
||||
store_layout = get_store_layout()
|
||||
for section in store_layout[tab]:
|
||||
for item in section['items']:
|
||||
if item in sales_raw:
|
||||
if not _ba.get_purchased(item):
|
||||
if not _internal.get_purchased(item):
|
||||
to_end = ((datetime.datetime.utcfromtimestamp(
|
||||
sales_raw[item]['e']) -
|
||||
datetime.datetime.utcnow()).total_seconds())
|
||||
|
|
@ -509,3 +510,35 @@ def get_available_sale_time(tab: str) -> int | None:
|
|||
from ba import _error
|
||||
_error.print_exception('error calcing sale time')
|
||||
return None
|
||||
|
||||
|
||||
def get_unowned_maps() -> list[str]:
|
||||
"""Return the list of local maps not owned by the current account.
|
||||
|
||||
Category: **Asset Functions**
|
||||
"""
|
||||
unowned_maps: set[str] = set()
|
||||
if not _ba.app.headless_mode:
|
||||
for map_section in get_store_layout()['maps']:
|
||||
for mapitem in map_section['items']:
|
||||
if not _internal.get_purchased(mapitem):
|
||||
m_info = get_store_item(mapitem)
|
||||
unowned_maps.add(m_info['map_type'].name)
|
||||
return sorted(unowned_maps)
|
||||
|
||||
|
||||
def get_unowned_game_types() -> set[type[ba.GameActivity]]:
|
||||
"""Return present game types not owned by the current account."""
|
||||
try:
|
||||
unowned_games: set[type[ba.GameActivity]] = set()
|
||||
if not _ba.app.headless_mode:
|
||||
for section in get_store_layout()['minigames']:
|
||||
for mname in section['items']:
|
||||
if not _internal.get_purchased(mname):
|
||||
m_info = get_store_item(mname)
|
||||
unowned_games.add(m_info['gametype'])
|
||||
return unowned_games
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_exception('error calcing un-owned games')
|
||||
return set()
|
||||
|
|
|
|||
216
dist/ba_data/python/ba/internal.py
vendored
216
dist/ba_data/python/ba/internal.py
vendored
|
|
@ -6,10 +6,35 @@ Classes and functions contained here, while technically 'public', may change
|
|||
or disappear without warning, so should be avoided (or used sparingly and
|
||||
defensively) in mods.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from ba._map import (get_unowned_maps, get_map_class, register_map,
|
||||
preload_map_preview_media, get_map_display_string,
|
||||
get_filtered_map_name)
|
||||
from _ba import (
|
||||
show_online_score_ui, set_ui_input_device, is_party_icon_visible,
|
||||
getinputdevice, add_clean_frame_callback, unlock_all_input,
|
||||
increment_analytics_count, set_debug_speed_exponent, get_special_widget,
|
||||
get_qrcode_texture, get_string_height, get_string_width, show_app_invite,
|
||||
appnameupper, lock_all_input, open_file_externally, fade_screen, appname,
|
||||
have_incentivized_ad, has_video_ads, workspaces_in_use,
|
||||
set_party_icon_always_visible, connect_to_party, get_game_port,
|
||||
end_host_scanning, host_scan_cycle, charstr, get_public_party_enabled,
|
||||
get_public_party_max_size, set_public_party_name,
|
||||
set_public_party_max_size, set_authenticate_clients,
|
||||
set_public_party_enabled, reset_random_player_names, new_host_session,
|
||||
get_foreground_host_session, get_local_active_input_devices_count,
|
||||
get_ui_input_device, is_in_replay, set_replay_speed_exponent,
|
||||
get_replay_speed_exponent, disconnect_from_host, set_party_window_open,
|
||||
get_connection_to_host_info, get_chat_messages, get_game_roster,
|
||||
disconnect_client, chatmessage, get_random_names, have_permission,
|
||||
request_permission, have_touchscreen_input, is_xcode_build,
|
||||
set_low_level_config_value, get_low_level_config_value,
|
||||
capture_gamepad_input, release_gamepad_input, has_gamma_control,
|
||||
get_max_graphics_quality, get_display_resolution, capture_keyboard_input,
|
||||
release_keyboard_input, value_test, set_touchscreen_editing,
|
||||
is_running_on_fire_tv, android_get_external_files_dir,
|
||||
set_telnet_access_enabled, new_replay_session, get_replays_dir)
|
||||
|
||||
from ba._map import (get_map_class, register_map, preload_map_preview_media,
|
||||
get_map_display_string, get_filtered_map_name)
|
||||
from ba._appconfig import commit_app_config
|
||||
from ba._input import (get_device_value, get_input_map_hash,
|
||||
get_input_device_config)
|
||||
|
|
@ -34,27 +59,174 @@ from ba._playlist import (get_default_free_for_all_playlist,
|
|||
from ba._store import (get_available_sale_time, get_available_purchase_count,
|
||||
get_store_item_name_translated,
|
||||
get_store_item_display_size, get_store_layout,
|
||||
get_store_item, get_clean_price)
|
||||
get_store_item, get_clean_price, get_unowned_maps,
|
||||
get_unowned_game_types)
|
||||
from ba._tournament import get_tournament_prize_strings
|
||||
from ba._gameutils import get_trophy_string
|
||||
|
||||
from ba._internal import (
|
||||
get_v2_fleet, get_master_server_address, is_blessed, get_news_show,
|
||||
game_service_has_leaderboard, report_achievement, submit_score,
|
||||
tournament_query, power_ranking_query, restore_purchases, purchase,
|
||||
get_purchases_state, get_purchased, get_price, in_game_purchase,
|
||||
add_transaction, reset_achievements, get_public_login_id,
|
||||
have_outstanding_transactions, run_transactions,
|
||||
get_v1_account_misc_read_val, get_v1_account_misc_read_val_2,
|
||||
get_v1_account_misc_val, get_v1_account_ticket_count,
|
||||
get_v1_account_state_num, get_v1_account_state,
|
||||
get_v1_account_display_string, get_v1_account_type, get_v1_account_name,
|
||||
sign_out_v1, sign_in_v1, mark_config_dirty)
|
||||
|
||||
__all__ = [
|
||||
'get_unowned_maps', 'get_map_class', 'register_map',
|
||||
'preload_map_preview_media', 'get_map_display_string',
|
||||
'get_filtered_map_name', 'commit_app_config', 'get_device_value',
|
||||
'get_input_map_hash', 'get_input_device_config', 'getclass', 'json_prep',
|
||||
'get_type_name', 'JoinActivity', 'ScoreScreenActivity',
|
||||
'is_browser_likely_available', 'get_remote_app_name',
|
||||
'should_submit_debug_info', 'run_gpu_benchmark', 'run_cpu_benchmark',
|
||||
'run_media_reload_benchmark', 'run_stress_test', 'getcampaign',
|
||||
'PlayerProfilesChangedMessage', 'DEFAULT_TEAM_COLORS',
|
||||
'DEFAULT_TEAM_NAMES', 'do_play_music', 'master_server_get',
|
||||
'master_server_post', 'get_ip_address_type',
|
||||
'DEFAULT_REQUEST_TIMEOUT_SECONDS', 'get_default_powerup_distribution',
|
||||
'get_player_profile_colors', 'get_player_profile_icon',
|
||||
'get_player_colors', 'get_next_tip', 'get_default_free_for_all_playlist',
|
||||
'get_default_teams_playlist', 'filter_playlist', 'get_available_sale_time',
|
||||
'get_available_purchase_count', 'get_store_item_name_translated',
|
||||
'get_store_item_display_size', 'get_store_layout', 'get_store_item',
|
||||
'get_clean_price', 'get_tournament_prize_strings', 'get_trophy_string'
|
||||
'show_online_score_ui',
|
||||
'set_ui_input_device',
|
||||
'is_party_icon_visible',
|
||||
'getinputdevice',
|
||||
'add_clean_frame_callback',
|
||||
'unlock_all_input',
|
||||
'increment_analytics_count',
|
||||
'set_debug_speed_exponent',
|
||||
'get_special_widget',
|
||||
'get_qrcode_texture',
|
||||
'get_string_height',
|
||||
'get_string_width',
|
||||
'show_app_invite',
|
||||
'appnameupper',
|
||||
'lock_all_input',
|
||||
'open_file_externally',
|
||||
'fade_screen',
|
||||
'appname',
|
||||
'have_incentivized_ad',
|
||||
'has_video_ads',
|
||||
'workspaces_in_use',
|
||||
'set_party_icon_always_visible',
|
||||
'connect_to_party',
|
||||
'get_game_port',
|
||||
'end_host_scanning',
|
||||
'host_scan_cycle',
|
||||
'charstr',
|
||||
'get_public_party_enabled',
|
||||
'get_public_party_max_size',
|
||||
'set_public_party_name',
|
||||
'set_public_party_max_size',
|
||||
'set_authenticate_clients',
|
||||
'set_public_party_enabled',
|
||||
'reset_random_player_names',
|
||||
'new_host_session',
|
||||
'get_foreground_host_session',
|
||||
'get_local_active_input_devices_count',
|
||||
'get_ui_input_device',
|
||||
'is_in_replay',
|
||||
'set_replay_speed_exponent',
|
||||
'get_replay_speed_exponent',
|
||||
'disconnect_from_host',
|
||||
'set_party_window_open',
|
||||
'get_connection_to_host_info',
|
||||
'get_chat_messages',
|
||||
'get_game_roster',
|
||||
'disconnect_client',
|
||||
'chatmessage',
|
||||
'get_random_names',
|
||||
'have_permission',
|
||||
'request_permission',
|
||||
'have_touchscreen_input',
|
||||
'is_xcode_build',
|
||||
'set_low_level_config_value',
|
||||
'get_low_level_config_value',
|
||||
'capture_gamepad_input',
|
||||
'release_gamepad_input',
|
||||
'has_gamma_control',
|
||||
'get_max_graphics_quality',
|
||||
'get_display_resolution',
|
||||
'capture_keyboard_input',
|
||||
'release_keyboard_input',
|
||||
'value_test',
|
||||
'set_touchscreen_editing',
|
||||
'is_running_on_fire_tv',
|
||||
'android_get_external_files_dir',
|
||||
'set_telnet_access_enabled',
|
||||
'new_replay_session',
|
||||
'get_replays_dir',
|
||||
# DIVIDER
|
||||
'get_unowned_maps',
|
||||
'get_unowned_game_types',
|
||||
'get_map_class',
|
||||
'register_map',
|
||||
'preload_map_preview_media',
|
||||
'get_map_display_string',
|
||||
'get_filtered_map_name',
|
||||
'commit_app_config',
|
||||
'get_device_value',
|
||||
'get_input_map_hash',
|
||||
'get_input_device_config',
|
||||
'getclass',
|
||||
'json_prep',
|
||||
'get_type_name',
|
||||
'JoinActivity',
|
||||
'ScoreScreenActivity',
|
||||
'is_browser_likely_available',
|
||||
'get_remote_app_name',
|
||||
'should_submit_debug_info',
|
||||
'run_gpu_benchmark',
|
||||
'run_cpu_benchmark',
|
||||
'run_media_reload_benchmark',
|
||||
'run_stress_test',
|
||||
'getcampaign',
|
||||
'PlayerProfilesChangedMessage',
|
||||
'DEFAULT_TEAM_COLORS',
|
||||
'DEFAULT_TEAM_NAMES',
|
||||
'do_play_music',
|
||||
'master_server_get',
|
||||
'master_server_post',
|
||||
'get_ip_address_type',
|
||||
'DEFAULT_REQUEST_TIMEOUT_SECONDS',
|
||||
'get_default_powerup_distribution',
|
||||
'get_player_profile_colors',
|
||||
'get_player_profile_icon',
|
||||
'get_player_colors',
|
||||
'get_next_tip',
|
||||
'get_default_free_for_all_playlist',
|
||||
'get_default_teams_playlist',
|
||||
'filter_playlist',
|
||||
'get_available_sale_time',
|
||||
'get_available_purchase_count',
|
||||
'get_store_item_name_translated',
|
||||
'get_store_item_display_size',
|
||||
'get_store_layout',
|
||||
'get_store_item',
|
||||
'get_clean_price',
|
||||
'get_tournament_prize_strings',
|
||||
'get_trophy_string',
|
||||
'get_v2_fleet',
|
||||
'get_master_server_address',
|
||||
'is_blessed',
|
||||
'get_news_show',
|
||||
'game_service_has_leaderboard',
|
||||
'report_achievement',
|
||||
'submit_score',
|
||||
'tournament_query',
|
||||
'power_ranking_query',
|
||||
'restore_purchases',
|
||||
'purchase',
|
||||
'get_purchases_state',
|
||||
'get_purchased',
|
||||
'get_price',
|
||||
'in_game_purchase',
|
||||
'add_transaction',
|
||||
'reset_achievements',
|
||||
'get_public_login_id',
|
||||
'have_outstanding_transactions',
|
||||
'run_transactions',
|
||||
'get_v1_account_misc_read_val',
|
||||
'get_v1_account_misc_read_val_2',
|
||||
'get_v1_account_misc_val',
|
||||
'get_v1_account_ticket_count',
|
||||
'get_v1_account_state_num',
|
||||
'get_v1_account_state',
|
||||
'get_v1_account_display_string',
|
||||
'get_v1_account_type',
|
||||
'get_v1_account_name',
|
||||
'sign_out_v1',
|
||||
'sign_in_v1',
|
||||
'mark_config_dirty',
|
||||
]
|
||||
|
|
|
|||
2
dist/ba_data/python/bacommon/bacloud.py
vendored
2
dist/ba_data/python/bacommon/bacloud.py
vendored
|
|
@ -14,7 +14,7 @@ if TYPE_CHECKING:
|
|||
|
||||
# Version is sent to the master-server with all commands. Can be incremented
|
||||
# if we need to change behavior server-side to go along with client changes.
|
||||
BACLOUD_VERSION = 7
|
||||
BACLOUD_VERSION = 8
|
||||
|
||||
|
||||
@ioprepped
|
||||
|
|
|
|||
10
dist/ba_data/python/bacommon/cloud.py
vendored
10
dist/ba_data/python/bacommon/cloud.py
vendored
|
|
@ -21,7 +21,7 @@ class LoginProxyRequestMessage(Message):
|
|||
"""Request send to the cloud to ask for a login-proxy."""
|
||||
|
||||
@classmethod
|
||||
def get_response_types(cls) -> list[type[Response]]:
|
||||
def get_response_types(cls) -> list[type[Response] | None]:
|
||||
return [LoginProxyRequestResponse]
|
||||
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ class LoginProxyStateQueryMessage(Message):
|
|||
proxykey: Annotated[str, IOAttrs('k')]
|
||||
|
||||
@classmethod
|
||||
def get_response_types(cls) -> list[type[Response]]:
|
||||
def get_response_types(cls) -> list[type[Response] | None]:
|
||||
return [LoginProxyStateQueryResponse]
|
||||
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ class PingMessage(Message):
|
|||
"""Standard ping."""
|
||||
|
||||
@classmethod
|
||||
def get_response_types(cls) -> list[type[Response]]:
|
||||
def get_response_types(cls) -> list[type[Response] | None]:
|
||||
return [PingResponse]
|
||||
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ class TestMessage(Message):
|
|||
testfoo: Annotated[int, IOAttrs('f')]
|
||||
|
||||
@classmethod
|
||||
def get_response_types(cls) -> list[type[Response]]:
|
||||
def get_response_types(cls) -> list[type[Response] | None]:
|
||||
return [TestResponse]
|
||||
|
||||
|
||||
|
|
@ -130,7 +130,7 @@ class WorkspaceFetchMessage(Message):
|
|||
state: Annotated[WorkspaceFetchState, IOAttrs('s')]
|
||||
|
||||
@classmethod
|
||||
def get_response_types(cls) -> list[type[Response]]:
|
||||
def get_response_types(cls) -> list[type[Response] | None]:
|
||||
return [WorkspaceFetchResponse]
|
||||
|
||||
|
||||
|
|
|
|||
183
dist/ba_data/python/bastd/activity/coopjoin.py
vendored
183
dist/ba_data/python/bastd/activity/coopjoin.py
vendored
|
|
@ -6,12 +6,11 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
from ba.internal import JoinActivity
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
pass
|
||||
|
||||
|
||||
class CoopJoinActivity(JoinActivity):
|
||||
|
|
@ -25,16 +24,6 @@ class CoopJoinActivity(JoinActivity):
|
|||
session = self.session
|
||||
assert isinstance(session, ba.CoopSession)
|
||||
|
||||
# Let's show a list of scores-to-beat for 1 player at least.
|
||||
assert session.campaign is not None
|
||||
level_name_full = (session.campaign.name + ':' +
|
||||
session.campaign_level_name)
|
||||
config_str = ('1p' + session.campaign.getlevel(
|
||||
session.campaign_level_name).get_score_version_string().replace(
|
||||
' ', '_'))
|
||||
_ba.get_scores_to_beat(level_name_full, config_str,
|
||||
ba.WeakCall(self._on_got_scores_to_beat))
|
||||
|
||||
def on_transition_in(self) -> None:
|
||||
from bastd.actor.controlsguide import ControlsGuide
|
||||
from bastd.actor.text import Text
|
||||
|
|
@ -53,143 +42,61 @@ class CoopJoinActivity(JoinActivity):
|
|||
position=(0, -95)).autoretain()
|
||||
ControlsGuide(delay=1.0).autoretain()
|
||||
|
||||
def _on_got_scores_to_beat(self,
|
||||
scores: list[dict[str, Any]] | None) -> None:
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
from efro.util import asserttype
|
||||
from bastd.actor.text import Text
|
||||
ba.pushcall(self._show_remaining_achievements)
|
||||
|
||||
# Sort by originating date so that the most recent is first.
|
||||
if scores is not None:
|
||||
scores.sort(reverse=True,
|
||||
key=lambda score: asserttype(score['time'], int))
|
||||
def _show_remaining_achievements(self) -> None:
|
||||
from bastd.actor.text import Text
|
||||
|
||||
# We only show achievements and challenges for CoopGameActivities.
|
||||
session = self.session
|
||||
assert isinstance(session, ba.CoopSession)
|
||||
gameinstance = session.get_current_game_instance()
|
||||
if isinstance(gameinstance, ba.CoopGameActivity):
|
||||
score_type = gameinstance.get_score_type()
|
||||
if scores is not None:
|
||||
achievement_challenges = [
|
||||
a for a in scores if a['type'] == 'achievement_challenge'
|
||||
]
|
||||
score_challenges = [
|
||||
a for a in scores if a['type'] == 'score_challenge'
|
||||
]
|
||||
else:
|
||||
achievement_challenges = score_challenges = []
|
||||
if not isinstance(gameinstance, ba.CoopGameActivity):
|
||||
return
|
||||
|
||||
delay = 1.0
|
||||
vpos = -140.0
|
||||
spacing = 25
|
||||
delay_inc = 0.1
|
||||
delay = 1.0
|
||||
vpos = -140.0
|
||||
|
||||
def _add_t(
|
||||
text: str | ba.Lstr,
|
||||
h_offs: float = 0.0,
|
||||
scale: float = 1.0,
|
||||
color: Sequence[float] = (1.0, 1.0, 1.0, 0.46)
|
||||
) -> None:
|
||||
Text(text,
|
||||
scale=scale * 0.76,
|
||||
h_align=Text.HAlign.LEFT,
|
||||
# Now list our remaining achievements for this level.
|
||||
assert self.session.campaign is not None
|
||||
assert isinstance(self.session, ba.CoopSession)
|
||||
levelname = (self.session.campaign.name + ':' +
|
||||
self.session.campaign_level_name)
|
||||
ts_h_offs = 60
|
||||
|
||||
if not (ba.app.demo_mode or ba.app.arcade_mode):
|
||||
achievements = [
|
||||
a for a in ba.app.ach.achievements_for_coop_level(levelname)
|
||||
if not a.complete
|
||||
]
|
||||
have_achievements = bool(achievements)
|
||||
achievements = [a for a in achievements if not a.complete]
|
||||
vrmode = ba.app.vr_mode
|
||||
if have_achievements:
|
||||
Text(ba.Lstr(resource='achievementsRemainingText'),
|
||||
host_only=True,
|
||||
position=(ts_h_offs - 10, vpos),
|
||||
transition=Text.Transition.FADE_IN,
|
||||
scale=1.1 * 0.76,
|
||||
h_attach=Text.HAttach.LEFT,
|
||||
v_attach=Text.VAttach.TOP,
|
||||
transition=Text.Transition.FADE_IN,
|
||||
transition_delay=delay,
|
||||
color=color,
|
||||
position=(60 + h_offs, vpos)).autoretain()
|
||||
|
||||
if score_challenges:
|
||||
_add_t(ba.Lstr(value='${A}:',
|
||||
subs=[('${A}',
|
||||
ba.Lstr(resource='scoreChallengesText'))
|
||||
]),
|
||||
scale=1.1)
|
||||
delay += delay_inc
|
||||
vpos -= spacing
|
||||
for chal in score_challenges:
|
||||
_add_t(str(chal['value'] if score_type == 'points' else ba.
|
||||
timestring(int(chal['value']) * 10,
|
||||
timeformat=ba.TimeFormat.MILLISECONDS
|
||||
).evaluate()) + ' (1 player)',
|
||||
h_offs=30,
|
||||
color=(0.9, 0.7, 1.0, 0.8))
|
||||
delay += delay_inc
|
||||
vpos -= 0.6 * spacing
|
||||
_add_t(chal['player'],
|
||||
h_offs=40,
|
||||
color=(0.8, 1, 0.8, 0.6),
|
||||
scale=0.8)
|
||||
delay += delay_inc
|
||||
vpos -= 1.2 * spacing
|
||||
vpos -= 0.5 * spacing
|
||||
|
||||
if achievement_challenges:
|
||||
_add_t(ba.Lstr(
|
||||
value='${A}:',
|
||||
subs=[('${A}',
|
||||
ba.Lstr(resource='achievementChallengesText'))]),
|
||||
scale=1.1)
|
||||
delay += delay_inc
|
||||
vpos -= spacing
|
||||
for chal in achievement_challenges:
|
||||
_add_t(str(chal['value']),
|
||||
h_offs=30,
|
||||
color=(0.9, 0.7, 1.0, 0.8))
|
||||
delay += delay_inc
|
||||
vpos -= 0.6 * spacing
|
||||
_add_t(chal['player'],
|
||||
h_offs=40,
|
||||
color=(0.8, 1, 0.8, 0.6),
|
||||
scale=0.8)
|
||||
delay += delay_inc
|
||||
vpos -= 1.2 * spacing
|
||||
vpos -= 0.5 * spacing
|
||||
|
||||
# Now list our remaining achievements for this level.
|
||||
assert self.session.campaign is not None
|
||||
assert isinstance(self.session, ba.CoopSession)
|
||||
levelname = (self.session.campaign.name + ':' +
|
||||
self.session.campaign_level_name)
|
||||
ts_h_offs = 60
|
||||
|
||||
if not (ba.app.demo_mode or ba.app.arcade_mode):
|
||||
achievements = [
|
||||
a
|
||||
for a in ba.app.ach.achievements_for_coop_level(levelname)
|
||||
if not a.complete
|
||||
]
|
||||
have_achievements = bool(achievements)
|
||||
achievements = [a for a in achievements if not a.complete]
|
||||
vrmode = ba.app.vr_mode
|
||||
if have_achievements:
|
||||
Text(ba.Lstr(resource='achievementsRemainingText'),
|
||||
color=(1, 1, 1.2, 1) if vrmode else (0.8, 0.8, 1, 1),
|
||||
shadow=1.0,
|
||||
flatness=1.0 if vrmode else 0.6,
|
||||
transition_delay=delay).autoretain()
|
||||
hval = ts_h_offs + 50
|
||||
vpos -= 35
|
||||
for ach in achievements:
|
||||
delay += 0.05
|
||||
ach.create_display(hval, vpos, delay, style='in_game')
|
||||
vpos -= 55
|
||||
if not achievements:
|
||||
Text(ba.Lstr(resource='noAchievementsRemainingText'),
|
||||
host_only=True,
|
||||
position=(ts_h_offs - 10, vpos),
|
||||
position=(ts_h_offs + 15, vpos + 10),
|
||||
transition=Text.Transition.FADE_IN,
|
||||
scale=1.1 * 0.76,
|
||||
scale=0.7,
|
||||
h_attach=Text.HAttach.LEFT,
|
||||
v_attach=Text.VAttach.TOP,
|
||||
color=(1, 1, 1.2, 1) if vrmode else (0.8, 0.8, 1, 1),
|
||||
shadow=1.0,
|
||||
flatness=1.0 if vrmode else 0.6,
|
||||
transition_delay=delay).autoretain()
|
||||
hval = ts_h_offs + 50
|
||||
vpos -= 35
|
||||
for ach in achievements:
|
||||
delay += 0.05
|
||||
ach.create_display(hval, vpos, delay, style='in_game')
|
||||
vpos -= 55
|
||||
if not achievements:
|
||||
Text(ba.Lstr(resource='noAchievementsRemainingText'),
|
||||
host_only=True,
|
||||
position=(ts_h_offs + 15, vpos + 10),
|
||||
transition=Text.Transition.FADE_IN,
|
||||
scale=0.7,
|
||||
h_attach=Text.HAttach.LEFT,
|
||||
v_attach=Text.VAttach.TOP,
|
||||
color=(1, 1, 1, 0.5),
|
||||
transition_delay=delay + 0.5).autoretain()
|
||||
color=(1, 1, 1, 0.5),
|
||||
transition_delay=delay + 0.5).autoretain()
|
||||
|
|
|
|||
72
dist/ba_data/python/bastd/activity/coopscore.py
vendored
72
dist/ba_data/python/bastd/activity/coopscore.py
vendored
|
|
@ -8,8 +8,8 @@ from __future__ import annotations
|
|||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.actor.text import Text
|
||||
from bastd.actor.zoomtext import ZoomText
|
||||
|
||||
|
|
@ -52,9 +52,9 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||
ba.app.ach.achievements_for_coop_level(self._campaign.name + ':' +
|
||||
settings['level']))
|
||||
|
||||
self._account_type = (_ba.get_v1_account_type()
|
||||
if _ba.get_v1_account_state() == 'signed_in' else
|
||||
None)
|
||||
self._account_type = (ba.internal.get_v1_account_type()
|
||||
if ba.internal.get_v1_account_state()
|
||||
== 'signed_in' else None)
|
||||
|
||||
self._game_service_icon_color: Sequence[float] | None
|
||||
self._game_service_achievements_texture: ba.Texture | None
|
||||
|
|
@ -167,7 +167,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||
|
||||
# If game-center/etc scores are available we show our friends'
|
||||
# scores. Otherwise we show our local high scores.
|
||||
self._show_friend_scores = _ba.game_service_has_leaderboard(
|
||||
self._show_friend_scores = ba.internal.game_service_has_leaderboard(
|
||||
self._game_name_str, self._game_config_str)
|
||||
|
||||
try:
|
||||
|
|
@ -264,12 +264,12 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||
self.end({'outcome': 'next_level'})
|
||||
|
||||
def _ui_gc(self) -> None:
|
||||
_ba.show_online_score_ui('leaderboard',
|
||||
game=self._game_name_str,
|
||||
game_version=self._game_config_str)
|
||||
ba.internal.show_online_score_ui('leaderboard',
|
||||
game=self._game_name_str,
|
||||
game_version=self._game_config_str)
|
||||
|
||||
def _ui_show_achievements(self) -> None:
|
||||
_ba.show_online_score_ui('achievements')
|
||||
ba.internal.show_online_score_ui('achievements')
|
||||
|
||||
def _ui_worlds_best(self) -> None:
|
||||
if self._score_link is None:
|
||||
|
|
@ -331,7 +331,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||
# to the game (like on mac).
|
||||
can_select_extra_buttons = ba.app.platform == 'android'
|
||||
|
||||
_ba.set_ui_input_device(None) # Menu is up for grabs.
|
||||
ba.internal.set_ui_input_device(None) # Menu is up for grabs.
|
||||
|
||||
if self._show_friend_scores:
|
||||
ba.buttonwidget(parent=rootc,
|
||||
|
|
@ -483,7 +483,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||
timetype=ba.TimeType.REAL)
|
||||
|
||||
def _update_corner_button_positions(self) -> None:
|
||||
offs = -55 if _ba.is_party_icon_visible() else 0
|
||||
offs = -55 if ba.internal.is_party_icon_visible() else 0
|
||||
assert self._corner_button_offs is not None
|
||||
pos_x = self._corner_button_offs[0] + offs
|
||||
pos_y = self._corner_button_offs[1]
|
||||
|
|
@ -497,9 +497,9 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||
|
||||
# If this activity is a good 'end point', ask server-mode just once if
|
||||
# it wants to do anything special like switch sessions or kill the app.
|
||||
if (self._allow_server_transition and _ba.app.server is not None
|
||||
if (self._allow_server_transition and ba.app.server is not None
|
||||
and self._server_transitioning is None):
|
||||
self._server_transitioning = _ba.app.server.handle_transition()
|
||||
self._server_transitioning = ba.app.server.handle_transition()
|
||||
assert isinstance(self._server_transitioning, bool)
|
||||
|
||||
# If server-mode is handling this, don't do anything ourself.
|
||||
|
|
@ -528,7 +528,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||
if ba.app.server is not None:
|
||||
# Host can't press retry button, so anyone can do it instead.
|
||||
time_till_assign = max(
|
||||
0, self._birth_time + self._min_view_time - _ba.time())
|
||||
0, self._birth_time + self._min_view_time - ba.time())
|
||||
|
||||
ba.timer(time_till_assign, ba.WeakCall(self._safe_assign, player))
|
||||
|
||||
|
|
@ -552,7 +552,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||
|
||||
# Any time we complete a level, set the next one as unlocked.
|
||||
if self._is_complete and self._is_more_levels:
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'COMPLETE_LEVEL',
|
||||
'campaign': self._campaign.name,
|
||||
'level': self._level_name
|
||||
|
|
@ -632,7 +632,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||
if ba.app.server is None:
|
||||
# If we're running in normal non-headless build, show this text
|
||||
# because only host can continue the game.
|
||||
adisp = _ba.get_v1_account_display_string()
|
||||
adisp = ba.internal.get_v1_account_display_string()
|
||||
txt = Text(ba.Lstr(resource='waitingForHostText',
|
||||
subs=[('${HOST}', adisp)]),
|
||||
maxwidth=300,
|
||||
|
|
@ -726,14 +726,14 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||
if self._score is not None:
|
||||
sver = (self._campaign.getlevel(
|
||||
self._level_name).get_score_version_string())
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'SET_LEVEL_LOCAL_HIGH_SCORES',
|
||||
'campaign': self._campaign.name,
|
||||
'level': self._level_name,
|
||||
'scoreVersion': sver,
|
||||
'scores': our_high_scores_all
|
||||
})
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
# We expect this only in kiosk mode; complain otherwise.
|
||||
if not (ba.app.demo_mode or ba.app.arcade_mode):
|
||||
print('got not-signed-in at score-submit; unexpected')
|
||||
|
|
@ -743,21 +743,22 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||
else:
|
||||
assert self._game_name_str is not None
|
||||
assert self._game_config_str is not None
|
||||
_ba.submit_score(self._game_name_str,
|
||||
self._game_config_str,
|
||||
name_str,
|
||||
self._score,
|
||||
ba.WeakCall(self._got_score_results),
|
||||
ba.WeakCall(self._got_friend_score_results)
|
||||
if self._show_friend_scores else None,
|
||||
order=self._score_order,
|
||||
tournament_id=self.session.tournament_id,
|
||||
score_type=self._score_type,
|
||||
campaign=self._campaign.name,
|
||||
level=self._level_name)
|
||||
ba.internal.submit_score(
|
||||
self._game_name_str,
|
||||
self._game_config_str,
|
||||
name_str,
|
||||
self._score,
|
||||
ba.WeakCall(self._got_score_results),
|
||||
ba.WeakCall(self._got_friend_score_results)
|
||||
if self._show_friend_scores else None,
|
||||
order=self._score_order,
|
||||
tournament_id=self.session.tournament_id,
|
||||
score_type=self._score_type,
|
||||
campaign=self._campaign.name,
|
||||
level=self._level_name)
|
||||
|
||||
# Apply the transactions we've been adding locally.
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
||||
# If we're not doing the world's-best button, just show a title
|
||||
# instead.
|
||||
|
|
@ -1074,9 +1075,12 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
|
|||
else:
|
||||
self._score_link = results['link']
|
||||
assert self._score_link is not None
|
||||
if not self._score_link.startswith('http://'):
|
||||
self._score_link = (_ba.get_master_server_address() + '/' +
|
||||
self._score_link)
|
||||
# Prepend our master-server addr if its a relative addr.
|
||||
if (not self._score_link.startswith('http://')
|
||||
and not self._score_link.startswith('https://')):
|
||||
self._score_link = (
|
||||
ba.internal.get_master_server_address() + '/' +
|
||||
self._score_link)
|
||||
self._score_loading_status = None
|
||||
if 'tournamentSecondsRemaining' in results:
|
||||
secs_remaining = results['tournamentSecondsRemaining']
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
|
|
@ -317,9 +317,8 @@ class ControlsGuide(ba.Actor):
|
|||
# an input device that is *not* the touchscreen.
|
||||
# (otherwise it is confusing to see the touchscreen buttons right
|
||||
# next to our display buttons)
|
||||
touchscreen: ba.InputDevice | None = _ba.getinputdevice('TouchScreen',
|
||||
'#1',
|
||||
doraise=False)
|
||||
touchscreen: ba.InputDevice | None = ba.internal.getinputdevice(
|
||||
'TouchScreen', '#1', doraise=False)
|
||||
|
||||
if touchscreen is not None:
|
||||
# We look at the session's players; not the activity's.
|
||||
|
|
@ -385,7 +384,7 @@ class ControlsGuide(ba.Actor):
|
|||
# If there's no players with input devices yet, try to default to
|
||||
# showing keyboard controls.
|
||||
if not input_devices:
|
||||
kbd = _ba.getinputdevice('Keyboard', '#1', doraise=False)
|
||||
kbd = ba.internal.getinputdevice('Keyboard', '#1', doraise=False)
|
||||
if kbd is not None:
|
||||
input_devices.append(kbd)
|
||||
|
||||
|
|
|
|||
4
dist/ba_data/python/bastd/actor/popuptext.py
vendored
4
dist/ba_data/python/bastd/actor/popuptext.py
vendored
|
|
@ -36,9 +36,9 @@ class PopupText(ba.Actor):
|
|||
if len(color) == 3:
|
||||
color = (color[0], color[1], color[2], 1.0)
|
||||
pos = (position[0] + offset[0] + random_offset *
|
||||
(0.5 - random.random()), position[1] + offset[0] +
|
||||
(0.5 - random.random()), position[1] + offset[1] +
|
||||
random_offset * (0.5 - random.random()), position[2] +
|
||||
offset[0] + random_offset * (0.5 - random.random()))
|
||||
offset[2] + random_offset * (0.5 - random.random()))
|
||||
|
||||
self.node = ba.newnode('text',
|
||||
attrs={
|
||||
|
|
|
|||
18
dist/ba_data/python/bastd/actor/spaz.py
vendored
18
dist/ba_data/python/bastd/actor/spaz.py
vendored
|
|
@ -81,7 +81,7 @@ class Spaz(ba.Actor):
|
|||
|
||||
factory = SpazFactory.get()
|
||||
|
||||
# we need to behave slightly different in the tutorial
|
||||
# We need to behave slightly different in the tutorial.
|
||||
self._demo_mode = demo_mode
|
||||
|
||||
self.play_big_death_sound = False
|
||||
|
|
@ -758,7 +758,7 @@ class Spaz(ba.Actor):
|
|||
tex = PowerupBoxFactory.get().tex_punch
|
||||
self._flash_billboard(tex)
|
||||
self.equip_boxing_gloves()
|
||||
if self.powerups_expire:
|
||||
if self.powerups_expire and not self.default_boxing_gloves:
|
||||
self.node.boxing_gloves_flashing = False
|
||||
self.node.mini_billboard_3_texture = tex
|
||||
t_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
|
||||
|
|
@ -966,7 +966,7 @@ class Spaz(ba.Actor):
|
|||
self.on_punched(damage)
|
||||
|
||||
# If damage was significant, lets show it.
|
||||
if damage > 350:
|
||||
if damage >= 350:
|
||||
assert msg.force_direction is not None
|
||||
ba.show_damage_count('-' + str(int(damage / 10)) + '%',
|
||||
msg.pos, msg.force_direction)
|
||||
|
|
@ -977,11 +977,13 @@ class Spaz(ba.Actor):
|
|||
ba.playsound(SpazFactory.get().punch_sound_stronger,
|
||||
1.0,
|
||||
position=self.node.position)
|
||||
if damage > 500:
|
||||
if damage >= 500:
|
||||
sounds = SpazFactory.get().punch_sound_strong
|
||||
sound = sounds[random.randrange(len(sounds))]
|
||||
else:
|
||||
elif damage >= 100:
|
||||
sound = SpazFactory.get().punch_sound
|
||||
else:
|
||||
sound = SpazFactory.get().punch_sound_weak
|
||||
ba.playsound(sound, 1.0, position=self.node.position)
|
||||
|
||||
# Throw up some chunks.
|
||||
|
|
@ -1075,7 +1077,7 @@ class Spaz(ba.Actor):
|
|||
# us if its grown high enough.
|
||||
if self.hitpoints <= 0:
|
||||
damage_avg = self.node.damage_smoothed * damage_scale
|
||||
if damage_avg > 1000:
|
||||
if damage_avg >= 1000:
|
||||
self.shatter()
|
||||
|
||||
elif isinstance(msg, BombDiedMessage):
|
||||
|
|
@ -1341,9 +1343,9 @@ class Spaz(ba.Actor):
|
|||
hit_type='impact'))
|
||||
self.node.handlemessage('knockout', max(0.0, 50.0 * intensity))
|
||||
sounds: Sequence[ba.Sound]
|
||||
if intensity > 5.0:
|
||||
if intensity >= 5.0:
|
||||
sounds = SpazFactory.get().impact_sounds_harder
|
||||
elif intensity > 3.0:
|
||||
elif intensity >= 3.0:
|
||||
sounds = SpazFactory.get().impact_sounds_hard
|
||||
else:
|
||||
sounds = SpazFactory.get().impact_sounds_medium
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -16,66 +16,67 @@ def get_appearances(include_locked: bool = False) -> list[str]:
|
|||
"""Get the list of available spaz appearances."""
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-branches
|
||||
get_purchased = ba.internal.get_purchased
|
||||
disallowed = []
|
||||
if not include_locked:
|
||||
# hmm yeah this'll be tough to hack...
|
||||
if not _ba.get_purchased('characters.santa'):
|
||||
if not get_purchased('characters.santa'):
|
||||
disallowed.append('Santa Claus')
|
||||
if not _ba.get_purchased('characters.frosty'):
|
||||
if not get_purchased('characters.frosty'):
|
||||
disallowed.append('Frosty')
|
||||
if not _ba.get_purchased('characters.bones'):
|
||||
if not get_purchased('characters.bones'):
|
||||
disallowed.append('Bones')
|
||||
if not _ba.get_purchased('characters.bernard'):
|
||||
if not get_purchased('characters.bernard'):
|
||||
disallowed.append('Bernard')
|
||||
if not _ba.get_purchased('characters.pixie'):
|
||||
if not get_purchased('characters.pixie'):
|
||||
disallowed.append('Pixel')
|
||||
if not _ba.get_purchased('characters.pascal'):
|
||||
if not get_purchased('characters.pascal'):
|
||||
disallowed.append('Pascal')
|
||||
if not _ba.get_purchased('characters.actionhero'):
|
||||
if not get_purchased('characters.actionhero'):
|
||||
disallowed.append('Todd McBurton')
|
||||
if not _ba.get_purchased('characters.taobaomascot'):
|
||||
if not get_purchased('characters.taobaomascot'):
|
||||
disallowed.append('Taobao Mascot')
|
||||
if not _ba.get_purchased('characters.agent'):
|
||||
if not get_purchased('characters.agent'):
|
||||
disallowed.append('Agent Johnson')
|
||||
if not _ba.get_purchased('characters.jumpsuit'):
|
||||
if not get_purchased('characters.jumpsuit'):
|
||||
disallowed.append('Lee')
|
||||
if not _ba.get_purchased('characters.assassin'):
|
||||
if not get_purchased('characters.assassin'):
|
||||
disallowed.append('Zola')
|
||||
if not _ba.get_purchased('characters.wizard'):
|
||||
if not get_purchased('characters.wizard'):
|
||||
disallowed.append('Grumbledorf')
|
||||
if not _ba.get_purchased('characters.cowboy'):
|
||||
if not get_purchased('characters.cowboy'):
|
||||
disallowed.append('Butch')
|
||||
if not _ba.get_purchased('characters.witch'):
|
||||
if not get_purchased('characters.witch'):
|
||||
disallowed.append('Witch')
|
||||
if not _ba.get_purchased('characters.warrior'):
|
||||
if not get_purchased('characters.warrior'):
|
||||
disallowed.append('Warrior')
|
||||
if not _ba.get_purchased('characters.superhero'):
|
||||
if not get_purchased('characters.superhero'):
|
||||
disallowed.append('Middle-Man')
|
||||
if not _ba.get_purchased('characters.alien'):
|
||||
if not get_purchased('characters.alien'):
|
||||
disallowed.append('Alien')
|
||||
if not _ba.get_purchased('characters.oldlady'):
|
||||
if not get_purchased('characters.oldlady'):
|
||||
disallowed.append('OldLady')
|
||||
if not _ba.get_purchased('characters.gladiator'):
|
||||
if not get_purchased('characters.gladiator'):
|
||||
disallowed.append('Gladiator')
|
||||
if not _ba.get_purchased('characters.wrestler'):
|
||||
if not get_purchased('characters.wrestler'):
|
||||
disallowed.append('Wrestler')
|
||||
if not _ba.get_purchased('characters.operasinger'):
|
||||
if not get_purchased('characters.operasinger'):
|
||||
disallowed.append('Gretel')
|
||||
if not _ba.get_purchased('characters.robot'):
|
||||
if not get_purchased('characters.robot'):
|
||||
disallowed.append('Robot')
|
||||
if not _ba.get_purchased('characters.cyborg'):
|
||||
if not get_purchased('characters.cyborg'):
|
||||
disallowed.append('B-9000')
|
||||
if not _ba.get_purchased('characters.bunny'):
|
||||
if not get_purchased('characters.bunny'):
|
||||
disallowed.append('Easter Bunny')
|
||||
if not _ba.get_purchased('characters.kronk'):
|
||||
if not get_purchased('characters.kronk'):
|
||||
disallowed.append('Kronk')
|
||||
if not _ba.get_purchased('characters.zoe'):
|
||||
if not get_purchased('characters.zoe'):
|
||||
disallowed.append('Zoe')
|
||||
if not _ba.get_purchased('characters.jackmorgan'):
|
||||
if not get_purchased('characters.jackmorgan'):
|
||||
disallowed.append('Jack Morgan')
|
||||
if not _ba.get_purchased('characters.mel'):
|
||||
if not get_purchased('characters.mel'):
|
||||
disallowed.append('Mel')
|
||||
if not _ba.get_purchased('characters.snakeshadow'):
|
||||
if not get_purchased('characters.snakeshadow'):
|
||||
disallowed.append('Snake Shadow')
|
||||
return [
|
||||
s for s in list(ba.app.spaz_appearances.keys()) if s not in disallowed
|
||||
|
|
|
|||
25
dist/ba_data/python/bastd/actor/spazfactory.py
vendored
25
dist/ba_data/python/bastd/actor/spazfactory.py
vendored
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.gameutils import SharedObjects
|
||||
import _ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
|
|
@ -38,6 +38,9 @@ class SpazFactory:
|
|||
"""The sound that plays for an 'important' spaz death such as in
|
||||
co-op games."""
|
||||
|
||||
punch_sound_weak: ba.Sound
|
||||
"""A weak punch ba.Sound."""
|
||||
|
||||
punch_sound: ba.Sound
|
||||
"""A standard punch ba.Sound."""
|
||||
|
||||
|
|
@ -98,6 +101,7 @@ class SpazFactory:
|
|||
self.impact_sounds_harder = (ba.getsound('bigImpact'),
|
||||
ba.getsound('bigImpact2'))
|
||||
self.single_player_death_sound = ba.getsound('playerDeath')
|
||||
self.punch_sound_weak = ba.getsound('punchWeak01')
|
||||
self.punch_sound = ba.getsound('punch01')
|
||||
self.punch_sound_strong = (ba.getsound('punchStrong01'),
|
||||
ba.getsound('punchStrong02'))
|
||||
|
|
@ -208,15 +212,18 @@ class SpazFactory:
|
|||
|
||||
# Lets load some basic rules.
|
||||
# (allows them to be tweaked from the master server)
|
||||
self.shield_decay_rate = _ba.get_v1_account_misc_read_val('rsdr', 10.0)
|
||||
self.punch_cooldown = _ba.get_v1_account_misc_read_val('rpc', 400)
|
||||
self.punch_cooldown_gloves = (_ba.get_v1_account_misc_read_val(
|
||||
self.shield_decay_rate = ba.internal.get_v1_account_misc_read_val(
|
||||
'rsdr', 10.0)
|
||||
self.punch_cooldown = ba.internal.get_v1_account_misc_read_val(
|
||||
'rpc', 400)
|
||||
self.punch_cooldown_gloves = (ba.internal.get_v1_account_misc_read_val(
|
||||
'rpcg', 300))
|
||||
self.punch_power_scale = _ba.get_v1_account_misc_read_val('rpp', 1.2)
|
||||
self.punch_power_scale_gloves = (_ba.get_v1_account_misc_read_val(
|
||||
'rppg', 1.4))
|
||||
self.max_shield_spillover_damage = (_ba.get_v1_account_misc_read_val(
|
||||
'rsms', 500))
|
||||
self.punch_power_scale = ba.internal.get_v1_account_misc_read_val(
|
||||
'rpp', 1.2)
|
||||
self.punch_power_scale_gloves = (
|
||||
ba.internal.get_v1_account_misc_read_val('rppg', 1.4))
|
||||
self.max_shield_spillover_damage = (
|
||||
ba.internal.get_v1_account_misc_read_val('rsms', 500))
|
||||
|
||||
def get_style(self, character: str) -> str:
|
||||
"""Return the named style for this character.
|
||||
|
|
|
|||
10
dist/ba_data/python/bastd/game/easteregghunt.py
vendored
10
dist/ba_data/python/bastd/game/easteregghunt.py
vendored
|
|
@ -44,7 +44,10 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
|||
|
||||
name = 'Easter Egg Hunt'
|
||||
description = 'Gather eggs!'
|
||||
available_settings = [ba.BoolSetting('Pro Mode', default=False)]
|
||||
available_settings = [
|
||||
ba.BoolSetting('Pro Mode', default=False),
|
||||
ba.BoolSetting('Epic Mode', default=False),
|
||||
]
|
||||
scoreconfig = ba.ScoreConfig(label='Score', scoretype=ba.ScoreType.POINTS)
|
||||
|
||||
# We're currently hard-coded for one map.
|
||||
|
|
@ -70,6 +73,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
|||
self.egg_tex_3 = ba.gettexture('eggTex3')
|
||||
self._collect_sound = ba.getsound('powerup01')
|
||||
self._pro_mode = settings.get('Pro Mode', False)
|
||||
self._epic_mode = settings.get('Epic Mode', False)
|
||||
self._max_eggs = 1.0
|
||||
self.egg_material = ba.Material()
|
||||
self.egg_material.add_actions(
|
||||
|
|
@ -81,7 +85,9 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
|||
self._bots: SpazBotSet | None = None
|
||||
|
||||
# Base class overrides
|
||||
self.default_music = ba.MusicType.FORWARD_MARCH
|
||||
self.slow_motion = self._epic_mode
|
||||
self.default_music = (ba.MusicType.EPIC if self._epic_mode else
|
||||
ba.MusicType.FORWARD_MARCH)
|
||||
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
if self.has_begun():
|
||||
|
|
|
|||
7
dist/ba_data/python/bastd/game/football.py
vendored
7
dist/ba_data/python/bastd/game/football.py
vendored
|
|
@ -106,8 +106,8 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
|||
],
|
||||
default=1.0,
|
||||
),
|
||||
ba.BoolSetting('Epic Mode', default=False),
|
||||
]
|
||||
default_music = ba.MusicType.FOOTBALL
|
||||
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
|
||||
|
|
@ -143,6 +143,10 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
|||
self._flag_respawn_light: ba.NodeActor | None = None
|
||||
self._score_to_win = int(settings['Score to Win'])
|
||||
self._time_limit = float(settings['Time Limit'])
|
||||
self._epic_mode = bool(settings['Epic Mode'])
|
||||
self.slow_motion = self._epic_mode
|
||||
self.default_music = (ba.MusicType.EPIC
|
||||
if self._epic_mode else ba.MusicType.FOOTBALL)
|
||||
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
touchdowns = self._score_to_win / 7
|
||||
|
|
@ -330,6 +334,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
|||
tips = ['Use the pick-up button to grab the flag < ${PICKUP} >']
|
||||
scoreconfig = ba.ScoreConfig(scoretype=ba.ScoreType.MILLISECONDS,
|
||||
version='B')
|
||||
|
||||
default_music = ba.MusicType.FOOTBALL
|
||||
|
||||
# FIXME: Need to update co-op games to use getscoreconfig.
|
||||
|
|
|
|||
6
dist/ba_data/python/bastd/game/hockey.py
vendored
6
dist/ba_data/python/bastd/game/hockey.py
vendored
|
|
@ -137,8 +137,8 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
|||
],
|
||||
default=1.0,
|
||||
),
|
||||
ba.BoolSetting('Epic Mode', default=False),
|
||||
]
|
||||
default_music = ba.MusicType.HOCKEY
|
||||
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
|
||||
|
|
@ -203,6 +203,10 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
|||
self._puck: Puck | None = None
|
||||
self._score_to_win = int(settings['Score to Win'])
|
||||
self._time_limit = float(settings['Time Limit'])
|
||||
self._epic_mode = bool(settings['Epic Mode'])
|
||||
self.slow_motion = self._epic_mode
|
||||
self.default_music = (ba.MusicType.EPIC
|
||||
if self._epic_mode else ba.MusicType.HOCKEY)
|
||||
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
if self._score_to_win == 1:
|
||||
|
|
|
|||
6
dist/ba_data/python/bastd/game/keepaway.py
vendored
6
dist/ba_data/python/bastd/game/keepaway.py
vendored
|
|
@ -76,9 +76,9 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]):
|
|||
],
|
||||
default=1.0,
|
||||
),
|
||||
ba.BoolSetting('Epic Mode', default=False),
|
||||
]
|
||||
scoreconfig = ba.ScoreConfig(label='Time Held')
|
||||
default_music = ba.MusicType.KEEP_AWAY
|
||||
|
||||
@classmethod
|
||||
def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
|
||||
|
|
@ -115,6 +115,10 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]):
|
|||
self._flag: Flag | None = None
|
||||
self._hold_time = int(settings['Hold Time'])
|
||||
self._time_limit = float(settings['Time Limit'])
|
||||
self._epic_mode = bool(settings['Epic Mode'])
|
||||
self.slow_motion = self._epic_mode
|
||||
self.default_music = (ba.MusicType.EPIC
|
||||
if self._epic_mode else ba.MusicType.KEEP_AWAY)
|
||||
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
return 'Carry the flag for ${ARG1} seconds.', self._hold_time
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]):
|
|||
],
|
||||
default=1.0,
|
||||
),
|
||||
ba.BoolSetting('Epic Mode', default=False),
|
||||
]
|
||||
scoreconfig = ba.ScoreConfig(label='Time Held')
|
||||
|
||||
|
|
@ -115,6 +116,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]):
|
|||
self._scoring_team: weakref.ref[Team] | None = None
|
||||
self._hold_time = int(settings['Hold Time'])
|
||||
self._time_limit = float(settings['Time Limit'])
|
||||
self._epic_mode = bool(settings['Epic Mode'])
|
||||
self._flag_region_material = ba.Material()
|
||||
self._flag_region_material.add_actions(
|
||||
conditions=('they_have_material', shared.player_material),
|
||||
|
|
@ -128,7 +130,9 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]):
|
|||
))
|
||||
|
||||
# Base class overrides.
|
||||
self.default_music = ba.MusicType.SCARY
|
||||
self.slow_motion = self._epic_mode
|
||||
self.default_music = (ba.MusicType.EPIC
|
||||
if self._epic_mode else ba.MusicType.SCARY)
|
||||
|
||||
def get_instance_description(self) -> str | Sequence:
|
||||
return 'Secure the flag for ${ARG1} seconds.', self._hold_time
|
||||
|
|
|
|||
20
dist/ba_data/python/bastd/mainmenu.py
vendored
20
dist/ba_data/python/bastd/mainmenu.py
vendored
|
|
@ -10,7 +10,7 @@ import weakref
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
import _ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -67,7 +67,8 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]):
|
|||
# host is navigating menus while they're just staring at an
|
||||
# empty-ish screen.
|
||||
tval = ba.Lstr(resource='hostIsNavigatingMenusText',
|
||||
subs=[('${HOST}', _ba.get_v1_account_display_string())])
|
||||
subs=[('${HOST}',
|
||||
ba.internal.get_v1_account_display_string())])
|
||||
self._host_is_navigating_text = ba.NodeActor(
|
||||
ba.newnode('text',
|
||||
attrs={
|
||||
|
|
@ -251,7 +252,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]):
|
|||
self._update()
|
||||
|
||||
# Hopefully this won't hitch but lets space these out anyway.
|
||||
_ba.add_clean_frame_callback(ba.WeakCall(self._start_preloads))
|
||||
ba.internal.add_clean_frame_callback(ba.WeakCall(self._start_preloads))
|
||||
|
||||
random.seed()
|
||||
|
||||
|
|
@ -274,7 +275,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]):
|
|||
|
||||
# We now want to wait until we're signed in before fetching news.
|
||||
def _try_fetching_news(self) -> None:
|
||||
if _ba.get_v1_account_state() == 'signed_in':
|
||||
if ba.internal.get_v1_account_state() == 'signed_in':
|
||||
self._fetch_news()
|
||||
self._fetch_timer = None
|
||||
|
||||
|
|
@ -282,7 +283,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]):
|
|||
ba.app.main_menu_last_news_fetch_time = time.time()
|
||||
|
||||
# UPDATE - We now just pull news from MRVs.
|
||||
news = _ba.get_v1_account_misc_read_val('n', None)
|
||||
news = ba.internal.get_v1_account_misc_read_val('n', None)
|
||||
if news is not None:
|
||||
self._got_news(news)
|
||||
|
||||
|
|
@ -453,6 +454,11 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]):
|
|||
ba.app.ui.set_main_menu_window(
|
||||
CoopBrowserWindow(
|
||||
transition=None).get_root_widget())
|
||||
elif main_menu_location == 'Benchmarks & Stress Tests':
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.debug import DebugWindow
|
||||
ba.app.ui.set_main_menu_window(
|
||||
DebugWindow(transition=None).get_root_widget())
|
||||
else:
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.mainmenu import MainMenuWindow
|
||||
|
|
@ -757,7 +763,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]):
|
|||
})
|
||||
|
||||
def _get_custom_logo_tex_name(self) -> str | None:
|
||||
if _ba.get_v1_account_misc_read_val('easter', False):
|
||||
if ba.internal.get_v1_account_misc_read_val('easter', False):
|
||||
return 'logoEaster'
|
||||
return None
|
||||
|
||||
|
|
@ -930,7 +936,7 @@ class MainMenuSession(ba.Session):
|
|||
|
||||
def on_activity_end(self, activity: ba.Activity, results: Any) -> None:
|
||||
if self._locked:
|
||||
_ba.unlock_all_input()
|
||||
ba.internal.unlock_all_input()
|
||||
|
||||
# Any ending activity leads us into the main menu one.
|
||||
self.setactivity(ba.newactivity(MainMenuActivity))
|
||||
|
|
|
|||
10
dist/ba_data/python/bastd/tutorial.py
vendored
10
dist/ba_data/python/bastd/tutorial.py
vendored
|
|
@ -18,8 +18,8 @@ from __future__ import annotations
|
|||
import math
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.actor import spaz as basespaz
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -235,7 +235,7 @@ class TutorialActivity(ba.Activity[Player, Team]):
|
|||
super().on_begin()
|
||||
|
||||
ba.set_analytics_screen('Tutorial Start')
|
||||
_ba.increment_analytics_count('Tutorial start')
|
||||
ba.internal.increment_analytics_count('Tutorial start')
|
||||
|
||||
if bool(False):
|
||||
# Buttons on top.
|
||||
|
|
@ -461,7 +461,7 @@ class TutorialActivity(ba.Activity[Player, Team]):
|
|||
|
||||
def run(self, a: TutorialActivity) -> None:
|
||||
print('setting to', self._speed)
|
||||
_ba.set_debug_speed_exponent(self._speed)
|
||||
ba.internal.set_debug_speed_exponent(self._speed)
|
||||
|
||||
class RemoveGloves:
|
||||
|
||||
|
|
@ -609,7 +609,7 @@ class TutorialActivity(ba.Activity[Player, Team]):
|
|||
pass
|
||||
|
||||
def run(self, a: TutorialActivity) -> None:
|
||||
_ba.increment_analytics_count('Tutorial finish')
|
||||
ba.internal.increment_analytics_count('Tutorial finish')
|
||||
a.end()
|
||||
|
||||
class Move:
|
||||
|
|
@ -2328,7 +2328,7 @@ class TutorialActivity(ba.Activity[Player, Team]):
|
|||
('${TOTAL}', str(len(self.players)))]) if count > 0 else ''
|
||||
if (count >= len(self.players) and self.players
|
||||
and not self._have_skipped):
|
||||
_ba.increment_analytics_count('Tutorial skip')
|
||||
ba.internal.increment_analytics_count('Tutorial skip')
|
||||
ba.set_analytics_screen('Tutorial Skip')
|
||||
self._have_skipped = True
|
||||
ba.playsound(ba.getsound('swish'))
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
|
||||
|
||||
|
|
@ -12,10 +11,11 @@ def show_sign_in_prompt(account_type: str | None = None) -> None:
|
|||
"""Bring up a prompt telling the user they must sign in."""
|
||||
from bastd.ui.confirm import ConfirmWindow
|
||||
from bastd.ui.account import settings
|
||||
from ba.internal import sign_in_v1
|
||||
if account_type == 'Google Play':
|
||||
ConfirmWindow(
|
||||
ba.Lstr(resource='notSignedInGooglePlayErrorText'),
|
||||
lambda: _ba.sign_in_v1('Google Play'),
|
||||
lambda: sign_in_v1('Google Play'),
|
||||
ok_text=ba.Lstr(resource='accountSettingsWindow.signInText'),
|
||||
width=460,
|
||||
height=130)
|
||||
|
|
|
|||
11
dist/ba_data/python/bastd/ui/account/link.py
vendored
11
dist/ba_data/python/bastd/ui/account/link.py
vendored
|
|
@ -8,8 +8,8 @@ import copy
|
|||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -50,7 +50,8 @@ class AccountLinkWindow(ba.Window):
|
|||
autoselect=True,
|
||||
icon=ba.gettexture('crossOut'),
|
||||
iconscale=1.2)
|
||||
maxlinks = _ba.get_v1_account_misc_read_val('maxLinkAccounts', 5)
|
||||
maxlinks = ba.internal.get_v1_account_misc_read_val(
|
||||
'maxLinkAccounts', 5)
|
||||
ba.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height * 0.56),
|
||||
|
|
@ -84,17 +85,17 @@ class AccountLinkWindow(ba.Window):
|
|||
|
||||
def _generate_press(self) -> None:
|
||||
from bastd.ui import account
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
account.show_sign_in_prompt()
|
||||
return
|
||||
ba.screenmessage(
|
||||
ba.Lstr(resource='gatherWindow.requestingAPromoCodeText'),
|
||||
color=(0, 1, 0))
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'ACCOUNT_LINK_CODE_REQUEST',
|
||||
'expire_time': time.time() + 5
|
||||
})
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
||||
def _enter_code_press(self) -> None:
|
||||
from bastd.ui import promocode
|
||||
|
|
|
|||
184
dist/ba_data/python/bastd/ui/account/settings.py
vendored
184
dist/ba_data/python/bastd/ui/account/settings.py
vendored
|
|
@ -8,8 +8,8 @@ from __future__ import annotations
|
|||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -25,7 +25,6 @@ class AccountSettingsWindow(ba.Window):
|
|||
close_once_signed_in: bool = False):
|
||||
# pylint: disable=too-many-statements
|
||||
|
||||
self._sign_in_game_circle_button: ba.Widget | None = None
|
||||
self._sign_in_v2_button: ba.Widget | None = None
|
||||
self._sign_in_device_button: ba.Widget | None = None
|
||||
|
||||
|
|
@ -45,10 +44,10 @@ class AccountSettingsWindow(ba.Window):
|
|||
self._r = 'accountSettingsWindow'
|
||||
self._modal = modal
|
||||
self._needs_refresh = False
|
||||
self._signed_in = (_ba.get_v1_account_state() == 'signed_in')
|
||||
self._account_state_num = _ba.get_v1_account_state_num()
|
||||
self._signed_in = (ba.internal.get_v1_account_state() == 'signed_in')
|
||||
self._account_state_num = ba.internal.get_v1_account_state_num()
|
||||
self._show_linked = (self._signed_in
|
||||
and _ba.get_v1_account_misc_read_val(
|
||||
and ba.internal.get_v1_account_misc_read_val(
|
||||
'allowAccountLinking2', False))
|
||||
self._check_sign_in_timer = ba.Timer(1.0,
|
||||
ba.WeakCall(self._update),
|
||||
|
|
@ -58,7 +57,7 @@ class AccountSettingsWindow(ba.Window):
|
|||
# Currently we can only reset achievements on game-center.
|
||||
account_type: str | None
|
||||
if self._signed_in:
|
||||
account_type = _ba.get_v1_account_type()
|
||||
account_type = ba.internal.get_v1_account_type()
|
||||
else:
|
||||
account_type = None
|
||||
self._can_reset_achievements = (account_type == 'Game Center')
|
||||
|
|
@ -84,9 +83,6 @@ class AccountSettingsWindow(ba.Window):
|
|||
if app.platform == 'android' and app.subplatform == 'google':
|
||||
self._show_sign_in_buttons.append('Google Play')
|
||||
|
||||
elif app.platform == 'android' and app.subplatform == 'amazon':
|
||||
self._show_sign_in_buttons.append('Game Circle')
|
||||
|
||||
# Local accounts are generally always available with a few key
|
||||
# exceptions.
|
||||
self._show_sign_in_buttons.append('Local')
|
||||
|
|
@ -159,11 +155,12 @@ class AccountSettingsWindow(ba.Window):
|
|||
# Hmm should update this to use get_account_state_num.
|
||||
# Theoretically if we switch from one signed-in account to another
|
||||
# in the background this would break.
|
||||
account_state_num = _ba.get_v1_account_state_num()
|
||||
account_state = _ba.get_v1_account_state()
|
||||
account_state_num = ba.internal.get_v1_account_state_num()
|
||||
account_state = ba.internal.get_v1_account_state()
|
||||
|
||||
show_linked = (self._signed_in and _ba.get_v1_account_misc_read_val(
|
||||
'allowAccountLinking2', False))
|
||||
show_linked = (self._signed_in
|
||||
and ba.internal.get_v1_account_misc_read_val(
|
||||
'allowAccountLinking2', False))
|
||||
|
||||
if (account_state_num != self._account_state_num
|
||||
or self._show_linked != show_linked or self._needs_refresh):
|
||||
|
|
@ -191,8 +188,8 @@ class AccountSettingsWindow(ba.Window):
|
|||
# pylint: disable=cyclic-import
|
||||
from bastd.ui import confirm
|
||||
|
||||
account_state = _ba.get_v1_account_state()
|
||||
account_type = (_ba.get_v1_account_type()
|
||||
account_state = ba.internal.get_v1_account_state()
|
||||
account_type = (ba.internal.get_v1_account_type()
|
||||
if account_state == 'signed_in' else 'unknown')
|
||||
|
||||
is_google = account_type == 'Google Play'
|
||||
|
|
@ -212,27 +209,24 @@ class AccountSettingsWindow(ba.Window):
|
|||
show_google_play_sign_in_button = (account_state == 'signed_out'
|
||||
and 'Google Play'
|
||||
in self._show_sign_in_buttons)
|
||||
show_game_circle_sign_in_button = (account_state == 'signed_out'
|
||||
and 'Game Circle'
|
||||
in self._show_sign_in_buttons)
|
||||
show_device_sign_in_button = (account_state == 'signed_out' and 'Local'
|
||||
in self._show_sign_in_buttons)
|
||||
show_v2_sign_in_button = (account_state == 'signed_out'
|
||||
and 'V2' in self._show_sign_in_buttons)
|
||||
sign_in_button_space = 70.0
|
||||
|
||||
show_game_service_button = (self._signed_in and account_type
|
||||
in ['Game Center', 'Game Circle'])
|
||||
show_game_service_button = (self._signed_in
|
||||
and account_type in ['Game Center'])
|
||||
game_service_button_space = 60.0
|
||||
|
||||
show_linked_accounts_text = (self._signed_in
|
||||
and _ba.get_v1_account_misc_read_val(
|
||||
show_linked_accounts_text = (self._signed_in and
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
'allowAccountLinking2', False))
|
||||
linked_accounts_text_space = 60.0
|
||||
|
||||
show_achievements_button = (
|
||||
self._signed_in
|
||||
and account_type in ('Google Play', 'Alibaba', 'Local', 'OUYA'))
|
||||
show_achievements_button = (self._signed_in and account_type
|
||||
in ('Google Play', 'Alibaba', 'Local',
|
||||
'OUYA', 'V2'))
|
||||
achievements_button_space = 60.0
|
||||
|
||||
show_achievements_text = (self._signed_in
|
||||
|
|
@ -251,11 +245,17 @@ class AccountSettingsWindow(ba.Window):
|
|||
show_reset_progress_button = False
|
||||
reset_progress_button_space = 70.0
|
||||
|
||||
show_player_profiles_button = self._signed_in
|
||||
player_profiles_button_space = 100.0
|
||||
show_manage_v2_account_button = (self._signed_in
|
||||
and account_type == 'V2'
|
||||
and bool(False)) # Disabled for now.
|
||||
manage_v2_account_button_space = 100.0
|
||||
|
||||
show_link_accounts_button = (self._signed_in
|
||||
and _ba.get_v1_account_misc_read_val(
|
||||
show_player_profiles_button = self._signed_in
|
||||
player_profiles_button_space = (70.0 if show_manage_v2_account_button
|
||||
else 100.0)
|
||||
|
||||
show_link_accounts_button = (self._signed_in and
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
'allowAccountLinking2', False))
|
||||
link_accounts_button_space = 70.0
|
||||
|
||||
|
|
@ -282,8 +282,6 @@ class AccountSettingsWindow(ba.Window):
|
|||
self._sub_height += signing_in_text_space
|
||||
if show_google_play_sign_in_button:
|
||||
self._sub_height += sign_in_button_space
|
||||
if show_game_circle_sign_in_button:
|
||||
self._sub_height += sign_in_button_space
|
||||
if show_device_sign_in_button:
|
||||
self._sub_height += sign_in_button_space
|
||||
if show_v2_sign_in_button:
|
||||
|
|
@ -306,6 +304,8 @@ class AccountSettingsWindow(ba.Window):
|
|||
self._sub_height += sign_in_benefits_space
|
||||
if show_reset_progress_button:
|
||||
self._sub_height += reset_progress_button_space
|
||||
if show_manage_v2_account_button:
|
||||
self._sub_height += manage_v2_account_button_space
|
||||
if show_player_profiles_button:
|
||||
self._sub_height += player_profiles_button_space
|
||||
if show_link_accounts_button:
|
||||
|
|
@ -335,7 +335,8 @@ class AccountSettingsWindow(ba.Window):
|
|||
size=(0, 0),
|
||||
text=ba.Lstr(
|
||||
resource='accountSettingsWindow.deviceSpecificAccountText',
|
||||
subs=[('${NAME}', _ba.get_v1_account_display_string())]),
|
||||
subs=[('${NAME}',
|
||||
ba.internal.get_v1_account_display_string())]),
|
||||
scale=0.7,
|
||||
color=(0.5, 0.5, 0.6),
|
||||
maxwidth=self._sub_width * 0.9,
|
||||
|
|
@ -376,7 +377,7 @@ class AccountSettingsWindow(ba.Window):
|
|||
self._account_name_text = None
|
||||
|
||||
if self._back_button is None:
|
||||
bbtn = _ba.get_special_widget('back_button')
|
||||
bbtn = ba.internal.get_special_widget('back_button')
|
||||
else:
|
||||
bbtn = self._back_button
|
||||
|
||||
|
|
@ -444,32 +445,8 @@ class AccountSettingsWindow(ba.Window):
|
|||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn)
|
||||
ba.widget(edit=btn, show_buffer_bottom=40, show_buffer_top=100)
|
||||
self._sign_in_text = None
|
||||
|
||||
if show_game_circle_sign_in_button:
|
||||
button_width = 350
|
||||
v -= sign_in_button_space
|
||||
self._sign_in_game_circle_button = btn = ba.buttonwidget(
|
||||
parent=self._subcontainer,
|
||||
position=((self._sub_width - button_width) * 0.5, v - 20),
|
||||
autoselect=True,
|
||||
size=(button_width, 60),
|
||||
label=ba.Lstr(value='${A}${B}',
|
||||
subs=[('${A}',
|
||||
ba.charstr(
|
||||
ba.SpecialChar.GAME_CIRCLE_LOGO)),
|
||||
('${B}',
|
||||
ba.Lstr(resource=self._r +
|
||||
'.signInWithGameCircleText'))]),
|
||||
on_activate_call=lambda: self._sign_in_press('Game Circle'))
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn)
|
||||
ba.widget(edit=btn, show_buffer_bottom=40, show_buffer_top=100)
|
||||
self._sign_in_text = None
|
||||
|
|
@ -514,7 +491,8 @@ class AccountSettingsWindow(ba.Window):
|
|||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn)
|
||||
ba.widget(edit=btn, show_buffer_bottom=40, show_buffer_top=100)
|
||||
self._sign_in_text = None
|
||||
|
|
@ -560,11 +538,34 @@ class AccountSettingsWindow(ba.Window):
|
|||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn)
|
||||
ba.widget(edit=btn, show_buffer_bottom=40, show_buffer_top=100)
|
||||
self._sign_in_text = None
|
||||
|
||||
if show_manage_v2_account_button:
|
||||
button_width = 300
|
||||
v -= manage_v2_account_button_space
|
||||
self._manage_v2_button = btn = ba.buttonwidget(
|
||||
parent=self._subcontainer,
|
||||
position=((self._sub_width - button_width) * 0.5, v + 30),
|
||||
autoselect=True,
|
||||
size=(button_width, 60),
|
||||
label=ba.Lstr(resource=self._r + '.manageAccount'),
|
||||
color=(0.55, 0.5, 0.6),
|
||||
icon=ba.gettexture('settingsIcon'),
|
||||
textcolor=(0.75, 0.7, 0.8),
|
||||
on_activate_call=lambda: ba.open_url(
|
||||
'https://ballistica.net/accountsettings'))
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn)
|
||||
|
||||
if show_player_profiles_button:
|
||||
button_width = 300
|
||||
v -= player_profiles_button_space
|
||||
|
|
@ -582,18 +583,17 @@ class AccountSettingsWindow(ba.Window):
|
|||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=0)
|
||||
|
||||
# the button to go to OS-Specific leaderboards/high-score-lists/etc.
|
||||
if show_game_service_button:
|
||||
button_width = 300
|
||||
v -= game_service_button_space * 0.85
|
||||
account_type = _ba.get_v1_account_type()
|
||||
account_type = ba.internal.get_v1_account_type()
|
||||
if account_type == 'Game Center':
|
||||
account_type_name = ba.Lstr(resource='gameCenterText')
|
||||
elif account_type == 'Game Circle':
|
||||
account_type_name = ba.Lstr(resource='gameCircleText')
|
||||
else:
|
||||
raise ValueError("unknown account type: '" +
|
||||
str(account_type) + "'")
|
||||
|
|
@ -603,14 +603,15 @@ class AccountSettingsWindow(ba.Window):
|
|||
color=(0.55, 0.5, 0.6),
|
||||
textcolor=(0.75, 0.7, 0.8),
|
||||
autoselect=True,
|
||||
on_activate_call=_ba.show_online_score_ui,
|
||||
on_activate_call=ba.internal.show_online_score_ui,
|
||||
size=(button_width, 50),
|
||||
label=account_type_name)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn)
|
||||
v -= game_service_button_space * 0.15
|
||||
else:
|
||||
|
|
@ -652,7 +653,8 @@ class AccountSettingsWindow(ba.Window):
|
|||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn)
|
||||
v -= achievements_button_space * 0.15
|
||||
else:
|
||||
|
|
@ -680,7 +682,8 @@ class AccountSettingsWindow(ba.Window):
|
|||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn)
|
||||
v -= leaderboards_button_space * 0.15
|
||||
else:
|
||||
|
|
@ -750,7 +753,8 @@ class AccountSettingsWindow(ba.Window):
|
|||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn)
|
||||
|
||||
self._linked_accounts_text: ba.Widget | None
|
||||
|
|
@ -805,7 +809,8 @@ class AccountSettingsWindow(ba.Window):
|
|||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=50)
|
||||
|
||||
self._unlink_accounts_button: ba.Widget | None
|
||||
|
|
@ -833,7 +838,8 @@ class AccountSettingsWindow(ba.Window):
|
|||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=50)
|
||||
self._update_unlink_accounts_button()
|
||||
else:
|
||||
|
|
@ -854,7 +860,8 @@ class AccountSettingsWindow(ba.Window):
|
|||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=15)
|
||||
|
||||
if show_cancel_v2_sign_in_button:
|
||||
|
|
@ -872,7 +879,8 @@ class AccountSettingsWindow(ba.Window):
|
|||
first_selectable = btn
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=15)
|
||||
|
||||
# Whatever the topmost selectable thing is, we want it to scroll all
|
||||
|
|
@ -889,13 +897,13 @@ class AccountSettingsWindow(ba.Window):
|
|||
def _on_achievements_press(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui import achievements
|
||||
account_state = _ba.get_v1_account_state()
|
||||
account_type = (_ba.get_v1_account_type()
|
||||
account_state = ba.internal.get_v1_account_state()
|
||||
account_type = (ba.internal.get_v1_account_type()
|
||||
if account_state == 'signed_in' else 'unknown')
|
||||
# for google play we use the built-in UI; otherwise pop up our own
|
||||
if account_type == 'Google Play':
|
||||
ba.timer(0.15,
|
||||
ba.Call(_ba.show_online_score_ui, 'achievements'),
|
||||
ba.Call(ba.internal.show_online_score_ui, 'achievements'),
|
||||
timetype=ba.TimeType.REAL)
|
||||
elif account_type != 'unknown':
|
||||
assert self._achievements_button is not None
|
||||
|
|
@ -907,15 +915,16 @@ class AccountSettingsWindow(ba.Window):
|
|||
|
||||
def _on_leaderboards_press(self) -> None:
|
||||
ba.timer(0.15,
|
||||
ba.Call(_ba.show_online_score_ui, 'leaderboards'),
|
||||
ba.Call(ba.internal.show_online_score_ui, 'leaderboards'),
|
||||
timetype=ba.TimeType.REAL)
|
||||
|
||||
def _have_unlinkable_accounts(self) -> bool:
|
||||
# if this is not present, we haven't had contact from the server so
|
||||
# let's not proceed..
|
||||
if _ba.get_public_login_id() is None:
|
||||
if ba.internal.get_public_login_id() is None:
|
||||
return False
|
||||
accounts = _ba.get_v1_account_misc_read_val_2('linkedAccounts', [])
|
||||
accounts = ba.internal.get_v1_account_misc_read_val_2(
|
||||
'linkedAccounts', [])
|
||||
return len(accounts) > 1
|
||||
|
||||
def _update_unlink_accounts_button(self) -> None:
|
||||
|
|
@ -933,11 +942,12 @@ class AccountSettingsWindow(ba.Window):
|
|||
|
||||
# if this is not present, we haven't had contact from the server so
|
||||
# let's not proceed..
|
||||
if _ba.get_public_login_id() is None:
|
||||
if ba.internal.get_public_login_id() is None:
|
||||
num = int(time.time()) % 4
|
||||
accounts_str = num * '.' + (4 - num) * ' '
|
||||
else:
|
||||
accounts = _ba.get_v1_account_misc_read_val_2('linkedAccounts', [])
|
||||
accounts = ba.internal.get_v1_account_misc_read_val_2(
|
||||
'linkedAccounts', [])
|
||||
# our_account = _bs.get_v1_account_display_string()
|
||||
# accounts = [a for a in accounts if a != our_account]
|
||||
# accounts_str = u', '.join(accounts) if accounts else
|
||||
|
|
@ -977,7 +987,7 @@ class AccountSettingsWindow(ba.Window):
|
|||
if self._tickets_text is None:
|
||||
return
|
||||
try:
|
||||
tc_str = str(_ba.get_v1_account_ticket_count())
|
||||
tc_str = str(ba.internal.get_v1_account_ticket_count())
|
||||
except Exception:
|
||||
ba.print_exception()
|
||||
tc_str = '-'
|
||||
|
|
@ -989,7 +999,7 @@ class AccountSettingsWindow(ba.Window):
|
|||
if self._account_name_text is None:
|
||||
return
|
||||
try:
|
||||
name_str = _ba.get_v1_account_display_string()
|
||||
name_str = ba.internal.get_v1_account_display_string()
|
||||
except Exception:
|
||||
ba.print_exception()
|
||||
name_str = '??'
|
||||
|
|
@ -1043,7 +1053,7 @@ class AccountSettingsWindow(ba.Window):
|
|||
if ba.app.accounts_v2.have_primary_credentials():
|
||||
ba.app.accounts_v2.set_primary_credentials(None)
|
||||
else:
|
||||
_ba.sign_out_v1()
|
||||
ba.internal.sign_out_v1()
|
||||
|
||||
cfg = ba.app.config
|
||||
|
||||
|
|
@ -1061,7 +1071,7 @@ class AccountSettingsWindow(ba.Window):
|
|||
account_type: str,
|
||||
show_test_warning: bool = True) -> None:
|
||||
del show_test_warning # unused
|
||||
_ba.sign_in_v1(account_type)
|
||||
ba.internal.sign_in_v1(account_type)
|
||||
|
||||
# Make note of the type account we're *wanting* to be signed in with.
|
||||
cfg = ba.app.config
|
||||
|
|
@ -1082,7 +1092,7 @@ class AccountSettingsWindow(ba.Window):
|
|||
# FIXME: This would need to happen server-side these days.
|
||||
if self._can_reset_achievements:
|
||||
ba.app.config['Achievements'] = {}
|
||||
_ba.reset_achievements()
|
||||
ba.internal.reset_achievements()
|
||||
campaign = getcampaign('Default')
|
||||
campaign.reset() # also writes the config..
|
||||
campaign = getcampaign('Challenges')
|
||||
|
|
|
|||
10
dist/ba_data/python/bastd/ui/account/unlink.py
vendored
10
dist/ba_data/python/bastd/ui/account/unlink.py
vendored
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -77,11 +77,11 @@ class AccountUnlinkWindow(ba.Window):
|
|||
margin=0,
|
||||
left_border=10)
|
||||
|
||||
our_login_id = _ba.get_public_login_id()
|
||||
our_login_id = ba.internal.get_public_login_id()
|
||||
if our_login_id is None:
|
||||
entries = []
|
||||
else:
|
||||
account_infos = _ba.get_v1_account_misc_read_val_2(
|
||||
account_infos = ba.internal.get_v1_account_misc_read_val_2(
|
||||
'linkedAccounts2', [])
|
||||
entries = [{
|
||||
'name': ai['d'],
|
||||
|
|
@ -108,12 +108,12 @@ class AccountUnlinkWindow(ba.Window):
|
|||
ba.screenmessage(ba.Lstr(resource='pleaseWaitText',
|
||||
fallback_resource='requestingText'),
|
||||
color=(0, 1, 0))
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'ACCOUNT_UNLINK_REQUEST',
|
||||
'accountID': entry['id'],
|
||||
'expire_time': time.time() + 5
|
||||
})
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
ba.containerwidget(edit=self._root_widget,
|
||||
transition=self._transition_out)
|
||||
|
||||
|
|
|
|||
7
dist/ba_data/python/bastd/ui/account/v2.py
vendored
7
dist/ba_data/python/bastd/ui/account/v2.py
vendored
|
|
@ -8,7 +8,7 @@ import logging
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
import _ba
|
||||
import ba.internal
|
||||
|
||||
from efro.error import CommunicationError
|
||||
import bacommon.cloud
|
||||
|
|
@ -81,7 +81,8 @@ class V2SignInWindow(ba.Window):
|
|||
return
|
||||
|
||||
# Show link(s) the user can use to log in.
|
||||
address = _ba.get_master_server_address(version=2) + response.url
|
||||
address = ba.internal.get_master_server_address(
|
||||
version=2) + response.url
|
||||
address_pretty = address.removeprefix('https://')
|
||||
|
||||
ba.textwidget(
|
||||
|
|
@ -123,7 +124,7 @@ class V2SignInWindow(ba.Window):
|
|||
position=(self._width * 0.5 - qr_size * 0.5,
|
||||
self._height * 0.36 + qroffs - qr_size * 0.5),
|
||||
size=(qr_size, qr_size),
|
||||
texture=_ba.get_qrcode_texture(address))
|
||||
texture=ba.internal.get_qrcode_texture(address))
|
||||
|
||||
# Start querying for results.
|
||||
self._proxyid = response.proxyid
|
||||
|
|
|
|||
27
dist/ba_data/python/bastd/ui/account/viewer.py
vendored
27
dist/ba_data/python/bastd/ui/account/viewer.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.ui import popup
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -91,8 +91,9 @@ class AccountViewerWindow(popup.PopupWindow):
|
|||
|
||||
# In cases where the user most likely has a browser/email, lets
|
||||
# offer a 'report this user' button.
|
||||
if (is_browser_likely_available() and _ba.get_v1_account_misc_read_val(
|
||||
'showAccountExtrasMenu', False)):
|
||||
if (is_browser_likely_available()
|
||||
and ba.internal.get_v1_account_misc_read_val(
|
||||
'showAccountExtrasMenu', False)):
|
||||
|
||||
self._extras_menu_button = ba.buttonwidget(
|
||||
parent=self.root_widget,
|
||||
|
|
@ -154,11 +155,11 @@ class AccountViewerWindow(popup.PopupWindow):
|
|||
delegate=self)
|
||||
|
||||
def _on_ban_press(self) -> None:
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'BAN_ACCOUNT',
|
||||
'account': self._account_id
|
||||
})
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
||||
def _on_report_press(self) -> None:
|
||||
from bastd.ui import report
|
||||
|
|
@ -166,8 +167,8 @@ class AccountViewerWindow(popup.PopupWindow):
|
|||
origin_widget=self._extras_menu_button)
|
||||
|
||||
def _on_more_press(self) -> None:
|
||||
ba.open_url(_ba.get_master_server_address() + '/highscores?profile=' +
|
||||
self._account_id)
|
||||
ba.open_url(ba.internal.get_master_server_address() +
|
||||
'/highscores?profile=' + self._account_id)
|
||||
|
||||
def _on_query_response(self, data: dict[str, Any] | None) -> None:
|
||||
# FIXME: Tidy this up.
|
||||
|
|
@ -197,8 +198,8 @@ class AccountViewerWindow(popup.PopupWindow):
|
|||
ba.print_exception('Error displaying trophies.')
|
||||
account_name_spacing = 15
|
||||
tscale = 0.65
|
||||
ts_height = _ba.get_string_height(trophystr,
|
||||
suppress_warning=True)
|
||||
ts_height = ba.internal.get_string_height(
|
||||
trophystr, suppress_warning=True)
|
||||
sub_width = self._width - 80
|
||||
sub_height = 200 + ts_height * tscale + \
|
||||
account_name_spacing * len(data['accountDisplayStrings'])
|
||||
|
|
@ -321,8 +322,8 @@ class AccountViewerWindow(popup.PopupWindow):
|
|||
('${SUFFIX}', '')]).evaluate()
|
||||
rank_str_width = min(
|
||||
sub_width * maxwidth_scale,
|
||||
_ba.get_string_width(rank_str, suppress_warning=True) *
|
||||
0.55)
|
||||
ba.internal.get_string_width(
|
||||
rank_str, suppress_warning=True) * 0.55)
|
||||
|
||||
# Only tack our suffix on if its at the end and only for
|
||||
# non-diamond leagues.
|
||||
|
|
@ -374,8 +375,8 @@ class AccountViewerWindow(popup.PopupWindow):
|
|||
]).evaluate()
|
||||
rank_str_width = min(
|
||||
sub_width * maxwidth_scale,
|
||||
_ba.get_string_width(rank_str, suppress_warning=True) *
|
||||
0.3)
|
||||
ba.internal.get_string_width(
|
||||
rank_str, suppress_warning=True) * 0.3)
|
||||
|
||||
# Only tack our suffix on if its at the end and only for
|
||||
# non-diamond leagues.
|
||||
|
|
|
|||
39
dist/ba_data/python/bastd/ui/appinvite.py
vendored
39
dist/ba_data/python/bastd/ui/appinvite.py
vendored
|
|
@ -8,8 +8,8 @@ import copy
|
|||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -62,11 +62,11 @@ class AppInviteWindow(ba.Window):
|
|||
'gatherWindow.earnTicketsForRecommendingText'),
|
||||
subs=[('${COUNT}',
|
||||
str(
|
||||
_ba.get_v1_account_misc_read_val(
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
'friendTryTickets', 300))),
|
||||
('${YOU_COUNT}',
|
||||
str(
|
||||
_ba.get_v1_account_misc_read_val(
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
'friendTryAwardTickets', 100)))]))
|
||||
|
||||
or_text = ba.Lstr(resource='orText',
|
||||
|
|
@ -104,14 +104,14 @@ class AppInviteWindow(ba.Window):
|
|||
on_activate_call=ba.WeakCall(self._send_code))
|
||||
|
||||
# kick off a transaction to get our code
|
||||
_ba.add_transaction(
|
||||
ba.internal.add_transaction(
|
||||
{
|
||||
'type': 'FRIEND_PROMO_CODE_REQUEST',
|
||||
'ali': False,
|
||||
'expire_time': time.time() + 20
|
||||
},
|
||||
callback=ba.WeakCall(self._on_code_result))
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
||||
def _on_code_result(self, result: dict[str, Any] | None) -> None:
|
||||
if result is not None:
|
||||
|
|
@ -128,18 +128,18 @@ class AppInviteWindow(ba.Window):
|
|||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
if _ba.get_v1_account_state() == 'signed_in':
|
||||
if ba.internal.get_v1_account_state() == 'signed_in':
|
||||
ba.set_analytics_screen('App Invite UI')
|
||||
_ba.show_app_invite(
|
||||
ba.internal.show_app_invite(
|
||||
ba.Lstr(resource='gatherWindow.appInviteTitleText',
|
||||
subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))
|
||||
]).evaluate(),
|
||||
ba.Lstr(resource='gatherWindow.appInviteMessageText',
|
||||
subs=[
|
||||
('${COUNT}', str(self._data['tickets'])),
|
||||
('${NAME}', _ba.get_v1_account_name().split()[0]),
|
||||
('${APP_NAME}', ba.Lstr(resource='titleText'))
|
||||
]).evaluate(), self._data['code'])
|
||||
subs=[('${COUNT}', str(self._data['tickets'])),
|
||||
('${NAME}',
|
||||
ba.internal.get_v1_account_name().split()[0]),
|
||||
('${APP_NAME}', ba.Lstr(resource='titleText'))
|
||||
]).evaluate(), self._data['code'])
|
||||
else:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
|
||||
|
|
@ -250,13 +250,14 @@ class ShowFriendCodeWindow(ba.Window):
|
|||
|
||||
def _google_invites(self) -> None:
|
||||
ba.set_analytics_screen('App Invite UI')
|
||||
_ba.show_app_invite(
|
||||
ba.internal.show_app_invite(
|
||||
ba.Lstr(resource='gatherWindow.appInviteTitleText',
|
||||
subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))
|
||||
]).evaluate(),
|
||||
ba.Lstr(resource='gatherWindow.appInviteMessageText',
|
||||
subs=[('${COUNT}', str(self._data['tickets'])),
|
||||
('${NAME}', _ba.get_v1_account_name().split()[0]),
|
||||
('${NAME}',
|
||||
ba.internal.get_v1_account_name().split()[0]),
|
||||
('${APP_NAME}', ba.Lstr(resource='titleText'))
|
||||
]).evaluate(), self._data['code'])
|
||||
|
||||
|
|
@ -264,7 +265,7 @@ class ShowFriendCodeWindow(ba.Window):
|
|||
import urllib.parse
|
||||
|
||||
# If somehow we got signed out.
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
ba.screenmessage(ba.Lstr(resource='notSignedInText'),
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
|
|
@ -273,7 +274,7 @@ class ShowFriendCodeWindow(ba.Window):
|
|||
ba.set_analytics_screen('Email Friend Code')
|
||||
subject = (ba.Lstr(resource='gatherWindow.friendHasSentPromoCodeText').
|
||||
evaluate().replace(
|
||||
'${NAME}', _ba.get_v1_account_name()).replace(
|
||||
'${NAME}', ba.internal.get_v1_account_name()).replace(
|
||||
'${APP_NAME}',
|
||||
ba.Lstr(resource='titleText').evaluate()).replace(
|
||||
'${COUNT}', str(self._data['tickets'])))
|
||||
|
|
@ -304,7 +305,7 @@ def handle_app_invites_press(force_code: bool = False) -> None:
|
|||
"""(internal)"""
|
||||
app = ba.app
|
||||
do_app_invites = (app.platform == 'android' and app.subplatform == 'google'
|
||||
and _ba.get_v1_account_misc_read_val(
|
||||
and ba.internal.get_v1_account_misc_read_val(
|
||||
'enableAppInvites', False) and not app.on_tv)
|
||||
if force_code:
|
||||
do_app_invites = False
|
||||
|
|
@ -326,11 +327,11 @@ def handle_app_invites_press(force_code: bool = False) -> None:
|
|||
else:
|
||||
ShowFriendCodeWindow(result)
|
||||
|
||||
_ba.add_transaction(
|
||||
ba.internal.add_transaction(
|
||||
{
|
||||
'type': 'FRIEND_PROMO_CODE_REQUEST',
|
||||
'ali': False,
|
||||
'expire_time': time.time() + 10
|
||||
},
|
||||
callback=handle_result)
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
import math
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.ui import popup
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -156,7 +156,7 @@ class CharacterPicker(popup.PopupWindow):
|
|||
def _on_store_press(self) -> None:
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
from bastd.ui.store.browser import StoreBrowserWindow
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
self._transition_out()
|
||||
|
|
|
|||
8
dist/ba_data/python/bastd/ui/configerror.py
vendored
8
dist/ba_data/python/bastd/ui/configerror.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -29,7 +29,7 @@ class ConfigErrorWindow(ba.Window):
|
|||
h_align='center',
|
||||
v_align='top',
|
||||
scale=0.73,
|
||||
text=(f'Error reading {_ba.appnameupper()} config file'
|
||||
text=(f'Error reading {ba.internal.appnameupper()} config file'
|
||||
':\n\n\nCheck the console'
|
||||
' (press ~ twice) for details.\n\nWould you like to quit and'
|
||||
' try to fix it by hand\nor overwrite it with defaults?\n\n'
|
||||
|
|
@ -58,10 +58,10 @@ class ConfigErrorWindow(ba.Window):
|
|||
|
||||
def _quit(self) -> None:
|
||||
ba.timer(0.001, self._edit_and_quit, timetype=ba.TimeType.REAL)
|
||||
_ba.lock_all_input()
|
||||
ba.internal.lock_all_input()
|
||||
|
||||
def _edit_and_quit(self) -> None:
|
||||
_ba.open_file_externally(self._config_file_path)
|
||||
ba.internal.open_file_externally(self._config_file_path)
|
||||
ba.timer(0.1, ba.quit, timetype=ba.TimeType.REAL)
|
||||
|
||||
def _defaults(self) -> None:
|
||||
|
|
|
|||
15
dist/ba_data/python/bastd/ui/confirm.py
vendored
15
dist/ba_data/python/bastd/ui/confirm.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
|
@ -54,7 +54,7 @@ class ConfirmWindow:
|
|||
size=(width, height),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_minimal_no_back',
|
||||
parent=_ba.get_special_widget('overlay_stack'),
|
||||
parent=ba.internal.get_special_widget('overlay_stack'),
|
||||
scale=(2.1 if uiscale is ba.UIScale.SMALL else
|
||||
1.5 if uiscale is ba.UIScale.MEDIUM else 1.0),
|
||||
scale_origin_stack_offset=scale_origin)
|
||||
|
|
@ -147,12 +147,13 @@ class QuitWindow:
|
|||
origin_widget=origin_widget).root_widget)
|
||||
|
||||
def _fade_and_quit(self) -> None:
|
||||
_ba.fade_screen(False,
|
||||
time=0.2,
|
||||
endcall=lambda: ba.quit(soft=True, back=self._back))
|
||||
_ba.lock_all_input()
|
||||
ba.internal.fade_screen(
|
||||
False,
|
||||
time=0.2,
|
||||
endcall=lambda: ba.quit(soft=True, back=self._back))
|
||||
ba.internal.lock_all_input()
|
||||
|
||||
# Unlock and fade back in shortly.. just in case something goes wrong
|
||||
# (or on android where quit just backs out of our activity and
|
||||
# we may come back)
|
||||
ba.timer(0.3, _ba.unlock_all_input, timetype=ba.TimeType.REAL)
|
||||
ba.timer(0.3, ba.internal.unlock_all_input, timetype=ba.TimeType.REAL)
|
||||
|
|
|
|||
26
dist/ba_data/python/bastd/ui/continues.py
vendored
26
dist/ba_data/python/bastd/ui/continues.py
vendored
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
import weakref
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
|
@ -37,11 +37,14 @@ class ContinuesWindow(ba.Window):
|
|||
txt = (ba.Lstr(
|
||||
resource='continuePurchaseText').evaluate().split('${PRICE}'))
|
||||
t_left = txt[0]
|
||||
t_left_width = _ba.get_string_width(t_left, suppress_warning=True)
|
||||
t_left_width = ba.internal.get_string_width(t_left,
|
||||
suppress_warning=True)
|
||||
t_price = ba.charstr(ba.SpecialChar.TICKET) + str(self._cost)
|
||||
t_price_width = _ba.get_string_width(t_price, suppress_warning=True)
|
||||
t_price_width = ba.internal.get_string_width(t_price,
|
||||
suppress_warning=True)
|
||||
t_right = txt[-1]
|
||||
t_right_width = _ba.get_string_width(t_right, suppress_warning=True)
|
||||
t_right_width = ba.internal.get_string_width(t_right,
|
||||
suppress_warning=True)
|
||||
width_total_half = (t_left_width + t_price_width + t_right_width) * 0.5
|
||||
|
||||
ba.textwidget(parent=self._root_widget,
|
||||
|
|
@ -133,8 +136,15 @@ class ContinuesWindow(ba.Window):
|
|||
ba.WeakCall(self._tick),
|
||||
repeat=True,
|
||||
timetype=ba.TimeType.REAL)
|
||||
|
||||
# If there is foreground activity, suspend it.
|
||||
ba.app.pause()
|
||||
self._tick()
|
||||
|
||||
def __del__(self) -> None:
|
||||
# If there is suspended foreground activity, resume it.
|
||||
ba.app.resume()
|
||||
|
||||
def _tick(self) -> None:
|
||||
# if our target activity is gone or has ended, go away
|
||||
activity = self._activity()
|
||||
|
|
@ -142,9 +152,9 @@ class ContinuesWindow(ba.Window):
|
|||
self._on_cancel()
|
||||
return
|
||||
|
||||
if _ba.get_v1_account_state() == 'signed_in':
|
||||
if ba.internal.get_v1_account_state() == 'signed_in':
|
||||
sval = (ba.charstr(ba.SpecialChar.TICKET) +
|
||||
str(_ba.get_v1_account_ticket_count()))
|
||||
str(ba.internal.get_v1_account_ticket_count()))
|
||||
else:
|
||||
sval = '?'
|
||||
if self._tickets_text is not None:
|
||||
|
|
@ -176,14 +186,14 @@ class ContinuesWindow(ba.Window):
|
|||
ba.playsound(ba.getsound('error'))
|
||||
else:
|
||||
# If somehow we got signed out...
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
ba.screenmessage(ba.Lstr(resource='notSignedInText'),
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
# If it appears we don't have enough tickets, offer to buy more.
|
||||
tickets = _ba.get_v1_account_ticket_count()
|
||||
tickets = ba.internal.get_v1_account_ticket_count()
|
||||
if tickets < self._cost:
|
||||
# FIXME: Should we start the timer back up again after?
|
||||
self._counting_down = False
|
||||
|
|
|
|||
58
dist/ba_data/python/bastd/ui/coop/browser.py
vendored
58
dist/ba_data/python/bastd/ui/coop/browser.py
vendored
|
|
@ -8,8 +8,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.ui.store.button import StoreButton
|
||||
from bastd.ui.league.rankbutton import LeagueRankButton
|
||||
from bastd.ui.store.browser import StoreBrowserWindow
|
||||
|
|
@ -26,7 +26,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
def _update_corner_button_positions(self) -> None:
|
||||
uiscale = ba.app.ui.uiscale
|
||||
offs = (-55 if uiscale is ba.UIScale.SMALL
|
||||
and _ba.is_party_icon_visible() else 0)
|
||||
and ba.internal.is_party_icon_visible() else 0)
|
||||
if self._league_rank_button is not None:
|
||||
self._league_rank_button.set_position(
|
||||
(self._width - 282 + offs - self._x_inset, self._height - 85 -
|
||||
|
|
@ -54,7 +54,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
|
||||
# Quick note to players that tourneys won't work in ballistica
|
||||
# core builds. (need to split the word so it won't get subbed out)
|
||||
if 'ballistica' + 'core' == _ba.appname():
|
||||
if 'ballistica' + 'core' == ba.internal.appname():
|
||||
ba.timer(1.0,
|
||||
lambda: ba.screenmessage(
|
||||
ba.Lstr(resource='noTournamentsInTestBuildText'),
|
||||
|
|
@ -93,7 +93,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
|
||||
self._tourney_data_up_to_date = False
|
||||
|
||||
self._campaign_difficulty = _ba.get_v1_account_misc_val(
|
||||
self._campaign_difficulty = ba.internal.get_v1_account_misc_val(
|
||||
'campaignDifficulty', 'easy')
|
||||
|
||||
super().__init__(root_widget=ba.containerwidget(
|
||||
|
|
@ -234,7 +234,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
self._subcontainer: ba.Widget | None = None
|
||||
|
||||
# Take note of our account state; we'll refresh later if this changes.
|
||||
self._account_state_num = _ba.get_v1_account_state_num()
|
||||
self._account_state_num = ba.internal.get_v1_account_state_num()
|
||||
|
||||
# Same for fg/bg state.
|
||||
self._fg_state = app.fg_state
|
||||
|
|
@ -252,7 +252,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
# starting point.
|
||||
if (app.accounts_v1.account_tournament_list is not None
|
||||
and app.accounts_v1.account_tournament_list[0]
|
||||
== _ba.get_v1_account_state_num() and all(
|
||||
== ba.internal.get_v1_account_state_num() and all(
|
||||
t_id in app.accounts_v1.tournament_info
|
||||
for t_id in app.accounts_v1.account_tournament_list[1])):
|
||||
tourney_data = [
|
||||
|
|
@ -300,7 +300,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
self._tourney_data_up_to_date = False
|
||||
|
||||
# If our account state has changed, do a full request.
|
||||
account_state_num = _ba.get_v1_account_state_num()
|
||||
account_state_num = ba.internal.get_v1_account_state_num()
|
||||
if account_state_num != self._account_state_num:
|
||||
self._account_state_num = account_state_num
|
||||
self._save_state()
|
||||
|
|
@ -324,7 +324,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
self._fg_state = ba.app.fg_state
|
||||
self._last_tournament_query_time = cur_time
|
||||
self._doing_tournament_query = True
|
||||
_ba.tournament_query(
|
||||
ba.internal.tournament_query(
|
||||
args={
|
||||
'source': 'coop window refresh',
|
||||
'numScores': 1
|
||||
|
|
@ -333,7 +333,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
)
|
||||
|
||||
# Decrement time on our tournament buttons.
|
||||
ads_enabled = _ba.have_incentivized_ad()
|
||||
ads_enabled = ba.internal.have_incentivized_ad()
|
||||
for tbtn in self._tournament_buttons:
|
||||
tbtn.time_remaining = max(0, tbtn.time_remaining - 1)
|
||||
if tbtn.time_remaining_value_text is not None:
|
||||
|
|
@ -346,7 +346,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
and self._tourney_data_up_to_date) else '-')
|
||||
|
||||
# Also adjust the ad icon visibility.
|
||||
if tbtn.allow_ads and _ba.has_video_ads():
|
||||
if tbtn.allow_ads and ba.internal.has_video_ads():
|
||||
ba.imagewidget(edit=tbtn.entry_fee_ad_image,
|
||||
opacity=1.0 if ads_enabled else 0.25)
|
||||
ba.textwidget(edit=tbtn.entry_fee_text_remaining,
|
||||
|
|
@ -395,11 +395,9 @@ class CoopBrowserWindow(ba.Window):
|
|||
accounts.cache_tournament_info(tournament_data)
|
||||
|
||||
# Also cache the current tourney list/order for this account.
|
||||
accounts.account_tournament_list = (_ba.get_v1_account_state_num(),
|
||||
[
|
||||
e['tournamentID']
|
||||
for e in tournament_data
|
||||
])
|
||||
accounts.account_tournament_list = (
|
||||
ba.internal.get_v1_account_state_num(),
|
||||
[e['tournamentID'] for e in tournament_data])
|
||||
|
||||
self._doing_tournament_query = False
|
||||
self._update_for_data(tournament_data)
|
||||
|
|
@ -417,7 +415,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
print('ERROR: invalid campaign difficulty:', difficulty)
|
||||
difficulty = 'easy'
|
||||
self._campaign_difficulty = difficulty
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'SET_MISC_VAL',
|
||||
'name': 'campaignDifficulty',
|
||||
'value': difficulty
|
||||
|
|
@ -638,7 +636,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
# FIXME shouldn't use hard-coded strings here.
|
||||
txt = ba.Lstr(resource='tournamentsText',
|
||||
fallback_resource='tournamentText').evaluate()
|
||||
t_width = _ba.get_string_width(txt, suppress_warning=True)
|
||||
t_width = ba.internal.get_string_width(txt, suppress_warning=True)
|
||||
ba.textwidget(parent=w_parent,
|
||||
position=(h_base + 27, v + 30),
|
||||
size=(0, 0),
|
||||
|
|
@ -668,7 +666,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
# no tournaments).
|
||||
if self._tournament_button_count == 0:
|
||||
unavailable_text = ba.Lstr(resource='unavailableText')
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
unavailable_text = ba.Lstr(
|
||||
value='${A} (${B})',
|
||||
subs=[('${A}', unavailable_text),
|
||||
|
|
@ -744,8 +742,9 @@ class CoopBrowserWindow(ba.Window):
|
|||
]
|
||||
|
||||
# Show easter-egg-hunt either if its easter or we own it.
|
||||
if _ba.get_v1_account_misc_read_val(
|
||||
'easter', False) or _ba.get_purchased('games.easter_egg_hunt'):
|
||||
if ba.internal.get_v1_account_misc_read_val(
|
||||
'easter',
|
||||
False) or ba.internal.get_purchased('games.easter_egg_hunt'):
|
||||
items = [
|
||||
'Challenges:Easter Egg Hunt',
|
||||
'Challenges:Pro Easter Egg Hunt',
|
||||
|
|
@ -838,7 +837,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
from bastd.ui.league.rankwindow import LeagueRankWindow
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
self._save_state()
|
||||
|
|
@ -855,7 +854,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
self._save_state()
|
||||
|
|
@ -893,7 +892,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
if game in ('Challenges:Infinite Runaround',
|
||||
'Challenges:Infinite Onslaught'
|
||||
) and not ba.app.accounts_v1.have_pro():
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
else:
|
||||
PurchaseWindow(items=['pro'])
|
||||
|
|
@ -920,8 +919,8 @@ class CoopBrowserWindow(ba.Window):
|
|||
required_purchase = None
|
||||
|
||||
if (required_purchase is not None
|
||||
and not _ba.get_purchased(required_purchase)):
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
and not ba.internal.get_purchased(required_purchase)):
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
else:
|
||||
PurchaseWindow(items=[required_purchase])
|
||||
|
|
@ -937,10 +936,17 @@ class CoopBrowserWindow(ba.Window):
|
|||
from bastd.ui.account import show_sign_in_prompt
|
||||
from bastd.ui.tournamententry import TournamentEntryWindow
|
||||
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
|
||||
if ba.internal.workspaces_in_use():
|
||||
ba.screenmessage(
|
||||
ba.Lstr(resource='tournamentsDisabledWorkspaceText'),
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
if not self._tourney_data_up_to_date:
|
||||
ba.screenmessage(ba.Lstr(resource='tournamentCheckingStateText'),
|
||||
color=(1, 1, 0))
|
||||
|
|
|
|||
15
dist/ba_data/python/bastd/ui/coop/gamebutton.py
vendored
15
dist/ba_data/python/bastd/ui/coop/gamebutton.py
vendored
|
|
@ -7,7 +7,6 @@ from __future__ import annotations
|
|||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -200,17 +199,17 @@ class GameButton:
|
|||
'Challenges:Infinite Onslaught')
|
||||
and not ba.app.accounts_v1.have_pro())
|
||||
or (game in ('Challenges:Meteor Shower', )
|
||||
and not _ba.get_purchased('games.meteor_shower'))
|
||||
and not ba.internal.get_purchased('games.meteor_shower'))
|
||||
or (game in ('Challenges:Target Practice',
|
||||
'Challenges:Target Practice B')
|
||||
and not _ba.get_purchased('games.target_practice'))
|
||||
and not ba.internal.get_purchased('games.target_practice'))
|
||||
or (game in ('Challenges:Ninja Fight', )
|
||||
and not _ba.get_purchased('games.ninja_fight'))
|
||||
and not ba.internal.get_purchased('games.ninja_fight'))
|
||||
or (game in ('Challenges:Pro Ninja Fight', )
|
||||
and not _ba.get_purchased('games.ninja_fight'))
|
||||
or (game in ('Challenges:Easter Egg Hunt',
|
||||
'Challenges:Pro Easter Egg Hunt')
|
||||
and not _ba.get_purchased('games.easter_egg_hunt'))):
|
||||
and not ba.internal.get_purchased('games.ninja_fight')) or
|
||||
(game in ('Challenges:Easter Egg Hunt',
|
||||
'Challenges:Pro Easter Egg Hunt')
|
||||
and not ba.internal.get_purchased('games.easter_egg_hunt'))):
|
||||
unlocked = False
|
||||
|
||||
# Let's tint levels a slightly different color when easy mode
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from typing import TYPE_CHECKING
|
|||
import copy
|
||||
|
||||
import ba
|
||||
import _ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
|
@ -499,7 +499,7 @@ class TournamentButton:
|
|||
self.allow_ads = allow_ads = entry['allowAds']
|
||||
|
||||
final_fee: int | None = (None if fee_var is None else
|
||||
_ba.get_v1_account_misc_read_val(
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
fee_var, '?'))
|
||||
|
||||
final_fee_str: str | ba.Lstr
|
||||
|
|
@ -519,8 +519,8 @@ class TournamentButton:
|
|||
|
||||
# Now, if this fee allows ads and we support video ads, show
|
||||
# the 'or ad' version.
|
||||
if allow_ads and _ba.has_video_ads():
|
||||
ads_enabled = _ba.have_incentivized_ad()
|
||||
if allow_ads and ba.internal.has_video_ads():
|
||||
ads_enabled = ba.internal.have_incentivized_ad()
|
||||
ba.imagewidget(edit=self.entry_fee_ad_image,
|
||||
opacity=1.0 if ads_enabled else 0.25)
|
||||
or_text = ba.Lstr(resource='orText',
|
||||
|
|
|
|||
21
dist/ba_data/python/bastd/ui/creditslist.py
vendored
21
dist/ba_data/python/bastd/ui/creditslist.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Sequence
|
||||
|
|
@ -91,17 +91,19 @@ class CreditsListWindow(ba.Window):
|
|||
capture_arrows=True)
|
||||
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=scroll,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
ba.widget(
|
||||
edit=scroll,
|
||||
right_widget=ba.internal.get_special_widget('party_button'))
|
||||
if uiscale is ba.UIScale.SMALL:
|
||||
ba.widget(edit=scroll,
|
||||
left_widget=_ba.get_special_widget('back_button'))
|
||||
ba.widget(
|
||||
edit=scroll,
|
||||
left_widget=ba.internal.get_special_widget('back_button'))
|
||||
|
||||
def _format_names(names2: Sequence[str], inset: float) -> str:
|
||||
sval = ''
|
||||
# measure a series since there's overlaps and stuff..
|
||||
space_width = _ba.get_string_width(' ' * 10,
|
||||
suppress_warning=True) / 10.0
|
||||
space_width = ba.internal.get_string_width(
|
||||
' ' * 10, suppress_warning=True) / 10.0
|
||||
spacing = 330.0
|
||||
col1 = inset
|
||||
col2 = col1 + spacing
|
||||
|
|
@ -124,7 +126,8 @@ class CreditsListWindow(ba.Window):
|
|||
spacingstr = ' ' * int((target - line_width) / space_width)
|
||||
nline += spacingstr
|
||||
nline += name
|
||||
line_width = _ba.get_string_width(nline, suppress_warning=True)
|
||||
line_width = ba.internal.get_string_width(
|
||||
nline, suppress_warning=True)
|
||||
if nline != '':
|
||||
sval += nline + '\n'
|
||||
return sval
|
||||
|
|
@ -236,7 +239,7 @@ class CreditsListWindow(ba.Window):
|
|||
'${NAME}', 'the Khronos Group') + '\n'
|
||||
'\n'
|
||||
' '
|
||||
' www.froemling.net\n')
|
||||
' www.ballistica.net\n')
|
||||
|
||||
txt = credits_text
|
||||
lines = txt.splitlines()
|
||||
|
|
|
|||
3
dist/ba_data/python/bastd/ui/debug.py
vendored
3
dist/ba_data/python/bastd/ui/debug.py
vendored
|
|
@ -15,11 +15,12 @@ if TYPE_CHECKING:
|
|||
class DebugWindow(ba.Window):
|
||||
"""Window for debugging internal values."""
|
||||
|
||||
def __init__(self, transition: str = 'in_right'):
|
||||
def __init__(self, transition: str | None = 'in_right'):
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui import popup
|
||||
|
||||
ba.app.ui.set_main_menu_location('Benchmarks & Stress Tests')
|
||||
uiscale = ba.app.ui.uiscale
|
||||
self._width = width = 580
|
||||
self._height = height = (350 if uiscale is ba.UIScale.SMALL else
|
||||
|
|
|
|||
6
dist/ba_data/python/bastd/ui/feedback.py
vendored
6
dist/ba_data/python/bastd/ui/feedback.py
vendored
|
|
@ -7,6 +7,7 @@ from __future__ import annotations
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -54,13 +55,12 @@ def ask_for_rating() -> ba.Widget | None:
|
|||
v_align='center')
|
||||
|
||||
def do_rating() -> None:
|
||||
import _ba
|
||||
if platform == 'android':
|
||||
appname = _ba.appname()
|
||||
appname = ba.internal.appname()
|
||||
if subplatform == 'google':
|
||||
url = f'market://details?id=net.froemling.{appname}'
|
||||
else:
|
||||
url = 'market://details?id=net.froemling.{appname}cb'
|
||||
url = f'market://details?id=net.froemling.{appname}cb'
|
||||
else:
|
||||
url = 'macappstore://itunes.apple.com/app/id416482767?ls=1&mt=12'
|
||||
|
||||
|
|
|
|||
4
dist/ba_data/python/bastd/ui/fileselector.py
vendored
4
dist/ba_data/python/bastd/ui/fileselector.py
vendored
|
|
@ -9,8 +9,8 @@ import threading
|
|||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable, Sequence
|
||||
|
|
@ -242,7 +242,7 @@ class FileSelectorWindow(ba.Window):
|
|||
max_str_width = 300.0
|
||||
str_width = min(
|
||||
max_str_width,
|
||||
_ba.get_string_width(folder_name, suppress_warning=True))
|
||||
ba.internal.get_string_width(folder_name, suppress_warning=True))
|
||||
ba.textwidget(edit=self._path_text,
|
||||
text=folder_name,
|
||||
maxwidth=max_str_width)
|
||||
|
|
|
|||
19
dist/ba_data/python/bastd/ui/gather/__init__.py
vendored
19
dist/ba_data/python/bastd/ui/gather/__init__.py
vendored
|
|
@ -8,8 +8,8 @@ import weakref
|
|||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.ui.tabs import TabRow
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -88,7 +88,7 @@ class GatherWindow(ba.Window):
|
|||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
ba.app.ui.set_main_menu_location('Gather')
|
||||
_ba.set_party_icon_always_visible(True)
|
||||
ba.internal.set_party_icon_always_visible(True)
|
||||
uiscale = ba.app.ui.uiscale
|
||||
self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040
|
||||
x_offs = 100 if uiscale is ba.UIScale.SMALL else 0
|
||||
|
|
@ -151,7 +151,8 @@ class GatherWindow(ba.Window):
|
|||
tabdefs: list[tuple[GatherWindow.TabID, ba.Lstr]] = [
|
||||
(self.TabID.ABOUT, ba.Lstr(resource=self._r + '.aboutText'))
|
||||
]
|
||||
if _ba.get_v1_account_misc_read_val('enablePublicParties', True):
|
||||
if ba.internal.get_v1_account_misc_read_val('enablePublicParties',
|
||||
True):
|
||||
tabdefs.append((self.TabID.INTERNET,
|
||||
ba.Lstr(resource=self._r + '.publicText')))
|
||||
tabdefs.append(
|
||||
|
|
@ -186,11 +187,13 @@ class GatherWindow(ba.Window):
|
|||
self._tabs[tab_id] = tabtype(self)
|
||||
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=self._tab_row.tabs[tabdefs[-1][0]].button,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
ba.widget(
|
||||
edit=self._tab_row.tabs[tabdefs[-1][0]].button,
|
||||
right_widget=ba.internal.get_special_widget('party_button'))
|
||||
if uiscale is ba.UIScale.SMALL:
|
||||
ba.widget(edit=self._tab_row.tabs[tabdefs[0][0]].button,
|
||||
left_widget=_ba.get_special_widget('back_button'))
|
||||
ba.widget(
|
||||
edit=self._tab_row.tabs[tabdefs[0][0]].button,
|
||||
left_widget=ba.internal.get_special_widget('back_button'))
|
||||
|
||||
self._scroll_width = self._width - scroll_buffer_h
|
||||
self._scroll_height = self._height - 180.0 + tabs_top_extra
|
||||
|
|
@ -214,7 +217,7 @@ class GatherWindow(ba.Window):
|
|||
self._restore_state()
|
||||
|
||||
def __del__(self) -> None:
|
||||
_ba.set_party_icon_always_visible(False)
|
||||
ba.internal.set_party_icon_always_visible(False)
|
||||
|
||||
def playlist_select(self, origin_widget: ba.Widget) -> None:
|
||||
"""Called by the private-hosting tab to select a playlist."""
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from __future__ import annotations
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
import _ba
|
||||
import ba.internal
|
||||
from bastd.ui.gather import GatherTab
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -51,8 +51,8 @@ class AboutGatherTab(GatherTab):
|
|||
include_invite = True
|
||||
msc_scale = 1.1
|
||||
c_height_2 = min(region_height, string_height * msc_scale + 100)
|
||||
try_tickets = _ba.get_v1_account_misc_read_val('friendTryTickets',
|
||||
None)
|
||||
try_tickets = ba.internal.get_v1_account_misc_read_val(
|
||||
'friendTryTickets', None)
|
||||
if try_tickets is None:
|
||||
include_invite = False
|
||||
self._container = ba.containerwidget(
|
||||
|
|
@ -106,7 +106,7 @@ class AboutGatherTab(GatherTab):
|
|||
def _invite_to_try_press(self) -> None:
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
from bastd.ui.appinvite import handle_app_invites_press
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
handle_app_invites_press()
|
||||
|
|
|
|||
20
dist/ba_data/python/bastd/ui/gather/manualtab.py
vendored
20
dist/ba_data/python/bastd/ui/gather/manualtab.py
vendored
|
|
@ -11,8 +11,8 @@ from enum import Enum
|
|||
from dataclasses import dataclass
|
||||
from bastd.ui.gather import GatherTab
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
|
@ -341,8 +341,9 @@ class ManualGatherTab(GatherTab):
|
|||
label=ba.Lstr(resource='gatherWindow.manualConnectText'),
|
||||
autoselect=True)
|
||||
if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn1,
|
||||
left_widget=_ba.get_special_widget('back_button'))
|
||||
ba.widget(
|
||||
edit=btn1,
|
||||
left_widget=ba.internal.get_special_widget('back_button'))
|
||||
btnv -= b_height + b_space_extra
|
||||
ba.buttonwidget(parent=self._container,
|
||||
size=(b_width, b_height),
|
||||
|
|
@ -686,7 +687,7 @@ class ManualGatherTab(GatherTab):
|
|||
config = ba.app.config
|
||||
config['Last Manual Party Connect Address'] = resolved_address
|
||||
config.commit()
|
||||
_ba.connect_to_party(resolved_address, port=port)
|
||||
ba.internal.connect_to_party(resolved_address, port=port)
|
||||
|
||||
def _run_addr_fetch(self) -> None:
|
||||
try:
|
||||
|
|
@ -894,9 +895,12 @@ class ManualGatherTab(GatherTab):
|
|||
if t_accessible_extra:
|
||||
ba.textwidget(
|
||||
edit=t_accessible_extra,
|
||||
text=ba.Lstr(resource='gatherWindow.'
|
||||
'manualRouterForwardingText',
|
||||
subs=[('${PORT}',
|
||||
str(_ba.get_game_port()))]),
|
||||
text=ba.Lstr(
|
||||
resource='gatherWindow.'
|
||||
'manualRouterForwardingText',
|
||||
subs=[
|
||||
('${PORT}', str(ba.internal.get_game_port())),
|
||||
],
|
||||
),
|
||||
color=color_bad,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import weakref
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
import _ba
|
||||
import ba.internal
|
||||
from bastd.ui.gather import GatherTab
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -42,13 +42,13 @@ class NetScanner:
|
|||
ba.timer(0.25, ba.WeakCall(self.update), timetype=ba.TimeType.REAL)
|
||||
|
||||
def __del__(self) -> None:
|
||||
_ba.end_host_scanning()
|
||||
ba.internal.end_host_scanning()
|
||||
|
||||
def _on_select(self, host: dict[str, Any]) -> None:
|
||||
self._last_selected_host = host
|
||||
|
||||
def _on_activate(self, host: dict[str, Any]) -> None:
|
||||
_ba.connect_to_party(host['address'])
|
||||
ba.internal.connect_to_party(host['address'])
|
||||
|
||||
def update(self) -> None:
|
||||
"""(internal)"""
|
||||
|
|
@ -65,7 +65,7 @@ class NetScanner:
|
|||
|
||||
# Grab this now this since adding widgets will change it.
|
||||
last_selected_host = self._last_selected_host
|
||||
hosts = _ba.host_scan_cycle()
|
||||
hosts = ba.internal.host_scan_cycle()
|
||||
for i, host in enumerate(hosts):
|
||||
txt3 = ba.textwidget(parent=self._columnwidget,
|
||||
size=(self._width / t_scale, 30),
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@ from enum import Enum
|
|||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
import ba
|
||||
import _ba
|
||||
from efro.dataclassio import dataclass_from_dict, dataclass_to_dict
|
||||
from bacommon.net import (PrivateHostingState, PrivateHostingConfig,
|
||||
PrivatePartyConnectResult)
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.ui.gather import GatherTab
|
||||
from bastd.ui import getcurrency
|
||||
|
||||
|
|
@ -184,7 +184,9 @@ class PrivateGatherTab(GatherTab):
|
|||
if playlist is None:
|
||||
playlist = pvars.get_default_list_call()
|
||||
|
||||
hcfg.playlist = filter_playlist(playlist, sessiontype)
|
||||
hcfg.playlist = filter_playlist(playlist,
|
||||
sessiontype,
|
||||
name=playlist_name)
|
||||
|
||||
randomize = cfg.get(f'{pvars.config_name} Playlist Randomize')
|
||||
if not isinstance(randomize, bool):
|
||||
|
|
@ -225,7 +227,7 @@ class PrivateGatherTab(GatherTab):
|
|||
def _update_currency_ui(self) -> None:
|
||||
# Keep currency count up to date if applicable.
|
||||
try:
|
||||
t_str = str(_ba.get_v1_account_ticket_count())
|
||||
t_str = str(ba.internal.get_v1_account_ticket_count())
|
||||
except Exception:
|
||||
t_str = '?'
|
||||
if self._get_tickets_button:
|
||||
|
|
@ -245,7 +247,7 @@ class PrivateGatherTab(GatherTab):
|
|||
if self._state.sub_tab is SubTabType.HOST:
|
||||
|
||||
# If we're not signed in, just refresh to show that.
|
||||
if (_ba.get_v1_account_state() != 'signed_in'
|
||||
if (ba.internal.get_v1_account_state() != 'signed_in'
|
||||
and self._showing_not_signed_in_screen):
|
||||
self._refresh_sub_tab()
|
||||
else:
|
||||
|
|
@ -254,8 +256,8 @@ class PrivateGatherTab(GatherTab):
|
|||
if (self._last_hosting_state_query_time is None
|
||||
or now - self._last_hosting_state_query_time > 15.0):
|
||||
self._debug_server_comm('querying private party state')
|
||||
if _ba.get_v1_account_state() == 'signed_in':
|
||||
_ba.add_transaction(
|
||||
if ba.internal.get_v1_account_state() == 'signed_in':
|
||||
ba.internal.add_transaction(
|
||||
{
|
||||
'type': 'PRIVATE_PARTY_QUERY',
|
||||
'expire_time': time.time() + 20,
|
||||
|
|
@ -263,7 +265,7 @@ class PrivateGatherTab(GatherTab):
|
|||
callback=ba.WeakCall(
|
||||
self._hosting_state_idle_response),
|
||||
)
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
else:
|
||||
self._hosting_state_idle_response(None)
|
||||
self._last_hosting_state_query_time = now
|
||||
|
|
@ -436,7 +438,7 @@ class PrivateGatherTab(GatherTab):
|
|||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
ba.textwidget(parent=self._container,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
|
|
@ -702,7 +704,7 @@ class PrivateGatherTab(GatherTab):
|
|||
btnlabel = ba.Lstr(
|
||||
resource='gatherWindow.hostingUnavailableText')
|
||||
elif self._hostingstate.party_code is None:
|
||||
ticon = _ba.charstr(ba.SpecialChar.TICKET)
|
||||
ticon = ba.internal.charstr(ba.SpecialChar.TICKET)
|
||||
nowtickets = self._hostingstate.tickets_to_host_now
|
||||
if nowtickets > 0:
|
||||
btnlabel = ba.Lstr(
|
||||
|
|
@ -760,7 +762,7 @@ class PrivateGatherTab(GatherTab):
|
|||
self._connect_press_time = now
|
||||
|
||||
self._debug_server_comm('sending private party connect')
|
||||
_ba.add_transaction(
|
||||
ba.internal.add_transaction(
|
||||
{
|
||||
'type': 'PRIVATE_PARTY_CONNECT',
|
||||
'expire_time': time.time() + 20,
|
||||
|
|
@ -768,14 +770,14 @@ class PrivateGatherTab(GatherTab):
|
|||
},
|
||||
callback=ba.WeakCall(self._connect_response),
|
||||
)
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
||||
def _start_stop_button_press(self) -> None:
|
||||
if (self._waiting_for_start_stop_response
|
||||
or self._waiting_for_initial_state):
|
||||
return
|
||||
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
ba.screenmessage(ba.Lstr(resource='notSignedInErrorText'))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
self._refresh_sub_tab()
|
||||
|
|
@ -794,7 +796,7 @@ class PrivateGatherTab(GatherTab):
|
|||
if self._hostingstate.tickets_to_host_now > 0:
|
||||
ticket_count: int | None
|
||||
try:
|
||||
ticket_count = _ba.get_v1_account_ticket_count()
|
||||
ticket_count = ba.internal.get_v1_account_ticket_count()
|
||||
except Exception:
|
||||
# FIXME: should add a ba.NotSignedInError we can use here.
|
||||
ticket_count = None
|
||||
|
|
@ -804,7 +806,7 @@ class PrivateGatherTab(GatherTab):
|
|||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
self._last_action_send_time = time.time()
|
||||
_ba.add_transaction(
|
||||
ba.internal.add_transaction(
|
||||
{
|
||||
'type': 'PRIVATE_PARTY_START',
|
||||
'config': dataclass_to_dict(self._hostingconfig),
|
||||
|
|
@ -812,17 +814,17 @@ class PrivateGatherTab(GatherTab):
|
|||
'expire_time': time.time() + 20,
|
||||
},
|
||||
callback=ba.WeakCall(self._hosting_state_response))
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
||||
else:
|
||||
self._last_action_send_time = time.time()
|
||||
_ba.add_transaction(
|
||||
ba.internal.add_transaction(
|
||||
{
|
||||
'type': 'PRIVATE_PARTY_STOP',
|
||||
'expire_time': time.time() + 20,
|
||||
},
|
||||
callback=ba.WeakCall(self._hosting_state_response))
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
ba.playsound(ba.getsound('click01'))
|
||||
|
||||
self._waiting_for_start_stop_response = True
|
||||
|
|
@ -860,7 +862,7 @@ class PrivateGatherTab(GatherTab):
|
|||
return
|
||||
self._debug_server_comm('got valid connect response')
|
||||
assert cresult.addr is not None and cresult.port is not None
|
||||
_ba.connect_to_party(cresult.addr, port=cresult.port)
|
||||
ba.internal.connect_to_party(cresult.addr, port=cresult.port)
|
||||
except Exception:
|
||||
self._debug_server_comm('got connect response error')
|
||||
ba.playsound(ba.getsound('error'))
|
||||
|
|
|
|||
76
dist/ba_data/python/bastd/ui/gather/publictab.py
vendored
76
dist/ba_data/python/bastd/ui/gather/publictab.py
vendored
|
|
@ -12,8 +12,8 @@ from enum import Enum
|
|||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.ui.gather import GatherTab
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -88,8 +88,8 @@ class UIRow:
|
|||
if party.clean_display_index == index:
|
||||
return
|
||||
|
||||
ping_good = _ba.get_v1_account_misc_read_val('pingGood', 100)
|
||||
ping_med = _ba.get_v1_account_misc_read_val('pingMed', 500)
|
||||
ping_good = ba.internal.get_v1_account_misc_read_val('pingGood', 100)
|
||||
ping_med = ba.internal.get_v1_account_misc_read_val('pingMed', 500)
|
||||
|
||||
self._clear()
|
||||
hpos = 20
|
||||
|
|
@ -122,8 +122,8 @@ class UIRow:
|
|||
if party.stats_addr:
|
||||
url = party.stats_addr.replace(
|
||||
'${ACCOUNT}',
|
||||
_ba.get_v1_account_misc_read_val_2('resolvedAccountID',
|
||||
'UNKNOWN'))
|
||||
ba.internal.get_v1_account_misc_read_val_2(
|
||||
'resolvedAccountID', 'UNKNOWN'))
|
||||
self._stats_button = ba.buttonwidget(
|
||||
color=(0.3, 0.6, 0.94),
|
||||
textcolor=(1.0, 1.0, 1.0),
|
||||
|
|
@ -582,7 +582,7 @@ class PublicGatherTab(GatherTab):
|
|||
c_height = region_height - 20
|
||||
v = c_height - 35
|
||||
v -= 25
|
||||
is_public_enabled = _ba.get_public_party_enabled()
|
||||
is_public_enabled = ba.internal.get_public_party_enabled()
|
||||
v -= 30
|
||||
|
||||
ba.textwidget(
|
||||
|
|
@ -643,7 +643,7 @@ class PublicGatherTab(GatherTab):
|
|||
scale=1.2,
|
||||
color=(1, 1, 1),
|
||||
position=(240, v - 9),
|
||||
text=str(_ba.get_public_party_max_size()))
|
||||
text=str(ba.internal.get_public_party_max_size()))
|
||||
btn1 = self._host_max_party_size_minus_button = (ba.buttonwidget(
|
||||
parent=self._container,
|
||||
size=(40, 40),
|
||||
|
|
@ -711,7 +711,7 @@ class PublicGatherTab(GatherTab):
|
|||
|
||||
# If public sharing is already on,
|
||||
# launch a status-check immediately.
|
||||
if _ba.get_public_party_enabled():
|
||||
if ba.internal.get_public_party_enabled():
|
||||
self._do_status_check()
|
||||
|
||||
def _on_public_party_query_result(self,
|
||||
|
|
@ -793,7 +793,7 @@ class PublicGatherTab(GatherTab):
|
|||
self._process_pending_party_infos()
|
||||
|
||||
# Anytime we sign in/out, make sure we refresh our list.
|
||||
signed_in = _ba.get_v1_account_state() == 'signed_in'
|
||||
signed_in = ba.internal.get_v1_account_state() == 'signed_in'
|
||||
if self._signed_in != signed_in:
|
||||
self._signed_in = signed_in
|
||||
self._party_lists_dirty = True
|
||||
|
|
@ -806,7 +806,7 @@ class PublicGatherTab(GatherTab):
|
|||
text = self._host_name_text
|
||||
if text:
|
||||
name = cast(str, ba.textwidget(query=self._host_name_text))
|
||||
_ba.set_public_party_name(name)
|
||||
ba.internal.set_public_party_name(name)
|
||||
|
||||
# Update status text.
|
||||
status_text = self._join_status_text
|
||||
|
|
@ -986,7 +986,7 @@ class PublicGatherTab(GatherTab):
|
|||
p[1].index))
|
||||
|
||||
# If signed out or errored, show no parties.
|
||||
if (_ba.get_v1_account_state() != 'signed_in'
|
||||
if (ba.internal.get_v1_account_state() != 'signed_in'
|
||||
or not self._have_valid_server_list):
|
||||
self._parties_displayed = {}
|
||||
else:
|
||||
|
|
@ -1022,20 +1022,21 @@ class PublicGatherTab(GatherTab):
|
|||
|
||||
# Fire off a new public-party query periodically.
|
||||
if (self._last_server_list_query_time is None
|
||||
or now - self._last_server_list_query_time > 0.001 *
|
||||
_ba.get_v1_account_misc_read_val('pubPartyRefreshMS', 10000)):
|
||||
or now - self._last_server_list_query_time >
|
||||
0.001 * ba.internal.get_v1_account_misc_read_val(
|
||||
'pubPartyRefreshMS', 10000)):
|
||||
self._last_server_list_query_time = now
|
||||
if DEBUG_SERVER_COMMUNICATION:
|
||||
print('REQUESTING SERVER LIST')
|
||||
if _ba.get_v1_account_state() == 'signed_in':
|
||||
_ba.add_transaction(
|
||||
if ba.internal.get_v1_account_state() == 'signed_in':
|
||||
ba.internal.add_transaction(
|
||||
{
|
||||
'type': 'PUBLIC_PARTY_QUERY',
|
||||
'proto': ba.app.protocol_version,
|
||||
'lang': ba.app.lang.language
|
||||
},
|
||||
callback=ba.WeakCall(self._on_public_party_query_result))
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
else:
|
||||
self._on_public_party_query_result(None)
|
||||
|
||||
|
|
@ -1128,15 +1129,18 @@ class PublicGatherTab(GatherTab):
|
|||
edit=text,
|
||||
text=ba.Lstr(
|
||||
value='${A}\n${B}${C}',
|
||||
subs=[('${A}',
|
||||
ba.Lstr(resource='gatherWindow.'
|
||||
'partyStatusNotJoinableText')),
|
||||
('${B}',
|
||||
ba.Lstr(resource='gatherWindow.'
|
||||
'manualRouterForwardingText',
|
||||
subs=[('${PORT}',
|
||||
str(_ba.get_game_port()))])),
|
||||
('${C}', ex_line)]),
|
||||
subs=[
|
||||
('${A}',
|
||||
ba.Lstr(resource='gatherWindow.'
|
||||
'partyStatusNotJoinableText')),
|
||||
('${B}',
|
||||
ba.Lstr(resource='gatherWindow.'
|
||||
'manualRouterForwardingText',
|
||||
subs=[
|
||||
('${PORT}',
|
||||
str(ba.internal.get_game_port()))
|
||||
])), ('${C}', ex_line)
|
||||
]),
|
||||
color=(1, 0, 0))
|
||||
else:
|
||||
ba.textwidget(edit=text,
|
||||
|
|
@ -1156,7 +1160,7 @@ class PublicGatherTab(GatherTab):
|
|||
|
||||
def _on_start_advertizing_press(self) -> None:
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
|
||||
|
|
@ -1166,16 +1170,16 @@ class PublicGatherTab(GatherTab):
|
|||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
_ba.set_public_party_name(name)
|
||||
ba.internal.set_public_party_name(name)
|
||||
cfg = ba.app.config
|
||||
cfg['Public Party Name'] = name
|
||||
cfg.commit()
|
||||
ba.playsound(ba.getsound('shieldUp'))
|
||||
_ba.set_public_party_enabled(True)
|
||||
ba.internal.set_public_party_enabled(True)
|
||||
|
||||
# In GUI builds we want to authenticate clients only when hosting
|
||||
# public parties.
|
||||
_ba.set_authenticate_clients(True)
|
||||
ba.internal.set_authenticate_clients(True)
|
||||
|
||||
self._do_status_check()
|
||||
ba.buttonwidget(
|
||||
|
|
@ -1186,11 +1190,11 @@ class PublicGatherTab(GatherTab):
|
|||
on_activate_call=self._on_stop_advertising_press)
|
||||
|
||||
def _on_stop_advertising_press(self) -> None:
|
||||
_ba.set_public_party_enabled(False)
|
||||
ba.internal.set_public_party_enabled(False)
|
||||
|
||||
# In GUI builds we want to authenticate clients only when hosting
|
||||
# public parties.
|
||||
_ba.set_authenticate_clients(False)
|
||||
ba.internal.set_authenticate_clients(False)
|
||||
ba.playsound(ba.getsound('shieldDown'))
|
||||
text = self._host_status_text
|
||||
if text:
|
||||
|
|
@ -1222,7 +1226,7 @@ class PublicGatherTab(GatherTab):
|
|||
now = time.time()
|
||||
last_connect_time = self._last_connect_attempt_time
|
||||
if last_connect_time is None or now - last_connect_time > 2.0:
|
||||
_ba.connect_to_party(address, port=port)
|
||||
ba.internal.connect_to_party(address, port=port)
|
||||
self._last_connect_attempt_time = now
|
||||
|
||||
def set_public_party_selection(self, sel: Selection) -> None:
|
||||
|
|
@ -1233,12 +1237,12 @@ class PublicGatherTab(GatherTab):
|
|||
self._have_user_selected_row = True
|
||||
|
||||
def _on_max_public_party_size_minus_press(self) -> None:
|
||||
val = max(1, _ba.get_public_party_max_size() - 1)
|
||||
_ba.set_public_party_max_size(val)
|
||||
val = max(1, ba.internal.get_public_party_max_size() - 1)
|
||||
ba.internal.set_public_party_max_size(val)
|
||||
ba.textwidget(edit=self._host_max_party_size_value, text=str(val))
|
||||
|
||||
def _on_max_public_party_size_plus_press(self) -> None:
|
||||
val = _ba.get_public_party_max_size()
|
||||
val = ba.internal.get_public_party_max_size()
|
||||
val += 1
|
||||
_ba.set_public_party_max_size(val)
|
||||
ba.internal.set_public_party_max_size(val)
|
||||
ba.textwidget(edit=self._host_max_party_size_value, text=str(val))
|
||||
|
|
|
|||
89
dist/ba_data/python/bastd/ui/getcurrency.py
vendored
89
dist/ba_data/python/bastd/ui/getcurrency.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -176,38 +176,34 @@ class GetCurrencyWindow(ba.Window):
|
|||
|
||||
rsrc = self._r + '.ticketsText'
|
||||
|
||||
c2txt = ba.Lstr(
|
||||
resource=rsrc,
|
||||
subs=[('${COUNT}',
|
||||
str(_ba.get_v1_account_misc_read_val('tickets2Amount',
|
||||
500)))])
|
||||
c3txt = ba.Lstr(
|
||||
resource=rsrc,
|
||||
subs=[
|
||||
('${COUNT}',
|
||||
str(_ba.get_v1_account_misc_read_val('tickets3Amount', 1500)))
|
||||
])
|
||||
c4txt = ba.Lstr(
|
||||
resource=rsrc,
|
||||
subs=[
|
||||
('${COUNT}',
|
||||
str(_ba.get_v1_account_misc_read_val('tickets4Amount', 5000)))
|
||||
])
|
||||
c5txt = ba.Lstr(
|
||||
resource=rsrc,
|
||||
subs=[
|
||||
('${COUNT}',
|
||||
str(_ba.get_v1_account_misc_read_val('tickets5Amount',
|
||||
15000)))
|
||||
])
|
||||
c2txt = ba.Lstr(resource=rsrc,
|
||||
subs=[('${COUNT}',
|
||||
str(
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
'tickets2Amount', 500)))])
|
||||
c3txt = ba.Lstr(resource=rsrc,
|
||||
subs=[('${COUNT}',
|
||||
str(
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
'tickets3Amount', 1500)))])
|
||||
c4txt = ba.Lstr(resource=rsrc,
|
||||
subs=[('${COUNT}',
|
||||
str(
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
'tickets4Amount', 5000)))])
|
||||
c5txt = ba.Lstr(resource=rsrc,
|
||||
subs=[('${COUNT}',
|
||||
str(
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
'tickets5Amount', 15000)))])
|
||||
|
||||
h = 110.0
|
||||
|
||||
# enable buttons if we have prices..
|
||||
tickets2_price = _ba.get_price('tickets2')
|
||||
tickets3_price = _ba.get_price('tickets3')
|
||||
tickets4_price = _ba.get_price('tickets4')
|
||||
tickets5_price = _ba.get_price('tickets5')
|
||||
tickets2_price = ba.internal.get_price('tickets2')
|
||||
tickets3_price = ba.internal.get_price('tickets3')
|
||||
tickets4_price = ba.internal.get_price('tickets4')
|
||||
tickets5_price = ba.internal.get_price('tickets5')
|
||||
|
||||
# TEMP
|
||||
# tickets1_price = '$0.99'
|
||||
|
|
@ -252,7 +248,7 @@ class GetCurrencyWindow(ba.Window):
|
|||
tex_name='ticketRolls',
|
||||
tex_scale=1.2) # 19.99-ish
|
||||
|
||||
self._enable_ad_button = _ba.has_video_ads()
|
||||
self._enable_ad_button = ba.internal.has_video_ads()
|
||||
h = self._width * 0.5 + 110.0
|
||||
v = self._height - b_size[1] - 115.0
|
||||
|
||||
|
|
@ -263,11 +259,12 @@ class GetCurrencyWindow(ba.Window):
|
|||
'ad',
|
||||
position=(h + h_offs, v),
|
||||
size=b_size_3,
|
||||
label=ba.Lstr(resource=self._r + '.ticketsFromASponsorText',
|
||||
subs=[('${COUNT}',
|
||||
str(
|
||||
_ba.get_v1_account_misc_read_val(
|
||||
'sponsorTickets', 5)))]),
|
||||
label=ba.Lstr(
|
||||
resource=self._r + '.ticketsFromASponsorText',
|
||||
subs=[('${COUNT}',
|
||||
str(
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
'sponsorTickets', 5)))]),
|
||||
tex_name='ticketsMore',
|
||||
enabled=self._enable_ad_button,
|
||||
tex_opacity=0.6,
|
||||
|
|
@ -308,7 +305,7 @@ class GetCurrencyWindow(ba.Window):
|
|||
resource='gatherWindow.earnTicketsForRecommendingText',
|
||||
subs=[('${COUNT}',
|
||||
str(
|
||||
_ba.get_v1_account_misc_read_val(
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
'sponsorTickets', 5)))]),
|
||||
tex_name='ticketsMore',
|
||||
enabled=True,
|
||||
|
|
@ -431,22 +428,22 @@ class GetCurrencyWindow(ba.Window):
|
|||
import datetime
|
||||
|
||||
# if we somehow get signed out, just die..
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
self._back()
|
||||
return
|
||||
|
||||
self._ticket_count = _ba.get_v1_account_ticket_count()
|
||||
self._ticket_count = ba.internal.get_v1_account_ticket_count()
|
||||
|
||||
# update our incentivized ad button depending on whether ads are
|
||||
# available
|
||||
if self._ad_button is not None:
|
||||
next_reward_ad_time = _ba.get_v1_account_misc_read_val_2(
|
||||
next_reward_ad_time = ba.internal.get_v1_account_misc_read_val_2(
|
||||
'nextRewardAdTime', None)
|
||||
if next_reward_ad_time is not None:
|
||||
next_reward_ad_time = datetime.datetime.utcfromtimestamp(
|
||||
next_reward_ad_time)
|
||||
now = datetime.datetime.utcnow()
|
||||
if (_ba.have_incentivized_ad() and
|
||||
if (ba.internal.have_incentivized_ad() and
|
||||
(next_reward_ad_time is None or next_reward_ad_time <= now)):
|
||||
self._ad_button_greyed = False
|
||||
ba.buttonwidget(edit=self._ad_button, color=(0.65, 0.5, 0.7))
|
||||
|
|
@ -499,8 +496,8 @@ class GetCurrencyWindow(ba.Window):
|
|||
if ((app.test_build or
|
||||
(app.platform == 'android'
|
||||
and app.subplatform in ['oculus', 'cardboard']))
|
||||
and _ba.get_v1_account_misc_read_val('allowAccountLinking2',
|
||||
False)):
|
||||
and ba.internal.get_v1_account_misc_read_val(
|
||||
'allowAccountLinking2', False)):
|
||||
ba.screenmessage(ba.Lstr(resource=self._r +
|
||||
'.unavailableLinkAccountText'),
|
||||
color=(1, 0.5, 0))
|
||||
|
|
@ -514,7 +511,7 @@ class GetCurrencyWindow(ba.Window):
|
|||
from bastd.ui import appinvite
|
||||
from ba.internal import master_server_get
|
||||
if item == 'app_invite':
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
account.show_sign_in_prompt()
|
||||
return
|
||||
appinvite.handle_app_invites_press()
|
||||
|
|
@ -559,7 +556,7 @@ class GetCurrencyWindow(ba.Window):
|
|||
if item == 'ad':
|
||||
import datetime
|
||||
# if ads are disabled until some time, error..
|
||||
next_reward_ad_time = _ba.get_v1_account_misc_read_val_2(
|
||||
next_reward_ad_time = ba.internal.get_v1_account_misc_read_val_2(
|
||||
'nextRewardAdTime', None)
|
||||
if next_reward_ad_time is not None:
|
||||
next_reward_ad_time = datetime.datetime.utcfromtimestamp(
|
||||
|
|
@ -572,9 +569,9 @@ class GetCurrencyWindow(ba.Window):
|
|||
resource='getTicketsWindow.unavailableTemporarilyText'),
|
||||
color=(1, 0, 0))
|
||||
elif self._enable_ad_button:
|
||||
_ba.app.ads.show_ad('tickets')
|
||||
ba.app.ads.show_ad('tickets')
|
||||
else:
|
||||
_ba.purchase(item)
|
||||
ba.internal.purchase(item)
|
||||
|
||||
def _back(self) -> None:
|
||||
from bastd.ui.store import browser
|
||||
|
|
|
|||
21
dist/ba_data/python/bastd/ui/helpui.py
vendored
21
dist/ba_data/python/bastd/ui/helpui.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -76,8 +76,9 @@ class HelpWindow(ba.Window):
|
|||
capture_arrows=True)
|
||||
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=self._scrollwidget,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
ba.widget(
|
||||
edit=self._scrollwidget,
|
||||
right_widget=ba.internal.get_special_widget('party_button'))
|
||||
ba.containerwidget(edit=self._root_widget,
|
||||
selected_child=self._scrollwidget)
|
||||
|
||||
|
|
@ -86,8 +87,9 @@ class HelpWindow(ba.Window):
|
|||
if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars:
|
||||
ba.containerwidget(edit=self._root_widget,
|
||||
on_cancel_call=self._close)
|
||||
ba.widget(edit=self._scrollwidget,
|
||||
left_widget=_ba.get_special_widget('back_button'))
|
||||
ba.widget(
|
||||
edit=self._scrollwidget,
|
||||
left_widget=ba.internal.get_special_widget('back_button'))
|
||||
else:
|
||||
btn = ba.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
|
|
@ -150,7 +152,8 @@ class HelpWindow(ba.Window):
|
|||
maxwidth=txt_maxwidth)
|
||||
txt_width = min(
|
||||
txt_maxwidth,
|
||||
_ba.get_string_width(txt, suppress_warning=True) * txt_scale)
|
||||
ba.internal.get_string_width(txt, suppress_warning=True) *
|
||||
txt_scale)
|
||||
|
||||
icon_size = 70
|
||||
hval2 = h - (txt_width * 0.5 + icon_size * 0.5 * icon_buffer)
|
||||
|
|
@ -350,7 +353,8 @@ class HelpWindow(ba.Window):
|
|||
maxwidth=txt_maxwidth)
|
||||
txt_width = min(
|
||||
txt_maxwidth,
|
||||
_ba.get_string_width(txt, suppress_warning=True) * txt_scale)
|
||||
ba.internal.get_string_width(txt, suppress_warning=True) *
|
||||
txt_scale)
|
||||
icon_size = 70
|
||||
|
||||
hval2 = h - (txt_width * 0.5 + icon_size * 0.5 * icon_buffer)
|
||||
|
|
@ -496,7 +500,8 @@ class HelpWindow(ba.Window):
|
|||
maxwidth=txt_maxwidth)
|
||||
txt_width = min(
|
||||
txt_maxwidth,
|
||||
_ba.get_string_width(txt, suppress_warning=True) * txt_scale)
|
||||
ba.internal.get_string_width(txt, suppress_warning=True) *
|
||||
txt_scale)
|
||||
icon_size = 70
|
||||
hval2 = h - (txt_width * 0.5 + icon_size * 0.5 * icon_buffer)
|
||||
ba.imagewidget(parent=self._subcontainer,
|
||||
|
|
|
|||
4
dist/ba_data/python/bastd/ui/iconpicker.py
vendored
4
dist/ba_data/python/bastd/ui/iconpicker.py
vendored
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
import math
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.ui import popup
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -137,7 +137,7 @@ class IconPicker(popup.PopupWindow):
|
|||
def _on_store_press(self) -> None:
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
from bastd.ui.store.browser import StoreBrowserWindow
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
self._transition_out()
|
||||
|
|
|
|||
28
dist/ba_data/python/bastd/ui/kiosk.py
vendored
28
dist/ba_data/python/bastd/ui/kiosk.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -37,7 +37,7 @@ class KioskWindow(ba.Window):
|
|||
self._show_multiplayer = False
|
||||
|
||||
# Let's reset all random player names every time we hit the main menu.
|
||||
_ba.reset_random_player_names()
|
||||
ba.internal.reset_random_player_names()
|
||||
|
||||
# Reset achievements too (at least locally).
|
||||
ba.app.config['Achievements'] = {}
|
||||
|
|
@ -360,7 +360,7 @@ class KioskWindow(ba.Window):
|
|||
def _update(self) -> None:
|
||||
# Kiosk-mode is designed to be used signed-out... try for force
|
||||
# the issue.
|
||||
if _ba.get_v1_account_state() == 'signed_in':
|
||||
if ba.internal.get_v1_account_state() == 'signed_in':
|
||||
# _bs.sign_out()
|
||||
# FIXME: Try to delete player profiles here too.
|
||||
pass
|
||||
|
|
@ -390,11 +390,12 @@ class KioskWindow(ba.Window):
|
|||
'type': 'bs_elimination.EliminationGame'
|
||||
}]
|
||||
appconfig['Free-for-All Playlist Selection'] = 'Just Epic Elim'
|
||||
_ba.fade_screen(False,
|
||||
endcall=ba.Call(
|
||||
ba.pushcall,
|
||||
ba.Call(_ba.new_host_session,
|
||||
ba.FreeForAllSession)))
|
||||
ba.internal.fade_screen(False,
|
||||
endcall=ba.Call(
|
||||
ba.pushcall,
|
||||
ba.Call(
|
||||
ba.internal.new_host_session,
|
||||
ba.FreeForAllSession)))
|
||||
else:
|
||||
if mode == 'ctf':
|
||||
appconfig['Team Tournament Playlists']['Just CTF'] = [{
|
||||
|
|
@ -423,11 +424,12 @@ class KioskWindow(ba.Window):
|
|||
}]
|
||||
appconfig['Team Tournament Playlist Selection'] = (
|
||||
'Just Hockey')
|
||||
_ba.fade_screen(False,
|
||||
endcall=ba.Call(
|
||||
ba.pushcall,
|
||||
ba.Call(_ba.new_host_session,
|
||||
ba.DualTeamSession)))
|
||||
ba.internal.fade_screen(False,
|
||||
endcall=ba.Call(
|
||||
ba.pushcall,
|
||||
ba.Call(
|
||||
ba.internal.new_host_session,
|
||||
ba.DualTeamSession)))
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
|
@ -94,7 +94,7 @@ class LeagueRankButton:
|
|||
self._smooth_update_timer: ba.Timer | None = None
|
||||
|
||||
# Take note of our account state; we'll refresh later if this changes.
|
||||
self._account_state_num = _ba.get_v1_account_state_num()
|
||||
self._account_state_num = ba.internal.get_v1_account_state_num()
|
||||
self._last_power_ranking_query_time: float | None = None
|
||||
self._doing_power_ranking_query = False
|
||||
self.set_position(position)
|
||||
|
|
@ -111,7 +111,7 @@ class LeagueRankButton:
|
|||
self._update_for_league_rank_data(data)
|
||||
|
||||
def _on_activate(self) -> None:
|
||||
_ba.increment_analytics_count('League rank button press')
|
||||
ba.internal.increment_analytics_count('League rank button press')
|
||||
self._on_activate_call()
|
||||
|
||||
def __del__(self) -> None:
|
||||
|
|
@ -224,7 +224,7 @@ class LeagueRankButton:
|
|||
|
||||
in_top = data is not None and data['rank'] is not None
|
||||
do_percent = False
|
||||
if data is None or _ba.get_v1_account_state() != 'signed_in':
|
||||
if data is None or ba.internal.get_v1_account_state() != 'signed_in':
|
||||
self._percent = self._rank = None
|
||||
status_text = '-'
|
||||
elif in_top:
|
||||
|
|
@ -335,7 +335,7 @@ class LeagueRankButton:
|
|||
cur_time = ba.time(ba.TimeType.REAL)
|
||||
|
||||
# If our account state has changed, refresh our UI.
|
||||
account_state_num = _ba.get_v1_account_state_num()
|
||||
account_state_num = ba.internal.get_v1_account_state_num()
|
||||
if account_state_num != self._account_state_num:
|
||||
self._account_state_num = account_state_num
|
||||
|
||||
|
|
@ -350,7 +350,7 @@ class LeagueRankButton:
|
|||
or cur_time - self._last_power_ranking_query_time > 30.0):
|
||||
self._last_power_ranking_query_time = cur_time
|
||||
self._doing_power_ranking_query = True
|
||||
_ba.power_ranking_query(
|
||||
ba.internal.power_ranking_query(
|
||||
callback=ba.WeakCall(self._on_power_ranking_query_response))
|
||||
|
||||
def _default_on_activate_call(self) -> None:
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
import copy
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.ui import popup as popup_ui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -118,7 +118,7 @@ class LeagueRankWindow(ba.Window):
|
|||
self._season: str | None = None
|
||||
|
||||
# take note of our account state; we'll refresh later if this changes
|
||||
self._account_state = _ba.get_v1_account_state()
|
||||
self._account_state = ba.internal.get_v1_account_state()
|
||||
|
||||
self._refresh()
|
||||
self._restore_state()
|
||||
|
|
@ -155,8 +155,9 @@ class LeagueRankWindow(ba.Window):
|
|||
resource='coopSelectWindow.activenessAllTimeInfoText'
|
||||
if self._season == 'a' else 'coopSelectWindow.activenessInfoText',
|
||||
subs=[('${MAX}',
|
||||
str(_ba.get_v1_account_misc_read_val('activenessMax',
|
||||
1.0)))])
|
||||
str(
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
'activenessMax', 1.0)))])
|
||||
confirm.ConfirmWindow(txt,
|
||||
cancel_button=False,
|
||||
width=460,
|
||||
|
|
@ -168,7 +169,7 @@ class LeagueRankWindow(ba.Window):
|
|||
txt = ba.Lstr(resource='coopSelectWindow.proMultInfoText',
|
||||
subs=[('${PERCENT}',
|
||||
str(
|
||||
_ba.get_v1_account_misc_read_val(
|
||||
ba.internal.get_v1_account_misc_read_val(
|
||||
'proPowerRankingBoost', 10))),
|
||||
('${PRO}',
|
||||
ba.Lstr(resource='store.bombSquadProNameText',
|
||||
|
|
@ -208,7 +209,7 @@ class LeagueRankWindow(ba.Window):
|
|||
cur_time = ba.time(ba.TimeType.REAL)
|
||||
|
||||
# if our account state has changed, refresh our UI
|
||||
account_state = _ba.get_v1_account_state()
|
||||
account_state = ba.internal.get_v1_account_state()
|
||||
if account_state != self._account_state:
|
||||
self._account_state = account_state
|
||||
self._save_state()
|
||||
|
|
@ -242,9 +243,9 @@ class LeagueRankWindow(ba.Window):
|
|||
|
||||
self._last_power_ranking_query_time = cur_time
|
||||
self._doing_power_ranking_query = True
|
||||
_ba.power_ranking_query(season=self._requested_season,
|
||||
callback=ba.WeakCall(
|
||||
self._on_power_ranking_query_response))
|
||||
ba.internal.power_ranking_query(
|
||||
season=self._requested_season,
|
||||
callback=ba.WeakCall(self._on_power_ranking_query_response))
|
||||
|
||||
def _refresh(self) -> None:
|
||||
# pylint: disable=too-many-statements
|
||||
|
|
@ -352,7 +353,7 @@ class LeagueRankWindow(ba.Window):
|
|||
maxwidth=200)
|
||||
|
||||
self._activity_mult_button: ba.Widget | None
|
||||
if _ba.get_v1_account_misc_read_val('act', False):
|
||||
if ba.internal.get_v1_account_misc_read_val('act', False):
|
||||
self._activity_mult_button = ba.buttonwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 - 60, v2 + 10),
|
||||
|
|
@ -564,7 +565,7 @@ class LeagueRankWindow(ba.Window):
|
|||
self._on_more_press))
|
||||
|
||||
def _on_more_press(self) -> None:
|
||||
our_login_id = _ba.get_public_login_id()
|
||||
our_login_id = ba.internal.get_public_login_id()
|
||||
# our_login_id = _bs.get_account_misc_read_val_2(
|
||||
# 'resolvedAccountID', None)
|
||||
if not self._can_do_more_button or our_login_id is None:
|
||||
|
|
@ -582,7 +583,7 @@ class LeagueRankWindow(ba.Window):
|
|||
league_str = '&league=' + self._league_url_arg
|
||||
else:
|
||||
league_str = ''
|
||||
ba.open_url(_ba.get_master_server_address() +
|
||||
ba.open_url(ba.internal.get_master_server_address() +
|
||||
'/highscores?list=powerRankings&v=2' + league_str +
|
||||
season_str + '&player=' + our_login_id)
|
||||
|
||||
|
|
@ -602,7 +603,7 @@ class LeagueRankWindow(ba.Window):
|
|||
finished_season_unranked = False
|
||||
self._can_do_more_button = True
|
||||
extra_text = ''
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
status_text = '(' + ba.Lstr(
|
||||
resource='notSignedInText').evaluate() + ')'
|
||||
elif in_top:
|
||||
|
|
@ -746,7 +747,7 @@ class LeagueRankWindow(ba.Window):
|
|||
ba.textwidget(edit=self._league_text, text=lname, color=lcolor)
|
||||
l_text_width = min(
|
||||
self._league_text_maxwidth,
|
||||
_ba.get_string_width(lname, suppress_warning=True) *
|
||||
ba.internal.get_string_width(lname, suppress_warning=True) *
|
||||
self._league_text_scale)
|
||||
ba.textwidget(
|
||||
edit=self._league_number_text,
|
||||
|
|
@ -789,8 +790,8 @@ class LeagueRankWindow(ba.Window):
|
|||
|
||||
have_pro = False if data is None else data['p']
|
||||
pro_mult = 1.0 + float(
|
||||
_ba.get_v1_account_misc_read_val('proPowerRankingBoost',
|
||||
0.0)) * 0.01
|
||||
ba.internal.get_v1_account_misc_read_val('proPowerRankingBoost',
|
||||
0.0)) * 0.01
|
||||
# pylint: disable=consider-using-f-string
|
||||
ba.textwidget(edit=self._pro_mult_text,
|
||||
text=' -' if
|
||||
|
|
|
|||
69
dist/ba_data/python/bastd/ui/mainmenu.py
vendored
69
dist/ba_data/python/bastd/ui/mainmenu.py
vendored
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
import _ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
|
@ -21,8 +21,8 @@ class MainMenuWindow(ba.Window):
|
|||
# pylint: disable=cyclic-import
|
||||
import threading
|
||||
from bastd.mainmenu import MainMenuSession
|
||||
self._in_game = not isinstance(_ba.get_foreground_host_session(),
|
||||
MainMenuSession)
|
||||
self._in_game = not isinstance(
|
||||
ba.internal.get_foreground_host_session(), MainMenuSession)
|
||||
|
||||
# Preload some modules we use in a background thread so we won't
|
||||
# have a visual hitch when the user taps them.
|
||||
|
|
@ -67,9 +67,9 @@ class MainMenuWindow(ba.Window):
|
|||
self._restore_state()
|
||||
|
||||
# Keep an eye on a few things and refresh if they change.
|
||||
self._account_state = _ba.get_v1_account_state()
|
||||
self._account_state_num = _ba.get_v1_account_state_num()
|
||||
self._account_type = (_ba.get_v1_account_type()
|
||||
self._account_state = ba.internal.get_v1_account_state()
|
||||
self._account_state_num = ba.internal.get_v1_account_state_num()
|
||||
self._account_type = (ba.internal.get_v1_account_type()
|
||||
if self._account_state == 'signed_in' else None)
|
||||
self._refresh_timer = ba.Timer(1.0,
|
||||
ba.WeakCall(self._check_refresh),
|
||||
|
|
@ -101,7 +101,7 @@ class MainMenuWindow(ba.Window):
|
|||
try:
|
||||
app = ba.app
|
||||
force_test = False
|
||||
_ba.get_local_active_input_devices_count()
|
||||
ba.internal.get_local_active_input_devices_count()
|
||||
if (((app.on_tv or app.platform == 'mac')
|
||||
and ba.app.config.get('launchCount', 0) <= 1)
|
||||
or force_test):
|
||||
|
|
@ -122,10 +122,11 @@ class MainMenuWindow(ba.Window):
|
|||
ba.print_exception('Error showing get-remote-app info')
|
||||
|
||||
def _get_store_char_tex(self) -> str:
|
||||
return ('storeCharacterXmas' if _ba.get_v1_account_misc_read_val(
|
||||
'xmas', False) else
|
||||
'storeCharacterEaster' if _ba.get_v1_account_misc_read_val(
|
||||
'easter', False) else 'storeCharacter')
|
||||
return (
|
||||
'storeCharacterXmas' if ba.internal.get_v1_account_misc_read_val(
|
||||
'xmas', False) else
|
||||
'storeCharacterEaster' if ba.internal.get_v1_account_misc_read_val(
|
||||
'easter', False) else 'storeCharacter')
|
||||
|
||||
def _check_refresh(self) -> None:
|
||||
if not self._root_widget:
|
||||
|
|
@ -138,13 +139,14 @@ class MainMenuWindow(ba.Window):
|
|||
return
|
||||
|
||||
store_char_tex = self._get_store_char_tex()
|
||||
account_state_num = _ba.get_v1_account_state_num()
|
||||
account_state_num = ba.internal.get_v1_account_state_num()
|
||||
if (account_state_num != self._account_state_num
|
||||
or store_char_tex != self._store_char_tex):
|
||||
self._store_char_tex = store_char_tex
|
||||
self._account_state_num = account_state_num
|
||||
account_state = self._account_state = (_ba.get_v1_account_state())
|
||||
self._account_type = (_ba.get_v1_account_type()
|
||||
account_state = self._account_state = (
|
||||
ba.internal.get_v1_account_state())
|
||||
self._account_type = (ba.internal.get_v1_account_type()
|
||||
if account_state == 'signed_in' else None)
|
||||
self._save_state()
|
||||
self._refresh()
|
||||
|
|
@ -185,7 +187,7 @@ class MainMenuWindow(ba.Window):
|
|||
(not self._in_game or not app.toolbar_test)
|
||||
and not (self._is_demo or self._is_arcade or self._is_iircade))
|
||||
|
||||
self._input_device = input_device = _ba.get_ui_input_device()
|
||||
self._input_device = input_device = ba.internal.get_ui_input_device()
|
||||
self._input_player = input_device.player if input_device else None
|
||||
self._connected_to_remote_player = (
|
||||
input_device.is_connected_to_remote_player()
|
||||
|
|
@ -213,8 +215,8 @@ class MainMenuWindow(ba.Window):
|
|||
on_activate_call=self._settings)
|
||||
|
||||
# Scattered eggs on easter.
|
||||
if _ba.get_v1_account_misc_read_val('easter',
|
||||
False) and not self._in_game:
|
||||
if ba.internal.get_v1_account_misc_read_val(
|
||||
'easter', False) and not self._in_game:
|
||||
icon_size = 34
|
||||
ba.imagewidget(parent=self._root_widget,
|
||||
position=(h - icon_size * 0.5 - 15,
|
||||
|
|
@ -232,7 +234,7 @@ class MainMenuWindow(ba.Window):
|
|||
self._p_index += 1
|
||||
|
||||
# If we're in a replay, we have a 'Leave Replay' button.
|
||||
if _ba.is_in_replay():
|
||||
if ba.internal.is_in_replay():
|
||||
ba.buttonwidget(parent=self._root_widget,
|
||||
position=(h - self._button_width * 0.5 * scale,
|
||||
v),
|
||||
|
|
@ -241,7 +243,7 @@ class MainMenuWindow(ba.Window):
|
|||
autoselect=self._use_autoselect,
|
||||
label=ba.Lstr(resource='replayEndText'),
|
||||
on_activate_call=self._confirm_end_replay)
|
||||
elif _ba.get_foreground_host_session() is not None:
|
||||
elif ba.internal.get_foreground_host_session() is not None:
|
||||
ba.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h - self._button_width * 0.5 * scale, v),
|
||||
|
|
@ -310,7 +312,7 @@ class MainMenuWindow(ba.Window):
|
|||
transition_delay=self._tdelay)
|
||||
|
||||
# Scattered eggs on easter.
|
||||
if _ba.get_v1_account_misc_read_val('easter', False):
|
||||
if ba.internal.get_v1_account_misc_read_val('easter', False):
|
||||
icon_size = 30
|
||||
ba.imagewidget(parent=self._root_widget,
|
||||
position=(h - icon_size * 0.5 + 25,
|
||||
|
|
@ -341,7 +343,7 @@ class MainMenuWindow(ba.Window):
|
|||
# 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 _ba.is_in_replay():
|
||||
if ba.internal.is_in_replay():
|
||||
b_size = 50.0
|
||||
b_buffer = 10.0
|
||||
t_scale = 0.75
|
||||
|
|
@ -427,8 +429,8 @@ class MainMenuWindow(ba.Window):
|
|||
self._height = 200.0
|
||||
enable_account_button = True
|
||||
account_type_name: str | ba.Lstr
|
||||
if _ba.get_v1_account_state() == 'signed_in':
|
||||
account_type_name = _ba.get_v1_account_display_string()
|
||||
if ba.internal.get_v1_account_state() == 'signed_in':
|
||||
account_type_name = ba.internal.get_v1_account_display_string()
|
||||
account_type_icon = None
|
||||
account_textcolor = (1.0, 1.0, 1.0)
|
||||
else:
|
||||
|
|
@ -618,8 +620,8 @@ class MainMenuWindow(ba.Window):
|
|||
enable_sound=account_type_enable_button_sound)
|
||||
|
||||
# Scattered eggs on easter.
|
||||
if _ba.get_v1_account_misc_read_val('easter',
|
||||
False) and not self._in_game:
|
||||
if ba.internal.get_v1_account_misc_read_val(
|
||||
'easter', False) and not self._in_game:
|
||||
icon_size = 32
|
||||
ba.imagewidget(parent=self._root_widget,
|
||||
position=(h - icon_size * 0.5 + 35,
|
||||
|
|
@ -648,8 +650,8 @@ class MainMenuWindow(ba.Window):
|
|||
self._how_to_play_button = btn
|
||||
|
||||
# Scattered eggs on easter.
|
||||
if _ba.get_v1_account_misc_read_val('easter',
|
||||
False) and not self._in_game:
|
||||
if ba.internal.get_v1_account_misc_read_val(
|
||||
'easter', False) and not self._in_game:
|
||||
icon_size = 28
|
||||
ba.imagewidget(parent=self._root_widget,
|
||||
position=(h - icon_size * 0.5 + 30,
|
||||
|
|
@ -682,7 +684,7 @@ class MainMenuWindow(ba.Window):
|
|||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
custom_menu_entries: list[dict[str, Any]] = []
|
||||
session = _ba.get_foreground_host_session()
|
||||
session = ba.internal.get_foreground_host_session()
|
||||
if session is not None:
|
||||
try:
|
||||
custom_menu_entries = session.get_custom_menu_entries()
|
||||
|
|
@ -819,8 +821,9 @@ class MainMenuWindow(ba.Window):
|
|||
if ba.do_once():
|
||||
print('_change_replay_speed called without widget')
|
||||
return
|
||||
_ba.set_replay_speed_exponent(_ba.get_replay_speed_exponent() + offs)
|
||||
actual_speed = pow(2.0, _ba.get_replay_speed_exponent())
|
||||
ba.internal.set_replay_speed_exponent(
|
||||
ba.internal.get_replay_speed_exponent() + offs)
|
||||
actual_speed = pow(2.0, ba.internal.get_replay_speed_exponent())
|
||||
ba.textwidget(edit=self._replay_speed_text,
|
||||
text=ba.Lstr(resource='watchWindow.playbackSpeedText',
|
||||
subs=[('${SPEED}', str(actual_speed))]))
|
||||
|
|
@ -851,7 +854,7 @@ class MainMenuWindow(ba.Window):
|
|||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.store.browser import StoreBrowserWindow
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
self._save_state()
|
||||
|
|
@ -892,7 +895,7 @@ class MainMenuWindow(ba.Window):
|
|||
cancel_is_selected=True)
|
||||
|
||||
def _leave_party(self) -> None:
|
||||
_ba.disconnect_from_host()
|
||||
ba.internal.disconnect_from_host()
|
||||
|
||||
def _end_game(self) -> None:
|
||||
if not self._root_widget:
|
||||
|
|
@ -942,7 +945,7 @@ class MainMenuWindow(ba.Window):
|
|||
|
||||
def _do_game_service_press(self) -> None:
|
||||
self._save_state()
|
||||
_ba.show_online_score_ui()
|
||||
ba.internal.show_online_score_ui()
|
||||
|
||||
def _save_state(self) -> None:
|
||||
|
||||
|
|
|
|||
34
dist/ba_data/python/bastd/ui/onscreenkeyboard.py
vendored
34
dist/ba_data/python/bastd/ui/onscreenkeyboard.py
vendored
|
|
@ -6,10 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
from ba import charstr
|
||||
from ba import SpecialChar as SpCh
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -25,7 +23,7 @@ class OnScreenKeyboardWindow(ba.Window):
|
|||
uiscale = ba.app.ui.uiscale
|
||||
top_extra = 20 if uiscale is ba.UIScale.SMALL else 0
|
||||
super().__init__(root_widget=ba.containerwidget(
|
||||
parent=_ba.get_special_widget('overlay_stack'),
|
||||
parent=ba.internal.get_special_widget('overlay_stack'),
|
||||
size=(self._width, self._height + top_extra),
|
||||
transition='in_scale',
|
||||
scale_origin_stack_offset=self._target_text.
|
||||
|
|
@ -129,7 +127,7 @@ class OnScreenKeyboardWindow(ba.Window):
|
|||
autoselect=True,
|
||||
textcolor=key_textcolor,
|
||||
color=key_color_dark,
|
||||
label=charstr(SpCh.SHIFT),
|
||||
label=ba.charstr(ba.SpecialChar.SHIFT),
|
||||
enable_sound=False,
|
||||
extra_touch_border_scale=0.3,
|
||||
button_type='square',
|
||||
|
|
@ -165,7 +163,7 @@ class OnScreenKeyboardWindow(ba.Window):
|
|||
repeat=True,
|
||||
textcolor=key_textcolor,
|
||||
color=key_color_dark,
|
||||
label=charstr(SpCh.DELETE),
|
||||
label=ba.charstr(ba.SpecialChar.DELETE),
|
||||
button_type='square',
|
||||
on_activate_call=self._del)
|
||||
v -= (key_height + 9)
|
||||
|
|
@ -193,7 +191,7 @@ class OnScreenKeyboardWindow(ba.Window):
|
|||
enable_sound=False,
|
||||
textcolor=key_textcolor,
|
||||
color=key_color_dark,
|
||||
label=charstr(SpCh.LOGO_FLAT),
|
||||
label=ba.charstr(ba.SpecialChar.LOGO_FLAT),
|
||||
extra_touch_border_scale=0.3,
|
||||
button_type='square',
|
||||
)
|
||||
|
|
@ -213,8 +211,10 @@ class OnScreenKeyboardWindow(ba.Window):
|
|||
|
||||
# Show change instructions only if we have more than one
|
||||
# keyboard option.
|
||||
if (ba.app.meta.scanresults is not None
|
||||
and len(ba.app.meta.scanresults.keyboards) > 1):
|
||||
keyboards = (ba.app.meta.scanresults.exports_of_class(
|
||||
ba.Keyboard) if ba.app.meta.scanresults is not None
|
||||
else [])
|
||||
if len(keyboards) > 1:
|
||||
ba.textwidget(
|
||||
parent=self._root_widget,
|
||||
h_align='center',
|
||||
|
|
@ -239,7 +239,8 @@ class OnScreenKeyboardWindow(ba.Window):
|
|||
|
||||
def _get_keyboard(self) -> ba.Keyboard:
|
||||
assert ba.app.meta.scanresults is not None
|
||||
classname = ba.app.meta.scanresults.keyboards[self._keyboard_index]
|
||||
classname = ba.app.meta.scanresults.exports_of_class(
|
||||
ba.Keyboard)[self._keyboard_index]
|
||||
kbclass = ba.getclass(classname, ba.Keyboard)
|
||||
return kbclass()
|
||||
|
||||
|
|
@ -252,14 +253,14 @@ class OnScreenKeyboardWindow(ba.Window):
|
|||
ba.buttonwidget(edit=self._shift_button,
|
||||
color=self._key_color_lit
|
||||
if self._mode == 'caps' else self._key_color_dark,
|
||||
label=charstr(SpCh.SHIFT),
|
||||
label=ba.charstr(ba.SpecialChar.SHIFT),
|
||||
on_activate_call=self._shift)
|
||||
ba.buttonwidget(edit=self._num_mode_button,
|
||||
label='123#&*',
|
||||
on_activate_call=self._num_mode)
|
||||
ba.buttonwidget(edit=self._emoji_button,
|
||||
color=self._key_color_dark,
|
||||
label=charstr(SpCh.LOGO_FLAT),
|
||||
label=ba.charstr(ba.SpecialChar.LOGO_FLAT),
|
||||
on_activate_call=self._next_mode)
|
||||
else:
|
||||
if self._mode == 'num':
|
||||
|
|
@ -275,7 +276,7 @@ class OnScreenKeyboardWindow(ba.Window):
|
|||
on_activate_call=self._abc_mode)
|
||||
ba.buttonwidget(edit=self._emoji_button,
|
||||
color=self._key_color_dark,
|
||||
label=charstr(SpCh.LOGO_FLAT),
|
||||
label=ba.charstr(ba.SpecialChar.LOGO_FLAT),
|
||||
on_activate_call=self._next_mode)
|
||||
|
||||
for i, btn in enumerate(self._char_keys):
|
||||
|
|
@ -318,10 +319,11 @@ class OnScreenKeyboardWindow(ba.Window):
|
|||
|
||||
def _next_keyboard(self) -> None:
|
||||
assert ba.app.meta.scanresults is not None
|
||||
self._keyboard_index = (self._keyboard_index + 1) % len(
|
||||
ba.app.meta.scanresults.keyboards)
|
||||
kbexports = ba.app.meta.scanresults.exports_of_class(ba.Keyboard)
|
||||
self._keyboard_index = (self._keyboard_index + 1) % len(kbexports)
|
||||
|
||||
self._load_keyboard()
|
||||
if len(ba.app.meta.scanresults.keyboards) < 2:
|
||||
if len(kbexports) < 2:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
ba.screenmessage(ba.Lstr(resource='keyboardNoOthersAvailableText'),
|
||||
color=(1, 0, 0))
|
||||
|
|
|
|||
27
dist/ba_data/python/bastd/ui/party.py
vendored
27
dist/ba_data/python/bastd/ui/party.py
vendored
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
import math
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.ui import popup
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -19,10 +19,10 @@ class PartyWindow(ba.Window):
|
|||
"""Party list/chat window."""
|
||||
|
||||
def __del__(self) -> None:
|
||||
_ba.set_party_window_open(False)
|
||||
ba.internal.set_party_window_open(False)
|
||||
|
||||
def __init__(self, origin: Sequence[float] = (0, 0)):
|
||||
_ba.set_party_window_open(True)
|
||||
ba.internal.set_party_window_open(True)
|
||||
self._r = 'partyWindow'
|
||||
self._popup_type: str | None = None
|
||||
self._popup_party_member_client_id: int | None = None
|
||||
|
|
@ -35,7 +35,7 @@ class PartyWindow(ba.Window):
|
|||
size=(self._width, self._height),
|
||||
transition='in_scale',
|
||||
color=(0.40, 0.55, 0.20),
|
||||
parent=_ba.get_special_widget('overlay_stack'),
|
||||
parent=ba.internal.get_special_widget('overlay_stack'),
|
||||
on_outside_click_call=self.close_with_sound,
|
||||
scale_origin_stack_offset=origin,
|
||||
scale=(2.0 if uiscale is ba.UIScale.SMALL else
|
||||
|
|
@ -68,7 +68,7 @@ class PartyWindow(ba.Window):
|
|||
color=(0.55, 0.73, 0.25),
|
||||
iconscale=1.2)
|
||||
|
||||
info = _ba.get_connection_to_host_info()
|
||||
info = ba.internal.get_connection_to_host_info()
|
||||
if info.get('name', '') != '':
|
||||
title = ba.Lstr(value=info['name'])
|
||||
else:
|
||||
|
|
@ -116,7 +116,7 @@ class PartyWindow(ba.Window):
|
|||
|
||||
# add all existing messages if chat is not muted
|
||||
if not ba.app.config.resolve('Chat Muted'):
|
||||
msgs = _ba.get_chat_messages()
|
||||
msgs = ba.internal.get_chat_messages()
|
||||
for msg in msgs:
|
||||
self._add_msg(msg)
|
||||
|
||||
|
|
@ -215,7 +215,7 @@ class PartyWindow(ba.Window):
|
|||
ba.textwidget(edit=self._muted_text, color=(1, 1, 1, 0.0))
|
||||
|
||||
# update roster section
|
||||
roster = _ba.get_game_roster()
|
||||
roster = ba.internal.get_game_roster()
|
||||
if roster != self._roster:
|
||||
self._roster = roster
|
||||
|
||||
|
|
@ -318,7 +318,7 @@ class PartyWindow(ba.Window):
|
|||
if is_host:
|
||||
twd = min(
|
||||
c_width * 0.85,
|
||||
_ba.get_string_width(
|
||||
ba.internal.get_string_width(
|
||||
p_str, suppress_warning=True) *
|
||||
t_scale)
|
||||
self._name_widgets.append(
|
||||
|
|
@ -357,7 +357,7 @@ class PartyWindow(ba.Window):
|
|||
assert self._popup_party_member_client_id is not None
|
||||
|
||||
# Ban for 5 minutes.
|
||||
result = _ba.disconnect_client(
|
||||
result = ba.internal.disconnect_client(
|
||||
self._popup_party_member_client_id, ban_time=5 * 60)
|
||||
if not result:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
|
|
@ -379,12 +379,12 @@ class PartyWindow(ba.Window):
|
|||
def _on_party_member_press(self, client_id: int, is_host: bool,
|
||||
widget: ba.Widget) -> None:
|
||||
# if we're the host, pop up 'kick' options for all non-host members
|
||||
if _ba.get_foreground_host_session() is not None:
|
||||
if ba.internal.get_foreground_host_session() is not None:
|
||||
kick_str = ba.Lstr(resource='kickText')
|
||||
else:
|
||||
# kick-votes appeared in build 14248
|
||||
if (_ba.get_connection_to_host_info().get('build_number', 0) <
|
||||
14248):
|
||||
if (ba.internal.get_connection_to_host_info().get(
|
||||
'build_number', 0) < 14248):
|
||||
return
|
||||
kick_str = ba.Lstr(resource='kickVoteText')
|
||||
uiscale = ba.app.ui.uiscale
|
||||
|
|
@ -401,7 +401,8 @@ class PartyWindow(ba.Window):
|
|||
self._popup_party_member_is_host = is_host
|
||||
|
||||
def _send_chat_message(self) -> None:
|
||||
_ba.chatmessage(cast(str, ba.textwidget(query=self._text_field)))
|
||||
ba.internal.chatmessage(
|
||||
cast(str, ba.textwidget(query=self._text_field)))
|
||||
ba.textwidget(edit=self._text_field, text='')
|
||||
|
||||
def close(self) -> None:
|
||||
|
|
|
|||
41
dist/ba_data/python/bastd/ui/partyqueue.py
vendored
41
dist/ba_data/python/bastd/ui/partyqueue.py
vendored
|
|
@ -8,8 +8,8 @@ import random
|
|||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence
|
||||
|
|
@ -257,11 +257,11 @@ class PartyQueueWindow(ba.Window):
|
|||
def __del__(self) -> None:
|
||||
try:
|
||||
ba.app.ui.have_party_queue_window = False
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'PARTY_QUEUE_REMOVE',
|
||||
'q': self._queue_id
|
||||
})
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
except Exception:
|
||||
ba.print_exception('Error removing self from party queue.')
|
||||
|
||||
|
|
@ -320,8 +320,9 @@ class PartyQueueWindow(ba.Window):
|
|||
if -1 not in self._dudes_by_id:
|
||||
dude = self.Dude(
|
||||
self, response['d'], self._initial_offset, True,
|
||||
_ba.get_v1_account_misc_read_val_2('resolvedAccountID', None),
|
||||
_ba.get_v1_account_display_string())
|
||||
ba.internal.get_v1_account_misc_read_val_2(
|
||||
'resolvedAccountID', None),
|
||||
ba.internal.get_v1_account_display_string())
|
||||
self._dudes_by_id[-1] = dude
|
||||
self._dudes.append(dude)
|
||||
else:
|
||||
|
|
@ -448,26 +449,26 @@ class PartyQueueWindow(ba.Window):
|
|||
now = time.time()
|
||||
if (self._last_connect_attempt_time is None
|
||||
or now - self._last_connect_attempt_time > 10.0):
|
||||
_ba.connect_to_party(address=self._address,
|
||||
port=self._port,
|
||||
print_progress=False)
|
||||
ba.internal.connect_to_party(address=self._address,
|
||||
port=self._port,
|
||||
print_progress=False)
|
||||
self._last_connect_attempt_time = now
|
||||
|
||||
def on_boost_press(self) -> None:
|
||||
"""Boost was pressed."""
|
||||
from bastd.ui import account
|
||||
from bastd.ui import getcurrency
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
account.show_sign_in_prompt()
|
||||
return
|
||||
|
||||
if _ba.get_v1_account_ticket_count() < self._boost_tickets:
|
||||
if ba.internal.get_v1_account_ticket_count() < self._boost_tickets:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
getcurrency.show_get_tickets_prompt()
|
||||
return
|
||||
|
||||
ba.playsound(ba.getsound('laserReverse'))
|
||||
_ba.add_transaction(
|
||||
ba.internal.add_transaction(
|
||||
{
|
||||
'type': 'PARTY_QUEUE_BOOST',
|
||||
't': self._boost_tickets,
|
||||
|
|
@ -497,18 +498,18 @@ class PartyQueueWindow(ba.Window):
|
|||
|
||||
# Update boost button color based on if we have enough moola.
|
||||
if self._boost_button is not None:
|
||||
can_boost = (
|
||||
(_ba.get_v1_account_state() == 'signed_in'
|
||||
and _ba.get_v1_account_ticket_count() >= self._boost_tickets))
|
||||
can_boost = ((ba.internal.get_v1_account_state() == 'signed_in'
|
||||
and ba.internal.get_v1_account_ticket_count() >=
|
||||
self._boost_tickets))
|
||||
ba.buttonwidget(edit=self._boost_button,
|
||||
color=(0, 1, 0) if can_boost else (0.7, 0.7, 0.7))
|
||||
|
||||
# Update ticket-count.
|
||||
if self._tickets_text is not None:
|
||||
if self._boost_button is not None:
|
||||
if _ba.get_v1_account_state() == 'signed_in':
|
||||
if ba.internal.get_v1_account_state() == 'signed_in':
|
||||
val = ba.charstr(ba.SpecialChar.TICKET) + str(
|
||||
_ba.get_v1_account_ticket_count())
|
||||
ba.internal.get_v1_account_ticket_count())
|
||||
else:
|
||||
val = ba.charstr(ba.SpecialChar.TICKET) + '???'
|
||||
ba.textwidget(edit=self._tickets_text, text=val)
|
||||
|
|
@ -517,16 +518,16 @@ class PartyQueueWindow(ba.Window):
|
|||
|
||||
current_time = ba.time(ba.TimeType.REAL)
|
||||
if (self._last_transaction_time is None
|
||||
or current_time - self._last_transaction_time >
|
||||
0.001 * _ba.get_v1_account_misc_read_val('pqInt', 5000)):
|
||||
or current_time - self._last_transaction_time > 0.001 *
|
||||
ba.internal.get_v1_account_misc_read_val('pqInt', 5000)):
|
||||
self._last_transaction_time = current_time
|
||||
_ba.add_transaction(
|
||||
ba.internal.add_transaction(
|
||||
{
|
||||
'type': 'PARTY_QUEUE_QUERY',
|
||||
'q': self._queue_id
|
||||
},
|
||||
callback=ba.WeakCall(self.on_update_response))
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
||||
# step our dudes
|
||||
for dude in self._dudes:
|
||||
|
|
|
|||
24
dist/ba_data/python/bastd/ui/play.py
vendored
24
dist/ba_data/python/bastd/ui/play.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -129,13 +129,15 @@ class PlayWindow(ba.Window):
|
|||
on_activate_call=self._coop)
|
||||
|
||||
if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
|
||||
ba.widget(edit=btn,
|
||||
left_widget=_ba.get_special_widget('back_button'))
|
||||
ba.widget(edit=btn,
|
||||
up_widget=_ba.get_special_widget('account_button'))
|
||||
ba.widget(
|
||||
edit=btn,
|
||||
down_widget=_ba.get_special_widget('settings_button'))
|
||||
left_widget=ba.internal.get_special_widget('back_button'))
|
||||
ba.widget(
|
||||
edit=btn,
|
||||
up_widget=ba.internal.get_special_widget('account_button'))
|
||||
ba.widget(edit=btn,
|
||||
down_widget=ba.internal.get_special_widget(
|
||||
'settings_button'))
|
||||
|
||||
self._draw_dude(0,
|
||||
btn,
|
||||
|
|
@ -216,9 +218,11 @@ class PlayWindow(ba.Window):
|
|||
on_activate_call=self._team_tourney)
|
||||
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
up_widget=_ba.get_special_widget('tickets_plus_button'),
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
ba.widget(
|
||||
edit=btn,
|
||||
up_widget=ba.internal.get_special_widget(
|
||||
'tickets_plus_button'),
|
||||
right_widget=ba.internal.get_special_widget('party_button'))
|
||||
|
||||
xxx = -14
|
||||
self._draw_dude(2,
|
||||
|
|
@ -447,7 +451,7 @@ class PlayWindow(ba.Window):
|
|||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
from bastd.ui.coop.browser import CoopBrowserWindow
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
self._save_state()
|
||||
|
|
|
|||
53
dist/ba_data/python/bastd/ui/playlist/addgame.py
vendored
53
dist/ba_data/python/bastd/ui/playlist/addgame.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bastd.ui.playlist.editcontroller import PlaylistEditController
|
||||
|
|
@ -57,8 +57,9 @@ class PlaylistAddGameWindow(ba.Window):
|
|||
on_activate_call=self._add)
|
||||
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=select_button,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
ba.widget(
|
||||
edit=select_button,
|
||||
right_widget=ba.internal.get_special_widget('party_button'))
|
||||
|
||||
ba.textwidget(parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height - 28),
|
||||
|
|
@ -116,9 +117,39 @@ class PlaylistAddGameWindow(ba.Window):
|
|||
ba.containerwidget(edit=self._root_widget,
|
||||
selected_child=self._scrollwidget)
|
||||
|
||||
self._game_types: list[type[ba.GameActivity]] = []
|
||||
|
||||
# Get actual games loading in the bg.
|
||||
ba.app.meta.load_exported_classes(ba.GameActivity,
|
||||
self._on_game_types_loaded,
|
||||
completion_cb_in_bg_thread=True)
|
||||
|
||||
# Refresh with our initial empty list. We'll refresh again once
|
||||
# game loading is complete.
|
||||
self._refresh()
|
||||
|
||||
def _on_game_types_loaded(self,
|
||||
gametypes: list[type[ba.GameActivity]]) -> None:
|
||||
from ba.internal import get_unowned_game_types
|
||||
|
||||
# We asked for a bg thread completion cb so we can do some
|
||||
# filtering here in the bg thread where its not gonna cause hitches.
|
||||
assert not ba.in_logic_thread()
|
||||
sessiontype = self._editcontroller.get_session_type()
|
||||
unowned = get_unowned_game_types()
|
||||
self._game_types = [
|
||||
gt for gt in gametypes
|
||||
if gt not in unowned and gt.supports_session_type(sessiontype)
|
||||
]
|
||||
|
||||
# Sort in the current language.
|
||||
self._game_types.sort(key=lambda g: g.get_display_string().evaluate())
|
||||
|
||||
# Tell ourself to refresh back in the logic thread.
|
||||
ba.pushcall(self._refresh, from_other_thread=True)
|
||||
|
||||
def _refresh(self, select_get_more_games_button: bool = False) -> None:
|
||||
# from ba.internal import get_game_types
|
||||
|
||||
if self._column is not None:
|
||||
self._column.delete()
|
||||
|
|
@ -127,15 +158,7 @@ class PlaylistAddGameWindow(ba.Window):
|
|||
border=2,
|
||||
margin=0)
|
||||
|
||||
gametypes = [
|
||||
gt for gt in ba.app.meta.get_game_types() if
|
||||
gt.supports_session_type(self._editcontroller.get_session_type())
|
||||
]
|
||||
|
||||
# Sort in the current language.
|
||||
gametypes.sort(key=lambda g: g.get_display_string().evaluate())
|
||||
|
||||
for i, gametype in enumerate(gametypes):
|
||||
for i, gametype in enumerate(self._game_types):
|
||||
|
||||
def _doit() -> None:
|
||||
if self._select_button:
|
||||
|
|
@ -175,7 +198,7 @@ class PlaylistAddGameWindow(ba.Window):
|
|||
def _on_get_more_games_press(self) -> None:
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
from bastd.ui.store.browser import StoreBrowserWindow
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
StoreBrowserWindow(modal=True,
|
||||
|
|
@ -187,8 +210,8 @@ class PlaylistAddGameWindow(ba.Window):
|
|||
self._refresh(select_get_more_games_button=True)
|
||||
|
||||
def _add(self) -> None:
|
||||
_ba.lock_all_input() # Make sure no more commands happen.
|
||||
ba.timer(0.1, _ba.unlock_all_input, timetype=ba.TimeType.REAL)
|
||||
ba.internal.lock_all_input() # Make sure no more commands happen.
|
||||
ba.timer(0.1, ba.internal.unlock_all_input, timetype=ba.TimeType.REAL)
|
||||
assert self._selected_game_type is not None
|
||||
self._editcontroller.add_game_type_selected(self._selected_game_type)
|
||||
|
||||
|
|
|
|||
32
dist/ba_data/python/bastd/ui/playlist/browser.py
vendored
32
dist/ba_data/python/bastd/ui/playlist/browser.py
vendored
|
|
@ -8,8 +8,8 @@ import copy
|
|||
import math
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -140,8 +140,9 @@ class PlaylistBrowserWindow(ba.Window):
|
|||
def _ensure_standard_playlists_exist(self) -> None:
|
||||
# On new installations, go ahead and create a few playlists
|
||||
# besides the hard-coded default one:
|
||||
if not _ba.get_v1_account_misc_val('madeStandardPlaylists', False):
|
||||
_ba.add_transaction({
|
||||
if not ba.internal.get_v1_account_misc_val('madeStandardPlaylists',
|
||||
False):
|
||||
ba.internal.add_transaction({
|
||||
'type':
|
||||
'ADD_PLAYLIST',
|
||||
'playlistType':
|
||||
|
|
@ -175,7 +176,7 @@ class PlaylistBrowserWindow(ba.Window):
|
|||
},
|
||||
]
|
||||
})
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type':
|
||||
'ADD_PLAYLIST',
|
||||
'playlistType':
|
||||
|
|
@ -226,7 +227,7 @@ class PlaylistBrowserWindow(ba.Window):
|
|||
},
|
||||
]
|
||||
})
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type':
|
||||
'ADD_PLAYLIST',
|
||||
'playlistType':
|
||||
|
|
@ -255,7 +256,7 @@ class PlaylistBrowserWindow(ba.Window):
|
|||
},
|
||||
]
|
||||
})
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type':
|
||||
'ADD_PLAYLIST',
|
||||
'playlistType':
|
||||
|
|
@ -274,12 +275,12 @@ class PlaylistBrowserWindow(ba.Window):
|
|||
}
|
||||
}]
|
||||
})
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'SET_MISC_VAL',
|
||||
'name': 'madeStandardPlaylists',
|
||||
'value': True
|
||||
})
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
||||
def _refresh(self) -> None:
|
||||
# FIXME: Should tidy this up.
|
||||
|
|
@ -367,14 +368,14 @@ class PlaylistBrowserWindow(ba.Window):
|
|||
|
||||
if (x == 0 and ba.app.ui.use_toolbars
|
||||
and uiscale is ba.UIScale.SMALL):
|
||||
ba.widget(
|
||||
edit=btn,
|
||||
left_widget=_ba.get_special_widget('back_button'))
|
||||
ba.widget(edit=btn,
|
||||
left_widget=ba.internal.get_special_widget(
|
||||
'back_button'))
|
||||
if (x == columns - 1 and ba.app.ui.use_toolbars
|
||||
and uiscale is ba.UIScale.SMALL):
|
||||
ba.widget(
|
||||
edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
ba.widget(edit=btn,
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
ba.buttonwidget(
|
||||
edit=btn,
|
||||
on_activate_call=ba.Call(self._on_playlist_press, btn,
|
||||
|
|
@ -429,7 +430,8 @@ class PlaylistBrowserWindow(ba.Window):
|
|||
playlist = filter_playlist(playlist,
|
||||
self._sessiontype,
|
||||
remove_unowned=False,
|
||||
mark_unowned=True)
|
||||
mark_unowned=True,
|
||||
name=name)
|
||||
for entry in playlist:
|
||||
mapname = entry['settings']['map']
|
||||
maptype: type[ba.Map] | None
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import copy
|
|||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -225,7 +225,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||
ba.widget(edit=btn, right_widget=scrollwidget)
|
||||
ba.widget(edit=scrollwidget,
|
||||
left_widget=new_button,
|
||||
right_widget=_ba.get_special_widget('party_button')
|
||||
right_widget=ba.internal.get_special_widget('party_button')
|
||||
if ba.app.ui.use_toolbars else None)
|
||||
|
||||
# make sure config exists
|
||||
|
|
@ -279,23 +279,23 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||
|
||||
def _run_selected_playlist(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
_ba.unlock_all_input()
|
||||
ba.internal.unlock_all_input()
|
||||
try:
|
||||
_ba.new_host_session(self._sessiontype)
|
||||
ba.internal.new_host_session(self._sessiontype)
|
||||
except Exception:
|
||||
from bastd import mainmenu
|
||||
ba.print_exception(f'Error running session {self._sessiontype}.')
|
||||
|
||||
# Drop back into a main menu session.
|
||||
_ba.new_host_session(mainmenu.MainMenuSession)
|
||||
ba.internal.new_host_session(mainmenu.MainMenuSession)
|
||||
|
||||
def _choose_playlist(self) -> None:
|
||||
if self._selected_playlist_name is None:
|
||||
return
|
||||
self._save_playlist_selection()
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
_ba.fade_screen(False, endcall=self._run_selected_playlist)
|
||||
_ba.lock_all_input()
|
||||
ba.internal.fade_screen(False, endcall=self._run_selected_playlist)
|
||||
ba.internal.lock_all_input()
|
||||
|
||||
def _refresh(self, select_playlist: str | None = None) -> None:
|
||||
from efro.util import asserttype
|
||||
|
|
@ -424,12 +424,12 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
|
||||
def _do_delete_playlist(self) -> None:
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'REMOVE_PLAYLIST',
|
||||
'playlistType': self._pvars.config_name,
|
||||
'playlistName': self._selected_playlist_name
|
||||
})
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
ba.playsound(ba.getsound('shieldDown'))
|
||||
|
||||
# (we don't use len()-1 here because the default list adds one)
|
||||
|
|
@ -445,7 +445,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||
from bastd.ui.playlist import share
|
||||
|
||||
# Gotta be signed in for this to work.
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
ba.screenmessage(ba.Lstr(resource='notSignedInErrorText'),
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
|
|
@ -477,7 +477,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||
return
|
||||
|
||||
# Gotta be signed in for this to work.
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
ba.screenmessage(ba.Lstr(resource='notSignedInErrorText'),
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
|
|
@ -492,7 +492,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||
if self._selected_playlist_name is None:
|
||||
return
|
||||
|
||||
_ba.add_transaction(
|
||||
ba.internal.add_transaction(
|
||||
{
|
||||
'type': 'SHARE_PLAYLIST',
|
||||
'expire_time': time.time() + 5,
|
||||
|
|
@ -501,7 +501,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||
},
|
||||
callback=ba.WeakCall(self._on_share_playlist_response,
|
||||
self._selected_playlist_name))
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
ba.screenmessage(ba.Lstr(resource='sharingText'))
|
||||
|
||||
def _delete_playlist(self) -> None:
|
||||
|
|
@ -582,13 +582,13 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
|
|||
break
|
||||
test_index += 1
|
||||
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'ADD_PLAYLIST',
|
||||
'playlistType': self._pvars.config_name,
|
||||
'playlistName': test_name,
|
||||
'playlist': copy.deepcopy(plst)
|
||||
})
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
||||
ba.playsound(ba.getsound('gunCocking'))
|
||||
self._refresh(select_playlist=test_name)
|
||||
|
|
|
|||
13
dist/ba_data/python/bastd/ui/playlist/edit.py
vendored
13
dist/ba_data/python/bastd/ui/playlist/edit.py
vendored
|
|
@ -7,7 +7,7 @@ from __future__ import annotations
|
|||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
import ba
|
||||
import _ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bastd.ui.playlist.editcontroller import PlaylistEditController
|
||||
|
|
@ -58,8 +58,9 @@ class PlaylistEditWindow(ba.Window):
|
|||
text_scale=1.2)
|
||||
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
ba.widget(
|
||||
edit=btn,
|
||||
right_widget=ba.internal.get_special_widget('party_button'))
|
||||
|
||||
ba.widget(edit=cancel_button,
|
||||
left_widget=cancel_button,
|
||||
|
|
@ -283,7 +284,7 @@ class PlaylistEditWindow(ba.Window):
|
|||
|
||||
# If we had an old one, delete it.
|
||||
if self._editcontroller.get_existing_playlist_name() is not None:
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type':
|
||||
'REMOVE_PLAYLIST',
|
||||
'playlistType':
|
||||
|
|
@ -292,13 +293,13 @@ class PlaylistEditWindow(ba.Window):
|
|||
self._editcontroller.get_existing_playlist_name()
|
||||
})
|
||||
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'ADD_PLAYLIST',
|
||||
'playlistType': self._editcontroller.get_config_name(),
|
||||
'playlistName': new_name,
|
||||
'playlist': self._editcontroller.get_playlist()
|
||||
})
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
ba.playsound(ba.getsound('gunCocking'))
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ class PlaylistEditController:
|
|||
appconfig[self._pvars.config_name +
|
||||
' Playlists'][existing_playlist_name],
|
||||
sessiontype=sessiontype,
|
||||
remove_unowned=False)
|
||||
remove_unowned=False,
|
||||
name=existing_playlist_name)
|
||||
self._edit_ui_selection = None
|
||||
else:
|
||||
if playlist is not None:
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import copy
|
|||
import random
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
|
@ -134,7 +134,7 @@ class PlaylistEditGameWindow(ba.Window):
|
|||
resource='doneText'))
|
||||
|
||||
if ba.app.ui.use_toolbars:
|
||||
pbtn = _ba.get_special_widget('party_button')
|
||||
pbtn = ba.internal.get_special_widget('party_button')
|
||||
ba.widget(edit=add_button, right_widget=pbtn, up_widget=pbtn)
|
||||
|
||||
ba.textwidget(parent=self._root_widget,
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
import math
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
|
@ -165,9 +165,9 @@ class PlaylistMapSelectWindow(ba.Window):
|
|||
if y == 0:
|
||||
ba.widget(edit=btn, up_widget=self._cancel_button)
|
||||
if x == columns - 1 and ba.app.ui.use_toolbars:
|
||||
ba.widget(
|
||||
edit=btn,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
ba.widget(edit=btn,
|
||||
right_widget=ba.internal.get_special_widget(
|
||||
'party_button'))
|
||||
|
||||
ba.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60)
|
||||
if self._maps[index][0] == self._previous_map:
|
||||
|
|
@ -210,7 +210,7 @@ class PlaylistMapSelectWindow(ba.Window):
|
|||
def _on_store_press(self) -> None:
|
||||
from bastd.ui import account
|
||||
from bastd.ui.store.browser import StoreBrowserWindow
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
account.show_sign_in_prompt()
|
||||
return
|
||||
StoreBrowserWindow(modal=True,
|
||||
|
|
@ -236,8 +236,8 @@ class PlaylistMapSelectWindow(ba.Window):
|
|||
edit_info=self._edit_info).get_root_widget())
|
||||
|
||||
def _select_with_delay(self, map_name: str) -> None:
|
||||
_ba.lock_all_input()
|
||||
ba.timer(0.1, _ba.unlock_all_input, timetype=ba.TimeType.REAL)
|
||||
ba.internal.lock_all_input()
|
||||
ba.timer(0.1, ba.internal.unlock_all_input, timetype=ba.TimeType.REAL)
|
||||
ba.timer(0.1,
|
||||
ba.WeakCall(self._select, map_name),
|
||||
timetype=ba.TimeType.REAL)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.ui import promocode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -50,14 +50,14 @@ class SharePlaylistImportWindow(promocode.PromoCodeWindow):
|
|||
transition=self._transition_out)
|
||||
|
||||
def _do_enter(self) -> None:
|
||||
_ba.add_transaction(
|
||||
ba.internal.add_transaction(
|
||||
{
|
||||
'type': 'IMPORT_PLAYLIST',
|
||||
'expire_time': time.time() + 5,
|
||||
'code': ba.textwidget(query=self._text_field)
|
||||
},
|
||||
callback=ba.WeakCall(self._on_import_response))
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
ba.screenmessage(ba.Lstr(resource='importingText'))
|
||||
|
||||
|
||||
|
|
|
|||
17
dist/ba_data/python/bastd/ui/playoptions.py
vendored
17
dist/ba_data/python/bastd/ui/playoptions.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.ui import popup
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -86,7 +86,8 @@ class PlayOptionsWindow(popup.PopupWindow):
|
|||
plst = filter_playlist(plst,
|
||||
self._sessiontype,
|
||||
remove_unowned=False,
|
||||
mark_unowned=True)
|
||||
mark_unowned=True,
|
||||
name=name)
|
||||
game_count = len(plst)
|
||||
for entry in plst:
|
||||
mapname = entry['settings']['map']
|
||||
|
|
@ -349,7 +350,7 @@ class PlayOptionsWindow(popup.PopupWindow):
|
|||
from bastd.ui.teamnamescolors import TeamNamesColorsWindow
|
||||
from bastd.ui.purchase import PurchaseWindow
|
||||
if not ba.app.accounts_v1.have_pro():
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
else:
|
||||
PurchaseWindow(items=['pro'])
|
||||
|
|
@ -417,8 +418,8 @@ class PlayOptionsWindow(popup.PopupWindow):
|
|||
if self._delegate is not None:
|
||||
self._delegate.on_play_options_window_run_game()
|
||||
else:
|
||||
_ba.fade_screen(False, endcall=self._run_selected_playlist)
|
||||
_ba.lock_all_input()
|
||||
ba.internal.fade_screen(False, endcall=self._run_selected_playlist)
|
||||
ba.internal.lock_all_input()
|
||||
self._transition_out(transition='out_left')
|
||||
if self._delegate is not None:
|
||||
self._delegate.on_play_options_window_run_game()
|
||||
|
|
@ -426,12 +427,12 @@ class PlayOptionsWindow(popup.PopupWindow):
|
|||
cfg.commit()
|
||||
|
||||
def _run_selected_playlist(self) -> None:
|
||||
_ba.unlock_all_input()
|
||||
ba.internal.unlock_all_input()
|
||||
try:
|
||||
_ba.new_host_session(self._sessiontype)
|
||||
ba.internal.new_host_session(self._sessiontype)
|
||||
except Exception:
|
||||
from bastd import mainmenu
|
||||
ba.print_exception('exception running session', self._sessiontype)
|
||||
|
||||
# Drop back into a main menu session.
|
||||
_ba.new_host_session(mainmenu.MainMenuSession)
|
||||
ba.internal.new_host_session(mainmenu.MainMenuSession)
|
||||
|
|
|
|||
12
dist/ba_data/python/bastd/ui/popup.py
vendored
12
dist/ba_data/python/bastd/ui/popup.py
vendored
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
import weakref
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence, Callable
|
||||
|
|
@ -81,7 +81,7 @@ class PopupWindow:
|
|||
scale=scale,
|
||||
toolbar_visibility=toolbar_visibility,
|
||||
size=size,
|
||||
parent=_ba.get_special_widget('overlay_stack'),
|
||||
parent=ba.internal.get_special_widget('overlay_stack'),
|
||||
stack_offset=(x_fin - x_offs, y_fin - y_offs),
|
||||
scale_origin_stack_offset=(position[0], position[1]),
|
||||
on_outside_click_call=self.on_popup_cancel,
|
||||
|
|
@ -159,15 +159,15 @@ class PopupMenuWindow(PopupWindow):
|
|||
self._width,
|
||||
min(
|
||||
maxwidth,
|
||||
_ba.get_string_width(choice_display_name,
|
||||
suppress_warning=True)) + 75)
|
||||
ba.internal.get_string_width(
|
||||
choice_display_name, suppress_warning=True)) + 75)
|
||||
else:
|
||||
self._width = max(
|
||||
self._width,
|
||||
min(
|
||||
maxwidth,
|
||||
_ba.get_string_width(choice_display_name,
|
||||
suppress_warning=True)) + 60)
|
||||
ba.internal.get_string_width(
|
||||
choice_display_name, suppress_warning=True)) + 60)
|
||||
|
||||
# init parent class - this will rescale and reposition things as
|
||||
# needed and create our root widget
|
||||
|
|
|
|||
15
dist/ba_data/python/bastd/ui/profile/browser.py
vendored
15
dist/ba_data/python/bastd/ui/profile/browser.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -174,7 +174,8 @@ class ProfileBrowserWindow(ba.Window):
|
|||
from bastd.ui.purchase import PurchaseWindow
|
||||
|
||||
# Limit to a handful profiles if they don't have pro-options.
|
||||
max_non_pro_profiles = _ba.get_v1_account_misc_read_val('mnpp', 5)
|
||||
max_non_pro_profiles = ba.internal.get_v1_account_misc_read_val(
|
||||
'mnpp', 5)
|
||||
assert self._profiles is not None
|
||||
if (not ba.app.accounts_v1.have_pro_options()
|
||||
and len(self._profiles) >= max_non_pro_profiles):
|
||||
|
|
@ -221,11 +222,11 @@ class ProfileBrowserWindow(ba.Window):
|
|||
self._do_delete_profile, 350)
|
||||
|
||||
def _do_delete_profile(self) -> None:
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'REMOVE_PLAYER_PROFILE',
|
||||
'name': self._selected_profile
|
||||
})
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
ba.playsound(ba.getsound('shieldDown'))
|
||||
self._refresh()
|
||||
|
||||
|
|
@ -283,8 +284,8 @@ class ProfileBrowserWindow(ba.Window):
|
|||
items.sort(key=lambda x: asserttype(x[0], str).lower())
|
||||
index = 0
|
||||
account_name: str | None
|
||||
if _ba.get_v1_account_state() == 'signed_in':
|
||||
account_name = _ba.get_v1_account_display_string()
|
||||
if ba.internal.get_v1_account_state() == 'signed_in':
|
||||
account_name = ba.internal.get_v1_account_display_string()
|
||||
else:
|
||||
account_name = None
|
||||
widget_to_select = None
|
||||
|
|
@ -330,7 +331,7 @@ class ProfileBrowserWindow(ba.Window):
|
|||
|
||||
# If there's a team-chooser in existence, tell it the profile-list
|
||||
# has probably changed.
|
||||
session = _ba.get_foreground_host_session()
|
||||
session = ba.internal.get_foreground_host_session()
|
||||
if session is not None:
|
||||
session.handlemessage(PlayerProfilesChangedMessage())
|
||||
|
||||
|
|
|
|||
30
dist/ba_data/python/bastd/ui/profile/edit.py
vendored
30
dist/ba_data/python/bastd/ui/profile/edit.py
vendored
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
import random
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bastd.ui.colorpicker import ColorPicker
|
||||
|
|
@ -144,7 +144,7 @@ class EditProfileWindow(ba.Window):
|
|||
|
||||
# Assign a random name if they had none.
|
||||
if self._name == '':
|
||||
names = _ba.get_random_names()
|
||||
names = ba.internal.get_random_names()
|
||||
self._name = names[random.randrange(len(names))]
|
||||
|
||||
self._clipped_name_text = ba.textwidget(parent=self._root_widget,
|
||||
|
|
@ -172,8 +172,8 @@ class EditProfileWindow(ba.Window):
|
|||
|
||||
self._upgrade_button = None
|
||||
if self._is_account_profile:
|
||||
if _ba.get_v1_account_state() == 'signed_in':
|
||||
sval = _ba.get_v1_account_display_string()
|
||||
if ba.internal.get_v1_account_state() == 'signed_in':
|
||||
sval = ba.internal.get_v1_account_display_string()
|
||||
else:
|
||||
sval = '??'
|
||||
ba.textwidget(parent=self._root_widget,
|
||||
|
|
@ -188,7 +188,8 @@ class EditProfileWindow(ba.Window):
|
|||
resource='editProfileWindow.accountProfileText').evaluate()
|
||||
b_width = min(
|
||||
270.0,
|
||||
_ba.get_string_width(txtl, suppress_warning=True) * 0.6)
|
||||
ba.internal.get_string_width(txtl, suppress_warning=True) *
|
||||
0.6)
|
||||
ba.textwidget(parent=self._root_widget,
|
||||
position=(self._width * 0.5, v - 39),
|
||||
size=(0, 0),
|
||||
|
|
@ -258,7 +259,8 @@ class EditProfileWindow(ba.Window):
|
|||
resource='editProfileWindow.globalProfileText').evaluate()
|
||||
b_width = min(
|
||||
240.0,
|
||||
_ba.get_string_width(txtl, suppress_warning=True) * 0.6)
|
||||
ba.internal.get_string_width(txtl, suppress_warning=True) *
|
||||
0.6)
|
||||
ba.textwidget(parent=self._root_widget,
|
||||
position=(self._width * 0.5, v - 39),
|
||||
size=(0, 0),
|
||||
|
|
@ -299,7 +301,8 @@ class EditProfileWindow(ba.Window):
|
|||
resource='editProfileWindow.localProfileText').evaluate()
|
||||
b_width = min(
|
||||
270.0,
|
||||
_ba.get_string_width(txtl, suppress_warning=True) * 0.6)
|
||||
ba.internal.get_string_width(txtl, suppress_warning=True) *
|
||||
0.6)
|
||||
ba.textwidget(parent=self._root_widget,
|
||||
position=(self._width * 0.5, v - 43),
|
||||
size=(0, 0),
|
||||
|
|
@ -426,7 +429,7 @@ class EditProfileWindow(ba.Window):
|
|||
"""Attempt to ugrade the profile to global."""
|
||||
from bastd.ui import account
|
||||
from bastd.ui.profile import upgrade as pupgrade
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
account.show_sign_in_prompt()
|
||||
return
|
||||
|
||||
|
|
@ -592,8 +595,9 @@ class EditProfileWindow(ba.Window):
|
|||
return
|
||||
name = self.getname()
|
||||
if name == '__account__':
|
||||
name = (_ba.get_v1_account_name()
|
||||
if _ba.get_v1_account_state() == 'signed_in' else '???')
|
||||
name = (ba.internal.get_v1_account_name()
|
||||
if ba.internal.get_v1_account_state() == 'signed_in' else
|
||||
'???')
|
||||
if len(name) > 10 and not (self._global or self._is_account_profile):
|
||||
ba.textwidget(edit=self._clipped_name_text,
|
||||
text=ba.Lstr(resource='inGameClippedNameText',
|
||||
|
|
@ -640,7 +644,7 @@ class EditProfileWindow(ba.Window):
|
|||
|
||||
# Delete old in case we're renaming.
|
||||
if self._existing_profile and self._existing_profile != new_name:
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'REMOVE_PLAYER_PROFILE',
|
||||
'name': self._existing_profile
|
||||
})
|
||||
|
|
@ -649,7 +653,7 @@ class EditProfileWindow(ba.Window):
|
|||
# new name (will need to re-request it).
|
||||
self._global = False
|
||||
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'ADD_PLAYER_PROFILE',
|
||||
'name': new_name,
|
||||
'profile': {
|
||||
|
|
@ -662,7 +666,7 @@ class EditProfileWindow(ba.Window):
|
|||
})
|
||||
|
||||
if transition_out:
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
ba.app.ui.set_main_menu_window(
|
||||
ProfileBrowserWindow(
|
||||
|
|
|
|||
16
dist/ba_data/python/bastd/ui/profile/upgrade.py
vendored
16
dist/ba_data/python/bastd/ui/profile/upgrade.py
vendored
|
|
@ -8,8 +8,8 @@ import time
|
|||
import weakref
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -126,8 +126,8 @@ class ProfileUpgradeWindow(ba.Window):
|
|||
'b': ba.app.build_number
|
||||
},
|
||||
callback=ba.WeakCall(self._profile_check_result))
|
||||
self._cost = _ba.get_v1_account_misc_read_val('price.global_profile',
|
||||
500)
|
||||
self._cost = ba.internal.get_v1_account_misc_read_val(
|
||||
'price.global_profile', 500)
|
||||
self._status: str | None = 'waiting'
|
||||
self._update_timer = ba.Timer(1.0,
|
||||
ba.WeakCall(self._update),
|
||||
|
|
@ -170,7 +170,7 @@ class ProfileUpgradeWindow(ba.Window):
|
|||
from bastd.ui import getcurrency
|
||||
if self._status is None:
|
||||
# If it appears we don't have enough tickets, offer to buy more.
|
||||
tickets = _ba.get_v1_account_ticket_count()
|
||||
tickets = ba.internal.get_v1_account_ticket_count()
|
||||
if tickets < self._cost:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
getcurrency.show_get_tickets_prompt()
|
||||
|
|
@ -193,11 +193,11 @@ class ProfileUpgradeWindow(ba.Window):
|
|||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'UPGRADE_PROFILE',
|
||||
'name': self._name
|
||||
})
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
self._status = 'upgrading'
|
||||
self._upgrade_start_time = time.time()
|
||||
else:
|
||||
|
|
@ -205,7 +205,7 @@ class ProfileUpgradeWindow(ba.Window):
|
|||
|
||||
def _update(self) -> None:
|
||||
try:
|
||||
t_str = str(_ba.get_v1_account_ticket_count())
|
||||
t_str = str(ba.internal.get_v1_account_ticket_count())
|
||||
except Exception:
|
||||
t_str = '?'
|
||||
if self._tickets_text is not None:
|
||||
|
|
@ -219,7 +219,7 @@ class ProfileUpgradeWindow(ba.Window):
|
|||
# Once we've kicked off an upgrade attempt and all transactions go
|
||||
# through, we're done.
|
||||
if (self._status == 'upgrading'
|
||||
and not _ba.have_outstanding_transactions()):
|
||||
and not ba.internal.have_outstanding_transactions()):
|
||||
self._status = 'exiting'
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
edit_profile_window = self._edit_profile_window()
|
||||
|
|
|
|||
6
dist/ba_data/python/bastd/ui/promocode.py
vendored
6
dist/ba_data/python/bastd/ui/promocode.py
vendored
|
|
@ -7,8 +7,8 @@ from __future__ import annotations
|
|||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -112,9 +112,9 @@ class PromoCodeWindow(ba.Window):
|
|||
if not self._modal:
|
||||
ba.app.ui.set_main_menu_window(
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget())
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'PROMO_CODE',
|
||||
'expire_time': time.time() + 5,
|
||||
'code': ba.textwidget(query=self._text_field)
|
||||
})
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
|
|
|||
14
dist/ba_data/python/bastd/ui/purchase.py
vendored
14
dist/ba_data/python/bastd/ui/purchase.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -68,11 +68,11 @@ class PurchaseWindow(ba.Window):
|
|||
pass # not working
|
||||
else:
|
||||
if self._items == ['pro']:
|
||||
price_str = _ba.get_price(self._items[0])
|
||||
price_str = ba.internal.get_price(self._items[0])
|
||||
pyoffs = -15
|
||||
else:
|
||||
pyoffs = 0
|
||||
price = self._price = _ba.get_v1_account_misc_read_val(
|
||||
price = self._price = ba.internal.get_v1_account_misc_read_val(
|
||||
'price.' + str(items[0]), -1)
|
||||
price_str = ba.charstr(ba.SpecialChar.TICKET) + str(price)
|
||||
self._price_text = ba.textwidget(parent=self._root_widget,
|
||||
|
|
@ -121,7 +121,7 @@ class PurchaseWindow(ba.Window):
|
|||
if ba.app.accounts_v1.have_pro():
|
||||
can_die = True
|
||||
else:
|
||||
if _ba.get_purchased(self._items[0]):
|
||||
if ba.internal.get_purchased(self._items[0]):
|
||||
can_die = True
|
||||
|
||||
if can_die:
|
||||
|
|
@ -130,11 +130,11 @@ class PurchaseWindow(ba.Window):
|
|||
def _purchase(self) -> None:
|
||||
from bastd.ui import getcurrency
|
||||
if self._items == ['pro']:
|
||||
_ba.purchase('pro')
|
||||
ba.internal.purchase('pro')
|
||||
else:
|
||||
ticket_count: int | None
|
||||
try:
|
||||
ticket_count = _ba.get_v1_account_ticket_count()
|
||||
ticket_count = ba.internal.get_v1_account_ticket_count()
|
||||
except Exception:
|
||||
ticket_count = None
|
||||
if ticket_count is not None and ticket_count < self._price:
|
||||
|
|
@ -143,7 +143,7 @@ class PurchaseWindow(ba.Window):
|
|||
return
|
||||
|
||||
def do_it() -> None:
|
||||
_ba.in_game_purchase(self._items[0], self._price)
|
||||
ba.internal.in_game_purchase(self._items[0], self._price)
|
||||
|
||||
ba.playsound(ba.getsound('swish'))
|
||||
do_it()
|
||||
|
|
|
|||
12
dist/ba_data/python/bastd/ui/report.py
vendored
12
dist/ba_data/python/bastd/ui/report.py
vendored
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
|
||||
class ReportPlayerWindow(ba.Window):
|
||||
|
|
@ -18,7 +18,7 @@ class ReportPlayerWindow(ba.Window):
|
|||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
|
||||
overlay_stack = _ba.get_special_widget('overlay_stack')
|
||||
overlay_stack = ba.internal.get_special_widget('overlay_stack')
|
||||
uiscale = ba.app.ui.uiscale
|
||||
super().__init__(root_widget=ba.containerwidget(
|
||||
size=(self._width, self._height),
|
||||
|
|
@ -63,27 +63,27 @@ class ReportPlayerWindow(ba.Window):
|
|||
|
||||
def _on_language_press(self) -> None:
|
||||
from urllib import parse
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'REPORT_ACCOUNT',
|
||||
'reason': 'language',
|
||||
'account': self._account_id
|
||||
})
|
||||
body = ba.Lstr(resource='reportPlayerExplanationText').evaluate()
|
||||
ba.open_url('mailto:support@froemling.net'
|
||||
f'?subject={_ba.appnameupper()} Player Report: ' +
|
||||
f'?subject={ba.internal.appnameupper()} Player Report: ' +
|
||||
self._account_id + '&body=' + parse.quote(body))
|
||||
self.close()
|
||||
|
||||
def _on_cheating_press(self) -> None:
|
||||
from urllib import parse
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'REPORT_ACCOUNT',
|
||||
'reason': 'cheating',
|
||||
'account': self._account_id
|
||||
})
|
||||
body = ba.Lstr(resource='reportPlayerExplanationText').evaluate()
|
||||
ba.open_url('mailto:support@froemling.net'
|
||||
f'?subject={_ba.appnameupper()} Player Report: ' +
|
||||
f'?subject={ba.internal.appnameupper()} Player Report: ' +
|
||||
self._account_id + '&body=' + parse.quote(body))
|
||||
self.close()
|
||||
|
||||
|
|
|
|||
102
dist/ba_data/python/bastd/ui/serverdialog.py
vendored
102
dist/ba_data/python/bastd/ui/serverdialog.py
vendored
|
|
@ -4,35 +4,52 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
import logging
|
||||
from dataclasses import dataclass, field
|
||||
from typing import TYPE_CHECKING, Annotated
|
||||
|
||||
from efro.dataclassio import ioprepped, IOAttrs
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
pass
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class ServerDialogData:
|
||||
"""Data for ServerDialog."""
|
||||
dialog_id: Annotated[str, IOAttrs('dialogID')]
|
||||
text: Annotated[str, IOAttrs('text')]
|
||||
subs: Annotated[list[tuple[str, str]],
|
||||
IOAttrs('subs')] = field(default_factory=list)
|
||||
show_cancel: Annotated[bool, IOAttrs('showCancel')] = True
|
||||
copy_text: Annotated[str | None, IOAttrs('copyText')] = None
|
||||
|
||||
|
||||
class ServerDialogWindow(ba.Window):
|
||||
"""A dialog window driven by the master-server."""
|
||||
|
||||
def __init__(self, data: dict[str, Any]):
|
||||
self._dialog_id = data['dialogID']
|
||||
txt = ba.Lstr(translate=('serverResponses', data['text']),
|
||||
subs=data.get('subs', [])).evaluate()
|
||||
def __init__(self, data: ServerDialogData):
|
||||
self._data = data
|
||||
txt = ba.Lstr(translate=('serverResponses', data.text),
|
||||
subs=data.subs).evaluate()
|
||||
txt = txt.strip()
|
||||
txt_scale = 1.5
|
||||
txt_height = (_ba.get_string_height(txt, suppress_warning=True) *
|
||||
txt_scale)
|
||||
txt_height = (
|
||||
ba.internal.get_string_height(txt, suppress_warning=True) *
|
||||
txt_scale)
|
||||
self._width = 500
|
||||
self._height = 130 + min(200, txt_height)
|
||||
self._height = 160 + min(200, txt_height)
|
||||
uiscale = ba.app.ui.uiscale
|
||||
super().__init__(root_widget=ba.containerwidget(
|
||||
size=(self._width, self._height),
|
||||
transition='in_scale',
|
||||
scale=(1.8 if uiscale is ba.UIScale.SMALL else
|
||||
1.35 if uiscale is ba.UIScale.MEDIUM else 1.0)))
|
||||
self._starttime = ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS)
|
||||
self._starttime = ba.time(ba.TimeType.REAL)
|
||||
|
||||
ba.playsound(ba.getsound('swish'))
|
||||
ba.textwidget(parent=self._root_widget,
|
||||
|
|
@ -46,51 +63,72 @@ class ServerDialogWindow(ba.Window):
|
|||
text=txt,
|
||||
maxwidth=self._width * 0.85,
|
||||
max_height=(self._height - 110))
|
||||
show_cancel = data.get('showCancel', True)
|
||||
self._cancel_button: ba.Widget | None
|
||||
if show_cancel:
|
||||
self._cancel_button = ba.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(30, 30),
|
||||
size=(160, 60),
|
||||
autoselect=True,
|
||||
label=ba.Lstr(resource='cancelText'),
|
||||
on_activate_call=self._cancel_press)
|
||||
else:
|
||||
self._cancel_button = None
|
||||
|
||||
show_copy = data.copy_text is not None and ba.clipboard_is_supported()
|
||||
|
||||
# Currently can't do both copy and cancel since they go in the same
|
||||
# spot. Cancel wins in this case since it is important functionality
|
||||
# and copy is just for convenience (and not even always available).
|
||||
if show_copy and data.show_cancel:
|
||||
logging.warning('serverdialog requesting both copy and cancel;'
|
||||
' copy will not be shown.')
|
||||
show_copy = False
|
||||
|
||||
self._cancel_button = (None
|
||||
if not data.show_cancel else ba.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(30, 30),
|
||||
size=(160, 60),
|
||||
autoselect=True,
|
||||
label=ba.Lstr(resource='cancelText'),
|
||||
on_activate_call=self._cancel_press))
|
||||
|
||||
self._copy_button = None if not show_copy else ba.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(30, 30),
|
||||
size=(160, 60),
|
||||
autoselect=True,
|
||||
label=ba.Lstr(resource='copyText'),
|
||||
on_activate_call=self._copy_press)
|
||||
|
||||
self._ok_button = ba.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=((self._width - 182) if show_cancel else
|
||||
position=((self._width - 182) if
|
||||
(data.show_cancel or show_copy) else
|
||||
(self._width * 0.5 - 80), 30),
|
||||
size=(160, 60),
|
||||
autoselect=True,
|
||||
label=ba.Lstr(resource='okText'),
|
||||
on_activate_call=self._ok_press)
|
||||
|
||||
ba.containerwidget(edit=self._root_widget,
|
||||
cancel_button=self._cancel_button,
|
||||
start_button=self._ok_button,
|
||||
selected_child=self._ok_button)
|
||||
|
||||
def _copy_press(self) -> None:
|
||||
assert self._data.copy_text is not None
|
||||
ba.clipboard_set_text(self._data.copy_text)
|
||||
ba.screenmessage(ba.Lstr(resource='copyConfirmText'), color=(0, 1, 0))
|
||||
|
||||
def _ok_press(self) -> None:
|
||||
if ba.time(ba.TimeType.REAL,
|
||||
ba.TimeFormat.MILLISECONDS) - self._starttime < 1000:
|
||||
if ba.time(ba.TimeType.REAL) - self._starttime < 1.0:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'DIALOG_RESPONSE',
|
||||
'dialogID': self._dialog_id,
|
||||
'dialogID': self._data.dialog_id,
|
||||
'response': 1
|
||||
})
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_scale')
|
||||
|
||||
def _cancel_press(self) -> None:
|
||||
if ba.time(ba.TimeType.REAL,
|
||||
ba.TimeFormat.MILLISECONDS) - self._starttime < 1000:
|
||||
if ba.time(ba.TimeType.REAL) - self._starttime < 1.0:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'DIALOG_RESPONSE',
|
||||
'dialogID': self._dialog_id,
|
||||
'dialogID': self._data.dialog_id,
|
||||
'response': 0
|
||||
})
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_scale')
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
from bastd.ui import popup as popup_ui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -200,10 +200,10 @@ class AdvancedSettingsWindow(ba.Window):
|
|||
# menu based on the language so still need this. ...however we could
|
||||
# make this more limited to it only rebuilds that one menu instead
|
||||
# of everything.
|
||||
if self._menu_open or (self._prev_lang == _ba.app.config.get(
|
||||
if self._menu_open or (self._prev_lang == ba.app.config.get(
|
||||
'Lang', None) and self._prev_lang_list == available_languages):
|
||||
return
|
||||
self._prev_lang = _ba.app.config.get('Lang', None)
|
||||
self._prev_lang = ba.app.config.get('Lang', None)
|
||||
self._prev_lang_list = available_languages
|
||||
|
||||
# Clear out our sub-container.
|
||||
|
|
@ -251,8 +251,8 @@ class AdvancedSettingsWindow(ba.Window):
|
|||
h_align='right',
|
||||
v_align='center')
|
||||
|
||||
languages = _ba.app.lang.available_languages
|
||||
cur_lang = _ba.app.config.get('Lang', None)
|
||||
languages = ba.app.lang.available_languages
|
||||
cur_lang = ba.app.config.get('Lang', None)
|
||||
if cur_lang is None:
|
||||
cur_lang = 'Auto'
|
||||
|
||||
|
|
@ -340,7 +340,7 @@ class AdvancedSettingsWindow(ba.Window):
|
|||
self._update_lang_status()
|
||||
v -= 40
|
||||
|
||||
lang_inform = _ba.get_v1_account_misc_val('langInform', False)
|
||||
lang_inform = ba.internal.get_v1_account_misc_val('langInform', False)
|
||||
|
||||
self._language_inform_checkbox = cbw = ba.checkboxwidget(
|
||||
parent=self._subcontainer,
|
||||
|
|
@ -432,7 +432,7 @@ class AdvancedSettingsWindow(ba.Window):
|
|||
label=ba.Lstr(resource=self._r + '.moddingGuideText'),
|
||||
text_scale=1.0,
|
||||
on_activate_call=ba.Call(
|
||||
ba.open_url, 'http://ballistica.net/wiki/modding-guide'))
|
||||
ba.open_url, 'https://ballistica.net/wiki/modding-guide'))
|
||||
if self._show_always_use_internal_keyboard:
|
||||
assert self._always_use_internal_keyboard_check_box is not None
|
||||
ba.widget(edit=self._always_use_internal_keyboard_check_box.widget,
|
||||
|
|
@ -512,11 +512,12 @@ class AdvancedSettingsWindow(ba.Window):
|
|||
ba.widget(edit=child, show_buffer_bottom=30, show_buffer_top=20)
|
||||
|
||||
if ba.app.ui.use_toolbars:
|
||||
pbtn = _ba.get_special_widget('party_button')
|
||||
pbtn = ba.internal.get_special_widget('party_button')
|
||||
ba.widget(edit=self._scrollwidget, right_widget=pbtn)
|
||||
if self._back_button is None:
|
||||
ba.widget(edit=self._scrollwidget,
|
||||
left_widget=_ba.get_special_widget('back_button'))
|
||||
ba.widget(
|
||||
edit=self._scrollwidget,
|
||||
left_widget=ba.internal.get_special_widget('back_button'))
|
||||
|
||||
self._restore_state()
|
||||
|
||||
|
|
@ -526,12 +527,12 @@ class AdvancedSettingsWindow(ba.Window):
|
|||
color=(1, 1, 0))
|
||||
|
||||
def _on_lang_inform_value_change(self, val: bool) -> None:
|
||||
_ba.add_transaction({
|
||||
ba.internal.add_transaction({
|
||||
'type': 'SET_MISC_VAL',
|
||||
'name': 'langInform',
|
||||
'value': val
|
||||
})
|
||||
_ba.run_transactions()
|
||||
ba.internal.run_transactions()
|
||||
|
||||
def _on_vr_test_press(self) -> None:
|
||||
from bastd.ui.settings.vrtesting import VRTestingWindow
|
||||
|
|
@ -544,7 +545,7 @@ class AdvancedSettingsWindow(ba.Window):
|
|||
from bastd.ui.settings.nettesting import NetTestingWindow
|
||||
|
||||
# Net-testing requires a signed in v1 account.
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
ba.screenmessage(ba.Lstr(resource='notSignedInErrorText'),
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
|
|
@ -558,7 +559,7 @@ class AdvancedSettingsWindow(ba.Window):
|
|||
def _on_friend_promo_code_press(self) -> None:
|
||||
from bastd.ui import appinvite
|
||||
from bastd.ui import account
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
account.show_sign_in_prompt()
|
||||
return
|
||||
appinvite.handle_app_invites_press()
|
||||
|
|
@ -576,7 +577,7 @@ class AdvancedSettingsWindow(ba.Window):
|
|||
from bastd.ui.account import show_sign_in_prompt
|
||||
|
||||
# We have to be logged in for promo-codes to work.
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
if ba.internal.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
self._save_state()
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -118,7 +118,7 @@ class AllSettingsWindow(ba.Window):
|
|||
label='',
|
||||
on_activate_call=self._do_controllers)
|
||||
if ba.app.ui.use_toolbars and self._back_button is None:
|
||||
bbtn = _ba.get_special_widget('back_button')
|
||||
bbtn = ba.internal.get_special_widget('back_button')
|
||||
ba.widget(edit=ctb, left_widget=bbtn)
|
||||
_b_title(x_offs2, v, ctb,
|
||||
ba.Lstr(resource=self._r + '.controllersText'))
|
||||
|
|
@ -138,7 +138,7 @@ class AllSettingsWindow(ba.Window):
|
|||
label='',
|
||||
on_activate_call=self._do_graphics)
|
||||
if ba.app.ui.use_toolbars:
|
||||
pbtn = _ba.get_special_widget('party_button')
|
||||
pbtn = ba.internal.get_special_widget('party_button')
|
||||
ba.widget(edit=gfxb, up_widget=pbtn, right_widget=pbtn)
|
||||
_b_title(x_offs3, v, gfxb, ba.Lstr(resource=self._r + '.graphicsText'))
|
||||
imgw = imgh = 110
|
||||
|
|
|
|||
12
dist/ba_data/python/bastd/ui/settings/audio.py
vendored
12
dist/ba_data/python/bastd/ui/settings/audio.py
vendored
|
|
@ -6,8 +6,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
import ba
|
||||
import ba.internal
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -105,8 +105,9 @@ class AudioSettingsWindow(ba.Window):
|
|||
maxval=1.0,
|
||||
increment=0.1)
|
||||
if ba.app.ui.use_toolbars:
|
||||
ba.widget(edit=svne.plusbutton,
|
||||
right_widget=_ba.get_special_widget('party_button'))
|
||||
ba.widget(
|
||||
edit=svne.plusbutton,
|
||||
right_widget=ba.internal.get_special_widget('party_button'))
|
||||
v -= spacing
|
||||
self._music_volume_numedit = ConfigNumberEdit(
|
||||
parent=self._root_widget,
|
||||
|
|
@ -208,12 +209,13 @@ class AudioSettingsWindow(ba.Window):
|
|||
|
||||
# We require disk access for soundtracks;
|
||||
# if we don't have it, request it.
|
||||
if not _ba.have_permission(ba.Permission.STORAGE):
|
||||
if not ba.internal.have_permission(ba.Permission.STORAGE):
|
||||
ba.playsound(ba.getsound('ding'))
|
||||
ba.screenmessage(ba.Lstr(resource='storagePermissionAccessText'),
|
||||
color=(0.5, 1, 0.5))
|
||||
ba.timer(1.0,
|
||||
ba.Call(_ba.request_permission, ba.Permission.STORAGE),
|
||||
ba.Call(ba.internal.request_permission,
|
||||
ba.Permission.STORAGE),
|
||||
timetype=ba.TimeType.REAL)
|
||||
return
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue