Internal work related to tourney security

This commit is contained in:
Eric Froemling 2020-06-07 23:17:48 -07:00
parent 431e6e80bf
commit 5565b4bfa5
33 changed files with 2671 additions and 2596 deletions

View File

@ -420,34 +420,34 @@
"assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762",
"assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074",
"assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1",
"assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/98/6d/e6de20b119fd6a5914982cd468b6",
"assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/d4/df/3ab21c23dedf45ab454b0c4286b1",
"assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/b8/ed/e18bec56ff1d094aae86517a7854",
"assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637",
"assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/80/b2/b24a9a8395580ef2dea714abf478",
"assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/bc/59/21bb0b4ef33c733022340c60aebf",
"assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/aa/91/2411c0728bae33619c21237a2689",
"assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/bb/9c/360fc084e6254a087096993af219",
"assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/f2/90/62968ad28a2499a8d182a5740a85",
"assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28",
"assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/5b/a3/a46a77f0cc498e1f1e369d772414",
"assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/b4/fe/f33399347c16a13f17e920c7e33c",
"assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/30/f3/4ef3bbaf1e5b7abe114c119ec106",
"assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731",
"assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/95/9b/66e9080c82ef76387832dedee9b4",
"assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/9d/00/a8c4ef9f0a25e789c046bd741203",
"assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/e7/ff/638467708af1e2eea569e9225906",
"assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/8e/24/f070599beb7b09e1268569fa55b1",
"assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa",
"assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/7a/64/04464dc6ee8a45632857fa436bff",
"assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/4d/4b/0790110201c9adb1b521e9a55e63",
"assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/8e/e7/38e093014a917418e6cf7aa9315d",
"assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/a5/05/fbdf4d90b85609e4fa258e1ce814",
"assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/a5/ef/b1935b3767692070f070847f40df",
"assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52",
"assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/c2/fc/dd1c15cf9ecb411d9defbd000c06",
"assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/db/eb/324f86a4b714240ae50ffeeed2f8",
"assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/a9/bc/ea61ebd23066c685fb779e23d10f",
"assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/66/0b/df2cd57be4eb505876d209a673d9",
"assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/f6/d0/335b952306d211d56172b5c72d8c",
"assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/56/f4/b76f1e862b29db5f642a67da67f3",
"assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/33/82/be19758f3563ba6617db4736de74",
"assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b",
"assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2",
"assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/90/d9/0f8f5b03bbe2dfebfb544cee6bd6",
"assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/a9/77/722faae6a695f19501bac76098db",
"assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0",
"assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/30/70/ba6f57b2d865d0027a50c6e1dba5",
"assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/e0/f7/f6daa488dc29e303dea69aae864b",
@ -4132,16 +4132,16 @@
"assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c",
"assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb",
"assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe",
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/92/ca/9fa8a48f38554ef676a900136ce9",
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e3/2c/f3e52a261f8dabced7a41d925053",
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/df/82/1c63fa091da3fb52bcecf87f8ea6",
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/83/18/a60e9e2f6e37e2f36ca8c8f4f42c",
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/96/6a/cc35319fd83bca6ff578e4c8dad6",
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5a/a2/b04d489862ae208c6b2b31697519",
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a8/ca/89e007ea20b4f2a3dee09e1361c3",
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6e/cd/f8ad50715cb46d5cae7bd87bb498",
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/36/d1/67a51def178a07f99acc3cc2b11c",
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/52/4a/a7a5b56eda157fde6e58a90ab98a",
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cc/ec/d82c9ba9d587598f8183bc360326",
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8e/2a/f24b48e15ef4fd5794c5e426081b"
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1e/2c/09ca7e7ab982a04608a9cee6230b",
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/d6/25671c9f875c9eb1f25f09d1000f",
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f8/ee/6989965b6929d55044156e41017b",
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ca/e9/c7b41ca260cb04e539cc81fd79c4",
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5b/ef/9d427caa8a691f225cbf3e0c649e",
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/88/61/63b817195328d360c02c8705405a",
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/51/bf8fdbea96a0e76f9203bcd1c427",
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c1/34/ad36c057f3d2c890617a25311cd8",
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e3/00/d0cfc8d72ef8dd1567ca7e48a58e",
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cd/c0/56c8c49c60298727d7593f91928a",
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/24/d1/d73ae026e9797924e5257d87fe98",
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8b/4f/112f32d713898abca7fa465779c1"
}

View File

