mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-21 22:33:58 +08:00
More modernizing
This commit is contained in:
parent
849bd11795
commit
08ea64bdc5
@ -4132,16 +4132,16 @@
|
||||
"assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c",
|
||||
"assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb",
|
||||
"assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe",
|
||||
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/35/3b6bc5c5609b1dd37bd65c39df45",
|
||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a6/bc/c2c7231dc6bf085eda15d6198554",
|
||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/fd/020ed9bb0e8c8a18b2d793fee8bd",
|
||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/43/0b/78c8bacb215abaf50dcb3284eef7",
|
||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f8/e1/e0dc64b5c00661cce19530c0e836",
|
||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e6/74/73a514993d626a6bc75717d185ef",
|
||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f0/7d/dbd2624759a1fdce2a20d53cab1a",
|
||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1c/01/4833ec215cc6c53f7e4ebf850608",
|
||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b1/57/b72500d2a568df5afa36556f89dd",
|
||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/48/ea/c83f97f44703b16eeec794d29da6",
|
||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a3/16/284b9953c7ef4a841ff907079cbd",
|
||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/12/43/d0513cf8f8dac0712cbf42d4b94b"
|
||||
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ca/db/9c7cfd4e4f4a1f7a7adc980bca42",
|
||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4e/0b/231e38ff29d932df7552050891c5",
|
||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f2/56/bb316ec28ee98ece5c0c3a04b77f",
|
||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/92/d787c99db6cc85f70b7131ff2c0c",
|
||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/97/b9/9c6c3c90f10d319250a9f3d287b3",
|
||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f0/2a/60bdf1c4d4e13bdbb5f4df121e3e",
|
||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/66/25/79ea606983dc91ac0cd79c1e7da6",
|
||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/70/c6/0ab2cdf222ffcadade37dd3b8462",
|
||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3c/65/450a67dab189c0832b6bf28a9e9c",
|
||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7e/a9/e1ab6defb8bcf536dff46d0c62b2",
|
||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ab/fc/d00336dae2b1c7323b31518b52aa",
|
||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ed/98/dbea1af1da83bfa1a3283175b234"
|
||||
}
|
||||
@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand.
|
||||
"""
|
||||
|
||||
# (hash we can use to see if this file is out of date)
|
||||
# SOURCES_HASH=223083205204988067566025188831386474803
|
||||
# SOURCES_HASH=265401783818737452594582363319036908124
|
||||
|
||||
# I'm sorry Pylint. I know this file saddens you. Be strong.
|
||||
# pylint: disable=useless-suppression
|
||||
|
||||
@ -73,7 +73,8 @@ from ba._apputils import is_browser_likely_available
|
||||
from ba._campaign import Campaign
|
||||
from ba._gameutils import (animate, animate_array, show_damage_count,
|
||||
sharedobj, timestring, cameraflash)
|
||||
from ba._general import WeakCall, Call, existing, Existable
|
||||
from ba._general import (WeakCall, Call, existing, Existable,
|
||||
verify_object_death)
|
||||
from ba._level import Level
|
||||
from ba._lobby import Lobby, Chooser
|
||||
from ba._math import normalized_color, is_point_in_box, vec3validate
|
||||
|
||||
@ -28,6 +28,7 @@ from ba._team import Team
|
||||
from ba._player import Player
|
||||
from ba._error import print_exception, print_error, SessionTeamNotFoundError
|
||||
from ba._dependency import DependencyComponent
|
||||
from ba._general import Call, verify_object_death
|
||||
import _ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -217,7 +218,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
|
||||
self._stats: Optional[ba.Stats] = None
|
||||
|
||||
def __del__(self) -> None:
|
||||
from ba._apputils import garbage_collect, call_after_ad
|
||||
|
||||
# If the activity has been run then we should have already cleaned
|
||||
# it up, but we still need to run expire calls for un-run activities.
|
||||
@ -225,20 +225,13 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
|
||||
with _ba.Context('empty'):
|
||||
self._expire()
|
||||
|
||||
# Since we're mostly between activities at this point, lets run a cycle
|
||||
# of garbage collection; hopefully it won't cause hitches here.
|
||||
garbage_collect(session_end=False)
|
||||
|
||||
# Now that our object is officially gonna be dead, tell the session it
|
||||
# can fire up the next activity.
|
||||
# Inform our owner that we're officially kicking the bucket.
|
||||
if self._transitioning_out:
|
||||
session = self._session()
|
||||
if session is not None:
|
||||
with _ba.Context(session):
|
||||
if self.can_show_ad_on_death:
|
||||
call_after_ad(session.begin_next_activity)
|
||||
else:
|
||||
_ba.pushcall(session.begin_next_activity)
|
||||
_ba.pushcall(
|
||||
Call(session.transitioning_out_activity_was_freed,
|
||||
self.can_show_ad_on_death))
|
||||
|
||||
@property
|
||||
def stats(self) -> ba.Stats:
|
||||
@ -304,7 +297,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
|
||||
|
||||
(internal)
|
||||
"""
|
||||
from ba._general import Call
|
||||
from ba._enums import TimeType
|
||||
|
||||
# Create a real-timer that watches a weak-ref of this activity
|
||||
@ -628,6 +620,10 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
|
||||
self.players.remove(player)
|
||||
assert player not in self.players
|
||||
|
||||
# This should allow our ba.Player instance to die.
|
||||
# Complain if that doesn't happen.
|
||||
# verify_object_death(player)
|
||||
|
||||
with _ba.Context(self):
|
||||
# Make a decent attempt to persevere if user code breaks.
|
||||
try:
|
||||
@ -670,6 +666,10 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
|
||||
self.teams.remove(team)
|
||||
assert team not in self.teams
|
||||
|
||||
# This should allow our ba.Team instance to die. Complain
|
||||
# if that doesn't happen.
|
||||
# verify_object_death(team)
|
||||
|
||||
with _ba.Context(self):
|
||||
# Make a decent attempt to persevere if user code breaks.
|
||||
try:
|
||||
@ -680,6 +680,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
|
||||
sessionteam.reset_gamedata()
|
||||
except Exception:
|
||||
print_exception(f'Error in reset_gamedata for {self}')
|
||||
|
||||
sessionteam.gameteam = None
|
||||
|
||||
def _sanity_check_begin_call(self) -> None:
|
||||
@ -777,32 +778,45 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
|
||||
for actor_ref in self._actor_weak_refs:
|
||||
actor = actor_ref()
|
||||
if actor is not None:
|
||||
verify_object_death(actor)
|
||||
try:
|
||||
actor.on_expire()
|
||||
except Exception:
|
||||
print_exception(f'Error expiring Actor {actor_ref()}')
|
||||
print_exception(f'Error in Actor.on_expire()'
|
||||
f' for {actor_ref()}')
|
||||
|
||||
# Reset all Players.
|
||||
# (releases any attached actors, clears game-data, etc)
|
||||
for player in self.players:
|
||||
if player:
|
||||
try:
|
||||
sessionplayer = player.sessionplayer
|
||||
player.reset()
|
||||
sessionplayer.set_node(None)
|
||||
sessionplayer.set_activity(None)
|
||||
sessionplayer.gameplayer = None
|
||||
sessionplayer.reset()
|
||||
except Exception:
|
||||
print_exception(f'Error resetting Player {player}')
|
||||
try:
|
||||
# This should allow our ba.Player instance to die.
|
||||
# Complain if that doesn't happen.
|
||||
# verify_object_death(player)
|
||||
sessionplayer = player.sessionplayer
|
||||
player.reset()
|
||||
sessionplayer.set_node(None)
|
||||
sessionplayer.set_activity(None)
|
||||
|
||||
sessionplayer.gameplayer = None
|
||||
sessionplayer.reset()
|
||||
except Exception:
|
||||
print_exception(f'Error resetting Player {player}')
|
||||
|
||||
# Ditto with Teams.
|
||||
for team in self.teams:
|
||||
try:
|
||||
sessionteam = team.sessionteam
|
||||
|
||||
# This should allow our ba.Team instance to die.
|
||||
# Complain if that doesn't happen.
|
||||
# verify_object_death(sessionteam.gameteam)
|
||||
sessionteam.gameteam = None
|
||||
sessionteam.reset_gamedata()
|
||||
except SessionTeamNotFoundError:
|
||||
# It is expected that Team objects may last longer than
|
||||
# the SessionTeam they came from (game objects may hold
|
||||
# team references past the point at which the underlying
|
||||
# player/team leaves)
|
||||
pass
|
||||
except Exception:
|
||||
print_exception(f'Error resetting Team {team}')
|
||||
|
||||
@ -21,16 +21,22 @@
|
||||
"""Utility snippets applying to generic Python code."""
|
||||
from __future__ import annotations
|
||||
|
||||
import gc
|
||||
import types
|
||||
import weakref
|
||||
import random
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
from typing_extensions import Protocol
|
||||
|
||||
from efro.terminal import Clr
|
||||
from ba._error import print_error, print_exception
|
||||
from ba._enums import TimeType
|
||||
import _ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Type, Optional
|
||||
from efro.call import Call as Call # 'as Call' so we re-export.
|
||||
from weakref import ReferenceType
|
||||
|
||||
|
||||
class Existable(Protocol):
|
||||
@ -100,22 +106,18 @@ def json_prep(data: Any) -> Any:
|
||||
if isinstance(data, list):
|
||||
return [json_prep(element) for element in data]
|
||||
if isinstance(data, tuple):
|
||||
from ba import _error
|
||||
_error.print_error('json_prep encountered tuple', once=True)
|
||||
print_error('json_prep encountered tuple', once=True)
|
||||
return [json_prep(element) for element in data]
|
||||
if isinstance(data, bytes):
|
||||
try:
|
||||
return data.decode(errors='ignore')
|
||||
except Exception:
|
||||
from ba import _error
|
||||
_error.print_error('json_prep encountered utf-8 decode error',
|
||||
once=True)
|
||||
print_error('json_prep encountered utf-8 decode error', once=True)
|
||||
return data.decode(errors='ignore')
|
||||
if not isinstance(data, (str, float, bool, type(None), int)):
|
||||
from ba import _error
|
||||
_error.print_error('got unsupported type in json_prep:' +
|
||||
str(type(data)),
|
||||
once=True)
|
||||
print_error('got unsupported type in json_prep:' + str(type(data)),
|
||||
once=True)
|
||||
return data
|
||||
|
||||
|
||||
@ -135,7 +137,6 @@ def utf8_all(data: Any) -> Any:
|
||||
|
||||
def print_refs(obj: Any) -> None:
|
||||
"""Print a list of known live references to an object."""
|
||||
import gc
|
||||
|
||||
# Hmmm; I just noticed that calling this on an object
|
||||
# seems to keep it alive. Should figure out why.
|
||||
@ -291,3 +292,47 @@ class WeakMethod:
|
||||
|
||||
def __str__(self) -> str:
|
||||
return '<ba.WeakMethod object; call=' + str(self._func) + '>'
|
||||
|
||||
|
||||
def verify_object_death(obj: object) -> None:
|
||||
"""Warn if an object does not get freed within a short period.
|
||||
|
||||
Category: General Utility Functions
|
||||
|
||||
This can be handy to detect and prevent memory/resource leaks.
|
||||
"""
|
||||
try:
|
||||
ref = weakref.ref(obj)
|
||||
except Exception:
|
||||
print_exception('Unable to create weak-ref in verify_object_death')
|
||||
|
||||
# Use a slight range for our checks so they don't all land at once
|
||||
# if we queue a lot of them.
|
||||
delay = random.uniform(2.0, 5.5)
|
||||
with _ba.Context('ui'):
|
||||
_ba.timer(delay,
|
||||
lambda: _verify_object_death(ref),
|
||||
timetype=TimeType.REAL)
|
||||
|
||||
|
||||
def _verify_object_death(wref: ReferenceType) -> None:
|
||||
obj = wref()
|
||||
if obj is None:
|
||||
return
|
||||
|
||||
try:
|
||||
name = type(obj).__name__
|
||||
except Exception:
|
||||
print(f'Note: unable to get type name for {obj}')
|
||||
name = 'object'
|
||||
|
||||
print(f'{Clr.RED}Error: {name} not dying'
|
||||
f' when expected to: {Clr.BLD}{obj}{Clr.RST}')
|
||||
refs = list(gc.get_referrers(obj))
|
||||
print(f'{Clr.YLW}Active References:{Clr.RST}')
|
||||
i = 1
|
||||
for ref in refs:
|
||||
# if isinstance(ref, types.FrameType):
|
||||
# continue
|
||||
print(f'{Clr.YLW} reference {i}:{Clr.BLU} {ref}{Clr.RST}')
|
||||
i += 1
|
||||
|
||||
@ -35,7 +35,7 @@ PLAYER_COLORS = [(1, 0.15, 0.15), (0.2, 1, 0.2), (0.1, 0.1, 1), (0.2, 1, 1),
|
||||
(0.5, 0.25, 1.0), (1, 1, 0), (1, 0.5, 0), (1, 0.3, 0.5),
|
||||
(0.1, 0.1, 0.5), (0.4, 0.2, 0.1), (0.1, 0.35, 0.1),
|
||||
(1, 0.8, 0.5), (0.4, 0.05, 0.05), (0.13, 0.13, 0.13),
|
||||
(0.5, 0.5, 0.5), (1, 1, 1)] # yapf: disable
|
||||
(0.5, 0.5, 0.5), (1, 1, 1)]
|
||||
|
||||
|
||||
def get_player_colors() -> List[Tuple[float, float, float]]:
|
||||
@ -75,8 +75,8 @@ def get_player_profile_colors(
|
||||
if profiles is None:
|
||||
profiles = bs_config['Player Profiles']
|
||||
|
||||
# special case - when being asked for a random color in kiosk mode,
|
||||
# always return default purple
|
||||
# Special case: when being asked for a random color in kiosk mode,
|
||||
# always return default purple.
|
||||
if _ba.app.kiosk_mode and profilename is None:
|
||||
color = (0.5, 0.4, 1.0)
|
||||
highlight = (0.4, 0.4, 0.5)
|
||||
@ -85,22 +85,22 @@ def get_player_profile_colors(
|
||||
assert profilename is not None
|
||||
color = profiles[profilename]['color']
|
||||
except (KeyError, AssertionError):
|
||||
# key off name if possible
|
||||
# Key off name if possible.
|
||||
if profilename is None:
|
||||
# first 6 are bright-ish
|
||||
# First 6 are bright-ish.
|
||||
color = PLAYER_COLORS[random.randrange(6)]
|
||||
else:
|
||||
# first 6 are bright-ish
|
||||
# First 6 are bright-ish.
|
||||
color = PLAYER_COLORS[sum([ord(c) for c in profilename]) % 6]
|
||||
|
||||
try:
|
||||
assert profilename is not None
|
||||
highlight = profiles[profilename]['highlight']
|
||||
except (KeyError, AssertionError):
|
||||
# key off name if possible
|
||||
# Key off name if possible.
|
||||
if profilename is None:
|
||||
# last 2 are grey and white; ignore those or we
|
||||
# get lots of old-looking players
|
||||
# Last 2 are grey and white; ignore those or we
|
||||
# get lots of old-looking players.
|
||||
highlight = PLAYER_COLORS[random.randrange(
|
||||
len(PLAYER_COLORS) - 2)]
|
||||
else:
|
||||
|
||||
@ -582,6 +582,21 @@ class Session:
|
||||
self._add_chosen_player(chooser)
|
||||
lobby.remove_chooser(chooser.getplayer())
|
||||
|
||||
def transitioning_out_activity_was_freed(
|
||||
self, can_show_ad_on_death: bool) -> None:
|
||||
"""(internal)"""
|
||||
from ba._apputils import garbage_collect, call_after_ad
|
||||
|
||||
# Since we're mostly between activities at this point, lets run a cycle
|
||||
# of garbage collection; hopefully it won't cause hitches here.
|
||||
garbage_collect(session_end=False)
|
||||
|
||||
with _ba.Context(self):
|
||||
if can_show_ad_on_death:
|
||||
call_after_ad(self.begin_next_activity)
|
||||
else:
|
||||
_ba.pushcall(self.begin_next_activity)
|
||||
|
||||
def _add_chosen_player(self, chooser: ba.Chooser) -> ba.SessionPlayer:
|
||||
from ba._team import SessionTeam
|
||||
sessionplayer = chooser.getplayer()
|
||||
|
||||
@ -40,18 +40,17 @@ class RespawnIcon:
|
||||
"""
|
||||
|
||||
def __init__(self, player: ba.Player, respawn_time: float):
|
||||
"""
|
||||
Instantiate with a given ba.Player and respawn_time (in seconds)
|
||||
"""
|
||||
"""Instantiate with a ba.Player and respawn_time (in seconds)."""
|
||||
self._visible = True
|
||||
|
||||
on_right, offs_extra, respawn_icons = self._get_context(player)
|
||||
|
||||
try:
|
||||
mask_tex = (player.team.gamedata['_spaz_respawn_icons_mask_tex'])
|
||||
except Exception:
|
||||
mask_tex = player.team.gamedata['_spaz_respawn_icons_mask_tex'] = (
|
||||
ba.gettexture('characterIconMask'))
|
||||
# Cache our mask tex on the team for easy access.
|
||||
mask_tex = getattr(player.team, '_spaz_respawn_icons_mask_tex', None)
|
||||
if mask_tex is None:
|
||||
mask_tex = ba.gettexture('characterIconMask')
|
||||
setattr(player.team, '_spaz_respawn_icons_mask_tex', mask_tex)
|
||||
assert isinstance(mask_tex, ba.Texture)
|
||||
|
||||
# Now find the first unused slot and use that.
|
||||
index = 0
|
||||
@ -139,12 +138,14 @@ class RespawnIcon:
|
||||
on_right = player.team.id % 2 == 1
|
||||
|
||||
# Store a list of icons in the team.
|
||||
try:
|
||||
respawn_icons = (
|
||||
player.team.gamedata['_spaz_respawn_icons_right'])
|
||||
except Exception:
|
||||
respawn_icons = (
|
||||
player.team.gamedata['_spaz_respawn_icons_right']) = {}
|
||||
respawn_icons = getattr(player.team, '_spaz_respawn_icons_right',
|
||||
None)
|
||||
if respawn_icons is None:
|
||||
respawn_icons = {}
|
||||
setattr(player.team, '_spaz_respawn_icons_right',
|
||||
respawn_icons)
|
||||
assert isinstance(respawn_icons, dict)
|
||||
|
||||
offs_extra = -20
|
||||
else:
|
||||
on_right = False
|
||||
|
||||
@ -200,7 +200,8 @@ class _Entry:
|
||||
|
||||
def set_position(self, position: Sequence[float]) -> None:
|
||||
"""Set the entry's position."""
|
||||
# abort if we've been killed
|
||||
|
||||
# Abort if we've been killed
|
||||
if not self._backing.node:
|
||||
return
|
||||
self._pos = tuple(position)
|
||||
@ -315,13 +316,15 @@ class _EntryProxy:
|
||||
|
||||
def __init__(self, scoreboard: Scoreboard, team: ba.Team):
|
||||
self._scoreboard = weakref.ref(scoreboard)
|
||||
# have to store ID here instead of a weak-ref since the team will be
|
||||
# dead when we die and need to remove it
|
||||
|
||||
# Have to store ID here instead of a weak-ref since the team will be
|
||||
# dead when we die and need to remove it.
|
||||
self._team_id = team.id
|
||||
|
||||
def __del__(self) -> None:
|
||||
scoreboard = self._scoreboard()
|
||||
# remove our team from the scoreboard if its still around
|
||||
|
||||
# Remove our team from the scoreboard if its still around.
|
||||
if scoreboard is not None:
|
||||
scoreboard.remove_team(self._team_id)
|
||||
|
||||
@ -343,7 +346,7 @@ class Scoreboard:
|
||||
self._label = label
|
||||
self.score_split = score_split
|
||||
|
||||
# for free-for-all we go simpler since we have one per player
|
||||
# For free-for-all we go simpler since we have one per player.
|
||||
self._pos: Sequence[float]
|
||||
if isinstance(ba.getsession(), ba.FreeForAllSession):
|
||||
self._do_cover = False
|
||||
@ -368,11 +371,11 @@ class Scoreboard:
|
||||
"""Update the score-board display for the given ba.Team."""
|
||||
if not team.id in self._entries:
|
||||
self._add_team(team)
|
||||
# create a proxy in the team which will kill
|
||||
|
||||
# Create a proxy in the team which will kill
|
||||
# our entry when it dies (for convenience)
|
||||
if '_scoreboard_entry' in team.gamedata:
|
||||
raise Exception('existing _EntryProxy found')
|
||||
team.gamedata['_scoreboard_entry'] = _EntryProxy(self, team)
|
||||
assert not hasattr(team, '_scoreboard_entry')
|
||||
setattr(team, '_scoreboard_entry', _EntryProxy(self, team))
|
||||
|
||||
# Now set the entry.
|
||||
self._entries[team.id].set_value(score=score,
|
||||
@ -383,7 +386,7 @@ class Scoreboard:
|
||||
|
||||
def _add_team(self, team: ba.Team) -> None:
|
||||
if team.id in self._entries:
|
||||
raise Exception('Duplicate team add')
|
||||
raise RuntimeError('Duplicate team add')
|
||||
self._entries[team.id] = _Entry(self,
|
||||
team,
|
||||
do_cover=self._do_cover,
|
||||
|
||||
@ -49,16 +49,16 @@ class SpazBotPunchedMessage:
|
||||
|
||||
Attributes:
|
||||
|
||||
badguy
|
||||
spazbot
|
||||
The ba.SpazBot that got punched.
|
||||
|
||||
damage
|
||||
How much damage was done to the ba.SpazBot.
|
||||
"""
|
||||
|
||||
def __init__(self, badguy: SpazBot, damage: int):
|
||||
def __init__(self, spazbot: SpazBot, damage: int):
|
||||
"""Instantiate a message with the given values."""
|
||||
self.badguy = badguy
|
||||
self.spazbot = spazbot
|
||||
self.damage = damage
|
||||
|
||||
|
||||
@ -69,7 +69,7 @@ class SpazBotDiedMessage:
|
||||
|
||||
Attributes:
|
||||
|
||||
badguy
|
||||
spazbot
|
||||
The ba.SpazBot that was killed.
|
||||
|
||||
killerplayer
|
||||
@ -79,10 +79,10 @@ class SpazBotDiedMessage:
|
||||
The particular type of death.
|
||||
"""
|
||||
|
||||
def __init__(self, badguy: SpazBot, killerplayer: Optional[ba.Player],
|
||||
def __init__(self, spazbot: SpazBot, killerplayer: Optional[ba.Player],
|
||||
how: ba.DeathType):
|
||||
"""Instantiate with given values."""
|
||||
self.badguy = badguy
|
||||
self.spazbot = spazbot
|
||||
self.killerplayer = killerplayer
|
||||
self.how = how
|
||||
|
||||
|
||||
@ -216,8 +216,8 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
||||
# Whenever our evil bunny dies, respawn him and spew some eggs.
|
||||
elif isinstance(msg, SpazBotDiedMessage):
|
||||
self._spawn_evil_bunny()
|
||||
assert msg.badguy.node
|
||||
pos = msg.badguy.node.position
|
||||
assert msg.spazbot.node
|
||||
pos = msg.spazbot.node.position
|
||||
for _i in range(6):
|
||||
spread = 0.4
|
||||
self._eggs.append(
|
||||
|
||||
@ -816,7 +816,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
||||
elif isinstance(msg, SpazBotDiedMessage):
|
||||
|
||||
# Every time a bad guy dies, spawn a new one.
|
||||
ba.timer(3.0, ba.Call(self._spawn_bot, (type(msg.badguy))))
|
||||
ba.timer(3.0, ba.Call(self._spawn_bot, (type(msg.spazbot))))
|
||||
|
||||
elif isinstance(msg, SpazBotPunchedMessage):
|
||||
if self._preset in ['rookie', 'rookie_easy']:
|
||||
|
||||
@ -36,7 +36,7 @@ if TYPE_CHECKING:
|
||||
from typing import Any, Sequence, Dict, Type, List, Optional, Union
|
||||
|
||||
|
||||
class PuckDeathMessage:
|
||||
class PuckDiedMessage:
|
||||
"""Inform something that a puck has died."""
|
||||
|
||||
def __init__(self, puck: Puck):
|
||||
@ -78,7 +78,7 @@ class Puck(ba.Actor):
|
||||
self.node.delete()
|
||||
activity = self._activity()
|
||||
if activity and not msg.immediate:
|
||||
activity.handlemessage(PuckDeathMessage(self))
|
||||
activity.handlemessage(PuckDiedMessage(self))
|
||||
|
||||
# If we go out of bounds, move back to where we started.
|
||||
elif isinstance(msg, ba.OutOfBoundsMessage):
|
||||
@ -113,6 +113,9 @@ class Player(ba.Player['Team']):
|
||||
class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.score = 0
|
||||
|
||||
|
||||
# ba_meta export game
|
||||
class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
||||
@ -196,26 +199,28 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
||||
self._puck_spawn_pos: Optional[Sequence[float]] = None
|
||||
self._score_regions: Optional[List[ba.NodeActor]] = None
|
||||
self._puck: Optional[Puck] = None
|
||||
self._score_to_win = int(settings['Score to Win'])
|
||||
self._time_limit = float(settings['Time Limit'])
|
||||
|
||||
def get_instance_description(self) -> Union[str, Sequence]:
|
||||
if self.settings_raw['Score to Win'] == 1:
|
||||
if self._score_to_win == 1:
|
||||
return 'Score a goal.'
|
||||
return 'Score ${ARG1} goals.', self.settings_raw['Score to Win']
|
||||
return 'Score ${ARG1} goals.', self._score_to_win
|
||||
|
||||
def get_instance_description_short(self) -> Union[str, Sequence]:
|
||||
if self.settings_raw['Score to Win'] == 1:
|
||||
if self._score_to_win == 1:
|
||||
return 'score a goal'
|
||||
return 'score ${ARG1} goals', self.settings_raw['Score to Win']
|
||||
return 'score ${ARG1} goals', self._score_to_win
|
||||
|
||||
def on_begin(self) -> None:
|
||||
super().on_begin()
|
||||
|
||||
self.setup_standard_time_limit(self.settings_raw['Time Limit'])
|
||||
self.setup_standard_time_limit(self._time_limit)
|
||||
self.setup_standard_powerup_drops()
|
||||
self._puck_spawn_pos = self.map.get_flag_position(None)
|
||||
self._spawn_puck()
|
||||
|
||||
# set up the two score regions
|
||||
# Set up the two score regions.
|
||||
defs = self.map.defs
|
||||
self._score_regions = []
|
||||
self._score_regions.append(
|
||||
@ -240,7 +245,6 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
||||
ba.playsound(self._chant_sound)
|
||||
|
||||
def on_team_join(self, team: Team) -> None:
|
||||
team.gamedata['score'] = 0
|
||||
self._update_scoreboard()
|
||||
|
||||
def _handle_puck_player_collide(self) -> None:
|
||||
@ -274,7 +278,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
||||
for team in self.teams:
|
||||
if team.id == index:
|
||||
scoring_team = team
|
||||
team.gamedata['score'] += 1
|
||||
team.score += 1
|
||||
|
||||
# Tell all players to celebrate.
|
||||
for player in team.players:
|
||||
@ -291,7 +295,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
||||
big_message=True)
|
||||
|
||||
# End game if we won.
|
||||
if team.gamedata['score'] >= self.settings_raw['Score to Win']:
|
||||
if team.score >= self._score_to_win:
|
||||
self.end_game()
|
||||
|
||||
ba.playsound(self._foghorn_sound)
|
||||
@ -317,14 +321,13 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
||||
def end_game(self) -> None:
|
||||
results = ba.TeamGameResults()
|
||||
for team in self.teams:
|
||||
results.set_team_score(team, team.gamedata['score'])
|
||||
results.set_team_score(team, team.score)
|
||||
self.end(results=results)
|
||||
|
||||
def _update_scoreboard(self) -> None:
|
||||
winscore = self.settings_raw['Score to Win']
|
||||
winscore = self._score_to_win
|
||||
for team in self.teams:
|
||||
self._scoreboard.set_team_value(team, team.gamedata['score'],
|
||||
winscore)
|
||||
self._scoreboard.set_team_value(team, team.score, winscore)
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
|
||||
@ -335,7 +338,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
||||
self.respawn_player(msg.getplayer(Player))
|
||||
|
||||
# Respawn dead pucks.
|
||||
elif isinstance(msg, PuckDeathMessage):
|
||||
elif isinstance(msg, PuckDiedMessage):
|
||||
if not self.has_ended():
|
||||
ba.timer(3.0, self._spawn_puck)
|
||||
else:
|
||||
|
||||
@ -1220,13 +1220,13 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
||||
ba.timer(0.1, self._checkroundover)
|
||||
|
||||
elif isinstance(msg, SpazBotDiedMessage):
|
||||
pts, importance = msg.badguy.get_death_points(msg.how)
|
||||
pts, importance = msg.spazbot.get_death_points(msg.how)
|
||||
if msg.killerplayer is not None:
|
||||
self._handle_kill_achievements(msg)
|
||||
target: Optional[Sequence[float]]
|
||||
try:
|
||||
assert msg.badguy.node
|
||||
target = msg.badguy.node.position
|
||||
assert msg.spazbot.node
|
||||
target = msg.spazbot.node.position
|
||||
except Exception:
|
||||
ba.print_exception()
|
||||
target = None
|
||||
@ -1265,13 +1265,13 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
||||
def _handle_uber_kill_achievements(self, msg: SpazBotDiedMessage) -> None:
|
||||
|
||||
# Uber mine achievement:
|
||||
if msg.badguy.last_attacked_type == ('explosion', 'land_mine'):
|
||||
if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'):
|
||||
self._land_mine_kills += 1
|
||||
if self._land_mine_kills >= 6:
|
||||
self._award_achievement('Gold Miner')
|
||||
|
||||
# Uber tnt achievement:
|
||||
if msg.badguy.last_attacked_type == ('explosion', 'tnt'):
|
||||
if msg.spazbot.last_attacked_type == ('explosion', 'tnt'):
|
||||
self._tnt_kills += 1
|
||||
if self._tnt_kills >= 6:
|
||||
ba.timer(0.5, ba.WeakCall(self._award_achievement,
|
||||
@ -1280,7 +1280,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
||||
def _handle_pro_kill_achievements(self, msg: SpazBotDiedMessage) -> None:
|
||||
|
||||
# TNT achievement:
|
||||
if msg.badguy.last_attacked_type == ('explosion', 'tnt'):
|
||||
if msg.spazbot.last_attacked_type == ('explosion', 'tnt'):
|
||||
self._tnt_kills += 1
|
||||
if self._tnt_kills >= 3:
|
||||
ba.timer(
|
||||
@ -1291,7 +1291,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
||||
def _handle_rookie_kill_achievements(self,
|
||||
msg: SpazBotDiedMessage) -> None:
|
||||
# Land-mine achievement:
|
||||
if msg.badguy.last_attacked_type == ('explosion', 'land_mine'):
|
||||
if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'):
|
||||
self._land_mine_kills += 1
|
||||
if self._land_mine_kills >= 3:
|
||||
self._award_achievement('Mine Games')
|
||||
@ -1299,7 +1299,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
||||
def _handle_training_kill_achievements(self,
|
||||
msg: SpazBotDiedMessage) -> None:
|
||||
# Toss-off-map achievement:
|
||||
if msg.badguy.last_attacked_type == ('picked_up', 'default'):
|
||||
if msg.spazbot.last_attacked_type == ('picked_up', 'default'):
|
||||
self._throw_off_kills += 1
|
||||
if self._throw_off_kills >= 3:
|
||||
self._award_achievement('Off You Go Then')
|
||||
|
||||
@ -180,18 +180,18 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
def get_instance_description(self) -> Union[str, Sequence]:
|
||||
if (isinstance(self.session, ba.DualTeamSession)
|
||||
and self.settings_raw.get('Entire Team Must Finish', False)):
|
||||
and self._entire_team_must_finish):
|
||||
t_str = ' Your entire team has to finish.'
|
||||
else:
|
||||
t_str = ''
|
||||
|
||||
if self.settings_raw['Laps'] > 1:
|
||||
return 'Run ${ARG1} laps.' + t_str, self.settings_raw['Laps']
|
||||
if self._laps > 1:
|
||||
return 'Run ${ARG1} laps.' + t_str, self._laps
|
||||
return 'Run 1 lap.' + t_str
|
||||
|
||||
def get_instance_description_short(self) -> Union[str, Sequence]:
|
||||
if self.settings_raw['Laps'] > 1:
|
||||
return 'run ${ARG1} laps', self.settings_raw['Laps']
|
||||
if self._laps > 1:
|
||||
return 'run ${ARG1} laps', self._laps
|
||||
return 'run 1 lap'
|
||||
|
||||
def on_transition_in(self) -> None:
|
||||
@ -715,8 +715,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, ba.PlayerDiedMessage):
|
||||
# Augment default behavior.
|
||||
super().handlemessage(msg)
|
||||
super().handlemessage(msg) # Augment default behavior.
|
||||
player = msg.getplayer(Player)
|
||||
if not player.finished:
|
||||
self.respawn_player(player, respawn_time=1)
|
||||
|
||||
@ -47,6 +47,10 @@ if TYPE_CHECKING:
|
||||
class Player(ba.Player['Team']):
|
||||
"""Our player type for this game."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.respawn_timer: Optional[ba.Timer] = None
|
||||
self.respawn_icon: Optional[RespawnIcon] = None
|
||||
|
||||
|
||||
class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
@ -1113,20 +1117,20 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
||||
# Respawn them shortly.
|
||||
assert self.initial_player_info is not None
|
||||
respawn_time = 2.0 + len(self.initial_player_info) * 1.0
|
||||
player.gamedata['respawn_timer'] = ba.Timer(
|
||||
player.respawn_timer = ba.Timer(
|
||||
respawn_time, ba.Call(self.spawn_player_if_exists, player))
|
||||
player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time)
|
||||
player.respawn_icon = RespawnIcon(player, respawn_time)
|
||||
|
||||
elif isinstance(msg, SpazBotDiedMessage):
|
||||
if msg.how is ba.DeathType.REACHED_GOAL:
|
||||
return
|
||||
pts, importance = msg.badguy.get_death_points(msg.how)
|
||||
return None
|
||||
pts, importance = msg.spazbot.get_death_points(msg.how)
|
||||
if msg.killerplayer is not None:
|
||||
target: Optional[Sequence[float]]
|
||||
try:
|
||||
assert msg.badguy is not None
|
||||
assert msg.badguy.node
|
||||
target = msg.badguy.node.position
|
||||
assert msg.spazbot is not None
|
||||
assert msg.spazbot.node
|
||||
target = msg.spazbot.node.position
|
||||
except Exception:
|
||||
ba.print_exception()
|
||||
target = None
|
||||
@ -1151,7 +1155,8 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
||||
self._update_scores()
|
||||
|
||||
else:
|
||||
super().handlemessage(msg)
|
||||
return super().handlemessage(msg)
|
||||
return None
|
||||
|
||||
def _get_bot_speed(self, bot_type: Type[SpazBot]) -> float:
|
||||
speed = self._bot_speed_map.get(bot_type)
|
||||
|
||||
@ -272,11 +272,11 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]):
|
||||
self._update_scores()
|
||||
|
||||
elif isinstance(msg, SpazBotDiedMessage):
|
||||
pts, importance = msg.badguy.get_death_points(msg.how)
|
||||
pts, importance = msg.spazbot.get_death_points(msg.how)
|
||||
target: Optional[Sequence[float]]
|
||||
if msg.killerplayer:
|
||||
assert msg.badguy.node
|
||||
target = msg.badguy.node.position
|
||||
assert msg.spazbot.node
|
||||
target = msg.spazbot.node.position
|
||||
self.stats.player_scored(msg.killerplayer,
|
||||
pts,
|
||||
target=target,
|
||||
|
||||
@ -28,8 +28,8 @@
|
||||
# pylint: disable=missing-function-docstring, missing-class-docstring
|
||||
# pylint: disable=invalid-name
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=unused-variable
|
||||
# pylint: disable=unused-argument
|
||||
# pylint: disable=unused-variable
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@ -181,7 +181,21 @@ class ButtonRelease:
|
||||
timeformat=ba.TimeFormat.MILLISECONDS)
|
||||
|
||||
|
||||
class TutorialActivity(ba.Activity[ba.Player, ba.Team]):
|
||||
class Player(ba.Player['Team']):
|
||||
"""Our player type for this game."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.pressed = False
|
||||
|
||||
|
||||
class Team(ba.Team[Player]):
|
||||
"""Our team type for this game."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class TutorialActivity(ba.Activity[Player, Team]):
|
||||
|
||||
def __init__(self, settings: Dict[str, Any] = None):
|
||||
from bastd.maps import Rampage
|
||||
@ -462,6 +476,7 @@ class TutorialActivity(ba.Activity[ba.Player, ba.Team]):
|
||||
n.opacity = 0.0
|
||||
a.set_stick_image_position(0, 0)
|
||||
|
||||
# Can be used for debugging.
|
||||
class SetSpeed:
|
||||
|
||||
def __init__(self, speed: int):
|
||||
@ -2330,7 +2345,7 @@ class TutorialActivity(ba.Activity[ba.Player, ba.Team]):
|
||||
ba.WeakCall(self._read_entries))
|
||||
|
||||
def _update_skip_votes(self) -> None:
|
||||
count = sum(1 for player in self.players if player.gamedata['pressed'])
|
||||
count = sum(1 for player in self.players if player.pressed)
|
||||
assert self._skip_count_text
|
||||
self._skip_count_text.text = ba.Lstr(
|
||||
resource=self._r + '.skipVoteCountText',
|
||||
@ -2349,7 +2364,7 @@ class TutorialActivity(ba.Activity[ba.Player, ba.Team]):
|
||||
self._skip_text.text = ''
|
||||
self.end()
|
||||
|
||||
def _player_pressed_button(self, player: ba.Player) -> None:
|
||||
def _player_pressed_button(self, player: Player) -> None:
|
||||
|
||||
# Special case: if there's only one player, we give them a
|
||||
# warning on their first press (some players were thinking the
|
||||
@ -2363,7 +2378,7 @@ class TutorialActivity(ba.Activity[ba.Player, ba.Team]):
|
||||
self._skip_text.scale = 1.3
|
||||
incr = 50
|
||||
t = incr
|
||||
for i in range(6):
|
||||
for _i in range(6):
|
||||
ba.timer(t,
|
||||
ba.Call(setattr, self._skip_text, 'color',
|
||||
(1, 0.5, 0.1)),
|
||||
@ -2376,7 +2391,7 @@ class TutorialActivity(ba.Activity[ba.Player, ba.Team]):
|
||||
ba.timer(6.0, ba.WeakCall(self._revert_confirm))
|
||||
return
|
||||
|
||||
player.gamedata['pressed'] = True
|
||||
player.pressed = True
|
||||
|
||||
# test...
|
||||
if not all(self.players):
|
||||
@ -2393,15 +2408,15 @@ class TutorialActivity(ba.Activity[ba.Player, ba.Team]):
|
||||
self._skip_text.color = (1, 1, 1)
|
||||
self._issued_warning = False
|
||||
|
||||
def on_player_join(self, player: ba.Player) -> None:
|
||||
def on_player_join(self, player: Player) -> None:
|
||||
super().on_player_join(player)
|
||||
player.gamedata['pressed'] = False
|
||||
# we just wanna know if this player presses anything..
|
||||
|
||||
# We just wanna know if this player presses anything.
|
||||
player.assign_input_call(
|
||||
('jumpPress', 'punchPress', 'bombPress', 'pickUpPress'),
|
||||
ba.Call(self._player_pressed_button, player))
|
||||
|
||||
def on_player_leave(self, player: ba.Player) -> None:
|
||||
def on_player_leave(self, player: Player) -> None:
|
||||
if not all(self.players):
|
||||
ba.print_error('Nonexistent player in on_player_leave: ' +
|
||||
str([str(p) for p in self.players]) + ': we are ' +
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
||||
<h4><em>last updated on 2020-05-25 for Ballistica version 1.5.0 build 20029</em></h4>
|
||||
<h4><em>last updated on 2020-05-27 for Ballistica version 1.5.0 build 20030</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>
|
||||
@ -97,6 +97,7 @@
|
||||
<li><a href="#function_ba_timer">ba.timer()</a></li>
|
||||
<li><a href="#function_ba_timestring">ba.timestring()</a></li>
|
||||
<li><a href="#function_ba_vec3validate">ba.vec3validate()</a></li>
|
||||
<li><a href="#function_ba_verify_object_death">ba.verify_object_death()</a></li>
|
||||
</ul>
|
||||
<h4><a name="class_category_Asset_Classes">Asset Classes</a></h4>
|
||||
<ul>
|
||||
@ -1644,7 +1645,7 @@ and it should begin its actual game logic.</p>
|
||||
<h3>Attributes Inherited:</h3>
|
||||
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__campaign">campaign</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
|
||||
<h3>Methods Inherited:</h3>
|
||||
<h5><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__getactivity">getactivity()</a>, <a href="#method_ba_Session__handlemessage">handlemessage()</a>, <a href="#method_ba_Session__launch_end_session_activity">launch_end_session_activity()</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>
|
||||
<h5><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__getactivity">getactivity()</a>, <a href="#method_ba_Session__handlemessage">handlemessage()</a>, <a href="#method_ba_Session__launch_end_session_activity">launch_end_session_activity()</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>, <a href="#method_ba_Session__transitioning_out_activity_was_freed">transitioning_out_activity_was_freed()</a></h5>
|
||||
<h3>Methods Defined or Overridden:</h3>
|
||||
<h5><a href="#method_ba_CoopSession____init__"><constructor></a>, <a href="#method_ba_CoopSession__get_current_game_instance">get_current_game_instance()</a>, <a href="#method_ba_CoopSession__get_custom_menu_entries">get_custom_menu_entries()</a>, <a href="#method_ba_CoopSession__on_activity_end">on_activity_end()</a>, <a href="#method_ba_CoopSession__on_player_leave">on_player_leave()</a>, <a href="#method_ba_CoopSession__restart">restart()</a></h5>
|
||||
<dl>
|
||||
@ -1987,7 +1988,7 @@ its time with lingering corpses, sound effects, etc.</p>
|
||||
<h3>Attributes Inherited:</h3>
|
||||
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__campaign">campaign</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
|
||||
<h3>Methods Inherited:</h3>
|
||||
<h5><a href="#method_ba_MultiTeamSession__announce_game_results">announce_game_results()</a>, <a href="#method_ba_MultiTeamSession__begin_next_activity">begin_next_activity()</a>, <a href="#method_ba_MultiTeamSession__end">end()</a>, <a href="#method_ba_MultiTeamSession__end_activity">end_activity()</a>, <a href="#method_ba_MultiTeamSession__get_custom_menu_entries">get_custom_menu_entries()</a>, <a href="#method_ba_MultiTeamSession__get_ffa_series_length">get_ffa_series_length()</a>, <a href="#method_ba_MultiTeamSession__get_game_number">get_game_number()</a>, <a href="#method_ba_MultiTeamSession__get_max_players">get_max_players()</a>, <a href="#method_ba_MultiTeamSession__get_next_game_description">get_next_game_description()</a>, <a href="#method_ba_MultiTeamSession__get_series_length">get_series_length()</a>, <a href="#method_ba_MultiTeamSession__getactivity">getactivity()</a>, <a href="#method_ba_MultiTeamSession__handlemessage">handlemessage()</a>, <a href="#method_ba_MultiTeamSession__launch_end_session_activity">launch_end_session_activity()</a>, <a href="#method_ba_MultiTeamSession__on_activity_end">on_activity_end()</a>, <a href="#method_ba_MultiTeamSession__on_player_leave">on_player_leave()</a>, <a href="#method_ba_MultiTeamSession__on_player_request">on_player_request()</a>, <a href="#method_ba_MultiTeamSession__on_team_join">on_team_join()</a>, <a href="#method_ba_MultiTeamSession__on_team_leave">on_team_leave()</a>, <a href="#method_ba_MultiTeamSession__set_activity">set_activity()</a></h5>
|
||||
<h5><a href="#method_ba_MultiTeamSession__announce_game_results">announce_game_results()</a>, <a href="#method_ba_MultiTeamSession__begin_next_activity">begin_next_activity()</a>, <a href="#method_ba_MultiTeamSession__end">end()</a>, <a href="#method_ba_MultiTeamSession__end_activity">end_activity()</a>, <a href="#method_ba_MultiTeamSession__get_custom_menu_entries">get_custom_menu_entries()</a>, <a href="#method_ba_MultiTeamSession__get_ffa_series_length">get_ffa_series_length()</a>, <a href="#method_ba_MultiTeamSession__get_game_number">get_game_number()</a>, <a href="#method_ba_MultiTeamSession__get_max_players">get_max_players()</a>, <a href="#method_ba_MultiTeamSession__get_next_game_description">get_next_game_description()</a>, <a href="#method_ba_MultiTeamSession__get_series_length">get_series_length()</a>, <a href="#method_ba_MultiTeamSession__getactivity">getactivity()</a>, <a href="#method_ba_MultiTeamSession__handlemessage">handlemessage()</a>, <a href="#method_ba_MultiTeamSession__launch_end_session_activity">launch_end_session_activity()</a>, <a href="#method_ba_MultiTeamSession__on_activity_end">on_activity_end()</a>, <a href="#method_ba_MultiTeamSession__on_player_leave">on_player_leave()</a>, <a href="#method_ba_MultiTeamSession__on_player_request">on_player_request()</a>, <a href="#method_ba_MultiTeamSession__on_team_join">on_team_join()</a>, <a href="#method_ba_MultiTeamSession__on_team_leave">on_team_leave()</a>, <a href="#method_ba_MultiTeamSession__set_activity">set_activity()</a>, <a href="#method_ba_MultiTeamSession__transitioning_out_activity_was_freed">transitioning_out_activity_was_freed()</a></h5>
|
||||
<h3>Methods Defined or Overridden:</h3>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_DualTeamSession____init__"><constructor></a></dt></h4><dd>
|
||||
@ -2025,7 +2026,7 @@ its time with lingering corpses, sound effects, etc.</p>
|
||||
<h3>Attributes Inherited:</h3>
|
||||
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__campaign">campaign</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
|
||||
<h3>Methods Inherited:</h3>
|
||||
<h5><a href="#method_ba_MultiTeamSession__announce_game_results">announce_game_results()</a>, <a href="#method_ba_MultiTeamSession__begin_next_activity">begin_next_activity()</a>, <a href="#method_ba_MultiTeamSession__end">end()</a>, <a href="#method_ba_MultiTeamSession__end_activity">end_activity()</a>, <a href="#method_ba_MultiTeamSession__get_custom_menu_entries">get_custom_menu_entries()</a>, <a href="#method_ba_MultiTeamSession__get_ffa_series_length">get_ffa_series_length()</a>, <a href="#method_ba_MultiTeamSession__get_game_number">get_game_number()</a>, <a href="#method_ba_MultiTeamSession__get_max_players">get_max_players()</a>, <a href="#method_ba_MultiTeamSession__get_next_game_description">get_next_game_description()</a>, <a href="#method_ba_MultiTeamSession__get_series_length">get_series_length()</a>, <a href="#method_ba_MultiTeamSession__getactivity">getactivity()</a>, <a href="#method_ba_MultiTeamSession__handlemessage">handlemessage()</a>, <a href="#method_ba_MultiTeamSession__launch_end_session_activity">launch_end_session_activity()</a>, <a href="#method_ba_MultiTeamSession__on_activity_end">on_activity_end()</a>, <a href="#method_ba_MultiTeamSession__on_player_leave">on_player_leave()</a>, <a href="#method_ba_MultiTeamSession__on_player_request">on_player_request()</a>, <a href="#method_ba_MultiTeamSession__on_team_join">on_team_join()</a>, <a href="#method_ba_MultiTeamSession__on_team_leave">on_team_leave()</a>, <a href="#method_ba_MultiTeamSession__set_activity">set_activity()</a></h5>
|
||||
<h5><a href="#method_ba_MultiTeamSession__announce_game_results">announce_game_results()</a>, <a href="#method_ba_MultiTeamSession__begin_next_activity">begin_next_activity()</a>, <a href="#method_ba_MultiTeamSession__end">end()</a>, <a href="#method_ba_MultiTeamSession__end_activity">end_activity()</a>, <a href="#method_ba_MultiTeamSession__get_custom_menu_entries">get_custom_menu_entries()</a>, <a href="#method_ba_MultiTeamSession__get_ffa_series_length">get_ffa_series_length()</a>, <a href="#method_ba_MultiTeamSession__get_game_number">get_game_number()</a>, <a href="#method_ba_MultiTeamSession__get_max_players">get_max_players()</a>, <a href="#method_ba_MultiTeamSession__get_next_game_description">get_next_game_description()</a>, <a href="#method_ba_MultiTeamSession__get_series_length">get_series_length()</a>, <a href="#method_ba_MultiTeamSession__getactivity">getactivity()</a>, <a href="#method_ba_MultiTeamSession__handlemessage">handlemessage()</a>, <a href="#method_ba_MultiTeamSession__launch_end_session_activity">launch_end_session_activity()</a>, <a href="#method_ba_MultiTeamSession__on_activity_end">on_activity_end()</a>, <a href="#method_ba_MultiTeamSession__on_player_leave">on_player_leave()</a>, <a href="#method_ba_MultiTeamSession__on_player_request">on_player_request()</a>, <a href="#method_ba_MultiTeamSession__on_team_join">on_team_join()</a>, <a href="#method_ba_MultiTeamSession__on_team_leave">on_team_leave()</a>, <a href="#method_ba_MultiTeamSession__set_activity">set_activity()</a>, <a href="#method_ba_MultiTeamSession__transitioning_out_activity_was_freed">transitioning_out_activity_was_freed()</a></h5>
|
||||
<h3>Methods Defined or Overridden:</h3>
|
||||
<h5><a href="#method_ba_FreeForAllSession____init__"><constructor></a>, <a href="#method_ba_FreeForAllSession__get_ffa_point_awards">get_ffa_point_awards()</a></h5>
|
||||
<dl>
|
||||
@ -3329,7 +3330,7 @@ Use <a href="#function_ba_getmodel">ba.getmodel</a>() to instantiate one.</p>
|
||||
<h3>Attributes Inherited:</h3>
|
||||
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__campaign">campaign</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
|
||||
<h3>Methods Inherited:</h3>
|
||||
<h5><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__launch_end_session_activity">launch_end_session_activity()</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_leave">on_team_leave()</a>, <a href="#method_ba_Session__set_activity">set_activity()</a></h5>
|
||||
<h5><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__launch_end_session_activity">launch_end_session_activity()</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_leave">on_team_leave()</a>, <a href="#method_ba_Session__set_activity">set_activity()</a>, <a href="#method_ba_Session__transitioning_out_activity_was_freed">transitioning_out_activity_was_freed()</a></h5>
|
||||
<h3>Methods Defined or Overridden:</h3>
|
||||
<h5><a href="#method_ba_MultiTeamSession____init__"><constructor></a>, <a href="#method_ba_MultiTeamSession__announce_game_results">announce_game_results()</a>, <a href="#method_ba_MultiTeamSession__get_ffa_series_length">get_ffa_series_length()</a>, <a href="#method_ba_MultiTeamSession__get_game_number">get_game_number()</a>, <a href="#method_ba_MultiTeamSession__get_max_players">get_max_players()</a>, <a href="#method_ba_MultiTeamSession__get_next_game_description">get_next_game_description()</a>, <a href="#method_ba_MultiTeamSession__get_series_length">get_series_length()</a>, <a href="#method_ba_MultiTeamSession__on_activity_end">on_activity_end()</a>, <a href="#method_ba_MultiTeamSession__on_team_join">on_team_join()</a></h5>
|
||||
<dl>
|
||||
@ -6522,6 +6523,16 @@ so this can be used to disambiguate 'Any' types).
|
||||
Generally this should be used in 'if __debug__' or assert clauses
|
||||
to keep runtime overhead minimal.</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_verify_object_death">ba.verify_object_death()</a></strong></h3>
|
||||
<p><span>verify_object_death(obj: object) -> None</span></p>
|
||||
|
||||
<p>Warn if an object does not get freed within a short period.</p>
|
||||
|
||||
<p>Category: <a href="#function_category_General_Utility_Functions">General Utility Functions</a></p>
|
||||
|
||||
<p>This can be handy to detect and prevent memory/resource leaks.</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_widget">ba.widget()</a></strong></h3>
|
||||
<p><span>widget(edit: <a href="#class_ba_Widget">ba.Widget</a> = None, up_widget: <a href="#class_ba_Widget">ba.Widget</a> = None,
|
||||
|
||||
@ -26,6 +26,7 @@ import json
|
||||
import os
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from efro.terminal import Clr
|
||||
from efrotools import get_files_hash
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -104,8 +105,8 @@ class FileCache:
|
||||
# if anything has been modified, don't write.
|
||||
for fname, mtime in self.mtimes.items():
|
||||
if os.path.getmtime(fname) != mtime:
|
||||
print('File changed during run: "' + fname + '";' +
|
||||
' cache not updated.')
|
||||
print(f'{Clr.YLW}File changed during run:'
|
||||
f' "{fname}"; cache not updated.{Clr.RST}')
|
||||
return
|
||||
out = json.dumps(self.entries)
|
||||
with open(self._path, 'w') as outfile:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user