Reworked chat completely. Added Herochat integration. New tag-parsing system. Non-monitor-breaking relation colored chat.

This commit is contained in:
Olof Larsson 2012-05-02 04:45:10 +02:00
parent 06d22549e2
commit 1459c9c057
14 changed files with 316 additions and 326 deletions

BIN
lib/Herochat.jar Normal file

Binary file not shown.

View File

@ -64,21 +64,18 @@ public class Conf
// Disallow joining/leaving/kicking while power is negative // Disallow joining/leaving/kicking while power is negative
public static boolean canLeaveWithNegativePower = true; public static boolean canLeaveWithNegativePower = true;
// Configuration for faction-only chat
public static boolean factionOnlyChat = true;
// Configuration on the Faction tag in chat messages. // Configuration on the Faction tag in chat messages.
public static boolean chatTagEnabled = true; public static boolean chatSetFormat = false;
public static transient boolean chatTagHandledByAnotherPlugin = false; public static String chatSetFormatTo = "<{faction_relcolor}§l{faction_roleprefix}§r{faction_relcolor}{faction_tag_pr}"+ChatColor.WHITE.toString()+"%s> %s";
public static boolean chatTagRelationColored = true; public static boolean chatParseTags = true;
public static String chatTagReplaceString = "[FACTION]"; public static boolean chatParseTagsColored = true;
public static String chatTagInsertAfterString = ""; public static Map<String, String> chatSingleFormats = new HashMap<String, String>();
public static String chatTagInsertBeforeString = ""; public static transient boolean chatTagHandledByAnotherPlugin = false; // Why do we need this? (Olof asks)
public static int chatTagInsertIndex = 1; public static String chatTagFormat = "%s"+ChatColor.WHITE; // This one is almost deprecated now right? or is it?
public static boolean chatTagPadBefore = false;
public static boolean chatTagPadAfter = true; // Herochat
public static String chatTagFormat = "%s"+ChatColor.WHITE; public static String herochatFactionChannelName = "Faction";
public static String factionChatFormat = "%s:"+ChatColor.WHITE+" %s"; public static String herochatAllyChannelName = "Allies";
public static String allianceChatFormat = ChatColor.LIGHT_PURPLE+"%s:"+ChatColor.WHITE+" %s";
public static double autoLeaveAfterDaysOfInactivity = 10.0; public static double autoLeaveAfterDaysOfInactivity = 10.0;
public static double autoLeaveRoutineRunsEveryXMinutes = 5.0; public static double autoLeaveRoutineRunsEveryXMinutes = 5.0;
@ -260,6 +257,10 @@ public class Conf
factionPermDefaults.put(perm, perm.defaultDefaultValue); factionPermDefaults.put(perm, perm.defaultDefaultValue);
} }
chatSingleFormats.put("pl", " %s");
chatSingleFormats.put("pr", "%s ");
chatSingleFormats.put("pb", " %s ");
territoryEnemyDenyCommands.add("home"); territoryEnemyDenyCommands.add("home");
territoryEnemyDenyCommands.add("sethome"); territoryEnemyDenyCommands.add("sethome");
territoryEnemyDenyCommands.add("spawn"); territoryEnemyDenyCommands.add("spawn");

View File

@ -16,7 +16,6 @@ import com.massivecraft.factions.integration.Econ;
import com.massivecraft.factions.integration.LWCFeatures; import com.massivecraft.factions.integration.LWCFeatures;
import com.massivecraft.factions.integration.SpoutFeatures; import com.massivecraft.factions.integration.SpoutFeatures;
import com.massivecraft.factions.integration.Worldguard; import com.massivecraft.factions.integration.Worldguard;
import com.massivecraft.factions.struct.ChatMode;
import com.massivecraft.factions.struct.FFlag; import com.massivecraft.factions.struct.FFlag;
import com.massivecraft.factions.struct.FPerm; import com.massivecraft.factions.struct.FPerm;
import com.massivecraft.factions.struct.Rel; import com.massivecraft.factions.struct.Rel;
@ -99,23 +98,6 @@ public class FPlayer extends PlayerEntity implements EconomyParticipator
// FIELD: loginPvpDisabled // FIELD: loginPvpDisabled
private transient boolean loginPvpDisabled; private transient boolean loginPvpDisabled;
// FIELD: chatMode
private ChatMode chatMode;
public void setChatMode(ChatMode chatMode) { this.chatMode = chatMode; }
public ChatMode getChatMode()
{
if(this.factionId.equals("0") || ! Conf.factionOnlyChat)
{
this.chatMode = ChatMode.PUBLIC;
}
return chatMode;
}
// FIELD: chatSpy
private transient boolean spyingChat = false;
public void setSpyingChat(boolean chatSpying) { this.spyingChat = chatSpying; }
public boolean isSpyingChat() { return spyingChat; }
// FIELD: account // FIELD: account
public String getAccountId() { return this.getId(); } public String getAccountId() { return this.getId(); }
@ -153,7 +135,6 @@ public class FPlayer extends PlayerEntity implements EconomyParticipator
} }
this.factionId = "0"; // The default neutral faction this.factionId = "0"; // The default neutral faction
this.chatMode = ChatMode.PUBLIC;
this.role = Rel.MEMBER; this.role = Rel.MEMBER;
this.title = ""; this.title = "";
this.autoClaimFor = null; this.autoClaimFor = null;

