A bit of tidying for co-op server mode

This commit is contained in:
Eric Froemling 2021-10-08 21:02:57 -05:00
parent 14ed8d24cb
commit 6ff2b30933
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
12 changed files with 70 additions and 61 deletions

View File

@ -1598,6 +1598,7 @@
<w>outpath</w>
<w>outputter</w>
<w>outval</w>
<w>outvals</w>
<w>outvalue</w>
<w>ouya</w>
<w>overloadsigs</w>

View File

@ -1,4 +1,5 @@
### 1.6.5 (20388)
- Added co-op support to server builds (thanks Dliwk!)
### 1.6.4 (20382)
- Some cleanups in the Favorites tab of the gather window.

View File

@ -112,8 +112,9 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
# transitions).
inherits_tint = False
# Whether players should be allowed to join in the middle of
# activity.
# Whether players should be allowed to join in the middle of this
# activity. Note that Sessions may not allow mid-activity-joins even
# if the activity says its ok.
allow_mid_activity_joins: bool = True
# If the activity fades or transitions in, it should set the length of

View File

@ -166,51 +166,44 @@ class CoopSession(Session):
from ba._general import WeakCall
super().on_player_leave(sessionplayer)
_ba.timer(2.0, WeakCall(self._check_end_game))
_ba.timer(2.0, WeakCall(self._handle_empty_activity))
def _check_end_game(self) -> None:
if not _ba.app.server:
self._end_session_if_empty()
def _handle_empty_activity(self) -> None:
"""Handle cases where all players have left the current activity."""
activity = self.getactivity()
if activity is None:
return # Probably everything is already broken, why do something?
if [player for player in activity.players if player.is_alive()]:
return
with _ba.Context(activity):
from ba._gameactivity import GameActivity
if isinstance(activity, GameActivity):
activity.end_game()
def _end_session_if_empty(self) -> None:
from ba._gameactivity import GameActivity
activity = self.getactivity()
if activity is None:
return # Hmm what should we do in this case?
# If there's still players in the current activity, we're good.
# If there are still players in the current activity, we're good.
if activity.players:
return
# If there's *no* players left in the current activity but there *is*
# in the session, restart the activity to pull them into the game
# (or quit if they're just in the lobby).
# If there are *not* players in the current activity but there
# *are* in the session:
if not activity.players and self.sessionplayers:
# Special exception for tourney games; don't auto-restart these.
if self.tournament_id is not None:
self.end()
else:
# Don't restart joining activities; this probably means there's
# someone with a chooser up in that case.
if not activity.is_joining_activity:
# If we're in a game, we should restart to pull in players
# currently waiting in the session.
if isinstance(activity, GameActivity):
# Never restart tourney games however; just end the session
# if all players are gone.
if self.tournament_id is not None:
self.end()
else:
self.restart()
# Hmm; no players anywhere. lets just end the session.
# Hmm; no players anywhere. Let's end the entire session if we're
# running a GUI (or just the current game if we're running headless).
else:
self.end()
if not _ba.app.headless_mode:
self.end()
else:
if isinstance(activity, GameActivity):
with _ba.Context(activity):
activity.end_game()
def _on_tournament_restart_menu_press(
self, resume_callback: Callable[[], Any]) -> None:
@ -274,9 +267,10 @@ class CoopSession(Session):
else:
outcome = '' if results is None else results.get('outcome', '')
# If at any point we have no in-game players, quit out of the session
# (this can happen if someone leaves in the tutorial for instance).
if isinstance(activity, TutorialActivity):
# If we're running with a gui and at any point we have no
# in-game players, quit out of the session (this can happen if
# someone leaves in the tutorial for instance).
if not _ba.app.headless_mode:
active_players = [p for p in self.sessionplayers if p.in_game]
if not active_players:
self.end()

View File

@ -36,6 +36,10 @@ class Level:
self._index: Optional[int] = None
self._score_version_string: Optional[str] = None
def __repr__(self) -> str:
cls = type(self)
return f"<{cls.__module__}.{cls.__name__} '{self._name}'>"
@property
def name(self) -> str:
"""The unique name for this Level."""

View File

@ -98,8 +98,6 @@ class ServerController:
self._playlist_fetch_got_response = False
self._playlist_fetch_code = -1
self._coop_game_name = self._config.coop_game_name
# Now sit around doing any pre-launch prep such as waiting for
# account sign-in or fetching playlists; this will kick off the
# session once done.
@ -349,11 +347,9 @@ class ServerController:
appcfg['Team Tournament Playlist Randomize'] = (
self._config.playlist_shuffle)
elif sessiontype is CoopSession:
gamename = self._coop_game_name or 'Default:Onslaught Training'
campaignname, levelname = gamename.split(':')
app.coop_session_args = {
'campaign': campaignname,
'level': levelname,
'campaign': self._config.coop_campaign,
'level': self._config.coop_level,
}
else:
raise RuntimeError(f'Unknown session type {sessiontype}')

