Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show division in replays when available #3042

Merged
merged 11 commits into from
Mar 22, 2024
Merged
3 changes: 3 additions & 0 deletions src/main/java/com/faforever/client/api/FafApiAccessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.faforever.commons.api.dto.GameReviewsSummary;
import com.faforever.commons.api.dto.LeaderboardEntry;
import com.faforever.commons.api.dto.LeaderboardRatingJournal;
import com.faforever.commons.api.dto.LeagueScoreJournal;
import com.faforever.commons.api.dto.LeagueSeason;
import com.faforever.commons.api.dto.LeagueSeasonDivisionSubdivision;
import com.faforever.commons.api.dto.LeagueSeasonScore;
Expand Down Expand Up @@ -97,6 +98,8 @@ public class FafApiAccessor implements InitializingBean {
List.of("leagueSeason", "leagueSeason.leaderboard", "leagueSeason.league",
"leagueSeasonDivisionSubdivision", "leagueSeasonDivisionSubdivision.leagueSeasonDivision")),
java.util.Map.entry(LeagueSeasonDivisionSubdivision.class, List.of("leagueSeasonDivision")),
java.util.Map.entry(LeagueScoreJournal.class, List.of("leagueSeason", "leagueSeasonDivisionSubdivisionBefore", "leagueSeasonDivisionSubdivisionAfter",
"leagueSeasonDivisionSubdivisionBefore.leagueSeasonDivision", "leagueSeasonDivisionSubdivisionAfter.leagueSeasonDivision")),
java.util.Map.entry(MapVersion.class, List.of("map", "map.reviewsSummary", "map.author")),
java.util.Map.entry(MapReviewsSummary.class, List.of("map.latestVersion", "map.author", "map.reviewsSummary")),
java.util.Map.entry(Map.class, List.of("latestVersion", "author", "reviewsSummary")),
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/faforever/client/domain/api/GameOutcome.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.faforever.client.domain.api;

public enum GameOutcome {
VICTORY,
DEFEAT,
DRAW,
MUTUAL_DRAW,
UNKNOWN,
CONFLICTING
}
12 changes: 10 additions & 2 deletions src/main/java/com/faforever/client/domain/api/GamePlayerStats.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@
import java.util.List;