View File

@ -24,6 +24,7 @@ import com.massivecraft.factions.cmd.*;
import com.massivecraft.factions.integration.capi.CapiFeatures; import com.massivecraft.factions.integration.capi.CapiFeatures;
import com.massivecraft.factions.integration.Econ; import com.massivecraft.factions.integration.Econ;
import com.massivecraft.factions.integration.EssentialsFeatures; import com.massivecraft.factions.integration.EssentialsFeatures;
import com.massivecraft.factions.integration.HerochatFeatures;
import com.massivecraft.factions.integration.LWCFeatures; import com.massivecraft.factions.integration.LWCFeatures;
import com.massivecraft.factions.integration.SpoutFeatures; import com.massivecraft.factions.integration.SpoutFeatures;
import com.massivecraft.factions.integration.Worldguard; import com.massivecraft.factions.integration.Worldguard;
@ -34,7 +35,6 @@ import com.massivecraft.factions.listeners.FactionsExploitListener;
import com.massivecraft.factions.listeners.FactionsHealthBarListener; import com.massivecraft.factions.listeners.FactionsHealthBarListener;
import com.massivecraft.factions.listeners.FactionsPlayerListener; import com.massivecraft.factions.listeners.FactionsPlayerListener;
import com.massivecraft.factions.listeners.FactionsServerListener; import com.massivecraft.factions.listeners.FactionsServerListener;
import com.massivecraft.factions.struct.ChatMode;
import com.massivecraft.factions.struct.FFlag; import com.massivecraft.factions.struct.FFlag;
import com.massivecraft.factions.struct.FPerm; import com.massivecraft.factions.struct.FPerm;
import com.massivecraft.factions.struct.Rel; import com.massivecraft.factions.struct.Rel;
@ -105,6 +105,7 @@ public class P extends MPlugin
SpoutFeatures.setup(); SpoutFeatures.setup();
Econ.setup(); Econ.setup();
CapiFeatures.setup(); CapiFeatures.setup();
HerochatFeatures.setup();
LWCFeatures.setup(); LWCFeatures.setup();
if(Conf.worldGuardChecking) if(Conf.worldGuardChecking)
@ -241,13 +242,12 @@ public class P extends MPlugin
// Does player have Faction Chat enabled? If so, chat plugins should preferably not do channels, // Does player have Faction Chat enabled? If so, chat plugins should preferably not do channels,
// local chat, or anything else which targets individual recipients, so Faction Chat can be done // local chat, or anything else which targets individual recipients, so Faction Chat can be done
/**
* @deprecated As of release 1.8, there is no built in faction chat.
*/
public boolean isPlayerFactionChatting(Player player) public boolean isPlayerFactionChatting(Player player)
{ {
if (player == null) return false; return false;
FPlayer me = FPlayers.i.get(player);
if (me == null)return false;
return me.getChatMode().isAtLeast(ChatMode.ALLIANCE);
} }
// Is this chat message actually a Factions command, and thus should be left alone by other plugins? // Is this chat message actually a Factions command, and thus should be left alone by other plugins?
@ -276,7 +276,7 @@ public class P extends MPlugin
return tag; return tag;
// if listener isn't set, or config option is disabled, give back uncolored tag // if listener isn't set, or config option is disabled, give back uncolored tag
if (listener == null || !Conf.chatTagRelationColored) { if (listener == null || !Conf.chatParseTagsColored) {
tag = me.getChatTag().trim(); tag = me.getChatTag().trim();
} else { } else {
FPlayer you = FPlayers.i.get(listener); FPlayer you = FPlayers.i.get(listener);

View File

@ -1,77 +0,0 @@
package com.massivecraft.factions.cmd;
import com.massivecraft.factions.Conf;
import com.massivecraft.factions.struct.ChatMode;
import com.massivecraft.factions.struct.Permission;
public class CmdChat extends FCommand
{
public CmdChat()
{
super();
this.aliases.add("c");
this.aliases.add("chat");
//this.requiredArgs.add("");
this.optionalArgs.put("mode", "next");
this.permission = Permission.CHAT.node;
this.disableOnLock = false;
senderMustBePlayer = true;
senderMustBeMember = true;
senderMustBeOfficer = false;
senderMustBeLeader = false;
}
@Override
public void perform()
{
if ( ! Conf.factionOnlyChat )
{
msg("<b>The built in chat chat channels are disabled on this server.");
return;
}
String modeString = this.argAsString(0);
ChatMode modeTarget = fme.getChatMode().getNext();
if (modeString != null)
{
modeString.toLowerCase();
if(modeString.startsWith("p"))
{
modeTarget = ChatMode.PUBLIC;
}
else if (modeString.startsWith("a"))
{
modeTarget = ChatMode.ALLIANCE;
}
else if(modeString.startsWith("f"))
{
modeTarget = ChatMode.FACTION;
}
else
{
msg("<b>Unrecognised chat mode. <i>Please enter either 'a','f' or 'p'");
return;
}
}
fme.setChatMode(modeTarget);
if(fme.getChatMode() == ChatMode.PUBLIC)
{
msg("<i>Public chat mode.");
}
else if (fme.getChatMode() == ChatMode.ALLIANCE )
{
msg("<i>Alliance only chat mode.");
}
else
{
msg("<i>Faction only chat mode.");
}
}
}

View File

@ -1,40 +0,0 @@
package com.massivecraft.factions.cmd;
import com.massivecraft.factions.P;
import com.massivecraft.factions.struct.Permission;
public class CmdChatSpy extends FCommand
{
public CmdChatSpy()
{
super();
this.aliases.add("chatspy");
this.optionalArgs.put("on/off", "flip");
this.permission = Permission.CHATSPY.node;
this.disableOnLock = false;
senderMustBePlayer = true;
senderMustBeMember = false;
senderMustBeOfficer = false;
senderMustBeLeader = false;
}
@Override
public void perform()
{
fme.setSpyingChat(this.argAsBool(0, ! fme.isSpyingChat()));
if ( fme.isSpyingChat())
{
fme.msg("<i>You have enabled chat spying mode.");
P.p.log(fme.getName() + " has ENABLED chat spying mode.");
}
else
{
fme.msg("<i>You have disabled chat spying mode.");
P.p.log(fme.getName() + " DISABLED chat spying mode.");
}
}
}

View File

@ -67,7 +67,6 @@ public class CmdHelp extends FCommand
pageLines.add( p.cmdBase.cmdPower.getUseageTemplate(true) ); pageLines.add( p.cmdBase.cmdPower.getUseageTemplate(true) );
pageLines.add( p.cmdBase.cmdJoin.getUseageTemplate(true) ); pageLines.add( p.cmdBase.cmdJoin.getUseageTemplate(true) );
pageLines.add( p.cmdBase.cmdLeave.getUseageTemplate(true) ); pageLines.add( p.cmdBase.cmdLeave.getUseageTemplate(true) );
pageLines.add( p.cmdBase.cmdChat.getUseageTemplate(true) );
pageLines.add( p.cmdBase.cmdHome.getUseageTemplate(true) ); pageLines.add( p.cmdBase.cmdHome.getUseageTemplate(true) );
pageLines.add( p.txt.parse("<i>Learn how to create a faction on the next page.") ); pageLines.add( p.txt.parse("<i>Learn how to create a faction on the next page.") );
helpPages.add(pageLines); helpPages.add(pageLines);
@ -166,7 +165,6 @@ public class CmdHelp extends FCommand
pageLines = new ArrayList<String>(); pageLines = new ArrayList<String>();
pageLines.add(p.txt.parse("<i>More commands for server admins:")); pageLines.add(p.txt.parse("<i>More commands for server admins:"));
pageLines.add( p.cmdBase.cmdChatSpy.getUseageTemplate(true) );
pageLines.add( p.cmdBase.cmdPowerBoost.getUseageTemplate(true) ); pageLines.add( p.cmdBase.cmdPowerBoost.getUseageTemplate(true) );
pageLines.add( p.cmdBase.cmdLock.getUseageTemplate(true) ); pageLines.add( p.cmdBase.cmdLock.getUseageTemplate(true) );
pageLines.add( p.cmdBase.cmdReload.getUseageTemplate(true) ); pageLines.add( p.cmdBase.cmdReload.getUseageTemplate(true) );

View File

@ -9,8 +9,6 @@ public class FCmdRoot extends FCommand
public CmdLeader cmdLeader = new CmdLeader(); public CmdLeader cmdLeader = new CmdLeader();
public CmdAutoClaim cmdAutoClaim = new CmdAutoClaim(); public CmdAutoClaim cmdAutoClaim = new CmdAutoClaim();
public CmdAdmin cmdBypass = new CmdAdmin(); public CmdAdmin cmdBypass = new CmdAdmin();
public CmdChat cmdChat = new CmdChat();
public CmdChatSpy cmdChatSpy = new CmdChatSpy();
public CmdClaim cmdClaim = new CmdClaim(); public CmdClaim cmdClaim = new CmdClaim();
public CmdConfig cmdConfig = new CmdConfig(); public CmdConfig cmdConfig = new CmdConfig();
public CmdCreate cmdCreate = new CmdCreate(); public CmdCreate cmdCreate = new CmdCreate();
@ -73,8 +71,6 @@ public class FCmdRoot extends FCommand
this.addSubCommand(this.cmdLeader); this.addSubCommand(this.cmdLeader);
this.addSubCommand(this.cmdAutoClaim); this.addSubCommand(this.cmdAutoClaim);
this.addSubCommand(this.cmdBypass); this.addSubCommand(this.cmdBypass);
this.addSubCommand(this.cmdChat);
this.addSubCommand(this.cmdChatSpy);
this.addSubCommand(this.cmdClaim); this.addSubCommand(this.cmdClaim);
this.addSubCommand(this.cmdConfig); this.addSubCommand(this.cmdConfig);
this.addSubCommand(this.cmdCreate); this.addSubCommand(this.cmdCreate);

View File

@ -11,6 +11,7 @@ import org.bukkit.plugin.Plugin;
import com.massivecraft.factions.Conf; import com.massivecraft.factions.Conf;
import com.massivecraft.factions.P; import com.massivecraft.factions.P;
import com.massivecraft.factions.listeners.FactionsChatListener;
import com.earth2me.essentials.IEssentials; import com.earth2me.essentials.IEssentials;
import com.earth2me.essentials.Teleport; import com.earth2me.essentials.Teleport;
@ -105,13 +106,6 @@ public class EssentialsFeatures
{ {
Bukkit.getServer().getPluginManager().registerEvents(new LocalChatListener(), P.p); Bukkit.getServer().getPluginManager().registerEvents(new LocalChatListener(), P.p);
P.p.log("Found and will integrate chat with newer "+essChat.getDescription().getFullName()); P.p.log("Found and will integrate chat with newer "+essChat.getDescription().getFullName());
// curly braces used to be accepted by the format string EssentialsChat but no longer are, so... deal with chatTagReplaceString which might need updating
if (Conf.chatTagReplaceString.contains("{"))
{
Conf.chatTagReplaceString = Conf.chatTagReplaceString.replace("{", "[").replace("}", "]");
P.p.log("NOTE: as of Essentials 2.8+, we've had to switch the default chat replacement tag from \"{FACTION}\" to \"[FACTION]\". This has automatically been updated for you.");
}
} }
catch (NoSuchMethodError ex) catch (NoSuchMethodError ex)
{ {
@ -127,7 +121,9 @@ public class EssentialsFeatures
{ {
Player speaker = event.getPlayer(); Player speaker = event.getPlayer();
String format = event.getFormat(); String format = event.getFormat();
format = format.replace(Conf.chatTagReplaceString, P.p.getPlayerFactionTag(speaker)).replace("[FACTION_TITLE]", P.p.getPlayerTitle(speaker));
format = FactionsChatListener.parseTags(format, speaker);
event.setFormat(format); event.setFormat(format);
// NOTE: above doesn't do relation coloring. if/when we can get a local recipient list from EssentialsLocalChatEvent, we'll probably // NOTE: above doesn't do relation coloring. if/when we can get a local recipient list from EssentialsLocalChatEvent, we'll probably
// want to pass it on to FactionsPlayerListener.onPlayerChat(PlayerChatEvent event) rather than duplicating code // want to pass it on to FactionsPlayerListener.onPlayerChat(PlayerChatEvent event) rather than duplicating code

View File

@ -3,8 +3,8 @@ package com.massivecraft.factions.integration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerChatEvent; import org.bukkit.event.player.PlayerChatEvent;
import com.massivecraft.factions.Conf;
import com.massivecraft.factions.P; import com.massivecraft.factions.P;
import com.massivecraft.factions.listeners.FactionsChatListener;
import com.earth2me.essentials.chat.EssentialsChat; import com.earth2me.essentials.chat.EssentialsChat;
import com.earth2me.essentials.chat.IEssentialsChatListener; import com.earth2me.essentials.chat.IEssentialsChatListener;
@ -31,17 +31,11 @@ public class EssentialsOldVersionFeatures
} }
public String modifyMessage(PlayerChatEvent event, Player target, String message) public String modifyMessage(PlayerChatEvent event, Player target, String message)
{ {
return message.replace(Conf.chatTagReplaceString, P.p.getPlayerFactionTagRelation(event.getPlayer(), target)).replace("[FACTION_TITLE]", P.p.getPlayerTitle(event.getPlayer())); return FactionsChatListener.parseTags(message, event.getPlayer());
//return message.replace(Conf.chatTagReplaceString, P.p.getPlayerFactionTagRelation(event.getPlayer(), target)).replace("[FACTION_TITLE]", P.p.getPlayerTitle(event.getPlayer()));
} }
}); });
P.p.log("Found and will integrate chat with "+essChat.getDescription().getFullName()); P.p.log("Found and will integrate chat with "+essChat.getDescription().getFullName());
// As of Essentials 2.8+, curly braces are not accepted and are instead replaced with square braces, so... deal with it
if (essChat.getDescription().getVersion().startsWith("2.8.") && Conf.chatTagReplaceString.contains("{"))
{
Conf.chatTagReplaceString = Conf.chatTagReplaceString.replace("{", "[").replace("}", "]");
P.p.log("NOTE: as of Essentials 2.8+, we've had to switch the default chat replacement tag from \"{FACTION}\" to \"[FACTION]\". This has automatically been updated for you.");
}
} }
catch (NoSuchMethodError ex) catch (NoSuchMethodError ex)
{ {

View File

@ -0,0 +1,71 @@
package com.massivecraft.factions.integration;
import org.bukkit.Bukkit;
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.plugin.Plugin;
import com.dthielke.herochat.Channel;
import com.dthielke.herochat.ChannelChatEvent;
import com.massivecraft.factions.Conf;
import com.massivecraft.factions.FPlayer;
import com.massivecraft.factions.FPlayers;
import com.massivecraft.factions.Faction;
import com.massivecraft.factions.P;
import com.massivecraft.factions.struct.Rel;
public class HerochatFeatures implements Listener
{
P p;
public HerochatFeatures(P p)
{
this.p = p;
}
public static void setup()
{
Plugin plug = Bukkit.getServer().getPluginManager().getPlugin("Herochat");
if (plug != null && plug.getClass().getName().equals("com.dthielke.herochat.Herochat"))
{
P.p.log("Integration with Herochat successful");
Bukkit.getPluginManager().registerEvents(new HerochatFeatures(P.p), P.p);
}
}
@EventHandler(priority = EventPriority.LOW)
public void onChannelChatEvent(ChannelChatEvent event)
{
Channel ch = event.getChannel();
boolean isFactionChat = ch.getName().equals(Conf.herochatFactionChannelName);
boolean isAllyChat = ch.getName().equals(Conf.herochatAllyChannelName);
if ( ! isFactionChat && ! isAllyChat) return;
// Do common setup
Player sender = event.getSender().getPlayer();
FPlayer fpsender = FPlayers.i.get(sender);
event.getBukkitEvent().getRecipients().clear();
if ( ! fpsender.hasFaction())
{
sender.sendMessage(ChatColor.YELLOW.toString()+"You must join a faction to use the "+ch.getColor().toString()+ch.getName()+ChatColor.YELLOW.toString()+"-channel.");
event.getBukkitEvent().setCancelled(true);
return;
}
Faction faction = fpsender.getFaction();
event.getBukkitEvent().getRecipients().addAll(faction.getOnlinePlayers());
if (isAllyChat)
{
for (FPlayer fplayer : FPlayers.i.getOnline())
{
if(faction.getRelationTo(fplayer) == Rel.ALLY)
{
event.getBukkitEvent().getRecipients().add(fplayer.getPlayer());
}
}
}
}
}

View File

@ -77,13 +77,6 @@ public class PluginCapiListener implements Listener
if (event.getChannel().getId().equals("faction") && myFaction.isNormal()) if (event.getChannel().getId().equals("faction") && myFaction.isNormal())
{ {
event.getThem().addAll(myFaction.getOnlinePlayers()); event.getThem().addAll(myFaction.getOnlinePlayers());
// Send to any players who are spying chat... could probably be implemented better than this
for (FPlayer fplayer : FPlayers.i.getOnline())
{
if(fplayer.isSpyingChat() && fplayer.getFaction() != myFaction)
fplayer.sendMessage("[FCspy] "+myFaction.getTag()+": "+event.getMessage());
}
} }
else if (event.getChannel().getId().equals("allies")) else if (event.getChannel().getId().equals("allies"))
{ {
@ -92,9 +85,6 @@ public class PluginCapiListener implements Listener
FPlayer someFPlayer = FPlayers.i.get(somePlayer); FPlayer someFPlayer = FPlayers.i.get(somePlayer);
if (someFPlayer.getRelationTo(fme).isAtLeast(Rel.ALLY)) if (someFPlayer.getRelationTo(fme).isAtLeast(Rel.ALLY))
event.getThem().add(somePlayer); event.getThem().add(somePlayer);
// Send to any players who are spying chat
else if(someFPlayer.isSpyingChat())
someFPlayer.sendMessage("[ACspy]: " + event.getMessage());
} }
} }
} }