@ -79,6 +79,8 @@
<w>appkit</w>
<w>applescript</w>
<w>appletv</w>
<w>appname</w>
<w>appnameupper</w>
<w>appstate</w>
<w>appstore</w>
<w>apputils</w>
@ -155,6 +157,7 @@
<w>basespaz</w>
<w>basetime</w>
<w>baseurl</w>
<w>baseval</w>
<w>basew</w>
<w>bastd</w>
<w>batools</w>
@ -184,6 +187,7 @@
<w>blas</w>
<w>blastos</w>
<w>bldtp</w>
<w>blesspath</w>
<w>blocksize</w>
<w>bluetooth</w>
<w>bmag</w>
@ -222,8 +226,11 @@
<w>btnh</w>
<w>btnv</w>
<w>btnx</w>
<w>buildblessing</w>
<w>buildblessingcheck</w>
<w>builddir</w>
<w>buildfile</w>
<w>buildnum</w>
<w>buildtype</w>
<w>bullseye</w>
<w>bumpmap</w>
@ -780,6 +787,7 @@
<w>getlevel</w>
<w>getlevelname</w>
<w>getlevels</w>
<w>getlocalconfig</w>
<w>getlog</w>
<w>getmaps</w>
<w>getmodel</w>
@ -850,6 +858,7 @@
<w>hasstarted</w>
<w>hatmotion</w>
<w>hattach</w>
<w>hcalc</w>
<w>hdpi</w>
<w>headercheckline</w>
<w>headerregistry</w>
@ -1051,6 +1060,7 @@
<w>lineno</w>
<w>linenum</w>
<w>linenumber</w>
<w>linenums</w>
<w>linetype</w>
<w>linetypes</w>
<w>linflav</w>
@ -1127,6 +1137,7 @@
<w>markupbase</w>
<w>masktex</w>
<w>masktexstorename</w>
<w>masterhash</w>
<w>mathmodule</w>
<w>mathnode</w>
<w>mathutils</w>
@ -1148,6 +1159,8 @@
<w>meteorshower</w>
<w>mfpath</w>
<w>mhash</w>
<w>mhbegin</w>
<w>mhend</w>
<w>mhsh</w>
<w>microprotocols</w>
<w>mikirog</w>
@ -1326,6 +1339,7 @@
<w>osval</w>
<w>otherplayer</w>
<w>otherspawn</w>
<w>ourhash</w>
<w>ourself</w>
<w>outdata</w>
<w>outdelay</w>
@ -1548,7 +1562,9 @@
<w>pysources</w>
<w>pytest</w>
<w>pythondontwritebytecode</w>
<w>pythonhashseed</w>
<w>pythonpath</w>
<w>pythonpaths</w>
<w>pythonw</w>
<w>pytree</w>
<w>pytz</w>

File diff suppressed because it is too large Load Diff

View File