public record GamePlayerStats(
PlayerInfo player, byte score, byte team,
Faction faction, OffsetDateTime scoreTime, List<LeaderboardRatingJournal> leaderboardRatingJournals
boolean ai,
Faction faction,
byte color,
byte team,
byte startSpot,
byte score,
OffsetDateTime scoreTime,
GameOutcome outcome,
PlayerInfo player,
List<LeaderboardRatingJournal> leaderboardRatingJournals
) {

public GamePlayerStats {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.faforever.client.domain.api;

public record LeagueScoreJournal(
int id,
int gameId,
int loginId,
int gameCount,
int scoreBefore,
int scoreAfter,
LeagueSeason season,
Subdivision divisionBefore,
Subdivision divisionAfter
) {}

53 changes: 49 additions & 4 deletions src/main/java/com/faforever/client/game/PlayerCardController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.faforever.client.avatar.AvatarService;
import com.faforever.client.domain.api.GamePlayerStats;
import com.faforever.client.domain.api.LeaderboardRatingJournal;
import com.faforever.client.domain.api.Subdivision;
import com.faforever.client.domain.server.PlayerInfo;
import com.faforever.client.fx.JavaFxUtil;
import com.faforever.client.fx.NodeController;
Expand All @@ -21,8 +22,10 @@
import com.faforever.client.fx.contextmenu.ShowPlayerInfoMenuItem;
import com.faforever.client.fx.contextmenu.ViewReplaysMenuItem;
import com.faforever.client.i18n.I18n;
import com.faforever.client.leaderboard.LeaderboardService;
import com.faforever.client.player.CountryFlagService;
import com.faforever.client.player.SocialStatus;
import com.faforever.client.replay.DisplayType;
import com.faforever.client.theme.ThemeService;
import com.faforever.client.theme.UiService;
import com.faforever.client.util.RatingUtil;
Expand Down Expand Up @@ -60,6 +63,7 @@
private final UiService uiService;
private final CountryFlagService countryFlagService;
private final AvatarService avatarService;
private final LeaderboardService leaderboardService;
private final ContextMenuBuilder contextMenuBuilder;
private final I18n i18n;

Expand All @@ -72,21 +76,30 @@
public Label friendIconText;
public Region factionIcon;
public ImageView factionImage;
public ImageView divisionImageView;
public Label noteIcon;
public Label ratingLabel;
public Label ratingChange;

private final ObjectProperty<PlayerInfo> player = new SimpleObjectProperty<>();
private final ObjectProperty<GamePlayerStats> playerStats = new SimpleObjectProperty<>();
private final ObjectProperty<Integer> rating = new SimpleObjectProperty<>();
private final ObjectProperty<Subdivision> division = new SimpleObjectProperty<>();
private final ObjectProperty<Faction> faction = new SimpleObjectProperty<>();
private final ObjectProperty<DisplayType> displayType = new SimpleObjectProperty<>();
private final Tooltip noteTooltip = new Tooltip();
private final Tooltip avatarTooltip = new Tooltip();
private final Tooltip divisionTooltip = new Tooltip();

@Override
protected void onInitialize() {
JavaFxUtil.bindManagedToVisible(avatarStackPane, factionIcon, foeIconText, factionImage, friendIconText, countryImageView, noteIcon);
JavaFxUtil.bindManagedToVisible(avatarStackPane, factionIcon, foeIconText, factionImage, friendIconText,
countryImageView, divisionImageView, ratingLabel, ratingChange, noteIcon);
countryImageView.visibleProperty().bind(countryImageView.imageProperty().isNotNull());
avatarImageView.visibleProperty().bind(avatarImageView.imageProperty().isNotNull());
divisionImageView.visibleProperty().bind(divisionImageView.imageProperty().isNotNull());
ratingLabel.visibleProperty().bind(rating.isNotNull().and(displayType.isEqualTo(DisplayType.RATING)));
ratingChange.visibleProperty().bind(playerStats.isNotNull().and(displayType.isEqualTo(DisplayType.RATING)));

factionImage.setImage(uiService.getImage(ThemeService.RANDOM_FACTION_IMAGE));
factionImage.visibleProperty().bind(faction.map(value -> value == Faction.RANDOM));
Expand All @@ -97,10 +110,12 @@
.when(showing));
avatarImageView.imageProperty()
.bind(player.flatMap(PlayerInfo::avatarProperty).map(avatarService::loadAvatar).when(showing));
divisionImageView.imageProperty()
.bind(division.map(Subdivision::smallImageUrl).map(leaderboardService::loadDivisionImage).when(showing));
playerInfo.textProperty().bind(player.flatMap(PlayerInfo::usernameProperty)
.flatMap(username -> rating.map(value -> i18n.get("userInfo.tooltipFormat.withRating", username, value))
.orElse(i18n.get("userInfo.tooltipFormat.noRating", username)))
.when(showing));
ratingLabel.textProperty().bind(rating.map(value -> i18n.get("game.tooltip.ratingFormat", value))
.when(showing));
foeIconText.visibleProperty().bind(player.flatMap(PlayerInfo::socialStatusProperty)
.map(socialStatus -> socialStatus == SocialStatus.FOE)
.when(showing));
Expand All @@ -111,7 +126,6 @@
.when(showing)
.addListener((SimpleChangeListener<String>) this::onNoteChanged);

ratingChange.visibleProperty().bind(playerStats.isNotNull());
ObservableValue<Integer> ratingChangeObservable = playerStats.map(GamePlayerStats::leaderboardRatingJournals)
.map(
journals -> journals.isEmpty() ? null : journals.getFirst())
Expand All @@ -131,6 +145,13 @@
avatarTooltip.setShowDelay(Duration.ZERO);
avatarTooltip.setShowDuration(Duration.seconds(30));
Tooltip.install(avatarImageView, avatarTooltip);

divisionTooltip.textProperty().bind(
division.map(value -> i18n.get("leaderboard.divisionName", i18n.get("leagues.divisionName.%s".formatted(value.division().nameKey())), value.nameKey()))
.when(showing));
divisionTooltip.setShowDelay(Duration.ZERO);
divisionTooltip.setShowDuration(Duration.seconds(30));
Tooltip.install(divisionImageView, divisionTooltip);
}

private void onNoteChanged(String newValue) {
Expand Down Expand Up @@ -241,6 +262,18 @@
this.rating.set(rating);
}

public Subdivision getDivision() {
return division.get();

Check warning on line 266 in src/main/java/com/faforever/client/game/PlayerCardController.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/game/PlayerCardController.java#L266

Added line #L266 was not covered by tests
}

public ObjectProperty<Subdivision> divisionProperty() {
return division;

Check warning on line 270 in src/main/java/com/faforever/client/game/PlayerCardController.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/game/PlayerCardController.java#L270

Added line #L270 was not covered by tests
}

public void setDivision(Subdivision subdivision) {
this.division.set(subdivision);
}

Check warning on line 275 in src/main/java/com/faforever/client/game/PlayerCardController.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/game/PlayerCardController.java#L274-L275

Added lines #L274 - L275 were not covered by tests

public Faction getFaction() {
return faction.get();
}
Expand All @@ -253,6 +286,18 @@
this.faction.set(faction);
}

