initial work on cloudtool functionality

This commit is contained in:
Eric Froemling 2019-11-24 22:38:35 -08:00
parent 6674c526ce
commit 05a4793cd1
27 changed files with 822 additions and 685 deletions

View File

@ -5,6 +5,7 @@
<sourceFolder url="file://$MODULE_DIR$/assets/src/data/scripts" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/tools" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/generated_src/ballistica" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/.efrocache" />
<excludeFolder url="file://$MODULE_DIR$/assets/build" />
<excludeFolder url="file://$MODULE_DIR$/assets/src/data/audio" />
<excludeFolder url="file://$MODULE_DIR$/assets/src/data/data" />
@ -26,13 +27,13 @@
<excludeFolder url="file://$MODULE_DIR$/ballisticacore-xcode" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/config" />
<excludeFolder url="file://$MODULE_DIR$/docs" />
<excludeFolder url="file://$MODULE_DIR$/resources" />
<excludeFolder url="file://$MODULE_DIR$/src/ballistica" />
<excludeFolder url="file://$MODULE_DIR$/src/external" />
<excludeFolder url="file://$MODULE_DIR$/src/generated" />
<excludeFolder url="file://$MODULE_DIR$/src/tools" />
<excludeFolder url="file://$MODULE_DIR$/submodules" />
<excludeFolder url="file://$MODULE_DIR$/.efrocache" />
<excludePattern pattern=".assetcache" />
<excludePattern pattern=".cache*" />
<excludePattern pattern=".clang-format" />
@ -66,4 +67,4 @@
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
</component>
</module>
</module>

View File

@ -14,6 +14,7 @@
<w>abeb</w>
<w>abot</w>
<w>abtn</w>
<w>accountname</w>
<w>accountui</w>
<w>accum</w>
<w>accumkillcount</w>
@ -94,6 +95,7 @@
<w>audioop</w>
<w>autodesk</w>
<w>autogenerate</w>
<w>autonoassets</w>
<w>autoremove</w>
<w>autoretain</w>
<w>autoselect</w>
@ -245,6 +247,8 @@
<w>clionbin</w>
<w>clioncode</w>
<w>clionroot</w>
<w>cloudtool</w>
<w>cloudtoolcmd</w>
<w>clrblu</w>
<w>clrend</w>
<w>clrgrn</w>
@ -326,6 +330,7 @@
<w>datamodule</w>
<w>dataname</w>
<w>datetimemodule</w>
<w>datetimes</w>
<w>daynum</w>
<w>dayoffset</w>
<w>dbapi</w>
@ -339,6 +344,7 @@
<w>depcls</w>
<w>depdata</w>
<w>depdatas</w>
<w>depentry</w>
<w>deps</w>
<w>depset</w>
<w>depsets</w>
@ -871,6 +877,7 @@
<w>locationval</w>
<w>locs</w>
<w>logcat</w>
<w>logintoken</w>
<w>logitech</w>
<w>logput</w>
<w>loofa</w>
@ -1087,6 +1094,7 @@
<w>ouya</w>
<w>packagedir</w>
<w>packagedirs</w>
<w>packagename</w>
<w>painttxtattr</w>
<w>palmos</w>
<w>pandoc</w>
@ -1365,6 +1373,7 @@
<w>servercallthread</w>
<w>servercallthreadtype</w>
<w>servercfg</w>
<w>servercmd</w>
<w>serverdialog</w>
<w>serverget</w>
<w>serverput</w>
@ -1552,6 +1561,7 @@
<w>testm</w>
<w>testmagicmethods</w>
<w>testmock</w>
<w>testobj</w>
<w>testpatch</w>
<w>testpt</w>
<w>testsealable</w>
@ -1678,6 +1688,7 @@
<w>useragentstring</w>
<w>userbase</w>
<w>userfunctions</w>
<w>utcnow</w>
<w>utimensat</w>
<w>validpgpkeys</w>
<w>valnew</w>
@ -1737,6 +1748,7 @@
<w>wmsbe</w>
<w>woooo</w>
<w>workdir</w>
<w>workflows</w>
<w>wpath</w>
<w>writeclasses</w>
<w>writefuncs</w>

View File

@ -54,32 +54,31 @@ prereqs-clean:
assets: prereqs
@cd assets && make -j${CPUS}
# Build only assets required for cmake builds (linux, mac)
# Build assets required for cmake builds (linux, mac)
assets-cmake: prereqs
@cd assets && $(MAKE) -j${CPUS} cmake
# Build only assets required for windows builds.
# (honoring the WINDOWS_PLATFORM value)
# Build assets required for WINDOWS_PLATFORM windows builds.
assets-windows: prereqs
@cd assets && $(MAKE) -j${CPUS} win-${WINDOWS_PLATFORM}
# Build only assets required for Win32 windows builds.
# Build assets required for Win32 windows builds.
assets-windows-Win32: prereqs
@cd assets && $(MAKE) -j${CPUS} win-Win32
# Build only assets required for x64 windows builds.
# Build assets required for x64 windows builds.
assets-windows-x64: prereqs
@cd assets && $(MAKE) -j${CPUS} win-x64
# Build only assets required for mac xcode builds
# Build assets required for mac xcode builds
assets-mac: prereqs
@cd assets && $(MAKE) -j${CPUS} mac
# Build only assets required for ios.
# Build assets required for ios.
assets-ios: prereqs
@cd assets && $(MAKE) -j${CPUS} ios
# Build only assets required for android.
# Build assets required for android.
assets-android: prereqs
@cd assets && $(MAKE) -j${CPUS} android

View File

@ -14,7 +14,7 @@
"data/scripts/ba/__pycache__/_campaign.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_dep.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_dependency.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_enums.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_error.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc",
@ -27,7 +27,7 @@
"data/scripts/ba/__pycache__/_lang.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_level.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_lobby.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_maps.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_map.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_math.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_messages.cpython-37.opt-1.pyc",
"data/scripts/ba/__pycache__/_meta.cpython-37.opt-1.pyc",
@ -62,7 +62,7 @@
"data/scripts/ba/_campaign.py",
"data/scripts/ba/_coopgame.py",
"data/scripts/ba/_coopsession.py",
"data/scripts/ba/_dep.py",
"data/scripts/ba/_dependency.py",
"data/scripts/ba/_enums.py",
"data/scripts/ba/_error.py",
"data/scripts/ba/_freeforallsession.py",
@ -75,7 +75,7 @@
"data/scripts/ba/_lang.py",
"data/scripts/ba/_level.py",
"data/scripts/ba/_lobby.py",
"data/scripts/ba/_maps.py",
"data/scripts/ba/_map.py",
"data/scripts/ba/_math.py",
"data/scripts/ba/_messages.py",
"data/scripts/ba/_meta.py",

View File

@ -170,6 +170,7 @@ SCRIPT_TARGETS_PY_1 = \
build/data/scripts/ba/_profile.py \
build/data/scripts/ba/_error.py \
build/data/scripts/ba/_achievement.py \
build/data/scripts/ba/_map.py \
build/data/scripts/ba/_teambasesession.py \
build/data/scripts/ba/_gameutils.py \
build/data/scripts/ba/_activity.py \
@ -197,14 +198,13 @@ SCRIPT_TARGETS_PY_1 = \
build/data/scripts/ba/_lobby.py \
build/data/scripts/ba/_stats.py \
build/data/scripts/ba/_input.py \
build/data/scripts/ba/_dep.py \
build/data/scripts/ba/_level.py \
build/data/scripts/ba/_dependency.py \
build/data/scripts/ba/_general.py \
build/data/scripts/ba/_server.py \
build/data/scripts/ba/_account.py \
build/data/scripts/ba/_music.py \
build/data/scripts/ba/_lang.py \
build/data/scripts/ba/_maps.py \
build/data/scripts/ba/_teamgame.py \
build/data/scripts/ba/ui/__init__.py \
build/data/scripts/bastd/mainmenu.py \
@ -405,6 +405,7 @@ SCRIPT_TARGETS_PYC_1 = \
build/data/scripts/ba/__pycache__/_profile.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_error.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_achievement.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_map.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_teambasesession.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_activity.cpython-37.opt-1.pyc \
@ -432,14 +433,13 @@ SCRIPT_TARGETS_PYC_1 = \
build/data/scripts/ba/__pycache__/_lobby.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_stats.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_input.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_dep.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_level.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_dependency.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_general.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_server.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_account.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_music.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_lang.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_maps.cpython-37.opt-1.pyc \
build/data/scripts/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc \
build/data/scripts/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc \
build/data/scripts/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc \
@ -764,6 +764,11 @@ build/data/scripts/ba/__pycache__/_achievement.cpython-37.opt-1.pyc: \
@echo Compiling script: $^
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
build/data/scripts/ba/__pycache__/_map.cpython-37.opt-1.pyc: \
build/data/scripts/ba/_map.py
@echo Compiling script: $^
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
build/data/scripts/ba/__pycache__/_teambasesession.cpython-37.opt-1.pyc: \
build/data/scripts/ba/_teambasesession.py
@echo Compiling script: $^
@ -899,13 +904,13 @@ build/data/scripts/ba/__pycache__/_input.cpython-37.opt-1.pyc: \
@echo Compiling script: $^
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
build/data/scripts/ba/__pycache__/_dep.cpython-37.opt-1.pyc: \
build/data/scripts/ba/_dep.py
build/data/scripts/ba/__pycache__/_level.cpython-37.opt-1.pyc: \
build/data/scripts/ba/_level.py
@echo Compiling script: $^
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
build/data/scripts/ba/__pycache__/_level.cpython-37.opt-1.pyc: \
build/data/scripts/ba/_level.py
build/data/scripts/ba/__pycache__/_dependency.cpython-37.opt-1.pyc: \
build/data/scripts/ba/_dependency.py
@echo Compiling script: $^
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
@ -934,11 +939,6 @@ build/data/scripts/ba/__pycache__/_lang.cpython-37.opt-1.pyc: \
@echo Compiling script: $^
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
build/data/scripts/ba/__pycache__/_maps.cpython-37.opt-1.pyc: \
build/data/scripts/ba/_maps.py
@echo Compiling script: $^
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
build/data/scripts/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc: \
build/data/scripts/ba/_teamgame.py
@echo Compiling script: $^

View File

