From efee66071b354ed56936aef628277aaa0ef402e0 Mon Sep 17 00:00:00 2001 From: Naman Date: Sun, 8 Apr 2018 22:13:41 -0500 Subject: [PATCH] 1.0.23 configurable enemy check radius for fly, option added in conf.json Added a system faction check to neutral Added a enderpearl disable while flying option to conf.json Added my own repository to maven along with coreprotect for shading. --Factions Inspect Added-- --- pom.xml | 10 +++ .../java/com/massivecraft/factions/Conf.java | 3 + .../com/massivecraft/factions/FPlayer.java | 6 ++ .../java/com/massivecraft/factions/P.java | 27 ++++++++ .../com/massivecraft/factions/cmd/CmdFly.java | 69 ++++++++++--------- .../massivecraft/factions/cmd/CmdInspect.java | 40 +++++++++++ .../massivecraft/factions/cmd/CmdVersion.java | 1 + .../massivecraft/factions/cmd/FCmdRoot.java | 12 +++- .../listeners/FactionsEntityListener.java | 17 +++++ .../listeners/FactionsPlayerListener.java | 55 ++++++++++++++- .../factions/struct/Permission.java | 1 + .../util/ClipPlaceholderAPIManager.java | 3 + .../factions/zcore/persist/MemoryFPlayer.java | 17 ++++- .../massivecraft/factions/zcore/util/TL.java | 13 +++- src/main/resources/plugin.yml | 2 +- 15 files changed, 236 insertions(+), 40 deletions(-) create mode 100644 src/main/java/com/massivecraft/factions/cmd/CmdInspect.java diff --git a/pom.xml b/pom.xml index c75402f3..6b923840 100644 --- a/pom.xml +++ b/pom.xml @@ -318,6 +318,12 @@ + + net.coreprotect + CoreProtect + 2 + provided + @@ -349,5 +355,9 @@ mvdw-software http://repo.mvdw-software.be/content/groups/public/ + + ProSavage + https://www.myget.org/F/prosavage/maven/ + \ No newline at end of file diff --git a/src/main/java/com/massivecraft/factions/Conf.java b/src/main/java/com/massivecraft/factions/Conf.java index e5d72f96..65689c4d 100644 --- a/src/main/java/com/massivecraft/factions/Conf.java +++ b/src/main/java/com/massivecraft/factions/Conf.java @@ -79,6 +79,9 @@ public class Conf { public static String truceChatFormat = ChatColor.DARK_PURPLE + "%s:" + ChatColor.WHITE + " %s"; public static String modChatFormat = ChatColor.RED + "%s:" + ChatColor.WHITE + " %s"; + public static int enemyFlyCheckRadius = 16; + public static boolean noEnderpearlsInFly = false; + public static boolean broadcastDescriptionChanges = false; public static boolean broadcastTagChanges = false; diff --git a/src/main/java/com/massivecraft/factions/FPlayer.java b/src/main/java/com/massivecraft/factions/FPlayer.java index 0ef0d232..6b247eb0 100644 --- a/src/main/java/com/massivecraft/factions/FPlayer.java +++ b/src/main/java/com/massivecraft/factions/FPlayer.java @@ -159,6 +159,12 @@ public interface FPlayer extends EconomyParticipator { public boolean hasMoney(int amt); + //inspect Stuff + + public boolean isInspectMode(); + + public void setInspectMode(boolean status); + // Fly Checks diff --git a/src/main/java/com/massivecraft/factions/P.java b/src/main/java/com/massivecraft/factions/P.java index fa10d7b9..26901f40 100644 --- a/src/main/java/com/massivecraft/factions/P.java +++ b/src/main/java/com/massivecraft/factions/P.java @@ -21,6 +21,8 @@ import com.massivecraft.factions.zcore.fupgrades.EXPUpgrade; import com.massivecraft.factions.zcore.fupgrades.FUpgradesGUI; import com.massivecraft.factions.zcore.fupgrades.SpawnerUpgrades; import com.massivecraft.factions.zcore.util.TextUtil; +import net.coreprotect.CoreProtect; +import net.coreprotect.CoreProtectAPI; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; import org.bukkit.*; @@ -48,6 +50,8 @@ public class P extends MPlugin { public static P p; public static Permission perms = null; + + // Persistence related private boolean locked = false; @@ -123,6 +127,11 @@ public class P extends MPlugin { Board.getInstance().load(); Board.getInstance().clean(); + //inspect stuff + if (!initCoreProtect()){ + P.p.log("Inspect will be disabled, you need coreprotect installed for it to function!"); + } + // Add Base Commands this.cmdBase = new FCmdRoot(); this.cmdAutoHelp = new CmdAutoHelp(); @@ -162,6 +171,10 @@ public class P extends MPlugin { // since some other plugins execute commands directly through this command interface, provide it this.getCommand(this.refCommand).setExecutor(this); + + + + setupPlaceholderAPI(); postEnable(); this.loadSuccessful = true; @@ -335,6 +348,20 @@ public class P extends MPlugin { return event != null && (isPlayerFactionChatting(event.getPlayer()) || isFactionsCommand(event.getMessage())); } + + //Inspect stuff + private boolean initCoreProtect() + { + if (!getServer().getPluginManager().isPluginEnabled("CoreProtect")) { + return false; + } + CoreProtectAPI coreProtectAPI = CoreProtect.getInstance().getAPI(); + return true; + } + + + + // 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 public boolean isPlayerFactionChatting(Player player) { diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdFly.java b/src/main/java/com/massivecraft/factions/cmd/CmdFly.java index 29c0b9e6..16fa05e3 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdFly.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdFly.java @@ -14,6 +14,7 @@ import org.bukkit.GameMode; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.List; @@ -60,48 +61,48 @@ public class CmdFly extends FCommand { public static void startFlyCheck() { flyid = Bukkit.getScheduler().scheduleSyncRepeatingTask(P.p, new Runnable() { @Override - public void run() { + public void run() throws ConcurrentModificationException { //threw the exception for now, until I recode fly :( Cringe. checkTaskState(); if (flyMap.keySet().size() != 0) { - for (String name : flyMap.keySet()) { - if (name == null) { - continue; - } - Player player = Bukkit.getPlayer(name); - if (player == null) { - continue; - } - if (!player.isFlying()) { - continue; - } - FPlayer fPlayer = FPlayers.getInstance().getByPlayer(player); + for (String name : flyMap.keySet()) { + if (name == null) { + continue; + } + Player player = Bukkit.getPlayer(name); + if (player == null) { + continue; + } + if (!player.isFlying()) { + continue; + } + FPlayer fPlayer = FPlayers.getInstance().getByPlayer(player); - if (fPlayer == null) { - continue; - } - if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { - continue; - } - Faction myFaction = fPlayer.getFaction(); - if (myFaction.isWilderness()) { - fPlayer.setFlying(false); - flyMap.remove(name); - continue; - } - if (fPlayer.checkIfNearbyEnemies()) { - continue; - } - FLocation myFloc = new FLocation(player.getLocation()); - Faction toFac = Board.getInstance().getFactionAt(myFloc); - if (Board.getInstance().getFactionAt(myFloc) != myFaction) { - if (!checkBypassPerms(fPlayer, player, toFac)) { + if (fPlayer == null) { + continue; + } + if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { + continue; + } + Faction myFaction = fPlayer.getFaction(); + if (myFaction.isWilderness()) { fPlayer.setFlying(false); flyMap.remove(name); continue; } - } + if (fPlayer.checkIfNearbyEnemies()) { + continue; + } + FLocation myFloc = new FLocation(player.getLocation()); + Faction toFac = Board.getInstance().getFactionAt(myFloc); + if (Board.getInstance().getFactionAt(myFloc) != myFaction) { + if (!checkBypassPerms(fPlayer, player, toFac)) { + fPlayer.setFlying(false); + flyMap.remove(name); + continue; + } + } - } + } } } diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdInspect.java b/src/main/java/com/massivecraft/factions/cmd/CmdInspect.java new file mode 100644 index 00000000..8ca32b6c --- /dev/null +++ b/src/main/java/com/massivecraft/factions/cmd/CmdInspect.java @@ -0,0 +1,40 @@ +package com.massivecraft.factions.cmd; + +import com.massivecraft.factions.struct.Permission; +import com.massivecraft.factions.zcore.util.TL; + +public class CmdInspect extends FCommand +{ + public CmdInspect(){ + super(); + this.aliases.add("inspect"); + this.aliases.add("ins"); + + this.permission = Permission.INSPECT.node; + this.disableOnLock = true; + + senderMustBePlayer = true; + senderMustBeMember = true; + senderMustBeModerator = false; + senderMustBeColeader = false; + senderMustBeAdmin = false; + } + + + @Override + public void perform(){ + if (fme.isInspectMode()){ + fme.setInspectMode(false); + msg(TL.COMMAND_INSPECT_DISABLED); + } else { + fme.setInspectMode(true); + msg(TL.COMMAND_INSPECT_ENABLED); + } + + } + + @Override + public TL getUsageTranslation() { + return TL.COMMAND_INSPECT_DESCRIPTION; + } +} diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdVersion.java b/src/main/java/com/massivecraft/factions/cmd/CmdVersion.java index 84b2362c..b84c0fa9 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdVersion.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdVersion.java @@ -25,6 +25,7 @@ public class CmdVersion extends FCommand { @Override public void perform() { + msg(TL.COMMAND_VERSION_NAME); // Did this so people can differentiate between SavageFactions and FactionsUUID (( Requested Feature )) msg(TL.COMMAND_VERSION_VERSION, P.p.getDescription().getFullName()); } diff --git a/src/main/java/com/massivecraft/factions/cmd/FCmdRoot.java b/src/main/java/com/massivecraft/factions/cmd/FCmdRoot.java index 7764e27f..943a419c 100644 --- a/src/main/java/com/massivecraft/factions/cmd/FCmdRoot.java +++ b/src/main/java/com/massivecraft/factions/cmd/FCmdRoot.java @@ -3,6 +3,7 @@ package com.massivecraft.factions.cmd; import com.massivecraft.factions.Conf; import com.massivecraft.factions.P; import com.massivecraft.factions.zcore.util.TL; +import net.coreprotect.CoreProtect; import org.bukkit.Bukkit; import java.util.Collections; @@ -93,6 +94,10 @@ public class FCmdRoot extends FCommand { public CmdBanner cmdBanner = new CmdBanner(); public CmdTpBanner cmdTpBanner = new CmdTpBanner(); public CmdKillHolograms cmdKillHolograms = new CmdKillHolograms(); + public CmdInspect cmdInspect = new CmdInspect(); + + + public FCmdRoot() { super(); this.aliases.addAll(Conf.baseCommandAliases); @@ -197,7 +202,12 @@ public class FCmdRoot extends FCommand { this.addSubCommand(this.cmdTpBanner); this.addSubCommand(this.cmdKillHolograms); - + if (CoreProtect.getInstance() != null){ + P.p.log("Found CoreProtect, enabling Inspect"); + this.addSubCommand(this.cmdInspect); + } else { + P.p.log("CoreProtect not found, disabling Inspect"); + } if (P.p.getConfig().getBoolean("enable-faction-flight", false)) { this.addSubCommand(this.cmdFly); diff --git a/src/main/java/com/massivecraft/factions/listeners/FactionsEntityListener.java b/src/main/java/com/massivecraft/factions/listeners/FactionsEntityListener.java index 2f6bf006..833ae570 100644 --- a/src/main/java/com/massivecraft/factions/listeners/FactionsEntityListener.java +++ b/src/main/java/com/massivecraft/factions/listeners/FactionsEntityListener.java @@ -7,6 +7,7 @@ import com.massivecraft.factions.util.MiscUtil; import com.massivecraft.factions.zcore.util.TL; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.TravelAgent; import org.bukkit.block.Block; import org.bukkit.entity.*; @@ -19,6 +20,7 @@ import org.bukkit.event.hanging.HangingBreakByEntityEvent; import org.bukkit.event.hanging.HangingBreakEvent; import org.bukkit.event.hanging.HangingBreakEvent.RemoveCause; import org.bukkit.event.hanging.HangingPlaceEvent; +import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerPortalEvent; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; @@ -252,6 +254,21 @@ public class FactionsEntityListener implements Listener { } } + //For disabling enderpearl throws + @EventHandler + public void onPearl(PlayerInteractEvent e) { + Player player = e.getPlayer(); + if (player.getItemInHand().getType() == Material.ENDER_PEARL) { + FPlayer fPlayer = FPlayers.getInstance().getByPlayer(player); + if (fPlayer.isFlying()){ + if (!Conf.noEnderpearlsInFly){ + fPlayer.msg(TL.COMMAND_FLY_NO_EPEARL); + e.setCancelled(true); + } + } + } + } + // mainly for flaming arrows; don't want allies or people in safe zones to be ignited even after damage event is cancelled @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) diff --git a/src/main/java/com/massivecraft/factions/listeners/FactionsPlayerListener.java b/src/main/java/com/massivecraft/factions/listeners/FactionsPlayerListener.java index 5cd2e421..85b15521 100644 --- a/src/main/java/com/massivecraft/factions/listeners/FactionsPlayerListener.java +++ b/src/main/java/com/massivecraft/factions/listeners/FactionsPlayerListener.java @@ -21,6 +21,8 @@ import com.massivecraft.factions.zcore.fperms.PermissableAction; import com.massivecraft.factions.zcore.persist.MemoryFPlayer; import com.massivecraft.factions.zcore.util.TL; import com.massivecraft.factions.zcore.util.TextUtil; +import net.coreprotect.CoreProtect; +import net.coreprotect.CoreProtectAPI; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -257,6 +259,51 @@ public class FactionsPlayerListener implements Listener { } } + //inspect + @EventHandler + public void onInspect(PlayerInteractEvent e){ + if (e.getAction().name().contains("BLOCK")){ + FPlayer fplayer = FPlayers.getInstance().getByPlayer(e.getPlayer()); + if (!fplayer.isInspectMode()){ + return; + } + if (!fplayer.isAdminBypassing()){ + if (fplayer.getFaction() != Board.getInstance().getFactionAt(new FLocation(e.getPlayer().getLocation()))){ + fplayer.msg(TL.COMMAND_INSPECT_NOTINCLAIM); + return; + } + } else { + fplayer.msg(TL.COMMAND_INSPECT_BYPASS); + } + List info = CoreProtect.getInstance().getAPI().blockLookup(e.getClickedBlock(),0); + if (info.size() == 0) { + e.getPlayer().sendMessage(TL.COMMAND_INSPECT_NODATA.toString()); + return; + } + Player player = e.getPlayer(); + CoreProtectAPI coAPI = CoreProtect.getInstance().getAPI(); + player.sendMessage(TL.COMMAND_INSPECT_HEADER.toString().replace("{x}",e.getClickedBlock().getX() + "") + .replace("{y}",e.getClickedBlock().getY() + "") + .replace("{z}",e.getClickedBlock().getZ() + "")); + String rowFormat = TL.COMMAND_INSPECT_ROW.toString(); + for (int i = 0; i < info.size(); i++){ + CoreProtectAPI.ParseResult row = coAPI.parseResult((String[])info.get(0)); + player.sendMessage(rowFormat + .replace("{time}",convertTime(row.getTime())) + .replace("{action}",row.getActionString()) + .replace("{player}",row.getPlayer()) + .replace("{block-type}",row.getType().toString().toLowerCase())); + } + + } + } + + private String convertTime(int time) + { + String result = String.valueOf(Math.round((System.currentTimeMillis() / 1000L - time) / 36.0D) / 100.0D); + return (result.length() == 3 ? result + "0" : result) + "/hrs ago"; + } + // Holds the next time a player can have a map shown. private HashMap showTimes = new HashMap<>(); @@ -318,7 +365,7 @@ public class FactionsPlayerListener implements Listener { (relationTo == Relation.ENEMY && me.canflyinEnemy()) || (relationTo == Relation.ALLY && me.canflyinAlly()) || (relationTo == Relation.TRUCE && me.canflyinTruce()) || - (relationTo == Relation.NEUTRAL && me.canflyinNeutral())) { + (relationTo == Relation.NEUTRAL && me.canflyinNeutral() && !isSystemFaction(factionTo))) { enableFly(me); } @@ -390,6 +437,12 @@ public class FactionsPlayerListener implements Listener { } + public static Boolean isSystemFaction(Faction faction) { + return faction.isSafeZone() || + faction.isWarZone() || + faction.isWilderness(); + } + HashMap bannerCooldownMap = new HashMap<>(); public static HashMap bannerLocations = new HashMap<>(); diff --git a/src/main/java/com/massivecraft/factions/struct/Permission.java b/src/main/java/com/massivecraft/factions/struct/Permission.java index 7b9d3b3f..9834d58d 100644 --- a/src/main/java/com/massivecraft/factions/struct/Permission.java +++ b/src/main/java/com/massivecraft/factions/struct/Permission.java @@ -98,6 +98,7 @@ public enum Permission { BANNER("banner"), TPBANNER("tpbanner"), KILLHOLOS("killholos"), + INSPECT("inspect"), WARP("warp"); public final String node; diff --git a/src/main/java/com/massivecraft/factions/util/ClipPlaceholderAPIManager.java b/src/main/java/com/massivecraft/factions/util/ClipPlaceholderAPIManager.java index a15cbe75..b147db5c 100644 --- a/src/main/java/com/massivecraft/factions/util/ClipPlaceholderAPIManager.java +++ b/src/main/java/com/massivecraft/factions/util/ClipPlaceholderAPIManager.java @@ -38,6 +38,9 @@ public class ClipPlaceholderAPIManager extends PlaceholderExpansion implements R return P.p.getDescription().getVersion(); } + + + // Relational placeholders @Override public String onPlaceholderRequest(Player p1, Player p2, String placeholder) { diff --git a/src/main/java/com/massivecraft/factions/zcore/persist/MemoryFPlayer.java b/src/main/java/com/massivecraft/factions/zcore/persist/MemoryFPlayer.java index da0d1887..77331c2e 100644 --- a/src/main/java/com/massivecraft/factions/zcore/persist/MemoryFPlayer.java +++ b/src/main/java/com/massivecraft/factions/zcore/persist/MemoryFPlayer.java @@ -1103,7 +1103,8 @@ public abstract class MemoryFPlayer implements FPlayer { @Override public boolean checkIfNearbyEnemies(){ Player me = this.getPlayer(); - for (Entity e : me.getNearbyEntities(16, 255, 16)) { + int radius = Conf.enemyFlyCheckRadius; + for (Entity e : me.getNearbyEntities(radius, 255, radius)) { if (e == null) { continue; } if (e instanceof Player) { Player eplayer = (((Player) e).getPlayer()); @@ -1125,7 +1126,6 @@ public abstract class MemoryFPlayer implements FPlayer { @Override public Boolean canflyinWilderness() { return getPlayer().hasPermission("factions.fly.wilderness"); - } @Override @@ -1165,6 +1165,19 @@ public abstract class MemoryFPlayer implements FPlayer { } + boolean inspectMode = false; + + @Override + public boolean isInspectMode(){ + return inspectMode; + } + + @Override + public void setInspectMode( boolean status){ + inspectMode = status; + } + + diff --git a/src/main/java/com/massivecraft/factions/zcore/util/TL.java b/src/main/java/com/massivecraft/factions/zcore/util/TL.java index ba968c3c..55d3386c 100644 --- a/src/main/java/com/massivecraft/factions/zcore/util/TL.java +++ b/src/main/java/com/massivecraft/factions/zcore/util/TL.java @@ -285,6 +285,7 @@ public enum TL { COMMAND_FLY_NO_ACCESS("&c&l[!]&7 &cCannot fly &7in territory of %1$s"), COMMAND_FLY_ENEMY_NEAR("&c&l[!]&7 Flight has been&c disabled&7 an enemy is nearby"), COMMAND_FLY_CHECK_ENEMY("&c&l[!]&7 Cannot fly here, an enemy is &cnearby"), + COMMAND_FLY_NO_EPEARL("&c&l[!] &7You &ccannot&7 throw enderpearls while flying!"), COMMAND_FWARP_CLICKTOWARP("&c&l[!]&7 Click to &cwarp!"), COMMAND_FWARP_COMMANDFORMAT("&c&l[!]&7 /f warp &c[password]"), @@ -308,6 +309,15 @@ public enum TL { COMMAND_HOME_FORTELEPORT("for teleporting to your faction home"), COMMAND_HOME_DESCRIPTION("Teleport to the faction home"), + COMMAND_INSPECT_DISABLED("&c&l[!]&7 Inspect mode is now &cdisabled."), + COMMAND_INSPECT_ENABLED("&c&l[!]&7 Inspect mode is now &aEnabled."), + COMMAND_INSPECT_HEADER("&c&m---&7Inspect Data&c&m---&c//&7x:{x},y:{y},z:{z}"), + COMMAND_INSPECT_ROW("&c{time} &7// &c{action} &7// &c{player} &7// &c{block-type}"), + COMMAND_INSPECT_NODATA("&c&l[!]&7 &7No Data was found!"), + COMMAND_INSPECT_NOTINCLAIM("&c&l[!]&7 &7You can &conly&7 inspect in &cyour &7claims!"), + COMMAND_INSPECT_BYPASS("&c&l[!]&7 Inspecting in &cbypass&7 mode"), + COMMAND_INSPECT_DESCRIPTION("Inspect blocks!"), + COMMAND_INVITE_TOINVITE("to invite someone"), COMMAND_INVITE_FORINVITE("for inviting someone"), COMMAND_INVITE_CLICKTOJOIN("Click to join!"), @@ -675,7 +685,8 @@ public enum TL { COMMAND_UNCLAIMALL_DESCRIPTION("Unclaim all of your factions land"), COMMAND_UNCLAIM_CLICKTOUNCLAIM("Click to unclaim &2(%1$d, %2$d)"), - COMMAND_VERSION_VERSION("You are running %1$s"), + COMMAND_VERSION_NAME("&c&l[!]&7 SavageFactions &c» &7By ProSavage"), + COMMAND_VERSION_VERSION("&7Version &c» &7%1$s"), COMMAND_VERSION_DESCRIPTION("Show plugin and translation version information"), COMMAND_WARUNCLAIMALL_DESCRIPTION("Unclaim all warzone land"), diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 76b9dd7a..d91acb24 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -2,7 +2,7 @@ name: Factions version: ${project.version}-SF-1.0.23-BETA main: com.massivecraft.factions.P authors: [Olof Larsson, Brett Flannigan, drtshock, ProSavage] -softdepend: [PlayerVaults, PlaceholderAPI, MVdWPlaceholderAPI, PermissionsEx, Permissions, Essentials, EssentialsChat, HeroChat, iChat, LocalAreaChat, LWC, nChat, ChatManager, CAPI, AuthMe, Vault, Spout, WorldEdit, WorldGuard, AuthDB, CaptureThePoints, CombatTag, dynmap, FactionsTop] +softdepend: [CoreProtect, PlayerVaults, PlaceholderAPI, MVdWPlaceholderAPI, PermissionsEx, Permissions, Essentials, EssentialsChat, HeroChat, iChat, LocalAreaChat, LWC, nChat, ChatManager, CAPI, AuthMe, Vault, Spout, WorldEdit, WorldGuard, AuthDB, CaptureThePoints, CombatTag, dynmap, FactionsTop] commands: factions: description: Reference command for Factions.