FAForever / server

The servercode for the Forged Alliance Forever lobby

Home Page:http://www.faforever.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Remove mutual draw exemption for game validity

Sheikah45 opened this issue · comments

A mutual draw is only the case when all players in the game ask for a draw. If someone already died then the server doesn't consider this a mutual draw.

The server treats games where players ask for a draw after someone died the same as all teams died draw as seen here.

def resolve_game(team_outcomes: list[set[ArmyOutcome]]) -> list[GameOutcome]:
"""
Takes a list of length two containing sets of ArmyOutcome
for individual players on a team
and converts a list of two GameOutcomes,
either VICTORY and DEFEAT or DRAW and DRAW.
# Params
- `team_outcomes`: list of `GameOutcomes`
# Errors
Throws `GameResolutionError` if outcomes are inconsistent or ambiguous.
# Returns
A list of ranks as to be used with trueskill
"""
if len(team_outcomes) != 2:
raise GameResolutionError(
"Will not resolve game with other than two parties."
)
victory0 = ArmyOutcome.VICTORY in team_outcomes[0]
victory1 = ArmyOutcome.VICTORY in team_outcomes[1]
both_claim_victory = victory0 and victory1
someone_claims_victory = victory0 or victory1
if both_claim_victory:
raise GameResolutionError(
"Cannot resolve game in which both teams claimed victory. "
f" Team outcomes: {team_outcomes}"
)
elif someone_claims_victory:
return [
GameOutcome.VICTORY
if ArmyOutcome.VICTORY in outcomes
else GameOutcome.DEFEAT
for outcomes in team_outcomes
]
# Now know that no-one has GameOutcome.VICTORY
draw0 = ArmyOutcome.DRAW in team_outcomes[0]
draw1 = ArmyOutcome.DRAW in team_outcomes[1]
both_claim_draw = draw0 and draw1
someone_claims_draw = draw0 or draw1
if both_claim_draw:
return [GameOutcome.DRAW, GameOutcome.DRAW]
elif someone_claims_draw:
raise GameResolutionError(
"Cannot resolve game with unilateral draw. "
f"Team outcomes: {team_outcomes}"
)
# Now know that the only results are DEFEAT or UNKNOWN/CONFLICTING
# Unrank if there are any players with unknown result
all_outcomes = team_outcomes[0] | team_outcomes[1]
if (
ArmyOutcome.UNKNOWN in all_outcomes
or ArmyOutcome.CONFLICTING in all_outcomes
):
raise GameResolutionError(
"Cannot resolve game with ambiguous outcome. "
f" Team outcomes: {team_outcomes}"
)
# Otherwise everyone is DEFEAT, we return a draw
return [GameOutcome.DRAW, GameOutcome.DRAW]

The only case when the server unranks for a mutual draw is when all players survive and all players ask for a draw as seen here.

def is_mutually_agreed_draw(self, player_armies) -> bool:
# Can't tell if we have no results
if not self:
return False
# Everyone has to agree to a mutual draw
for army in player_armies:
if army not in self:
continue
if any(r.outcome is not ArmyReportedOutcome.MUTUAL_DRAW for r in self[army]):
return False
return True

This is an artifact left from when ladder was only 1v1 as this situation would never occur in that context.

This is unintuitive and would be better to just rank all drawn games through any method.

Fine with me. So you're saying that the game outcome resolution already handles all the cases correctly, and we just need to remove the special case for unranking mutual draws?

correct since resolve game doesn't distinguish between a draw by everyone defeated vs a draw where people use the button