public DisplayType getDisplayType() {
return displayType.get();

Check warning on line 290 in src/main/java/com/faforever/client/game/PlayerCardController.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/game/PlayerCardController.java#L290

Added line #L290 was not covered by tests
}

public ObjectProperty<DisplayType> displayTypeProperty() {
return displayType;

Check warning on line 294 in src/main/java/com/faforever/client/game/PlayerCardController.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/game/PlayerCardController.java#L294

Added line #L294 was not covered by tests
}

public void setDisplayType(DisplayType displayType) {
this.displayType.set(displayType);
}

public GamePlayerStats getPlayerStats() {
return playerStats.get();
}
Expand Down
84 changes: 80 additions & 4 deletions src/main/java/com/faforever/client/game/TeamCardController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@


import com.faforever.client.domain.api.GamePlayerStats;
import com.faforever.client.domain.api.Subdivision;
import com.faforever.client.domain.server.GameInfo;
import com.faforever.client.domain.api.GameOutcome;
import com.faforever.client.domain.server.PlayerInfo;
import com.faforever.client.fx.FxApplicationThreadExecutor;
import com.faforever.client.fx.JavaFxUtil;
import com.faforever.client.fx.NodeController;
import com.faforever.client.fx.SimpleChangeListener;
import com.faforever.client.i18n.I18n;
import com.faforever.client.player.PlayerService;
import com.faforever.client.replay.DisplayType;
import com.faforever.client.theme.UiService;
import com.faforever.client.util.RatingUtil;
import com.faforever.commons.api.dto.Faction;
Expand All @@ -18,6 +22,7 @@
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.css.PseudoClass;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
Expand All @@ -43,6 +48,12 @@
@Slf4j
@RequiredArgsConstructor
public class TeamCardController extends NodeController<Node> {

private static final PseudoClass VICTORY = PseudoClass.getPseudoClass("victory");
private static final PseudoClass DEFEAT = PseudoClass.getPseudoClass("defeat");
private static final PseudoClass DRAW = PseudoClass.getPseudoClass("draw");
private static final PseudoClass UNKNOWN = PseudoClass.getPseudoClass("unknown");

private final I18n i18n;
private final PlayerService playerService;
private final FxApplicationThreadExecutor fxApplicationThreadExecutor;
Expand All @@ -51,12 +62,17 @@
public Pane teamPaneRoot;
public VBox teamPane;
public Label teamNameLabel;
public Label teamRatingLabel;
public Label gameResultLabel;

private final ObjectProperty<List<Integer>> playerIds = new SimpleObjectProperty<>(List.of());
private final ObjectProperty<List<PlayerInfo>> players = new SimpleObjectProperty<>(List.of());
private final ObjectProperty<Function<PlayerInfo, Integer>> ratingProvider = new SimpleObjectProperty<>();
private final ObjectProperty<Function<PlayerInfo, Subdivision>> divisionProvider = new SimpleObjectProperty<>();
private final ObjectProperty<Function<PlayerInfo, Faction>> factionProvider = new SimpleObjectProperty<>();
private final ObjectProperty<RatingPrecision> ratingPrecision = new SimpleObjectProperty<>();
private final ObjectProperty<GameOutcome> teamOutcome = new SimpleObjectProperty<>();
private final ObjectProperty<DisplayType> displayType = new SimpleObjectProperty<>();
private final IntegerProperty teamId = new SimpleIntegerProperty();
private final SimpleChangeListener<List<PlayerInfo>> playersListener = this::populateTeamContainer;
private final ObservableValue<Integer> teamRating = ratingProvider.flatMap(provider -> ratingPrecision.flatMap(precision -> players.map(playerBeans -> playerBeans.stream()
Expand All @@ -69,19 +85,23 @@

@Override
protected void onInitialize() {
setDisplayType(DisplayType.RATING);
teamNameLabel.textProperty()
.bind(teamRating.flatMap(teamRating -> teamId.map(id -> switch (id.intValue()) {
.bind(teamId.map(id -> switch (id.intValue()) {
case 0, GameInfo.NO_TEAM -> i18n.get("game.tooltip.teamTitleNoTeam");
case GameInfo.OBSERVERS_TEAM -> i18n.get("game.tooltip.observers");
default -> {
try {
yield i18n.get("game.tooltip.teamTitle", id.intValue() - 1, teamRating);
yield i18n.get("game.tooltip.teamTitle", id.intValue() - 1);
} catch (NumberFormatException e) {
yield "";
}
}
})));

}));
JavaFxUtil.bindManagedToVisible(teamRatingLabel, gameResultLabel);
teamRatingLabel.textProperty().bind(teamRating.map(value -> i18n.get("game.tooltip.ratingFormat", value)));
teamRatingLabel.visibleProperty().bind(teamRating.flatMap(teamRating -> displayType.map(type -> type == DisplayType.RATING && teamRating != 0)));
gameResultLabel.visibleProperty().bind(gameResultLabel.textProperty().isEmpty().not());
players.addListener(playersListener);
}

Expand All @@ -99,27 +119,71 @@
controller.ratingProperty()
.bind(ratingProvider.map(ratingFunction -> ratingFunction.apply(player))
.flatMap(rating -> ratingPrecision.map(precision -> precision == RatingPrecision.ROUNDED ? RatingUtil.getRoundedRating(rating) : rating)));
controller.divisionProperty()
.bind(divisionProvider.map(divisionFunction -> divisionFunction.apply(player)));
controller.factionProperty()
.bind(factionProvider.map(factionFunction -> factionFunction.apply(player)));
controller.setPlayer(player);
controller.displayTypeProperty().bind(displayType);

playerCardControllersMap.put(player, controller);

return controller;
}).toList();
}

public void showGameResult() {
switch (teamOutcome.get()) {
case VICTORY -> {
gameResultLabel.setText(i18n.get("game.resultVictory"));
gameResultLabel.pseudoClassStateChanged(VICTORY, true);
gameResultLabel.pseudoClassStateChanged(DEFEAT, false);
gameResultLabel.pseudoClassStateChanged(DRAW, false);
gameResultLabel.pseudoClassStateChanged(UNKNOWN, false);
}

Check warning on line 143 in src/main/java/com/faforever/client/game/TeamCardController.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/game/TeamCardController.java#L138-L143

Added lines #L138 - L143 were not covered by tests
case DEFEAT -> {
gameResultLabel.setText(i18n.get("game.resultDefeat"));
gameResultLabel.pseudoClassStateChanged(VICTORY, false);
gameResultLabel.pseudoClassStateChanged(DEFEAT, true);
gameResultLabel.pseudoClassStateChanged(DRAW, false);
gameResultLabel.pseudoClassStateChanged(UNKNOWN, false);
}

Check warning on line 150 in src/main/java/com/faforever/client/game/TeamCardController.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/game/TeamCardController.java#L145-L150

Added lines #L145 - L150 were not covered by tests
case DRAW, MUTUAL_DRAW -> {
gameResultLabel.setText(i18n.get("game.resultDraw"));
gameResultLabel.pseudoClassStateChanged(VICTORY, false);
gameResultLabel.pseudoClassStateChanged(DEFEAT, false);
gameResultLabel.pseudoClassStateChanged(DRAW, true);
gameResultLabel.pseudoClassStateChanged(UNKNOWN, false);
}
default -> {
gameResultLabel.setText(i18n.get("game.resultUnknown"));
gameResultLabel.pseudoClassStateChanged(VICTORY, false);
gameResultLabel.pseudoClassStateChanged(DEFEAT, false);
gameResultLabel.pseudoClassStateChanged(DRAW, false);
gameResultLabel.pseudoClassStateChanged(UNKNOWN, true);

Check warning on line 163 in src/main/java/com/faforever/client/game/TeamCardController.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/game/TeamCardController.java#L159-L163

Added lines #L159 - L163 were not covered by tests
}
}
}

public void bindPlayersToPlayerIds() {
players.bind(playerIds.map(ids -> ids.stream()
.map(playerService::getPlayerByIdIfOnline)
.flatMap(Optional::stream)
.collect(Collectors.toCollection(FXCollections::observableArrayList))));
}

public void setDisplayType(DisplayType type) {
this.displayType.set(type);
}

public void setRatingProvider(Function<PlayerInfo, Integer> ratingProvider) {
this.ratingProvider.set(ratingProvider);
}

public void setDivisionProvider(Function<PlayerInfo, Subdivision> divisionProvider) {
this.divisionProvider.set(divisionProvider);
}

Check warning on line 185 in src/main/java/com/faforever/client/game/TeamCardController.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/game/TeamCardController.java#L184-L185

Added lines #L184 - L185 were not covered by tests

public void setFactionProvider(Function<PlayerInfo, Faction> factionProvider) {
this.factionProvider.set(factionProvider);
}
Expand Down Expand Up @@ -156,6 +220,18 @@
return ratingProvider;
}

public void setTeamOutcome(GameOutcome teamOutcome) {
this.teamOutcome.set(teamOutcome);
}

public GameOutcome getTeamOutcome() {
return teamOutcome.get();

Check warning on line 228 in src/main/java/com/faforever/client/game/TeamCardController.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/game/TeamCardController.java#L228

Added line #L228 was not covered by tests
}

public ObjectProperty<GameOutcome> teamResult() {
return teamOutcome;

Check warning on line 232 in src/main/java/com/faforever/client/game/TeamCardController.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/game/TeamCardController.java#L232

Added line #L232 was not covered by tests
}

public void setStats(List<GamePlayerStats> teamPlayerStats) {
for (GamePlayerStats playerStats : teamPlayerStats) {
PlayerCardController controller = playerCardControllersMap.get(playerStats.player());
Expand Down
Loading
Loading