diff --git a/src/main/java/com/massivecraft/factions/Const.java b/src/main/java/com/massivecraft/factions/Const.java index 2f424d19..c21413bf 100644 --- a/src/main/java/com/massivecraft/factions/Const.java +++ b/src/main/java/com/massivecraft/factions/Const.java @@ -22,4 +22,26 @@ public class Const public static final char[] MAP_KEY_CHARS = "\\/#?$%=&^ABCDEFGHJKLMNOPQRSTUVWXYZ1234567890abcdeghjmnopqrsuvwxyz".toCharArray(); + // SHOW + + public static final String SHOW_ID_FACTION_ID = BASENAME_ + "id"; + public static final String SHOW_ID_FACTION_DESCRIPTION = BASENAME_ + "description"; + public static final String SHOW_ID_FACTION_AGE = BASENAME_ + "age"; + public static final String SHOW_ID_FACTION_FLAGS = BASENAME_ + "flags"; + public static final String SHOW_ID_FACTION_POWER = BASENAME_ + "power"; + public static final String SHOW_ID_FACTION_LANDVALUES = BASENAME_ + "landvalue"; + public static final String SHOW_ID_FACTION_BANK = BASENAME_ + "bank"; + public static final String SHOW_ID_FACTION_RELATIONS = BASENAME_ + "relations"; + public static final String SHOW_ID_FACTION_FOLLOWERS = BASENAME_ + "followers"; + + public static final int SHOW_PRIORITY_FACTION_ID = 1000; + public static final int SHOW_PRIORITY_FACTION_DESCRIPTION = 2000; + public static final int SHOW_PRIORITY_FACTION_AGE = 3000; + public static final int SHOW_PRIORITY_FACTION_FLAGS = 4000; + public static final int SHOW_PRIORITY_FACTION_POWER = 5000; + public static final int SHOW_PRIORITY_FACTION_LANDVALUES = 6000; + public static final int SHOW_PRIORITY_FACTION_BANK = 7000; + public static final int SHOW_PRIORITY_FACTION_RELATIONS = 8000; + public static final int SHOW_PRIORITY_FACTION_FOLLOWERS = 9000; + } diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdFactionsFaction.java b/src/main/java/com/massivecraft/factions/cmd/CmdFactionsFaction.java index 0cac08c7..81cac203 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdFactionsFaction.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdFactionsFaction.java @@ -1,26 +1,13 @@ package com.massivecraft.factions.cmd; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.TreeSet; import com.massivecraft.factions.cmd.arg.ARFaction; -import com.massivecraft.factions.entity.MConf; -import com.massivecraft.factions.entity.MFlag; -import com.massivecraft.factions.entity.MPlayer; import com.massivecraft.factions.entity.Faction; -import com.massivecraft.factions.event.EventFactionsChunkChangeType; -import com.massivecraft.factions.integration.Econ; +import com.massivecraft.factions.event.EventFactionsFactionShow; import com.massivecraft.factions.Perm; -import com.massivecraft.factions.PlayerRoleComparator; -import com.massivecraft.factions.Rel; +import com.massivecraft.massivecore.PriorityLines; import com.massivecraft.massivecore.cmd.req.ReqHasPerm; -import com.massivecraft.massivecore.mixin.Mixin; -import com.massivecraft.massivecore.money.Money; -import com.massivecraft.massivecore.util.TimeDiffUtil; -import com.massivecraft.massivecore.util.TimeUnit; import com.massivecraft.massivecore.util.Txt; public class CmdFactionsFaction extends FactionsCommand @@ -52,127 +39,19 @@ public class CmdFactionsFaction extends FactionsCommand Faction faction = this.arg(0, ARFaction.get(), msenderFaction); if (faction == null) return; - // Data precalculation - //boolean none = faction.isNone(); - boolean normal = faction.isNormal(); + // Event + EventFactionsFactionShow event = new EventFactionsFactionShow(sender, faction); + event.run(); + if (event.isCancelled()) return; - // INFO: Title + // Title msg(Txt.titleize("Faction " + faction.getName(msender))); - // INFO: Id (admin mode output only) - if (msender.isUsingAdminMode()) + // Lines + TreeSet priorityLiness = new TreeSet(event.getIdPriorityLiness().values()); + for (PriorityLines priorityLines : priorityLiness) { - msg("ID: %s", faction.getId()); - } - - // INFO: Description - msg("Description: %s", faction.getDescription()); - - if (normal) - { - // INFO: Age - long ageMillis = faction.getCreatedAtMillis() - System.currentTimeMillis(); - LinkedHashMap ageUnitcounts = TimeDiffUtil.limit(TimeDiffUtil.unitcounts(ageMillis, TimeUnit.getAllButMillis()), 3); - String ageString = TimeDiffUtil.formatedVerboose(ageUnitcounts, ""); - msg("Age: %s", ageString); - - // INFO: Open - // TODO: Why hardcode displaying the open flag only? We should rather display everything publicly editable. - msg("Open: "+(faction.getFlag(MFlag.getFlagOpen()) ? "Yes, anyone can join" : "No, only invited people can join")); - - // INFO: Power - double powerBoost = faction.getPowerBoost(); - String boost = (powerBoost == 0.0) ? "" : (powerBoost > 0.0 ? " (bonus: " : " (penalty: ") + powerBoost + ")"; - msg("Land / Power / Maxpower: %d/%d/%d %s", faction.getLandCount(), faction.getPowerRounded(), faction.getPowerMaxRounded(), boost); - - // show the land value - if (Econ.isEnabled()) - { - long landCount = faction.getLandCount(); - - for (EventFactionsChunkChangeType type : EventFactionsChunkChangeType.values()) - { - Double money = MConf.get().econChunkCost.get(type); - if (money == null) continue; - if (money == 0D) continue; - money *= landCount; - - String word = null; - if (money > 0) - { - word = "cost"; - } - else - { - word = "reward"; - money *= -1; - } - - msg("Total land %s %s: %s", type.toString().toLowerCase(), word, Money.format(money)); - } - - // Show bank contents - if (MConf.get().bankEnabled) - { - msg("Bank contains: "+Money.format(Money.get(faction))); - } - } - - // Display important flags - // TODO: Find the non default flags, and display them instead. - if (faction.getFlag(MFlag.getFlagPermanent())) - { - msg("This faction is permanent - remaining even with no followers."); - } - - if (faction.getFlag(MFlag.getFlagPeaceful())) - { - msg("This faction is peaceful - in truce with everyone."); - } - } - - String sepparator = Txt.parse("")+", "; - - // List the relations to other factions - Map> relationNames = faction.getFactionNamesPerRelation(msender, true); - - if (faction.getFlag(MFlag.getFlagPeaceful())) - { - sendMessage(Txt.parse("In Truce with: *everyone*")); - } - else - { - sendMessage(Txt.parse("In Truce with: ") + Txt.implode(relationNames.get(Rel.TRUCE), sepparator)); - } - - sendMessage(Txt.parse("Allies: ") + Txt.implode(relationNames.get(Rel.ALLY), sepparator)); - sendMessage(Txt.parse("Enemies: ") + Txt.implode(relationNames.get(Rel.ENEMY), sepparator)); - - // List the followers... - List followerNamesOnline = new ArrayList(); - List followerNamesOffline = new ArrayList(); - - List followers = faction.getMPlayers(); - Collections.sort(followers, PlayerRoleComparator.get()); - - for (MPlayer follower : followers) - { - if (follower.isOnline() && Mixin.canSee(sender, follower.getId())) - { - followerNamesOnline.add(follower.getNameAndTitle(msender)); - } - else if (normal) - { - // For the non-faction we skip the offline members since they are far to many (infinate almost) - followerNamesOffline.add(follower.getNameAndTitle(msender)); - } - } - - sendMessage(Txt.parse("Followers online (%s): ", followerNamesOnline.size()) + Txt.implode(followerNamesOnline, sepparator)); - - if (normal) - { - sendMessage(Txt.parse("Followers offline (%s): ", followerNamesOffline.size()) + Txt.implode(followerNamesOffline, sepparator)); + sendMessage(priorityLines.getLines()); } } diff --git a/src/main/java/com/massivecraft/factions/engine/EngineMain.java b/src/main/java/com/massivecraft/factions/engine/EngineMain.java index 256b8865..8bb61351 100644 --- a/src/main/java/com/massivecraft/factions/engine/EngineMain.java +++ b/src/main/java/com/massivecraft/factions/engine/EngineMain.java @@ -1,12 +1,17 @@ package com.massivecraft.factions.engine; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.EnumSet; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import org.bukkit.Bukkit; @@ -62,6 +67,7 @@ import org.bukkit.projectiles.ProjectileSource; import com.massivecraft.factions.Const; import com.massivecraft.factions.Factions; +import com.massivecraft.factions.PlayerRoleComparator; import com.massivecraft.factions.Rel; import com.massivecraft.factions.TerritoryAccess; import com.massivecraft.factions.entity.BoardColl; @@ -72,17 +78,24 @@ import com.massivecraft.factions.entity.MPlayer; import com.massivecraft.factions.entity.Faction; import com.massivecraft.factions.entity.MConf; import com.massivecraft.factions.entity.MPlayerColl; +import com.massivecraft.factions.event.EventFactionsChunkChangeType; import com.massivecraft.factions.event.EventFactionsChunksChange; +import com.massivecraft.factions.event.EventFactionsFactionShow; import com.massivecraft.factions.event.EventFactionsPvpDisallowed; import com.massivecraft.factions.event.EventFactionsPowerChange; import com.massivecraft.factions.event.EventFactionsPowerChange.PowerChangeReason; +import com.massivecraft.factions.integration.Econ; import com.massivecraft.factions.util.VisualizeUtil; import com.massivecraft.massivecore.EngineAbstract; +import com.massivecraft.massivecore.PriorityLines; import com.massivecraft.massivecore.event.EventMassiveCorePlayerLeave; import com.massivecraft.massivecore.mixin.Mixin; +import com.massivecraft.massivecore.money.Money; import com.massivecraft.massivecore.ps.PS; import com.massivecraft.massivecore.util.MUtil; import com.massivecraft.massivecore.util.PlayerUtil; +import com.massivecraft.massivecore.util.TimeDiffUtil; +import com.massivecraft.massivecore.util.TimeUnit; import com.massivecraft.massivecore.util.Txt; public class EngineMain extends EngineAbstract @@ -105,6 +118,227 @@ public class EngineMain extends EngineAbstract return Factions.get(); } + // -------------------------------------------- // + // FACTION SHOW + // -------------------------------------------- // + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onFactionShow(EventFactionsFactionShow event) + { + final int tableCols = 4; + final CommandSender sender = event.getSender(); + final MPlayer msender = event.getMSender(); + final Faction faction = event.getFaction(); + final boolean normal = faction.isNormal(); + final Map idPriorityLiness = event.getIdPriorityLiness(); + final boolean peaceful = faction.getFlag(MFlag.getFlagPeaceful()); + + // ID + if (msender.isUsingAdminMode()) + { + show(idPriorityLiness, Const.SHOW_ID_FACTION_ID, Const.SHOW_PRIORITY_FACTION_ID, "ID", faction.getId()); + } + + // DESCRIPTION + show(idPriorityLiness, Const.SHOW_ID_FACTION_DESCRIPTION, Const.SHOW_PRIORITY_FACTION_DESCRIPTION, "Description", faction.getDescription()); + + // SECTION: NORMAL + if (normal) + { + // AGE + long ageMillis = faction.getCreatedAtMillis() - System.currentTimeMillis(); + LinkedHashMap ageUnitcounts = TimeDiffUtil.limit(TimeDiffUtil.unitcounts(ageMillis, TimeUnit.getAllButMillis()), 3); + String ageDesc = TimeDiffUtil.formatedVerboose(ageUnitcounts, ""); + show(idPriorityLiness, Const.SHOW_ID_FACTION_AGE, Const.SHOW_PRIORITY_FACTION_AGE, "Age", ageDesc); + + // FLAGS + // We display all editable and non default ones. The rest we skip. + List flagDescs = new LinkedList(); + for (Entry entry : faction.getFlags().entrySet()) + { + final MFlag mflag = entry.getKey(); + if (mflag == null) continue; + + final Boolean value = entry.getValue(); + if (value == null) continue; + + if ( ! mflag.isInteresting(value)) continue; + + String flagDesc = Txt.parse(value ? "" : "") + mflag.getName(); + flagDescs.add(flagDesc); + } + String flagsDesc = Txt.parse("default"); + if ( ! flagDescs.isEmpty()) + { + flagsDesc = Txt.implode(flagDescs, Txt.parse(" | ")); + } + show(idPriorityLiness, Const.SHOW_ID_FACTION_FLAGS, Const.SHOW_PRIORITY_FACTION_FLAGS, "Flags", flagsDesc); + + // POWER + double powerBoost = faction.getPowerBoost(); + String boost = (powerBoost == 0.0) ? "" : (powerBoost > 0.0 ? " (bonus: " : " (penalty: ") + powerBoost + ")"; + String powerDesc = Txt.parse("%d/%d/%d%s", faction.getLandCount(), faction.getPowerRounded(), faction.getPowerMaxRounded(), boost); + show(idPriorityLiness, Const.SHOW_ID_FACTION_POWER, Const.SHOW_PRIORITY_FACTION_POWER, "Land / Power / Maxpower", powerDesc); + + // SECTION: ECON + if (Econ.isEnabled()) + { + // LANDVALUES + List landvalueLines = new LinkedList(); + long landCount = faction.getLandCount(); + for (EventFactionsChunkChangeType type : EventFactionsChunkChangeType.values()) + { + Double money = MConf.get().econChunkCost.get(type); + if (money == null) continue; + if (money == 0) continue; + System.out.println("money: "+money); + money *= landCount; + + String word = "Cost"; + if (money <= 0) + { + word = "Reward"; + money *= -1; + } + + String key = Txt.parse("Total Land %s %s", type.toString().toLowerCase(), word); + String value = Money.format(money); + String line = show(key, value); + landvalueLines.add(line); + } + idPriorityLiness.put(Const.SHOW_ID_FACTION_LANDVALUES, new PriorityLines(Const.SHOW_PRIORITY_FACTION_LANDVALUES, landvalueLines)); + + // BANK + if (MConf.get().bankEnabled) + { + String bankDesc = Money.format(Money.get(faction)); + show(idPriorityLiness, Const.SHOW_ID_FACTION_BANK, Const.SHOW_PRIORITY_FACTION_BANK, "Bank", bankDesc); + } + } + } + + // RELATIONS + List relationLines = new ArrayList(); + String none = Txt.parse("none"); + String everyone = MConf.get().colorTruce.toString() + Txt.parse("*EVERYONE*"); + Set rels = EnumSet.of(Rel.TRUCE, Rel.ALLY, Rel.ENEMY); + Map> relNames = faction.getRelationNames(msender, rels, true); + for (Entry> entry : relNames.entrySet()) + { + Rel rel = entry.getKey(); + List names = entry.getValue(); + String header = Txt.parse("Relation %s%s (%d):", rel.getColor().toString(), Txt.getNicedEnum(rel), names.size()); + relationLines.add(header); + if (rel == Rel.TRUCE && peaceful) + { + relationLines.add(everyone); + } + else + { + if (names.isEmpty()) + { + relationLines.add(none); + } + else + { + relationLines.addAll(table(names, tableCols)); + } + } + } + idPriorityLiness.put(Const.SHOW_ID_FACTION_RELATIONS, new PriorityLines(Const.SHOW_PRIORITY_FACTION_RELATIONS, relationLines)); + + // FOLLOWERS + List followerLines = new ArrayList(); + + List followerNamesOnline = new ArrayList(); + List followerNamesOffline = new ArrayList(); + + List followers = faction.getMPlayers(); + Collections.sort(followers, PlayerRoleComparator.get()); + for (MPlayer follower : followers) + { + if (follower.isOnline() && Mixin.canSee(sender, follower.getId())) + { + followerNamesOnline.add(follower.getNameAndTitle(msender)); + } + else if (normal) + { + // For the non-faction we skip the offline members since they are far to many (infinite almost) + followerNamesOffline.add(follower.getNameAndTitle(msender)); + } + } + + String headerOnline = Txt.parse("Followers Online (%s):", followerNamesOnline.size()); + followerLines.add(headerOnline); + if (followerNamesOnline.isEmpty()) + { + followerLines.add(none); + } + else + { + followerLines.addAll(table(followerNamesOnline, tableCols)); + } + + if (normal) + { + String headerOffline = Txt.parse("Followers Offline (%s):", followerNamesOffline.size()); + followerLines.add(headerOffline); + if (followerNamesOffline.isEmpty()) + { + followerLines.add(none); + } + else + { + followerLines.addAll(table(followerNamesOffline, tableCols)); + } + } + idPriorityLiness.put(Const.SHOW_ID_FACTION_FOLLOWERS, new PriorityLines(Const.SHOW_PRIORITY_FACTION_FOLLOWERS, followerLines)); + } + + public static String show(String key, String value) + { + return Txt.parse("%s: %s", key, value); + } + + public static PriorityLines show(int priority, String key, String value) + { + return new PriorityLines(priority, show(key, value)); + } + + public static void show(Map idPriorityLiness, String id, int priority, String key, String value) + { + idPriorityLiness.put(id, show(priority, key, value)); + } + + public static List table(List strings, int cols) + { + List ret = new ArrayList(); + + StringBuilder row = new StringBuilder(); + int count = 0; + + Iterator iter = strings.iterator(); + while (iter.hasNext()) + { + String string = iter.next(); + row.append(string); + count++; + + if (iter.hasNext() && count != cols) + { + row.append(Txt.parse(" | ")); + } + else + { + ret.add(row.toString()); + row = new StringBuilder(); + count = 0; + } + } + + return ret; + } + // -------------------------------------------- // // UPDATE LAST ACTIVITY // -------------------------------------------- // diff --git a/src/main/java/com/massivecraft/factions/entity/Faction.java b/src/main/java/com/massivecraft/factions/entity/Faction.java index 1baa9873..8f9a4598 100644 --- a/src/main/java/com/massivecraft/factions/entity/Faction.java +++ b/src/main/java/com/massivecraft/factions/entity/Faction.java @@ -562,27 +562,29 @@ public class Faction extends Entity implements EconomyParticipator this.setRelationWish(faction.getId(), rel); } - // TODO: What is this and where is it used? - - public Map> getFactionNamesPerRelation(RelationParticipator rp) + public Map> getRelationNames(RelationParticipator rp, Set rels, boolean skipPeaceful) { - return getFactionNamesPerRelation(rp, false); - } - - // onlyNonNeutral option provides substantial performance boost on large servers for listing only non-neutral factions - public Map> getFactionNamesPerRelation(RelationParticipator rp, boolean onlyNonNeutral) - { - Map> ret = new HashMap>(); - for (Rel rel : Rel.values()) + // Create Ret + Map> ret = new LinkedHashMap>(); + for (Rel rel : rels) { ret.put(rel, new ArrayList()); } + for (Faction faction : FactionColl.get().getAll()) { - Rel relation = faction.getRelationTo(this); - if (onlyNonNeutral && relation == Rel.NEUTRAL) continue; - ret.get(relation).add(faction.getName(rp)); + if (skipPeaceful && faction.getFlag(MFlag.getFlagPeaceful())) continue; + + Rel rel = faction.getRelationTo(this); + + List names = ret.get(rel); + if (names == null) continue; + + String name = faction.getName(rp); + names.add(name); } + + // Return Ret return ret; } diff --git a/src/main/java/com/massivecraft/factions/entity/MFlag.java b/src/main/java/com/massivecraft/factions/entity/MFlag.java index 1ae90400..d2d6f2cb 100644 --- a/src/main/java/com/massivecraft/factions/entity/MFlag.java +++ b/src/main/java/com/massivecraft/factions/entity/MFlag.java @@ -188,6 +188,13 @@ public class MFlag extends Entity implements Prioritized, Registerable // EXTRAS // -------------------------------------------- // + public boolean isInteresting(boolean value) + { + if ( ! this.isVisible()) return false; + if (this.isEditable()) return true; + return this.isStandard() != value; + } + public String getStateInfo(boolean value, boolean withDesc) { String valueDesc = value ? "YES" : "NOO"; diff --git a/src/main/java/com/massivecraft/factions/event/EventFactionsFactionShow.java b/src/main/java/com/massivecraft/factions/event/EventFactionsFactionShow.java new file mode 100644 index 00000000..dd275a1a --- /dev/null +++ b/src/main/java/com/massivecraft/factions/event/EventFactionsFactionShow.java @@ -0,0 +1,43 @@ +package com.massivecraft.factions.event; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.command.CommandSender; +import org.bukkit.event.HandlerList; + +import com.massivecraft.factions.entity.Faction; +import com.massivecraft.massivecore.PriorityLines; + +public class EventFactionsFactionShow extends EventFactionsAbstractSender +{ + // -------------------------------------------- // + // REQUIRED EVENT CODE + // -------------------------------------------- // + + private static final HandlerList handlers = new HandlerList(); + @Override public HandlerList getHandlers() { return handlers; } + public static HandlerList getHandlerList() { return handlers; } + + // -------------------------------------------- // + // FIELDS + // -------------------------------------------- // + + private final Faction faction; + public Faction getFaction() { return this.faction; } + + private final Map idPriorityLiness; + public Map getIdPriorityLiness() { return this.idPriorityLiness; } + + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public EventFactionsFactionShow(CommandSender sender, Faction faction) + { + super(sender); + this.faction = faction; + this.idPriorityLiness = new HashMap(); + } + +} diff --git a/src/main/java/com/massivecraft/factions/integration/dynmap/EngineDynmap.java b/src/main/java/com/massivecraft/factions/integration/dynmap/EngineDynmap.java index 1e25fc89..5baf23ef 100644 --- a/src/main/java/com/massivecraft/factions/integration/dynmap/EngineDynmap.java +++ b/src/main/java/com/massivecraft/factions/integration/dynmap/EngineDynmap.java @@ -783,7 +783,7 @@ public class EngineDynmap extends EngineAbstract ret = ret.replace("%" + flag + ".color%", color); // monsters (red or green) ret = ret.replace("%" + flag + ".boolcolor%", boolcolor); // true (red or green) - if (!mflag.isVisible()) continue; + if ( ! mflag.isInteresting(value)) continue; flagMapParts.add(flag + ": " + boolcolor); flagTableParts.add(color); }