latest cloudtool work

This commit is contained in:
Eric Froemling 2019-12-04 08:43:23 -08:00
parent e01573f418
commit ec5225856d
64 changed files with 372 additions and 218 deletions

View File

@ -11,6 +11,7 @@
<w>aaah</w>
<w>aaai</w>
<w>aarch</w>
<w>abcdefghijklmnopqrstuvwxyz</w>
<w>abeb</w>
<w>abot</w>
<w>abtn</w>
@ -78,7 +79,13 @@
<w>argval</w>
<w>armeabi</w>
<w>arraymodule</w>
<w>assetbundle</w>
<w>assetcache</w>
<w>assetdata</w>
<w>assetpackage</w>
<w>assetpath</w>
<w>assettype</w>
<w>assettypestr</w>
<w>astcenc</w>
<w>astroid</w>
<w>asus</w>
@ -741,6 +748,7 @@
<w>incrementbuild</w>
<w>indentfilter</w>
<w>indentstr</w>
<w>indexfilename</w>
<w>indicies</w>
<w>indstr</w>
<w>inet</w>
@ -1233,6 +1241,7 @@
<w>pushdocs</w>
<w>pushish</w>
<w>pushlist</w>
<w>putasset</w>
<w>pval</w>
<w>pvars</w>
<w>pvrtc</w>

View File