@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand.
"""
# (hash we can use to see if this file is out of date)
# SOURCES_HASH=102801821147286215106809880997032542189
# SOURCES_HASH=197797300249336200681012613336602141418
# I'm sorry Pylint. I know this file saddens you. Be strong.
# pylint: disable=useless-suppression
@ -1334,6 +1334,22 @@ def apply_config() -> None:
return None
def appname() -> str:
"""appname() -> str
(internal)
"""
return str()
def appnameupper() -> str:
"""appnameupper() -> str
(internal)
"""
return str()
def back_press() -> None:
"""back_press() -> None
@ -2708,6 +2724,14 @@ def invite_players() -> None:
return None
def is_blessed() -> bool:
"""is_blessed() -> bool
(internal)
"""
return bool()
def is_in_replay() -> bool:
"""is_in_replay() -> bool

View File

@ -163,7 +163,7 @@ def have_pro() -> bool:
return bool(
_ba.get_purchased('upgrades.pro') or _ba.get_purchased('static.pro')
or _ba.get_purchased('static.pro_sale')
or 'ballistica' + 'core' == 'ballisticacore')
or 'ballistica' + 'core' == _ba.appname())
def have_pro_options() -> bool:

View File

@ -185,14 +185,14 @@ class App:
return self._python_directory_user
@property
def python_directory_ba(self) -> str:
def python_directory_app(self) -> str:
"""Path where the app looks for its bundled scripts."""
return self._python_directory_ba
return self._python_directory_app
@property
def python_directory_site(self) -> str:
def python_directory_app_site(self) -> str:
"""Path containing pip packages bundled with the app."""
return self._python_directory_site
return self._python_directory_app_site
@property
def config(self) -> ba.AppConfig:
@ -297,10 +297,10 @@ class App:
assert isinstance(self._test_build, bool)
self._python_directory_user: str = env['python_directory_user']
assert isinstance(self._python_directory_user, str)
self._python_directory_ba: str = env['python_directory_ba']
assert isinstance(self._python_directory_ba, str)
self._python_directory_site: str = env['python_directory_site']
assert isinstance(self._python_directory_site, str)
self._python_directory_app: str = env['python_directory_app']
assert isinstance(self._python_directory_app, str)
self._python_directory_app_site: str = env['python_directory_app_site']
assert isinstance(self._python_directory_app_site, str)
self._platform: str = env['platform']
assert isinstance(self._platform, str)
self._subplatform: str = env['subplatform']
@ -325,7 +325,6 @@ class App:
self.metascan: Optional[_meta.ScanResults] = None
self.tips: List[str] = []
self.stress_test_reset_timer: Optional[ba.Timer] = None
self.suppress_debug_reports = False
self.last_ad_completion_time: Optional[float] = None
self.last_ad_was_short = False
self.did_weak_call_warning = False
@ -477,8 +476,11 @@ class App:
]:
_map.register_map(maptype)
if self.debug_build:
_apputils.suppress_debug_reports()
# Non-test, non-debug builds should generally be blessed; warn if not.
# (so I don't accidentally release a build that can't play tourneys)
if (not self.debug_build and not self.test_build
and not _ba.is_blessed()):
_ba.screenmessage('WARNING: NON-BLESSED BUILD', color=(1, 0, 0))
# IMPORTANT - if tweaking UI stuff, you need to make sure it behaves
# for small, medium, and large UI modes. (doesn't run off screen, etc).
@ -526,7 +528,7 @@ class App:
# Notify the user if we're using custom system scripts.
# FIXME: This no longer works since sys-scripts is an absolute path;
# need to just add a proper call to query this.
# if env['python_directory_ba'] != 'data/scripts':
# if env['python_directory_app'] != 'data/scripts':
# ba.screenmessage("Using custom system scripts...",
# color=(0, 1, 0))
@ -795,8 +797,9 @@ class App:
"""Handle a deep link URL."""
from ba._lang import Lstr
from ba._enums import TimeType
if url.startswith('ballisticacore://code/'):
code = url.replace('ballisticacore://code/', '')
appname = _ba.appname()
if url.startswith(f'{appname}://code/'):
code = url.replace(f'{appname}://code/', '')
# If we're not signed in, queue up the code to run the next time we
# are and issue a warning if we haven't signed in within the next

View File

@ -67,15 +67,6 @@ def should_submit_debug_info() -> bool:
return _ba.app.config.get('Submit Debug Info', True)
def suppress_debug_reports() -> None:
"""Turn debug-reporting to the master server off.
This should be called in devel/debug situations to avoid spamming
the master server with spurious logs.
"""
_ba.app.suppress_debug_reports = True
def handle_log() -> None:
"""Called on debug log prints.
@ -89,37 +80,38 @@ def handle_log() -> None:
if not app.log_upload_timer_started:
def _put_log() -> None:
if not app.suppress_debug_reports:
try:
sessionname = str(_ba.get_foreground_host_session())
except Exception:
sessionname = 'unavailable'
try:
activityname = str(_ba.get_foreground_host_activity())
except Exception:
activityname = 'unavailable'
info = {
'log': _ba.getlog(),
'version': app.version,
'build': app.build_number,
'userAgentString': app.user_agent_string,
'session': sessionname,
'activity': activityname,
'fatal': 0,
'userRanCommands': _ba.has_user_run_commands(),
'time': _ba.time(TimeType.REAL),
'userModded': _ba.has_user_mods()
}
try:
sessionname = str(_ba.get_foreground_host_session())
except Exception:
sessionname = 'unavailable'
try:
activityname = str(_ba.get_foreground_host_activity())
except Exception:
activityname = 'unavailable'
def response(data: Any) -> None:
# A non-None response means success; lets
# take note that we don't need to report further
# log info this run
if data is not None:
app.log_have_new = False
_ba.mark_log_sent()
info = {
'log': _ba.getlog(),
'version': app.version,
'build': app.build_number,
'userAgentString': app.user_agent_string,
'session': sessionname,
'activity': activityname,
'fatal': 0,
'userRanCommands': _ba.has_user_run_commands(),
'time': _ba.time(TimeType.REAL),
'userModded': _ba.has_user_mods(),
'newsShow': _ba.get_news_show(),
}
serverput('bsLog', info, response)
def response(data: Any) -> None:
# A non-None response means success; lets
# take note that we don't need to report further
# log info this run
if data is not None:
app.log_have_new = False
_ba.mark_log_sent()
serverput('bsLog', info, response)
app.log_upload_timer_started = True

View File

@ -122,6 +122,9 @@ def init_campaigns() -> None:
from bastd.game.easteregghunt import EasterEggHuntGame
from bastd.game.ninjafight import NinjaFightGame
# TODO: Campaigns should be load-on-demand; not all imported at launch
# like this.
# FIXME: Once translations catch up, we can convert these to use the
# generic display-name '${GAME} Training' type stuff.
campaign = Campaign('Easy')

View File

@ -264,10 +264,7 @@ class CoopSession(Session):
if isinstance(results, GameResults):
outcome = 'defeat' # This can't be 'beaten'.
else:
try:
outcome = results['outcome']
except Exception:
outcome = ''
outcome = '' if results is None else results.get('outcome', '')
# If 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).
@ -315,7 +312,7 @@ class CoopSession(Session):
self.stats.register_sessionplayer(player)
self.stats.setactivity(next_game)
# Now flip the current activity.
# Now flip the current activity..
self.setactivity(next_game)
if not app.kiosk_mode:

View File

@ -26,6 +26,8 @@ import weakref
from dataclasses import dataclass
from typing import TYPE_CHECKING
from ba._team import Team, SessionTeam
if TYPE_CHECKING:
from weakref import ReferenceType
from typing import Sequence, Tuple, Any, Optional, Dict, List, Union
@ -66,7 +68,9 @@ class GameResults:
if self._game_set:
raise RuntimeError('Game set twice for GameResults.')
self._game_set = True
self._sessionteams = [weakref.ref(team) for team in game.teams]
self._sessionteams = [
weakref.ref(team.sessionteam) for team in game.teams
]
scoreconfig = game.getscoreconfig()
self._playerinfos = copy.deepcopy(game.initialplayerinfos)
self._lower_is_better = scoreconfig.lower_is_better
@ -80,12 +84,14 @@ class GameResults:
This can be a number or None.
(see the none_is_winner arg in the constructor)
"""
assert isinstance(team, Team)
sessionteam = team.sessionteam
self._scores[sessionteam.id] = (weakref.ref(sessionteam), score)
def get_sessionteam_score(self,
sessionteam: ba.SessionTeam) -> Optional[int]:
"""Return the score for a given ba.SessionTeam."""
assert isinstance(sessionteam, SessionTeam)
for score in list(self._scores.values()):
if score[0]() is sessionteam:
return score[1]

View File

@ -89,7 +89,7 @@ def getclass(name: str, subclassof: Type[T]) -> Type[T]:
cls: Type = getattr(module, classname)
if not issubclass(cls, subclassof):
raise TypeError(name + ' is not a subclass of ' + str(subclassof))
raise TypeError(f'{name} is not a subclass of {subclassof}.')
return cls

View File

@ -56,7 +56,7 @@ def start_scan() -> None:
app = _ba.app
if app.metascan is not None:
print('WARNING: meta scan run more than once.')
scriptdirs = [app.python_directory_ba, app.python_directory_user]
scriptdirs = [app.python_directory_app, app.python_directory_user]
thread = ScanThread(scriptdirs)
thread.start()

View File

@ -119,9 +119,9 @@ def create_user_system_scripts() -> None:
# Hmm; shutil.copytree doesn't seem to work nicely on android,
# so lets do it manually.
# NOTE: Should retry this now that we have 3.7 (this note was for 2.7)
src_dir = app.python_directory_ba
src_dir = app.python_directory_app
dst_dir = path + '_tmp'
filenames = os.listdir(app.python_directory_ba)
filenames = os.listdir(app.python_directory_app)
for fname in filenames:
print('COPYING', src_dir + '/' + fname, '->', dst_dir)
shutil.copyfile(src_dir + '/' + fname, dst_dir + '/' + fname)

View File

@ -321,7 +321,7 @@ class ServerController:
if self._first_run:
curtimestr = time.strftime('%c')
print(f'{Clr.BLD}{Clr.BLU}BallisticaCore {app.version}'
print(f'{Clr.BLD}{Clr.BLU}{_ba.appnameupper()} {app.version}'
f' ({app.build_number})'
f' entering server-mode {curtimestr}{Clr.RST}')

View File

@ -71,7 +71,7 @@ class OSMusicPlayer(MusicPlayer):
elif entry_type == 'musicFolder':
# Launch a thread to scan this folder and give us a random
# valid file within.
# valid file within it.
self._want_to_play = True
self._actually_playing = False
_PickFolderSongThread(name, self.get_valid_music_file_extensions(),

View File

@ -18,6 +18,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# -----------------------------------------------------------------------------
"""BallisticaCore standard library: games, UI, etc."""
"""Ballistica standard library: games, UI, etc."""
# ba_meta require api 6

View File

@ -239,7 +239,6 @@ class TutorialActivity(ba.Activity[Player, Team]):
self.bomb_image_color = (1.0, 1.0, 1.0)
self.pickup_image_color = (1.0, 1.0, 1.0)
self.control_ui_nodes: List[ba.Node] = []
self._test_file = ''
self.spazzes: Dict[int, basespaz.Spaz] = {}
self.jump_image_color = (1.0, 1.0, 1.0)
self._entries: List[Any] = []
@ -400,9 +399,6 @@ class TutorialActivity(ba.Activity[Player, Team]):
]
for n in self.control_ui_nodes:
n.opacity = 0.0
self._test_file = ('/Users/ericf/Library/Containers/'
'net.froemling.ballisticacore/Data/'
'Library/Application Support/Ballisticacore/foo.py')
self._read_entries()
def set_stick_image_position(self, x: float, y: float) -> None:
@ -844,7 +840,7 @@ class TutorialActivity(ba.Activity[Player, Team]):
ba.Lstr(resource=self._r + '.phrase02Text',
subs=[
('${APP_NAME}', ba.Lstr(resource='titleText'))
])), # welcome to ballisticacore
])), # welcome to <appname>
DelayOld(80),
Run(release=False),
Jump(release=False),

View File

@ -47,7 +47,7 @@ class ConfigErrorWindow(ba.Window):
h_align='center',
v_align='top',
scale=0.73,
text=('Error reading BallisticaCore config file'
text=(f'Error reading {_ba.appnameupper()} config file'
':\n\n\nCheck the console'
' (press ~ twice) for details.\n\nWould you like to quit and'
' try to fix it by hand\nor overwrite it with defaults?\n\n'

View File

@ -61,6 +61,16 @@ class CoopBrowserWindow(ba.Window):
app = ba.app
cfg = app.config
# Quick note to players that tourneys won't work if we're a non-blessed
# or a debug build...
if not _ba.is_blessed() or ba.app.debug_build:
ba.timer(1.0,
lambda: ba.screenmessage(
ba.Lstr(resource='noTournamentsInTestBuildText'),
color=(1, 1, 0),
),
timetype=ba.TimeType.REAL)
# If they provided an origin-widget, scale up from that.
scale_origin: Optional[Tuple[float, float]]
if origin_widget is not None:
@ -99,10 +109,8 @@ class CoopBrowserWindow(ba.Window):
size=(self._width, self._height + top_extra),
toolbar_visibility='menu_full',
scale_origin_stack_offset=scale_origin,
stack_offset=(0,
-15) if app.small_ui else (0,
0) if app.med_ui else (0,
0),
stack_offset=((0, -15) if app.small_ui else (
0, 0) if app.med_ui else (0, 0)),
transition=transition,
scale=1.2 if app.small_ui else 0.8 if app.med_ui else 0.75))

View File

@ -66,11 +66,13 @@ def ask_for_rating() -> Optional[ba.Widget]:
v_align='center')
def do_rating() -> None:
import _ba
if platform == 'android':
appname = _ba.appname()
if subplatform == 'google':
url = 'market://details?id=net.froemling.ballisticacore'
url = f'market://details?id=net.froemling.{appname}'
else:
url = 'market://details?id=net.froemling.ballisticacorecb'
url = 'market://details?id=net.froemling.{appname}cb'
else:
url = 'macappstore://itunes.apple.com/app/id416482767?ls=1&mt=12'

View File

@ -61,8 +61,8 @@ class PlaylistTypeVars:
self.sessiontype = ba.FreeForAllSession
else:
raise TypeError('playlist type vars undefined for session type: ' +
str(sessiontype))
raise RuntimeError(
f'Playlist type vars undefined for sessiontype: {sessiontype}')
self.default_list_name = ba.Lstr(resource='defaultGameListNameText',
subs=[('${PLAYMODE}', play_mode_name)
])

View File

@ -87,7 +87,7 @@ class ReportPlayerWindow(ba.Window):
})
body = ba.Lstr(resource='reportPlayerExplanationText').evaluate()
ba.open_url('mailto:support@froemling.net'
'?subject=BallisticaCore Player Report: ' +
f'?subject={_ba.appnameupper()} Player Report: ' +
self._account_id + '&body=' + parse.quote(body))
self.close()
@ -100,7 +100,7 @@ class ReportPlayerWindow(ba.Window):
})
body = ba.Lstr(resource='reportPlayerExplanationText').evaluate()
ba.open_url('mailto:support@froemling.net'
'?subject=BallisticaCore Player Report: ' +
f'?subject={_ba.appnameupper()} Player Report: ' +
self._account_id + '&body=' + parse.quote(body))
self.close()

View File

@ -1,5 +1,5 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<h4><em>last updated on 2020-06-04 for Ballistica version 1.5.0 build 20045</em></h4>
<h4><em>last updated on 2020-06-07 for Ballistica version 1.5.0 build 20059</em></h4>
<p>This page documents the Python classes and functions in the 'ba' module,
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
<hr>
@ -805,7 +805,7 @@ likely result in errors.</p>
</p>
<h3>Attributes:</h3>
<h5><a href="#attr_ba_App__api_version">api_version</a>, <a href="#attr_ba_App__build_number">build_number</a>, <a href="#attr_ba_App__config">config</a>, <a href="#attr_ba_App__config_file_path">config_file_path</a>, <a href="#attr_ba_App__debug_build">debug_build</a>, <a href="#attr_ba_App__interface_type">interface_type</a>, <a href="#attr_ba_App__language">language</a>, <a href="#attr_ba_App__locale">locale</a>, <a href="#attr_ba_App__on_tv">on_tv</a>, <a href="#attr_ba_App__platform">platform</a>, <a href="#attr_ba_App__python_directory_ba">python_directory_ba</a>, <a href="#attr_ba_App__python_directory_site">python_directory_site</a>, <a href="#attr_ba_App__python_directory_user">python_directory_user</a>, <a href="#attr_ba_App__subplatform">subplatform</a>, <a href="#attr_ba_App__test_build">test_build</a>, <a href="#attr_ba_App__ui_bounds">ui_bounds</a>, <a href="#attr_ba_App__user_agent_string">user_agent_string</a>, <a href="#attr_ba_App__version">version</a>, <a href="#attr_ba_App__vr_mode">vr_mode</a></h5>
<h5><a href="#attr_ba_App__api_version">api_version</a>, <a href="#attr_ba_App__build_number">build_number</a>, <a href="#attr_ba_App__config">config</a>, <a href="#attr_ba_App__config_file_path">config_file_path</a>, <a href="#attr_ba_App__debug_build">debug_build</a>, <a href="#attr_ba_App__interface_type">interface_type</a>, <a href="#attr_ba_App__language">language</a>, <a href="#attr_ba_App__locale">locale</a>, <a href="#attr_ba_App__on_tv">on_tv</a>, <a href="#attr_ba_App__platform">platform</a>, <a href="#attr_ba_App__python_directory_app">python_directory_app</a>, <a href="#attr_ba_App__python_directory_app_site">python_directory_app_site</a>, <a href="#attr_ba_App__python_directory_user">python_directory_user</a>, <a href="#attr_ba_App__subplatform">subplatform</a>, <a href="#attr_ba_App__test_build">test_build</a>, <a href="#attr_ba_App__ui_bounds">ui_bounds</a>, <a href="#attr_ba_App__user_agent_string">user_agent_string</a>, <a href="#attr_ba_App__version">version</a>, <a href="#attr_ba_App__vr_mode">vr_mode</a></h5>
<dl>
<dt><h4><a name="attr_ba_App__api_version">api_version</a></h4></dt><dd>
<p><span>int</span></p>
@ -886,12 +886,12 @@ likely result in errors.</p>
<p> Examples are: 'mac', 'windows', android'.</p>
</dd>
<dt><h4><a name="attr_ba_App__python_directory_ba">python_directory_ba</a></h4></dt><dd>
<dt><h4><a name="attr_ba_App__python_directory_app">python_directory_app</a></h4></dt><dd>
<p><span>str</span></p>
<p>Path where the app looks for its bundled scripts.</p>
</dd>
<dt><h4><a name="attr_ba_App__python_directory_site">python_directory_site</a></h4></dt><dd>
<dt><h4><a name="attr_ba_App__python_directory_app_site">python_directory_app_site</a></h4></dt><dd>
<p><span>str</span></p>
<p>Path containing pip packages bundled with the app.</p>

View File

@ -31,7 +31,7 @@ if TYPE_CHECKING:
@dataclass
class ServerConfig:
"""Configuration for the server manager app (ballisticacore_server)."""
"""Configuration for the server manager app (<appname>_server)."""
# Name of our server in the public parties list.
party_name: str = 'FFA'
@ -87,7 +87,7 @@ class ServerConfig:
# Whether to enable telnet access.
# IMPORTANT: This option is no longer available, as it was being used
# for exploits. Live access to the running server is still possible through
# the mgr.cmd() function in ballisticacore_server. Run your server through
# the mgr.cmd() function in the server script. Run your server through
# tools such as 'screen' or 'tmux' and you can reconnect to it remotely
# over a secure ssh connection.
enable_telnet: bool = False

View File

@ -158,7 +158,7 @@ def _lazybuild_check_paths(inpaths: List[str], category: SourceCategory,
if _testpath(fpath):
return True
unchanged_count += 1
print(f'{Clr.SBLU}Lazybuild: skipping "{tnamepretty}"'
print(f'{Clr.BLU}Lazybuild: skipping "{tnamepretty}"'
f' ({unchanged_count} inputs unchanged).{Clr.RST}')
return False

View File

@ -70,7 +70,7 @@ def explicit_bool(value: bool) -> bool:
return value
def get_localconfig(projroot: Path) -> Dict[str, Any]:
def getlocalconfig(projroot: Path) -> Dict[str, Any]:
"""Return a project's localconfig contents (or default if missing)."""
localconfig: Dict[str, Any]
try:
@ -81,7 +81,7 @@ def get_localconfig(projroot: Path) -> Dict[str, Any]:
return localconfig
def get_config(projroot: Path) -> Dict[str, Any]:
def getconfig(projroot: Path) -> Dict[str, Any]:
"""Return a project's config contents (or default if missing)."""
config: Dict[str, Any]
try:

View File

@ -86,7 +86,7 @@ def cpplint(projroot: Path, full: bool) -> None:
import tempfile
from concurrent.futures import ThreadPoolExecutor
from multiprocessing import cpu_count
from efrotools import get_config
from efrotools import getconfig
from efro.terminal import Clr
from efro.error import CleanError
@ -97,7 +97,7 @@ def cpplint(projroot: Path, full: bool) -> None:
raise Exception(f'Found space in path {fpath}; unexpected.')
# Check the config for a list of ones to ignore.
code_blacklist: List[str] = get_config(projroot).get(
code_blacklist: List[str] = getconfig(projroot).get(
'cpplint_blacklist', [])
# Just pretend blacklisted ones don't exist.
@ -170,9 +170,9 @@ def cpplint(projroot: Path, full: bool) -> None:
def get_code_filenames(projroot: Path) -> List[str]:
"""Return the list of files to lint-check or auto-formatting."""
from efrotools import get_config
from efrotools import getconfig
exts = ('.h', '.c', '.cc', '.cpp', '.cxx', '.m', '.mm')
places = get_config(projroot).get('code_source_dirs', None)
places = getconfig(projroot).get('code_source_dirs', None)
if places is None:
raise RuntimeError('code_source_dirs not declared in config')
codefilenames = []
@ -249,9 +249,9 @@ def _should_include_script(fnamefull: str) -> bool:
def get_script_filenames(projroot: Path) -> List[str]:
"""Return the Python filenames to lint-check or auto-format."""
from efrotools import get_config
from efrotools import getconfig
filenames = set()
places = get_config(projroot).get('python_source_dirs', None)
places = getconfig(projroot).get('python_source_dirs', None)
if places is None:
raise RuntimeError('python_source_dirs not declared in config')
for place in places:
@ -436,7 +436,7 @@ def _apply_pylint_run_to_cache(projroot: Path, run: Any, dirtyfiles: List[str],
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
from astroid import modutils
from efrotools import get_config
from efrotools import getconfig
from efro.error import CleanError
# First off, build a map of dirtyfiles to module names
@ -484,7 +484,7 @@ def _apply_pylint_run_to_cache(projroot: Path, run: Any, dirtyfiles: List[str],
else:
untracked_deps.add(mname)
ignored_untracked_deps: List[str] = get_config(projroot).get(
ignored_untracked_deps: List[str] = getconfig(projroot).get(
'pylint_ignored_untracked_deps', [])
# Add a few that this package itself triggers.

View File

@ -27,7 +27,7 @@ import subprocess
import sys
from dataclasses import dataclass
from efrotools import get_localconfig, get_config
from efrotools import getlocalconfig, getconfig
MODES = {
'debug': {
@ -78,8 +78,8 @@ def push_ipa(root: pathlib.Path, modename: str) -> None:
"""
# Load both the local and project config data.
cfg = Config(**get_config(root)['push_ipa_config'])
lcfg = LocalConfig(**get_localconfig(root)['push_ipa_local_config'])
cfg = Config(**getconfig(root)['push_ipa_config'])
lcfg = LocalConfig(**getlocalconfig(root)['push_ipa_local_config'])
if modename not in MODES:
raise Exception('invalid mode: "' + str(modename) + '"')

View File

@ -353,7 +353,7 @@ def tool_config_install() -> None:
def _filter_tool_config(cfg: str) -> str:
import textwrap
from efrotools import get_config
from efrotools import getconfig
# Stick project-root wherever they want.
cfg = cfg.replace('__EFRO_PROJECT_ROOT__', str(PROJROOT))
@ -391,7 +391,7 @@ def _filter_tool_config(cfg: str) -> str:
# Gen a pylint init to set up our python paths:
pylint_init_tag = '__EFRO_PYLINT_INIT__'
if pylint_init_tag in cfg:
pypaths = get_config(PROJROOT).get('python_paths')
pypaths = getconfig(PROJROOT).get('python_paths')
if pypaths is None:
raise RuntimeError('python_paths not set in project config')
cstr = "init-hook='import sys;"
@ -460,13 +460,13 @@ def sync_all() -> None:
def sync() -> None:
"""Runs standard syncs between this project and others."""
from efrotools import get_config
from efrotools import getconfig
from efrotools.sync import Mode, SyncItem, run_standard_syncs
mode = Mode(sys.argv[2]) if len(sys.argv) > 2 else Mode.PULL
# Load sync-items from project config and run them
sync_items = [
SyncItem(**i) for i in get_config(PROJROOT).get('sync_items', [])
SyncItem(**i) for i in getconfig(PROJROOT).get('sync_items', [])
]
run_standard_syncs(PROJROOT, mode, sync_items)
@ -498,11 +498,11 @@ def pytest() -> None:
import os
import platform
import subprocess
from efrotools import get_config, PYTHON_BIN
from efrotools import getconfig, PYTHON_BIN
from efro.error import CleanError
# Grab our python paths for the project and stuff them in PYTHONPATH.
pypaths = get_config(PROJROOT).get('python_paths')
pypaths = getconfig(PROJROOT).get('python_paths')
if pypaths is None:
raise CleanError('python_paths not found in project config.')

View File

@ -76,8 +76,8 @@ def run_standard_syncs(projectroot: Path, mode: Mode,
Syncitems should be a list of tuples consisting of a src project name,
a src subpath, and optionally a dst subpath (src will be used by default).
"""
from efrotools import get_localconfig
localconfig = get_localconfig(projectroot)
from efrotools import getlocalconfig
localconfig = getlocalconfig(projectroot)
for syncitem in syncitems:
assert isinstance(syncitem, SyncItem)
src_project = syncitem.src_project_id

View File

@ -41,14 +41,36 @@ from efrotools.snippets import (
PROJROOT, snippets_main, formatcode, formatscripts, formatmakefile,
cpplint, pylint, runpylint, mypy, runmypy, dmypy, tool_config_install,
sync, sync_all, scriptfiles, pycharm, clioncode, androidstudiocode,
makefile_target_list, spelling, spelling_all, compile_python_files, pytest,
echo)
makefile_target_list, spelling, spelling_all, pytest, echo)
from efrotools.snippets import compile_python_files as _orig_compile_py_files
# pylint: enable=unused-import
if TYPE_CHECKING:
from typing import Optional
def compile_python_files() -> None:
"""Override for compiling python files."""
from pathlib import Path
import subprocess
import os
from efrotools import getlocalconfig
# Run the standard command
_orig_compile_py_files()
# Optionally also blow away blessing status to keep it clear that
# things need to be re-blessed.
blesspath = Path(PROJROOT, 'tools/bless')
if os.path.exists(blesspath) and getlocalconfig(PROJROOT).get(
'auto_clear_blessing', False):
subprocess.run([blesspath, 'clear'], check=True, cwd=PROJROOT)
# Copy the original func's doc-string
compile_python_files.__doc__ = _orig_compile_py_files.__doc__
def archive_old_builds() -> None:
"""Stuff our old public builds into the 'old' dir.
@ -156,7 +178,7 @@ def get_master_asset_src_dir() -> None:
if ('origin/master' in output.splitlines()[0]
and 'ballistica' + 'core' == 'ballisticacore'):
# We seem to be in master in core repo.. lets do it.
# We seem to be in master in core repo; lets do it.
print('/Users/ericf/Dropbox/ballisticacore_master_assets')
else:
# Still need to supply dummy path for makefile if not..
@ -399,8 +421,8 @@ def warm_start_asset_build() -> None:
import os
import subprocess
from pathlib import Path
from efrotools import get_config
public: bool = get_config(PROJROOT)['public']
from efrotools import getconfig
public: bool = getconfig(PROJROOT)['public']
if public:
from efrotools.efrocache import warm_start_cache

View File

@ -180,9 +180,15 @@ def _get_py_targets_subset(all_targets: Set[str], subset: str,
' instead, but perhaps listing these explicitly isn\'t so bad.\n')
for i, target in enumerate(pyc_targets):
# Note: there's currently a bug which can cause python bytecode
# generation to be non-deterministic. This can break our blessing
# process since we bless in core but then regenerate bytecode in
# spinoffs. See https://bugs.python.org/issue34722
# For now setting PYTHONHASHSEED=1 is a workaround.
out += ('\n' + target + ': \\\n ' + py_targets[i] +
'\n\t@echo Compiling script: $^\n'
'\t@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^'
'\t@rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets'
' compile_python_files $^'
' && chmod 444 $@\n')
return out
@ -248,7 +254,7 @@ def _get_extras_targets_win(all_targets: Set[str], platform: str) -> str:
def main() -> None:
"""Main script entry point."""
# pylint: disable=too-many-locals
from efrotools import get_config
from efrotools import getconfig
from pathlib import Path
# In 'check' mode we simply error on differences.
@ -257,7 +263,7 @@ def main() -> None:
# Always operate out of dist root dir.
os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '..'))
public = get_config(Path('.'))['public']
public = getconfig(Path('.'))['public']
assert isinstance(public, bool)
fname = 'assets/Makefile'

View File

@ -67,14 +67,14 @@ class App:
"""Context for an app run."""
def __init__(self) -> None:
from efrotools import get_config, get_localconfig
from efrotools import getconfig, getlocalconfig
from pathlib import Path
self._check = ('--check' in sys.argv)
self._fix = ('--fix' in sys.argv)
self._checkarg = ' --check' if self._check else ''
# We behave differently in the public repo
self._public = get_config(Path('.'))['public']
self._public = getconfig(Path('.'))['public']
assert isinstance(self._public, bool)
self._source_files: List[str] = []
@ -84,7 +84,7 @@ class App:
self._file_changes: Dict[str, str] = {}
self._copyright_checks = bool(
get_localconfig(Path('.')).get('copyright_checks', True))
getlocalconfig(Path('.')).get('copyright_checks', True))
def run(self) -> None:
"""Do the thing."""