View File

@ -206,11 +206,12 @@ class Session:
return node
def should_allow_mid_activity_joins(self, activity: ba.Activity) -> bool:
"""Returned value is used by the Session to determine
whether to allow players to join in the middle of activity.
"""Ask ourself if we should allow joins during an Activity.
Activity.allow_mid_activity_joins is also required to allow these
joins."""
Note that for a join to be allowed, both the Session and Activity
have to be ok with it (via this function and the
Activity.allow_mid_activity_joins property.
"""
del activity # Unused.
return True

View File

@ -561,7 +561,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
fail_message = None
else:
score = None
fail_message = 'Reach wave 2 to rank.'
fail_message = ba.Lstr(resource='reachWave2Text')
self.end(delay=delay,
results={

View File

@ -766,6 +766,7 @@
<w>outpath</w>
<w>outputter</w>
<w>outval</w>
<w>outvals</w>
<w>outvalue</w>
<w>ouya</w>
<w>ovld</w>

View File

@ -1837,11 +1837,11 @@ is pressed.</p>
<dt><h4><a name="method_ba_CoopSession__should_allow_mid_activity_joins">should_allow_mid_activity_joins()</a></dt></h4><dd>
<p><span>should_allow_mid_activity_joins(self, activity: <a href="#class_ba_Activity">ba.Activity</a>) -&gt; bool</span></p>
<p>Returned value is used by the Session to determine
whether to allow players to join in the middle of activity.</p>
<p>Ask ourself if we should allow joins during an Activity.</p>
<p>Activity.allow_mid_activity_joins is also required to allow these
joins.</p>
<p>Note that for a join to be allowed, both the Session and Activity
have to be ok with it (via this function and the
Activity.allow_mid_activity_joins property.</p>
</dd>
</dl>
@ -5263,11 +5263,11 @@ session.setactivity(foo) and then <a href="#function_ba_newnode">ba.newnode</a>(
<dt><h4><a name="method_ba_Session__should_allow_mid_activity_joins">should_allow_mid_activity_joins()</a></dt></h4><dd>
<p><span>should_allow_mid_activity_joins(self, activity: <a href="#class_ba_Activity">ba.Activity</a>) -&gt; bool</span></p>
<p>Returned value is used by the Session to determine
whether to allow players to join in the middle of activity.</p>
<p>Ask ourself if we should allow joins during an Activity.</p>
<p>Activity.allow_mid_activity_joins is also required to allow these
joins.</p>
<p>Note that for a join to be allowed, both the Session and Activity
have to be ok with it (via this function and the
Activity.allow_mid_activity_joins property.</p>
</dd>
</dl>

View File

@ -55,10 +55,7 @@ class ServerConfig:
# This value is ignored if you supply a playlist_code (see below).
session_type: str = 'ffa'
# There are unavailable co-op playlists now, so if you want to host a co-op
# game, pass level name here.
coop_game_name: Optional[str] = None
# Playlist-code for teams or free-for-all mode sessions.
# To host your own custom playlists, use the 'share' functionality in the
# playlist editor in the regular version of the game.
# This will give you a numeric code you can enter here to host that
@ -76,6 +73,15 @@ class ServerConfig:
# (teams mode only).
auto_balance_teams: bool = True
# The campaign used when in co-op session mode.
# Do print(ba.app.campaigns) to see available campaign names.
coop_campaign: str = 'Easy'
# The level name within the campaign used in co-op session mode.
# For campaign name FOO, do print(ba.app.campaigns['FOO'].levels) to see
# available level names.
coop_level: str = 'Onslaught Training'
# Whether to enable telnet access.
# IMPORTANT: This option is no longer available, as it was being used
# for exploits. Live access to the running server is still possible through

View File

@ -742,10 +742,14 @@ def _get_server_config_template_yaml(projroot: str) -> str:
continue
if line != '' and not line.startswith('#'):
vname, _vtype, veq, vval_raw = line.split()
before_equal_sign, vval_raw = line.split('=', 1)
before_equal_sign = before_equal_sign.strip()
vval_raw = vval_raw.strip()
# vname, _vtype, veq, vval_raw = line.split()
vname, _vtype = before_equal_sign.split()
assert vname.endswith(':')
vname = vname[:-1]
assert veq == '='
# assert veq == '='
vval: Any
if vval_raw == 'field(default_factory=list)':
vval = []