@ -43,7 +43,8 @@ from ba._actor import Actor
from ba._app import App
from ba._coopgame import CoopGameActivity
from ba._coopsession import CoopSession
from ba._dep import Dep, Dependency, DepComponent, DepSet, AssetPackage
from ba._dependency import (Dependency, DependencyComponent, DependencySet,
AssetPackage)
from ba._enums import TimeType, Permission, TimeFormat, SpecialChar
from ba._error import (UNHANDLED, print_exception, print_error, NotFoundError,
PlayerNotFoundError, NodeNotFoundError,
@ -55,7 +56,7 @@ from ba._freeforallsession import FreeForAllSession
from ba._gameactivity import GameActivity
from ba._gameresults import TeamGameResults
from ba._lang import Lstr, setlanguage, get_valid_languages
from ba._maps import Map, getmaps
from ba._map import Map, getmaps
from ba._session import Session
from ba._stats import PlayerScoredMessage, PlayerRecord, Stats
from ba._team import Team

View File

@ -25,7 +25,7 @@ import weakref
from typing import TYPE_CHECKING
import _ba
from ba._dep import InstancedDepComponent
from ba._dependency import DependencyComponent
if TYPE_CHECKING:
from weakref import ReferenceType
@ -34,7 +34,7 @@ if TYPE_CHECKING:
from bastd.actor.respawnicon import RespawnIcon
class Activity(InstancedDepComponent):
class Activity(DependencyComponent):
"""Units of execution wrangled by a ba.Session.
Category: Gameplay Classes

View File

@ -422,7 +422,7 @@ class App:
from ba import _appconfig
from ba import ui as bsui
from ba import _achievement
from ba import _maps
from ba import _map
from ba import _meta
from ba import _music
from ba import _campaign
@ -451,7 +451,7 @@ class App:
stdmaps.CragCastle, stdmaps.TowerD, stdmaps.HappyThoughts,
stdmaps.StepRightUp, stdmaps.Courtyard, stdmaps.Rampage
]:
_maps.register_map(maptype)
_map.register_map(maptype)
if self.debug_build:
_apputils.suppress_debug_reports()
@ -590,7 +590,7 @@ class App:
self.ran_on_launch = True
from ba._dep import test_depset
from ba._dependency import test_depset
test_depset()
# print('GAME TYPES ARE', meta.get_game_types())
# _bs.quit()

View File

@ -43,7 +43,7 @@ def run_cpu_benchmark() -> None:
def __init__(self) -> None:
print('FIXME: BENCHMARK SESSION WOULD CALC DEPS.')
depsets: Sequence[ba.DepSet] = []
depsets: Sequence[ba.DependencySet] = []
super().__init__(depsets)

View File

@ -73,7 +73,7 @@ class CoopSession(Session):
max_players = 4
print('FIXME: COOP SESSION WOULD CALC DEPS.')
depsets: Sequence[ba.DepSet] = []
depsets: Sequence[ba.DependencySet] = []
super().__init__(depsets,
team_names=TEAM_NAMES,

View File

@ -1,523 +0,0 @@
# Copyright (c) 2011-2019 Eric Froemling
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# -----------------------------------------------------------------------------
"""Functionality related to object/asset dependencies."""
from __future__ import annotations
import weakref
from typing import (Generic, TypeVar, TYPE_CHECKING, cast, Type, overload)
import _ba
from ba import _general
if TYPE_CHECKING:
from typing import Optional, Any, Dict, List, Set
import ba
T = TypeVar('T', bound='DepComponent')
TI = TypeVar('TI', bound='InstancedDepComponent')
TS = TypeVar('TS', bound='StaticDepComponent')
class Dependency(Generic[T]):
"""A dependency on a DepComponent (with an optional config).
Category: Dependency Classes
This class is used to request and access functionality provided
by other DepComponent classes from a DepComponent class.
The class functions as a descriptor, allowing dependencies to
be added at a class level much the same as properties or methods
and then used with class instances to access those dependencies.
For instance, if you do 'floofcls = ba.Dependency(FloofClass)' you
would then be able to instantiate a FloofClass in your class's
methods via self.floofcls().
"""
def __init__(self, cls: Type[T], config: Any = None):
"""Instantiate a Dependency given a ba.DepComponent subtype.
Optionally, an arbitrary object can be passed as 'config' to
influence dependency calculation for the target class.
"""
self.cls: Type[T] = cls
self.config = config
self._hash: Optional[int] = None
def get_hash(self) -> int:
"""Return the dependency's hash, calculating it if necessary."""
if self._hash is None:
self._hash = _general.make_hash((self.cls, self.config))
return self._hash
# NOTE: it appears that mypy is currently not able to do overloads based
# on the type of 'self', otherwise we could just overload this to
# return different things based on self's type and avoid the need for
# the fake dep classes below.
# See https://github.com/python/mypy/issues/5320
def __get__(self, obj: Any, cls: Any = None) -> Any:
if obj is None:
raise TypeError("Dependency must be accessed through an instance.")
# We expect to be instantiated from an already living DepComponent
# with valid dep-data in place..
assert type is not None
depdata = getattr(obj, '_depdata')
if depdata is None:
raise RuntimeError("Invalid dependency access.")
assert isinstance(depdata, DepData)
# Now look up the data for this particular dep
depset = depdata.depset()
assert isinstance(depset, DepSet)
assert self._hash in depset.depdatas
depdata = depset.depdatas[self._hash]
assert isinstance(depdata, DepData)
if depdata.valid is False:
raise RuntimeError(
f'Accessing DepComponent {depdata.cls} in an invalid state.')
assert self.cls.dep_get_payload(depdata) is not None
return self.cls.dep_get_payload(depdata)
# We define a 'Dep' which at runtime simply aliases the Dependency class
# but in type-checking points to two overloaded functions based on the argument
# type. This lets the type system know what type of object the Dep represents.
# (object instances in the case of StaticDep classes or object types in the
# case of regular deps) At some point hopefully we can replace this with a
# simple overload in Dependency.__get__ based on the type of self
# (see note above).
if not TYPE_CHECKING:
Dep = Dependency
else:
class _InstanceDep(Dependency[TI]):
"""Fake stub we use to tell the type system we provide a type."""
def __get__(self, obj: Any, cls: Any = None) -> Type[TI]:
return cast(Type[TI], None)
class _StaticDep(Dependency[TS]):
"""Fake stub we use to tell the type system we provide an instance."""
def __get__(self, obj: Any, cls: Any = None) -> TS:
return cast(TS, None)
# pylint: disable=invalid-name
# noinspection PyPep8Naming
@overload
def Dep(cls: Type[TI], config: Any = None) -> _InstanceDep[TI]:
"""test"""
return _InstanceDep(cls, config)
# noinspection PyPep8Naming
@overload
def Dep(cls: Type[TS], config: Any = None) -> _StaticDep[TS]:
"""test"""
return _StaticDep(cls, config)
# noinspection PyPep8Naming
def Dep(cls: Any, config: Any = None) -> Any:
"""test"""
return Dependency(cls, config)
# pylint: enable=invalid-name
class BoundDepComponent:
"""A DepComponent class bound to its DepSet data.
Can be called to instantiate the class with its data properly in place."""
def __init__(self, cls: Any, depdata: DepData):
self.cls = cls
# BoundDepComponents can be stored on depdatas so we use weakrefs
# to avoid dependency cycles.
self.depdata = weakref.ref(depdata)
def __call__(self, *args: Any, **keywds: Any) -> Any:
# We don't simply call our target type to instantiate it;
# instead we manually call __new__ and then __init__.
# This allows us to inject its data properly before __init__().
obj = self.cls.__new__(self.cls, *args, **keywds)
obj._depdata = self.depdata()
assert isinstance(obj._depdata, DepData)
obj.__init__(*args, **keywds)
return obj
class DepComponent:
"""Base class for all classes that can act as or use dependencies.
category: Dependency Classes
"""
_depdata: DepData
def __init__(self) -> None:
"""Instantiate a DepComponent."""
# For now lets issue a warning if these are instantiated without
# data; we'll make this an error once we're no longer seeing warnings.
depdata = getattr(self, '_depdata', None)
if depdata is None:
print(f'FIXME: INSTANTIATING DEP CLASS {type(self)} DIRECTLY.')
self.context = _ba.Context('current')
@classmethod
def is_present(cls, config: Any = None) -> bool:
"""Return whether this component/config is present on this device."""
del config # Unused here.
return True
@classmethod
def get_dynamic_deps(cls, config: Any = None) -> List[Dependency]:
"""Return any dynamically-calculated deps for this component/config.
Deps declared statically as part of the class do not need to be
included here; this is only for additional deps that may vary based
on the dep config value. (for instance a map required by a game type)
"""
del config # Unused here.
return []
@classmethod
def dep_get_payload(cls, depdata: DepData) -> Any:
"""Return user-facing data for a loaded dep.
If this dep does not yet have a 'payload' value, it should
be generated and cached. Otherwise the existing value
should be returned.
This is the value given for a DepComponent when accessed
through a Dependency instance on a live object, etc.
"""
del depdata # Unused here.
class DepData:
"""Data associated with a dependency in a dependency set."""
def __init__(self, depset: DepSet, dep: Dependency[T]):
# Note: identical Dep/config pairs will share data, so the dep
# entry on a given Dep may not point to.
self.cls = dep.cls
self.config = dep.config
# Arbitrary data for use by dependencies in the resolved set
# (the static instance for static-deps, etc).
self.payload: Any = None
self.valid: bool = False
# Weakref to the depset that includes us (to avoid ref loop).
self.depset = weakref.ref(depset)
class DepSet(Generic[TI]):
"""Set of resolved dependencies and their associated data."""
def __init__(self, root: Dependency[TI]):
self.root = root
self._resolved = False
# Dependency data indexed by hash.
self.depdatas: Dict[int, DepData] = {}
# Instantiated static-components.
self.static_instances: List[StaticDepComponent] = []
def __del__(self) -> None:
# When our dep-set goes down, clear out all dep-data payloads
# so we can throw errors if anyone tries to use them anymore.
for depdata in self.depdatas.values():
depdata.payload = None
depdata.valid = False
def resolve(self) -> None:
"""Resolve the total set of required dependencies for the set.
Raises a ba.DependencyError if dependencies are missing (or other
Exception types on other errors).
"""
if self._resolved:
raise Exception("DepSet has already been resolved.")
print('RESOLVING DEP SET')
# First, recursively expand out all dependencies.
self._resolve(self.root, 0)
# Now, if any dependencies are not present, raise an Exception
# telling exactly which ones (so hopefully they'll be able to be
# downloaded/etc.
missing = [
Dependency(entry.cls, entry.config)
for entry in self.depdatas.values()
if not entry.cls.is_present(entry.config)
]
if missing:
from ba._error import DependencyError
raise DependencyError(missing)
self._resolved = True
print('RESOLVE SUCCESS!')
def get_asset_package_ids(self) -> Set[str]:
"""Return the set of asset-package-ids required by this dep-set.
Must be called on a resolved dep-set.
"""
ids: Set[str] = set()
if not self._resolved:
raise Exception('Must be called on a resolved dep-set.')
for entry in self.depdatas.values():
if issubclass(entry.cls, AssetPackage):
assert isinstance(entry.config, str)
ids.add(entry.config)
return ids
def load(self) -> Type[TI]:
"""Attach the resolved set to the current context.
Returns a wrapper which can be used to instantiate the root dep.
"""
# NOTE: stuff below here should probably go in a separate 'instantiate'
# method or something.
if not self._resolved:
raise Exception("Can't instantiate an unresolved DepSet")
# Go through all of our dep entries and give them a chance to
# preload whatever they want.
for entry in self.depdatas.values():
# First mark everything as valid so recursive loads don't fail.
assert entry.valid is False
entry.valid = True
for entry in self.depdatas.values():
# Do a get on everything which will init all payloads
# in the proper order recursively.
# NOTE: should we guard for recursion here?...
entry.cls.dep_get_payload(entry)
# NOTE: like above, we're cheating here and telling the type
# system we're simply returning the root dependency class, when
# actually it's a bound-dependency wrapper containing its data/etc.
# ..Should fix if/when mypy is smart enough to preserve type safety
# on the wrapper's __call__()
rootdata = self.depdatas[self.root.get_hash()]
return cast(Type[TI], BoundDepComponent(self.root.cls, rootdata))
def _resolve(self, dep: Dependency[T], recursion: int) -> None:
# Watch for wacky infinite dep loops.
if recursion > 10:
raise Exception('Max recursion reached')
hashval = dep.get_hash()
if hashval in self.depdatas:
# Found an already resolved one; we're done here.
return
# Add our entry before we recurse so we don't repeat add it if
# there's a dependency loop.
self.depdatas[hashval] = DepData(self, dep)
# Grab all Dependency instances we find in the class.
subdeps = [
cls for cls in dep.cls.__dict__.values()
if isinstance(cls, Dependency)
]
# ..and add in any dynamic ones it provides.
subdeps += dep.cls.get_dynamic_deps(dep.config)
for subdep in subdeps:
self._resolve(subdep, recursion + 1)
class InstancedDepComponent(DepComponent):
"""Base class for DepComponents intended to be instantiated as needed."""
@classmethod
def dep_get_payload(cls, depdata: DepData) -> Any:
"""Data provider override; returns a BoundDepComponent."""
if depdata.payload is None:
# The payload we want for ourself in the dep-set is simply
# the bound-def that users can use to instantiate our class
# with its data properly intact. We could also just store
# the class and instantiate one of these each time.
depdata.payload = BoundDepComponent(cls, depdata)
return depdata.payload
class StaticDepComponent(DepComponent):
"""Base for DepComponents intended to be instantiated once and shared."""
@classmethod
def dep_get_payload(cls, depdata: DepData) -> Any:
"""Data provider override; returns shared instance."""
if depdata.payload is None:
# We want to share a single instance of our object with anything
# in the set that requested it, so create a temp bound-dep and
# create an instance from that.
depcls = BoundDepComponent(cls, depdata)
# Instances have a strong ref to depdata so we can't give
# depdata a strong reference to it without creating a cycle.
# We also can't just weak-ref the instance or else it won't be
# kept alive. Our solution is to stick strong refs to all static
# components somewhere on the DepSet.
instance = depcls()
assert depdata.depset
depset2 = depdata.depset()
assert depset2 is not None
depset2.static_instances.append(instance)
depdata.payload = weakref.ref(instance)
assert isinstance(depdata.payload, weakref.ref)
payload = depdata.payload()
if payload is None:
raise RuntimeError(
f'Accessing DepComponent {cls} in an invalid state.')
return payload
class AssetPackage(StaticDepComponent):
"""DepComponent representing a bundled package of game assets."""
def __init__(self) -> None:
super().__init__()
# pylint: disable=no-member
assert isinstance(self._depdata.config, str)
self.package_id = self._depdata.config
print(f'LOADING ASSET PACKAGE {self.package_id}')
@classmethod
def is_present(cls, config: Any = None) -> bool:
assert isinstance(config, str)
# Temp: hard-coding for a single asset-package at the moment.
if config == 'stdassets@1':
return True
return False
def gettexture(self, name: str) -> ba.Texture:
"""Load a named ba.Texture from the AssetPackage.
Behavior is similar to ba.gettexture()
"""
return _ba.get_package_texture(self, name)
def getmodel(self, name: str) -> ba.Model:
"""Load a named ba.Model from the AssetPackage.
Behavior is similar to ba.getmodel()
"""
return _ba.get_package_model(self, name)
def getcollidemodel(self, name: str) -> ba.CollideModel:
"""Load a named ba.CollideModel from the AssetPackage.
Behavior is similar to ba.getcollideModel()
"""
return _ba.get_package_collide_model(self, name)
def getsound(self, name: str) -> ba.Sound:
"""Load a named ba.Sound from the AssetPackage.
Behavior is similar to ba.getsound()
"""
return _ba.get_package_sound(self, name)
def getdata(self, name: str) -> ba.Data:
"""Load a named ba.Data from the AssetPackage.
Behavior is similar to ba.getdata()
"""
return _ba.get_package_data(self, name)
class TestClassFactory(StaticDepComponent):
"""Another test dep-obj."""
_assets = Dep(AssetPackage, 'stdassets@1')
def __init__(self) -> None:
super().__init__()
print("Instantiating TestClassFactory")
self.tex = self._assets.gettexture('black')
self.model = self._assets.getmodel('landMine')
self.sound = self._assets.getsound('error')
self.data = self._assets.getdata('langdata')
class TestClassObj(InstancedDepComponent):
"""Another test dep-obj."""
class TestClass(InstancedDepComponent):
"""A test dep-obj."""
_actorclass = Dep(TestClassObj)
_factoryclass = Dep(TestClassFactory, 123)
_factoryclass2 = Dep(TestClassFactory, 124)
def __init__(self, arg: int) -> None:
super().__init__()
del arg
self._actor = self._actorclass()
print('got actor', self._actor)
print('have factory', self._factoryclass)
print('have factory2', self._factoryclass2)
def test_depset() -> None:
"""Test call to try this stuff out..."""
# noinspection PyUnreachableCode
if False: # pylint: disable=using-constant-test
print('running test_depset()...')
def doit() -> None:
from ba._error import DependencyError
depset = DepSet(Dep(TestClass))
resolved = False
try:
depset.resolve()
resolved = True
except DependencyError as exc:
for dep in exc.deps:
if dep.cls is AssetPackage:
print('MISSING PACKAGE', dep.config)
else:
raise Exception('unknown dependency error for ' +
str(dep.cls))
except Exception as exc:
print('DepSet resolve failed with exc type:', type(exc))
if resolved:
testclass = depset.load()
instance = testclass(123)
print("INSTANTIATED ROOT:", instance)
doit()
# To test this, add prints on __del__ for stuff used above;
# everything should be dead at this point if we have no cycles.
print('everything should be cleaned up...')
_ba.quit()

View File

@ -0,0 +1,437 @@
# Copyright (c) 2011-2019 Eric Froemling
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# -----------------------------------------------------------------------------
"""Functionality related to object/asset dependencies."""
from __future__ import annotations
import weakref
from typing import (Generic, TypeVar, TYPE_CHECKING)
import _ba
from ba import _general
if TYPE_CHECKING:
from typing import Optional, Any, Dict, List, Set, Type
from weakref import ReferenceType
import ba
T = TypeVar('T', bound='DependencyComponent')
class Dependency(Generic[T]):
"""A dependency on a DependencyComponent (with an optional config).
Category: Dependency Classes
This class is used to request and access functionality provided
by other DependencyComponent classes from a DependencyComponent class.
The class functions as a descriptor, allowing dependencies to
be added at a class level much the same as properties or methods
and then used with class instances to access those dependencies.
For instance, if you do 'floofcls = ba.Dependency(FloofClass)' you
would then be able to instantiate a FloofClass in your class's
methods via self.floofcls().
"""
def __init__(self, cls: Type[T], config: Any = None):
"""Instantiate a Dependency given a ba.DependencyComponent type.
Optionally, an arbitrary object can be passed as 'config' to
influence dependency calculation for the target class.
"""
self.cls: Type[T] = cls
self.config = config
self._hash: Optional[int] = None
def get_hash(self) -> int:
"""Return the dependency's hash, calculating it if necessary."""
if self._hash is None:
self._hash = _general.make_hash((self.cls, self.config))
return self._hash
def __get__(self, obj: Any, cls: Any = None) -> T:
if not isinstance(obj, DependencyComponent):
if obj is None:
raise TypeError(
"Dependency must be accessed through an instance.")
raise TypeError(
f"Dependency cannot be added to class of type {type(obj)}"
" (class must inherit from ba.DependencyComponent).")
# We expect to be instantiated from an already living
# DependencyComponent with valid dep-data in place..
assert cls is not None
# Get the DependencyEntry this instance is associated with and from
# there get back to the DependencySet
entry = getattr(obj, '_dep_entry')
if entry is None:
raise RuntimeError("Invalid dependency access.")
entry = entry()
assert isinstance(entry, DependencyEntry)
depset = entry.depset()
assert isinstance(depset, DependencySet)
if not depset.resolved:
raise RuntimeError(
"Can't access data on an unresolved DependencySet.")
# Look up the data in the set based on the hash for this Dependency.
assert self._hash in depset.entries
entry = depset.entries[self._hash]
assert isinstance(entry, DependencyEntry)
retval = entry.get_component()
assert isinstance(retval, self.cls)
return retval
class DependencyComponent:
"""Base class for all classes that can act as or use dependencies.
category: Dependency Classes
"""
_dep_entry: ReferenceType[DependencyEntry]
def __init__(self) -> None:
"""Instantiate a DependencyComponent."""
# For now lets issue a warning if these are instantiated without
# a dep-entry; we'll make this an error once we're no longer
# seeing warnings.
entry = getattr(self, '_dep_entry', None)
if entry is None:
print(f'FIXME: INSTANTIATING DEP CLASS {type(self)} DIRECTLY.')
@classmethod
def dep_is_present(cls, config: Any = None) -> bool:
"""Return whether this component/config is present on this device."""
del config # Unused here.
return True
@classmethod
def get_dynamic_deps(cls, config: Any = None) -> List[Dependency]:
"""Return any dynamically-calculated deps for this component/config.
Deps declared statically as part of the class do not need to be
included here; this is only for additional deps that may vary based
on the dep config value. (for instance a map required by a game type)
"""
del config # Unused here.
return []
class DependencyEntry:
"""Data associated with a dependency/config pair in a ba.DependencySet."""
def __del__(self) -> None:
print('~DepEntry()', self.cls)
def __init__(self, depset: DependencySet, dep: Dependency[T]):
print("DepEntry()", dep.cls)
self.cls = dep.cls
self.config = dep.config
# Arbitrary data for use by dependencies in the resolved set
# (the static instance for static-deps, etc).
self.component: Optional[DependencyComponent] = None
# Weakref to the depset that includes us (to avoid ref loop).
self.depset = weakref.ref(depset)
def get_component(self) -> DependencyComponent:
"""Return the component instance, creating it if necessary."""
if self.component is None:
# We don't simply call our type to instantiate our instance;
# instead we manually call __new__ and then __init__.
# This allows us to inject its data properly before __init__().
print('creating', self.cls)
instance = self.cls.__new__(self.cls)
# pylint: disable=protected-access
instance._dep_entry = weakref.ref(self)
instance.__init__()
assert self.depset
depset = self.depset()
assert depset is not None
self.component = instance
component = self.component
assert isinstance(component, self.cls)
if component is None:
raise RuntimeError(f'Accessing DependencyComponent {self.cls} '
'in an invalid state.')
return component
class DependencySet(Generic[T]):
"""Set of resolved dependencies and their associated data.
To use DependencyComponents, a set must be created, resolved, and then
loaded. The DependencyComponents are only valid while the set remains
in existence.
"""
def __init__(self, root_dependency: Dependency[T]):
print('DepSet()')
self._root_dependency = root_dependency
self._resolved = False
self._loaded = False
# Dependency data indexed by hash.
self.entries: Dict[int, DependencyEntry] = {}
def __del__(self) -> None:
print("~DepSet()")
def resolve(self) -> None:
"""Resolve the complete set of required dependencies for this set.
Raises a ba.DependencyError if dependencies are missing (or other
Exception types on other errors).
"""
if self._resolved:
raise Exception("DependencySet has already been resolved.")
print('RESOLVING DEP SET')
# First, recursively expand out all dependencies.
self._resolve(self._root_dependency, 0)
# Now, if any dependencies are not present, raise an Exception
# telling exactly which ones (so hopefully they'll be able to be
# downloaded/etc.
missing = [
Dependency(entry.cls, entry.config)
for entry in self.entries.values()
if not entry.cls.dep_is_present(entry.config)
]
if missing:
from ba._error import DependencyError
raise DependencyError(missing)
self._resolved = True
print('RESOLVE SUCCESS!')
@property
def resolved(self) -> bool:
"""Whether this set has been successfully resolved."""
return self._resolved
def get_asset_package_ids(self) -> Set[str]:
"""Return the set of asset-package-ids required by this dep-set.
Must be called on a resolved dep-set.
"""
ids: Set[str] = set()
if not self._resolved:
raise Exception('Must be called on a resolved dep-set.')
for entry in self.entries.values():
if issubclass(entry.cls, AssetPackage):
assert isinstance(entry.config, str)
ids.add(entry.config)
return ids
def load(self) -> None:
"""Instantiate all DependencyComponents in the set.
Returns a wrapper which can be used to instantiate the root dep.
"""
# NOTE: stuff below here should probably go in a separate 'instantiate'
# method or something.
if not self._resolved:
raise RuntimeError("Can't load an unresolved DependencySet")
for entry in self.entries.values():
# Do a get on everything which will init all payloads
# in the proper order recursively.
entry.get_component()
self._loaded = True
@property
def root(self) -> T:
"""The instantiated root DependencyComponent instance for the set."""
if not self._loaded:
raise RuntimeError("DependencySet is not loaded.")
rootdata = self.entries[self._root_dependency.get_hash()].component
assert isinstance(rootdata, self._root_dependency.cls)
return rootdata
def _resolve(self, dep: Dependency[T], recursion: int) -> None:
# Watch for wacky infinite dep loops.
if recursion > 10:
raise Exception('Max recursion reached')
hashval = dep.get_hash()
if hashval in self.entries:
# Found an already resolved one; we're done here.
return
# Add our entry before we recurse so we don't repeat add it if
# there's a dependency loop.
self.entries[hashval] = DependencyEntry(self, dep)
# Grab all Dependency instances we find in the class.
subdeps = [
cls for cls in dep.cls.__dict__.values()
if isinstance(cls, Dependency)
]
# ..and add in any dynamic ones it provides.
subdeps += dep.cls.get_dynamic_deps(dep.config)
for subdep in subdeps:
self._resolve(subdep, recursion + 1)
class AssetPackage(DependencyComponent):
"""DependencyComponent representing a bundled package of game assets."""
def __init__(self) -> None:
super().__init__()
# pylint: disable=no-member
# This is used internally by the get_package_xxx calls.
self.context = _ba.Context('current')
entry = self._dep_entry()
assert entry is not None
assert isinstance(entry.config, str)
self.package_id = entry.config
print(f'LOADING ASSET PACKAGE {self.package_id}')
@classmethod
def dep_is_present(cls, config: Any = None) -> bool:
assert isinstance(config, str)
# Temp: hard-coding for a single asset-package at the moment.
if config == 'stdassets@1':
return True
return False
def gettexture(self, name: str) -> ba.Texture:
"""Load a named ba.Texture from the AssetPackage.
Behavior is similar to ba.gettexture()
"""
return _ba.get_package_texture(self, name)
def getmodel(self, name: str) -> ba.Model:
"""Load a named ba.Model from the AssetPackage.
Behavior is similar to ba.getmodel()
"""
return _ba.get_package_model(self, name)
def getcollidemodel(self, name: str) -> ba.CollideModel:
"""Load a named ba.CollideModel from the AssetPackage.
Behavior is similar to ba.getcollideModel()
"""
return _ba.get_package_collide_model(self, name)
def getsound(self, name: str) -> ba.Sound:
"""Load a named ba.Sound from the AssetPackage.
Behavior is similar to ba.getsound()
"""
return _ba.get_package_sound(self, name)
def getdata(self, name: str) -> ba.Data:
"""Load a named ba.Data from the AssetPackage.
Behavior is similar to ba.getdata()
"""
return _ba.get_package_data(self, name)
class TestClassFactory(DependencyComponent):
"""Another test dep-obj."""
_assets = Dependency(AssetPackage, 'stdassets@1')
def __init__(self) -> None:
super().__init__()
print("Instantiating TestClassFactory")
self.tex = self._assets.gettexture('black')
self.model = self._assets.getmodel('landMine')
self.sound = self._assets.getsound('error')
self.data = self._assets.getdata('langdata')
class TestClassObj(DependencyComponent):
"""Another test dep-obj."""
class TestClass(DependencyComponent):
"""A test dep-obj."""
_testclass = Dependency(TestClassObj)
_factoryclass = Dependency(TestClassFactory, 123)
_factoryclass2 = Dependency(TestClassFactory, 123)
def __del__(self) -> None:
print("~TestClass()")
def __init__(self) -> None:
super().__init__()
print('TestClass()')
self._actor = self._testclass
print('got actor', self._actor)
print('have factory', self._factoryclass)
print('have factory2', self._factoryclass2)
def test_depset() -> None:
"""Test call to try this stuff out..."""
# noinspection PyUnreachableCode
if False: # pylint: disable=using-constant-test
print('running test_depset()...')
def doit() -> None:
from ba._error import DependencyError
depset = DependencySet(Dependency(TestClass))
try:
depset.resolve()
except DependencyError as exc:
for dep in exc.deps:
if dep.cls is AssetPackage:
print('MISSING ASSET PACKAGE', dep.config)
else:
raise Exception('unknown dependency error for ' +
str(dep.cls))
except Exception as exc:
print('DependencySet resolve failed with exc type:', type(exc))
if depset.resolved:
depset.load()
testobj = depset.root
# instance = testclass(123)
print("INSTANTIATED ROOT:", testobj)
doit()
# To test this, add prints on __del__ for stuff used above;
# everything should be dead at this point if we have no cycles.
print('everything should be cleaned up...')
_ba.quit()

View File

@ -250,9 +250,9 @@ class GameActivity(Activity):
implementation; should return a list of map names valid
for this game-type for the given ba.Session type.
"""
from ba import _maps
from ba import _map
del sessiontype # unused arg
return _maps.getmaps("melee")
return _map.getmaps("melee")
@classmethod
def get_config_display_string(cls, config: Dict[str, Any]) -> ba.Lstr:
@ -261,7 +261,7 @@ class GameActivity(Activity):
This is used when viewing game-lists or showing what game
is up next in a series.
"""
from ba import _maps
from ba import _map
name = cls.get_display_string(config['settings'])
# in newer configs, map is in settings; it used to be in the
@ -270,15 +270,15 @@ class GameActivity(Activity):
sval = Lstr(value="${NAME} @ ${MAP}",
subs=[('${NAME}', name),
('${MAP}',
_maps.get_map_display_string(
_maps.get_filtered_map_name(
_map.get_map_display_string(
_map.get_filtered_map_name(
config['settings']['map'])))])
elif 'map' in config:
sval = Lstr(value="${NAME} @ ${MAP}",
subs=[('${NAME}', name),
('${MAP}',
_maps.get_map_display_string(
_maps.get_filtered_map_name(config['map'])))
_map.get_map_display_string(
_map.get_filtered_map_name(config['map'])))
])
else:
print('invalid game config - expected map entry under settings')
@ -295,7 +295,7 @@ class GameActivity(Activity):
def __init__(self, settings: Dict[str, Any]):
"""Instantiate the Activity."""
from ba import _maps
from ba import _map
super().__init__(settings)
# Set some defaults.
@ -313,7 +313,7 @@ class GameActivity(Activity):
else:
# If settings doesn't specify a map, pick a random one from the
# list of supported ones.
unowned_maps = _maps.get_unowned_maps()
unowned_maps = _map.get_unowned_maps()
valid_maps: List[str] = [
m for m in self.get_supported_maps(type(self.session))
if m not in unowned_maps
@ -322,7 +322,7 @@ class GameActivity(Activity):
_ba.screenmessage(Lstr(resource='noValidMapsErrorText'))
raise Exception("No valid maps")
map_name = valid_maps[random.randrange(len(valid_maps))]
self._map_type = _maps.get_map_class(map_name)
self._map_type = _map.get_map_class(map_name)
self._map_type.preload()
self._map: Optional[ba.Map] = None
self._powerup_drop_timer: Optional[ba.Timer] = None

View File

@ -47,13 +47,13 @@ def filter_playlist(playlist: PlaylistType,
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
from ba import _meta
from ba import _maps
from ba import _map
from ba import _general
from ba import _gameactivity
goodlist: List[Dict] = []
unowned_maps: Sequence[str]
if remove_unowned or mark_unowned:
unowned_maps = _maps.get_unowned_maps()
unowned_maps = _map.get_unowned_maps()
unowned_game_types = _meta.get_unowned_game_types()
else:
unowned_maps = []
@ -69,7 +69,7 @@ def filter_playlist(playlist: PlaylistType,
entry['settings']['map'] = entry['map']
del entry['map']
# update old map names to new ones
entry['settings']['map'] = _maps.get_filtered_map_name(
entry['settings']['map'] = _map.get_filtered_map_name(
entry['settings']['map'])
if remove_unowned and entry['settings']['map'] in unowned_maps:
continue

View File

@ -83,7 +83,7 @@ class Session:
players: List[ba.Player]
def __init__(self,
depsets: Sequence[ba.DepSet],
depsets: Sequence[ba.DependencySet],
team_names: Sequence[str] = None,
team_colors: Sequence[Sequence[float]] = None,
use_team_colors: bool = True,
@ -94,7 +94,7 @@ class Session:
# pylint: disable=too-many-branches
"""Instantiate a session.
depsets should be a sequence of successfully resolved ba.DepSet
depsets should be a sequence of successfully resolved ba.DependencySet
instances; one for each ba.Activity the session may potentially run.
"""
# pylint: disable=too-many-locals
@ -105,7 +105,7 @@ class Session:
from ba._gameactivity import GameActivity
from ba._team import Team
from ba._error import DependencyError
from ba._dep import Dep, AssetPackage
from ba._dependency import Dependency, AssetPackage
print(' WOULD LOOK AT DEP SETS', depsets)
@ -131,7 +131,8 @@ class Session:
# throw a combined exception if we found anything missing
if missing_asset_packages:
raise DependencyError([
Dep(AssetPackage, set_id) for set_id in missing_asset_packages
Dependency(AssetPackage, set_id)
for set_id in missing_asset_packages
])
# ok; looks like our dependencies check out.

View File

@ -40,7 +40,7 @@ def get_store_item_name_translated(item_name: str) -> ba.Lstr:
"""Return a ba.Lstr for a store item name."""
# pylint: disable=cyclic-import
from ba import _lang
from ba import _maps
from ba import _map
item_info = get_store_item(item_name)
if item_name.startswith('characters.'):
return _lang.Lstr(translate=('characterNames', item_info['character']))
@ -50,7 +50,7 @@ def get_store_item_name_translated(item_name: str) -> ba.Lstr:
_lang.Lstr(resource='titleText'))])
if item_name.startswith('maps.'):
map_type: Type[ba.Map] = item_info['map_type']
return _maps.get_map_display_string(map_type.name)
return _map.get_map_display_string(map_type.name)
if item_name.startswith('games.'):
gametype: Type[ba.GameActivity] = item_info['gametype']
return gametype.get_display_string()

View File

@ -66,7 +66,7 @@ class TeamBaseSession(Session):
team_colors = None
print('FIXME: TEAM BASE SESSION WOULD CALC DEPS.')
depsets: Sequence[ba.DepSet] = []
depsets: Sequence[ba.DependencySet] = []
super().__init__(depsets,
team_names=team_names,
team_colors=team_colors,

View File

@ -27,9 +27,9 @@ defensively) in mods.
# pylint: disable=unused-import
from ba._maps import (get_unowned_maps, get_map_class, register_map,
preload_map_preview_media, get_map_display_string,
get_filtered_map_name)
from ba._map import (get_unowned_maps, get_map_class, register_map,
preload_map_preview_media, get_map_display_string,
get_filtered_map_name)
from ba._appconfig import commit_app_config
from ba._input import (get_device_value, get_input_map_hash,
get_input_device_config)

View File

@ -18,4 +18,4 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# -----------------------------------------------------------------------------
"""Functionality shared between Ballistica client and server components."""
"""Functionality shared between all Ballistica clients, servers, and tools."""

View File

@ -36,7 +36,13 @@ TRET = TypeVar('TRET')
def utc_now() -> datetime.datetime:
"""Get offset-aware current utc time."""
"""Get offset-aware current utc time.
This should be used for all datetimes getting sent over the network,
used with the entity system, etc.
(datetime.utcnow() gives a utc time value, but it is not timezone-aware
which makes it less safe to use)
"""
return datetime.datetime.now(datetime.timezone.utc)

View File

@ -46,7 +46,7 @@ if TYPE_CHECKING:
class MainMenuActivity(ba.Activity):
"""Activity showing the rotating main menu bg stuff."""
_stdassets = ba.Dep(ba.AssetPackage, 'stdassets@1')
_stdassets = ba.Dependency(ba.AssetPackage, 'stdassets@1')
def on_transition_in(self) -> None:
super().on_transition_in()
@ -903,7 +903,7 @@ class MainMenuSession(ba.Session):
def __init__(self) -> None:
# Gather dependencies we'll need (just our activity).
self._activity_deps = ba.DepSet(ba.Dep(MainMenuActivity))
self._activity_deps = ba.DependencySet(ba.Dependency(MainMenuActivity))
super().__init__([self._activity_deps])
self._locked = False

View File

@ -1,6 +1,6 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<!--DOCSHASH=f593a39e3a39b53bf74c893acf8c746b-->
<h4><em>last updated on 2019-11-12 for Ballistica version 1.5.0 build 20001</em></h4>
<!--DOCSHASH=51c5d02115be6a67ed7833c3ec13432e-->
<h4><em>last updated on 2019-11-21 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>
@ -150,8 +150,8 @@
</ul>
<h4><a class="offsanchor" name="class_category_Dependency_Classes">Dependency Classes</a></h4>
<ul>
<li><a href="#class_ba_DepComponent">ba.DepComponent</a></li>
<li><a href="#class_ba_Dependency">ba.Dependency</a></li>
<li><a href="#class_ba_DependencyComponent">ba.DependencyComponent</a></li>
</ul>
<h4><a class="offsanchor" name="class_category_Enums">Enums</a></h4>
<ul>
@ -182,7 +182,7 @@
<li><a href="#class_ba_AssetPackage">ba.AssetPackage</a></li>
<li><a href="#class_ba_Campaign">ba.Campaign</a></li>
<li><a href="#class_ba_Chooser">ba.Chooser</a></li>
<li><a href="#class_ba_DepSet">ba.DepSet</a></li>
<li><a href="#class_ba_DependencySet">ba.DependencySet</a></li>
<li><a href="#class_ba_Lobby">ba.Lobby</a></li>
<li><a href="#class_ba_MusicPlayer">ba.MusicPlayer</a></li>
<li><a href="#class_ba_OldWindow">ba.OldWindow</a></li>
@ -287,7 +287,7 @@ actually award achievements.</p>
<hr>
<h2><strong><a class="offsanchor" name="class_ba_Activity">ba.Activity</a></strong></h3>
<p style="padding-left: 30px;">inherits from: <a href="#class_ba__dep_InstancedDepComponent">ba._dep.InstancedDepComponent</a>, <a href="#class_ba_DepComponent">ba.DepComponent</a></p>
<p style="padding-left: 30px;">inherits from: <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a></p>
<p style="padding-left: 30px;">Units of execution wrangled by a <a href="#class_ba_Session">ba.Session</a>.</p>
<p style="padding-left: 30px;">Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
@ -329,7 +329,7 @@ player gets their own team; in teams mode there are always 2 teams
regardless of the player count).</p>
<h3 style="padding-left: 0px;">Methods Inherited:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba__dep_InstancedDepComponent__dep_get_payload">dep_get_payload()</a>, <a href="#method_ba__dep_InstancedDepComponent__get_dynamic_deps">get_dynamic_deps()</a>, <a href="#method_ba__dep_InstancedDepComponent__is_present">is_present()</a></h5>
<h5 style="padding-left: 30px;"><a href="#method_ba_DependencyComponent__dep_is_present">dep_is_present()</a>, <a href="#method_ba_DependencyComponent__get_dynamic_deps">get_dynamic_deps()</a></h5>
<h3 style="padding-left: 0px;">Methods Defined or Overridden:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_Activity____init__">&lt;constructor&gt;</a>, <a href="#method_ba_Activity__add_actor_weak_ref">add_actor_weak_ref()</a>, <a href="#method_ba_Activity__create_player_node">create_player_node()</a>, <a href="#method_ba_Activity__end">end()</a>, <a href="#method_ba_Activity__handlemessage">handlemessage()</a>, <a href="#method_ba_Activity__has_begun">has_begun()</a>, <a href="#method_ba_Activity__has_ended">has_ended()</a>, <a href="#method_ba_Activity__has_transitioned_in">has_transitioned_in()</a>, <a href="#method_ba_Activity__is_expired">is_expired()</a>, <a href="#method_ba_Activity__is_transitioning_out">is_transitioning_out()</a>, <a href="#method_ba_Activity__on_begin">on_begin()</a>, <a href="#method_ba_Activity__on_expire">on_expire()</a>, <a href="#method_ba_Activity__on_player_join">on_player_join()</a>, <a href="#method_ba_Activity__on_player_leave">on_player_leave()</a>, <a href="#method_ba_Activity__on_team_join">on_team_join()</a>, <a href="#method_ba_Activity__on_team_leave">on_team_leave()</a>, <a href="#method_ba_Activity__on_transition_in">on_transition_in()</a>, <a href="#method_ba_Activity__on_transition_out">on_transition_out()</a>, <a href="#method_ba_Activity__retain_actor">retain_actor()</a></h5>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_Activity____init__"><strong>&lt;constructor&gt;</strong></a></h4>
@ -903,17 +903,23 @@ when done.</p>
<hr>
<h2><strong><a class="offsanchor" name="class_ba_AssetPackage">ba.AssetPackage</a></strong></h3>
<p style="padding-left: 30px;">inherits from: <a href="#class_ba__dep_StaticDepComponent">ba._dep.StaticDepComponent</a>, <a href="#class_ba_DepComponent">ba.DepComponent</a></p>
<p style="padding-left: 30px;">DepComponent representing a bundled package of game assets.</p>
<p style="padding-left: 30px;">inherits from: <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a></p>
<p style="padding-left: 30px;">DependencyComponent representing a bundled package of game assets.</p>
<h3 style="padding-left: 0px;">Methods Inherited:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba__dep_StaticDepComponent__dep_get_payload">dep_get_payload()</a>, <a href="#method_ba__dep_StaticDepComponent__get_dynamic_deps">get_dynamic_deps()</a></h5>
<h5 style="padding-left: 30px;"><a href="#method_ba_DependencyComponent__get_dynamic_deps">get_dynamic_deps()</a></h5>
<h3 style="padding-left: 0px;">Methods Defined or Overridden:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_AssetPackage____init__">&lt;constructor&gt;</a>, <a href="#method_ba_AssetPackage__getcollidemodel">getcollidemodel()</a>, <a href="#method_ba_AssetPackage__getdata">getdata()</a>, <a href="#method_ba_AssetPackage__getmodel">getmodel()</a>, <a href="#method_ba_AssetPackage__getsound">getsound()</a>, <a href="#method_ba_AssetPackage__gettexture">gettexture()</a>, <a href="#method_ba_AssetPackage__is_present">is_present()</a></h5>
<h5 style="padding-left: 30px;"><a href="#method_ba_AssetPackage____init__">&lt;constructor&gt;</a>, <a href="#method_ba_AssetPackage__dep_is_present">dep_is_present()</a>, <a href="#method_ba_AssetPackage__getcollidemodel">getcollidemodel()</a>, <a href="#method_ba_AssetPackage__getdata">getdata()</a>, <a href="#method_ba_AssetPackage__getmodel">getmodel()</a>, <a href="#method_ba_AssetPackage__getsound">getsound()</a>, <a href="#method_ba_AssetPackage__gettexture">gettexture()</a></h5>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_AssetPackage____init__"><strong>&lt;constructor&gt;</strong></a></h4>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">ba.AssetPackage()</span></p>
<p style="padding-left: 60px;">Instantiate a DepComponent.</p>
<p style="padding-left: 60px;">Instantiate a DependencyComponent.</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_AssetPackage__dep_is_present"><strong>dep_is_present()</strong></a></h4>
<h5 style="padding-left: 60px;"><span style="color: #CC6600;"><em>&lt;class method&gt;</span></em></h5>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">dep_is_present(config: Any = None) -&gt; bool </span></p>
<p style="padding-left: 60px;">Return whether this component/config is present on this device.</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_AssetPackage__getcollidemodel"><strong>getcollidemodel()</strong></a></h4>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">getcollidemodel(self, name: str) -&gt; <a href="#class_ba_CollideModel">ba.CollideModel</a></span></p>
@ -950,12 +956,6 @@ when done.</p>
<p style="padding-left: 60px;">Behavior is similar to <a href="#function_ba_gettexture">ba.gettexture</a>()</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_AssetPackage__is_present"><strong>is_present()</strong></a></h4>
<h5 style="padding-left: 60px;"><span style="color: #CC6600;"><em>&lt;class method&gt;</span></em></h5>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">is_present(config: Any = None) -&gt; bool </span></p>
<p style="padding-left: 60px;">Return whether this component/config is present on this device.</p>
<hr>
<h2><strong><a class="offsanchor" name="class_ba_Call">ba.Call</a></strong></h3>
<p style="padding-left: 30px;"><em>&lt;top level class&gt;</em>
@ -1229,7 +1229,7 @@ start_long_action(callback_when_done=<a href="#class_ba_ContextCall">ba.ContextC
<hr>
<h2><strong><a class="offsanchor" name="class_ba_CoopGameActivity">ba.CoopGameActivity</a></strong></h3>
<p style="padding-left: 30px;">inherits from: <a href="#class_ba_GameActivity">ba.GameActivity</a>, <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba__dep_InstancedDepComponent">ba._dep.InstancedDepComponent</a>, <a href="#class_ba_DepComponent">ba.DepComponent</a></p>
<p style="padding-left: 30px;">inherits from: <a href="#class_ba_GameActivity">ba.GameActivity</a>, <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a></p>
<p style="padding-left: 30px;">Base class for cooperative-mode games.</p>
<p style="padding-left: 30px;">Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a>
@ -1258,7 +1258,7 @@ start_long_action(callback_when_done=<a href="#class_ba_ContextCall">ba.ContextC
<p style="padding-left: 60px;"> If access is attempted before or after, raises a <a href="#class_ba_NotFoundError">ba.NotFoundError</a>.</p>
<h3 style="padding-left: 0px;">Methods Inherited:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_GameActivity__add_actor_weak_ref">add_actor_weak_ref()</a>, <a href="#method_ba_GameActivity__begin">begin()</a>, <a href="#method_ba_GameActivity__continue_or_end_game">continue_or_end_game()</a>, <a href="#method_ba_GameActivity__create_config_ui">create_config_ui()</a>, <a href="#method_ba_GameActivity__create_player_node">create_player_node()</a>, <a href="#method_ba_GameActivity__dep_get_payload">dep_get_payload()</a>, <a href="#method_ba_GameActivity__end">end()</a>, <a href="#method_ba_GameActivity__end_game">end_game()</a>, <a href="#method_ba_GameActivity__get_config_display_string">get_config_display_string()</a>, <a href="#method_ba_GameActivity__get_description">get_description()</a>, <a href="#method_ba_GameActivity__get_description_display_string">get_description_display_string()</a>, <a href="#method_ba_GameActivity__get_display_string">get_display_string()</a>, <a href="#method_ba_GameActivity__get_dynamic_deps">get_dynamic_deps()</a>, <a href="#method_ba_GameActivity__get_instance_description">get_instance_description()</a>, <a href="#method_ba_GameActivity__get_instance_display_string">get_instance_display_string()</a>, <a href="#method_ba_GameActivity__get_instance_scoreboard_description">get_instance_scoreboard_description()</a>, <a href="#method_ba_GameActivity__get_instance_scoreboard_display_string">get_instance_scoreboard_display_string()</a>, <a href="#method_ba_GameActivity__get_name">get_name()</a>, <a href="#method_ba_GameActivity__get_resolved_score_info">get_resolved_score_info()</a>, <a href="#method_ba_GameActivity__get_score_info">get_score_info()</a>, <a href="#method_ba_GameActivity__get_settings">get_settings()</a>, <a href="#method_ba_GameActivity__get_supported_maps">get_supported_maps()</a>, <a href="#method_ba_GameActivity__get_team_display_string">get_team_display_string()</a>, <a href="#method_ba_GameActivity__handlemessage">handlemessage()</a>, <a href="#method_ba_GameActivity__has_begun">has_begun()</a>, <a href="#method_ba_GameActivity__has_ended">has_ended()</a>, <a href="#method_ba_GameActivity__has_transitioned_in">has_transitioned_in()</a>, <a href="#method_ba_GameActivity__is_expired">is_expired()</a>, <a href="#method_ba_GameActivity__is_present">is_present()</a>, <a href="#method_ba_GameActivity__is_transitioning_out">is_transitioning_out()</a>, <a href="#method_ba_GameActivity__is_waiting_for_continue">is_waiting_for_continue()</a>, <a href="#method_ba_GameActivity__on_continue">on_continue()</a>, <a href="#method_ba_GameActivity__on_expire">on_expire()</a>, <a href="#method_ba_GameActivity__on_player_join">on_player_join()</a>, <a href="#method_ba_GameActivity__on_player_leave">on_player_leave()</a>, <a href="#method_ba_GameActivity__on_team_join">on_team_join()</a>, <a href="#method_ba_GameActivity__on_team_leave">on_team_leave()</a>, <a href="#method_ba_GameActivity__on_transition_in">on_transition_in()</a>, <a href="#method_ba_GameActivity__on_transition_out">on_transition_out()</a>, <a href="#method_ba_GameActivity__project_flag_stand">project_flag_stand()</a>, <a href="#method_ba_GameActivity__respawn_player">respawn_player()</a>, <a href="#method_ba_GameActivity__retain_actor">retain_actor()</a>, <a href="#method_ba_GameActivity__set_has_ended">set_has_ended()</a>, <a href="#method_ba_GameActivity__set_immediate_end">set_immediate_end()</a>, <a href="#method_ba_GameActivity__setup_standard_powerup_drops">setup_standard_powerup_drops()</a>, <a href="#method_ba_GameActivity__setup_standard_time_limit">setup_standard_time_limit()</a>, <a href="#method_ba_GameActivity__show_info">show_info()</a>, <a href="#method_ba_GameActivity__show_scoreboard_info">show_scoreboard_info()</a>, <a href="#method_ba_GameActivity__show_zoom_message">show_zoom_message()</a>, <a href="#method_ba_GameActivity__spawn_player">spawn_player()</a>, <a href="#method_ba_GameActivity__spawn_player_if_exists">spawn_player_if_exists()</a>, <a href="#method_ba_GameActivity__start_transition_in">start_transition_in()</a></h5>
<h5 style="padding-left: 30px;"><a href="#method_ba_GameActivity__add_actor_weak_ref">add_actor_weak_ref()</a>, <a href="#method_ba_GameActivity__begin">begin()</a>, <a href="#method_ba_GameActivity__continue_or_end_game">continue_or_end_game()</a>, <a href="#method_ba_GameActivity__create_config_ui">create_config_ui()</a>, <a href="#method_ba_GameActivity__create_player_node">create_player_node()</a>, <a href="#method_ba_GameActivity__dep_is_present">dep_is_present()</a>, <a href="#method_ba_GameActivity__end">end()</a>, <a href="#method_ba_GameActivity__end_game">end_game()</a>, <a href="#method_ba_GameActivity__get_config_display_string">get_config_display_string()</a>, <a href="#method_ba_GameActivity__get_description">get_description()</a>, <a href="#method_ba_GameActivity__get_description_display_string">get_description_display_string()</a>, <a href="#method_ba_GameActivity__get_display_string">get_display_string()</a>, <a href="#method_ba_GameActivity__get_dynamic_deps">get_dynamic_deps()</a>, <a href="#method_ba_GameActivity__get_instance_description">get_instance_description()</a>, <a href="#method_ba_GameActivity__get_instance_display_string">get_instance_display_string()</a>, <a href="#method_ba_GameActivity__get_instance_scoreboard_description">get_instance_scoreboard_description()</a>, <a href="#method_ba_GameActivity__get_instance_scoreboard_display_string">get_instance_scoreboard_display_string()</a>, <a href="#method_ba_GameActivity__get_name">get_name()</a>, <a href="#method_ba_GameActivity__get_resolved_score_info">get_resolved_score_info()</a>, <a href="#method_ba_GameActivity__get_score_info">get_score_info()</a>, <a href="#method_ba_GameActivity__get_settings">get_settings()</a>, <a href="#method_ba_GameActivity__get_supported_maps">get_supported_maps()</a>, <a href="#method_ba_GameActivity__get_team_display_string">get_team_display_string()</a>, <a href="#method_ba_GameActivity__handlemessage">handlemessage()</a>, <a href="#method_ba_GameActivity__has_begun">has_begun()</a>, <a href="#method_ba_GameActivity__has_ended">has_ended()</a>, <a href="#method_ba_GameActivity__has_transitioned_in">has_transitioned_in()</a>, <a href="#method_ba_GameActivity__is_expired">is_expired()</a>, <a href="#method_ba_GameActivity__is_transitioning_out">is_transitioning_out()</a>, <a href="#method_ba_GameActivity__is_waiting_for_continue">is_waiting_for_continue()</a>, <a href="#method_ba_GameActivity__on_continue">on_continue()</a>, <a href="#method_ba_GameActivity__on_expire">on_expire()</a>, <a href="#method_ba_GameActivity__on_player_join">on_player_join()</a>, <a href="#method_ba_GameActivity__on_player_leave">on_player_leave()</a>, <a href="#method_ba_GameActivity__on_team_join">on_team_join()</a>, <a href="#method_ba_GameActivity__on_team_leave">on_team_leave()</a>, <a href="#method_ba_GameActivity__on_transition_in">on_transition_in()</a>, <a href="#method_ba_GameActivity__on_transition_out">on_transition_out()</a>, <a href="#method_ba_GameActivity__project_flag_stand">project_flag_stand()</a>, <a href="#method_ba_GameActivity__respawn_player">respawn_player()</a>, <a href="#method_ba_GameActivity__retain_actor">retain_actor()</a>, <a href="#method_ba_GameActivity__set_has_ended">set_has_ended()</a>, <a href="#method_ba_GameActivity__set_immediate_end">set_immediate_end()</a>, <a href="#method_ba_GameActivity__setup_standard_powerup_drops">setup_standard_powerup_drops()</a>, <a href="#method_ba_GameActivity__setup_standard_time_limit">setup_standard_time_limit()</a>, <a href="#method_ba_GameActivity__show_info">show_info()</a>, <a href="#method_ba_GameActivity__show_scoreboard_info">show_scoreboard_info()</a>, <a href="#method_ba_GameActivity__show_zoom_message">show_zoom_message()</a>, <a href="#method_ba_GameActivity__spawn_player">spawn_player()</a>, <a href="#method_ba_GameActivity__spawn_player_if_exists">spawn_player_if_exists()</a>, <a href="#method_ba_GameActivity__start_transition_in">start_transition_in()</a></h5>
<h3 style="padding-left: 0px;">Methods Defined or Overridden:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_CoopGameActivity____init__">&lt;constructor&gt;</a>, <a href="#method_ba_CoopGameActivity__celebrate">celebrate()</a>, <a href="#method_ba_CoopGameActivity__fade_to_red">fade_to_red()</a>, <a href="#method_ba_CoopGameActivity__get_score_type">get_score_type()</a>, <a href="#method_ba_CoopGameActivity__on_begin">on_begin()</a>, <a href="#method_ba_CoopGameActivity__setup_low_life_warning_sound">setup_low_life_warning_sound()</a>, <a href="#method_ba_CoopGameActivity__spawn_player_spaz">spawn_player_spaz()</a>, <a href="#method_ba_CoopGameActivity__supports_session_type">supports_session_type()</a></h5>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_CoopGameActivity____init__"><strong>&lt;constructor&gt;</strong></a></h4>
@ -1386,59 +1386,15 @@ Note that this call will block if the data has not yet been loaded,
so it can be beneficial to plan a short bit of time between when
the data object is requested and when it's value is accessed.</p>
<hr>
<h2><strong><a class="offsanchor" name="class_ba_DepComponent">ba.DepComponent</a></strong></h3>
<p style="padding-left: 30px;"><em>&lt;top level class&gt;</em>
</p>
<p style="padding-left: 30px;">Base class for all classes that can act as or use dependencies.</p>
<p style="padding-left: 30px;">Category: <a href="#class_category_Dependency_Classes">Dependency Classes</a>
</p>
<h3 style="padding-left: 0px;">Methods:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_DepComponent____init__">&lt;constructor&gt;</a>, <a href="#method_ba_DepComponent__dep_get_payload">dep_get_payload()</a>, <a href="#method_ba_DepComponent__get_dynamic_deps">get_dynamic_deps()</a>, <a href="#method_ba_DepComponent__is_present">is_present()</a></h5>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DepComponent____init__"><strong>&lt;constructor&gt;</strong></a></h4>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">ba.DepComponent()</span></p>
<p style="padding-left: 60px;">Instantiate a DepComponent.</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DepComponent__dep_get_payload"><strong>dep_get_payload()</strong></a></h4>
<h5 style="padding-left: 60px;"><span style="color: #CC6600;"><em>&lt;class method&gt;</span></em></h5>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">dep_get_payload(depdata: DepData) -&gt; Any </span></p>
<p style="padding-left: 60px;">Return user-facing data for a loaded dep.</p>
<p style="padding-left: 60px;">If this dep does not yet have a 'payload' value, it should
be generated and cached. Otherwise the existing value
should be returned.
This is the value given for a DepComponent when accessed
through a Dependency instance on a live object, etc.</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DepComponent__get_dynamic_deps"><strong>get_dynamic_deps()</strong></a></h4>
<h5 style="padding-left: 60px;"><span style="color: #CC6600;"><em>&lt;class method&gt;</span></em></h5>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">get_dynamic_deps(config: Any = None) -&gt; List[Dependency] </span></p>
<p style="padding-left: 60px;">Return any dynamically-calculated deps for this component/config.</p>
<p style="padding-left: 60px;">Deps declared statically as part of the class do not need to be
included here; this is only for additional deps that may vary based
on the dep config value. (for instance a map required by a game type)</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DepComponent__is_present"><strong>is_present()</strong></a></h4>
<h5 style="padding-left: 60px;"><span style="color: #CC6600;"><em>&lt;class method&gt;</span></em></h5>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">is_present(config: Any = None) -&gt; bool </span></p>
<p style="padding-left: 60px;">Return whether this component/config is present on this device.</p>
<hr>
<h2><strong><a class="offsanchor" name="class_ba_Dependency">ba.Dependency</a></strong></h3>
<p style="padding-left: 30px;">inherits from: <a href="#class_typing_Generic">typing.Generic</a></p>
<p style="padding-left: 30px;">A dependency on a DepComponent (with an optional config).</p>
<p style="padding-left: 30px;">A dependency on a DependencyComponent (with an optional config).</p>
<p style="padding-left: 30px;">Category: <a href="#class_category_Dependency_Classes">Dependency Classes</a></p>
<p style="padding-left: 30px;"> This class is used to request and access functionality provided
by other DepComponent classes from a DepComponent class.
by other DependencyComponent classes from a DependencyComponent class.
The class functions as a descriptor, allowing dependencies to
be added at a class level much the same as properties or methods
and then used with class instances to access those dependencies.
@ -1452,7 +1408,7 @@ on the dep config value. (for instance a map required by a game type)</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_Dependency____init__"><strong>&lt;constructor&gt;</strong></a></h4>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">ba.Dependency(cls: Type[T], config: Any = None)</span></p>
<p style="padding-left: 60px;">Instantiate a Dependency given a <a href="#class_ba_DepComponent">ba.DepComponent</a> subtype.</p>
<p style="padding-left: 60px;">Instantiate a Dependency given a <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a> type.</p>
<p style="padding-left: 60px;">Optionally, an arbitrary object can be passed as 'config' to
influence dependency calculation for the target class.</p>
@ -1462,6 +1418,38 @@ influence dependency calculation for the target class.</p>
<p style="padding-left: 60px;">Return the dependency's hash, calculating it if necessary.</p>
<hr>
<h2><strong><a class="offsanchor" name="class_ba_DependencyComponent">ba.DependencyComponent</a></strong></h3>
<p style="padding-left: 30px;"><em>&lt;top level class&gt;</em>
</p>
<p style="padding-left: 30px;">Base class for all classes that can act as or use dependencies.</p>
<p style="padding-left: 30px;">Category: <a href="#class_category_Dependency_Classes">Dependency Classes</a>
</p>
<h3 style="padding-left: 0px;">Methods:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_DependencyComponent____init__">&lt;constructor&gt;</a>, <a href="#method_ba_DependencyComponent__dep_is_present">dep_is_present()</a>, <a href="#method_ba_DependencyComponent__get_dynamic_deps">get_dynamic_deps()</a></h5>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DependencyComponent____init__"><strong>&lt;constructor&gt;</strong></a></h4>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">ba.DependencyComponent()</span></p>
<p style="padding-left: 60px;">Instantiate a DependencyComponent.</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DependencyComponent__dep_is_present"><strong>dep_is_present()</strong></a></h4>
<h5 style="padding-left: 60px;"><span style="color: #CC6600;"><em>&lt;class method&gt;</span></em></h5>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">dep_is_present(config: Any = None) -&gt; bool </span></p>
<p style="padding-left: 60px;">Return whether this component/config is present on this device.</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DependencyComponent__get_dynamic_deps"><strong>get_dynamic_deps()</strong></a></h4>
<h5 style="padding-left: 60px;"><span style="color: #CC6600;"><em>&lt;class method&gt;</span></em></h5>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">get_dynamic_deps(config: Any = None) -&gt; List[Dependency] </span></p>
<p style="padding-left: 60px;">Return any dynamically-calculated deps for this component/config.</p>
<p style="padding-left: 60px;">Deps declared statically as part of the class do not need to be
included here; this is only for additional deps that may vary based
on the dep config value. (for instance a map required by a game type)</p>
<hr>
<h2><strong><a class="offsanchor" name="class_ba_DependencyError">ba.DependencyError</a></strong></h3>
<p style="padding-left: 30px;">inherits from: Exception, BaseException</p>
@ -1484,33 +1472,48 @@ influence dependency calculation for the target class.</p>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">ba.DependencyError(deps: List[<a href="#class_ba_Dependency">ba.Dependency</a>])</span></p>
<hr>
<h2><strong><a class="offsanchor" name="class_ba_DepSet">ba.DepSet</a></strong></h3>
<h2><strong><a class="offsanchor" name="class_ba_DependencySet">ba.DependencySet</a></strong></h3>
<p style="padding-left: 30px;">inherits from: <a href="#class_typing_Generic">typing.Generic</a></p>
<p style="padding-left: 30px;">Set of resolved dependencies and their associated data.</p>
<h3 style="padding-left: 0px;">Methods:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_DepSet____init__">&lt;constructor&gt;</a>, <a href="#method_ba_DepSet__get_asset_package_ids">get_asset_package_ids()</a>, <a href="#method_ba_DepSet__load">load()</a>, <a href="#method_ba_DepSet__resolve">resolve()</a></h5>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DepSet____init__"><strong>&lt;constructor&gt;</strong></a></h4>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">ba.DepSet(root: Dependency[TI])</span></p>
<p style="padding-left: 30px;"> To use DependencyComponents, a set must be created, resolved, and then
loaded. The DependencyComponents are only valid while the set remains
in existence.
</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DepSet__get_asset_package_ids"><strong>get_asset_package_ids()</strong></a></h4>
<h3 style="padding-left: 0px;">Attributes:</h3>
<h5 style="padding-left: 30px;"><a href="#attr_ba_DependencySet__resolved">resolved</a>, <a href="#attr_ba_DependencySet__root">root</a></h5>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="attr_ba_DependencySet__resolved"><strong>resolved</strong></a></h4>
<p style="padding-left: 60px;"><span style="color: #666677;">bool</span></p>
<p style="padding-left: 60px;">Whether this set has been successfully resolved.</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="attr_ba_DependencySet__root"><strong>root</strong></a></h4>
<p style="padding-left: 60px;"><span style="color: #666677;">T</span></p>
<p style="padding-left: 60px;">The instantiated root DependencyComponent instance for the set.</p>
<h3 style="padding-left: 0px;">Methods:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_DependencySet____init__">&lt;constructor&gt;</a>, <a href="#method_ba_DependencySet__get_asset_package_ids">get_asset_package_ids()</a>, <a href="#method_ba_DependencySet__load">load()</a>, <a href="#method_ba_DependencySet__resolve">resolve()</a></h5>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DependencySet____init__"><strong>&lt;constructor&gt;</strong></a></h4>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">ba.DependencySet(root_dependency: Dependency[T])</span></p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DependencySet__get_asset_package_ids"><strong>get_asset_package_ids()</strong></a></h4>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">get_asset_package_ids(self) -&gt; Set[str]</span></p>
<p style="padding-left: 60px;">Return the set of asset-package-ids required by this dep-set.</p>
<p style="padding-left: 60px;">Must be called on a resolved dep-set.</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DepSet__load"><strong>load()</strong></a></h4>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">load(self) -&gt; Type[TI]</span></p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DependencySet__load"><strong>load()</strong></a></h4>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">load(self) -&gt; None</span></p>
<p style="padding-left: 60px;">Attach the resolved set to the current context.</p>
<p style="padding-left: 60px;">Instantiate all DependencyComponents in the set.</p>
<p style="padding-left: 60px;">Returns a wrapper which can be used to instantiate the root dep.</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DepSet__resolve"><strong>resolve()</strong></a></h4>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_DependencySet__resolve"><strong>resolve()</strong></a></h4>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">resolve(self) -&gt; None</span></p>
<p style="padding-left: 60px;">Resolve the total set of required dependencies for the set.</p>
<p style="padding-left: 60px;">Resolve the complete set of required dependencies for this set.</p>
<p style="padding-left: 60px;">Raises a <a href="#class_ba_DependencyError">ba.DependencyError</a> if dependencies are missing (or other
Exception types on other errors).</p>
@ -1616,7 +1619,7 @@ its time with lingering corpses, sound effects, etc.</p>
<hr>
<h2><strong><a class="offsanchor" name="class_ba_GameActivity">ba.GameActivity</a></strong></h3>
<p style="padding-left: 30px;">inherits from: <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba__dep_InstancedDepComponent">ba._dep.InstancedDepComponent</a>, <a href="#class_ba_DepComponent">ba.DepComponent</a></p>
<p style="padding-left: 30px;">inherits from: <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a></p>
<p style="padding-left: 30px;">Common base class for all game ba.Activities.</p>
<p style="padding-left: 30px;">Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a>
@ -1645,7 +1648,7 @@ its time with lingering corpses, sound effects, etc.</p>
<p style="padding-left: 60px;"> If access is attempted before or after, raises a <a href="#class_ba_NotFoundError">ba.NotFoundError</a>.</p>
<h3 style="padding-left: 0px;">Methods Inherited:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_Activity__add_actor_weak_ref">add_actor_weak_ref()</a>, <a href="#method_ba_Activity__begin">begin()</a>, <a href="#method_ba_Activity__create_player_node">create_player_node()</a>, <a href="#method_ba_Activity__dep_get_payload">dep_get_payload()</a>, <a href="#method_ba_Activity__get_dynamic_deps">get_dynamic_deps()</a>, <a href="#method_ba_Activity__has_begun">has_begun()</a>, <a href="#method_ba_Activity__has_ended">has_ended()</a>, <a href="#method_ba_Activity__has_transitioned_in">has_transitioned_in()</a>, <a href="#method_ba_Activity__is_expired">is_expired()</a>, <a href="#method_ba_Activity__is_present">is_present()</a>, <a href="#method_ba_Activity__is_transitioning_out">is_transitioning_out()</a>, <a href="#method_ba_Activity__on_expire">on_expire()</a>, <a href="#method_ba_Activity__on_team_join">on_team_join()</a>, <a href="#method_ba_Activity__on_team_leave">on_team_leave()</a>, <a href="#method_ba_Activity__on_transition_out">on_transition_out()</a>, <a href="#method_ba_Activity__retain_actor">retain_actor()</a>, <a href="#method_ba_Activity__set_has_ended">set_has_ended()</a>, <a href="#method_ba_Activity__set_immediate_end">set_immediate_end()</a>, <a href="#method_ba_Activity__start_transition_in">start_transition_in()</a></h5>
<h5 style="padding-left: 30px;"><a href="#method_ba_Activity__add_actor_weak_ref">add_actor_weak_ref()</a>, <a href="#method_ba_Activity__begin">begin()</a>, <a href="#method_ba_Activity__create_player_node">create_player_node()</a>, <a href="#method_ba_Activity__dep_is_present">dep_is_present()</a>, <a href="#method_ba_Activity__get_dynamic_deps">get_dynamic_deps()</a>, <a href="#method_ba_Activity__has_begun">has_begun()</a>, <a href="#method_ba_Activity__has_ended">has_ended()</a>, <a href="#method_ba_Activity__has_transitioned_in">has_transitioned_in()</a>, <a href="#method_ba_Activity__is_expired">is_expired()</a>, <a href="#method_ba_Activity__is_transitioning_out">is_transitioning_out()</a>, <a href="#method_ba_Activity__on_expire">on_expire()</a>, <a href="#method_ba_Activity__on_team_join">on_team_join()</a>, <a href="#method_ba_Activity__on_team_leave">on_team_leave()</a>, <a href="#method_ba_Activity__on_transition_out">on_transition_out()</a>, <a href="#method_ba_Activity__retain_actor">retain_actor()</a>, <a href="#method_ba_Activity__set_has_ended">set_has_ended()</a>, <a href="#method_ba_Activity__set_immediate_end">set_immediate_end()</a>, <a href="#method_ba_Activity__start_transition_in">start_transition_in()</a></h5>
<h3 style="padding-left: 0px;">Methods Defined or Overridden:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_GameActivity____init__">&lt;constructor&gt;</a>, <a href="#method_ba_GameActivity__continue_or_end_game">continue_or_end_game()</a>, <a href="#method_ba_GameActivity__create_config_ui">create_config_ui()</a>, <a href="#method_ba_GameActivity__end">end()</a>, <a href="#method_ba_GameActivity__end_game">end_game()</a>, <a href="#method_ba_GameActivity__get_config_display_string">get_config_display_string()</a>, <a href="#method_ba_GameActivity__get_description">get_description()</a>, <a href="#method_ba_GameActivity__get_description_display_string">get_description_display_string()</a>, <a href="#method_ba_GameActivity__get_display_string">get_display_string()</a>, <a href="#method_ba_GameActivity__get_instance_description">get_instance_description()</a>, <a href="#method_ba_GameActivity__get_instance_display_string">get_instance_display_string()</a>, <a href="#method_ba_GameActivity__get_instance_scoreboard_description">get_instance_scoreboard_description()</a>, <a href="#method_ba_GameActivity__get_instance_scoreboard_display_string">get_instance_scoreboard_display_string()</a>, <a href="#method_ba_GameActivity__get_name">get_name()</a>, <a href="#method_ba_GameActivity__get_resolved_score_info">get_resolved_score_info()</a>, <a href="#method_ba_GameActivity__get_score_info">get_score_info()</a>, <a href="#method_ba_GameActivity__get_settings">get_settings()</a>, <a href="#method_ba_GameActivity__get_supported_maps">get_supported_maps()</a>, <a href="#method_ba_GameActivity__get_team_display_string">get_team_display_string()</a>, <a href="#method_ba_GameActivity__handlemessage">handlemessage()</a>, <a href="#method_ba_GameActivity__is_waiting_for_continue">is_waiting_for_continue()</a>, <a href="#method_ba_GameActivity__on_begin">on_begin()</a>, <a href="#method_ba_GameActivity__on_continue">on_continue()</a>, <a href="#method_ba_GameActivity__on_player_join">on_player_join()</a>, <a href="#method_ba_GameActivity__on_player_leave">on_player_leave()</a>, <a href="#method_ba_GameActivity__on_transition_in">on_transition_in()</a>, <a href="#method_ba_GameActivity__project_flag_stand">project_flag_stand()</a>, <a href="#method_ba_GameActivity__respawn_player">respawn_player()</a>, <a href="#method_ba_GameActivity__setup_standard_powerup_drops">setup_standard_powerup_drops()</a>, <a href="#method_ba_GameActivity__setup_standard_time_limit">setup_standard_time_limit()</a>, <a href="#method_ba_GameActivity__show_info">show_info()</a>, <a href="#method_ba_GameActivity__show_scoreboard_info">show_scoreboard_info()</a>, <a href="#method_ba_GameActivity__show_zoom_message">show_zoom_message()</a>, <a href="#method_ba_GameActivity__spawn_player">spawn_player()</a>, <a href="#method_ba_GameActivity__spawn_player_if_exists">spawn_player_if_exists()</a>, <a href="#method_ba_GameActivity__spawn_player_spaz">spawn_player_spaz()</a>, <a href="#method_ba_GameActivity__supports_session_type">supports_session_type()</a></h5>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_GameActivity____init__"><strong>&lt;constructor&gt;</strong></a></h4>
@ -3303,11 +3306,11 @@ list in <a href="#class_ba_Activity">ba.Activity</a>; not this.</p>
<h3 style="padding-left: 0px;">Methods:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_Session____init__">&lt;constructor&gt;</a>, <a href="#method_ba_Session__begin_next_activity">begin_next_activity()</a>, <a href="#method_ba_Session__end">end()</a>, <a href="#method_ba_Session__end_activity">end_activity()</a>, <a href="#method_ba_Session__get_custom_menu_entries">get_custom_menu_entries()</a>, <a href="#method_ba_Session__getactivity">getactivity()</a>, <a href="#method_ba_Session__handlemessage">handlemessage()</a>, <a href="#method_ba_Session__on_activity_end">on_activity_end()</a>, <a href="#method_ba_Session__on_player_leave">on_player_leave()</a>, <a href="#method_ba_Session__on_player_request">on_player_request()</a>, <a href="#method_ba_Session__on_team_join">on_team_join()</a>, <a href="#method_ba_Session__on_team_leave">on_team_leave()</a>, <a href="#method_ba_Session__set_activity">set_activity()</a></h5>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_Session____init__"><strong>&lt;constructor&gt;</strong></a></h4>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">ba.Session(depsets: Sequence[<a href="#class_ba_DepSet">ba.DepSet</a>], team_names: Sequence[str] = None, team_colors: Sequence[Sequence[float]] = None, use_team_colors: bool = True, min_players: int = 1, max_players: int = 8, allow_mid_activity_joins: bool = True)</span></p>
<p style="padding-left: 110px; text-indent: -50px;"><span style="color: #666677;">ba.Session(depsets: Sequence[<a href="#class_ba_DependencySet">ba.DependencySet</a>], team_names: Sequence[str] = None, team_colors: Sequence[Sequence[float]] = None, use_team_colors: bool = True, min_players: int = 1, max_players: int = 8, allow_mid_activity_joins: bool = True)</span></p>
<p style="padding-left: 60px;">Instantiate a session.</p>
<p style="padding-left: 60px;">depsets should be a sequence of successfully resolved <a href="#class_ba_DepSet">ba.DepSet</a>
<p style="padding-left: 60px;">depsets should be a sequence of successfully resolved <a href="#class_ba_DependencySet">ba.DependencySet</a>
instances; one for each <a href="#class_ba_Activity">ba.Activity</a> the session may potentially run.</p>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_Session__begin_next_activity"><strong>begin_next_activity()</strong></a></h4>
@ -3754,7 +3757,7 @@ another <a href="#class_ba_Activity">ba.Activity</a>.</p>
<hr>
<h2><strong><a class="offsanchor" name="class_ba_TeamGameActivity">ba.TeamGameActivity</a></strong></h3>
<p style="padding-left: 30px;">inherits from: <a href="#class_ba_GameActivity">ba.GameActivity</a>, <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba__dep_InstancedDepComponent">ba._dep.InstancedDepComponent</a>, <a href="#class_ba_DepComponent">ba.DepComponent</a></p>
<p style="padding-left: 30px;">inherits from: <a href="#class_ba_GameActivity">ba.GameActivity</a>, <a href="#class_ba_Activity">ba.Activity</a>, <a href="#class_ba_DependencyComponent">ba.DependencyComponent</a></p>
<p style="padding-left: 30px;">Base class for teams and free-for-all mode games.</p>
<p style="padding-left: 30px;">Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
@ -3786,7 +3789,7 @@ another <a href="#class_ba_Activity">ba.Activity</a>.</p>
<p style="padding-left: 60px;"> If access is attempted before or after, raises a <a href="#class_ba_NotFoundError">ba.NotFoundError</a>.</p>
<h3 style="padding-left: 0px;">Methods Inherited:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_GameActivity__add_actor_weak_ref">add_actor_weak_ref()</a>, <a href="#method_ba_GameActivity__begin">begin()</a>, <a href="#method_ba_GameActivity__continue_or_end_game">continue_or_end_game()</a>, <a href="#method_ba_GameActivity__create_config_ui">create_config_ui()</a>, <a href="#method_ba_GameActivity__create_player_node">create_player_node()</a>, <a href="#method_ba_GameActivity__dep_get_payload">dep_get_payload()</a>, <a href="#method_ba_GameActivity__end_game">end_game()</a>, <a href="#method_ba_GameActivity__get_config_display_string">get_config_display_string()</a>, <a href="#method_ba_GameActivity__get_description">get_description()</a>, <a href="#method_ba_GameActivity__get_description_display_string">get_description_display_string()</a>, <a href="#method_ba_GameActivity__get_display_string">get_display_string()</a>, <a href="#method_ba_GameActivity__get_dynamic_deps">get_dynamic_deps()</a>, <a href="#method_ba_GameActivity__get_instance_description">get_instance_description()</a>, <a href="#method_ba_GameActivity__get_instance_display_string">get_instance_display_string()</a>, <a href="#method_ba_GameActivity__get_instance_scoreboard_description">get_instance_scoreboard_description()</a>, <a href="#method_ba_GameActivity__get_instance_scoreboard_display_string">get_instance_scoreboard_display_string()</a>, <a href="#method_ba_GameActivity__get_name">get_name()</a>, <a href="#method_ba_GameActivity__get_resolved_score_info">get_resolved_score_info()</a>, <a href="#method_ba_GameActivity__get_score_info">get_score_info()</a>, <a href="#method_ba_GameActivity__get_settings">get_settings()</a>, <a href="#method_ba_GameActivity__get_supported_maps">get_supported_maps()</a>, <a href="#method_ba_GameActivity__get_team_display_string">get_team_display_string()</a>, <a href="#method_ba_GameActivity__handlemessage">handlemessage()</a>, <a href="#method_ba_GameActivity__has_begun">has_begun()</a>, <a href="#method_ba_GameActivity__has_ended">has_ended()</a>, <a href="#method_ba_GameActivity__has_transitioned_in">has_transitioned_in()</a>, <a href="#method_ba_GameActivity__is_expired">is_expired()</a>, <a href="#method_ba_GameActivity__is_present">is_present()</a>, <a href="#method_ba_GameActivity__is_transitioning_out">is_transitioning_out()</a>, <a href="#method_ba_GameActivity__is_waiting_for_continue">is_waiting_for_continue()</a>, <a href="#method_ba_GameActivity__on_continue">on_continue()</a>, <a href="#method_ba_GameActivity__on_expire">on_expire()</a>, <a href="#method_ba_GameActivity__on_player_join">on_player_join()</a>, <a href="#method_ba_GameActivity__on_player_leave">on_player_leave()</a>, <a href="#method_ba_GameActivity__on_team_join">on_team_join()</a>, <a href="#method_ba_GameActivity__on_team_leave">on_team_leave()</a>, <a href="#method_ba_GameActivity__on_transition_out">on_transition_out()</a>, <a href="#method_ba_GameActivity__project_flag_stand">project_flag_stand()</a>, <a href="#method_ba_GameActivity__respawn_player">respawn_player()</a>, <a href="#method_ba_GameActivity__retain_actor">retain_actor()</a>, <a href="#method_ba_GameActivity__set_has_ended">set_has_ended()</a>, <a href="#method_ba_GameActivity__set_immediate_end">set_immediate_end()</a>, <a href="#method_ba_GameActivity__setup_standard_powerup_drops">setup_standard_powerup_drops()</a>, <a href="#method_ba_GameActivity__setup_standard_time_limit">setup_standard_time_limit()</a>, <a href="#method_ba_GameActivity__show_info">show_info()</a>, <a href="#method_ba_GameActivity__show_scoreboard_info">show_scoreboard_info()</a>, <a href="#method_ba_GameActivity__show_zoom_message">show_zoom_message()</a>, <a href="#method_ba_GameActivity__spawn_player">spawn_player()</a>, <a href="#method_ba_GameActivity__spawn_player_if_exists">spawn_player_if_exists()</a>, <a href="#method_ba_GameActivity__start_transition_in">start_transition_in()</a></h5>
<h5 style="padding-left: 30px;"><a href="#method_ba_GameActivity__add_actor_weak_ref">add_actor_weak_ref()</a>, <a href="#method_ba_GameActivity__begin">begin()</a>, <a href="#method_ba_GameActivity__continue_or_end_game">continue_or_end_game()</a>, <a href="#method_ba_GameActivity__create_config_ui">create_config_ui()</a>, <a href="#method_ba_GameActivity__create_player_node">create_player_node()</a>, <a href="#method_ba_GameActivity__dep_is_present">dep_is_present()</a>, <a href="#method_ba_GameActivity__end_game">end_game()</a>, <a href="#method_ba_GameActivity__get_config_display_string">get_config_display_string()</a>, <a href="#method_ba_GameActivity__get_description">get_description()</a>, <a href="#method_ba_GameActivity__get_description_display_string">get_description_display_string()</a>, <a href="#method_ba_GameActivity__get_display_string">get_display_string()</a>, <a href="#method_ba_GameActivity__get_dynamic_deps">get_dynamic_deps()</a>, <a href="#method_ba_GameActivity__get_instance_description">get_instance_description()</a>, <a href="#method_ba_GameActivity__get_instance_display_string">get_instance_display_string()</a>, <a href="#method_ba_GameActivity__get_instance_scoreboard_description">get_instance_scoreboard_description()</a>, <a href="#method_ba_GameActivity__get_instance_scoreboard_display_string">get_instance_scoreboard_display_string()</a>, <a href="#method_ba_GameActivity__get_name">get_name()</a>, <a href="#method_ba_GameActivity__get_resolved_score_info">get_resolved_score_info()</a>, <a href="#method_ba_GameActivity__get_score_info">get_score_info()</a>, <a href="#method_ba_GameActivity__get_settings">get_settings()</a>, <a href="#method_ba_GameActivity__get_supported_maps">get_supported_maps()</a>, <a href="#method_ba_GameActivity__get_team_display_string">get_team_display_string()</a>, <a href="#method_ba_GameActivity__handlemessage">handlemessage()</a>, <a href="#method_ba_GameActivity__has_begun">has_begun()</a>, <a href="#method_ba_GameActivity__has_ended">has_ended()</a>, <a href="#method_ba_GameActivity__has_transitioned_in">has_transitioned_in()</a>, <a href="#method_ba_GameActivity__is_expired">is_expired()</a>, <a href="#method_ba_GameActivity__is_transitioning_out">is_transitioning_out()</a>, <a href="#method_ba_GameActivity__is_waiting_for_continue">is_waiting_for_continue()</a>, <a href="#method_ba_GameActivity__on_continue">on_continue()</a>, <a href="#method_ba_GameActivity__on_expire">on_expire()</a>, <a href="#method_ba_GameActivity__on_player_join">on_player_join()</a>, <a href="#method_ba_GameActivity__on_player_leave">on_player_leave()</a>, <a href="#method_ba_GameActivity__on_team_join">on_team_join()</a>, <a href="#method_ba_GameActivity__on_team_leave">on_team_leave()</a>, <a href="#method_ba_GameActivity__on_transition_out">on_transition_out()</a>, <a href="#method_ba_GameActivity__project_flag_stand">project_flag_stand()</a>, <a href="#method_ba_GameActivity__respawn_player">respawn_player()</a>, <a href="#method_ba_GameActivity__retain_actor">retain_actor()</a>, <a href="#method_ba_GameActivity__set_has_ended">set_has_ended()</a>, <a href="#method_ba_GameActivity__set_immediate_end">set_immediate_end()</a>, <a href="#method_ba_GameActivity__setup_standard_powerup_drops">setup_standard_powerup_drops()</a>, <a href="#method_ba_GameActivity__setup_standard_time_limit">setup_standard_time_limit()</a>, <a href="#method_ba_GameActivity__show_info">show_info()</a>, <a href="#method_ba_GameActivity__show_scoreboard_info">show_scoreboard_info()</a>, <a href="#method_ba_GameActivity__show_zoom_message">show_zoom_message()</a>, <a href="#method_ba_GameActivity__spawn_player">spawn_player()</a>, <a href="#method_ba_GameActivity__spawn_player_if_exists">spawn_player_if_exists()</a>, <a href="#method_ba_GameActivity__start_transition_in">start_transition_in()</a></h5>
<h3 style="padding-left: 0px;">Methods Defined or Overridden:</h3>
<h5 style="padding-left: 30px;"><a href="#method_ba_TeamGameActivity____init__">&lt;constructor&gt;</a>, <a href="#method_ba_TeamGameActivity__end">end()</a>, <a href="#method_ba_TeamGameActivity__on_begin">on_begin()</a>, <a href="#method_ba_TeamGameActivity__on_transition_in">on_transition_in()</a>, <a href="#method_ba_TeamGameActivity__spawn_player_spaz">spawn_player_spaz()</a>, <a href="#method_ba_TeamGameActivity__supports_session_type">supports_session_type()</a></h5>
<h4 style="padding-left: 30px;"><a class="offsanchor" name="method_ba_TeamGameActivity____init__"><strong>&lt;constructor&gt;</strong></a></h4>

199
tools/cloudtool Executable file
View File

@ -0,0 +1,199 @@
#!/usr/bin/env python3.7
# Copyright (c) 2011-2019 Eric Froemling
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# -----------------------------------------------------------------------------
"""A tool for interacting with ballistica's cloud services.
This facilitates workflows such as creating asset-bundles, etc.
"""
from __future__ import annotations
import sys
import os
from typing import TYPE_CHECKING
import urllib.request
import urllib.parse
import urllib.error
from dataclasses import dataclass
from pathlib import Path
import json
if TYPE_CHECKING:
from typing import Optional, Dict, Any
# Version is sent to the master-server with all commands. Can be incremented
# if we need to change behavior server-side to go along with client changes.
VERSION = 1
TOOL_NAME = 'cloudtool'
# Set CLOUDTOOL_LOCAL env var to 1 to test with a locally-run master-server.
MASTER_SERVER_ADDRESS = ('http://localhost:23524'
if os.environ.get('CLOUDTOOL_LOCAL') == '1' else
'https://bamaster.appspot.com')
USER_AGENT_STRING = 'cloudtool'
CACHE_DIR = Path('.cache/cloudtool')
CACHE_DATA_PATH = Path(CACHE_DIR, 'state')
CLRHDR = '\033[95m' # Header.
CLRGRN = '\033[92m' # Green.
CLRBLU = '\033[94m' # Glue.
CLRRED = '\033[91m' # Red.
CLREND = '\033[0m' # End.
CMD_LOGIN = 'login'
CMD_LOGOUT = 'logout'
CMD_HELP = 'help'
@dataclass
class StateData:
"""Persistent state data stored to disk."""
login_token: Optional[str] = None
@dataclass
class Response:
"""Response data from the master server for a command."""
message: Optional[str]
error: Optional[str]
data: Any
class CleanError(Exception):
"""Exception resulting in a clean error string print and exit."""
class App:
"""Context for a run of the tool."""
def __init__(self) -> None:
self._state = StateData()
def run(self) -> None:
"""Run the tool."""
# Make reasonably sure we're being run from project root.
if not os.path.exists(f'tools/{TOOL_NAME}'):
raise CleanError(
'This tool must be run from ballistica project root.')
self._load_cache()
if len(sys.argv) < 2:
raise CleanError(
f'Invalid args. Run "cloudtool help" for usage info.')
cmd = sys.argv[1]
if cmd == CMD_LOGIN:
self.do_login()
elif cmd == CMD_LOGOUT:
self.do_logout()
else:
# For all other commands, simply pass them to the server verbatim.
self.do_misc_command()
self._save_cache()
def _load_cache(self) -> None:
if not os.path.exists(CACHE_DATA_PATH):
return
try:
with open(CACHE_DATA_PATH, 'r') as infile:
self._state = StateData(**json.loads(infile.read()))
except Exception:
print(CLRRED +
f'Error loading {TOOL_NAME} data; resetting to defaults.' +
CLREND)
def _save_cache(self) -> None:
if not CACHE_DIR.exists():
CACHE_DIR.mkdir(parents=True, exist_ok=True)
with open(CACHE_DATA_PATH, 'w') as outfile:
outfile.write(json.dumps(self._state.__dict__))
def _servercmd(self, cmd: str, data: Dict) -> Response:
"""Issue a command to the server and get a response."""
# We do all communication through POST requests to the server.
response_raw = urllib.request.urlopen(
urllib.request.Request(
(MASTER_SERVER_ADDRESS + '/cloudtoolcmd'),
urllib.parse.urlencode({
'c': cmd,
'v': VERSION,
't': json.dumps(self._state.login_token),
'd': json.dumps(data)
}).encode(), {'User-Agent': USER_AGENT_STRING}))
output = json.loads(response_raw.read().decode())
assert isinstance(output, dict)
response = Response(message=output['m'],
data=output['d'],
error=output['e'])
# Handle errors and messages which are common to all command types.
if response.error is not None:
raise CleanError(response.error)
if response.message is not None:
print(response.message)
return response
def do_login(self) -> None:
"""Run the login command."""
if len(sys.argv) != 3:
raise CleanError('Expected a login code.')
login_code = sys.argv[2]
response = self._servercmd('login', {'c': login_code})
# If the command returned cleanly, we should have a token we can use
# to log in.
token = response.data['logintoken']
assert isinstance(token, str)
aname = response.data['accountname']
assert isinstance(aname, str)
print(f'{CLRGRN}Now logged in as {aname}.{CLREND}')
self._state.login_token = token
def do_logout(self) -> None:
"""Run the logout command."""
self._state.login_token = None
print(f'{CLRGRN}Cloudtool is now logged out.{CLREND}')
def do_misc_command(self) -> None:
"""Run a miscellaneous command."""
# We don't do anything special with the response here; the normal
# error-handling/message-printing is all that happens.
self._servercmd('misc', {'a': sys.argv[1:]})
if __name__ == '__main__':
try:
App().run()
except CleanError as exc:
if str(exc):
print(f'{CLRRED}{exc}{CLREND}')
sys.exit(-1)

View File

@ -447,9 +447,9 @@ def makefile_target_list() -> None:
return ' - ' + doc
return doc
print('--------------------------\n'
'Available Makefile Targets\n'
'--------------------------')
print('----------------------\n'
'Available Make Targets\n'
'----------------------')
entries: List[_Entry] = []
for i, line in enumerate(lines):

View File

@ -711,14 +711,16 @@ def checkenv() -> None:
raise CleanError('pip (for {python_bin}) is required.')
# Check for some required python modules.
for modname, minver in [
('pylint', [2, 4, 3]),
('mypy', [0, 740]),
('yapf', [0, 28, 0]),
('typing_extensions', None),
('pytz', None),
for modname, minver, packagename in [
('pylint', [2, 4, 4], None),
('mypy', [0, 740], None),
('yapf', [0, 28, 0], None),
('typing_extensions', None, None),
('pytz', None, None),
('yaml', None, 'PyYAML'),
]:
if packagename is None:
packagename = modname
if minver is not None:
results = subprocess.run(f'{python_bin} -m {modname} --version',
shell=True,
@ -730,9 +732,9 @@ def checkenv() -> None:
check=False,
capture_output=True)
if results.returncode != 0:
raise CleanError(
f'{modname} (for {python_bin}) is required.\n'
f'To install it, try: "{python_bin} -m pip install {modname}"')
raise CleanError(f'{packagename} (for {python_bin}) is required.\n'
f'To install it, try: "{python_bin}'
f' -m pip install {packagename}"')
if minver is not None:
ver_line = results.stdout.decode().splitlines()[0]
assert modname in ver_line
@ -740,7 +742,7 @@ def checkenv() -> None:
assert len(vnums) == len(minver)
if vnums < minver:
raise CleanError(
f'{modname} ver. {_vstr(minver)} or newer required;'
f'{packagename} ver. {_vstr(minver)} or newer required;'
f' found {_vstr(vnums)}')
print('Environment ok.', flush=True)

View File

@ -19,8 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# -----------------------------------------------------------------------------
"""
This script acts as a 'meta' Makefile for the project. It is in charge
"""This script acts as a 'meta' Makefile for the project. It is in charge
of generating Makefiles, IDE project files, procedurally generated source
files, etc. based on the current structure of the project.
It can also perform sanity checks or cleanup tasks.