ProjectAres/PGM/src/main/java/tc/oc/pgm/scoreboard/ScoreboardMatchModule.java

248 lines
10 KiB
Java

package tc.oc.pgm.scoreboard;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import javax.inject.Inject;
import com.google.common.collect.Iterables;
import me.anxuiz.settings.Setting;
import me.anxuiz.settings.SettingCallbackManager;
import me.anxuiz.settings.bukkit.PlayerSettingCallback;
import me.anxuiz.settings.bukkit.PlayerSettings;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.scoreboard.ScoreboardManager;
import org.bukkit.scoreboard.Team;
import tc.oc.commons.core.formatting.StringUtils;
import tc.oc.commons.core.util.MapUtils;
import tc.oc.pgm.events.ListenerScope;
import tc.oc.pgm.events.PartyAddEvent;
import tc.oc.pgm.events.PartyRemoveEvent;
import tc.oc.pgm.events.PartyRenameEvent;
import tc.oc.pgm.events.PlayerPartyChangeEvent;
import tc.oc.pgm.ghostsquadron.GhostSquadronMatchModule;
import tc.oc.pgm.match.Competitor;
import tc.oc.pgm.match.MatchModule;
import tc.oc.pgm.match.MatchPlayer;
import tc.oc.pgm.match.MatchScope;
import tc.oc.pgm.match.Party;
@ListenerScope(MatchScope.LOADED)
public class ScoreboardMatchModule extends MatchModule implements Listener {
protected final Map<Party, Scoreboard> partyScoreboards = new HashMap<>();
protected final Scoreboard hiddenScoreboard;
private final SettingCallbackManager settingCallbackManager;
protected final PlayerSettingCallback settingCallback = new PlayerSettingCallback() {
@Override
public void notifyChange(Player player, Setting setting, @Nullable Object oldValue, @Nullable Object newValue) {
MatchPlayer matchPlayer = getMatch().getPlayer(player);
if(matchPlayer != null) {
updatePlayer(matchPlayer, matchPlayer.getParty(), (Boolean) newValue);
}
}
};
@Inject ScoreboardMatchModule(ScoreboardManager scoreboardManager, SettingCallbackManager settingCallbackManager) {
this.hiddenScoreboard = scoreboardManager.getNewScoreboard();
this.settingCallbackManager = settingCallbackManager;
}
@Override
public void load() {
super.load();
match.parties().forEach(this::getScoreboard);
settingCallbackManager.addCallback(ScoreboardSettings.SHOW_SCOREBOARD, settingCallback);
}
@Override
public void unload() {
settingCallbackManager.removeCallback(ScoreboardSettings.SHOW_SCOREBOARD, settingCallback);
super.unload();
}
protected boolean getShowSetting(MatchPlayer player) {
return PlayerSettings.getManager(player.getBukkit()).getValue(ScoreboardSettings.SHOW_SCOREBOARD, Boolean.class);
}
protected String getScoreboardTeamName(@Nullable Party party) {
return party == null ? null : StringUtils.truncate(party.getDefaultName(), 16);
}
protected void updatePartyScoreboardTeam(Party party, Team team, boolean forObservers) {
logger.fine("Updating scoreboard team " + toString(team) + " for party " + party);
team.setDisplayName(party.getName());
team.setPrefix(party.getColor().toString());
team.setSuffix(ChatColor.WHITE.toString());
team.setCanSeeFriendlyInvisibles(true);
team.setAllowFriendlyFire(getMatch().getMapInfo().friendlyFire);
team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
if(!forObservers && party instanceof Competitor) {
Team.OptionStatus nameTags = ((Competitor) party).getNameTagVisibility();
// #HACK until this is fixed https://bugs.mojang.com/browse/MC-48730 we need to
// ensure enemy name tags are always hidden for GS.
if(getMatch().getMatchModule(GhostSquadronMatchModule.class) != null) {
switch(nameTags) {
case ALWAYS: nameTags = Team.OptionStatus.FOR_OWN_TEAM; break;
case FOR_OTHER_TEAMS: nameTags = Team.OptionStatus.NEVER; break;
}
}
team.setOption(Team.Option.NAME_TAG_VISIBILITY, nameTags);
} else {
team.setOption(Team.Option.NAME_TAG_VISIBILITY, Team.OptionStatus.ALWAYS);
}
}
protected Team createPartyScoreboardTeam(Party party, Scoreboard scoreboard, boolean forObservers) {
logger.fine("Creating team for party " + party + " on scoreboard " + toString(scoreboard));
Team team = scoreboard.registerNewTeam(getScoreboardTeamName(party));
updatePartyScoreboardTeam(party, team, forObservers);
for(MatchPlayer player : party.getPlayers()) {
team.addPlayer(player.getBukkit());
}
return team;
}
public Scoreboard getScoreboard(Party party) {
return MapUtils.computeIfAbsent(partyScoreboards, party, () -> {
// Create the new party's scoreboard
Scoreboard scoreboard = getMatch().getServer().getScoreboardManager().getNewScoreboard();
logger.fine("Created scoreboard " + toString(scoreboard) + " for party " + party);
// Add all other party scoreboards to the new party's scoreboard
for(Party oldParty : partyScoreboards.keySet()) {
createPartyScoreboardTeam(oldParty, scoreboard, !(party instanceof Competitor));
}
// Add the new party to its own scoreboard
createPartyScoreboardTeam(party, scoreboard, !(party instanceof Competitor));
// Add the new party to the hidden scoreboard
createPartyScoreboardTeam(party, hiddenScoreboard, false);
// Add the new party to all other party scoreboards
for(Map.Entry<Party, Scoreboard> entry : partyScoreboards.entrySet()) {
createPartyScoreboardTeam(party, entry.getValue(), !(entry.getKey() instanceof Competitor));
}
return scoreboard;
});
}
protected void removePartyScoreboard(Party party) {
// Remove and tear down the leaving party's scoreboard
Scoreboard scoreboard = partyScoreboards.remove(party);
if(scoreboard != null) {
for(Objective objective : scoreboard.getObjectives()) {
objective.unregister();
}
for(Team team : scoreboard.getTeams()) {
team.unregister();
}
}
logger.fine("Removed scoreboard " + toString(scoreboard) + " for party " + party);
// Remove the leaving party from all other scoreboards
String name = getScoreboardTeamName(party);
for(Scoreboard otherScoreboard : getScoreboards()) {
Team team = otherScoreboard.getTeam(name);
if(team != null) {
logger.fine("Unregistering team " + toString(team) + " from scoreboard " + toString(otherScoreboard));
team.unregister();
}
}
}
protected void changePlayerScoreboard(MatchPlayer player, @Nullable Party oldParty, @Nullable Party newParty) {
// Change the player's team in all scoreboards
String teamName = getScoreboardTeamName(newParty != null ? newParty : oldParty);
for(Scoreboard scoreboard : getScoreboards()) {
if(newParty != null) {
Team team = scoreboard.getTeam(teamName);
logger.fine("Adding player " + player + " to team " + toString(team) + " on scoreboard " + toString(scoreboard));
team.addPlayer(player.getBukkit()); // This also removes the player from their old team, if any
} else if(oldParty != null) {
Team team = scoreboard.getTeam(teamName);
logger.fine("Removing player " + player + " from team " + toString(team) + " on scoreboard " + toString(scoreboard));
team.removePlayer(player.getBukkit());
}
}
// Set the player's scoreboard
if(newParty != null) {
updatePlayer(player, newParty, getShowSetting(player));
}
}
protected void updatePlayer(MatchPlayer player, Party party, boolean show) {
if(show) {
Scoreboard scoreboard = partyScoreboards.get(party);
logger.fine("Setting player " + player + " to scoreboard " + toString(scoreboard));
player.getBukkit().setScoreboard(scoreboard);
} else {
logger.fine("Setting player " + player + " to hidden scoreboard");
player.getBukkit().setScoreboard(getHiddenScoreboard());
}
}
public Scoreboard getHiddenScoreboard() {
return hiddenScoreboard;
}
public Iterable<Scoreboard> getScoreboards() {
return Iterables.concat(partyScoreboards.values(), Collections.singleton(hiddenScoreboard));
}
public void updatePartyScoreboardTeam(Party party) {
String teamName = getScoreboardTeamName(party);
updatePartyScoreboardTeam(party, hiddenScoreboard.getTeam(teamName), false);
for(Map.Entry<Party, Scoreboard> entry : partyScoreboards.entrySet()) {
updatePartyScoreboardTeam(party, entry.getValue().getTeam(teamName), !(entry.getKey() instanceof Competitor));
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPartyAdd(PartyAddEvent event) {
getScoreboard(event.getParty());
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPartyRemove(PartyRemoveEvent event) {
removePartyScoreboard(event.getParty());
}
@EventHandler
public void onPartyRename(PartyRenameEvent event) {
updatePartyScoreboardTeam(event.getParty());
}
@EventHandler
public void onPlayerChangeParty(PlayerPartyChangeEvent event) {
changePlayerScoreboard(event.getPlayer(), event.getOldParty(), event.getNewParty());
}
private static String toString(Scoreboard scoreboard) {
return scoreboard == null ? "null" : "bukkit." + scoreboard.getClass().getSimpleName() + "{" + scoreboard.hashCode() + "}";
}
private static String toString(Team team) {
return team == null ? "null" : "bukkit." + team.getClass().getSimpleName() + "{" + team.getName() + "}";
}
}