View File

@ -1,25 +1,31 @@
package com.massivecraft.factions.listeners; package com.massivecraft.factions.listeners;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.UnknownFormatConversionException; import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChatEvent; import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.plugin.AuthorNagException;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredListener;
import com.massivecraft.factions.Conf; import com.massivecraft.factions.Conf;
import com.massivecraft.factions.FPlayer; import com.massivecraft.factions.FPlayer;
import com.massivecraft.factions.FPlayers; import com.massivecraft.factions.FPlayers;
import com.massivecraft.factions.Faction;
import com.massivecraft.factions.P; import com.massivecraft.factions.P;
import com.massivecraft.factions.struct.ChatMode;
import com.massivecraft.factions.struct.Rel; import com.massivecraft.factions.struct.Rel;
public class FactionsChatListener implements Listener public class FactionsChatListener implements Listener
{ {
public P p; public P p;
@ -28,158 +34,232 @@ public class FactionsChatListener implements Listener
this.p = p; this.p = p;
} }
// this is for handling slashless command usage and faction/alliance chat, set at lowest priority so Factions gets to them first public static Field fieldRegisteredListenerDotPriority;
@EventHandler(priority = EventPriority.LOWEST) public static final Pattern parsePattern;
public void onPlayerEarlyChat(PlayerChatEvent event) static
{ {
if (event.isCancelled()) return; try
Player talkingPlayer = event.getPlayer();
String msg = event.getMessage();
FPlayer me = FPlayers.i.get(talkingPlayer);
ChatMode chat = me.getChatMode();
// slashless factions commands need to be handled here if the user isn't in public chat mode
if (chat != ChatMode.PUBLIC && p.handleCommand(talkingPlayer, msg))
{ {
if (Conf.logPlayerCommands) fieldRegisteredListenerDotPriority = RegisteredListener.class.getDeclaredField("priority");
Bukkit.getLogger().log(Level.INFO, "[PLAYER_COMMAND] "+talkingPlayer.getName()+": "+msg); fieldRegisteredListenerDotPriority.setAccessible(true);
event.setCancelled(true); }
return; catch (Exception e)
{
P.p.log(Level.SEVERE, "A reflection trick is broken! This will lead to glitchy relation-colored-chat.");
} }
// Is it a faction chat message? parsePattern = Pattern.compile("[{\\[]factions?_([a-zA-Z_]+)[}\\]]");
if (chat == ChatMode.FACTION) }
/**
* We offer an optional and very simple chat formating functionality.
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled=true)
public void lowPlayerChatEvent(PlayerChatEvent event)
{
if (Conf.chatSetFormat)
{ {
Faction myFaction = me.getFaction(); event.setFormat(Conf.chatSetFormatTo);
String message = String.format(Conf.factionChatFormat, me.describeTo(myFaction), msg);
myFaction.sendMessage(message);
Bukkit.getLogger().log(Level.INFO, ChatColor.stripColor("FactionChat "+myFaction.getTag()+": "+message));
//Send to any players who are spying chat
for (FPlayer fplayer : FPlayers.i.getOnline())
{
if(fplayer.isSpyingChat() && fplayer.getFaction() != myFaction)
fplayer.sendMessage("[FCspy] "+myFaction.getTag()+": "+message);
}
event.setCancelled(true);
return;
}
else if (chat == ChatMode.ALLIANCE)
{
Faction myFaction = me.getFaction();
String message = String.format(Conf.allianceChatFormat, ChatColor.stripColor(me.getNameAndTag()), msg);
//Send message to our own faction
myFaction.sendMessage(message);
//Send to all our allies
for (FPlayer fplayer : FPlayers.i.getOnline())
{
if(myFaction.getRelationTo(fplayer) == Rel.ALLY)
fplayer.sendMessage(message);
//Send to any players who are spying chat
else if(fplayer.isSpyingChat())
fplayer.sendMessage("[ACspy]: " + message);
}
Bukkit.getLogger().log(Level.INFO, ChatColor.stripColor("AllianceChat: "+message));
event.setCancelled(true);
return;
} }
} }
// this is for handling insertion of the player's faction tag, set at highest priority to give other plugins a chance to modify chat first // this is for handling insertion of the player's faction tag, set at highest priority to give other plugins a chance to modify chat first
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerChat(PlayerChatEvent event) /**
* At the Highest event priority we apply chat formating.
* Relation colored faction tags may or may not be disabled (Conf.chatParseTagsColored)
* If color is disabled it works flawlessly.
* If however color is enabled we face a limitation in Bukkit.
* Bukkit does not support the same message looking different for each recipient.
* The method we use to get around this is a bit hacky:
* 1. We cancel the chat event on EventPriority.HIGHEST
* 2. We trigger EventPriority.MONITOR manually without relation color.
* 3. We log in console the way it's usually done (as in nms.NetServerHandler line~793).
* 4. We send out the messages to each player with relation color.
* The side effect is that other plugins at EventPriority.HIGHEST may experience the event as cancelled.
*/
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled=true)
public synchronized void onPlayerChat(PlayerChatEvent event)
{ {
if (event.isCancelled()) return; // Should we even parse?
if ( ! Conf.chatParseTags) return;
if (Conf.chatTagHandledByAnotherPlugin) return;
// Are we to insert the Faction tag into the format? Player from = event.getPlayer();
// If we are not to insert it - we are done. FPlayer fpfrom = FPlayers.i.get(from);
if ( ! Conf.chatTagEnabled || Conf.chatTagHandledByAnotherPlugin) return; String format = event.getFormat();
String message = event.getMessage();
Player talkingPlayer = event.getPlayer(); String formatWithoutColor = parseTags(format, from, fpfrom);
String msg = event.getMessage();
String eventFormat = event.getFormat();
FPlayer me = FPlayers.i.get(talkingPlayer);
int InsertIndex = 0;
if (!Conf.chatTagReplaceString.isEmpty() && eventFormat.contains(Conf.chatTagReplaceString)) if ( ! Conf.chatParseTagsColored)
{ {
// we're using the "replace" method of inserting the faction tags // The case without color is really this simple (:
// if they stuck "[FACTION_TITLE]" in there, go ahead and do it too event.setFormat(formatWithoutColor);
if (eventFormat.contains("[FACTION_TITLE]")) return;
{
eventFormat = eventFormat.replace("[FACTION_TITLE]", me.getTitle());
}
InsertIndex = eventFormat.indexOf(Conf.chatTagReplaceString);
eventFormat = eventFormat.replace(Conf.chatTagReplaceString, "");
Conf.chatTagPadAfter = false;
Conf.chatTagPadBefore = false;
}
else if (!Conf.chatTagInsertAfterString.isEmpty() && eventFormat.contains(Conf.chatTagInsertAfterString))
{
// we're using the "insert after string" method
InsertIndex = eventFormat.indexOf(Conf.chatTagInsertAfterString) + Conf.chatTagInsertAfterString.length();
}
else if (!Conf.chatTagInsertBeforeString.isEmpty() && eventFormat.contains(Conf.chatTagInsertBeforeString))
{
// we're using the "insert before string" method
InsertIndex = eventFormat.indexOf(Conf.chatTagInsertBeforeString);
}
else
{
// we'll fall back to using the index place method
InsertIndex = Conf.chatTagInsertIndex;
if (InsertIndex > eventFormat.length())
return;
} }
String formatStart = eventFormat.substring(0, InsertIndex) + ((Conf.chatTagPadBefore && !me.getChatTag().isEmpty()) ? " " : ""); // So you want color eh? You monster :O
String formatEnd = ((Conf.chatTagPadAfter && !me.getChatTag().isEmpty()) ? " " : "") + eventFormat.substring(InsertIndex);
String nonColoredMsgFormat = formatStart + me.getChatTag().trim() + formatEnd; // 1. We cancel the chat event on EventPriority.HIGHEST
event.setCancelled(true);
// Relation Colored? // 2. We trigger EventPriority.MONITOR manually without relation color.
if (Conf.chatTagRelationColored) PlayerChatEvent monitorOnlyEvent = new PlayerChatEvent(from, message);
monitorOnlyEvent.setFormat(formatWithoutColor);
callEventAtMonitorOnly(monitorOnlyEvent);
// 3. We log in console the way it's usually done (as in nms.NetServerHandler line~793).
Bukkit.getConsoleSender().sendMessage(String.format(monitorOnlyEvent.getFormat(), monitorOnlyEvent.getPlayer().getDisplayName(), monitorOnlyEvent.getMessage()));
// 4. We send out the messages to each player with relation color.
for (Player to : event.getRecipients())
{ {
// We must choke the standard message and send out individual messages to all players FPlayer fpto = FPlayers.i.get(to);
// Why? Because the relations will differ. String formatWithColor = parseTags(format, from, fpfrom, to, fpto);
event.setCancelled(true); to.sendMessage(String.format(formatWithColor, from.getDisplayName(), message));
}
}
for (Player listeningPlayer : event.getRecipients()) /**
{ * This is some nasty woodo - I know :/
FPlayer you = FPlayers.i.get(listeningPlayer); * I should make a pull request to Bukkit and CraftBukkit to support this feature natively
String yourFormat = formatStart + me.getChatTag(you).trim() + formatEnd; */
try public static synchronized void callEventAtMonitorOnly(Event event)
{
synchronized(Bukkit.getPluginManager())
{
HandlerList handlers = event.getHandlers();
RegisteredListener[] listeners = handlers.getRegisteredListeners();
for (RegisteredListener registration : listeners)
{
try
{ {
listeningPlayer.sendMessage(String.format(yourFormat, talkingPlayer.getDisplayName(), msg)); EventPriority priority = (EventPriority) fieldRegisteredListenerDotPriority.get(registration);
if (priority != EventPriority.MONITOR) continue;
} }
catch (UnknownFormatConversionException ex) catch (Exception e)
{ {
Conf.chatTagInsertIndex = 0; e.printStackTrace();
P.p.log(Level.SEVERE, "Critical error in chat message formatting!"); continue;
P.p.log(Level.SEVERE, "NOTE: This has been automatically fixed right now by setting chatTagInsertIndex to 0.");
P.p.log(Level.SEVERE, "For a more proper fix, please read this regarding chat configuration: http://massivecraft.com/plugins/factions/config#Chat_configuration");
return;
} }
}
// Write to the log... We will write the non colored message. // This rest is almost copy pasted from SimplePluginManager in Bukkit:
String nonColoredMsg = ChatColor.stripColor(String.format(nonColoredMsgFormat, talkingPlayer.getDisplayName(), msg));
Bukkit.getLogger().log(Level.INFO, nonColoredMsg); if (!registration.getPlugin().isEnabled()) {
} continue;
else }
{
// No relation color. try {
event.setFormat(nonColoredMsgFormat); registration.callEvent(event);
} catch (AuthorNagException ex) {
Plugin plugin = registration.getPlugin();
if (plugin.isNaggable()) {
plugin.setNaggable(false);
String author = "<NoAuthorGiven>";
if (plugin.getDescription().getAuthors().size() > 0) {
author = plugin.getDescription().getAuthors().get(0);
}
Bukkit.getServer().getLogger().log(Level.SEVERE, String.format(
"Nag author: '%s' of '%s' about the following: %s",
author,
plugin.getDescription().getName(),
ex.getMessage()
));
}
} catch (Throwable ex) {
Bukkit.getServer().getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getName(), ex);
}
}
} }
} }
public static String parseTags(String str, Player from)
{
FPlayer fpfrom = FPlayers.i.get(from);
return parseTags(str, from, fpfrom, null, null);
}
public static String parseTags(String str, Player from, FPlayer fpfrom)
{
return parseTags(str, from, fpfrom, null, null);
}
public static String parseTags(String str, Player from, Player to)
{
FPlayer fpfrom = FPlayers.i.get(from);
FPlayer fpto = FPlayers.i.get(to);
return parseTags(str, from, fpfrom, to, fpto);
}
public static String parseTags(String str, Player from, FPlayer fpfrom, Player to, FPlayer fpto)
{
StringBuffer ret = new StringBuffer();
Matcher matcher = parsePattern.matcher(str);
while (matcher.find())
{
String[] parts = matcher.group(1).toLowerCase().split("_");
List<String> args = new ArrayList<String>(Arrays.asList(parts));
String tag = args.remove(0);
matcher.appendReplacement(ret, produceTag(tag, args, from, fpfrom, to, fpto));
}
matcher.appendTail(ret);
return ret.toString();
}
public static String produceTag(String tag, List<String> args, Player from, FPlayer fpfrom, Player to, FPlayer fpto)
{
String ret = "";
if (tag.equals("relcolor"))
{
if (fpto == null)
{
ret = Rel.NEUTRAL.getColor().toString();
}
else
{
ret = fpfrom.getRelationTo(fpto).getColor().toString();
}
}
else if (tag.startsWith("roleprefix"))
{
ret = fpfrom.getRole().getPrefix();
}
else if (tag.equals("title"))
{
ret = fpfrom.getTitle();
}
else if (tag.equals("tag"))
{
if (fpfrom.hasFaction())
{
ret = fpfrom.getFaction().getTag();
}
}
else if (tag.startsWith("tagforce"))
{
ret = fpfrom.getFaction().getTag();
}
if (ret == null) ret = "";
return applyFormatsByName(ret, args);
}
public static String applyFormatsByName(String str, List<String> formatNames)
{
if (str.length() == 0) return str;
for (String formatName : formatNames)
{
String format = Conf.chatSingleFormats.get(formatName);
try
{
str = String.format(format, str);
}
catch (Exception e) { }
}
return str;
}
} }

View File

@ -39,7 +39,7 @@ public abstract class SpiralTask implements Runnable
private transient int length = -1; private transient int length = -1;
private transient int current = 0; private transient int current = 0;
@SuppressWarnings("LeakingThisInConstructor") // @SuppressWarnings("LeakingThisInConstructor") This actually triggers a warning in Eclipse xD Could we find another way to suppress the error please? :)
public SpiralTask(FLocation fLocation, int radius) public SpiralTask(FLocation fLocation, int radius)
{ {
// limit is determined based on spiral leg length for given radius; see insideRadius() // limit is determined based on spiral leg length for given radius; see insideRadius()