@ -88,7 +88,7 @@
</list>
</option>
</inspection_tool>
<inspection_tool class="PyUnusedLocalInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<inspection_tool class="PyUnusedLocalInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false">
<scope name="UncheckedPython" level="WEAK WARNING" enabled="false">
<option name="ignoreTupleUnpacking" value="true" />
<option name="ignoreLambdaParameters" value="true" />
@ -101,4 +101,4 @@
<option name="ignoreVariablesStartingWithUnderscore" value="true" />
</inspection_tool>
</profile>
</component>
</component>

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=221041082183416610193123748095056578345
# SOURCES_HASH=161757749075580767394847135785091690137
# I'm sorry Pylint. I know this file saddens you. Be strong.
# pylint: disable=useless-suppression
@ -388,7 +388,8 @@ class Material:
label: str
def add_actions(self, actions: Tuple,
def add_actions(self,
actions: Tuple,
conditions: Optional[Tuple] = None) -> None:
"""add_actions(actions: Tuple, conditions: Optional[Tuple] = None)
-> None
@ -939,7 +940,9 @@ class Player:
"""
return None
def set_name(self, name: str, full_name: str = None,
def set_name(self,
name: str,
full_name: str = None,
real: bool = True) -> None:
"""set_name(name: str, full_name: str = None, real: bool = True)
-> None
@ -2050,7 +2053,8 @@ def get_idle_time() -> int:
return int()
def get_input_device(name: str, unique_id: str,
def get_input_device(name: str,
unique_id: str,
doraise: bool = True) -> ba.InputDevice:
"""get_input_device(name: str, unique_id: str, doraise: bool = True)
-> ba.InputDevice
@ -3330,9 +3334,9 @@ def set_have_mods(have_mods: bool) -> None:
return None
def set_internal_language_keys(listobj: List[Tuple[str, str]],
random_names_list: List[Tuple[str, str]]
) -> None:
def set_internal_language_keys(
listobj: List[Tuple[str, str]],
random_names_list: List[Tuple[str, str]]) -> None:
"""set_internal_language_keys(listobj: List[Tuple[str, str]],
random_names_list: List[Tuple[str, str]]) -> None
@ -3349,8 +3353,8 @@ def set_low_level_config_value(key: str, value: int) -> None:
return None
def set_map_bounds(bounds: Tuple[float, float, float, float, float, float]
) -> None:
def set_map_bounds(
bounds: Tuple[float, float, float, float, float, float]) -> None:
"""set_map_bounds(bounds: Tuple[float, float, float, float, float, float])
-> None
@ -3729,8 +3733,8 @@ def time(timetype: ba.TimeType = TimeType.SIM,
return 0.0
def time_format_check(time_format: ba.TimeFormat,
length: Union[float, int]) -> None:
def time_format_check(time_format: ba.TimeFormat, length: Union[float,
int]) -> None:
"""time_format_check(time_format: ba.TimeFormat, length: Union[float, int])
-> None
@ -3839,7 +3843,8 @@ def unlock_all_input() -> None:
return None
def value_test(arg: str, change: float = None,
def value_test(arg: str,
change: float = None,
absolute: float = None) -> float:
"""value_test(arg: str, change: float = None, absolute: float = None)
-> float

View File

@ -516,7 +516,9 @@ class Activity(DependencyComponent):
def handlemessage(self, msg: Any) -> Any:
"""General message handling; can be passed any message object."""
def end(self, results: Any = None, delay: float = 0.0,
def end(self,
results: Any = None,
delay: float = 0.0,
force: bool = False) -> None:
"""Commences Activity shutdown and delivers results to the ba.Session.

View File

@ -377,8 +377,8 @@ class App:
self.main_menu_selection: Optional[str] = None # FIXME: Kill this.
self.have_party_queue_window = False
self.quit_window: Any = None
self.dismiss_wii_remotes_window_call: (
Optional[Callable[[], Any]]) = None
self.dismiss_wii_remotes_window_call: (Optional[Callable[[],
Any]]) = None
self.value_test_defaults: dict = {}
self.main_menu_window_refresh_check_count = 0
self.first_main_menu = True # FIXME: Move to mainmenu class.

View File

@ -32,9 +32,9 @@ class AppDelegate:
"""Defines handlers for high level app functionality."""
def create_default_game_config_ui(
self, gameclass: Type[ba.GameActivity],
sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]],
completion_call: Callable[[Optional[Dict[str, Any]]], None]
self, gameclass: Type[ba.GameActivity], sessionclass: Type[ba.Session],
config: Optional[Dict[str, Any]],
completion_call: Callable[[Optional[Dict[str, Any]]], None]
) -> None:
"""Launch a UI to configure the given game config.

View File

@ -202,7 +202,8 @@ class CoopGameActivity(GameActivity):
spaz.play_big_death_sound = True
return spaz
def _award_achievement(self, achievement_name: str,
def _award_achievement(self,
achievement_name: str,
sound: bool = True) -> None:
"""Award an achievement.

View File

@ -207,9 +207,8 @@ class CoopSession(Session):
else:
self.end()
def _on_tournament_restart_menu_press(self,
resume_callback: Callable[[], Any]
) -> None:
def _on_tournament_restart_menu_press(
self, resume_callback: Callable[[], Any]) -> None:
# pylint: disable=cyclic-import
from bastd.ui.tournamententry import TournamentEntryWindow
from ba._gameactivity import GameActivity

View File

@ -48,9 +48,8 @@ class GameActivity(Activity):
@classmethod
def create_config_ui(
cls, sessionclass: Type[ba.Session],
config: Optional[Dict[str, Any]],
completion_call: Callable[[Optional[Dict[str, Any]]], None]
cls, sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]],
completion_call: Callable[[Optional[Dict[str, Any]]], None]
) -> None:
"""Launch an in-game UI to configure settings for a game type.
@ -171,8 +170,8 @@ class GameActivity(Activity):
return ''
@classmethod
def get_description_display_string(cls, sessiontype: Type[ba.Session]
) -> ba.Lstr:
def get_description_display_string(
cls, sessiontype: Type[ba.Session]) -> ba.Lstr:
"""Return a translated version of get_description().
Sub-classes should override get_description(); not this.
@ -181,8 +180,9 @@ class GameActivity(Activity):
return Lstr(translate=('gameDescriptions', description))
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
"""
Called by the default ba.GameActivity.create_config_ui()
implementation; should return a dict of config options to be presented
@ -643,8 +643,8 @@ class GameActivity(Activity):
callback=WeakCall(
self._on_tournament_query_response))
def _on_tournament_query_response(self,
data: Optional[Dict[str, Any]]) -> None:
def _on_tournament_query_response(self, data: Optional[Dict[str,
Any]]) -> None:
from ba._account import cache_tournament_info
if data is not None:
data_t = data['t'] # This used to be the whole payload.
@ -935,7 +935,9 @@ class GameActivity(Activity):
animate(combine, 'input3', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0})
_ba.timer(5.0, tnode.delete)
def end(self, results: Any = None, delay: float = 0.0,
def end(self,
results: Any = None,
delay: float = 0.0,
force: bool = False) -> None:
from ba._gameresults import TeamGameResults

View File

@ -187,8 +187,8 @@ class TeamGameResults:
team = score[0]()
assert team is not None
sval.append(team)
results: List[Tuple[Optional[int], List[ba.Team]]] = list(
winners.items())
results: List[Tuple[Optional[int],
List[ba.Team]]] = list(winners.items())
results.sort(reverse=not self._lower_is_better)
# Also group the 'None' scores.
@ -200,8 +200,8 @@ class TeamGameResults:
# Add the Nones to the list (either as winners or losers
# depending on the rules).
if none_teams:
nones: List[Tuple[Optional[int], List[ba.Team]]] = [(None,
none_teams)]
nones: List[Tuple[Optional[int],
List[ba.Team]]] = [(None, none_teams)]
if self._none_is_winner:
results = nones + results
else:

View File

@ -171,11 +171,11 @@ class Level:
if campaign is None:
raise Exception("level is not in a campaign")
campaign_config = campaign.get_config_dict()
val: Dict[str, Any] = campaign_config.setdefault(
self._name, {
'Rating': 0.0,
'Complete': False
})
val: Dict[str,
Any] = campaign_config.setdefault(self._name, {
'Rating': 0.0,
'Complete': False
})
assert isinstance(val, dict)
return val

View File

@ -47,10 +47,10 @@ class JoinInfo:
from ba._enums import SpecialChar
can_switch_teams = (len(lobby.teams) > 1)
self._state = 0
press_to_punch: Union[str, ba.Lstr] = _ba.charstr(
SpecialChar.LEFT_BUTTON)
press_to_bomb: Union[str, ba.Lstr] = _ba.charstr(
SpecialChar.RIGHT_BUTTON)
press_to_punch: Union[str,
ba.Lstr] = _ba.charstr(SpecialChar.LEFT_BUTTON)
press_to_bomb: Union[str,
ba.Lstr] = _ba.charstr(SpecialChar.RIGHT_BUTTON)
# If we have a keyboard, grab keys for punch and pickup.
# FIXME: This of course is only correct on the local device;

View File

@ -293,7 +293,8 @@ class Map(Actor):
# FIXME: this should be part of game; not map.
self._next_ffa_start_index = 0
def is_point_near_edge(self, point: ba.Vec3,
def is_point_near_edge(self,
point: ba.Vec3,
running: bool = False) -> bool:
"""Return whether the provided point is near an edge of the map.
@ -306,7 +307,7 @@ class Map(Actor):
return False
def get_def_bound_box(
self, name: str
self, name: str
) -> Optional[Tuple[float, float, float, float, float, float]]:
"""Return a 6 member bounds tuple or None if it is not defined."""
try:
@ -352,8 +353,8 @@ class Map(Actor):
pnt[2] + random.uniform(*z_range))
return pnt
def get_ffa_start_position(self, players: Sequence[ba.Player]
) -> Sequence[float]:
def get_ffa_start_position(
self, players: Sequence[ba.Player]) -> Sequence[float]:
"""Return a random starting position in one of the FFA spawn areas.
If a list of ba.Players is provided; the returned points will be

View File

@ -337,8 +337,8 @@ class ITunesThread(threading.Thread):
self._commands.append(['GET_PLAYLISTS', callback])
self._commands_available.set()
def _handle_get_playlists_command(self, target: Callable[[List[str]], None]
) -> None:
def _handle_get_playlists_command(
self, target: Callable[[List[str]], None]) -> None:
from ba._general import Call
try:
playlists = _ba.itunes_get_playlists()

View File

@ -158,19 +158,19 @@ class ServerCallThread(threading.Thread):
from_other_thread=True)
def serverget(request: str,
data: Dict[str, Any],
callback: Optional[ServerCallbackType] = None,
response_type: ServerResponseType = ServerResponseType.JSON
) -> None:
def serverget(
request: str,
data: Dict[str, Any],
callback: Optional[ServerCallbackType] = None,
response_type: ServerResponseType = ServerResponseType.JSON) -> None:
"""Make a call to the master server via a http GET."""
ServerCallThread(request, 'get', data, callback, response_type).start()
def serverput(request: str,
data: Dict[str, Any],
callback: Optional[ServerCallbackType] = None,
response_type: ServerResponseType = ServerResponseType.JSON
) -> None:
def serverput(
request: str,
data: Dict[str, Any],
callback: Optional[ServerCallbackType] = None,
response_type: ServerResponseType = ServerResponseType.JSON) -> None:
"""Make a call to the master server via a http POST."""
ServerCallThread(request, 'post', data, callback, response_type).start()

View File

@ -67,7 +67,8 @@ def get_player_profile_icon(profilename: str) -> str:
def get_player_profile_colors(
profilename: Optional[str], profiles: Dict[str, Dict[str, Any]] = None
profilename: Optional[str],
profiles: Dict[str, Dict[str, Any]] = None
) -> Tuple[Tuple[float, float, float], Tuple[float, float, float]]:
"""Given a profile, return colors for them."""
bs_config = _ba.app.config

View File

@ -43,7 +43,8 @@ class EntityMixin:
class are accessible on the new type.
"""
def __init__(self, d_data: Dict[str, Any] = None,
def __init__(self,
d_data: Dict[str, Any] = None,
error: bool = False) -> None:
super().__init__()
if not isinstance(self, CompoundValue):
@ -69,8 +70,8 @@ class EntityMixin:
assert isinstance(self, CompoundValue)
self.apply_fields_to_data(self.d_data, error=error)
def copy_data(self,
target: Union[CompoundValue, BoundCompoundValue]) -> None:
def copy_data(self, target: Union[CompoundValue,
BoundCompoundValue]) -> None:
"""Copy data from a target Entity or compound-value.
This first verifies that the target has a matching set of fields

View File

@ -83,7 +83,9 @@ class Field(BaseField, Generic[T]):
class CompoundField(BaseField, Generic[TC]):
"""Field consisting of a single compound value."""
def __init__(self, d_key: str, value: TC,
def __init__(self,
d_key: str,
value: TC,
store_default: bool = False) -> None:
super().__init__(d_key)
if __debug__ is True:
@ -283,7 +285,9 @@ class CompoundListField(BaseField, Generic[TC]):
ie: mylist[10].fieldattr = 'foo'
"""
def __init__(self, d_key: str, valuetype: TC,
def __init__(self,
d_key: str,
valuetype: TC,
store_default: bool = False) -> None:
super().__init__(d_key)
self.d_value = valuetype
@ -421,7 +425,8 @@ class CompoundDictField(BaseField, Generic[TK, TC]):
...
@overload
def __get__(self, obj: Any,
def __get__(self,
obj: Any,
cls: Any = None) -> BoundCompoundDictField[TK, TC]:
...

View File

@ -45,8 +45,8 @@ class BoundCompoundValue:
Allows access to its values through our own equivalent attributes.
"""
def __init__(self, value: CompoundValue,
d_data: Union[List[Any], Dict[str, Any]]):
def __init__(self, value: CompoundValue, d_data: Union[List[Any],
Dict[str, Any]]):
self.d_value: CompoundValue
self.d_data: Union[List[Any], Dict[str, Any]]
# need to use base setters to avoid triggering our own overrides
@ -374,8 +374,8 @@ class BoundCompoundListField(Generic[TC]):
class BoundCompoundDictField(Generic[TK, TC]):
"""A CompoundDictField bound to its entity sub-data."""
def __init__(self, field: CompoundDictField[TK, TC],
d_data: Dict[Any, Any]):
def __init__(self, field: CompoundDictField[TK, TC], d_data: Dict[Any,
Any]):
self.d_field = field
self.d_data = d_data

View File

@ -146,7 +146,8 @@ class OptionalStringValue(SimpleValue[Optional[str]]):
class BoolValue(SimpleValue[bool]):
"""Value consisting of a single bool."""
def __init__(self, default: bool = False,
def __init__(self,
default: bool = False,
store_default: bool = False) -> None:
super().__init__(default, store_default, bool, (int, float))
@ -246,7 +247,8 @@ class IntValue(SimpleValue[int]):
class OptionalIntValue(SimpleValue[Optional[int]]):
"""Value consisting of a single int or None"""
def __init__(self, default: int = None,
def __init__(self,
default: int = None,
store_default: bool = False) -> None:
super().__init__(default,
store_default,
@ -257,7 +259,8 @@ class OptionalIntValue(SimpleValue[Optional[int]]):
class FloatValue(SimpleValue[float]):
"""Value consisting of a single float."""
def __init__(self, default: float = 0.0,
def __init__(self,
default: float = 0.0,
store_default: bool = False) -> None:
super().__init__(default, store_default, float, (bool, int))
@ -265,7 +268,8 @@ class FloatValue(SimpleValue[float]):
class OptionalFloatValue(SimpleValue[Optional[float]]):
"""Value consisting of a single float or None."""
def __init__(self, default: float = None,
def __init__(self,
default: float = None,
store_default: bool = False) -> None:
super().__init__(default,
store_default,

View File

@ -30,9 +30,9 @@ if TYPE_CHECKING:
from bafoundation.entity._support import BoundCompoundValue
def diff_compound_values(obj1: Union[BoundCompoundValue, CompoundValue],
obj2: Union[BoundCompoundValue, CompoundValue]
) -> str:
def diff_compound_values(
obj1: Union[BoundCompoundValue, CompoundValue],
obj2: Union[BoundCompoundValue, CompoundValue]) -> str:
"""Generate a string showing differences between two compound values.
Both must be associated with data and have the same set of fields.
@ -108,8 +108,9 @@ def have_matching_fields(val1: CompoundValue, val2: CompoundValue) -> bool:
return val1.get_fields() == val2.get_fields()
def get_compound_value_and_data(obj: Union[BoundCompoundValue, CompoundValue]
) -> Tuple[CompoundValue, Any]:
def get_compound_value_and_data(
obj: Union[BoundCompoundValue, CompoundValue]
) -> Tuple[CompoundValue, Any]:
"""Return value and data for bound or unbound compound values."""
# pylint: disable=cyclic-import
from bafoundation.entity._support import BoundCompoundValue

View File

@ -145,8 +145,8 @@ if TYPE_CHECKING:
class _Call5Args(Generic[In1T, In2T, In3T, In4T, In5T, OutT]):
"""Five argument variant of call wrapper"""
def __init__(self,
_call: Callable[[In1T, In2T, In3T, In4T, In5T], OutT]):
def __init__(self, _call: Callable[[In1T, In2T, In3T, In4T, In5T],
OutT]):
...
def __call__(self, _arg1: In1T, _arg2: In2T, _arg3: In3T, _arg4: In4T,
@ -156,9 +156,9 @@ if TYPE_CHECKING:
class _Call6Args(Generic[In1T, In2T, In3T, In4T, In5T, In6T, OutT]):
"""Six argument variant of call wrapper"""
def __init__(
self,
_call: Callable[[In1T, In2T, In3T, In4T, In5T, In6T], OutT]):
def __init__(self,
_call: Callable[[In1T, In2T, In3T, In4T, In5T, In6T],
OutT]):
...
def __call__(self, _arg1: In1T, _arg2: In2T, _arg3: In3T, _arg4: In4T,
@ -169,9 +169,8 @@ if TYPE_CHECKING:
"""Seven argument variant of call wrapper"""
def __init__(
self,
_call: Callable[[In1T, In2T, In3T, In4T, In5T, In6T, In7T],
OutT]):
self, _call: Callable[[In1T, In2T, In3T, In4T, In5T, In6T, In7T],
OutT]):
...
def __call__(self, _arg1: In1T, _arg2: In2T, _arg3: In3T, _arg4: In4T,
@ -240,8 +239,9 @@ if TYPE_CHECKING:
# 3 arg call; no args bundled.
# noinspection PyPep8Naming
@overload
def Call(call: Callable[[In1T, In2T, In3T], OutT]
) -> _Call3Args[In1T, In2T, In3T, OutT]:
def Call(
call: Callable[[In1T, In2T, In3T], OutT]
) -> _Call3Args[In1T, In2T, In3T, OutT]:
...
# 4 arg call; 4 args bundled.
@ -254,17 +254,17 @@ if TYPE_CHECKING:
# 5 arg call; 5 args bundled.
# noinspection PyPep8Naming
@overload
def Call(call: Callable[[In1T, In2T, In3T, In4T, In5T], OutT], arg1: In1T,
arg2: In2T, arg3: In3T, arg4: In4T,
arg5: In5T) -> _CallNoArgs[OutT]:
def Call(call: Callable[[In1T, In2T, In3T, In4T, In5T],
OutT], arg1: In1T, arg2: In2T, arg3: In3T,
arg4: In4T, arg5: In5T) -> _CallNoArgs[OutT]:
...
# 6 arg call; 6 args bundled.
# noinspection PyPep8Naming
@overload
def Call(call: Callable[[In1T, In2T, In3T, In4T, In5T, In6T], OutT],
arg1: In1T, arg2: In2T, arg3: In3T, arg4: In4T, arg5: In5T,
arg6: In6T) -> _CallNoArgs[OutT]:
def Call(call: Callable[[In1T, In2T, In3T, In4T, In5T, In6T],
OutT], arg1: In1T, arg2: In2T, arg3: In3T,
arg4: In4T, arg5: In5T, arg6: In6T) -> _CallNoArgs[OutT]:
...
# 7 arg call; 7 args bundled.

View File

@ -60,8 +60,9 @@ class DispatchMethodWrapper(Generic[TARG, TRET]):
# noinspection PyTypeHints, PyProtectedMember
def dispatchmethod(func: Callable[[Any, TARG], TRET]
) -> DispatchMethodWrapper[TARG, TRET]:
def dispatchmethod(
func: Callable[[Any, TARG], TRET]
) -> DispatchMethodWrapper[TARG, TRET]:
"""A variation of functools.singledispatch for methods."""
from functools import singledispatch, update_wrapper
origwrapper: Any = singledispatch(func)
@ -224,8 +225,9 @@ class ValueDispatcher(Generic[TVAL, TRET]):
return partial(self._add_handler, value)
def valuedispatch1arg(call: Callable[[TVAL, TARG], TRET]
) -> ValueDispatcher1Arg[TVAL, TARG, TRET]:
def valuedispatch1arg(
call: Callable[[TVAL, TARG], TRET]
) -> ValueDispatcher1Arg[TVAL, TARG, TRET]:
"""Like valuedispatch but for functions taking an extra argument."""
return ValueDispatcher1Arg(call)

View File

@ -98,10 +98,12 @@ class CoopJoiningActivity(JoiningActivity):
spacing = 25
delay_inc = 0.1
def _add_t(text: Union[str, ba.Lstr],
h_offs: float = 0.0,
scale: float = 1.0,
color: Sequence[float] = (1.0, 1.0, 1.0, 0.46)) -> None:
def _add_t(
text: Union[str, ba.Lstr],
h_offs: float = 0.0,
scale: float = 1.0,
color: Sequence[float] = (1.0, 1.0, 1.0, 0.46)
) -> None:
Text(text,
scale=scale * 0.76,
h_align='left',

View File

@ -118,8 +118,8 @@ class TeamsScoreScreenActivity(ScoreScreenActivity):
assert self.stats
valid_players = list(self.stats.get_records().items())
def _get_player_score_set_entry(player: ba.Player
) -> Optional[PlayerRecord]:
def _get_player_score_set_entry(
player: ba.Player) -> Optional[PlayerRecord]:
for p_rec in valid_players:
# PyCharm incorrectly thinks valid_players is a List[str]
# noinspection PyUnresolvedReferences

View File

@ -99,8 +99,10 @@ class OnScreenTimer(ba.Actor):
self.inputnode.timemax = endtime_ms - self._starttime
def getstarttime(self, timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS
) -> Union[int, float]:
def getstarttime(
self,
timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS
) -> Union[int, float]:
"""Return the sim-time when start() was called.
Time will be returned in seconds if timeformat is SECONDS or

View File

@ -243,8 +243,8 @@ class Spaz(ba.Actor):
self._bomb_held = False
if self.default_shields:
self.equip_shields()
self._dropped_bomb_callbacks: List[
Callable[[Spaz, ba.Actor], Any]] = []
self._dropped_bomb_callbacks: List[Callable[[Spaz, ba.Actor],
Any]] = []
self._score_text: Optional[ba.Node] = None
self._score_text_hide_timer: Optional[ba.Timer] = None
@ -262,8 +262,8 @@ class Spaz(ba.Actor):
self.punch_callback = None
self.pick_up_powerup_callback = None
def add_dropped_bomb_callback(self, call: Callable[[Spaz, ba.Actor], Any]
) -> None:
def add_dropped_bomb_callback(
self, call: Callable[[Spaz, ba.Actor], Any]) -> None:
"""
Add a call to be run whenever this Spaz drops a bomb.
The spaz and the newly-dropped bomb are passed as arguments.

View File

@ -179,8 +179,8 @@ class SpazBot(basespaz.Spaz):
assert mval is not None
return mval
def _get_target_player_pt(self
) -> Tuple[Optional[ba.Vec3], Optional[ba.Vec3]]:
def _get_target_player_pt(
self) -> Tuple[Optional[ba.Vec3], Optional[ba.Vec3]]:
"""Returns the position and velocity of our target.
Both values will be None in the case of no target.

View File

@ -33,9 +33,9 @@ class AppDelegate(ba.AppDelegate):
"""Defines handlers for high level app functionality."""
def create_default_game_config_ui(
self, gameclass: Type[ba.GameActivity],
sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]],
completion_call: Callable[[Optional[Dict[str, Any]]], Any]
self, gameclass: Type[ba.GameActivity], sessionclass: Type[ba.Session],
config: Optional[Dict[str, Any]],
completion_call: Callable[[Optional[Dict[str, Any]]], Any]
) -> None:
"""(internal)"""

View File

@ -56,8 +56,9 @@ class AssaultGame(ba.TeamGameActivity):
return ba.getmaps('team_flag')
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
return [('Score to Win', {'min_value': 1, 'default': 3}),
('Time Limit', {
'choices': [('None', 0), ('1 Minute', 60),

View File

@ -89,8 +89,9 @@ class CaptureTheFlagGame(ba.TeamGameActivity):
return ba.getmaps('team_flag')
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
return [
('Score to Win', {'min_value': 1, 'default': 3}),
('Flag Touch Return Time', {

View File

@ -62,8 +62,9 @@ class ChosenOneGame(ba.TeamGameActivity):
return ba.getmaps('keep_away')
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
return [("Chosen One Time", {
'min_value': 10,
'default': 30,

View File

@ -77,8 +77,9 @@ class ConquestGame(ba.TeamGameActivity):
return ba.getmaps("conquest")
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
return [
("Time Limit", {
'choices': [('None', 0), ('1 Minute', 60),

View File

@ -56,8 +56,9 @@ class DeathMatchGame(ba.TeamGameActivity):
return ba.getmaps("melee")
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
settings: List[Tuple[str, Dict[str, Any]]] = [
("Kills to Win Per Player", {
'min_value': 1,

View File

@ -67,8 +67,9 @@ class EasterEggHuntGame(ba.TeamGameActivity):
or issubclass(sessiontype, ba.FreeForAllSession))
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
return [("Pro Mode", {'default': False})]
def __init__(self, settings: Dict[str, Any]):

View File

@ -193,8 +193,9 @@ class EliminationGame(ba.TeamGameActivity):
return ba.getmaps("melee")
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
settings: List[Tuple[str, Dict[str, Any]]] = [
("Lives Per Player", {
'default': 1, 'min_value': 1,

View File

@ -87,8 +87,9 @@ class FootballTeamGame(ba.TeamGameActivity):
return ba.getmaps('football')
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
return [
("Score to Win", {
'min_value': 7,

View File

@ -126,8 +126,9 @@ class HockeyGame(ba.TeamGameActivity):
return ba.getmaps('hockey')
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
return [
("Score to Win", {
'min_value': 1, 'default': 1, 'increment': 1

View File

@ -67,8 +67,9 @@ class KeepAwayGame(ba.TeamGameActivity):
return ba.getmaps('keep_away')
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
return [
("Hold Time", {
'min_value': 10,

View File

@ -68,8 +68,9 @@ class KingOfTheHillGame(ba.TeamGameActivity):
return ba.getmaps("king_of_the_hill")
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
return [("Hold Time", {
'min_value': 10,
'default': 30,

View File

@ -63,8 +63,9 @@ class MeteorShowerGame(ba.TeamGameActivity):
return ['Rampage']
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
return [("Epic Mode", {'default': False})]
# We support teams, free-for-all, and co-op sessions.

View File

@ -87,8 +87,9 @@ class RaceGame(ba.TeamGameActivity):
return ba.getmaps("race")
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
settings: List[Tuple[str, Dict[str, Any]]] = [
("Laps", {
'min_value': 1,

View File

@ -822,9 +822,9 @@ class RunaroundGame(ba.CoopGameActivity):
elif path == 6:
this_target_point_s *= 0.7
def _add_defender(
defender_type: Tuple[Type[spazbot.SpazBot], float],
pnt: str) -> Tuple[float, Dict[str, Any]]:
def _add_defender(defender_type: Tuple[Type[spazbot.SpazBot],
float],
pnt: str) -> Tuple[float, Dict[str, Any]]:
# FIXME: should look into this warning
# pylint: disable=cell-var-from-loop
return this_target_point_s * defender_type[1], {

View File

@ -60,8 +60,9 @@ class TargetPracticeGame(ba.TeamGameActivity):
or issubclass(sessiontype, ba.TeamBaseSession))
@classmethod
def get_settings(cls, sessiontype: Type[ba.Session]
) -> List[Tuple[str, Dict[str, Any]]]:
def get_settings(
cls,
sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]:
return [("Target Count", {
'min_value': 1,
'default': 3

View File

@ -171,7 +171,8 @@ class FootballStadium(ba.Map):
gnode.vr_camera_offset = (0, -0.8, -1.1)
gnode.vr_near_clip = 0.5
def is_point_near_edge(self, point: ba.Vec3,
def is_point_near_edge(self,
point: ba.Vec3,
running: bool = False) -> bool:
box_position = self.defs.boxes['edge_box'][0:3]
box_scale = self.defs.boxes['edge_box'][6:9]
@ -814,7 +815,8 @@ class DoomShroom(ba.Map):
gnode.vignette_outer = (0.76, 0.76, 0.76)
gnode.vignette_inner = (0.95, 0.95, 0.99)
def is_point_near_edge(self, point: ba.Vec3,
def is_point_near_edge(self,
point: ba.Vec3,
running: bool = False) -> bool:
xpos = point.x
zpos = point.z
@ -1162,7 +1164,8 @@ class TowerD(ba.Map):
gnode.vignette_outer = (0.7, 0.73, 0.7)
gnode.vignette_inner = (0.95, 0.95, 0.95)
def is_point_near_edge(self, point: ba.Vec3,
def is_point_near_edge(self,
point: ba.Vec3,
running: bool = False) -> bool:
# see if we're within edge_box
boxes = self.defs.boxes
@ -1453,7 +1456,8 @@ class Courtyard(ba.Map):
gnode.vignette_outer = (0.6, 0.6, 0.64)
gnode.vignette_inner = (0.95, 0.95, 0.93)
def is_point_near_edge(self, point: ba.Vec3,
def is_point_near_edge(self,
point: ba.Vec3,
running: bool = False) -> bool:
# count anything off our ground level as safe (for our platforms)
# see if we're within edge_box
@ -1549,7 +1553,8 @@ class Rampage(ba.Map):
gnode.vignette_outer = (0.62, 0.64, 0.69)
gnode.vignette_inner = (0.97, 0.95, 0.93)
def is_point_near_edge(self, point: ba.Vec3,
def is_point_near_edge(self,
point: ba.Vec3,
running: bool = False) -> bool:
box_position = self.defs.boxes['edge_box'][0:3]
box_scale = self.defs.boxes['edge_box'][6:9]

View File

@ -1057,7 +1057,8 @@ class AccountSettingsWindow(ba.OldWindow):
ba.buttonwidget(edit=self._sign_out_button,
label=ba.Lstr(resource=self._r + '.signingOutText'))
def _sign_in_press(self, account_type: str,
def _sign_in_press(self,
account_type: str,
show_test_warning: bool = True) -> None:
del show_test_warning # unused
_ba.sign_in(account_type)

View File

@ -36,8 +36,8 @@ class ContinuesWindow(ba.OldWindow):
"""A window to continue a game."""
def __init__(self, activity: ba.Activity, cost: int,
continue_call: Callable[[], Any],
cancel_call: Callable[[], Any]):
continue_call: Callable[[], Any], cancel_call: Callable[[],
Any]):
self._activity = weakref.ref(activity)
self._cost = cost
self._continue_call = continue_call

View File

@ -569,8 +569,8 @@ class CoopBrowserWindow(ba.OldWindow):
('' + str(free_tries_remaining))),
color=(0.6, 0.6, 0.6, 1))
def _on_tournament_query_response(self,
data: Optional[Dict[str, Any]]) -> None:
def _on_tournament_query_response(self, data: Optional[Dict[str,
Any]]) -> None:
from ba.internal import cache_tournament_info
app = ba.app
if data is not None:

View File

@ -1351,8 +1351,8 @@ class GatherWindow(ba.OldWindow):
ba.textwidget(edit=self._internet_host_max_party_size_value,
text=str(val))
def _on_public_party_query_result(self, result: Optional[Dict[str, Any]]
) -> None:
def _on_public_party_query_result(
self, result: Optional[Dict[str, Any]]) -> None:
with ba.Context('ui'):
# any time we get any result at all, kill our loading status
status_text = self._internet_join_status_text
@ -1806,9 +1806,8 @@ class GatherWindow(ba.OldWindow):
fallback_resource='gatherWindow.stopAdvertisingText'),
on_activate_call=self._on_stop_internet_advertising_press)
def _on_public_party_accessible_response(self,
data: Optional[Dict[str, Any]]
) -> None:
def _on_public_party_accessible_response(
self, data: Optional[Dict[str, Any]]) -> None:
# If we've got status text widgets, update them.
text = self._internet_host_status_text
if text:

View File

@ -230,8 +230,8 @@ class LeagueRankButton:
ba.print_exception('error doing smooth update')
self._smooth_update_timer = None
def _update_for_league_rank_data(self,
data: Optional[Dict[str, Any]]) -> None:
def _update_for_league_rank_data(self, data: Optional[Dict[str,
Any]]) -> None:
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
from ba.internal import get_league_rank_points
@ -340,8 +340,8 @@ class LeagueRankButton:
ba.textwidget(edit=self._title_text, text=txt, color=t_color)
ba.textwidget(edit=self._value_text, text=status_text)
def _on_power_ranking_query_response(self, data: Optional[Dict[str, Any]]
) -> None:
def _on_power_ranking_query_response(
self, data: Optional[Dict[str, Any]]) -> None:
from ba.internal import cache_league_rank_data
self._doing_power_ranking_query = False
cache_league_rank_data(data)

View File

@ -210,8 +210,8 @@ class LeagueRankWindow(ba.OldWindow):
else:
ba.playsound(ba.getsound('error'))
def _on_power_ranking_query_response(self, data: Optional[Dict[str, Any]]
) -> None:
def _on_power_ranking_query_response(
self, data: Optional[Dict[str, Any]]) -> None:
from ba.internal import cache_league_rank_data
self._doing_power_ranking_query = False
# important: *only* cache this if we requested the current season..
@ -607,8 +607,8 @@ class LeagueRankWindow(ba.OldWindow):
'/highscores?list=powerRankings&v=2' + league_str +
season_str + '&player=' + our_login_id)
def _update_for_league_rank_data(self,
data: Optional[Dict[str, Any]]) -> None:
def _update_for_league_rank_data(self, data: Optional[Dict[str,
Any]]) -> None:
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals

View File

@ -400,8 +400,9 @@ class MainMenuWindow(ba.OldWindow):
size=(0, 0),
scale=3.0 * t_scale)
def _refresh_not_in_game(self, positions: List[Tuple[float, float, float]]
) -> Tuple[float, float, float]:
def _refresh_not_in_game(
self, positions: List[Tuple[float, float, float]]
) -> Tuple[float, float, float]:
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
# pylint: disable=too-many-statements
@ -654,8 +655,9 @@ class MainMenuWindow(ba.OldWindow):
self._tdelay += self._t_delay_inc
return h, v, scale
def _refresh_in_game(self, positions: List[Tuple[float, float, float]]
) -> Tuple[float, float, float]:
def _refresh_in_game(
self, positions: List[Tuple[float, float, float]]
) -> Tuple[float, float, float]:
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
# pylint: disable=too-many-statements

View File

@ -538,8 +538,8 @@ class EditProfileWindow(ba.OldWindow):
tint_color=self._color,
tint2_color=self._highlight)
def _make_picker(self, picker_type: str,
origin: Tuple[float, float]) -> None:
def _make_picker(self, picker_type: str, origin: Tuple[float,
float]) -> None:
from bastd.ui import colorpicker
if picker_type == 'color':
initial_color = self._color

View File

@ -769,13 +769,13 @@ class AwaitGamepadInputWindow(ba.OldWindow):
"""Window for capturing a gamepad button press."""
def __init__(
self,
gamepad: ba.InputDevice,
button: str,
callback: Callable[[str, Dict[str, Any], AwaitGamepadInputWindow],
Any],
message: ba.Lstr = None,
message2: ba.Lstr = None):
self,
gamepad: ba.InputDevice,
button: str,
callback: Callable[[str, Dict[str, Any], AwaitGamepadInputWindow],
Any],
message: ba.Lstr = None,
message2: ba.Lstr = None):
if message is None:
print('AwaitGamepadInputWindow message is None!')
message = ba.Lstr(

View File

@ -348,12 +348,12 @@ class GamepadAdvancedSettingsWindow(ba.OldWindow):
for child in self._subcontainer.get_children():
ba.widget(edit=child, show_buffer_bottom=30, show_buffer_top=30)
def _capture_button(self,
pos: Tuple[float, float],
name: ba.Lstr,
control: str,
message: Optional[ba.Lstr] = None
) -> Tuple[ba.Widget, ba.Widget]:
def _capture_button(
self,
pos: Tuple[float, float],
name: ba.Lstr,
control: str,
message: Optional[ba.Lstr] = None) -> Tuple[ba.Widget, ba.Widget]:
if message is None:
message = ba.Lstr(resource=self._parent_window.get_r() +
'.pressAnyButtonText')
@ -416,17 +416,17 @@ class GamepadAdvancedSettingsWindow(ba.OldWindow):
ba.textwidget(edit=self._textwidgets[control],
text=self._parent_window.get_control_value_name(control))
def _config_value_editor(self,
name: ba.Lstr,
control: str,
position: Tuple[float, float],
min_val: float = 0.0,
max_val: float = 100.0,
increment: float = 1.0,
change_sound: bool = True,
x_offset: float = 0.0,
displayname: ba.Lstr = None
) -> Tuple[ba.Widget, ba.Widget]:
def _config_value_editor(
self,
name: ba.Lstr,
control: str,
position: Tuple[float, float],
min_val: float = 0.0,
max_val: float = 100.0,
increment: float = 1.0,
change_sound: bool = True,
x_offset: float = 0.0,
displayname: ba.Lstr = None) -> Tuple[ba.Widget, ba.Widget]:
if displayname is None:
displayname = name

View File

@ -445,7 +445,8 @@ class StoreBrowserWindow(ba.OldWindow):
resource='getTicketsWindow.unavailableText'),
color=(1, 0, 0))
def _do_purchase_check(self, item: str,
def _do_purchase_check(self,
item: str,
is_ticket_purchase: bool = False) -> None:
from ba.internal import serverget

View File

@ -308,8 +308,8 @@ class TournamentEntryWindow(popup.PopupWindow):
self._update()
self._restore_state()
def _on_tournament_query_response(self,
data: Optional[Dict[str, Any]]) -> None:
def _on_tournament_query_response(self, data: Optional[Dict[str,
Any]]) -> None:
from ba.internal import cache_tournament_info
self._running_query = False
if data is not None:

View File

@ -124,8 +124,8 @@ class TournamentScoresWindow(popup_ui.PopupWindow):
callback=ba.WeakCall(
self._on_tournament_query_response))
def _on_tournament_query_response(self,
data: Optional[Dict[str, Any]]) -> None:
def _on_tournament_query_response(self, data: Optional[Dict[str,
Any]]) -> None:
if data is not None:
# this used to be the whole payload
data_t: List[Dict[str, Any]] = data['t']

View File

@ -123,8 +123,8 @@ def _get_default_config() -> Dict[str, Any]:
def _run_process_until_exit(process: subprocess.Popen,
input_commands: Sequence[str],
restart_minutes: int,
config: Dict[str, Any]) -> None:
restart_minutes: int, config: Dict[str,
Any]) -> None:
# So we pass our initial config.
config_dirty = True

View File

@ -25,7 +25,8 @@
"bs_mapdefs_football_stadium",
"bs_mapdefs_tower_d",
"bs_mapdefs_hockey_stadium",
"bs_mapdefs_roundabout"
"bs_mapdefs_roundabout",
"yaml"
],
"python_paths": [
"assets/src/data/scripts",

View File

@ -1,6 +1,6 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<!--DOCSHASH=51c5d02115be6a67ed7833c3ec13432e-->
<h4><em>last updated on 2019-11-21 for Ballistica version 1.5.0 build 20001</em></h4>
<!--DOCSHASH=f60857a13d4c5fd4ba30988f084e00a4-->
<h4><em>last updated on 2019-11-29 for Ballistica version 1.5.0 build 20001</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>

View File

@ -27,13 +27,15 @@ from __future__ import annotations
import sys
import os
from enum import Enum
from pathlib import Path
from typing import TYPE_CHECKING
import urllib.request
import urllib.parse
import urllib.error
from dataclasses import dataclass
from pathlib import Path
import json
import subprocess
if TYPE_CHECKING:
from typing import Optional, Dict, Any
@ -60,8 +62,12 @@ CLREND = '\033[0m' # End.
CMD_LOGIN = 'login'
CMD_LOGOUT = 'logout'
CMD_PUTASSET = 'putasset'
CMD_HELP = 'help'
ASSET_PATH_VALID_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_'
ASSET_PATH_MAX_LENGTH = 128
@dataclass
class StateData:
@ -81,6 +87,74 @@ class CleanError(Exception):
"""Exception resulting in a clean error string print and exit."""
class AssetType(Enum):
"""Types for asset files."""
TEXTURE = 'texture'
SOUND = 'sound'
class Asset:
"""Data for a single asset."""
def __init__(self, assettype: AssetType) -> None:
self.assettype = assettype
print('INITING ASSET OF TYPE', assettype)
def validate_asset_path(path: str) -> None:
"""Throw an exception on an invalid asset path."""
names = path.split('/')
for name in names:
if not name:
raise CleanError(f'Found empty component in asset path "{path}".')
for char in name:
if char not in ASSET_PATH_VALID_CHARS:
raise CleanError(
f'Found invalid char "{char}" in asset path "{path}".')
class AssetBundle:
"""Data for local or remote asset bundles."""
def __init__(self) -> None:
self.assets: Dict[str, Asset] = {}
@classmethod
def load_from_disk(cls, path: Path) -> AssetBundle:
"""Load an asset bundle from an existing one on disk."""
import yaml
indexfilename = 'assetbundle.yaml'
bundle = AssetBundle()
if not path.is_dir():
raise CleanError(f'Directory not found: "{path}"')
with open(Path(path, indexfilename)) as infile:
index = yaml.safe_load(infile)
if not isinstance(index, dict):
raise CleanError(f'Root dict not found in {indexfilename}')
assets = index.get('assets')
if not isinstance(assets, dict):
raise CleanError(f'No "assets" dict found in {indexfilename}')
for assetpath, assetdata in assets.items():
validate_asset_path(assetpath)
if len(assetpath) > ASSET_PATH_MAX_LENGTH:
raise CleanError(f'Asset path is too long: "{assetpath}"')
if not isinstance(assetdata, dict):
raise CleanError(
f'Invalid asset data for {assetpath} in {indexfilename}')
assettypestr = assetdata.get('type')
if not isinstance(assettypestr, str):
raise CleanError(
f'Invalid asset type for {assetpath} in {indexfilename}')
assettype = AssetType(assettypestr)
print('looking at', assetpath, assetdata)
bundle.assets[assetpath] = Asset(assettype)
return bundle
class App:
"""Context for a run of the tool."""
@ -95,6 +169,14 @@ class App:
raise CleanError(
'This tool must be run from ballistica project root.')
# Also run project prereqs checks so we can hopefully inform the user
# of missing python modules/etc. instead of just failing cryptically.
try:
subprocess.run(['make', '--quiet', 'prereqs'], check=True)
except subprocess.CalledProcessError:
raise CleanError('"make prereqs" check failed. '
'Install missing requirements and try again.')
self._load_cache()
if len(sys.argv) < 2:
@ -106,6 +188,8 @@ class App:
self.do_login()
elif cmd == CMD_LOGOUT:
self.do_logout()
elif cmd == CMD_PUTASSET:
self.do_putasset()
else:
# For all other commands, simply pass them to the server verbatim.
self.do_misc_command()
@ -182,6 +266,15 @@ class App:
self._state.login_token = None
print(f'{CLRGRN}Cloudtool is now logged out.{CLREND}')
def do_putasset(self) -> None:
"""Run a putasset command."""
if len(sys.argv) != 3:
raise CleanError('Expected a path to an assetpackage directory.')
path = Path(sys.argv[2])
_bundle = AssetBundle.load_from_disk(path)
def do_misc_command(self) -> None:
"""Run a miscellaneous command."""

View File

@ -504,7 +504,8 @@ def _filter_module_name(mpath: str) -> str:
return mpath[:-9] if mpath.endswith('.__init__') else mpath
def runmypy(filenames: List[str], full: bool = False,
def runmypy(filenames: List[str],
full: bool = False,
check: bool = True) -> None:
"""Run MyPy on provided filenames."""
args = [

View File

@ -293,7 +293,7 @@ def gen_fulltest_buildfile_linux() -> None:
dayoffset = datetime.datetime.now().timetuple().tm_yday
targets = ['build', 'server-build']
linflav = 'LINUX_FLAVOR=linux64-u19s'
linflav = 'LINUX_FLAVOR=u18s'
lines = []
for target in targets:
lines.append(f'{linflav} make linux-{target}')
@ -714,7 +714,7 @@ def checkenv() -> None:
for modname, minver, packagename in [
('pylint', [2, 4, 4], None),
('mypy', [0, 740], None),
('yapf', [0, 28, 0], None),
('yapf', [0, 29, 0], None),
('typing_extensions', None, None),
('pytz', None, None),
('yaml', None, 'PyYAML'),