ProjectAres/PGM/src/main/java/tc/oc/pgm/channels/ChannelMatchModule.java

207 lines
9.3 KiB
Java

package tc.oc.pgm.channels;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import com.github.rmsy.channels.Channel;
import com.github.rmsy.channels.ChannelsPlugin;
import com.github.rmsy.channels.PlayerManager;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.Plugin;
import tc.oc.chatmoderator.ChatModeratorPlugin;
import tc.oc.commons.bukkit.chat.ComponentRenderers;
import tc.oc.commons.bukkit.util.NullCommandSender;
import tc.oc.commons.bukkit.util.OnlinePlayerMapAdapter;
import tc.oc.commons.core.util.DefaultMapAdapter;
import tc.oc.pgm.events.ListenerScope;
import tc.oc.pgm.events.PartyAddEvent;
import tc.oc.pgm.events.PartyRemoveEvent;
import tc.oc.pgm.events.PlayerJoinPartyEvent;
import tc.oc.pgm.events.PlayerLeavePartyEvent;
import tc.oc.pgm.match.Match;
import tc.oc.pgm.match.MatchModule;
import tc.oc.pgm.match.MatchPlayer;
import tc.oc.pgm.match.MatchScope;
import tc.oc.pgm.match.MultiPlayerParty;
import tc.oc.pgm.match.Party;
@ListenerScope(MatchScope.LOADED)
public class ChannelMatchModule extends MatchModule implements Listener {
public static final String RECEIVE_ALL_PERMISSION = "pgm.chat.all.receive";
public static final String TEAM_RECEIVE_PERMISSION = "pgm.chat.team.receive";
public static final String TEAM_SEND_PERMISSION = "pgm.chat.team.send";
// This dynamic permission has all party channel listening permissions as children.
// A player with this permission receives all channels simultaneously. It is granted
// automatically to observers that have the RECEIVE_ALL_PERMISSION.
private final Permission matchListeningPermission;
private final ChannelsPlugin channelsPlugin = ChannelsPlugin.get();
private final Map<MultiPlayerParty, PartyChannel> partyChannels = new HashMap<>();
// This is used to keep track of players' global/team chat preference. We can't just
// check their channel through the Channels plugin because FFA players always use the
// global channel. All players are set to team chat when they join a match, and the /t
// command sets them to team chat. They can switch to global chat with /g, but we don't
// know when this happens, so we check for it whenever they switch parties.
private final Map<Player, Boolean> teamChatters;
@Inject ChannelMatchModule(Match match, Plugin plugin) {
this.matchListeningPermission = new Permission("pgm.chat.all." + match.getId() + ".receive", PermissionDefault.FALSE);
final OnlinePlayerMapAdapter<Boolean> map = new OnlinePlayerMapAdapter<>(plugin);
map.enable();
this.teamChatters = new DefaultMapAdapter<>(map, true, false);
}
protected void updatePlayerChannel(MatchPlayer player) {
if(teamChatters.get(player.getBukkit())) {
channelsPlugin.getPlayerManager().setMembershipChannel(player.getBukkit(), getChannel(player.getParty()));
} else {
channelsPlugin.getPlayerManager().setMembershipChannel(player.getBukkit(), channelsPlugin.getGlobalChannel());
}
}
public void setTeamChat(MatchPlayer player, boolean teamChat) {
teamChatters.put(player.getBukkit(), teamChat);
updatePlayerChannel(player);
}
public Channel getChannel(Party party) {
if(party instanceof MultiPlayerParty) {
return partyChannels.get(party);
} else {
return channelsPlugin.getGlobalChannel();
}
}
protected Permission createChannelPermission(Party party) {
Permission permission = new Permission("pgm.chat.team." + this.match.getId() + '-' + party.hashCode() + ".receive", PermissionDefault.FALSE);
getMatch().getPluginManager().addPermission(permission);
permission.addParent(matchListeningPermission, true);
return permission;
}
protected void removeChannelPermission(Channel channel) {
matchListeningPermission.getChildren().remove(channel.getListeningPermission().getName());
matchListeningPermission.recalculatePermissibles();
getMatch().getPluginManager().removePermission(channel.getListeningPermission());
}
protected void createChannel(Party party) {
if(party instanceof MultiPlayerParty) {
logger.fine("Creating channel for " + party);
String format = ComponentRenderers.toLegacyText(party.getChatPrefix(), NullCommandSender.INSTANCE) + "{1}§f: §7{3}";
PartyChannel channel;
if (getMatch().getPluginManager().getPlugin("ChatModerator") == null) {
channel = new UnfilteredPartyChannel(format,
createChannelPermission(party),
party);
} else {
channel = new FilteredPartyChannel(format,
createChannelPermission(party),
party,
ChatModeratorPlugin.MINIMUM_SCORE_NO_SEND,
ChatModeratorPlugin.PARTIALLY_OFFENSIVE_RATIO);
}
if(partyChannels.put((MultiPlayerParty) party, channel) != null) {
throw new IllegalStateException("Party added multiple times");
}
}
}
@Override
public void load() {
super.load();
// Let the console receive all channels
match.getPluginManager().addPermission(matchListeningPermission);
getMatch().getServer().getConsoleSender().addAttachment(getMatch().getPlugin()).setPermission(matchListeningPermission, true);
// Parties may be created before the module loads
for(Party party : getMatch().getParties()) {
createChannel(party);
}
}
@Override
public void unload() {
getMatch().getServer().getConsoleSender().removeAttachments(matchListeningPermission);
getMatch().getPluginManager().removePermission(matchListeningPermission);
super.unload();
}
@EventHandler(priority = EventPriority.LOWEST)
public void partyAdd(final PartyAddEvent event) {
createChannel(event.getParty());
}
@EventHandler(priority = EventPriority.MONITOR)
public void partyRemove(final PartyRemoveEvent event) {
if(event.getParty() instanceof MultiPlayerParty) {
PartyChannel channel = partyChannels.remove(event.getParty());
if(channel != null) {
removeChannelPermission(channel);
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void partyJoin(PlayerJoinPartyEvent event) {
if(event.getNewParty() instanceof MultiPlayerParty) {
PlayerManager playerManager = channelsPlugin.getPlayerManager();
Player bukkitPlayer = event.getPlayer().getBukkit();
PartyChannel channel = partyChannels.get(event.getNewParty());
if(channel != null) {
if(event.getNewParty().isObservingType() && bukkitPlayer.hasPermission(RECEIVE_ALL_PERMISSION)) {
// If the player is joining observers and they have the receive-all perm, let them listen to all channels
bukkitPlayer.addAttachment(getMatch().getPlugin()).setPermission(matchListeningPermission, true);
} else if(bukkitPlayer.hasPermission(TEAM_RECEIVE_PERMISSION)) {
// Give the player listening permission for the team's channel
bukkitPlayer.addAttachment(getMatch().getPlugin()).setPermission(channel.getListeningPermission(), true);
}
// If their sending channel was previously set to a team channel, switch it to the new team's channel
if(playerManager.getMembershipChannel(bukkitPlayer) instanceof PartyChannel) {
playerManager.setMembershipChannel(bukkitPlayer, channel);
}
}
}
updatePlayerChannel(event.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void partyLeave(PlayerLeavePartyEvent event) {
if(event.getOldParty() instanceof MultiPlayerParty) {
PlayerManager playerManager = channelsPlugin.getPlayerManager();
Player bukkitPlayer = event.getPlayer().getBukkit();
PartyChannel channel = partyChannels.get(event.getOldParty());
if(channel != null) {
bukkitPlayer.removeAttachments(channel.getListeningPermission());
bukkitPlayer.removeAttachments(matchListeningPermission);
// Whenever the player leaves a party with its own channel, check if that is the player's current channel,
// and if it's not, then set their team chat setting to false. This is the only way to find out when they
// switch to global chat, because the Channels plugin doesn't provide any notifcation.
if(playerManager.getMembershipChannel(bukkitPlayer) != channel) {
teamChatters.put(bukkitPlayer, false);
}
}
}
}
}