mirror of
https://github.com/imayushsaini/Bombsquad-Ballistica-Modded-Server.git
synced 2025-10-20 00:00:39 +00:00
update from origin
This commit is contained in:
parent
8beb334d64
commit
bf2f252ee5
91 changed files with 1839 additions and 1281 deletions
29
dist/ba_data/python/babase/__init__.py
vendored
29
dist/ba_data/python/babase/__init__.py
vendored
|
|
@ -27,6 +27,7 @@ from _babase import (
|
|||
apptime,
|
||||
apptimer,
|
||||
AppTimer,
|
||||
can_toggle_fullscreen,
|
||||
charstr,
|
||||
clipboard_get_text,
|
||||
clipboard_has_text,
|
||||
|
|
@ -39,6 +40,7 @@ from _babase import (
|
|||
DisplayTimer,
|
||||
do_once,
|
||||
env,
|
||||
Env,
|
||||
fade_screen,
|
||||
fatal_error,
|
||||
get_display_resolution,
|
||||
|
|
@ -48,8 +50,9 @@ from _babase import (
|
|||
get_replays_dir,
|
||||
get_string_height,
|
||||
get_string_width,
|
||||
get_v1_cloud_log_file_path,
|
||||
getsimplesound,
|
||||
has_gamma_control,
|
||||
has_user_run_commands,
|
||||
have_chars,
|
||||
have_permission,
|
||||
in_logic_thread,
|
||||
|
|
@ -83,7 +86,12 @@ from _babase import (
|
|||
set_thread_name,
|
||||
set_ui_input_device,
|
||||
show_progress_bar,
|
||||
shutdown_suppress_begin,
|
||||
shutdown_suppress_end,
|
||||
shutdown_suppress_count,
|
||||
SimpleSound,
|
||||
supports_max_fps,
|
||||
supports_vsync,
|
||||
unlock_all_input,
|
||||
user_agent_string,
|
||||
Vec3,
|
||||
|
|
@ -96,12 +104,14 @@ from babase._appconfig import commit_app_config
|
|||
from babase._appintent import AppIntent, AppIntentDefault, AppIntentExec
|
||||
from babase._appmode import AppMode
|
||||
from babase._appsubsystem import AppSubsystem
|
||||
from babase._appmodeselector import AppModeSelector
|
||||
from babase._appconfig import AppConfig
|
||||
from babase._apputils import (
|
||||
handle_leftover_v1_cloud_log_file,
|
||||
is_browser_likely_available,
|
||||
garbage_collect,
|
||||
get_remote_app_name,
|
||||
AppHealthMonitor,
|
||||
)
|
||||
from babase._cloud import CloudSubsystem
|
||||
from babase._emptyappmode import EmptyAppMode
|
||||
|
|
@ -135,7 +145,6 @@ from babase._general import (
|
|||
storagename,
|
||||
getclass,
|
||||
get_type_name,
|
||||
json_prep,
|
||||
)
|
||||
from babase._keyboard import Keyboard
|
||||
from babase._language import Lstr, LanguageSubsystem
|
||||
|
|
@ -153,6 +162,7 @@ from babase._math import normalized_color, is_point_in_box, vec3validate
|
|||
from babase._meta import MetadataSubsystem
|
||||
from babase._net import get_ip_address_type, DEFAULT_REQUEST_TIMEOUT_SECONDS
|
||||
from babase._plugin import PluginSpec, Plugin, PluginSubsystem
|
||||
from babase._stringedit import StringEditAdapter, StringEditSubsystem
|
||||
from babase._text import timestring
|
||||
|
||||
_babase.app = app = App()
|
||||
|
|
@ -169,12 +179,14 @@ __all__ = [
|
|||
'app',
|
||||
'App',
|
||||
'AppConfig',
|
||||
'AppHealthMonitor',
|
||||
'AppIntent',
|
||||
'AppIntentDefault',
|
||||
'AppIntentExec',
|
||||
'AppMode',
|
||||
'appname',
|
||||
'appnameupper',
|
||||
'AppModeSelector',
|
||||
'AppSubsystem',
|
||||
'apptime',
|
||||
'AppTime',
|
||||
|
|
@ -182,6 +194,7 @@ __all__ = [
|
|||
'apptimer',
|
||||
'AppTimer',
|
||||
'Call',
|
||||
'can_toggle_fullscreen',
|
||||
'charstr',
|
||||
'clipboard_get_text',
|
||||
'clipboard_has_text',
|
||||
|
|
@ -200,6 +213,7 @@ __all__ = [
|
|||
'do_once',
|
||||
'EmptyAppMode',
|
||||
'env',
|
||||
'Env',
|
||||
'Existable',
|
||||
'existing',
|
||||
'fade_screen',
|
||||
|
|
@ -214,11 +228,12 @@ __all__ = [
|
|||
'get_replays_dir',
|
||||
'get_string_height',
|
||||
'get_string_width',
|
||||
'get_v1_cloud_log_file_path',
|
||||
'get_type_name',
|
||||
'getclass',
|
||||
'getsimplesound',
|
||||
'handle_leftover_v1_cloud_log_file',
|
||||
'has_gamma_control',
|
||||
'has_user_run_commands',
|
||||
'have_chars',
|
||||
'have_permission',
|
||||
'in_logic_thread',
|
||||
|
|
@ -231,7 +246,6 @@ __all__ = [
|
|||
'is_point_in_box',
|
||||
'is_running_on_fire_tv',
|
||||
'is_xcode_build',
|
||||
'json_prep',
|
||||
'Keyboard',
|
||||
'LanguageSubsystem',
|
||||
'lock_all_input',
|
||||
|
|
@ -277,9 +291,16 @@ __all__ = [
|
|||
'set_thread_name',
|
||||
'set_ui_input_device',
|
||||
'show_progress_bar',
|
||||
'shutdown_suppress_begin',
|
||||
'shutdown_suppress_end',
|
||||
'shutdown_suppress_count',
|
||||
'SimpleSound',
|
||||
'SpecialChar',
|
||||
'storagename',
|
||||
'StringEditAdapter',
|
||||
'StringEditSubsystem',
|
||||
'supports_max_fps',
|
||||
'supports_vsync',
|
||||
'TeamNotFoundError',
|
||||
'timestring',
|
||||
'UIScale',
|
||||
|
|
|
|||
10
dist/ba_data/python/babase/_accountv2.py
vendored
10
dist/ba_data/python/babase/_accountv2.py
vendored
|
|
@ -64,7 +64,7 @@ class AccountV2Subsystem:
|
|||
|
||||
def set_primary_credentials(self, credentials: str | None) -> None:
|
||||
"""Set credentials for the primary app account."""
|
||||
raise RuntimeError('This should be overridden.')
|
||||
raise NotImplementedError('This should be overridden.')
|
||||
|
||||
def have_primary_credentials(self) -> bool:
|
||||
"""Are credentials currently set for the primary app account?
|
||||
|
|
@ -73,7 +73,7 @@ class AccountV2Subsystem:
|
|||
only that they exist. If/when credentials are validated, the 'primary'
|
||||
account handle will be set.
|
||||
"""
|
||||
raise RuntimeError('This should be overridden.')
|
||||
raise NotImplementedError('This should be overridden.')
|
||||
|
||||
@property
|
||||
def primary(self) -> AccountV2Handle | None:
|
||||
|
|
@ -128,7 +128,7 @@ class AccountV2Subsystem:
|
|||
# Ok; no workspace to worry about; carry on.
|
||||
if not self._initial_sign_in_completed:
|
||||
self._initial_sign_in_completed = True
|
||||
_babase.app.on_initial_sign_in_completed()
|
||||
_babase.app.on_initial_sign_in_complete()
|
||||
|
||||
def on_active_logins_changed(self, logins: dict[LoginType, str]) -> None:
|
||||
"""Should be called when logins for the active account change."""
|
||||
|
|
@ -163,7 +163,7 @@ class AccountV2Subsystem:
|
|||
"""
|
||||
if not self._initial_sign_in_completed:
|
||||
self._initial_sign_in_completed = True
|
||||
_babase.app.on_initial_sign_in_completed()
|
||||
_babase.app.on_initial_sign_in_complete()
|
||||
|
||||
@staticmethod
|
||||
def _hashstr(val: str) -> str:
|
||||
|
|
@ -409,7 +409,7 @@ class AccountV2Subsystem:
|
|||
def _on_set_active_workspace_completed(self) -> None:
|
||||
if not self._initial_sign_in_completed:
|
||||
self._initial_sign_in_completed = True
|
||||
_babase.app.on_initial_sign_in_completed()
|
||||
_babase.app.on_initial_sign_in_complete()
|
||||
|
||||
|
||||
class AccountV2Handle:
|
||||
|
|
|
|||
1127
dist/ba_data/python/babase/_app.py
vendored
1127
dist/ba_data/python/babase/_app.py
vendored
File diff suppressed because it is too large
Load diff
10
dist/ba_data/python/babase/_appcomponent.py
vendored
10
dist/ba_data/python/babase/_appcomponent.py
vendored
|
|
@ -50,7 +50,8 @@ class AppComponentSubsystem:
|
|||
# Currently limiting this to logic-thread use; can revisit if
|
||||
# needed (would need to guard access to our implementations
|
||||
# dict).
|
||||
assert _babase.in_logic_thread()
|
||||
if not _babase.in_logic_thread():
|
||||
raise RuntimeError('this must be called from the logic thread.')
|
||||
|
||||
if not issubclass(implementation, baseclass):
|
||||
raise TypeError(
|
||||
|
|
@ -73,7 +74,8 @@ class AppComponentSubsystem:
|
|||
If no custom implementation has been set, the provided
|
||||
base-class is returned.
|
||||
"""
|
||||
assert _babase.in_logic_thread()
|
||||
if not _babase.in_logic_thread():
|
||||
raise RuntimeError('this must be called from the logic thread.')
|
||||
|
||||
del baseclass # Unused.
|
||||
return cast(T, None)
|
||||
|
|
@ -87,7 +89,9 @@ class AppComponentSubsystem:
|
|||
loop. Note that any further setclass calls before the callback
|
||||
runs will not result in additional callbacks.
|
||||
"""
|
||||
assert _babase.in_logic_thread()
|
||||
if not _babase.in_logic_thread():
|
||||
raise RuntimeError('this must be called from the logic thread.')
|
||||
|
||||
self._change_callbacks.setdefault(baseclass, []).append(callback)
|
||||
|
||||
def _run_change_callbacks(self) -> None:
|
||||
|
|
|
|||
38
dist/ba_data/python/babase/_appconfig.py
vendored
38
dist/ba_data/python/babase/_appconfig.py
vendored
|
|
@ -3,6 +3,7 @@
|
|||
"""Provides the AppConfig class."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _babase
|
||||
|
|
@ -109,7 +110,7 @@ def read_app_config() -> tuple[AppConfig, bool]:
|
|||
|
||||
# NOTE: it is assumed that this only gets called once and the
|
||||
# config object will not change from here on out
|
||||
config_file_path = _babase.app.config_file_path
|
||||
config_file_path = _babase.app.env.config_file_path
|
||||
config_contents = ''
|
||||
try:
|
||||
if os.path.exists(config_file_path):
|
||||
|
|
@ -120,33 +121,24 @@ def read_app_config() -> tuple[AppConfig, bool]:
|
|||
config = AppConfig()
|
||||
config_file_healthy = True
|
||||
|
||||
except Exception as exc:
|
||||
print(
|
||||
(
|
||||
'error reading config file at time '
|
||||
+ str(_babase.apptime())
|
||||
+ ': \''
|
||||
+ config_file_path
|
||||
+ '\':\n'
|
||||
),
|
||||
exc,
|
||||
except Exception:
|
||||
logging.exception(
|
||||
"Error reading config file at time %.3f: '%s'.",
|
||||
_babase.apptime(),
|
||||
config_file_path,
|
||||
)
|
||||
|
||||
# Whenever this happens lets back up the broken one just in case it
|
||||
# gets overwritten accidentally.
|
||||
print(
|
||||
(
|
||||
'backing up current config file to \''
|
||||
+ config_file_path
|
||||
+ ".broken\'"
|
||||
)
|
||||
logging.info(
|
||||
"Backing up current config file to '%s.broken'", config_file_path
|
||||
)
|
||||
try:
|
||||
import shutil
|
||||
|
||||
shutil.copyfile(config_file_path, config_file_path + '.broken')
|
||||
except Exception as exc2:
|
||||
print('EXC copying broken config:', exc2)
|
||||
except Exception:
|
||||
logging.exception('Error copying broken config.')
|
||||
config = AppConfig()
|
||||
|
||||
# Now attempt to read one of our 'prev' backup copies.
|
||||
|
|
@ -159,9 +151,9 @@ def read_app_config() -> tuple[AppConfig, bool]:
|
|||
else:
|
||||
config = AppConfig()
|
||||
config_file_healthy = True
|
||||
print('successfully read backup config.')
|
||||
except Exception as exc2:
|
||||
print('EXC reading prev backup config:', exc2)
|
||||
logging.info('Successfully read backup config.')
|
||||
except Exception:
|
||||
logging.exception('Error reading prev backup config.')
|
||||
return config, config_file_healthy
|
||||
|
||||
|
||||
|
|
@ -176,7 +168,7 @@ def commit_app_config(force: bool = False) -> None:
|
|||
assert plus is not None
|
||||
|
||||
if not _babase.app.config_file_healthy and not force:
|
||||
print(
|
||||
logging.warning(
|
||||
'Current config file is broken; '
|
||||
'skipping write to avoid losing settings.'
|
||||
)
|
||||
|
|
|
|||
30
dist/ba_data/python/babase/_appmode.py
vendored
30
dist/ba_data/python/babase/_appmode.py
vendored
|
|
@ -6,6 +6,7 @@ from __future__ import annotations
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bacommon.app import AppExperience
|
||||
from babase._appintent import AppIntent
|
||||
|
||||
|
||||
|
|
@ -17,16 +18,33 @@ class AppMode:
|
|||
"""
|
||||
|
||||
@classmethod
|
||||
def supports_intent(cls, intent: AppIntent) -> bool:
|
||||
"""Return whether our mode can handle the provided intent."""
|
||||
del intent
|
||||
def get_app_experience(cls) -> AppExperience:
|
||||
"""Return the overall experience provided by this mode."""
|
||||
raise NotImplementedError('AppMode subclasses must override this.')
|
||||
|
||||
# Say no to everything by default. Let's make mode explicitly
|
||||
# lay out everything they *do* support.
|
||||
return False
|
||||
@classmethod
|
||||
def can_handle_intent(cls, intent: AppIntent) -> bool:
|
||||
"""Return whether this mode can handle the provided intent.
|
||||
|
||||
For this to return True, the AppMode must claim to support the
|
||||
provided intent (via its _supports_intent() method) AND the
|
||||
AppExperience associated with the AppMode must be supported by
|
||||
the current app and runtime environment.
|
||||
"""
|
||||
return cls._supports_intent(intent)
|
||||
|
||||
@classmethod
|
||||
def _supports_intent(cls, intent: AppIntent) -> bool:
|
||||
"""Return whether our mode can handle the provided intent.
|
||||
|
||||
AppModes should override this to define what they can handle.
|
||||
Note that AppExperience does not have to be considered here; that
|
||||
is handled automatically by the can_handle_intent() call."""
|
||||
raise NotImplementedError('AppMode subclasses must override this.')
|
||||
|
||||
def handle_intent(self, intent: AppIntent) -> None:
|
||||
"""Handle an intent."""
|
||||
raise NotImplementedError('AppMode subclasses must override this.')
|
||||
|
||||
def on_activate(self) -> None:
|
||||
"""Called when the mode is being activated."""
|
||||
|
|
|
|||
10
dist/ba_data/python/babase/_appmodeselector.py
vendored
10
dist/ba_data/python/babase/_appmodeselector.py
vendored
|
|
@ -1,6 +1,6 @@
|
|||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Provides AppMode functionality."""
|
||||
"""Contains AppModeSelector base class."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
|
@ -18,15 +18,15 @@ class AppModeSelector:
|
|||
The app calls an instance of this class when passed an AppIntent to
|
||||
determine which AppMode to use to handle the intent. Plugins or
|
||||
spinoff projects can modify high level app behavior by replacing or
|
||||
modifying this.
|
||||
modifying the app's mode-selector.
|
||||
"""
|
||||
|
||||
def app_mode_for_intent(self, intent: AppIntent) -> type[AppMode]:
|
||||
def app_mode_for_intent(self, intent: AppIntent) -> type[AppMode] | None:
|
||||
"""Given an AppIntent, return the AppMode that should handle it.
|
||||
|
||||
If None is returned, the AppIntent will be ignored.
|
||||
|
||||
This is called in a background thread, so avoid any calls
|
||||
This may be called in a background thread, so avoid any calls
|
||||
limited to logic thread use/etc.
|
||||
"""
|
||||
raise RuntimeError('app_mode_for_intent() should be overridden.')
|
||||
raise NotImplementedError('app_mode_for_intent() should be overridden.')
|
||||
|
|
|
|||
7
dist/ba_data/python/babase/_appsubsystem.py
vendored
7
dist/ba_data/python/babase/_appsubsystem.py
vendored
|
|
@ -18,8 +18,8 @@ class AppSubsystem:
|
|||
|
||||
An app 'subsystem' is a bit of a vague term, as pieces of the app
|
||||
can technically be any class and are not required to use this, but
|
||||
building one out of this base class provides some conveniences such
|
||||
as predefined callbacks during app state changes.
|
||||
building one out of this base class provides conveniences such as
|
||||
predefined callbacks during app state changes.
|
||||
|
||||
Subsystems must be registered with the app before it completes its
|
||||
transition to the 'running' state.
|
||||
|
|
@ -48,5 +48,8 @@ class AppSubsystem:
|
|||
def on_app_shutdown(self) -> None:
|
||||
"""Called when the app is shutting down."""
|
||||
|
||||
def on_app_shutdown_complete(self) -> None:
|
||||
"""Called when the app is done shutting down."""
|
||||
|
||||
def do_apply_app_config(self) -> None:
|
||||
"""Called when the app config should be applied."""
|
||||
|
|
|
|||
23
dist/ba_data/python/babase/_apputils.py
vendored
23
dist/ba_data/python/babase/_apputils.py
vendored
|
|
@ -48,7 +48,7 @@ def is_browser_likely_available() -> bool:
|
|||
# assume no browser.
|
||||
# FIXME: Might not be the case anymore; should make this definable
|
||||
# at the platform level.
|
||||
if app.vr_mode or (platform == 'android' and not hastouchscreen):
|
||||
if app.env.vr or (platform == 'android' and not hastouchscreen):
|
||||
return False
|
||||
|
||||
# Anywhere else assume we've got one.
|
||||
|
|
@ -103,8 +103,8 @@ def handle_v1_cloud_log() -> None:
|
|||
|
||||
info = {
|
||||
'log': _babase.get_v1_cloud_log(),
|
||||
'version': app.version,
|
||||
'build': app.build_number,
|
||||
'version': app.env.version,
|
||||
'build': app.env.build_number,
|
||||
'userAgentString': classic.legacy_user_agent_string,
|
||||
'session': sessionname,
|
||||
'activity': activityname,
|
||||
|
|
@ -222,8 +222,7 @@ def garbage_collect() -> None:
|
|||
def print_corrupt_file_error() -> None:
|
||||
"""Print an error if a corrupt file is found."""
|
||||
|
||||
# FIXME - filter this out for builds without bauiv1.
|
||||
if not _babase.app.headless_mode:
|
||||
if _babase.app.env.gui:
|
||||
_babase.apptimer(
|
||||
2.0,
|
||||
lambda: _babase.screenmessage(
|
||||
|
|
@ -279,7 +278,8 @@ def dump_app_state(
|
|||
# the dump in that case.
|
||||
try:
|
||||
mdpath = os.path.join(
|
||||
os.path.dirname(_babase.app.config_file_path), '_appstate_dump_md'
|
||||
os.path.dirname(_babase.app.env.config_file_path),
|
||||
'_appstate_dump_md',
|
||||
)
|
||||
with open(mdpath, 'w', encoding='utf-8') as outfile:
|
||||
outfile.write(
|
||||
|
|
@ -297,7 +297,7 @@ def dump_app_state(
|
|||
return
|
||||
|
||||
tbpath = os.path.join(
|
||||
os.path.dirname(_babase.app.config_file_path), '_appstate_dump_tb'
|
||||
os.path.dirname(_babase.app.env.config_file_path), '_appstate_dump_tb'
|
||||
)
|
||||
|
||||
tbfile = open(tbpath, 'w', encoding='utf-8')
|
||||
|
|
@ -329,7 +329,8 @@ def log_dumped_app_state() -> None:
|
|||
try:
|
||||
out = ''
|
||||
mdpath = os.path.join(
|
||||
os.path.dirname(_babase.app.config_file_path), '_appstate_dump_md'
|
||||
os.path.dirname(_babase.app.env.config_file_path),
|
||||
'_appstate_dump_md',
|
||||
)
|
||||
if os.path.exists(mdpath):
|
||||
# We may be hanging on to open file descriptors for use by
|
||||
|
|
@ -354,7 +355,7 @@ def log_dumped_app_state() -> None:
|
|||
f'Time: {metadata.app_time:.2f}'
|
||||
)
|
||||
tbpath = os.path.join(
|
||||
os.path.dirname(_babase.app.config_file_path),
|
||||
os.path.dirname(_babase.app.env.config_file_path),
|
||||
'_appstate_dump_tb',
|
||||
)
|
||||
if os.path.exists(tbpath):
|
||||
|
|
@ -378,6 +379,10 @@ class AppHealthMonitor(AppSubsystem):
|
|||
self._response = False
|
||||
self._first_check = True
|
||||
|
||||
def on_app_loading(self) -> None:
|
||||
# If any traceback dumps happened last run, log and clear them.
|
||||
log_dumped_app_state()
|
||||
|
||||
def _app_monitor_thread_main(self) -> None:
|
||||
try:
|
||||
self._monitor_app()
|
||||
|
|
|
|||
12
dist/ba_data/python/babase/_emptyappmode.py
vendored
12
dist/ba_data/python/babase/_emptyappmode.py
vendored
|
|
@ -5,6 +5,8 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bacommon.app import AppExperience
|
||||
|
||||
import _babase
|
||||
from babase._appmode import AppMode
|
||||
from babase._appintent import AppIntentExec, AppIntentDefault
|
||||
|
|
@ -17,7 +19,11 @@ class EmptyAppMode(AppMode):
|
|||
"""An empty app mode that can be used as a fallback/etc."""
|
||||
|
||||
@classmethod
|
||||
def supports_intent(cls, intent: AppIntent) -> bool:
|
||||
def get_app_experience(cls) -> AppExperience:
|
||||
return AppExperience.EMPTY
|
||||
|
||||
@classmethod
|
||||
def _supports_intent(cls, intent: AppIntent) -> bool:
|
||||
# We support default and exec intents currently.
|
||||
return isinstance(intent, AppIntentExec | AppIntentDefault)
|
||||
|
||||
|
|
@ -30,8 +36,8 @@ class EmptyAppMode(AppMode):
|
|||
|
||||
def on_activate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_babase.empty_app_mode_activate()
|
||||
_babase.on_empty_app_mode_activate()
|
||||
|
||||
def on_deactivate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_babase.empty_app_mode_deactivate()
|
||||
_babase.on_empty_app_mode_deactivate()
|
||||
|
|
|
|||
25
dist/ba_data/python/babase/_env.py
vendored
25
dist/ba_data/python/babase/_env.py
vendored
|
|
@ -6,6 +6,7 @@ from __future__ import annotations
|
|||
import sys
|
||||
import signal
|
||||
import logging
|
||||
import warnings
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from efro.log import LogLevel
|
||||
|
|
@ -103,6 +104,12 @@ def on_main_thread_start_app() -> None:
|
|||
signal.signal(signal.SIGINT, signal.SIG_DFL) # Do default handling.
|
||||
_babase.setup_sigint()
|
||||
|
||||
# Turn on deprecation warnings. By default these are off for release
|
||||
# builds except for in __main__. However this is a key way to
|
||||
# communicate api changes to modders and most modders are running
|
||||
# release builds so its good to have this on everywhere.
|
||||
warnings.simplefilter('default', DeprecationWarning)
|
||||
|
||||
# Turn off fancy-pants cyclic garbage-collection. We run it only at
|
||||
# explicit times to avoid random hitches and keep things more
|
||||
# deterministic. Non-reference-looped objects will still get cleaned
|
||||
|
|
@ -149,14 +156,15 @@ def on_main_thread_start_app() -> None:
|
|||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
|
||||
|
||||
def on_app_launching() -> None:
|
||||
"""Called when the app reaches the launching state."""
|
||||
def on_app_state_initing() -> None:
|
||||
"""Called when the app reaches the initing state."""
|
||||
import _babase
|
||||
import baenv
|
||||
|
||||
assert _babase.in_logic_thread()
|
||||
|
||||
# Let the user know if the app Python dir is a 'user' one.
|
||||
# Let the user know if the app Python dir is a 'user' one. This is a
|
||||
# risky thing to be doing so don't let them forget they're doing it.
|
||||
envconfig = baenv.get_config()
|
||||
if envconfig.is_user_app_python_dir:
|
||||
_babase.screenmessage(
|
||||
|
|
@ -192,12 +200,13 @@ def _feed_logs_to_babase(log_handler: LogHandler) -> None:
|
|||
# cache. This will feed the engine any logs that happened between
|
||||
# baenv.configure() and now.
|
||||
|
||||
# FIXME: while this works for now, the downside is that these
|
||||
# FIXME: while this setup works for now, the downside is that these
|
||||
# callbacks fire in a bg thread so certain things like android
|
||||
# logging will be delayed compared to code that uses native logging
|
||||
# calls directly. Perhaps we should add some sort of 'immediate'
|
||||
# callback option to better handle such cases (similar to the
|
||||
# immediate echofile stderr print that already occurs).
|
||||
# logging will be delayed relative to code that uses native logging
|
||||
# calls directly. Ideally we should add some sort of 'immediate'
|
||||
# callback option to better handle such cases (analogous to the
|
||||
# immediate echofile stderr print that LogHandler already
|
||||
# supports).
|
||||
log_handler.add_callback(_on_log, feed_existing_logs=True)
|
||||
|
||||
|
||||
|
|
|
|||
59
dist/ba_data/python/babase/_general.py
vendored
59
dist/ba_data/python/babase/_general.py
vendored
|
|
@ -6,12 +6,13 @@ from __future__ import annotations
|
|||
import types
|
||||
import weakref
|
||||
import random
|
||||
import logging
|
||||
import inspect
|
||||
from typing import TYPE_CHECKING, TypeVar, Protocol, NewType
|
||||
|
||||
from efro.terminal import Clr
|
||||
|
||||
import _babase
|
||||
from babase._error import print_error, print_exception
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
|
@ -19,7 +20,8 @@ if TYPE_CHECKING:
|
|||
|
||||
|
||||
# Declare distinct types for different time measurements we use so the
|
||||
# type-checker can help prevent us from mixing and matching accidentally.
|
||||
# type-checker can help prevent us from mixing and matching accidentally,
|
||||
# even if the *actual* types being used are the same.
|
||||
|
||||
# Our monotonic time measurement that starts at 0 when the app launches
|
||||
# and pauses while the app is suspended.
|
||||
|
|
@ -85,39 +87,6 @@ def getclass(name: str, subclassof: type[T]) -> type[T]:
|
|||
return cls
|
||||
|
||||
|
||||
def json_prep(data: Any) -> Any:
|
||||
"""Return a json-friendly version of the provided data.
|
||||
|
||||
This converts any tuples to lists and any bytes to strings
|
||||
(interpreted as utf-8, ignoring errors). Logs errors (just once)
|
||||
if any data is modified/discarded/unsupported.
|
||||
"""
|
||||
|
||||
if isinstance(data, dict):
|
||||
return dict(
|
||||
(json_prep(key), json_prep(value))
|
||||
for key, value in list(data.items())
|
||||
)
|
||||
if isinstance(data, list):
|
||||
return [json_prep(element) for element in data]
|
||||
if isinstance(data, tuple):
|
||||
print_error('json_prep encountered tuple', once=True)
|
||||
return [json_prep(element) for element in data]
|
||||
if isinstance(data, bytes):
|
||||
try:
|
||||
return data.decode(errors='ignore')
|
||||
except Exception:
|
||||
from babase import _error
|
||||
|
||||
print_error('json_prep encountered utf-8 decode error', once=True)
|
||||
return data.decode(errors='ignore')
|
||||
if not isinstance(data, (str, float, bool, type(None), int)):
|
||||
print_error(
|
||||
'got unsupported type in json_prep:' + str(type(data)), once=True
|
||||
)
|
||||
return data
|
||||
|
||||
|
||||
def utf8_all(data: Any) -> Any:
|
||||
"""Convert any unicode data in provided sequence(s) to utf8 bytes."""
|
||||
if isinstance(data, dict):
|
||||
|
|
@ -136,7 +105,7 @@ def utf8_all(data: Any) -> Any:
|
|||
|
||||
def get_type_name(cls: type) -> str:
|
||||
"""Return a full type name including module for a class."""
|
||||
return cls.__module__ + '.' + cls.__name__
|
||||
return f'{cls.__module__}.{cls.__name__}'
|
||||
|
||||
|
||||
class _WeakCall:
|
||||
|
|
@ -195,18 +164,12 @@ class _WeakCall:
|
|||
else:
|
||||
app = _babase.app
|
||||
if not self._did_invalid_call_warning:
|
||||
print(
|
||||
(
|
||||
'Warning: callable passed to babase.WeakCall() is not'
|
||||
' weak-referencable ('
|
||||
+ str(args[0])
|
||||
+ '); use babase.Call() instead to avoid this '
|
||||
'warning. Stack-trace:'
|
||||
)
|
||||
logging.warning(
|
||||
'Warning: callable passed to babase.WeakCall() is not'
|
||||
' weak-referencable (%s); use babase.Call() instead'
|
||||
' to avoid this warning.',
|
||||
stack_info=True,
|
||||
)
|
||||
import traceback
|
||||
|
||||
traceback.print_stack()
|
||||
self._did_invalid_call_warning = True
|
||||
self._call = args[0]
|
||||
self._args = args[1:]
|
||||
|
|
@ -320,7 +283,7 @@ def verify_object_death(obj: object) -> None:
|
|||
try:
|
||||
ref = weakref.ref(obj)
|
||||
except Exception:
|
||||
print_exception('Unable to create weak-ref in verify_object_death')
|
||||
logging.exception('Unable to create weak-ref in verify_object_death')
|
||||
return
|
||||
|
||||
# Use a slight range for our checks so they don't all land at once
|
||||
|
|
|
|||
57
dist/ba_data/python/babase/_hooks.py
vendored
57
dist/ba_data/python/babase/_hooks.py
vendored
|
|
@ -20,12 +20,7 @@ from typing import TYPE_CHECKING
|
|||
import _babase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
def on_app_bootstrapping_complete() -> None:
|
||||
"""Called by C++ layer when bootstrapping finishes."""
|
||||
_babase.app.on_app_bootstrapping_complete()
|
||||
from babase._stringedit import StringEditAdapter
|
||||
|
||||
|
||||
def reset_to_main_menu() -> None:
|
||||
|
|
@ -69,14 +64,6 @@ def open_url_with_webbrowser_module(url: str) -> None:
|
|||
_babase.screenmessage(Lstr(resource='errorText'), color=(1, 0, 0))
|
||||
|
||||
|
||||
def connecting_to_party_message() -> None:
|
||||
from babase._language import Lstr
|
||||
|
||||
_babase.screenmessage(
|
||||
Lstr(resource='internal.connectingToPartyText'), color=(1, 1, 1)
|
||||
)
|
||||
|
||||
|
||||
def rejecting_invite_already_in_party_message() -> None:
|
||||
from babase._language import Lstr
|
||||
|
||||
|
|
@ -97,7 +84,7 @@ def connection_failed_message() -> None:
|
|||
def temporarily_unavailable_message() -> None:
|
||||
from babase._language import Lstr
|
||||
|
||||
if not _babase.app.headless_mode:
|
||||
if _babase.app.env.gui:
|
||||
_babase.getsimplesound('error').play()
|
||||
_babase.screenmessage(
|
||||
Lstr(resource='getTicketsWindow.unavailableTemporarilyText'),
|
||||
|
|
@ -108,7 +95,7 @@ def temporarily_unavailable_message() -> None:
|
|||
def in_progress_message() -> None:
|
||||
from babase._language import Lstr
|
||||
|
||||
if not _babase.app.headless_mode:
|
||||
if _babase.app.env.gui:
|
||||
_babase.getsimplesound('error').play()
|
||||
_babase.screenmessage(
|
||||
Lstr(resource='getTicketsWindow.inProgressText'),
|
||||
|
|
@ -119,7 +106,7 @@ def in_progress_message() -> None:
|
|||
def error_message() -> None:
|
||||
from babase._language import Lstr
|
||||
|
||||
if not _babase.app.headless_mode:
|
||||
if _babase.app.env.gui:
|
||||
_babase.getsimplesound('error').play()
|
||||
_babase.screenmessage(Lstr(resource='errorText'), color=(1, 0, 0))
|
||||
|
||||
|
|
@ -127,7 +114,7 @@ def error_message() -> None:
|
|||
def purchase_not_valid_error() -> None:
|
||||
from babase._language import Lstr
|
||||
|
||||
if not _babase.app.headless_mode:
|
||||
if _babase.app.env.gui:
|
||||
_babase.getsimplesound('error').play()
|
||||
_babase.screenmessage(
|
||||
Lstr(
|
||||
|
|
@ -141,7 +128,7 @@ def purchase_not_valid_error() -> None:
|
|||
def purchase_already_in_progress_error() -> None:
|
||||
from babase._language import Lstr
|
||||
|
||||
if not _babase.app.headless_mode:
|
||||
if _babase.app.env.gui:
|
||||
_babase.getsimplesound('error').play()
|
||||
_babase.screenmessage(
|
||||
Lstr(resource='store.purchaseAlreadyInProgressText'),
|
||||
|
|
@ -172,14 +159,6 @@ def orientation_reset_message() -> None:
|
|||
)
|
||||
|
||||
|
||||
def on_app_pause() -> None:
|
||||
_babase.app.pause()
|
||||
|
||||
|
||||
def on_app_resume() -> None:
|
||||
_babase.app.resume()
|
||||
|
||||
|
||||
def show_post_purchase_message() -> None:
|
||||
assert _babase.app.classic is not None
|
||||
_babase.app.classic.accounts.show_post_purchase_message()
|
||||
|
|
@ -208,7 +187,7 @@ def award_dual_wielding_achievement() -> None:
|
|||
|
||||
|
||||
def play_gong_sound() -> None:
|
||||
if not _babase.app.headless_mode:
|
||||
if _babase.app.env.gui:
|
||||
_babase.getsimplesound('gong').play()
|
||||
|
||||
|
||||
|
|
@ -272,15 +251,11 @@ def toggle_fullscreen() -> None:
|
|||
cfg.apply_and_commit()
|
||||
|
||||
|
||||
def read_config() -> None:
|
||||
_babase.app.read_config()
|
||||
|
||||
|
||||
def ui_remote_press() -> None:
|
||||
"""Handle a press by a remote device that is only usable for nav."""
|
||||
from babase._language import Lstr
|
||||
|
||||
if _babase.app.headless_mode:
|
||||
if _babase.app.env.headless:
|
||||
return
|
||||
|
||||
# Can be called without a context; need a context for getsound.
|
||||
|
|
@ -300,10 +275,6 @@ def do_quit() -> None:
|
|||
_babase.quit()
|
||||
|
||||
|
||||
def shutdown() -> None:
|
||||
_babase.app.on_app_shutdown()
|
||||
|
||||
|
||||
def hash_strings(inputs: list[str]) -> str:
|
||||
"""Hash provided strings into a short output string."""
|
||||
import hashlib
|
||||
|
|
@ -375,11 +346,11 @@ def show_client_too_old_error() -> None:
|
|||
# a newer build.
|
||||
if (
|
||||
_babase.app.config.get('SuppressClientTooOldErrorForBuild')
|
||||
== _babase.app.build_number
|
||||
== _babase.app.env.build_number
|
||||
):
|
||||
return
|
||||
|
||||
if not _babase.app.headless_mode:
|
||||
if _babase.app.env.gui:
|
||||
_babase.getsimplesound('error').play()
|
||||
|
||||
_babase.screenmessage(
|
||||
|
|
@ -393,3 +364,11 @@ def show_client_too_old_error() -> None:
|
|||
),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
|
||||
|
||||
def string_edit_adapter_can_be_replaced(adapter: StringEditAdapter) -> bool:
|
||||
"""Return whether a StringEditAdapter can be replaced."""
|
||||
from babase._stringedit import StringEditAdapter
|
||||
|
||||
assert isinstance(adapter, StringEditAdapter)
|
||||
return adapter.can_be_replaced()
|
||||
|
|
|
|||
9
dist/ba_data/python/babase/_language.py
vendored
9
dist/ba_data/python/babase/_language.py
vendored
|
|
@ -68,7 +68,10 @@ class LanguageSubsystem(AppSubsystem):
|
|||
try:
|
||||
names = os.listdir(
|
||||
os.path.join(
|
||||
_babase.app.data_directory, 'ba_data', 'data', 'languages'
|
||||
_babase.app.env.data_directory,
|
||||
'ba_data',
|
||||
'data',
|
||||
'languages',
|
||||
)
|
||||
)
|
||||
names = [n.replace('.json', '').capitalize() for n in names]
|
||||
|
|
@ -121,7 +124,7 @@ class LanguageSubsystem(AppSubsystem):
|
|||
|
||||
with open(
|
||||
os.path.join(
|
||||
_babase.app.data_directory,
|
||||
_babase.app.env.data_directory,
|
||||
'ba_data',
|
||||
'data',
|
||||
'languages',
|
||||
|
|
@ -139,7 +142,7 @@ class LanguageSubsystem(AppSubsystem):
|
|||
lmodvalues = None
|
||||
else:
|
||||
lmodfile = os.path.join(
|
||||
_babase.app.data_directory,
|
||||
_babase.app.env.data_directory,
|
||||
'ba_data',
|
||||
'data',
|
||||
'languages',
|
||||
|
|
|
|||
1
dist/ba_data/python/babase/_login.py
vendored
1
dist/ba_data/python/babase/_login.py
vendored
|
|
@ -10,6 +10,7 @@ from dataclasses import dataclass
|
|||
from typing import TYPE_CHECKING, final
|
||||
|
||||
from bacommon.login import LoginType
|
||||
|
||||
import _babase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
|
|||
21
dist/ba_data/python/babase/_meta.py
vendored
21
dist/ba_data/python/babase/_meta.py
vendored
|
|
@ -18,11 +18,6 @@ import _babase
|
|||
if TYPE_CHECKING:
|
||||
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-Tag-System
|
||||
CURRENT_API_VERSION = 8
|
||||
|
||||
# Meta export lines can use these names to represent these classes.
|
||||
# This is purely a convenience; it is possible to use full class paths
|
||||
|
|
@ -76,14 +71,15 @@ class MetadataSubsystem:
|
|||
"""
|
||||
assert self._scan_complete_cb is None
|
||||
assert self._scan is None
|
||||
env = _babase.app.env
|
||||
|
||||
self._scan_complete_cb = scan_complete_cb
|
||||
self._scan = DirectoryScan(
|
||||
[
|
||||
path
|
||||
for path in [
|
||||
_babase.app.python_directory_app,
|
||||
_babase.app.python_directory_user,
|
||||
env.python_directory_app,
|
||||
env.python_directory_user,
|
||||
]
|
||||
if path is not None
|
||||
]
|
||||
|
|
@ -212,7 +208,7 @@ class MetadataSubsystem:
|
|||
'${NUM}',
|
||||
str(len(results.incorrect_api_modules) - 1),
|
||||
),
|
||||
('${API}', str(CURRENT_API_VERSION)),
|
||||
('${API}', str(_babase.app.env.api_version)),
|
||||
],
|
||||
)
|
||||
else:
|
||||
|
|
@ -220,7 +216,7 @@ class MetadataSubsystem:
|
|||
resource='scanScriptsSingleModuleNeedsUpdatesText',
|
||||
subs=[
|
||||
('${PATH}', results.incorrect_api_modules[0]),
|
||||
('${API}', str(CURRENT_API_VERSION)),
|
||||
('${API}', str(_babase.app.env.api_version)),
|
||||
],
|
||||
)
|
||||
_babase.screenmessage(msg, color=(1, 0, 0))
|
||||
|
|
@ -344,13 +340,16 @@ class DirectoryScan:
|
|||
|
||||
# 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 != _babase.app.env.api_version
|
||||
):
|
||||
logging.warning(
|
||||
'metascan: %s requires api %s but we are running'
|
||||
' %s. Ignoring module.',
|
||||
subpath,
|
||||
required_api,
|
||||
CURRENT_API_VERSION,
|
||||
_babase.app.env.api_version,
|
||||
)
|
||||
self.results.incorrect_api_modules.append(
|
||||
self._module_name_for_subpath(subpath)
|
||||
|
|
|
|||
38
dist/ba_data/python/babase/_plugin.py
vendored
38
dist/ba_data/python/babase/_plugin.py
vendored
|
|
@ -81,7 +81,7 @@ class PluginSubsystem(AppSubsystem):
|
|||
config_changed = True
|
||||
found_new = True
|
||||
|
||||
# If we're *not* auto-enabling, just let the user know if we
|
||||
# If we're *not* auto-enabling, simply let the user know if we
|
||||
# found new ones.
|
||||
if found_new and not auto_enable_new_plugins:
|
||||
_babase.screenmessage(
|
||||
|
|
@ -131,10 +131,10 @@ class PluginSubsystem(AppSubsystem):
|
|||
disappeared_plugs.add(class_path)
|
||||
continue
|
||||
|
||||
# If plugins disappeared, let the user know gently and remove them
|
||||
# from the config so we'll again let the user know if they later
|
||||
# reappear. This makes it much smoother to switch between users
|
||||
# or workspaces.
|
||||
# If plugins disappeared, let the user know gently and remove
|
||||
# them from the config so we'll again let the user know if they
|
||||
# later reappear. This makes it much smoother to switch between
|
||||
# users or workspaces.
|
||||
if disappeared_plugs:
|
||||
_babase.getsimplesound('shieldDown').play()
|
||||
_babase.screenmessage(
|
||||
|
|
@ -197,6 +197,17 @@ class PluginSubsystem(AppSubsystem):
|
|||
|
||||
_error.print_exception('Error in plugin on_app_shutdown()')
|
||||
|
||||
def on_app_shutdown_complete(self) -> None:
|
||||
for plugin in self.active_plugins:
|
||||
try:
|
||||
plugin.on_app_shutdown_complete()
|
||||
except Exception:
|
||||
from babase import _error
|
||||
|
||||
_error.print_exception(
|
||||
'Error in plugin on_app_shutdown_complete()'
|
||||
)
|
||||
|
||||
def load_plugins(self) -> None:
|
||||
"""(internal)"""
|
||||
|
||||
|
|
@ -217,7 +228,7 @@ class PluginSpec:
|
|||
key. Remember to commit the app-config after making any changes.
|
||||
|
||||
The 'attempted_load' attr will be True if the engine has attempted
|
||||
to load the plugin. If 'attempted_load' is True for a plugin-spec
|
||||
to load the plugin. If 'attempted_load' is True for a PluginSpec
|
||||
but the 'plugin' attr is None, it means there was an error loading
|
||||
the plugin. If a plugin's api-version does not match the running
|
||||
app, if a new plugin is detected with auto-enable-plugins disabled,
|
||||
|
|
@ -249,7 +260,7 @@ class PluginSpec:
|
|||
plugstate['enabled'] = val
|
||||
|
||||
def attempt_load_if_enabled(self) -> Plugin | None:
|
||||
"""Possibly load the plugin and report errors."""
|
||||
"""Possibly load the plugin and log any errors."""
|
||||
from babase._general import getclass
|
||||
from babase._language import Lstr
|
||||
|
||||
|
|
@ -308,8 +319,8 @@ class Plugin:
|
|||
Category: **App Classes**
|
||||
|
||||
Plugins are discoverable by the meta-tag system
|
||||
and the user can select which ones they want to activate.
|
||||
Active plugins are then called at specific times as the
|
||||
and the user can select which ones they want to enable.
|
||||
Enabled plugins are then called at specific times as the
|
||||
app is running in order to modify its behavior in some way.
|
||||
"""
|
||||
|
||||
|
|
@ -317,13 +328,16 @@ class Plugin:
|
|||
"""Called when the app reaches the running state."""
|
||||
|
||||
def on_app_pause(self) -> None:
|
||||
"""Called after pausing game activity."""
|
||||
"""Called when the app is switching to a paused state."""
|
||||
|
||||
def on_app_resume(self) -> None:
|
||||
"""Called after the game continues."""
|
||||
"""Called when the app is resuming from a paused state."""
|
||||
|
||||
def on_app_shutdown(self) -> None:
|
||||
"""Called before closing the application."""
|
||||
"""Called when the app is beginning the shutdown process."""
|
||||
|
||||
def on_app_shutdown_complete(self) -> None:
|
||||
"""Called when the app has completed the shutdown process."""
|
||||
|
||||
def has_settings_ui(self) -> bool:
|
||||
"""Called to ask if we have settings UI we can show."""
|
||||
|
|
|
|||
146
dist/ba_data/python/babase/_stringedit.py
vendored
Normal file
146
dist/ba_data/python/babase/_stringedit.py
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Functionality for editing text strings.
|
||||
|
||||
This abstracts native edit dialogs as well as ones implemented via our
|
||||
own ui toolkits.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
import logging
|
||||
import weakref
|
||||
from typing import TYPE_CHECKING, final
|
||||
|
||||
from efro.util import empty_weakref
|
||||
|
||||
import _babase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class StringEditSubsystem:
|
||||
"""Full string-edit state for the app."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.active_adapter = empty_weakref(StringEditAdapter)
|
||||
|
||||
|
||||
class StringEditAdapter:
|
||||
"""Represents a string editing operation on some object.
|
||||
|
||||
Editable objects such as text widgets or in-app-consoles can
|
||||
subclass this to make their contents editable on all platforms.
|
||||
|
||||
There can only be one string-edit at a time for the app. New
|
||||
StringEdits will attempt to register themselves as the globally
|
||||
active one in their constructor, but this may not succeed. When
|
||||
creating a StringEditAdapter, always check its 'is_valid()' value after
|
||||
creating it. If this is False, it was not able to set itself as
|
||||
the global active one and should be discarded.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
description: str,
|
||||
initial_text: str,
|
||||
max_length: int | None,
|
||||
screen_space_center: tuple[float, float] | None,
|
||||
) -> None:
|
||||
if not _babase.in_logic_thread():
|
||||
raise RuntimeError('This must be called from the logic thread.')
|
||||
|
||||
self.create_time = time.monotonic()
|
||||
|
||||
# Note: these attr names are hard-coded in C++ code so don't
|
||||
# change them willy-nilly.
|
||||
self.description = description
|
||||
self.initial_text = initial_text
|
||||
self.max_length = max_length
|
||||
self.screen_space_center = screen_space_center
|
||||
|
||||
# Attempt to register ourself as the active edit.
|
||||
subsys = _babase.app.stringedit
|
||||
current_edit = subsys.active_adapter()
|
||||
if current_edit is None or current_edit.can_be_replaced():
|
||||
subsys.active_adapter = weakref.ref(self)
|
||||
|
||||
@final
|
||||
def can_be_replaced(self) -> bool:
|
||||
"""Return whether this adapter can be replaced by a new one.
|
||||
|
||||
This is mainly a safeguard to allow adapters whose drivers have
|
||||
gone away without calling apply or cancel to time out and be
|
||||
replaced with new ones.
|
||||
"""
|
||||
if not _babase.in_logic_thread():
|
||||
raise RuntimeError('This must be called from the logic thread.')
|
||||
|
||||
# Allow ourself to be replaced after a bit.
|
||||
if time.monotonic() - self.create_time > 5.0:
|
||||
if _babase.do_once():
|
||||
logging.warning(
|
||||
'StringEditAdapter can_be_replaced() check for %s'
|
||||
' yielding True due to timeout; ideally this should'
|
||||
' not be possible as the StringEditAdapter driver'
|
||||
' should be blocking anything else from kicking off'
|
||||
' new edits.',
|
||||
self,
|
||||
)
|
||||
return True
|
||||
|
||||
# We also are always considered replaceable if we're not the
|
||||
# active global adapter.
|
||||
current_edit = _babase.app.stringedit.active_adapter()
|
||||
if current_edit is not self:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@final
|
||||
def apply(self, new_text: str) -> None:
|
||||
"""Should be called by the owner when editing is complete.
|
||||
|
||||
Note that in some cases this call may be a no-op (such as if
|
||||
this StringEditAdapter is no longer the globally active one).
|
||||
"""
|
||||
if not _babase.in_logic_thread():
|
||||
raise RuntimeError('This must be called from the logic thread.')
|
||||
|
||||
# Make sure whoever is feeding this adapter is honoring max-length.
|
||||
if self.max_length is not None and len(new_text) > self.max_length:
|
||||
logging.warning(
|
||||
'apply() on %s was passed a string of length %d,'
|
||||
' but adapter max_length is %d; this should not happen'
|
||||
' (will truncate).',
|
||||
self,
|
||||
len(new_text),
|
||||
self.max_length,
|
||||
stack_info=True,
|
||||
)
|
||||
new_text = new_text[: self.max_length]
|
||||
|
||||
self._do_apply(new_text)
|
||||
|
||||
@final
|
||||
def cancel(self) -> None:
|
||||
"""Should be called by the owner when editing is cancelled."""
|
||||
if not _babase.in_logic_thread():
|
||||
raise RuntimeError('This must be called from the logic thread.')
|
||||
self._do_cancel()
|
||||
|
||||
def _do_apply(self, new_text: str) -> None:
|
||||
"""Should be overridden by subclasses to handle apply.
|
||||
|
||||
Will always be called in the logic thread.
|
||||
"""
|
||||
raise NotImplementedError('Subclasses must override this.')
|
||||
|
||||
def _do_cancel(self) -> None:
|
||||
"""Should be overridden by subclasses to handle cancel.
|
||||
|
||||
Will always be called in the logic thread.
|
||||
"""
|
||||
raise NotImplementedError('Subclasses must override this.')
|
||||
32
dist/ba_data/python/babase/_ui.py
vendored
Normal file
32
dist/ba_data/python/babase/_ui.py
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""UI related bits of babase."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from babase._stringedit import StringEditAdapter
|
||||
import _babase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class DevConsoleStringEditAdapter(StringEditAdapter):
|
||||
"""Allows editing dev-console text."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
description = 'Dev Console Input'
|
||||
initial_text = _babase.get_dev_console_input_text()
|
||||
max_length = None
|
||||
screen_space_center = None
|
||||
super().__init__(
|
||||
description, initial_text, max_length, screen_space_center
|
||||
)
|
||||
|
||||
def _do_apply(self, new_text: str) -> None:
|
||||
_babase.set_dev_console_input_text(new_text)
|
||||
_babase.dev_console_input_adapter_finish()
|
||||
|
||||
def _do_cancel(self) -> None:
|
||||
_babase.dev_console_input_adapter_finish()
|
||||
32
dist/ba_data/python/babase/modutils.py
vendored
32
dist/ba_data/python/babase/modutils.py
vendored
|
|
@ -18,7 +18,7 @@ def get_human_readable_user_scripts_path() -> str:
|
|||
This is NOT a valid filesystem path; may be something like "(SD Card)".
|
||||
"""
|
||||
app = _babase.app
|
||||
path: str | None = app.python_directory_user
|
||||
path: str | None = app.env.python_directory_user
|
||||
if path is None:
|
||||
return '<Not Available>'
|
||||
|
||||
|
|
@ -66,19 +66,20 @@ def _request_storage_permission() -> bool:
|
|||
def show_user_scripts() -> None:
|
||||
"""Open or nicely print the location of the user-scripts directory."""
|
||||
app = _babase.app
|
||||
env = app.env
|
||||
|
||||
# First off, if we need permission for this, ask for it.
|
||||
if _request_storage_permission():
|
||||
return
|
||||
|
||||
# If we're running in a nonstandard environment its possible this is unset.
|
||||
if app.python_directory_user is None:
|
||||
if env.python_directory_user is None:
|
||||
_babase.screenmessage('<unset>')
|
||||
return
|
||||
|
||||
# Secondly, if the dir doesn't exist, attempt to make it.
|
||||
if not os.path.exists(app.python_directory_user):
|
||||
os.makedirs(app.python_directory_user)
|
||||
if not os.path.exists(env.python_directory_user):
|
||||
os.makedirs(env.python_directory_user)
|
||||
|
||||
# On android, attempt to write a file in their user-scripts dir telling
|
||||
# them about modding. This also has the side-effect of allowing us to
|
||||
|
|
@ -88,7 +89,7 @@ def show_user_scripts() -> None:
|
|||
# they can see it.
|
||||
if app.classic is not None and app.classic.platform == 'android':
|
||||
try:
|
||||
usd: str | None = app.python_directory_user
|
||||
usd: str | None = env.python_directory_user
|
||||
if usd is not None and os.path.isdir(usd):
|
||||
file_name = usd + '/about_this_folder.txt'
|
||||
with open(file_name, 'w', encoding='utf-8') as outfile:
|
||||
|
|
@ -105,7 +106,7 @@ def show_user_scripts() -> None:
|
|||
|
||||
# On a few platforms we try to open the dir in the UI.
|
||||
if app.classic is not None and app.classic.platform in ['mac', 'windows']:
|
||||
_babase.open_dir_externally(app.python_directory_user)
|
||||
_babase.open_dir_externally(env.python_directory_user)
|
||||
|
||||
# Otherwise we just print a pretty version of it.
|
||||
else:
|
||||
|
|
@ -120,18 +121,19 @@ def create_user_system_scripts() -> None:
|
|||
import shutil
|
||||
|
||||
app = _babase.app
|
||||
env = app.env
|
||||
|
||||
# First off, if we need permission for this, ask for it.
|
||||
if _request_storage_permission():
|
||||
return
|
||||
|
||||
# Its possible these are unset in non-standard environments.
|
||||
if app.python_directory_user is None:
|
||||
if env.python_directory_user is None:
|
||||
raise RuntimeError('user python dir unset')
|
||||
if app.python_directory_app is None:
|
||||
if env.python_directory_app is None:
|
||||
raise RuntimeError('app python dir unset')
|
||||
|
||||
path = app.python_directory_user + '/sys/' + app.version
|
||||
path = f'{env.python_directory_user}/sys/{env.version}'
|
||||
pathtmp = path + '_tmp'
|
||||
if os.path.exists(path):
|
||||
shutil.rmtree(path)
|
||||
|
|
@ -147,8 +149,8 @@ def create_user_system_scripts() -> None:
|
|||
# /Knowledge-Nuggets#python-cache-files-gotcha
|
||||
return ('__pycache__',)
|
||||
|
||||
print(f'COPYING "{app.python_directory_app}" -> "{pathtmp}".')
|
||||
shutil.copytree(app.python_directory_app, pathtmp, ignore=_ignore_filter)
|
||||
print(f'COPYING "{env.python_directory_app}" -> "{pathtmp}".')
|
||||
shutil.copytree(env.python_directory_app, pathtmp, ignore=_ignore_filter)
|
||||
|
||||
print(f'MOVING "{pathtmp}" -> "{path}".')
|
||||
shutil.move(pathtmp, path)
|
||||
|
|
@ -168,12 +170,12 @@ def delete_user_system_scripts() -> None:
|
|||
"""Clean out the scripts created by create_user_system_scripts()."""
|
||||
import shutil
|
||||
|
||||
app = _babase.app
|
||||
env = _babase.app.env
|
||||
|
||||
if app.python_directory_user is None:
|
||||
if env.python_directory_user is None:
|
||||
raise RuntimeError('user python dir unset')
|
||||
|
||||
path = app.python_directory_user + '/sys/' + app.version
|
||||
path = f'{env.python_directory_user}/sys/{env.version}'
|
||||
if os.path.exists(path):
|
||||
shutil.rmtree(path)
|
||||
print(
|
||||
|
|
@ -185,6 +187,6 @@ def delete_user_system_scripts() -> None:
|
|||
print(f"User system scripts not found at '{path}'.")
|
||||
|
||||
# If the sys path is empty, kill it.
|
||||
dpath = app.python_directory_user + '/sys'
|
||||
dpath = env.python_directory_user + '/sys'
|
||||
if os.path.isdir(dpath) and not os.listdir(dpath):
|
||||
os.rmdir(dpath)
|
||||
|
|
|
|||
2
dist/ba_data/python/baclassic/_accountv1.py
vendored
2
dist/ba_data/python/baclassic/_accountv1.py
vendored
|
|
@ -42,7 +42,7 @@ class AccountV1Subsystem:
|
|||
if babase.app.plus is None:
|
||||
return
|
||||
if (
|
||||
babase.app.headless_mode
|
||||
babase.app.env.headless
|
||||
or babase.app.config.get('Auto Account State') == 'Local'
|
||||
):
|
||||
babase.app.plus.sign_in_v1('Local')
|
||||
|
|
|
|||
21
dist/ba_data/python/baclassic/_input.py
vendored
21
dist/ba_data/python/baclassic/_input.py
vendored
|
|
@ -31,27 +31,6 @@ def get_input_device_mapped_value(
|
|||
subplatform = app.classic.subplatform
|
||||
appconfig = babase.app.config
|
||||
|
||||
# iiRcade: hard-code for a/b/c/x for now...
|
||||
if babase.app.iircade_mode:
|
||||
return {
|
||||
'triggerRun2': 19,
|
||||
'unassignedButtonsRun': False,
|
||||
'buttonPickUp': 100,
|
||||
'buttonBomb': 98,
|
||||
'buttonJump': 97,
|
||||
'buttonStart': 83,
|
||||
'buttonStart2': 109,
|
||||
'buttonPunch': 99,
|
||||
'buttonRun2': 102,
|
||||
'buttonRun1': 101,
|
||||
'triggerRun1': 18,
|
||||
'buttonLeft': 22,
|
||||
'buttonRight': 23,
|
||||
'buttonUp': 20,
|
||||
'buttonDown': 21,
|
||||
'buttonVRReorient': 110,
|
||||
}.get(name, -1)
|
||||
|
||||
# If there's an entry in our config for this controller, use it.
|
||||
if 'Controllers' in appconfig:
|
||||
ccfgs = appconfig['Controllers']
|
||||
|
|
|
|||
22
dist/ba_data/python/baclassic/_net.py
vendored
22
dist/ba_data/python/baclassic/_net.py
vendored
|
|
@ -4,13 +4,12 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import threading
|
||||
import weakref
|
||||
import threading
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
from babase import DEFAULT_REQUEST_TIMEOUT_SECONDS
|
||||
import bascenev1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -36,7 +35,9 @@ class MasterServerV1CallThread(threading.Thread):
|
|||
callback: MasterServerCallback | None,
|
||||
response_type: MasterServerResponseType,
|
||||
):
|
||||
super().__init__()
|
||||
# Set daemon=True so long-running requests don't keep us from
|
||||
# quitting the app.
|
||||
super().__init__(daemon=True)
|
||||
self._request = request
|
||||
self._request_type = request_type
|
||||
if not isinstance(response_type, MasterServerResponseType):
|
||||
|
|
@ -69,6 +70,7 @@ class MasterServerV1CallThread(threading.Thread):
|
|||
|
||||
def run(self) -> None:
|
||||
# pylint: disable=consider-using-with
|
||||
# pylint: disable=too-many-branches
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
import urllib.error
|
||||
|
|
@ -80,6 +82,13 @@ class MasterServerV1CallThread(threading.Thread):
|
|||
assert plus is not None
|
||||
response_data: Any = None
|
||||
url: str | None = None
|
||||
|
||||
# Tearing the app down while this is running can lead to
|
||||
# rare crashes in LibSSL, so avoid that if at all possible.
|
||||
if not babase.shutdown_suppress_begin():
|
||||
# App is already shutting down, so we're a no-op.
|
||||
return
|
||||
|
||||
try:
|
||||
classic = babase.app.classic
|
||||
assert classic is not None
|
||||
|
|
@ -101,7 +110,7 @@ class MasterServerV1CallThread(threading.Thread):
|
|||
{'User-Agent': classic.legacy_user_agent_string},
|
||||
),
|
||||
context=babase.app.net.sslcontext,
|
||||
timeout=DEFAULT_REQUEST_TIMEOUT_SECONDS,
|
||||
timeout=babase.DEFAULT_REQUEST_TIMEOUT_SECONDS,
|
||||
)
|
||||
elif self._request_type == 'post':
|
||||
url = plus.get_master_server_address() + '/' + self._request
|
||||
|
|
@ -113,7 +122,7 @@ class MasterServerV1CallThread(threading.Thread):
|
|||
{'User-Agent': classic.legacy_user_agent_string},
|
||||
),
|
||||
context=babase.app.net.sslcontext,
|
||||
timeout=DEFAULT_REQUEST_TIMEOUT_SECONDS,
|
||||
timeout=babase.DEFAULT_REQUEST_TIMEOUT_SECONDS,
|
||||
)
|
||||
else:
|
||||
raise TypeError('Invalid request_type: ' + self._request_type)
|
||||
|
|
@ -147,6 +156,9 @@ class MasterServerV1CallThread(threading.Thread):
|
|||
|
||||
response_data = None
|
||||
|
||||
finally:
|
||||
babase.shutdown_suppress_end()
|
||||
|
||||
if self._callback is not None:
|
||||
babase.pushcall(
|
||||
babase.Call(self._run_callback, response_data),
|
||||
|
|
|
|||
9
dist/ba_data/python/baclassic/_servermode.py
vendored
9
dist/ba_data/python/baclassic/_servermode.py
vendored
|
|
@ -214,7 +214,10 @@ class ServerController:
|
|||
|
||||
babase.app.classic.master_server_v1_get(
|
||||
'bsAccessCheck',
|
||||
{'port': bascenev1.get_game_port(), 'b': babase.app.build_number},
|
||||
{
|
||||
'port': bascenev1.get_game_port(),
|
||||
'b': babase.app.env.build_number,
|
||||
},
|
||||
callback=self._access_check_response,
|
||||
)
|
||||
|
||||
|
|
@ -379,8 +382,8 @@ class ServerController:
|
|||
if self._first_run:
|
||||
curtimestr = time.strftime('%c')
|
||||
startupmsg = (
|
||||
f'{Clr.BLD}{Clr.BLU}{babase.appnameupper()} {app.version}'
|
||||
f' ({app.build_number})'
|
||||
f'{Clr.BLD}{Clr.BLU}{babase.appnameupper()} {app.env.version}'
|
||||
f' ({app.env.build_number})'
|
||||
f' entering server-mode {curtimestr}{Clr.RST}'
|
||||
)
|
||||
logging.info(startupmsg)
|
||||
|
|
|
|||
4
dist/ba_data/python/baclassic/_store.py
vendored
4
dist/ba_data/python/baclassic/_store.py
vendored
|
|
@ -545,7 +545,7 @@ class StoreSubsystem:
|
|||
"""
|
||||
plus = babase.app.plus
|
||||
unowned_maps: set[str] = set()
|
||||
if not babase.app.headless_mode:
|
||||
if babase.app.env.gui:
|
||||
for map_section in self.get_store_layout()['maps']:
|
||||
for mapitem in map_section['items']:
|
||||
if plus is None or not plus.get_purchased(mapitem):
|
||||
|
|
@ -558,7 +558,7 @@ class StoreSubsystem:
|
|||
try:
|
||||
plus = babase.app.plus
|
||||
unowned_games: set[type[bascenev1.GameActivity]] = set()
|
||||
if not babase.app.headless_mode:
|
||||
if babase.app.env.gui:
|
||||
for section in self.get_store_layout()['minigames']:
|
||||
for mname in section['items']:
|
||||
if plus is None or not plus.get_purchased(mname):
|
||||
|
|
|
|||
50
dist/ba_data/python/baclassic/_subsystem.py
vendored
50
dist/ba_data/python/baclassic/_subsystem.py
vendored
|
|
@ -73,7 +73,7 @@ class ClassicSubsystem(babase.AppSubsystem):
|
|||
self.value_test_defaults: dict = {}
|
||||
self.special_offer: dict | None = None
|
||||
self.ping_thread_count = 0
|
||||
self.allow_ticket_purchases: bool = not babase.app.iircade_mode
|
||||
self.allow_ticket_purchases: bool = True
|
||||
|
||||
# Main Menu.
|
||||
self.main_menu_did_initial_transition = False
|
||||
|
|
@ -128,6 +128,10 @@ class ClassicSubsystem(babase.AppSubsystem):
|
|||
assert isinstance(self._env['platform'], str)
|
||||
return self._env['platform']
|
||||
|
||||
def scene_v1_protocol_version(self) -> int:
|
||||
"""(internal)"""
|
||||
return bascenev1.protocol_version()
|
||||
|
||||
@property
|
||||
def subplatform(self) -> str:
|
||||
"""String for subplatform.
|
||||
|
|
@ -153,6 +157,7 @@ class ClassicSubsystem(babase.AppSubsystem):
|
|||
plus = babase.app.plus
|
||||
assert plus is not None
|
||||
|
||||
env = babase.app.env
|
||||
cfg = babase.app.config
|
||||
|
||||
self.music.on_app_loading()
|
||||
|
|
@ -161,11 +166,7 @@ class ClassicSubsystem(babase.AppSubsystem):
|
|||
|
||||
# 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 babase.app.debug_build
|
||||
and not babase.app.test_build
|
||||
and not plus.is_blessed()
|
||||
):
|
||||
if not env.debug and not env.test and not plus.is_blessed():
|
||||
babase.screenmessage('WARNING: NON-BLESSED BUILD', color=(1, 0, 0))
|
||||
|
||||
# FIXME: This should not be hard-coded.
|
||||
|
|
@ -219,7 +220,7 @@ class ClassicSubsystem(babase.AppSubsystem):
|
|||
self.special_offer = cfg['pendingSpecialOffer']['o']
|
||||
show_offer()
|
||||
|
||||
if not babase.app.headless_mode:
|
||||
if babase.app.env.gui:
|
||||
babase.apptimer(3.0, check_special_offer)
|
||||
|
||||
# If there's a leftover log file, attempt to upload it to the
|
||||
|
|
@ -465,6 +466,37 @@ class ClassicSubsystem(babase.AppSubsystem):
|
|||
|
||||
_analytics.game_begin_analytics()
|
||||
|
||||
@classmethod
|
||||
def json_prep(cls, data: Any) -> Any:
|
||||
"""Return a json-friendly version of the provided data.
|
||||
|
||||
This converts any tuples to lists and any bytes to strings
|
||||
(interpreted as utf-8, ignoring errors). Logs errors (just once)
|
||||
if any data is modified/discarded/unsupported.
|
||||
"""
|
||||
|
||||
if isinstance(data, dict):
|
||||
return dict(
|
||||
(cls.json_prep(key), cls.json_prep(value))
|
||||
for key, value in list(data.items())
|
||||
)
|
||||
if isinstance(data, list):
|
||||
return [cls.json_prep(element) for element in data]
|
||||
if isinstance(data, tuple):
|
||||
logging.exception('json_prep encountered tuple')
|
||||
return [cls.json_prep(element) for element in data]
|
||||
if isinstance(data, bytes):
|
||||
try:
|
||||
return data.decode(errors='ignore')
|
||||
except Exception:
|
||||
logging.exception('json_prep encountered utf-8 decode error')
|
||||
return data.decode(errors='ignore')
|
||||
if not isinstance(data, (str, float, bool, type(None), int)):
|
||||
logging.exception(
|
||||
'got unsupported type in json_prep: %s', type(data)
|
||||
)
|
||||
return data
|
||||
|
||||
def master_server_v1_get(
|
||||
self,
|
||||
request: str,
|
||||
|
|
@ -750,7 +782,7 @@ class ClassicSubsystem(babase.AppSubsystem):
|
|||
from bauiv1lib.party import PartyWindow
|
||||
from babase import app
|
||||
|
||||
assert not app.headless_mode
|
||||
assert app.env.gui
|
||||
|
||||
bauiv1.getsound('swish').play()
|
||||
|
||||
|
|
@ -773,7 +805,7 @@ class ClassicSubsystem(babase.AppSubsystem):
|
|||
if not in_main_menu:
|
||||
set_ui_input_device(device_id)
|
||||
|
||||
if not babase.app.headless_mode:
|
||||
if babase.app.env.gui:
|
||||
bauiv1.getsound('swish').play()
|
||||
|
||||
babase.app.ui_v1.set_main_menu_window(
|
||||
|
|
|
|||
28
dist/ba_data/python/baclassic/_tips.py
vendored
28
dist/ba_data/python/baclassic/_tips.py
vendored
|
|
@ -106,16 +106,14 @@ def get_all_tips() -> list[str]:
|
|||
),
|
||||
]
|
||||
app = babase.app
|
||||
if not app.iircade_mode:
|
||||
tips += [
|
||||
'If your framerate is choppy, try turning down resolution\nor '
|
||||
'visuals in the game\'s graphics settings.'
|
||||
]
|
||||
tips += [
|
||||
'If your framerate is choppy, try turning down resolution\nor '
|
||||
'visuals in the game\'s graphics settings.'
|
||||
]
|
||||
if (
|
||||
app.classic is not None
|
||||
and app.classic.platform in ('android', 'ios')
|
||||
and not app.on_tv
|
||||
and not app.iircade_mode
|
||||
and not app.env.tv
|
||||
):
|
||||
tips += [
|
||||
(
|
||||
|
|
@ -124,11 +122,7 @@ def get_all_tips() -> list[str]:
|
|||
'in Settings->Graphics'
|
||||
),
|
||||
]
|
||||
if (
|
||||
app.classic is not None
|
||||
and app.classic.platform in ['mac', 'android']
|
||||
and not app.iircade_mode
|
||||
):
|
||||
if app.classic is not None and app.classic.platform in ['mac', 'android']:
|
||||
tips += [
|
||||
'Tired of the soundtrack? Replace it with your own!'
|
||||
'\nSee Settings->Audio->Soundtrack'
|
||||
|
|
@ -136,11 +130,11 @@ def get_all_tips() -> list[str]:
|
|||
|
||||
# Hot-plugging is currently only on some platforms.
|
||||
# FIXME: Should add a platform entry for this so don't forget to update it.
|
||||
if (
|
||||
app.classic is not None
|
||||
and app.classic.platform in ['mac', 'android', 'windows']
|
||||
and not app.iircade_mode
|
||||
):
|
||||
if app.classic is not None and app.classic.platform in [
|
||||
'mac',
|
||||
'android',
|
||||
'windows',
|
||||
]:
|
||||
tips += [
|
||||
'Players can join and leave in the middle of most games,\n'
|
||||
'and you can also plug and unplug controllers on the fly.',
|
||||
|
|
|
|||
35
dist/ba_data/python/bacommon/app.py
vendored
Normal file
35
dist/ba_data/python/bacommon/app.py
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Common high level values/functionality related to apps."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class AppExperience(Enum):
|
||||
"""Overall experience that can be provided by a Ballistica app.
|
||||
|
||||
This corresponds generally, but not exactly, to distinct apps built
|
||||
with Ballistica. However, a single app may support multiple experiences,
|
||||
or there may be multiple apps targeting one experience. Cloud components
|
||||
such as leagues are generally associated with an AppExperience.
|
||||
"""
|
||||
|
||||
# A special experience category that is supported everywhere. Used
|
||||
# for the default empty AppMode when starting the app, etc.
|
||||
EMPTY = 'empty'
|
||||
|
||||
# The traditional BombSquad experience: multiple players using
|
||||
# controllers in a single arena small enough for all action to be
|
||||
# viewed on a single screen.
|
||||
MELEE = 'melee'
|
||||
|
||||
# The traditional BombSquad Remote experience; buttons on a
|
||||
# touch-screen allowing a mobile device to be used as a game
|
||||
# controller.
|
||||
REMOTE = 'remote'
|
||||
22
dist/ba_data/python/baenv.py
vendored
22
dist/ba_data/python/baenv.py
vendored
|
|
@ -52,8 +52,8 @@ if TYPE_CHECKING:
|
|||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 21213
|
||||
TARGET_BALLISTICA_VERSION = '1.7.26'
|
||||
TARGET_BALLISTICA_BUILD = 21397
|
||||
TARGET_BALLISTICA_VERSION = '1.7.28'
|
||||
|
||||
|
||||
@dataclass
|
||||
|
|
@ -461,11 +461,12 @@ def _modular_main() -> None:
|
|||
# First baenv sets up things like Python paths the way the engine
|
||||
# needs them, and then we import and run the engine.
|
||||
#
|
||||
# Below we're doing a slightly fancier version of that. Namely we do
|
||||
# some processing of command line args to allow overriding of paths
|
||||
# or running explicit commands or whatever else. Our goal is that
|
||||
# this modular form of the app should be basically indistinguishable
|
||||
# from the monolithic form when used from the command line.
|
||||
# Below we're doing a slightly fancier version of that. Namely, we
|
||||
# do some processing of command line args to allow overriding of
|
||||
# paths or running explicit commands or whatever else. Our goal is
|
||||
# that this modular form of the app should be basically
|
||||
# indistinguishable from the monolithic form when used from the
|
||||
# command line.
|
||||
|
||||
try:
|
||||
# Take note that we're running via modular-main. The native
|
||||
|
|
@ -476,7 +477,8 @@ def _modular_main() -> None:
|
|||
# Deal with a few key things here ourself before even running
|
||||
# configure.
|
||||
|
||||
# Extract stuff below modifies this so work with a copy.
|
||||
# The extract_arg stuff below modifies this so we work with a
|
||||
# copy.
|
||||
args = sys.argv.copy()
|
||||
|
||||
# NOTE: We need to keep these arg long/short arg versions synced
|
||||
|
|
@ -496,8 +498,8 @@ def _modular_main() -> None:
|
|||
mods_dir = extract_arg(args, ['--mods-dir', '-m'], is_dir=True)
|
||||
|
||||
# We run configure() BEFORE importing babase. (part of its job
|
||||
# is to wrangle paths to determine where babase and everything
|
||||
# else gets loaded from).
|
||||
# is to wrangle paths which can affect where babase and
|
||||
# everything else gets loaded from).
|
||||
configure(
|
||||
config_dir=config_dir,
|
||||
data_dir=data_dir,
|
||||
|
|
|
|||
2
dist/ba_data/python/bascenev1/__init__.py
vendored
2
dist/ba_data/python/bascenev1/__init__.py
vendored
|
|
@ -112,6 +112,7 @@ from _bascenev1 import (
|
|||
newnode,
|
||||
Node,
|
||||
printnodes,
|
||||
protocol_version,
|
||||
release_gamepad_input,
|
||||
release_keyboard_input,
|
||||
reset_random_player_names,
|
||||
|
|
@ -383,6 +384,7 @@ __all__ = [
|
|||
'PowerupMessage',
|
||||
'print_live_object_warnings',
|
||||
'printnodes',
|
||||
'protocol_version',
|
||||
'pushcall',
|
||||
'register_map',
|
||||
'release_gamepad_input',
|
||||
|
|
|
|||
12
dist/ba_data/python/bascenev1/_appmode.py
vendored
12
dist/ba_data/python/bascenev1/_appmode.py
vendored
|
|
@ -5,7 +5,9 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bacommon.app import AppExperience
|
||||
from babase import AppMode, AppIntentExec, AppIntentDefault
|
||||
|
||||
import _bascenev1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -16,7 +18,11 @@ class SceneV1AppMode(AppMode):
|
|||
"""Our app-mode."""
|
||||
|
||||
@classmethod
|
||||
def supports_intent(cls, intent: AppIntent) -> bool:
|
||||
def get_app_experience(cls) -> AppExperience:
|
||||
return AppExperience.MELEE
|
||||
|
||||
@classmethod
|
||||
def _supports_intent(cls, intent: AppIntent) -> bool:
|
||||
# We support default and exec intents currently.
|
||||
return isinstance(intent, AppIntentExec | AppIntentDefault)
|
||||
|
||||
|
|
@ -29,8 +35,8 @@ class SceneV1AppMode(AppMode):
|
|||
|
||||
def on_activate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_bascenev1.app_mode_activate()
|
||||
_bascenev1.on_app_mode_activate()
|
||||
|
||||
def on_deactivate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_bascenev1.app_mode_deactivate()
|
||||
_bascenev1.on_app_mode_deactivate()
|
||||
|
|
|
|||
5
dist/ba_data/python/bascenev1/_coopgame.py
vendored
5
dist/ba_data/python/bascenev1/_coopgame.py
vendored
|
|
@ -53,7 +53,8 @@ class CoopGameActivity(GameActivity[PlayerT, TeamT]):
|
|||
super().on_begin()
|
||||
|
||||
# Show achievements remaining.
|
||||
if not (babase.app.demo_mode or babase.app.arcade_mode):
|
||||
env = babase.app.env
|
||||
if not (env.demo or env.arcade):
|
||||
_bascenev1.timer(
|
||||
3.8, babase.WeakCall(self._show_remaining_achievements)
|
||||
)
|
||||
|
|
@ -108,7 +109,7 @@ class CoopGameActivity(GameActivity[PlayerT, TeamT]):
|
|||
)
|
||||
if not a.complete
|
||||
]
|
||||
vrmode = babase.app.vr_mode
|
||||
vrmode = babase.app.env.vr
|
||||
if achievements:
|
||||
Text(
|
||||
babase.Lstr(resource='achievementsRemainingText'),
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ class CoopSession(Session):
|
|||
# Hmm; no players anywhere. Let's end the entire session if we're
|
||||
# running a GUI (or just the current game if we're running headless).
|
||||
else:
|
||||
if not babase.app.headless_mode:
|
||||
if babase.app.env.gui:
|
||||
self.end()
|
||||
else:
|
||||
if isinstance(activity, GameActivity):
|
||||
|
|
@ -277,6 +277,7 @@ class CoopSession(Session):
|
|||
from bascenev1._score import ScoreType
|
||||
|
||||
app = babase.app
|
||||
env = app.env
|
||||
classic = app.classic
|
||||
assert classic is not None
|
||||
|
||||
|
|
@ -291,7 +292,7 @@ class CoopSession(Session):
|
|||
# If we're running with a gui and at any point we have no
|
||||
# in-game players, quit out of the session (this can happen if
|
||||
# someone leaves in the tutorial for instance).
|
||||
if not babase.app.headless_mode:
|
||||
if env.gui:
|
||||
active_players = [p for p in self.sessionplayers if p.in_game]
|
||||
if not active_players:
|
||||
self.end()
|
||||
|
|
@ -317,7 +318,7 @@ class CoopSession(Session):
|
|||
if (
|
||||
isinstance(activity, JoinActivity)
|
||||
and self.campaign_level_name == 'Onslaught Training'
|
||||
and not (app.demo_mode or app.arcade_mode)
|
||||
and not (env.demo or env.arcade)
|
||||
):
|
||||
if self._tutorial_activity is None:
|
||||
raise RuntimeError('Tutorial not preloaded properly.')
|
||||
|
|
@ -339,7 +340,7 @@ class CoopSession(Session):
|
|||
# Now flip the current activity..
|
||||
self.setactivity(next_game)
|
||||
|
||||
if not (app.demo_mode or app.arcade_mode):
|
||||
if not (env.demo or env.arcade):
|
||||
if self.tournament_id is not None:
|
||||
self._custom_menu_ui = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -600,7 +600,7 @@ class GameActivity(Activity[PlayerT, TeamT]):
|
|||
translate=('gameDescriptions', sb_desc_l[0]), subs=subs
|
||||
)
|
||||
sb_desc = translation
|
||||
vrmode = babase.app.vr_mode
|
||||
vrmode = babase.app.env.vr
|
||||
yval = -34 if is_empty else -20
|
||||
yval -= 16
|
||||
sbpos = (
|
||||
|
|
@ -706,7 +706,7 @@ class GameActivity(Activity[PlayerT, TeamT]):
|
|||
resource='epicDescriptionFilterText',
|
||||
subs=[('${DESCRIPTION}', translation)],
|
||||
)
|
||||
vrmode = babase.app.vr_mode
|
||||
vrmode = babase.app.env.vr
|
||||
dnode = _bascenev1.newnode(
|
||||
'text',
|
||||
attrs={
|
||||
|
|
@ -761,7 +761,7 @@ class GameActivity(Activity[PlayerT, TeamT]):
|
|||
base_position = (75, 50)
|
||||
tip_scale = 0.8
|
||||
tip_title_scale = 1.2
|
||||
vrmode = babase.app.vr_mode
|
||||
vrmode = babase.app.env.vr
|
||||
|
||||
t_offs = -350.0
|
||||
tnode = _bascenev1.newnode(
|
||||
|
|
|
|||
2
dist/ba_data/python/bascenev1/_gameutils.py
vendored
2
dist/ba_data/python/bascenev1/_gameutils.py
vendored
|
|
@ -185,7 +185,7 @@ def show_damage_count(
|
|||
# (connected clients may have differing configs so they won't
|
||||
# get the intended results).
|
||||
assert app.classic is not None
|
||||
do_big = app.ui_v1.uiscale is babase.UIScale.SMALL or app.vr_mode
|
||||
do_big = app.ui_v1.uiscale is babase.UIScale.SMALL or app.env.vr
|
||||
txtnode = _bascenev1.newnode(
|
||||
'text',
|
||||
attrs={
|
||||
|
|
|
|||
27
dist/ba_data/python/bascenev1/_lobby.py
vendored
27
dist/ba_data/python/bascenev1/_lobby.py
vendored
|
|
@ -33,15 +33,11 @@ class JoinInfo:
|
|||
from bascenev1._nodeactor import NodeActor
|
||||
|
||||
self._state = 0
|
||||
self._press_to_punch: str | bascenev1.Lstr = (
|
||||
'C'
|
||||
if babase.app.iircade_mode
|
||||
else babase.charstr(babase.SpecialChar.LEFT_BUTTON)
|
||||
self._press_to_punch: str | bascenev1.Lstr = babase.charstr(
|
||||
babase.SpecialChar.LEFT_BUTTON
|
||||
)
|
||||
self._press_to_bomb: str | bascenev1.Lstr = (
|
||||
'B'
|
||||
if babase.app.iircade_mode
|
||||
else babase.charstr(babase.SpecialChar.RIGHT_BUTTON)
|
||||
self._press_to_bomb: str | bascenev1.Lstr = babase.charstr(
|
||||
babase.SpecialChar.RIGHT_BUTTON
|
||||
)
|
||||
self._joinmsg = babase.Lstr(resource='pressAnyButtonToJoinText')
|
||||
can_switch_teams = len(lobby.sessionteams) > 1
|
||||
|
|
@ -53,7 +49,7 @@ class JoinInfo:
|
|||
if keyboard is not None:
|
||||
self._update_for_keyboard(keyboard)
|
||||
|
||||
flatness = 1.0 if babase.app.vr_mode else 0.0
|
||||
flatness = 1.0 if babase.app.env.vr else 0.0
|
||||
self._text = NodeActor(
|
||||
_bascenev1.newnode(
|
||||
'text',
|
||||
|
|
@ -69,7 +65,7 @@ class JoinInfo:
|
|||
)
|
||||
)
|
||||
|
||||
if babase.app.demo_mode or babase.app.arcade_mode:
|
||||
if babase.app.env.demo or babase.app.env.arcade:
|
||||
self._messages = [self._joinmsg]
|
||||
else:
|
||||
msg1 = babase.Lstr(
|
||||
|
|
@ -438,6 +434,7 @@ class Chooser:
|
|||
"""Reload all player profiles."""
|
||||
|
||||
app = babase.app
|
||||
env = app.env
|
||||
assert app.classic is not None
|
||||
|
||||
# Re-construct our profile index and other stuff since the profile
|
||||
|
|
@ -465,7 +462,7 @@ class Chooser:
|
|||
# (non-unicode/non-json) version.
|
||||
# Make sure they conform to our standards
|
||||
# (unicode strings, no tuples, etc)
|
||||
self._profiles = babase.json_prep(self._profiles)
|
||||
self._profiles = app.classic.json_prep(self._profiles)
|
||||
|
||||
# Filter out any characters we're unaware of.
|
||||
for profile in list(self._profiles.items()):
|
||||
|
|
@ -479,17 +476,13 @@ class Chooser:
|
|||
self._profiles['_random'] = {}
|
||||
|
||||
# In kiosk mode we disable account profiles to force random.
|
||||
if app.demo_mode or app.arcade_mode:
|
||||
if env.demo or env.arcade:
|
||||
if '__account__' in self._profiles:
|
||||
del self._profiles['__account__']
|
||||
|
||||
# For local devices, add it an 'edit' option which will pop up
|
||||
# the profile window.
|
||||
if (
|
||||
not is_remote
|
||||
and not is_test_input
|
||||
and not (app.demo_mode or app.arcade_mode)
|
||||
):
|
||||
if not is_remote and not is_test_input and not (env.demo or env.arcade):
|
||||
self._profiles['_edit'] = {}
|
||||
|
||||
# Build a sorted name list we can iterate through.
|
||||
|
|
|
|||
2
dist/ba_data/python/bascenev1/_map.py
vendored
2
dist/ba_data/python/bascenev1/_map.py
vendored
|
|
@ -371,5 +371,5 @@ def register_map(maptype: type[Map]) -> None:
|
|||
"""Register a map class with the game."""
|
||||
assert babase.app.classic is not None
|
||||
if maptype.name in babase.app.classic.maps:
|
||||
raise RuntimeError('map "' + maptype.name + '" already registered')
|
||||
raise RuntimeError(f'Map "{maptype.name}" is already registered.')
|
||||
babase.app.classic.maps[maptype.name] = maptype
|
||||
|
|
|
|||
2
dist/ba_data/python/bascenev1/_profile.py
vendored
2
dist/ba_data/python/bascenev1/_profile.py
vendored
|
|
@ -69,7 +69,7 @@ def get_player_profile_colors(
|
|||
|
||||
# Special case: when being asked for a random color in kiosk mode,
|
||||
# always return default purple.
|
||||
if (babase.app.demo_mode or babase.app.arcade_mode) and profilename is None:
|
||||
if (babase.app.env.demo or babase.app.env.arcade) and profilename is None:
|
||||
color = (0.5, 0.4, 1.0)
|
||||
highlight = (0.4, 0.4, 0.5)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ class CoopJoinActivity(bs.JoinActivity):
|
|||
def _show_remaining_achievements(self) -> None:
|
||||
from bascenev1lib.actor.text import Text
|
||||
|
||||
app = bs.app
|
||||
env = app.env
|
||||
|
||||
# We only show achievements and challenges for CoopGameActivities.
|
||||
session = self.session
|
||||
assert isinstance(session, bs.CoopSession)
|
||||
|
|
@ -64,19 +67,15 @@ class CoopJoinActivity(bs.JoinActivity):
|
|||
ts_h_offs = 60
|
||||
|
||||
# Show remaining achievements in some cases.
|
||||
if bs.app.classic is not None and not (
|
||||
bs.app.demo_mode or bs.app.arcade_mode
|
||||
):
|
||||
if app.classic is not None and not (env.demo or env.arcade):
|
||||
achievements = [
|
||||
a
|
||||
for a in bs.app.classic.ach.achievements_for_coop_level(
|
||||
levelname
|
||||
)
|
||||
for a in app.classic.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 = bs.app.vr_mode
|
||||
vrmode = env.vr
|
||||
if have_achievements:
|
||||
Text(
|
||||
bs.Lstr(resource='achievementsRemainingText'),
|
||||
|
|
|
|||
|
|
@ -351,6 +351,8 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
|||
|
||||
assert bui.app.classic is not None
|
||||
|
||||
env = bui.app.env
|
||||
|
||||
delay = 0.7 if (self._score is not None) else 0.0
|
||||
|
||||
# If there's no players left in the game, lets not show the UI
|
||||
|
|
@ -406,9 +408,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
|||
else:
|
||||
pass
|
||||
|
||||
show_next_button = self._is_more_levels and not (
|
||||
bui.app.demo_mode or bui.app.arcade_mode
|
||||
)
|
||||
show_next_button = self._is_more_levels and not (env.demo or env.arcade)
|
||||
|
||||
if not show_next_button:
|
||||
h_offs += 70
|
||||
|
|
@ -486,7 +486,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
|||
v_offs + 560.0,
|
||||
)
|
||||
|
||||
if bui.app.demo_mode or bui.app.arcade_mode:
|
||||
if env.demo or env.arcade:
|
||||
self._league_rank_button = None
|
||||
self._store_button_instance = None
|
||||
else:
|
||||
|
|
@ -595,7 +595,9 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
|||
# pylint: disable=too-many-locals
|
||||
super().on_begin()
|
||||
|
||||
plus = bs.app.plus
|
||||
app = bs.app
|
||||
env = app.env
|
||||
plus = app.plus
|
||||
assert plus is not None
|
||||
|
||||
self._begin_time = bs.time()
|
||||
|
|
@ -624,7 +626,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
|||
# If this is the first time we completed it, set the next one
|
||||
# as current.
|
||||
if self._newly_complete:
|
||||
cfg = bs.app.config
|
||||
cfg = app.config
|
||||
cfg['Selected Coop Game'] = (
|
||||
self._campaign.name + ':' + self._next_level_name
|
||||
)
|
||||
|
|
@ -637,7 +639,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
|||
self._is_complete
|
||||
and self._victory
|
||||
and self._is_more_levels
|
||||
and not (bs.app.demo_mode or bs.app.arcade_mode)
|
||||
and not (env.demo or env.arcade)
|
||||
):
|
||||
Text(
|
||||
bs.Lstr(
|
||||
|
|
@ -715,7 +717,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
|||
position=(0, 230),
|
||||
).autoretain()
|
||||
|
||||
if bs.app.classic is not None and bs.app.classic.server is None:
|
||||
if app.classic is not None and app.classic.server is None:
|
||||
# If we're running in normal non-headless build, show this text
|
||||
# because only host can continue the game.
|
||||
adisp = plus.get_v1_account_display_string()
|
||||
|
|
@ -828,7 +830,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
|||
)
|
||||
if plus.get_v1_account_state() != 'signed_in':
|
||||
# We expect this only in kiosk mode; complain otherwise.
|
||||
if not (bs.app.demo_mode or bs.app.arcade_mode):
|
||||
if not (env.demo or env.arcade):
|
||||
logging.error('got not-signed-in at score-submit; unexpected')
|
||||
bs.pushcall(bs.WeakCall(self._got_score_results, None))
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ class Background(bs.Actor):
|
|||
self.node.connectattr('opacity', self.logo, 'opacity')
|
||||
# add jitter/pulse for a stop-motion-y look unless we're in VR
|
||||
# in which case stillness is better
|
||||
if not bs.app.vr_mode:
|
||||
if not bs.app.env.vr:
|
||||
self.cmb = bs.newnode(
|
||||
'combine', owner=self.node, attrs={'size': 2}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -58,45 +58,11 @@ class ControlsGuide(bs.Actor):
|
|||
self._update_timer: bs.Timer | None = None
|
||||
self._title_text: bs.Node | None
|
||||
clr: Sequence[float]
|
||||
extra_pos_1: tuple[float, float] | None
|
||||
extra_pos_2: tuple[float, float] | None
|
||||
if bs.app.iircade_mode:
|
||||
xtweak = 0.2
|
||||
ytweak = 0.2
|
||||
jump_pos = (
|
||||
position[0] + offs * (-1.2 + xtweak),
|
||||
position[1] + offs * (0.1 + ytweak),
|
||||
)
|
||||
bomb_pos = (
|
||||
position[0] + offs * (0.0 + xtweak),
|
||||
position[1] + offs * (0.5 + ytweak),
|
||||
)
|
||||
punch_pos = (
|
||||
position[0] + offs * (1.2 + xtweak),
|
||||
position[1] + offs * (0.5 + ytweak),
|
||||
)
|
||||
|
||||
pickup_pos = (
|
||||
position[0] + offs * (-1.4 + xtweak),
|
||||
position[1] + offs * (-1.2 + ytweak),
|
||||
)
|
||||
extra_pos_1 = (
|
||||
position[0] + offs * (-0.2 + xtweak),
|
||||
position[1] + offs * (-0.8 + ytweak),
|
||||
)
|
||||
extra_pos_2 = (
|
||||
position[0] + offs * (1.0 + xtweak),
|
||||
position[1] + offs * (-0.8 + ytweak),
|
||||
)
|
||||
self._force_hide_button_names = True
|
||||
else:
|
||||
punch_pos = (position[0] - offs * 1.1, position[1])
|
||||
jump_pos = (position[0], position[1] - offs)
|
||||
bomb_pos = (position[0] + offs * 1.1, position[1])
|
||||
pickup_pos = (position[0], position[1] + offs)
|
||||
extra_pos_1 = None
|
||||
extra_pos_2 = None
|
||||
self._force_hide_button_names = False
|
||||
punch_pos = (position[0] - offs * 1.1, position[1])
|
||||
jump_pos = (position[0], position[1] - offs)
|
||||
bomb_pos = (position[0] + offs * 1.1, position[1])
|
||||
pickup_pos = (position[0], position[1] + offs)
|
||||
self._force_hide_button_names = False
|
||||
|
||||
if show_title:
|
||||
self._title_text_pos_top = (
|
||||
|
|
@ -242,13 +208,13 @@ class ControlsGuide(bs.Actor):
|
|||
clr = (0.9, 0.9, 2.0, 1.0) if bright else (0.8, 0.8, 2.0, 1.0)
|
||||
self._run_text_pos_top = (position[0], position[1] - 135.0 * scale)
|
||||
self._run_text_pos_bottom = (position[0], position[1] - 172.0 * scale)
|
||||
sval = 1.0 * scale if bs.app.vr_mode else 0.8 * scale
|
||||
sval = 1.0 * scale if bs.app.env.vr else 0.8 * scale
|
||||
self._run_text = bs.newnode(
|
||||
'text',
|
||||
attrs={
|
||||
'scale': sval,
|
||||
'host_only': True,
|
||||
'shadow': 1.0 if bs.app.vr_mode else 0.5,
|
||||
'shadow': 1.0 if bs.app.env.vr else 0.5,
|
||||
'flatness': 1.0,
|
||||
'maxwidth': 380,
|
||||
'v_align': 'top',
|
||||
|
|
@ -271,36 +237,8 @@ class ControlsGuide(bs.Actor):
|
|||
},
|
||||
)
|
||||
|
||||
if extra_pos_1 is not None:
|
||||
self._extra_image_1: bs.Node | None = bs.newnode(
|
||||
'image',
|
||||
attrs={
|
||||
'texture': bs.gettexture('nub'),
|
||||
'absolute_scale': True,
|
||||
'host_only': True,
|
||||
'vr_depth': 10,
|
||||
'position': extra_pos_1,
|
||||
'scale': (image_size, image_size),
|
||||
'color': (0.5, 0.5, 0.5),
|
||||
},
|
||||
)
|
||||
else:
|
||||
self._extra_image_1 = None
|
||||
if extra_pos_2 is not None:
|
||||
self._extra_image_2: bs.Node | None = bs.newnode(
|
||||
'image',
|
||||
attrs={
|
||||
'texture': bs.gettexture('nub'),
|
||||
'absolute_scale': True,
|
||||
'host_only': True,
|
||||
'vr_depth': 10,
|
||||
'position': extra_pos_2,
|
||||
'scale': (image_size, image_size),
|
||||
'color': (0.5, 0.5, 0.5),
|
||||
},
|
||||
)
|
||||
else:
|
||||
self._extra_image_2 = None
|
||||
self._extra_image_1 = None
|
||||
self._extra_image_2 = None
|
||||
|
||||
self._nodes = [
|
||||
self._bomb_image,
|
||||
|
|
@ -317,10 +255,6 @@ class ControlsGuide(bs.Actor):
|
|||
if show_title:
|
||||
assert self._title_text
|
||||
self._nodes.append(self._title_text)
|
||||
if self._extra_image_1 is not None:
|
||||
self._nodes.append(self._extra_image_1)
|
||||
if self._extra_image_2 is not None:
|
||||
self._nodes.append(self._extra_image_2)
|
||||
|
||||
# Start everything invisible.
|
||||
for node in self._nodes:
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ class PlayerSpaz(Spaz):
|
|||
picked_up_by = msg.node.source_player
|
||||
if picked_up_by:
|
||||
self.last_player_attacked_by = picked_up_by
|
||||
self.last_attacked_time = bs.apptime()
|
||||
self.last_attacked_time = bs.time()
|
||||
self.last_attacked_type = ('picked_up', 'default')
|
||||
elif isinstance(msg, bs.StandMessage):
|
||||
super().handlemessage(msg) # Augment standard behavior.
|
||||
|
|
@ -247,7 +247,7 @@ class PlayerSpaz(Spaz):
|
|||
# something like last_actor_attacked_by to fix that.
|
||||
if (
|
||||
self.last_player_attacked_by
|
||||
and bs.apptime() - self.last_attacked_time < 4.0
|
||||
and bs.time() - self.last_attacked_time < 4.0
|
||||
):
|
||||
killerplayer = self.last_player_attacked_by
|
||||
else:
|
||||
|
|
@ -278,7 +278,7 @@ class PlayerSpaz(Spaz):
|
|||
source_player = msg.get_source_player(type(self._player))
|
||||
if source_player:
|
||||
self.last_player_attacked_by = source_player
|
||||
self.last_attacked_time = bs.apptime()
|
||||
self.last_attacked_time = bs.time()
|
||||
self.last_attacked_type = (msg.hit_type, msg.hit_subtype)
|
||||
super().handlemessage(msg) # Augment standard behavior.
|
||||
activity = self._activity()
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class _Entry:
|
|||
|
||||
# FIXME: Should not do things conditionally for vr-mode, as there may
|
||||
# be non-vr clients connected which will also get these value.
|
||||
vrmode = bs.app.vr_mode
|
||||
vrmode = bs.app.env.vr
|
||||
|
||||
if self._do_cover:
|
||||
if vrmode:
|
||||
|
|
|
|||
36
dist/ba_data/python/bascenev1lib/actor/spaz.py
vendored
36
dist/ba_data/python/bascenev1lib/actor/spaz.py
vendored
|
|
@ -19,6 +19,9 @@ if TYPE_CHECKING:
|
|||
from typing import Any, Sequence, Callable
|
||||
|
||||
POWERUP_WEAR_OFF_TIME = 20000
|
||||
|
||||
# Obsolete - just used for demo guy now.
|
||||
BASE_PUNCH_POWER_SCALE = 1.2
|
||||
BASE_PUNCH_COOLDOWN = 400
|
||||
|
||||
|
||||
|
|
@ -95,7 +98,7 @@ class Spaz(bs.Actor):
|
|||
self.source_player = source_player
|
||||
self._dead = False
|
||||
if self._demo_mode: # Preserve old behavior.
|
||||
self._punch_power_scale = 1.2
|
||||
self._punch_power_scale = BASE_PUNCH_POWER_SCALE
|
||||
else:
|
||||
self._punch_power_scale = factory.punch_power_scale
|
||||
self.fly = bs.getactivity().globalsnode.happy_thoughts_mode
|
||||
|
|
@ -189,7 +192,7 @@ class Spaz(bs.Actor):
|
|||
self.land_mine_count = 0
|
||||
self.blast_radius = 2.0
|
||||
self.powerups_expire = powerups_expire
|
||||
if self._demo_mode: # preserve old behavior
|
||||
if self._demo_mode: # Preserve old behavior.
|
||||
self._punch_cooldown = BASE_PUNCH_COOLDOWN
|
||||
else:
|
||||
self._punch_cooldown = factory.punch_cooldown
|
||||
|
|
@ -482,12 +485,12 @@ class Spaz(bs.Actor):
|
|||
Called to 'press bomb' on this spaz;
|
||||
used for player or AI connections.
|
||||
"""
|
||||
if not self.node:
|
||||
return
|
||||
|
||||
if self._dead or self.frozen:
|
||||
return
|
||||
if self.node.knockout > 0.0:
|
||||
if (
|
||||
not self.node
|
||||
or self._dead
|
||||
or self.frozen
|
||||
or self.node.knockout > 0.0
|
||||
):
|
||||
return
|
||||
t_ms = int(bs.time() * 1000.0)
|
||||
assert isinstance(t_ms, int)
|
||||
|
|
@ -514,15 +517,14 @@ class Spaz(bs.Actor):
|
|||
"""
|
||||
if not self.node:
|
||||
return
|
||||
|
||||
t_ms = int(bs.time() * 1000.0)
|
||||
assert isinstance(t_ms, int)
|
||||
self.last_run_time_ms = t_ms
|
||||
self.node.run = value
|
||||
|
||||
# filtering these events would be tough since its an analog
|
||||
# Filtering these events would be tough since its an analog
|
||||
# value, but lets still pass full 0-to-1 presses along to
|
||||
# the turbo filter to punish players if it looks like they're turbo-ing
|
||||
# the turbo filter to punish players if it looks like they're turbo-ing.
|
||||
if self._last_run_value < 0.01 and value > 0.99:
|
||||
self._turbo_filter_add_press('run')
|
||||
|
||||
|
|
@ -535,7 +537,7 @@ class Spaz(bs.Actor):
|
|||
"""
|
||||
if not self.node:
|
||||
return
|
||||
# not adding a cooldown time here for now; slightly worried
|
||||
# Not adding a cooldown time here for now; slightly worried
|
||||
# input events get clustered up during net-games and we'd wind up
|
||||
# killing a lot and making it hard to fly.. should look into this.
|
||||
self.node.fly_pressed = True
|
||||
|
|
@ -610,7 +612,7 @@ class Spaz(bs.Actor):
|
|||
self.node, attr, materials + (factory.curse_material,)
|
||||
)
|
||||
|
||||
# None specifies no time limit
|
||||
# None specifies no time limit.
|
||||
assert self.node
|
||||
if self.curse_time is None:
|
||||
self.node.curse_death_time = -1
|
||||
|
|
@ -878,7 +880,7 @@ class Spaz(bs.Actor):
|
|||
self.node.frozen = True
|
||||
bs.timer(5.0, bs.WeakCall(self.handlemessage, bs.ThawMessage()))
|
||||
# Instantly shatter if we're already dead.
|
||||
# (otherwise its hard to tell we're dead)
|
||||
# (otherwise its hard to tell we're dead).
|
||||
if self.hitpoints <= 0:
|
||||
self.shatter()
|
||||
|
||||
|
|
@ -898,7 +900,7 @@ class Spaz(bs.Actor):
|
|||
return True
|
||||
|
||||
# If we were recently hit, don't count this as another.
|
||||
# (so punch flurries and bomb pileups essentially count as 1 hit)
|
||||
# (so punch flurries and bomb pileups essentially count as 1 hit).
|
||||
local_time = int(bs.time() * 1000.0)
|
||||
assert isinstance(local_time, int)
|
||||
if (
|
||||
|
|
@ -1133,11 +1135,11 @@ class Spaz(bs.Actor):
|
|||
)
|
||||
if self.hitpoints > 0:
|
||||
# It's kinda crappy to die from impacts, so lets reduce
|
||||
# impact damage by a reasonable amount *if* it'll keep us alive
|
||||
# impact damage by a reasonable amount *if* it'll keep us alive.
|
||||
if msg.hit_type == 'impact' and damage > self.hitpoints:
|
||||
# Drop damage to whatever puts us at 10 hit points,
|
||||
# or 200 less than it used to be whichever is greater
|
||||
# (so it *can* still kill us if its high enough)
|
||||
# (so it *can* still kill us if its high enough).
|
||||
newdamage = max(damage - 200, self.hitpoints - 10)
|
||||
damage = newdamage
|
||||
self.node.handlemessage('flash')
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ class ZoomText(bs.Actor):
|
|||
)
|
||||
|
||||
# we never jitter in vr mode..
|
||||
if bs.app.vr_mode:
|
||||
if bs.app.env.vr:
|
||||
jitter = 0.0
|
||||
|
||||
# if they want jitter, animate its position slightly...
|
||||
|
|
|
|||
|
|
@ -483,9 +483,6 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
|
|||
except bs.NotFoundError:
|
||||
return
|
||||
|
||||
if not spaz.is_alive():
|
||||
return
|
||||
|
||||
player = spaz.getplayer(Player, True)
|
||||
|
||||
if player:
|
||||
|
|
|
|||
|
|
@ -487,8 +487,8 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
|
|||
|
||||
super().on_begin()
|
||||
|
||||
# Show controls help in kiosk mode.
|
||||
if bs.app.demo_mode or bs.app.arcade_mode:
|
||||
# Show controls help in demo or arcade mode.
|
||||
if bs.app.env.demo or bs.app.env.arcade:
|
||||
controlsguide.ControlsGuide(
|
||||
delay=3.0, lifespan=10.0, bright=True
|
||||
).autoretain()
|
||||
|
|
|
|||
10
dist/ba_data/python/bascenev1lib/game/hockey.py
vendored
10
dist/ba_data/python/bascenev1lib/game/hockey.py
vendored
|
|
@ -60,11 +60,11 @@ class Puck(bs.Actor):
|
|||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, bs.DieMessage):
|
||||
assert self.node
|
||||
self.node.delete()
|
||||
activity = self._activity()
|
||||
if activity and not msg.immediate:
|
||||
activity.handlemessage(PuckDiedMessage(self))
|
||||
if self.node:
|
||||
self.node.delete()
|
||||
activity = self._activity()
|
||||
if activity and not msg.immediate:
|
||||
activity.handlemessage(PuckDiedMessage(self))
|
||||
|
||||
# If we go out of bounds, move back to where we started.
|
||||
elif isinstance(msg, bs.OutOfBoundsMessage):
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ class KingOfTheHillGame(bs.TeamGameActivity[Player, Team]):
|
|||
'materials': flagmats,
|
||||
},
|
||||
)
|
||||
self._update_scoreboard()
|
||||
self._update_flag_state()
|
||||
|
||||
def _tick(self) -> None:
|
||||
|
|
|
|||
|
|
@ -550,8 +550,9 @@ class OnslaughtGame(bs.CoopGameActivity[Player, Team]):
|
|||
]
|
||||
|
||||
elif self._preset in {Preset.UBER, Preset.UBER_EASY}:
|
||||
# Show controls help in demo/arcade modes.
|
||||
if bs.app.demo_mode or bs.app.arcade_mode:
|
||||
# Show controls help in demo or arcade modes.
|
||||
env = bs.app.env
|
||||
if env.demo or env.arcade:
|
||||
ControlsGuide(
|
||||
delay=3.0, lifespan=10.0, bright=True
|
||||
).autoretain()
|
||||
|
|
|
|||
|
|
@ -478,7 +478,7 @@ class RunaroundGame(bs.CoopGameActivity[Player, Team]):
|
|||
)
|
||||
# FIXME; should not set things based on vr mode.
|
||||
# (won't look right to non-vr connected clients, etc)
|
||||
vrmode = bs.app.vr_mode
|
||||
vrmode = bs.app.env.vr
|
||||
self._lives_text = bs.NodeActor(
|
||||
bs.newnode(
|
||||
'text',
|
||||
|
|
|
|||
70
dist/ba_data/python/bascenev1lib/mainmenu.py
vendored
70
dist/ba_data/python/bascenev1lib/mainmenu.py
vendored
|
|
@ -50,6 +50,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||
super().on_transition_in()
|
||||
random.seed(123)
|
||||
app = bs.app
|
||||
env = app.env
|
||||
assert app.classic is not None
|
||||
|
||||
plus = bui.app.plus
|
||||
|
|
@ -59,9 +60,9 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||
# the host is VR mode or not (clients may differ in that regard).
|
||||
# Any differences need to happen at the engine level so everyone
|
||||
# sees things in their own optimal way.
|
||||
vr_mode = bs.app.vr_mode
|
||||
vr_mode = bs.app.env.vr
|
||||
|
||||
if not bs.app.toolbar_test:
|
||||
if not bs.app.ui_v1.use_toolbars:
|
||||
color = (1.0, 1.0, 1.0, 1.0) if vr_mode else (0.5, 0.6, 0.5, 0.6)
|
||||
|
||||
# FIXME: Need a node attr for vr-specific-scale.
|
||||
|
|
@ -117,21 +118,21 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||
# the host is vr mode or not (clients may not be or vice versa).
|
||||
# Any differences need to happen at the engine level so everyone sees
|
||||
# things in their own optimal way.
|
||||
vr_mode = app.vr_mode
|
||||
vr_mode = app.env.vr
|
||||
uiscale = app.ui_v1.uiscale
|
||||
|
||||
# In cases where we're doing lots of dev work lets always show the
|
||||
# build number.
|
||||
force_show_build_number = False
|
||||
|
||||
if not bs.app.toolbar_test:
|
||||
if app.debug_build or app.test_build or force_show_build_number:
|
||||
if app.debug_build:
|
||||
if not bs.app.ui_v1.use_toolbars:
|
||||
if env.debug or env.test or force_show_build_number:
|
||||
if env.debug:
|
||||
text = bs.Lstr(
|
||||
value='${V} (${B}) (${D})',
|
||||
subs=[
|
||||
('${V}', app.version),
|
||||
('${B}', str(app.build_number)),
|
||||
('${V}', app.env.version),
|
||||
('${B}', str(app.env.build_number)),
|
||||
('${D}', bs.Lstr(resource='debugText')),
|
||||
],
|
||||
)
|
||||
|
|
@ -139,12 +140,12 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||
text = bs.Lstr(
|
||||
value='${V} (${B})',
|
||||
subs=[
|
||||
('${V}', app.version),
|
||||
('${B}', str(app.build_number)),
|
||||
('${V}', app.env.version),
|
||||
('${B}', str(app.env.build_number)),
|
||||
],
|
||||
)
|
||||
else:
|
||||
text = bs.Lstr(value='${V}', subs=[('${V}', app.version)])
|
||||
text = bs.Lstr(value='${V}', subs=[('${V}', app.env.version)])
|
||||
scale = 0.9 if (uiscale is bs.UIScale.SMALL or vr_mode) else 0.7
|
||||
color = (1, 1, 1, 1) if vr_mode else (0.5, 0.6, 0.5, 0.7)
|
||||
self.version = bs.NodeActor(
|
||||
|
|
@ -168,31 +169,9 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||
assert self.version.node
|
||||
bs.animate(self.version.node, 'opacity', {2.3: 0, 3.0: 1.0})
|
||||
|
||||
# Show the iircade logo on our iircade build.
|
||||
if app.iircade_mode:
|
||||
img = bs.NodeActor(
|
||||
bs.newnode(
|
||||
'image',
|
||||
attrs={
|
||||
'texture': bs.gettexture('iircadeLogo'),
|
||||
'attach': 'center',
|
||||
'scale': (250, 250),
|
||||
'position': (0, 0),
|
||||
'tilt_translate': 0.21,
|
||||
'absolute_scale': True,
|
||||
},
|
||||
)
|
||||
).autoretain()
|
||||
imgdelay = (
|
||||
0.0 if app.classic.main_menu_did_initial_transition else 1.0
|
||||
)
|
||||
bs.animate(
|
||||
img.node, 'opacity', {imgdelay + 1.5: 0.0, imgdelay + 2.5: 1.0}
|
||||
)
|
||||
|
||||
# Throw in test build info.
|
||||
self.beta_info = self.beta_info_2 = None
|
||||
if app.test_build and not (app.demo_mode or app.arcade_mode):
|
||||
if env.test and not (env.demo or env.arcade):
|
||||
pos = (230, 35)
|
||||
self.beta_info = bs.NodeActor(
|
||||
bs.newnode(
|
||||
|
|
@ -313,7 +292,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||
|
||||
random.seed()
|
||||
|
||||
if not (app.demo_mode or app.arcade_mode) and not app.toolbar_test:
|
||||
if not (env.demo or env.arcade) and not app.ui_v1.use_toolbars:
|
||||
self._news = NewsDisplay(self)
|
||||
|
||||
# Bring up the last place we were, or start at the main menu otherwise.
|
||||
|
|
@ -330,7 +309,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||
|
||||
# When coming back from a kiosk-mode game, jump to
|
||||
# the kiosk start screen.
|
||||
if bs.app.demo_mode or bs.app.arcade_mode:
|
||||
if env.demo or env.arcade:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.kiosk import KioskWindow
|
||||
|
||||
|
|
@ -417,6 +396,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
app = bs.app
|
||||
env = app.env
|
||||
assert app.classic is not None
|
||||
|
||||
# Update logo in case it changes.
|
||||
|
|
@ -460,7 +440,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||
base_x = -270.0
|
||||
x = base_x - 20.0
|
||||
spacing = 85.0 * base_scale
|
||||
y_extra = 0.0 if (app.demo_mode or app.arcade_mode) else 0.0
|
||||
y_extra = 0.0 if (env.demo or env.arcade) else 0.0
|
||||
self._make_logo(
|
||||
x - 110 + 50,
|
||||
113 + y + 1.2 * y_extra,
|
||||
|
|
@ -525,7 +505,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||
base_x = -170
|
||||
x = base_x - 20
|
||||
spacing = 55 * base_scale
|
||||
y_extra = 0 if (app.demo_mode or app.arcade_mode) else 0
|
||||
y_extra = 0 if (env.demo or env.arcade) else 0
|
||||
xv1 = x
|
||||
delay1 = delay
|
||||
for shadow in (True, False):
|
||||
|
|
@ -677,7 +657,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||
# Add a bit of stop-motion-y jitter to the logo
|
||||
# (unless we're in VR mode in which case its best to
|
||||
# leave things still).
|
||||
if not bs.app.vr_mode:
|
||||
if not bs.app.env.vr:
|
||||
cmb: bs.Node | None
|
||||
cmb2: bs.Node | None
|
||||
if not shadow:
|
||||
|
|
@ -796,7 +776,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||
# (unless we're in VR mode in which case its best to
|
||||
# leave things still).
|
||||
assert logo.node
|
||||
if not bs.app.vr_mode:
|
||||
if not bs.app.env.vr:
|
||||
cmb = bs.newnode('combine', owner=logo.node, attrs={'size': 2})
|
||||
cmb.connectattr('output', logo.node, 'position')
|
||||
keys = {}
|
||||
|
|
@ -904,7 +884,7 @@ class NewsDisplay:
|
|||
self._phrases.insert(0, phr)
|
||||
val = self._phrases.pop()
|
||||
if val == '__ACH__':
|
||||
vrmode = app.vr_mode
|
||||
vrmode = app.env.vr
|
||||
Text(
|
||||
bs.Lstr(resource='nextAchievementsText'),
|
||||
color=((1, 1, 1, 1) if vrmode else (0.95, 0.9, 1, 0.4)),
|
||||
|
|
@ -970,7 +950,7 @@ class NewsDisplay:
|
|||
|
||||
# Show upcoming achievements in non-vr versions
|
||||
# (currently too hard to read in vr).
|
||||
self._used_phrases = (['__ACH__'] if not bs.app.vr_mode else []) + [
|
||||
self._used_phrases = (['__ACH__'] if not bs.app.env.vr else []) + [
|
||||
s for s in news.split('<br>\n') if s != ''
|
||||
]
|
||||
self._phrase_change_timer = bs.Timer(
|
||||
|
|
@ -982,12 +962,12 @@ class NewsDisplay:
|
|||
assert bs.app.classic is not None
|
||||
scl = (
|
||||
1.2
|
||||
if (bs.app.ui_v1.uiscale is bs.UIScale.SMALL or bs.app.vr_mode)
|
||||
if (bs.app.ui_v1.uiscale is bs.UIScale.SMALL or bs.app.env.vr)
|
||||
else 0.8
|
||||
)
|
||||
|
||||
color2 = (1, 1, 1, 1) if bs.app.vr_mode else (0.7, 0.65, 0.75, 1.0)
|
||||
shadow = 1.0 if bs.app.vr_mode else 0.4
|
||||
color2 = (1, 1, 1, 1) if bs.app.env.vr else (0.7, 0.65, 0.75, 1.0)
|
||||
shadow = 1.0 if bs.app.env.vr else 0.4
|
||||
self._text = bs.NodeActor(
|
||||
bs.newnode(
|
||||
'text',
|
||||
|
|
|
|||
4
dist/ba_data/python/batemplatefs/__init__.py
vendored
4
dist/ba_data/python/batemplatefs/__init__.py
vendored
|
|
@ -4,8 +4,12 @@
|
|||
|
||||
# ba_meta require api 8
|
||||
|
||||
# Package up various private bits (including stuff from our native
|
||||
# module) into a nice clean public API.
|
||||
from _batemplatefs import hello_again_world
|
||||
from batemplatefs._subsystem import TemplateFsSubsystem
|
||||
|
||||
__all__ = [
|
||||
'TemplateFsSubsystem',
|
||||
'hello_again_world',
|
||||
]
|
||||
|
|
|
|||
6
dist/ba_data/python/batemplatefs/_hooks.py
vendored
6
dist/ba_data/python/batemplatefs/_hooks.py
vendored
|
|
@ -1,12 +1,10 @@
|
|||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Snippets of code for use by the c++ layer."""
|
||||
|
||||
# (most of these are self-explanatory)
|
||||
# pylint: disable=missing-function-docstring
|
||||
"""Snippets of code for use by the native layer."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def hello_world() -> None:
|
||||
"""The usual example."""
|
||||
print('HELLO WORLD FROM TemplateFs!')
|
||||
|
|
|
|||
8
dist/ba_data/python/bauiv1/__init__.py
vendored
8
dist/ba_data/python/bauiv1/__init__.py
vendored
|
|
@ -31,6 +31,7 @@ from babase import (
|
|||
apptimer,
|
||||
AppTimer,
|
||||
Call,
|
||||
can_toggle_fullscreen,
|
||||
charstr,
|
||||
clipboard_is_supported,
|
||||
clipboard_set_text,
|
||||
|
|
@ -52,7 +53,6 @@ from babase import (
|
|||
get_string_width,
|
||||
get_type_name,
|
||||
getclass,
|
||||
has_gamma_control,
|
||||
have_permission,
|
||||
in_logic_thread,
|
||||
increment_analytics_count,
|
||||
|
|
@ -76,6 +76,8 @@ from babase import (
|
|||
set_low_level_config_value,
|
||||
set_ui_input_device,
|
||||
SpecialChar,
|
||||
supports_max_fps,
|
||||
supports_vsync,
|
||||
timestring,
|
||||
UIScale,
|
||||
unlock_all_input,
|
||||
|
|
@ -136,6 +138,7 @@ __all__ = [
|
|||
'buttonwidget',
|
||||
'Call',
|
||||
'can_show_ad',
|
||||
'can_toggle_fullscreen',
|
||||
'charstr',
|
||||
'checkboxwidget',
|
||||
'clipboard_is_supported',
|
||||
|
|
@ -165,7 +168,6 @@ __all__ = [
|
|||
'getmesh',
|
||||
'getsound',
|
||||
'gettexture',
|
||||
'has_gamma_control',
|
||||
'has_video_ads',
|
||||
'have_incentivized_ad',
|
||||
'have_permission',
|
||||
|
|
@ -205,6 +207,8 @@ __all__ = [
|
|||
'show_online_score_ui',
|
||||
'Sound',
|
||||
'SpecialChar',
|
||||
'supports_max_fps',
|
||||
'supports_vsync',
|
||||
'Texture',
|
||||
'textwidget',
|
||||
'timestring',
|
||||
|
|
|
|||
3
dist/ba_data/python/bauiv1/_subsystem.py
vendored
3
dist/ba_data/python/bauiv1/_subsystem.py
vendored
|
|
@ -55,7 +55,8 @@ class UIV1Subsystem(babase.AppSubsystem):
|
|||
self.have_party_queue_window = False
|
||||
self.cleanupchecks: list[UICleanupCheck] = []
|
||||
self.upkeeptimer: babase.AppTimer | None = None
|
||||
self.use_toolbars = env.get('toolbar_test', True)
|
||||
self.use_toolbars = _bauiv1.toolbar_test()
|
||||
|
||||
self.title_color = (0.72, 0.7, 0.75)
|
||||
self.heading_color = (0.72, 0.7, 0.75)
|
||||
self.infotextcolor = (0.7, 0.9, 0.7)
|
||||
|
|
|
|||
32
dist/ba_data/python/bauiv1/_uitypes.py
vendored
32
dist/ba_data/python/bauiv1/_uitypes.py
vendored
|
|
@ -241,3 +241,35 @@ def ui_upkeep() -> None:
|
|||
else:
|
||||
remainingchecks.append(check)
|
||||
ui.cleanupchecks = remainingchecks
|
||||
|
||||
|
||||
class TextWidgetStringEditAdapter(babase.StringEditAdapter):
|
||||
"""A StringEditAdapter subclass for editing our text widgets."""
|
||||
|
||||
def __init__(self, text_widget: bauiv1.Widget) -> None:
|
||||
self.widget = text_widget
|
||||
|
||||
# Ugly hacks to pull values from widgets. Really need to clean
|
||||
# up that api.
|
||||
description: Any = _bauiv1.textwidget(query_description=text_widget)
|
||||
assert isinstance(description, str)
|
||||
initial_text: Any = _bauiv1.textwidget(query=text_widget)
|
||||
assert isinstance(initial_text, str)
|
||||
max_length: Any = _bauiv1.textwidget(query_max_chars=text_widget)
|
||||
assert isinstance(max_length, int)
|
||||
|
||||
screen_space_center = text_widget.get_screen_space_center()
|
||||
|
||||
super().__init__(
|
||||
description, initial_text, max_length, screen_space_center
|
||||
)
|
||||
|
||||
def _do_apply(self, new_text: str) -> None:
|
||||
if self.widget:
|
||||
_bauiv1.textwidget(
|
||||
edit=self.widget, text=new_text, adapter_finished=True
|
||||
)
|
||||
|
||||
def _do_cancel(self) -> None:
|
||||
if self.widget:
|
||||
_bauiv1.textwidget(edit=self.widget, adapter_finished=True)
|
||||
|
|
|
|||
26
dist/ba_data/python/bauiv1/onscreenkeyboard.py
vendored
26
dist/ba_data/python/bauiv1/onscreenkeyboard.py
vendored
|
|
@ -15,27 +15,28 @@ import _bauiv1
|
|||
from bauiv1._uitypes import Window
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from babase import StringEditAdapter
|
||||
|
||||
import bauiv1 as bui
|
||||
|
||||
|
||||
class OnScreenKeyboardWindow(Window):
|
||||
"""Simple built-in on-screen keyboard."""
|
||||
|
||||
def __init__(self, textwidget: bui.Widget, label: str, max_chars: int):
|
||||
self._target_text = textwidget
|
||||
def __init__(self, adapter: StringEditAdapter):
|
||||
self._adapter = adapter
|
||||
self._width = 700
|
||||
self._height = 400
|
||||
assert babase.app.classic is not None
|
||||
uiscale = babase.app.ui_v1.uiscale
|
||||
top_extra = 20 if uiscale is babase.UIScale.SMALL else 0
|
||||
|
||||
super().__init__(
|
||||
root_widget=_bauiv1.containerwidget(
|
||||
parent=_bauiv1.get_special_widget('overlay_stack'),
|
||||
size=(self._width, self._height + top_extra),
|
||||
transition='in_scale',
|
||||
scale_origin_stack_offset=(
|
||||
self._target_text.get_screen_space_center()
|
||||
),
|
||||
scale_origin_stack_offset=adapter.screen_space_center,
|
||||
scale=(
|
||||
2.0
|
||||
if uiscale is babase.UIScale.SMALL
|
||||
|
|
@ -69,7 +70,7 @@ class OnScreenKeyboardWindow(Window):
|
|||
position=(self._width * 0.5, self._height - 41),
|
||||
size=(0, 0),
|
||||
scale=0.95,
|
||||
text=label,
|
||||
text=adapter.description,
|
||||
maxwidth=self._width - 140,
|
||||
color=babase.app.ui_v1.title_color,
|
||||
h_align='center',
|
||||
|
|
@ -79,8 +80,8 @@ class OnScreenKeyboardWindow(Window):
|
|||
self._text_field = _bauiv1.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(70, self._height - 116),
|
||||
max_chars=max_chars,
|
||||
text=cast(str, _bauiv1.textwidget(query=self._target_text)),
|
||||
max_chars=adapter.max_length,
|
||||
text=adapter.initial_text,
|
||||
on_return_press_call=self._done,
|
||||
autoselect=True,
|
||||
size=(self._width - 140, 55),
|
||||
|
|
@ -436,13 +437,12 @@ class OnScreenKeyboardWindow(Window):
|
|||
self._refresh()
|
||||
|
||||
def _cancel(self) -> None:
|
||||
self._adapter.cancel()
|
||||
_bauiv1.getsound('swish').play()
|
||||
_bauiv1.containerwidget(edit=self._root_widget, transition='out_scale')
|
||||
|
||||
def _done(self) -> None:
|
||||
_bauiv1.containerwidget(edit=self._root_widget, transition='out_scale')
|
||||
if self._target_text:
|
||||
_bauiv1.textwidget(
|
||||
edit=self._target_text,
|
||||
text=cast(str, _bauiv1.textwidget(query=self._text_field)),
|
||||
)
|
||||
self._adapter.apply(
|
||||
cast(str, _bauiv1.textwidget(query=self._text_field))
|
||||
)
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ class AccountViewerWindow(PopupWindow):
|
|||
bui.app.classic.master_server_v1_get(
|
||||
'bsAccountInfo',
|
||||
{
|
||||
'buildNumber': bui.app.build_number,
|
||||
'buildNumber': bui.app.env.build_number,
|
||||
'accountID': self._account_id,
|
||||
'profileID': self._profile_id,
|
||||
},
|
||||
|
|
|
|||
2
dist/ba_data/python/bauiv1lib/configerror.py
vendored
2
dist/ba_data/python/bauiv1lib/configerror.py
vendored
|
|
@ -11,7 +11,7 @@ class ConfigErrorWindow(bui.Window):
|
|||
"""Window for dealing with a broken config."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._config_file_path = bui.app.config_file_path
|
||||
self._config_file_path = bui.app.env.config_file_path
|
||||
width = 800
|
||||
super().__init__(
|
||||
bui.containerwidget(size=(width, 400), transition='in_right')
|
||||
|
|
|
|||
18
dist/ba_data/python/bauiv1lib/confirm.py
vendored
18
dist/ba_data/python/bauiv1lib/confirm.py
vendored
|
|
@ -197,9 +197,19 @@ class QuitWindow:
|
|||
time=0.2,
|
||||
endcall=lambda: bui.quit(soft=True, back=self._back),
|
||||
)
|
||||
|
||||
# Prevent the user from doing anything else while we're on our
|
||||
# way out.
|
||||
bui.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)
|
||||
bui.apptimer(0.3, bui.unlock_all_input)
|
||||
# On systems supporting soft-quit, unlock and fade back in shortly
|
||||
# (soft-quit basically just backgrounds/hides the app).
|
||||
if bui.app.env.supports_soft_quit:
|
||||
# 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 after).
|
||||
def _come_back() -> None:
|
||||
bui.unlock_all_input()
|
||||
bui.fade_screen(True)
|
||||
|
||||
bui.apptimer(0.5, _come_back)
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ class CoopBrowserWindow(bui.Window):
|
|||
# noinspection PyUnresolvedReferences
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use (called in bg thread)."""
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
import bauiv1lib.purchase as _unused1
|
||||
import bauiv1lib.coop.gamebutton as _unused2
|
||||
import bauiv1lib.confirm as _unused3
|
||||
|
|
|
|||
5
dist/ba_data/python/bauiv1lib/creditslist.py
vendored
5
dist/ba_data/python/bauiv1lib/creditslist.py
vendored
|
|
@ -212,7 +212,10 @@ class CreditsListWindow(bui.Window):
|
|||
try:
|
||||
with open(
|
||||
os.path.join(
|
||||
bui.app.data_directory, 'ba_data', 'data', 'langdata.json'
|
||||
bui.app.env.data_directory,
|
||||
'ba_data',
|
||||
'data',
|
||||
'langdata.json',
|
||||
),
|
||||
encoding='utf-8',
|
||||
) as infile:
|
||||
|
|
|
|||
2
dist/ba_data/python/bauiv1lib/feedback.py
vendored
2
dist/ba_data/python/bauiv1lib/feedback.py
vendored
|
|
@ -15,7 +15,7 @@ def ask_for_rating() -> bui.Widget | None:
|
|||
subplatform = app.classic.subplatform
|
||||
|
||||
# FIXME: should whitelist platforms we *do* want this for.
|
||||
if bui.app.test_build:
|
||||
if bui.app.env.test:
|
||||
return None
|
||||
if not (
|
||||
platform == 'mac'
|
||||
|
|
|
|||
|
|
@ -32,11 +32,7 @@ class AboutGatherTab(GatherTab):
|
|||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
party_button_label = (
|
||||
'X'
|
||||
if bui.app.iircade_mode
|
||||
else bui.charstr(bui.SpecialChar.TOP_BUTTON)
|
||||
)
|
||||
party_button_label = bui.charstr(bui.SpecialChar.TOP_BUTTON)
|
||||
message = bui.Lstr(
|
||||
resource='gatherWindow.aboutDescriptionText',
|
||||
subs=[
|
||||
|
|
@ -47,7 +43,7 @@ class AboutGatherTab(GatherTab):
|
|||
|
||||
# Let's not talk about sharing in vr-mode; its tricky to fit more
|
||||
# than one head in a VR-headset ;-)
|
||||
if not bui.app.vr_mode:
|
||||
if not bui.app.env.vr:
|
||||
message = bui.Lstr(
|
||||
value='${A}\n\n${B}',
|
||||
subs=[
|
||||
|
|
|
|||
|
|
@ -1010,7 +1010,7 @@ class ManualGatherTab(GatherTab):
|
|||
self._t_accessible_extra = t_accessible_extra
|
||||
bui.app.classic.master_server_v1_get(
|
||||
'bsAccessCheck',
|
||||
{'b': bui.app.build_number},
|
||||
{'b': bui.app.env.build_number},
|
||||
callback=bui.WeakCall(self._on_accessible_response),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1169,7 +1169,7 @@ class PublicGatherTab(GatherTab):
|
|||
plus.add_v1_account_transaction(
|
||||
{
|
||||
'type': 'PUBLIC_PARTY_QUERY',
|
||||
'proto': bui.app.protocol_version,
|
||||
'proto': bs.protocol_version(),
|
||||
'lang': bui.app.lang.language,
|
||||
},
|
||||
callback=bui.WeakCall(self._on_public_party_query_result),
|
||||
|
|
@ -1327,7 +1327,7 @@ class PublicGatherTab(GatherTab):
|
|||
)
|
||||
bui.app.classic.master_server_v1_get(
|
||||
'bsAccessCheck',
|
||||
{'b': bui.app.build_number},
|
||||
{'b': bui.app.env.build_number},
|
||||
callback=bui.WeakCall(self._on_public_party_accessible_response),
|
||||
)
|
||||
|
||||
|
|
|
|||
6
dist/ba_data/python/bauiv1lib/getcurrency.py
vendored
6
dist/ba_data/python/bauiv1lib/getcurrency.py
vendored
|
|
@ -621,7 +621,7 @@ class GetCurrencyWindow(bui.Window):
|
|||
app = bui.app
|
||||
assert app.classic is not None
|
||||
if (
|
||||
app.test_build
|
||||
app.env.test
|
||||
or (
|
||||
app.classic.platform == 'android'
|
||||
and app.classic.subplatform in ['oculus', 'cardboard']
|
||||
|
|
@ -664,8 +664,8 @@ class GetCurrencyWindow(bui.Window):
|
|||
'item': item,
|
||||
'platform': app.classic.platform,
|
||||
'subplatform': app.classic.subplatform,
|
||||
'version': app.version,
|
||||
'buildNumber': app.build_number,
|
||||
'version': app.env.version,
|
||||
'buildNumber': app.env.build_number,
|
||||
},
|
||||
callback=bui.WeakCall(self._purchase_check_result, item),
|
||||
)
|
||||
|
|
|
|||
344
dist/ba_data/python/bauiv1lib/helpui.py
vendored
344
dist/ba_data/python/bauiv1lib/helpui.py
vendored
|
|
@ -196,214 +196,158 @@ class HelpWindow(bui.Window):
|
|||
texture=logo_tex,
|
||||
)
|
||||
|
||||
force_test = False
|
||||
app = bui.app
|
||||
assert app.classic is not None
|
||||
if (
|
||||
app.classic.platform == 'android'
|
||||
and app.classic.subplatform == 'alibaba'
|
||||
) or force_test:
|
||||
v -= 120.0
|
||||
txtv = (
|
||||
'\xe8\xbf\x99\xe6\x98\xaf\xe4\xb8\x80\xe4\xb8\xaa\xe5\x8f\xaf'
|
||||
'\xe4\xbb\xa5\xe5\x92\x8c\xe5\xae\xb6\xe4\xba\xba\xe6\x9c\x8b'
|
||||
'\xe5\x8f\x8b\xe4\xb8\x80\xe8\xb5\xb7\xe7\x8e\xa9\xe7\x9a\x84'
|
||||
'\xe6\xb8\xb8\xe6\x88\x8f,\xe5\x90\x8c\xe6\x97\xb6\xe6\x94\xaf'
|
||||
'\xe6\x8c\x81\xe8\x81\x94 \xe2\x80\xa8\xe7\xbd\x91\xe5\xaf\xb9'
|
||||
'\xe6\x88\x98\xe3\x80\x82\n'
|
||||
'\xe5\xa6\x82\xe6\xb2\xa1\xe6\x9c\x89\xe6\xb8\xb8\xe6\x88\x8f'
|
||||
'\xe6\x89\x8b\xe6\x9f\x84,\xe5\x8f\xaf\xe4\xbb\xa5\xe4\xbd\xbf'
|
||||
'\xe7\x94\xa8\xe7\xa7\xbb\xe5\x8a\xa8\xe8\xae\xbe\xe5\xa4\x87'
|
||||
'\xe6\x89\xab\xe7\xa0\x81\xe4\xb8\x8b\xe8\xbd\xbd\xe2\x80\x9c'
|
||||
'\xe9\x98\xbf\xe9\x87\x8c\xc2'
|
||||
'\xa0TV\xc2\xa0\xe5\x8a\xa9\xe6\x89'
|
||||
'\x8b\xe2\x80\x9d\xe7\x94\xa8 \xe6\x9d\xa5\xe4\xbb\xa3\xe6\x9b'
|
||||
'\xbf\xe5\xa4\x96\xe8\xae\xbe\xe3\x80\x82\n'
|
||||
'\xe6\x9c\x80\xe5\xa4\x9a\xe6\x94\xaf\xe6\x8c\x81\xe6\x8e\xa5'
|
||||
'\xe5\x85\xa5\xc2\xa08\xc2\xa0\xe4\xb8\xaa\xe5\xa4\x96\xe8'
|
||||
'\xae\xbe'
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=self._sub_width * 0.9,
|
||||
position=(self._sub_width * 0.5, v - 180),
|
||||
text=txtv,
|
||||
)
|
||||
bui.imagewidget(
|
||||
parent=self._subcontainer,
|
||||
position=(self._sub_width - 320, v - 120),
|
||||
size=(200, 200),
|
||||
texture=bui.gettexture('aliControllerQR'),
|
||||
)
|
||||
bui.imagewidget(
|
||||
parent=self._subcontainer,
|
||||
position=(90, v - 130),
|
||||
size=(210, 210),
|
||||
texture=bui.gettexture('multiplayerExamples'),
|
||||
)
|
||||
v -= 120.0
|
||||
|
||||
v -= spacing * 50.0
|
||||
txt = bui.Lstr(resource=self._r + '.someDaysText').evaluate()
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(h, v),
|
||||
size=(0, 0),
|
||||
scale=1.2,
|
||||
maxwidth=self._sub_width * 0.9,
|
||||
text=txt,
|
||||
h_align='center',
|
||||
color=paragraph,
|
||||
v_align='center',
|
||||
flatness=1.0,
|
||||
)
|
||||
v -= spacing * 25.0 + getres(self._r + '.someDaysExtraSpace')
|
||||
txt_scale = 0.66
|
||||
txt = bui.Lstr(resource=self._r + '.orPunchingSomethingText').evaluate()
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(h, v),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
maxwidth=self._sub_width * 0.9,
|
||||
text=txt,
|
||||
h_align='center',
|
||||
color=paragraph,
|
||||
v_align='center',
|
||||
flatness=1.0,
|
||||
)
|
||||
v -= spacing * 27.0 + getres(self._r + '.orPunchingSomethingExtraSpace')
|
||||
txt_scale = 1.0
|
||||
txt = bui.Lstr(
|
||||
resource=self._r + '.canHelpText',
|
||||
subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
|
||||
).evaluate()
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(h, v),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
flatness=1.0,
|
||||
text=txt,
|
||||
h_align='center',
|
||||
color=paragraph,
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
v -= spacing * 70.0
|
||||
txt_scale = 1.0
|
||||
txt = bui.Lstr(resource=self._r + '.toGetTheMostText').evaluate()
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(h, v),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
maxwidth=self._sub_width * 0.9,
|
||||
text=txt,
|
||||
h_align='center',
|
||||
color=header,
|
||||
v_align='center',
|
||||
flatness=1.0,
|
||||
)
|
||||
|
||||
v -= spacing * 40.0
|
||||
txt_scale = 0.74
|
||||
txt = bui.Lstr(resource=self._r + '.friendsText').evaluate()
|
||||
hval2 = h - 220
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(hval2, v),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
maxwidth=100,
|
||||
text=txt,
|
||||
h_align='right',
|
||||
color=header,
|
||||
v_align='center',
|
||||
flatness=1.0,
|
||||
)
|
||||
|
||||
txt = bui.Lstr(
|
||||
resource=self._r + '.friendsGoodText',
|
||||
subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
|
||||
).evaluate()
|
||||
txt_scale = 0.7
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(hval2 + 10, v + 8),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
maxwidth=500,
|
||||
text=txt,
|
||||
h_align='left',
|
||||
color=paragraph,
|
||||
flatness=1.0,
|
||||
)
|
||||
|
||||
app = bui.app
|
||||
|
||||
v -= spacing * 45.0
|
||||
txt = (
|
||||
bui.Lstr(resource=self._r + '.devicesText').evaluate()
|
||||
if app.env.vr
|
||||
else bui.Lstr(resource=self._r + '.controllersText').evaluate()
|
||||
)
|
||||
txt_scale = 0.74
|
||||
hval2 = h - 220
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(hval2, v),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
maxwidth=100,
|
||||
text=txt,
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
color=header,
|
||||
flatness=1.0,
|
||||
)
|
||||
|
||||
txt_scale = 0.7
|
||||
if not app.env.vr:
|
||||
infotxt = '.controllersInfoText'
|
||||
txt = bui.Lstr(
|
||||
resource=self._r + infotxt,
|
||||
fallback_resource=self._r + '.controllersInfoText',
|
||||
subs=[
|
||||
('${APP_NAME}', bui.Lstr(resource='titleText')),
|
||||
('${REMOTE_APP_NAME}', bui.get_remote_app_name()),
|
||||
],
|
||||
).evaluate()
|
||||
else:
|
||||
v -= spacing * 50.0
|
||||
txt = bui.Lstr(resource=self._r + '.someDaysText').evaluate()
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(h, v),
|
||||
size=(0, 0),
|
||||
scale=1.2,
|
||||
maxwidth=self._sub_width * 0.9,
|
||||
text=txt,
|
||||
h_align='center',
|
||||
color=paragraph,
|
||||
v_align='center',
|
||||
flatness=1.0,
|
||||
)
|
||||
v -= spacing * 25.0 + getres(self._r + '.someDaysExtraSpace')
|
||||
txt_scale = 0.66
|
||||
txt = bui.Lstr(
|
||||
resource=self._r + '.orPunchingSomethingText'
|
||||
).evaluate()
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(h, v),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
maxwidth=self._sub_width * 0.9,
|
||||
text=txt,
|
||||
h_align='center',
|
||||
color=paragraph,
|
||||
v_align='center',
|
||||
flatness=1.0,
|
||||
)
|
||||
v -= spacing * 27.0 + getres(
|
||||
self._r + '.orPunchingSomethingExtraSpace'
|
||||
)
|
||||
txt_scale = 1.0
|
||||
txt = bui.Lstr(
|
||||
resource=self._r + '.canHelpText',
|
||||
resource=self._r + '.devicesInfoText',
|
||||
subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
|
||||
).evaluate()
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(h, v),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
flatness=1.0,
|
||||
text=txt,
|
||||
h_align='center',
|
||||
color=paragraph,
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
v -= spacing * 70.0
|
||||
txt_scale = 1.0
|
||||
txt = bui.Lstr(resource=self._r + '.toGetTheMostText').evaluate()
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(h, v),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
maxwidth=self._sub_width * 0.9,
|
||||
text=txt,
|
||||
h_align='center',
|
||||
color=header,
|
||||
v_align='center',
|
||||
flatness=1.0,
|
||||
)
|
||||
|
||||
v -= spacing * 40.0
|
||||
txt_scale = 0.74
|
||||
txt = bui.Lstr(resource=self._r + '.friendsText').evaluate()
|
||||
hval2 = h - 220
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(hval2, v),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
maxwidth=100,
|
||||
text=txt,
|
||||
h_align='right',
|
||||
color=header,
|
||||
v_align='center',
|
||||
flatness=1.0,
|
||||
)
|
||||
|
||||
txt = bui.Lstr(
|
||||
resource=self._r + '.friendsGoodText',
|
||||
subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
|
||||
).evaluate()
|
||||
txt_scale = 0.7
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(hval2 + 10, v + 8),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
maxwidth=500,
|
||||
text=txt,
|
||||
h_align='left',
|
||||
color=paragraph,
|
||||
flatness=1.0,
|
||||
)
|
||||
|
||||
app = bui.app
|
||||
|
||||
v -= spacing * 45.0
|
||||
txt = (
|
||||
bui.Lstr(resource=self._r + '.devicesText').evaluate()
|
||||
if app.vr_mode
|
||||
else bui.Lstr(resource=self._r + '.controllersText').evaluate()
|
||||
)
|
||||
txt_scale = 0.74
|
||||
hval2 = h - 220
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(hval2, v),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
maxwidth=100,
|
||||
text=txt,
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
color=header,
|
||||
flatness=1.0,
|
||||
)
|
||||
|
||||
txt_scale = 0.7
|
||||
if not app.vr_mode:
|
||||
infotxt = (
|
||||
'.controllersInfoTextRemoteOnly'
|
||||
if app.iircade_mode
|
||||
else '.controllersInfoText'
|
||||
)
|
||||
txt = bui.Lstr(
|
||||
resource=self._r + infotxt,
|
||||
fallback_resource=self._r + '.controllersInfoText',
|
||||
subs=[
|
||||
('${APP_NAME}', bui.Lstr(resource='titleText')),
|
||||
('${REMOTE_APP_NAME}', bui.get_remote_app_name()),
|
||||
],
|
||||
).evaluate()
|
||||
else:
|
||||
txt = bui.Lstr(
|
||||
resource=self._r + '.devicesInfoText',
|
||||
subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
|
||||
).evaluate()
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(hval2 + 10, v + 8),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
maxwidth=500,
|
||||
max_height=105,
|
||||
text=txt,
|
||||
h_align='left',
|
||||
color=paragraph,
|
||||
flatness=1.0,
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(hval2 + 10, v + 8),
|
||||
size=(0, 0),
|
||||
scale=txt_scale,
|
||||
maxwidth=500,
|
||||
max_height=105,
|
||||
text=txt,
|
||||
h_align='left',
|
||||
color=paragraph,
|
||||
flatness=1.0,
|
||||
)
|
||||
|
||||
v -= spacing * 150.0
|
||||
|
||||
|
|
|
|||
4
dist/ba_data/python/bauiv1lib/kiosk.py
vendored
4
dist/ba_data/python/bauiv1lib/kiosk.py
vendored
|
|
@ -88,7 +88,7 @@ class KioskWindow(bui.Window):
|
|||
resource='demoText',
|
||||
fallback_resource='mainMenu.demoMenuText',
|
||||
)
|
||||
if bui.app.demo_mode
|
||||
if bui.app.env.demo
|
||||
else 'ARCADE'
|
||||
),
|
||||
flatness=1.0,
|
||||
|
|
@ -332,7 +332,7 @@ class KioskWindow(bui.Window):
|
|||
self._b4 = self._b5 = self._b6 = None
|
||||
|
||||
self._b7: bui.Widget | None
|
||||
if bui.app.arcade_mode:
|
||||
if bui.app.env.arcade:
|
||||
self._b7 = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
|
|
|
|||
17
dist/ba_data/python/bauiv1lib/mainmenu.py
vendored
17
dist/ba_data/python/bauiv1lib/mainmenu.py
vendored
|
|
@ -50,9 +50,8 @@ class MainMenuWindow(bui.Window):
|
|||
)
|
||||
|
||||
# Grab this stuff in case it changes.
|
||||
self._is_demo = bui.app.demo_mode
|
||||
self._is_arcade = bui.app.arcade_mode
|
||||
self._is_iircade = bui.app.iircade_mode
|
||||
self._is_demo = bui.app.env.demo
|
||||
self._is_arcade = bui.app.env.arcade
|
||||
|
||||
self._tdelay = 0.0
|
||||
self._t_delay_inc = 0.02
|
||||
|
|
@ -93,7 +92,7 @@ class MainMenuWindow(bui.Window):
|
|||
# noinspection PyUnresolvedReferences
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use (called in bg thread)."""
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
import bauiv1lib.getremote as _unused
|
||||
import bauiv1lib.confirm as _unused2
|
||||
import bauiv1lib.store.button as _unused3
|
||||
|
|
@ -118,7 +117,7 @@ class MainMenuWindow(bui.Window):
|
|||
force_test = False
|
||||
bs.get_local_active_input_devices_count()
|
||||
if (
|
||||
(app.on_tv or app.classic.platform == 'mac')
|
||||
(app.env.tv or app.classic.platform == 'mac')
|
||||
and bui.app.config.get('launchCount', 0) <= 1
|
||||
) or force_test:
|
||||
|
||||
|
|
@ -220,8 +219,8 @@ class MainMenuWindow(bui.Window):
|
|||
self._have_store_button = not self._in_game
|
||||
|
||||
self._have_settings_button = (
|
||||
not self._in_game or not app.toolbar_test
|
||||
) and not (self._is_demo or self._is_arcade or self._is_iircade)
|
||||
not self._in_game or not app.ui_v1.use_toolbars
|
||||
) and not (self._is_demo or self._is_arcade)
|
||||
|
||||
self._input_device = input_device = bs.get_ui_input_device()
|
||||
|
||||
|
|
@ -618,7 +617,7 @@ class MainMenuWindow(bui.Window):
|
|||
)
|
||||
)
|
||||
# In kiosk mode, provide a button to get back to the kiosk menu.
|
||||
if bui.app.demo_mode or bui.app.arcade_mode:
|
||||
if bui.app.env.demo or bui.app.env.arcade:
|
||||
h, v, scale = positions[self._p_index]
|
||||
this_b_width = self._button_width * 0.4 * scale
|
||||
demo_menu_delay = (
|
||||
|
|
@ -635,7 +634,7 @@ class MainMenuWindow(bui.Window):
|
|||
textcolor=(0.7, 0.8, 0.7),
|
||||
label=bui.Lstr(
|
||||
resource='modeArcadeText'
|
||||
if bui.app.arcade_mode
|
||||
if bui.app.env.arcade
|
||||
else 'modeDemoText'
|
||||
),
|
||||
transition_delay=demo_menu_delay,
|
||||
|
|
|
|||
2
dist/ba_data/python/bauiv1lib/play.py
vendored
2
dist/ba_data/python/bauiv1lib/play.py
vendored
|
|
@ -513,7 +513,7 @@ class PlayWindow(bui.Window):
|
|||
# noinspection PyUnresolvedReferences
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use (called in bg thread)."""
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
import bauiv1lib.mainmenu as _unused1
|
||||
import bauiv1lib.account as _unused2
|
||||
import bauiv1lib.coop.browser as _unused3
|
||||
|
|
|
|||
2
dist/ba_data/python/bauiv1lib/popup.py
vendored
2
dist/ba_data/python/bauiv1lib/popup.py
vendored
|
|
@ -34,7 +34,7 @@ class PopupWindow:
|
|||
focus_size = size
|
||||
|
||||
# In vr mode we can't have windows going outside the screen.
|
||||
if bui.app.vr_mode:
|
||||
if bui.app.env.vr:
|
||||
focus_size = size
|
||||
focus_position = (0, 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -718,11 +718,13 @@ class EditProfileWindow(bui.Window):
|
|||
else '???'
|
||||
)
|
||||
if len(name) > 10 and not (self._global or self._is_account_profile):
|
||||
name = name.strip()
|
||||
display_name = (name[:10] + '...') if len(name) > 10 else name
|
||||
bui.textwidget(
|
||||
edit=self._clipped_name_text,
|
||||
text=bui.Lstr(
|
||||
resource='inGameClippedNameText',
|
||||
subs=[('${NAME}', name[:10] + '...')],
|
||||
subs=[('${NAME}', display_name)],
|
||||
),
|
||||
)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ class ProfileUpgradeWindow(bui.Window):
|
|||
|
||||
bui.app.classic.master_server_v1_get(
|
||||
'bsGlobalProfileCheck',
|
||||
{'name': self._name, 'b': bui.app.build_number},
|
||||
{'name': self._name, 'b': bui.app.env.build_number},
|
||||
callback=bui.WeakCall(self._profile_check_result),
|
||||
)
|
||||
self._cost = plus.get_v1_account_misc_read_val(
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ if TYPE_CHECKING:
|
|||
|
||||
|
||||
class AdvancedSettingsWindow(bui.Window):
|
||||
"""Window for editing advanced game settings."""
|
||||
"""Window for editing advanced app settings."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
|
@ -61,6 +61,7 @@ class AdvancedSettingsWindow(bui.Window):
|
|||
self._spacing = 32
|
||||
self._menu_open = False
|
||||
top_extra = 10 if uiscale is bui.UIScale.SMALL else 0
|
||||
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
|
|
@ -88,14 +89,12 @@ class AdvancedSettingsWindow(bui.Window):
|
|||
|
||||
# In vr-mode, the internal keyboard is currently the *only* option,
|
||||
# so no need to show this.
|
||||
self._show_always_use_internal_keyboard = (
|
||||
not app.vr_mode and not app.iircade_mode
|
||||
)
|
||||
self._show_always_use_internal_keyboard = not app.env.vr
|
||||
|
||||
self._scroll_width = self._width - (100 + 2 * x_inset)
|
||||
self._scroll_height = self._height - 115.0
|
||||
self._sub_width = self._scroll_width * 0.95
|
||||
self._sub_height = 724.0
|
||||
self._sub_height = 766.0
|
||||
|
||||
if self._show_always_use_internal_keyboard:
|
||||
self._sub_height += 62
|
||||
|
|
@ -104,7 +103,7 @@ class AdvancedSettingsWindow(bui.Window):
|
|||
if self._show_disable_gyro:
|
||||
self._sub_height += 42
|
||||
|
||||
self._do_vr_test_button = app.vr_mode
|
||||
self._do_vr_test_button = app.env.vr
|
||||
self._do_net_test_button = True
|
||||
self._extra_button_spacing = self._spacing * 2.5
|
||||
|
||||
|
|
@ -180,14 +179,14 @@ class AdvancedSettingsWindow(bui.Window):
|
|||
# Fetch the list of completed languages.
|
||||
bui.app.classic.master_server_v1_get(
|
||||
'bsLangGetCompleted',
|
||||
{'b': app.build_number},
|
||||
{'b': app.env.build_number},
|
||||
callback=bui.WeakCall(self._completed_langs_cb),
|
||||
)
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use (called in bg thread)."""
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
from babase import modutils as _unused2
|
||||
from bauiv1lib import config as _unused1
|
||||
from bauiv1lib.settings import vrtesting as _unused3
|
||||
|
|
@ -244,6 +243,7 @@ class AdvancedSettingsWindow(bui.Window):
|
|||
|
||||
# Don't rebuild if the menu is open or if our language and
|
||||
# language-list hasn't changed.
|
||||
|
||||
# NOTE - although we now support widgets updating their own
|
||||
# translations, we still change the label formatting on the language
|
||||
# menu based on the language so still need this. ...however we could
|
||||
|
|
@ -324,7 +324,10 @@ class AdvancedSettingsWindow(bui.Window):
|
|||
|
||||
with open(
|
||||
os.path.join(
|
||||
bui.app.data_directory, 'ba_data', 'data', 'langdata.json'
|
||||
bui.app.env.data_directory,
|
||||
'ba_data',
|
||||
'data',
|
||||
'langdata.json',
|
||||
),
|
||||
encoding='utf-8',
|
||||
) as infile:
|
||||
|
|
@ -473,6 +476,19 @@ class AdvancedSettingsWindow(bui.Window):
|
|||
maxwidth=430,
|
||||
)
|
||||
|
||||
v -= 42
|
||||
self._show_dev_console_button_check_box = ConfigCheckBox(
|
||||
parent=self._subcontainer,
|
||||
position=(50, v),
|
||||
size=(self._sub_width - 100, 30),
|
||||
configkey='Show Dev Console Button',
|
||||
displayname=bui.Lstr(
|
||||
resource=f'{self._r}.showDevConsoleButtonText'
|
||||
),
|
||||
scale=1.0,
|
||||
maxwidth=430,
|
||||
)
|
||||
|
||||
v -= 42
|
||||
self._disable_camera_shake_check_box = ConfigCheckBox(
|
||||
parent=self._subcontainer,
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ class AllSettingsWindow(bui.Window):
|
|||
# noinspection PyUnresolvedReferences
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use (called in bg thread)."""
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
import bauiv1lib.mainmenu as _unused1
|
||||
import bauiv1lib.settings.controls as _unused2
|
||||
import bauiv1lib.settings.graphics as _unused3
|
||||
|
|
|
|||
|
|
@ -47,14 +47,14 @@ class ControlsSettingsWindow(bui.Window):
|
|||
|
||||
space_height = spacing * 0.3
|
||||
|
||||
# FIXME: should create vis settings in platform for these,
|
||||
# not hard code them here.
|
||||
# FIXME: should create vis settings under platform or app-adapter
|
||||
# to determine whether to show this stuff; not hard code it.
|
||||
|
||||
show_gamepads = False
|
||||
platform = app.classic.platform
|
||||
subplatform = app.classic.subplatform
|
||||
non_vr_windows = platform == 'windows' and (
|
||||
subplatform != 'oculus' or not app.vr_mode
|
||||
subplatform != 'oculus' or not app.env.vr
|
||||
)
|
||||
if platform in ('linux', 'android', 'mac') or non_vr_windows:
|
||||
show_gamepads = True
|
||||
|
|
@ -74,7 +74,7 @@ class ControlsSettingsWindow(bui.Window):
|
|||
if bs.getinputdevice('Keyboard', '#1', doraise=False) is not None:
|
||||
show_keyboard = True
|
||||
height += spacing
|
||||
show_keyboard_p2 = False if app.vr_mode else show_keyboard
|
||||
show_keyboard_p2 = False if app.env.vr else show_keyboard
|
||||
if show_keyboard_p2:
|
||||
height += spacing
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ class ControlsSettingsWindow(bui.Window):
|
|||
|
||||
# On windows (outside of oculus/vr), show an option to disable xinput.
|
||||
show_xinput_toggle = False
|
||||
if platform == 'windows' and not app.vr_mode:
|
||||
if platform == 'windows' and not app.env.vr:
|
||||
show_xinput_toggle = True
|
||||
|
||||
# On mac builds, show an option to switch between generic and
|
||||
|
|
@ -352,6 +352,7 @@ class ControlsSettingsWindow(bui.Window):
|
|||
maxwidth=width * 0.8,
|
||||
)
|
||||
v -= spacing * 1.5
|
||||
|
||||
self._restore_state()
|
||||
|
||||
def _set_mac_controller_subsystem(self, val: str) -> None:
|
||||
|
|
|
|||
|
|
@ -829,7 +829,7 @@ class GamepadSettingsWindow(bui.Window):
|
|||
'controllerConfig',
|
||||
{
|
||||
'ua': classic.legacy_user_agent_string,
|
||||
'b': bui.app.build_number,
|
||||
'b': bui.app.env.build_number,
|
||||
'name': self._name,
|
||||
'inputMapHash': inputhash,
|
||||
'config': dst2,
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class GamepadAdvancedSettingsWindow(bui.Window):
|
|||
self._sub_height = (
|
||||
940 if self._parent_window.get_is_secondary() else 1040
|
||||
)
|
||||
if app.vr_mode:
|
||||
if app.env.vr:
|
||||
self._sub_height += 50
|
||||
self._scrollwidget = bui.scrollwidget(
|
||||
parent=self._root_widget,
|
||||
|
|
@ -183,7 +183,7 @@ class GamepadAdvancedSettingsWindow(bui.Window):
|
|||
)
|
||||
|
||||
# in vr mode, allow assigning a reset-view button
|
||||
if app.vr_mode:
|
||||
if app.env.vr:
|
||||
v -= 50
|
||||
self._capture_button(
|
||||
pos=(h2, v),
|
||||
|
|
|
|||
272
dist/ba_data/python/bauiv1lib/settings/graphics.py
vendored
272
dist/ba_data/python/bauiv1lib/settings/graphics.py
vendored
|
|
@ -4,12 +4,15 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
from bauiv1lib.popup import PopupMenu
|
||||
from bauiv1lib.config import ConfigCheckBox, ConfigNumberEdit
|
||||
from bauiv1lib.config import ConfigCheckBox
|
||||
import bauiv1 as bui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
|
||||
class GraphicsSettingsWindow(bui.Window):
|
||||
"""Window for graphics settings."""
|
||||
|
|
@ -42,26 +45,26 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
uiscale = app.ui_v1.uiscale
|
||||
width = 450.0
|
||||
height = 302.0
|
||||
self._max_fps_dirty = False
|
||||
self._last_max_fps_set_time = bui.apptime()
|
||||
self._last_max_fps_str = ''
|
||||
|
||||
self._show_fullscreen = False
|
||||
fullscreen_spacing_top = spacing * 0.2
|
||||
fullscreen_spacing = spacing * 1.2
|
||||
if uiscale == bui.UIScale.LARGE and app.classic.platform != 'android':
|
||||
if bui.can_toggle_fullscreen():
|
||||
self._show_fullscreen = True
|
||||
height += fullscreen_spacing + fullscreen_spacing_top
|
||||
|
||||
show_gamma = False
|
||||
gamma_spacing = spacing * 1.3
|
||||
if bui.has_gamma_control():
|
||||
show_gamma = True
|
||||
height += gamma_spacing
|
||||
show_vsync = bui.supports_vsync()
|
||||
show_tv_mode = not bui.app.env.vr
|
||||
|
||||
show_vsync = False
|
||||
if app.classic.platform == 'mac':
|
||||
show_vsync = True
|
||||
show_max_fps = bui.supports_max_fps()
|
||||
if show_max_fps:
|
||||
height += 50
|
||||
|
||||
show_resolution = True
|
||||
if app.vr_mode:
|
||||
if app.env.vr:
|
||||
show_resolution = (
|
||||
app.classic.platform == 'android'
|
||||
and app.classic.subplatform == 'cardboard'
|
||||
|
|
@ -70,7 +73,7 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
base_scale = (
|
||||
2.4
|
||||
2.0
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.5
|
||||
if uiscale is bui.UIScale.MEDIUM
|
||||
|
|
@ -91,19 +94,20 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
)
|
||||
)
|
||||
|
||||
btn = bui.buttonwidget(
|
||||
back_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(35, height - 50),
|
||||
size=(120, 60),
|
||||
# size=(120, 60),
|
||||
size=(60, 60),
|
||||
scale=0.8,
|
||||
text_scale=1.2,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
button_type='backSmall',
|
||||
on_activate_call=self._back,
|
||||
)
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=back_button)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
|
|
@ -115,15 +119,7 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
v_align='top',
|
||||
)
|
||||
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
self._fullscreen_checkbox: bui.Widget | None = None
|
||||
self._gamma_controls: ConfigNumberEdit | None = None
|
||||
if self._show_fullscreen:
|
||||
v -= fullscreen_spacing_top
|
||||
self._fullscreen_checkbox = ConfigCheckBox(
|
||||
|
|
@ -149,34 +145,10 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
self._have_selected_child = True
|
||||
v -= fullscreen_spacing
|
||||
|
||||
if show_gamma:
|
||||
self._gamma_controls = gmc = ConfigNumberEdit(
|
||||
parent=self._root_widget,
|
||||
position=(90, v),
|
||||
configkey='Screen Gamma',
|
||||
displayname=bui.Lstr(resource=self._r + '.gammaText'),
|
||||
minval=0.1,
|
||||
maxval=2.0,
|
||||
increment=0.1,
|
||||
xoffset=-70,
|
||||
textscale=0.85,
|
||||
)
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=gmc.plusbutton,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
if not self._have_selected_child:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, selected_child=gmc.minusbutton
|
||||
)
|
||||
self._have_selected_child = True
|
||||
v -= gamma_spacing
|
||||
|
||||
self._selected_color = (0.5, 1, 0.5, 1)
|
||||
self._unselected_color = (0.7, 0.7, 0.7, 1)
|
||||
|
||||
# quality
|
||||
# Quality
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(60, v),
|
||||
|
|
@ -208,7 +180,7 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
on_value_change_call=self._set_quality,
|
||||
)
|
||||
|
||||
# texture controls
|
||||
# Texture controls
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(230, v),
|
||||
|
|
@ -244,8 +216,9 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
|
||||
h_offs = 0
|
||||
|
||||
resolution_popup: PopupMenu | None = None
|
||||
|
||||
if show_resolution:
|
||||
# resolution
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h_offs + 60, v),
|
||||
|
|
@ -258,32 +231,17 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
v_align='center',
|
||||
)
|
||||
|
||||
# on standard android we have 'Auto', 'Native', and a few
|
||||
# HD standards
|
||||
# On standard android we have 'Auto', 'Native', and a few
|
||||
# HD standards.
|
||||
if app.classic.platform == 'android':
|
||||
# on cardboard/daydream android we have a few
|
||||
# render-target-scale options
|
||||
if app.classic.subplatform == 'cardboard':
|
||||
rawval = bui.app.config.resolve('GVR Render Target Scale')
|
||||
current_res_cardboard = (
|
||||
str(
|
||||
min(
|
||||
100,
|
||||
max(
|
||||
10,
|
||||
int(
|
||||
round(
|
||||
bui.app.config.resolve(
|
||||
'GVR Render Target Scale'
|
||||
)
|
||||
* 100.0
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
+ '%'
|
||||
str(min(100, max(10, int(round(rawval * 100.0))))) + '%'
|
||||
)
|
||||
PopupMenu(
|
||||
resolution_popup = PopupMenu(
|
||||
parent=self._root_widget,
|
||||
position=(h_offs + 60, v - 50),
|
||||
width=120,
|
||||
|
|
@ -301,16 +259,16 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
bui.Lstr(resource='nativeText'),
|
||||
]
|
||||
for res in [1440, 1080, 960, 720, 480]:
|
||||
# nav bar is 72px so lets allow for that in what
|
||||
# choices we show
|
||||
# Nav bar is 72px so lets allow for that in what
|
||||
# choices we show.
|
||||
if native_res[1] >= res - 72:
|
||||
res_str = str(res) + 'p'
|
||||
res_str = f'{res}p'
|
||||
choices.append(res_str)
|
||||
choices_display.append(bui.Lstr(value=res_str))
|
||||
current_res_android = bui.app.config.resolve(
|
||||
'Resolution (Android)'
|
||||
)
|
||||
PopupMenu(
|
||||
resolution_popup = PopupMenu(
|
||||
parent=self._root_widget,
|
||||
position=(h_offs + 60, v - 50),
|
||||
width=120,
|
||||
|
|
@ -325,26 +283,11 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
# set pixel-scale instead.
|
||||
current_res = bui.get_display_resolution()
|
||||
if current_res is None:
|
||||
rawval = bui.app.config.resolve('Screen Pixel Scale')
|
||||
current_res2 = (
|
||||
str(
|
||||
min(
|
||||
100,
|
||||
max(
|
||||
10,
|
||||
int(
|
||||
round(
|
||||
bui.app.config.resolve(
|
||||
'Screen Pixel Scale'
|
||||
)
|
||||
* 100.0
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
+ '%'
|
||||
str(min(100, max(10, int(round(rawval * 100.0))))) + '%'
|
||||
)
|
||||
PopupMenu(
|
||||
resolution_popup = PopupMenu(
|
||||
parent=self._root_widget,
|
||||
position=(h_offs + 60, v - 50),
|
||||
width=120,
|
||||
|
|
@ -355,11 +298,16 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'obsolete path; discrete resolutions'
|
||||
'obsolete code path; discrete resolutions'
|
||||
' no longer supported'
|
||||
)
|
||||
if resolution_popup is not None:
|
||||
bui.widget(
|
||||
edit=resolution_popup.get_button(),
|
||||
left_widget=back_button,
|
||||
)
|
||||
|
||||
# vsync
|
||||
vsync_popup: PopupMenu | None = None
|
||||
if show_vsync:
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
|
|
@ -372,8 +320,7 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
PopupMenu(
|
||||
vsync_popup = PopupMenu(
|
||||
parent=self._root_widget,
|
||||
position=(230, v - 50),
|
||||
width=150,
|
||||
|
|
@ -387,8 +334,59 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
current_choice=bui.app.config.resolve('Vertical Sync'),
|
||||
on_value_change_call=self._set_vsync,
|
||||
)
|
||||
if resolution_popup is not None:
|
||||
bui.widget(
|
||||
edit=vsync_popup.get_button(),
|
||||
left_widget=resolution_popup.get_button(),
|
||||
)
|
||||
|
||||
if resolution_popup is not None and vsync_popup is not None:
|
||||
bui.widget(
|
||||
edit=resolution_popup.get_button(),
|
||||
right_widget=vsync_popup.get_button(),
|
||||
)
|
||||
|
||||
v -= 90
|
||||
self._max_fps_text: bui.Widget | None = None
|
||||
if show_max_fps:
|
||||
v -= 5
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(155, v + 10),
|
||||
size=(0, 0),
|
||||
text=bui.Lstr(resource=self._r + '.maxFPSText'),
|
||||
color=bui.app.ui_v1.heading_color,
|
||||
scale=0.9,
|
||||
maxwidth=90,
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
max_fps_str = str(bui.app.config.resolve('Max FPS'))
|
||||
self._last_max_fps_str = max_fps_str
|
||||
self._max_fps_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(170, v - 5),
|
||||
size=(105, 30),
|
||||
text=max_fps_str,
|
||||
max_chars=5,
|
||||
editable=True,
|
||||
h_align='left',
|
||||
v_align='center',
|
||||
on_return_press_call=self._on_max_fps_return_press,
|
||||
)
|
||||
v -= 45
|
||||
|
||||
if self._max_fps_text is not None and resolution_popup is not None:
|
||||
bui.widget(
|
||||
edit=resolution_popup.get_button(),
|
||||
down_widget=self._max_fps_text,
|
||||
)
|
||||
bui.widget(
|
||||
edit=self._max_fps_text,
|
||||
up_widget=resolution_popup.get_button(),
|
||||
)
|
||||
|
||||
fpsc = ConfigCheckBox(
|
||||
parent=self._root_widget,
|
||||
position=(69, v - 6),
|
||||
|
|
@ -398,9 +396,17 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
displayname=bui.Lstr(resource=self._r + '.showFPSText'),
|
||||
maxwidth=130,
|
||||
)
|
||||
if self._max_fps_text is not None:
|
||||
bui.widget(
|
||||
edit=self._max_fps_text,
|
||||
down_widget=fpsc.widget,
|
||||
)
|
||||
bui.widget(
|
||||
edit=fpsc.widget,
|
||||
up_widget=self._max_fps_text,
|
||||
)
|
||||
|
||||
# (tv mode doesnt apply to vr)
|
||||
if not bui.app.vr_mode:
|
||||
if show_tv_mode:
|
||||
tvc = ConfigCheckBox(
|
||||
parent=self._root_widget,
|
||||
position=(240, v - 6),
|
||||
|
|
@ -410,13 +416,8 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
displayname=bui.Lstr(resource=self._r + '.tvBorderText'),
|
||||
maxwidth=130,
|
||||
)
|
||||
# grumble..
|
||||
bui.widget(edit=fpsc.widget, right_widget=tvc.widget)
|
||||
try:
|
||||
pass
|
||||
|
||||
except Exception:
|
||||
logging.exception('Exception wiring up graphics settings UI.')
|
||||
bui.widget(edit=tvc.widget, left_widget=fpsc.widget)
|
||||
|
||||
v -= spacing
|
||||
|
||||
|
|
@ -429,6 +430,10 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
def _back(self) -> None:
|
||||
from bauiv1lib.settings import allsettings
|
||||
|
||||
# Applying max-fps takes a few moments. Apply if it hasn't been
|
||||
# yet.
|
||||
self._apply_max_fps()
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
|
|
@ -469,7 +474,60 @@ class GraphicsSettingsWindow(bui.Window):
|
|||
cfg['Vertical Sync'] = val
|
||||
cfg.apply_and_commit()
|
||||
|
||||
def _on_max_fps_return_press(self) -> None:
|
||||
self._apply_max_fps()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, selected_child=cast(bui.Widget, 0)
|
||||
)
|
||||
|
||||
def _apply_max_fps(self) -> None:
|
||||
if not self._max_fps_dirty or not self._max_fps_text:
|
||||
return
|
||||
|
||||
val: Any = bui.textwidget(query=self._max_fps_text)
|
||||
assert isinstance(val, str)
|
||||
# If there's a broken value, replace it with the default.
|
||||
try:
|
||||
ival = int(val)
|
||||
except ValueError:
|
||||
ival = bui.app.config.default_value('Max FPS')
|
||||
assert isinstance(ival, int)
|
||||
|
||||
# Clamp to reasonable limits (allow -1 to mean no max).
|
||||
if ival != -1:
|
||||
ival = max(10, ival)
|
||||
ival = min(99999, ival)
|
||||
|
||||
# Store it to the config.
|
||||
cfg = bui.app.config
|
||||
cfg['Max FPS'] = ival
|
||||
cfg.apply_and_commit()
|
||||
|
||||
# Update the display if we changed the value.
|
||||
if str(ival) != val:
|
||||
bui.textwidget(edit=self._max_fps_text, text=str(ival))
|
||||
|
||||
self._max_fps_dirty = False
|
||||
|
||||
def _update_controls(self) -> None:
|
||||
if self._max_fps_text is not None:
|
||||
# Keep track of when the max-fps value changes. Once it
|
||||
# remains stable for a few moments, apply it.
|
||||
val: Any = bui.textwidget(query=self._max_fps_text)
|
||||
assert isinstance(val, str)
|
||||
if val != self._last_max_fps_str:
|
||||
# Oop; it changed. Note the time and the fact that we'll
|
||||
# need to apply it at some point.
|
||||
self._max_fps_dirty = True
|
||||
self._last_max_fps_str = val
|
||||
self._last_max_fps_set_time = bui.apptime()
|
||||
else:
|
||||
# If its been stable long enough, apply it.
|
||||
if (
|
||||
self._max_fps_dirty
|
||||
and bui.apptime() - self._last_max_fps_set_time > 1.0
|
||||
):
|
||||
self._apply_max_fps()
|
||||
if self._show_fullscreen:
|
||||
bui.checkboxwidget(
|
||||
edit=self._fullscreen_checkbox,
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ class ConfigKeyboardWindow(bui.Window):
|
|||
{
|
||||
'ua': bui.app.classic.legacy_user_agent_string,
|
||||
'name': self._name,
|
||||
'b': bui.app.build_number,
|
||||
'b': bui.app.env.build_number,
|
||||
'config': dst2,
|
||||
'v': 2,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,14 +44,14 @@ class SpecialOfferWindow(bui.Window):
|
|||
real_price = plus.get_price(
|
||||
'pro' if offer['item'] == 'pro_fullprice' else 'pro_sale'
|
||||
)
|
||||
if real_price is None and bui.app.debug_build:
|
||||
if real_price is None and bui.app.env.debug:
|
||||
print('NOTE: Faking prices for debug build.')
|
||||
real_price = '$1.23'
|
||||
zombie = real_price is None
|
||||
elif isinstance(offer['price'], str):
|
||||
# (a string price implies IAP id)
|
||||
real_price = plus.get_price(offer['price'])
|
||||
if real_price is None and bui.app.debug_build:
|
||||
if real_price is None and bui.app.env.debug:
|
||||
print('NOTE: Faking price for debug build.')
|
||||
real_price = '$1.23'
|
||||
zombie = real_price is None
|
||||
|
|
|
|||
12
dist/ba_data/python/bauiv1lib/store/browser.py
vendored
12
dist/ba_data/python/bauiv1lib/store/browser.py
vendored
|
|
@ -566,8 +566,8 @@ class StoreBrowserWindow(bui.Window):
|
|||
'item': item,
|
||||
'platform': app.classic.platform,
|
||||
'subplatform': app.classic.subplatform,
|
||||
'version': app.version,
|
||||
'buildNumber': app.build_number,
|
||||
'version': app.env.version,
|
||||
'buildNumber': app.env.build_number,
|
||||
'purchaseType': 'ticket' if is_ticket_purchase else 'real',
|
||||
},
|
||||
callback=bui.WeakCall(
|
||||
|
|
@ -1406,11 +1406,11 @@ def _check_merch_availability_in_bg_thread() -> None:
|
|||
time.sleep(1.1934) # A bit randomized to avoid aliasing.
|
||||
|
||||
|
||||
# Slight hack; start checking merch availability in the bg
|
||||
# (but only if it looks like we're part of a running app; don't want to
|
||||
# do this during docs generation/etc.)
|
||||
# Slight hack; start checking merch availability in the bg (but only if
|
||||
# it looks like we've been imported for use in a running app; don't want
|
||||
# to do this during docs generation/etc.)
|
||||
if (
|
||||
os.environ.get('BA_RUNNING_WITH_DUMMY_MODULES') != '1'
|
||||
and bui.app.state is not bui.app.State.INITIAL
|
||||
and bui.app.state is not bui.app.State.NOT_RUNNING
|
||||
):
|
||||
Thread(target=_check_merch_availability_in_bg_thread, daemon=True).start()
|
||||
|
|
|
|||
4
dist/ba_data/python/efro/cloudshell.py
vendored
4
dist/ba_data/python/efro/cloudshell.py
vendored
|
|
@ -36,7 +36,9 @@ class HostConfig:
|
|||
mosh_shell: str = 'sh'
|
||||
workspaces_root: str = '/home/${USER}/cloudshell_workspaces'
|
||||
sync_perms: bool = True
|
||||
precommand: str | None = None
|
||||
precommand: str | None = None # KILL THIS
|
||||
precommand_noninteractive: str | None = None
|
||||
precommand_interactive: str | None = None
|
||||
managed: bool = False
|
||||
idle_minutes: int = 5
|
||||
can_sudo_reboot: bool = False
|
||||
|
|
|
|||
19
dist/ba_data/python/efro/error.py
vendored
19
dist/ba_data/python/efro/error.py
vendored
|
|
@ -7,7 +7,9 @@ from typing import TYPE_CHECKING
|
|||
import errno
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
from typing import Any
|
||||
|
||||
from efro.terminal import ClrBase
|
||||
|
||||
|
||||
class CleanError(Exception):
|
||||
|
|
@ -25,18 +27,29 @@ class CleanError(Exception):
|
|||
more descriptive exception types.
|
||||
"""
|
||||
|
||||
def pretty_print(self, flush: bool = True, prefix: str = 'Error') -> None:
|
||||
def pretty_print(
|
||||
self,
|
||||
flush: bool = True,
|
||||
prefix: str = 'Error',
|
||||
file: Any = None,
|
||||
clr: type[ClrBase] | None = None,
|
||||
) -> None:
|
||||
"""Print the error to stdout, using red colored output if available.
|
||||
|
||||
If the error has an empty message, prints nothing (not even a newline).
|
||||
"""
|
||||
from efro.terminal import Clr
|
||||
|
||||
if clr is None:
|
||||
clr = Clr
|
||||
|
||||
if prefix:
|
||||
prefix = f'{prefix}: '
|
||||
errstr = str(self)
|
||||
if errstr:
|
||||
print(f'{Clr.SRED}{prefix}{errstr}{Clr.RST}', flush=flush)
|
||||
print(
|
||||
f'{clr.SRED}{prefix}{errstr}{clr.RST}', flush=flush, file=file
|
||||
)
|
||||
|
||||
|
||||
class CommunicationError(Exception):
|
||||
|
|
|
|||
11
dist/ba_data/python/efro/util.py
vendored
11
dist/ba_data/python/efro/util.py
vendored
|
|
@ -39,6 +39,12 @@ class _EmptyObj:
|
|||
pass
|
||||
|
||||
|
||||
# A dead weak-ref should be immutable, right? So we can create exactly
|
||||
# one and return it for all cases that need an empty weak-ref.
|
||||
_g_empty_weak_ref = weakref.ref(_EmptyObj())
|
||||
assert _g_empty_weak_ref() is None
|
||||
|
||||
|
||||
# TODO: kill this and just use efro.call.tpartial
|
||||
if TYPE_CHECKING:
|
||||
Call = Call
|
||||
|
|
@ -148,8 +154,11 @@ def empty_weakref(objtype: type[T]) -> weakref.ref[T]:
|
|||
# At runtime, all weakrefs are the same; our type arg is just
|
||||
# for the static type checker.
|
||||
del objtype # Unused.
|
||||
|
||||
# Just create an object and let it die. Is there a cleaner way to do this?
|
||||
return weakref.ref(_EmptyObj()) # type: ignore
|
||||
# return weakref.ref(_EmptyObj()) # type: ignore
|
||||
|
||||
return _g_empty_weak_ref # type: ignore
|
||||
|
||||
|
||||
def data_size_str(bytecount: int) -> str:
|
||||
|
|
|
|||
2
dist/ba_root/mods/custom_hooks.py
vendored
2
dist/ba_root/mods/custom_hooks.py
vendored
|
|
@ -64,7 +64,7 @@ class modSetup(babase.Plugin):
|
|||
bootstraping()
|
||||
servercheck.checkserver().start()
|
||||
ServerUpdate.check()
|
||||
bs.apptimer(5, account.updateOwnerIps)
|
||||
# bs.apptimer(5, account.updateOwnerIps)
|
||||
if settings["afk_remover"]['enable']:
|
||||
afk_check.checkIdle().start()
|
||||
if (settings["useV2Account"]):
|
||||
|
|
|
|||
BIN
dist/bombsquad_headless
vendored
BIN
dist/bombsquad_headless
vendored
Binary file not shown.
BIN
dist/bombsquad_headless_aarch64
vendored
BIN
dist/bombsquad_headless_aarch64
vendored
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue