diff --git a/src/main/java/com/massivecraft/factions/Conf.java b/src/main/java/com/massivecraft/factions/Conf.java index 6aa8ad3a..69cec4fc 100644 --- a/src/main/java/com/massivecraft/factions/Conf.java +++ b/src/main/java/com/massivecraft/factions/Conf.java @@ -239,6 +239,7 @@ public class Conf { public static boolean ownedMessageInsideTerritory = true; public static boolean ownedMessageByChunk = false; public static boolean pistonProtectionThroughDenyBuild = true; + public static Set loggableMaterials = EnumSet.noneOf(Material.class); public static Set territoryProtectedMaterials = EnumSet.noneOf(Material.class); public static Set territoryDenyUsageMaterials = EnumSet.noneOf(Material.class); public static Set territoryProtectedMaterialsWhenOffline = EnumSet.noneOf(Material.class); diff --git a/src/main/java/com/massivecraft/factions/FLocation.java b/src/main/java/com/massivecraft/factions/FLocation.java index 3b543943..9a94dc8a 100644 --- a/src/main/java/com/massivecraft/factions/FLocation.java +++ b/src/main/java/com/massivecraft/factions/FLocation.java @@ -152,6 +152,8 @@ public class FLocation implements Serializable { return "" + x + "," + z; } + public String formatXAndZ(String splitter) { return chunkToBlock(this.x) + "x" + splitter + " " + chunkToBlock(this.z) + "z"; } + //----------------------------------------------// // Misc Geometry //----------------------------------------------// diff --git a/src/main/java/com/massivecraft/factions/FactionsPlugin.java b/src/main/java/com/massivecraft/factions/FactionsPlugin.java index 5017ec47..05e111c1 100755 --- a/src/main/java/com/massivecraft/factions/FactionsPlugin.java +++ b/src/main/java/com/massivecraft/factions/FactionsPlugin.java @@ -8,6 +8,9 @@ import com.massivecraft.factions.cmd.CmdAutoHelp; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.FCmdRoot; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FChestListener; +import com.massivecraft.factions.cmd.audit.FLogManager; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.cmd.check.CheckTask; import com.massivecraft.factions.cmd.check.WeeWooTask; import com.massivecraft.factions.cmd.chest.AntiChestListener; @@ -90,6 +93,7 @@ public class FactionsPlugin extends MPlugin { private Listener[] eventsListener; public List itemList = getConfig().getStringList("fchest.Items-Not-Allowed"); private Worldguard wg; + private FLogManager fLogManager; public FactionsPlugin() { @@ -184,6 +188,7 @@ public class FactionsPlugin extends MPlugin { PermissionList.generateFile(); // Load Conf from disk Conf.load(); + fLogManager = new FLogManager(); //Dependency checks if (Conf.dependencyCheck && (!Bukkit.getPluginManager().isPluginEnabled("Vault") && !Bukkit.getPluginManager().isPluginEnabled("Essentials"))) { divider(); @@ -271,6 +276,7 @@ public class FactionsPlugin extends MPlugin { new Discord(this); ShopConfig.setup(); + fLogManager.loadLogs(this); getServer().getPluginManager().registerEvents(factionsPlayerListener = new FactionsPlayerListener(), this); @@ -283,6 +289,8 @@ public class FactionsPlugin extends MPlugin { new FUpgradesGUI(), new UpgradesListener(), new MissionHandler(this), + new FChestListener(), + new MenuListener(), new AntiChestListener() }; @@ -431,6 +439,11 @@ public class FactionsPlugin extends MPlugin { } DiscordListener.saveGuilds(); super.onDisable(); + try { + fLogManager.saveLogs(); + } catch (Exception e) { + e.printStackTrace(); + } } public void startAutoLeaveTask(boolean restartIfRunning) { @@ -556,22 +569,6 @@ public class FactionsPlugin extends MPlugin { } } - public void createTimedHologram(final Location location, String text, Long timeout) { - ArmorStand as = (ArmorStand) location.add(0.5, 1, 0.5).getWorld().spawnEntity(location, EntityType.ARMOR_STAND); //Spawn the ArmorStand - as.setVisible(false); //Makes the ArmorStand invisible - as.setGravity(false); //Make sure it doesn't fall - as.setCanPickupItems(false); //I'm not sure what happens if you leave this as it is, but you might as well disable it - as.setCustomName(FactionsPlugin.instance.color(text)); //Set this to the text you want - as.setCustomNameVisible(true); //This makes the text appear no matter if your looking at the entity or not - final ArmorStand armorStand = as; - - Bukkit.getScheduler().scheduleSyncDelayedTask(FactionsPlugin.instance, () -> { - armorStand.remove(); - getLogger().info("Removing Hologram."); - } - , timeout * 20); - } - // -------------------------------------------- // // Functions for other plugins to hook into @@ -651,6 +648,15 @@ public class FactionsPlugin extends MPlugin { return tag; } + + public FLogManager getFlogManager() { + return fLogManager; + } + + public void logFactionEvent(Faction faction, FLogType type, String... arguments) { + this.fLogManager.log(faction, type, arguments); + } + // Get a player's title within their faction, mainly for usage by chat plugins for local/channel chat public String getPlayerTitle(Player player) { if (player == null) { diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdAdmin.java b/src/main/java/com/massivecraft/factions/cmd/CmdAdmin.java index 89610a6a..72c0935f 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdAdmin.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdAdmin.java @@ -4,11 +4,13 @@ import com.massivecraft.factions.FPlayer; import com.massivecraft.factions.FPlayers; import com.massivecraft.factions.Faction; import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.event.FPlayerJoinEvent; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Role; import com.massivecraft.factions.zcore.util.TL; import org.bukkit.Bukkit; +import org.bukkit.ChatColor; public class CmdAdmin extends FCommand { @@ -84,6 +86,8 @@ public class CmdAdmin extends FCommand { fyou.setRole(Role.LEADER); context.msg(TL.COMMAND_ADMIN_PROMOTES, fyou.describeTo(context.fPlayer, true)); + FactionsPlugin.instance.getFlogManager().log(targetFaction, FLogType.RANK_EDIT, context.fPlayer.getName(), fyou.getName(), ChatColor.RED + "Admin"); + // Inform all players for (FPlayer fplayer : FPlayers.getInstance().getOnlinePlayers()) { fplayer.msg(TL.COMMAND_ADMIN_PROMOTED, diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdBan.java b/src/main/java/com/massivecraft/factions/cmd/CmdBan.java index ed6f27f2..58d142ab 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdBan.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdBan.java @@ -2,9 +2,11 @@ package com.massivecraft.factions.cmd; import com.massivecraft.factions.FPlayer; import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.event.FPlayerLeaveEvent; import com.massivecraft.factions.struct.BanInfo; import com.massivecraft.factions.struct.Permission; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.zcore.fperms.PermissableAction; import com.massivecraft.factions.zcore.util.TL; import org.bukkit.Bukkit; @@ -79,6 +81,7 @@ public class CmdBan extends FCommand { // Lets inform the people! target.msg(TL.COMMAND_BAN_TARGET, context.faction.getTag(target.getFaction())); + FactionsPlugin.instance.logFactionEvent(context.faction, FLogType.BANS, context.fPlayer.getName(), CC.Green + "banned", target.getName()); context.faction.msg(TL.COMMAND_BAN_BANNED, context.fPlayer.getName(), target.getName()); } diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdColeader.java b/src/main/java/com/massivecraft/factions/cmd/CmdColeader.java index d5b56daf..95740d83 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdColeader.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdColeader.java @@ -3,6 +3,8 @@ package com.massivecraft.factions.cmd; import com.massivecraft.factions.Conf; import com.massivecraft.factions.FPlayer; import com.massivecraft.factions.Faction; +import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Role; import com.massivecraft.factions.zcore.util.TL; @@ -81,6 +83,7 @@ public class CmdColeader extends FCommand { you.setRole(Role.COLEADER); targetFaction.msg(TL.COMMAND_COLEADER_PROMOTED, you.describeTo(targetFaction, true)); context.msg(TL.COMMAND_COLEADER_PROMOTES, you.describeTo(context.fPlayer, true)); + FactionsPlugin.instance.getFlogManager().log(targetFaction, FLogType.RANK_EDIT, context.fPlayer.getName(), you.getName(), ChatColor.RED + "Co-Leader"); } } diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdDescription.java b/src/main/java/com/massivecraft/factions/cmd/CmdDescription.java index 35eb619b..890152f9 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdDescription.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdDescription.java @@ -4,9 +4,11 @@ import com.massivecraft.factions.Conf; import com.massivecraft.factions.FPlayer; import com.massivecraft.factions.FPlayers; import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.zcore.util.TL; import com.massivecraft.factions.zcore.util.TextUtil; +import org.bukkit.Bukkit; public class CmdDescription extends FCommand { @@ -38,8 +40,9 @@ public class CmdDescription extends FCommand { // since "&" color tags seem to work even through plain old FPlayer.sendMessage() for some reason, we need to break those up // And replace all the % because it messes with string formatting and this is easy way around that. - context.faction.setDescription(TextUtil.implode(context.args, " ").replaceAll("%", "").replaceAll("(&([a-f0-9klmnor]))", "& $2")); - + String desc = TextUtil.implode(context.args, " ").replaceAll("%", "").replaceAll("(&([a-f0-9klmnor]))", "& $2"); + context.faction.setDescription(desc); + Bukkit.getScheduler().scheduleSyncDelayedTask(FactionsPlugin.instance, () -> FactionsPlugin.instance.logFactionEvent(context.faction, FLogType.FDESC_EDIT, context.fPlayer.getName(), desc)); if (!Conf.broadcastDescriptionChanges) { context.msg(TL.COMMAND_DESCRIPTION_CHANGED, context.faction.describeTo(context.fPlayer)); context.sendMessage(context.faction.getDescription()); diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdInvite.java b/src/main/java/com/massivecraft/factions/cmd/CmdInvite.java index 9002ab86..25092c6c 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdInvite.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdInvite.java @@ -3,7 +3,9 @@ package com.massivecraft.factions.cmd; import com.massivecraft.factions.Conf; import com.massivecraft.factions.FPlayer; import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.struct.Permission; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.zcore.fperms.PermissableAction; import com.massivecraft.factions.zcore.util.TL; import mkremins.fanciful.FancyMessage; @@ -68,11 +70,10 @@ public class CmdInvite extends FCommand { .command("/" + Conf.baseCommandAliases.get(0) + " join " + context.faction.getTag()) .then(context.faction.describeTo(target)).tooltip(TL.COMMAND_INVITE_CLICKTOJOIN.toString()) .command("/" + Conf.baseCommandAliases.get(0) + " join " + context.faction.getTag()); - message.send(target.getPlayer()); } - context.faction.msg(TL.COMMAND_INVITE_INVITED, context.fPlayer.describeTo(context.faction, true), target.describeTo(context.faction)); + FactionsPlugin.instance.logFactionEvent(context.faction, FLogType.INVITES, context.fPlayer.getName(), CC.Green + "invited", target.getName()); } @Override diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdJoin.java b/src/main/java/com/massivecraft/factions/cmd/CmdJoin.java index f9e59a9a..6a91b481 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdJoin.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdJoin.java @@ -1,15 +1,19 @@ package com.massivecraft.factions.cmd; import com.massivecraft.factions.*; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.discord.Discord; import com.massivecraft.factions.event.FPlayerJoinEvent; import com.massivecraft.factions.struct.Permission; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.zcore.fupgrades.UpgradeType; import com.massivecraft.factions.zcore.util.TL; import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.exceptions.HierarchyException; import org.bukkit.Bukkit; +import java.util.Objects; + public class CmdJoin extends FCommand { /** @@ -125,10 +129,11 @@ public class CmdJoin extends FCommand { faction.deinvite(fplayer); try { context.fPlayer.setRole(faction.getDefaultRole()); + FactionsPlugin.instance.logFactionEvent(faction, FLogType.INVITES, context.fPlayer.getName(), CC.Green + "joined", "the faction"); if (Discord.useDiscord && context.fPlayer.discordSetup() && Discord.isInMainGuild(context.fPlayer.discordUser()) && Discord.mainGuild != null) { Member m = Discord.mainGuild.getMember(context.fPlayer.discordUser()); if (Conf.factionRoles) { - Discord.mainGuild.getController().addSingleRoleToMember(m, Discord.createFactionRole(faction.getTag())).queue(); + Discord.mainGuild.getController().addSingleRoleToMember(m, Objects.requireNonNull(Discord.createFactionRole(faction.getTag()))).queue(); } if (Conf.factionDiscordTags) { Discord.mainGuild.getController().setNickname(m, Discord.getNicknameString(context.fPlayer)).queue(); diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdKick.java b/src/main/java/com/massivecraft/factions/cmd/CmdKick.java index d5d32e72..4d67fee0 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdKick.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdKick.java @@ -4,9 +4,11 @@ import com.massivecraft.factions.Conf; import com.massivecraft.factions.FPlayer; import com.massivecraft.factions.Faction; import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.event.FPlayerLeaveEvent; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Role; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.zcore.fperms.PermissableAction; import com.massivecraft.factions.zcore.util.TL; import mkremins.fanciful.FancyMessage; @@ -122,6 +124,7 @@ public class CmdKick extends FCommand { if (toKick.getRole() == Role.LEADER) { toKickFaction.promoteNewLeader(); } + FactionsPlugin.instance.logFactionEvent(toKickFaction, FLogType.INVITES, context.fPlayer.getName(), CC.Red + "kicked", toKick.getName()); toKickFaction.deinvite(toKick); toKick.resetFactionData(); } diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdMod.java b/src/main/java/com/massivecraft/factions/cmd/CmdMod.java index f8da28d3..b25bfa2e 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdMod.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdMod.java @@ -4,6 +4,7 @@ import com.massivecraft.factions.Conf; import com.massivecraft.factions.FPlayer; import com.massivecraft.factions.Faction; import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Role; import com.massivecraft.factions.zcore.util.TL; @@ -77,6 +78,8 @@ public class CmdMod extends FCommand { you.setRole(Role.MODERATOR); targetFaction.msg(TL.COMMAND_MOD_PROMOTED, you.describeTo(targetFaction, true)); context.msg(TL.COMMAND_MOD_PROMOTES, you.describeTo(context.fPlayer, true)); + FactionsPlugin.instance.getFlogManager().log(targetFaction, FLogType.RANK_EDIT, context.fPlayer.getName(), you.getName(), ChatColor.LIGHT_PURPLE + "Mod"); + } } diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdSaveAll.java b/src/main/java/com/massivecraft/factions/cmd/CmdSaveAll.java index 4184d3f0..0ba8151a 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdSaveAll.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdSaveAll.java @@ -1,9 +1,6 @@ package com.massivecraft.factions.cmd; -import com.massivecraft.factions.Board; -import com.massivecraft.factions.Conf; -import com.massivecraft.factions.FPlayers; -import com.massivecraft.factions.Factions; +import com.massivecraft.factions.*; import com.massivecraft.factions.shop.ShopConfig; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.zcore.util.TL; @@ -29,6 +26,11 @@ public class CmdSaveAll extends FCommand { Factions.getInstance().forceSave(false); Board.getInstance().forceSave(false); Conf.save(); + try { + FactionsPlugin.instance.getFlogManager().saveLogs(); + } catch (Exception e) { + e.printStackTrace(); + } ShopConfig.saveShop(); context.msg(TL.COMMAND_SAVEALL_SUCCESS); } diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdTag.java b/src/main/java/com/massivecraft/factions/cmd/CmdTag.java index 0ef9e35d..68337ab1 100644 --- a/src/main/java/com/massivecraft/factions/cmd/CmdTag.java +++ b/src/main/java/com/massivecraft/factions/cmd/CmdTag.java @@ -1,6 +1,7 @@ package com.massivecraft.factions.cmd; import com.massivecraft.factions.*; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.discord.Discord; import com.massivecraft.factions.event.FactionRenameEvent; import com.massivecraft.factions.scoreboards.FTeamWrapper; @@ -69,6 +70,8 @@ public class CmdTag extends FCommand { String oldtag = context.faction.getTag(); context.faction.setTag(tag); Discord.changeFactionTag(context.faction, oldtag); + FactionsPlugin.instance.logFactionEvent(context.faction, FLogType.FTAG_EDIT, context.fPlayer.getName(), tag); + // Inform for (FPlayer fplayer : FPlayers.getInstance().getOnlinePlayers()) { @@ -76,14 +79,12 @@ public class CmdTag extends FCommand { fplayer.msg(TL.COMMAND_TAG_FACTION, context.fPlayer.describeTo(context.faction, true), context.faction.getTag(context.faction)); continue; } - // Broadcast the tag change (if applicable) if (Conf.broadcastTagChanges) { Faction faction = fplayer.getFaction(); fplayer.msg(TL.COMMAND_TAG_CHANGED, context.fPlayer.getColorTo(faction) + oldtag, context.faction.getTag(faction)); } } - FTeamWrapper.updatePrefixes(context.faction); }); } diff --git a/src/main/java/com/massivecraft/factions/cmd/alts/CmdInviteAlt.java b/src/main/java/com/massivecraft/factions/cmd/alts/CmdInviteAlt.java index 5f507fd4..1b879551 100644 --- a/src/main/java/com/massivecraft/factions/cmd/alts/CmdInviteAlt.java +++ b/src/main/java/com/massivecraft/factions/cmd/alts/CmdInviteAlt.java @@ -6,8 +6,10 @@ import com.massivecraft.factions.FactionsPlugin; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Role; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.zcore.fperms.Access; import com.massivecraft.factions.zcore.fperms.PermissableAction; import com.massivecraft.factions.zcore.util.TL; @@ -84,7 +86,7 @@ public class CmdInviteAlt extends FCommand { .command("/" + Conf.baseCommandAliases.get(0) + " join " + context.faction.getTag()); message.send(target.getPlayer()); - + FactionsPlugin.instance.logFactionEvent(context.faction, FLogType.INVITES, context.fPlayer.getName(), CC.Green + "invited", target.getName()); context.faction.msg(TL.COMMAND_ALTINVITE_INVITED_ALT, context.fPlayer.describeTo(context.faction, true), target.describeTo(context.faction)); } diff --git a/src/main/java/com/massivecraft/factions/cmd/alts/CmdKickAlt.java b/src/main/java/com/massivecraft/factions/cmd/alts/CmdKickAlt.java index bf036482..eb04c077 100644 --- a/src/main/java/com/massivecraft/factions/cmd/alts/CmdKickAlt.java +++ b/src/main/java/com/massivecraft/factions/cmd/alts/CmdKickAlt.java @@ -7,9 +7,11 @@ import com.massivecraft.factions.FactionsPlugin; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.event.FPlayerLeaveEvent; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Role; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.zcore.fperms.Access; import com.massivecraft.factions.zcore.fperms.PermissableAction; import com.massivecraft.factions.zcore.util.TL; @@ -126,7 +128,7 @@ public class CmdKickAlt extends FCommand { toKickFaction.promoteNewLeader(); } - + FactionsPlugin.instance.logFactionEvent(toKickFaction, FLogType.INVITES, context.fPlayer.getName(), CC.Red + "kicked alt", toKick.getName()); toKickFaction.removeAltPlayer(toKick); toKickFaction.deinvite(toKick); toKick.resetFactionData(); diff --git a/src/main/java/com/massivecraft/factions/cmd/audit/CmdAudit.java b/src/main/java/com/massivecraft/factions/cmd/audit/CmdAudit.java new file mode 100644 index 00000000..2c8252ef --- /dev/null +++ b/src/main/java/com/massivecraft/factions/cmd/audit/CmdAudit.java @@ -0,0 +1,40 @@ +package com.massivecraft.factions.cmd.audit; + +/** + * @author Saser + */ + +import com.massivecraft.factions.Faction; +import com.massivecraft.factions.cmd.CommandContext; +import com.massivecraft.factions.cmd.CommandRequirements; +import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.struct.Permission; +import com.massivecraft.factions.zcore.util.TL; +import org.bukkit.entity.Player; + +public class CmdAudit extends FCommand { + + public CmdAudit() { + super(); + this.aliases.add("audit"); + this.aliases.add("logs"); + this.aliases.add("log"); + + + this.requirements = new CommandRequirements.Builder(Permission.AUDIT) + .playerOnly() + .memberOnly() + .noErrorOnManyArgs() + .build(); + } + @Override + public void perform(CommandContext context) { + Faction faction = context.args.size() == 1 && context.sender.isOp() ? context.argAsFaction(0) : context.faction; + new FAuditMenu((Player)context.sender, faction).open((Player)context.sender); + } + + @Override + public TL getUsageTranslation() { + return null; + } +} diff --git a/src/main/java/com/massivecraft/factions/cmd/audit/FAuditMenu.java b/src/main/java/com/massivecraft/factions/cmd/audit/FAuditMenu.java new file mode 100644 index 00000000..c12d7089 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/cmd/audit/FAuditMenu.java @@ -0,0 +1,157 @@ +package com.massivecraft.factions.cmd.audit; + +/** + * @author Saser + */ +import com.google.common.collect.Lists; +import com.massivecraft.factions.Faction; +import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.util.CC; +import com.massivecraft.factions.util.ItemBuilder; +import com.massivecraft.factions.util.serializable.ClickableItemStack; +import com.massivecraft.factions.util.serializable.GUIMenu; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class FAuditMenu extends GUIMenu { + private static int logsPerPage = 20; + private Player player; + private boolean showTimestamps = true; + private Faction faction; + + public FAuditMenu(Player player, Faction faction) { + super("Faction Logs", 18); + this.faction = faction; + this.player = player; + } + + public void drawItems() { + int index = 0; + FLogType[] logTypes = FLogType.values(); + int length1 = logTypes.length; + + for (FLogType type : logTypes) { + if (type != FLogType.F_TNT || FactionsPlugin.getInstance().getConfig().getBoolean("f-points.Enabled")) { + if (index == 9) { + index = FactionsPlugin.getInstance().getConfig().getBoolean("f-points.Enabled") ? 11 : 12; + } + + FactionLogs logs = FactionsPlugin.instance.getFlogManager().getFactionLogMap().get(this.faction.getId()); + if (logs == null) { + logs = new FactionLogs(); + } + + LinkedList recentLogs = logs.getMostRecentLogs().get(type); + if (recentLogs == null) { + recentLogs = Lists.newLinkedList(); + } + + List lore = Lists.newArrayList("", CC.GreenB + "Recent Logs " + CC.Green + "(" + CC.GreenB + recentLogs.size() + CC.Green + ")"); + int added = 0; + Iterator backwars = recentLogs.descendingIterator(); + while (backwars.hasNext()) { + FactionLogs.FactionLog log = (FactionLogs.FactionLog) backwars.next(); + if (added >= logsPerPage) { + break; + } + + String length = log.getLogLine(type, this.showTimestamps); + lore.add(" " + CC.Yellow + length); + ++added; + } + + int logSize = recentLogs.size(); + int logsLeft = logSize - logsPerPage; + if (logsLeft > 0) { + lore.add(CC.YellowB + logsLeft + CC.Yellow + " more logs..."); + } + + lore.add(""); + if (logsLeft > 0) { + lore.add(CC.Yellow + "Left-Click " + CC.Gray + "to view more logs"); + } + + lore.add(CC.Yellow + "Right-Click " + CC.Gray + "to toggle timestamps"); + this.setItem(index++, (new ClickableItemStack((new ItemBuilder(type.getDisplayMaterial())).name(CC.GreenB + type.getDisplayName()).lore(lore).build())).setClickCallback((click) -> { + click.setCancelled(true); + if (click.getClick() == ClickType.RIGHT) { + this.showTimestamps = !this.showTimestamps; + this.drawItems(); + } else { + if (logsLeft <= 0) { + this.player.sendMessage(CC.Red + "No extra logs to load."); + return; + } + Bukkit.getScheduler().scheduleSyncDelayedTask(FactionsPlugin.instance, () -> (new FAuditLogMenu(this.player, this.faction, type)).open(this.player)); + } + })); + } + } + + } + + class FAuditLogMenu extends GUIMenu { + private Player player; + private Faction faction; + private FLogType logType; + private boolean timeStamp = false; + + public FAuditLogMenu(Player player, Faction faction, FLogType type) { + super("Faction Logs", 9); + this.player = player; + this.faction = faction; + this.logType = type; + } + + public void drawItems() { + FactionLogs logs = FactionsPlugin.instance.getFlogManager().getFactionLogMap().get(faction.getId()); + int perPage = this.logType == FLogType.F_TNT ? 25 : 20; + if (logs != null) { + LinkedList log = logs.getMostRecentLogs().get(this.logType); + if (log != null) { + int slot = this.logType == FLogType.F_TNT ? 0 : 3; + int pagesToShow = (int)Math.max(1.0D, Math.ceil((double)log.size() / (double)perPage)); + + for(int page = 1; page <= pagesToShow; ++page) { + int startIndex = log.size() - (page * perPage - perPage); + if (startIndex >= log.size()) { + startIndex = log.size() - 1; + } + + List lore = Lists.newArrayList("", CC.GreenB + "Logs"); + + for(int i = startIndex; i > startIndex - perPage; --i) { + if (i < log.size()) { + if (i < 0) { + break; + } + + FactionLogs.FactionLog l = log.get(i); + lore.add(" " + CC.Yellow + l.getLogLine(this.logType, this.timeStamp)); + } + } + + lore.add(""); + lore.add(CC.Gray + "Click to toggle timestamp"); + this.setItem(slot++, (new ClickableItemStack((new ItemBuilder(Material.PAPER)).name(CC.GreenB + "Log #" + page).lore(lore).build())).setClickCallback((e) -> { + e.setCancelled(true); + this.timeStamp = !this.timeStamp; + this.drawItems(); + })); + } + } + } + + this.setItem(this.getSize() - 1, (new ClickableItemStack((new ItemBuilder(Material.ARROW)).name(CC.Green + "Previous Page").lore("", CC.Gray + "Click to view previous page!").build())).setClickCallback((event) -> { + event.setCancelled(true); + Bukkit.getScheduler().scheduleSyncDelayedTask(FactionsPlugin.instance, () -> (new FAuditMenu(this.player, this.faction)).open(this.player)); + })); + } + } +} diff --git a/src/main/java/com/massivecraft/factions/cmd/audit/FChestListener.java b/src/main/java/com/massivecraft/factions/cmd/audit/FChestListener.java new file mode 100644 index 00000000..ee5c6f51 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/cmd/audit/FChestListener.java @@ -0,0 +1,109 @@ +package com.massivecraft.factions.cmd.audit; + +/** + * @author Saser + */ +import com.massivecraft.factions.FPlayer; +import com.massivecraft.factions.FPlayers; +import com.massivecraft.factions.Faction; +import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.util.CC; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.util.Arrays; + +public class FChestListener implements Listener { + + @EventHandler + public void onInventoryDrag(InventoryDragEvent e) { + + Player player = (Player) e.getWhoClicked(); + FPlayer fPlayer = FPlayers.getInstance().getByPlayer(player); + if (!fPlayer.isInFactionsChest()) return; + if (e.isCancelled()) return; + e.setCancelled(true); + e.getWhoClicked().sendMessage(CC.RedB + "(!) " + CC.Red + "You cannot drag items while viewing a /f chest!"); + } + + + @EventHandler( + priority = EventPriority.HIGHEST, + ignoreCancelled = true + ) + public void onPlayerClickInventory(InventoryClickEvent event) { + Player player = (Player) event.getWhoClicked(); + FPlayer fPlayer = FPlayers.getInstance().getByPlayer(player); + if (!fPlayer.isInFactionsChest()) return; + + if (event.getClick() == ClickType.UNKNOWN) { + event.setCancelled(true); + player.sendMessage(CC.RedB + "(!) " + CC.Red + "You cannot use that click type inside the /f chest!"); + return; + } + + ItemStack currentItem = event.getCurrentItem(); + if (event.getClick() == ClickType.NUMBER_KEY) { + currentItem = event.getClickedInventory().getItem(event.getSlot()); + } + + Material currentItemType = currentItem != null ? currentItem.getType() : Material.AIR; + + ItemStack cursorItem = event.getCursor(); + if (event.getClick() == ClickType.NUMBER_KEY) { + cursorItem = player.getInventory().getItem(event.getHotbarButton()); + } + + Material cursorItemType = cursorItem != null ? cursorItem.getType() : Material.AIR; + FPlayer fplayer = FPlayers.getInstance().getByPlayer(player); + Faction faction; + if (fplayer == null || !(faction = fplayer.getFaction()).isNormal()) { + player.closeInventory(); + player.sendMessage(CC.RedB + "(!) " + CC.Red + "You are no longer in your faction!"); + return; + } + + if (event.getClickedInventory() == null) { + return; + } + + if (event.getView().getTitle().equalsIgnoreCase(FactionsPlugin.getInstance().color(FactionsPlugin.getInstance().getConfig().getString("fchest.Inventory-Title")))) { + if (currentItemType != Material.AIR) { + Inventory ours = faction.getChestInventory(); + if (ours == null || !ours.contains(currentItem)) { + event.setCancelled(true); + player.sendMessage(CC.RedB + "(!) That item not longer exists!"); + Bukkit.getLogger().info("[FactionChest] " + player.getName() + " tried to remove " + currentItem + " from /f chest when it didnt contain! Items: " + (ours == null ? "none" : Arrays.toString(ours.getContents()))); + player.closeInventory(); + return; + } + + this.logRemoveItem(currentItem, fplayer, player); + } else if (cursorItemType != Material.AIR && !event.isShiftClick()) { + this.logAddItem(cursorItem, fplayer, player); + } + } else if (event.isShiftClick() && currentItemType != Material.AIR) { + this.logAddItem(currentItem, fplayer, player); + } + } + + private void logAddItem(ItemStack cursorItem, FPlayer fplayer, Player player) { + String itemName = cursorItem.hasItemMeta() && cursorItem.getItemMeta().hasDisplayName() ? cursorItem.getItemMeta().getDisplayName() : StringUtils.capitaliseAllWords(cursorItem.getType().name().replace("_", " ").toLowerCase()); + FactionsPlugin.instance.logFactionEvent(fplayer.getFaction(), FLogType.FCHEST_EDIT, player.getName(), CC.GreenB + "ADDED", itemName); + } + + private void logRemoveItem(ItemStack currentItem, FPlayer fplayer, Player player) { + String itemName = currentItem.hasItemMeta() && currentItem.getItemMeta().hasDisplayName() ? currentItem.getItemMeta().getDisplayName() : StringUtils.capitaliseAllWords(currentItem.getType().name().replace("_", " ").toLowerCase()); + FactionsPlugin.instance.logFactionEvent(fplayer.getFaction(), FLogType.FCHEST_EDIT, player.getName(), CC.RedB + "TOOK", itemName); + } +} diff --git a/src/main/java/com/massivecraft/factions/cmd/audit/FLogManager.java b/src/main/java/com/massivecraft/factions/cmd/audit/FLogManager.java new file mode 100644 index 00000000..1aa90ce7 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/cmd/audit/FLogManager.java @@ -0,0 +1,151 @@ +package com.massivecraft.factions.cmd.audit; + +/** + * @author Saser + */ +import com.google.common.reflect.TypeToken; +import com.massivecraft.factions.Faction; +import com.massivecraft.factions.Factions; +import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.util.JSONUtils; +import org.bukkit.Bukkit; + +import java.io.File; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.Timer; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +public class FLogManager { + private Map factionLogMap = new ConcurrentHashMap<>(); + private File logFile; + private Type logToken = (new TypeToken>() { + }).getType(); + private Map logTimers = new ConcurrentHashMap<>(); + private boolean saving = false; + + public FLogManager() { + } + + public void log(Faction faction, FLogType type, String... arguments) { + FactionLogs logs = factionLogMap.computeIfAbsent(faction.getId(), (n) -> new FactionLogs()); + logs.log(type, arguments); + } + + public void loadLogs(FactionsPlugin plugin) { + try { + logFile = new File(plugin.getDataFolder(), "factionLogs.json"); + if (!logFile.exists()) { + logFile.createNewFile(); + } + + factionLogMap = (Map) JSONUtils.fromJson(logFile, logToken); + if (factionLogMap == null) { + factionLogMap = new ConcurrentHashMap<>(); + } + + factionLogMap.forEach((factionId, factionLogs) -> { + + Faction faction = Factions.getInstance().getFactionById(factionId); + if (faction != null && faction.isNormal()) { + factionLogs.checkExpired(); + if (factionLogs.isEmpty()) { + factionLogMap.remove(factionId); + } + + } else { + Bukkit.getLogger().info("Removing dead faction logs for " + factionId + "!"); + factionLogMap.remove(factionId); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + + long delay = TimeUnit.SECONDS.toMillis(15L); + long sellDelay = TimeUnit.SECONDS.toMillis(30L); + Bukkit.getScheduler().scheduleSyncRepeatingTask(FactionsPlugin.instance, () -> { + if (saving) { + Bukkit.getLogger().info("Ignoring saveLogs scheduler due to saving == true!"); + } else { + logTimers.forEach((uuid, logTimer) -> { + if (logTimer != null && logTimer.getFactionId() != null) { + Faction faction = Factions.getInstance().getFactionById(logTimer.getFactionId()); + if (faction == null) { + logTimers.remove(uuid); + Bukkit.getLogger().info("Null faction for logs " + logTimer.getFactionId()); + } else { + if (logTimer.isEmpty()) { + logTimers.remove(uuid); + } + } + } else { + logTimers.remove(uuid); + } + }); + } + }, 20L, 400L); + } + + public void pushPendingLogs(LogTimer.TimerType type) { + Faction faction = null; + + for (Map.Entry uuidLogTimerEntry : getLogTimers().entrySet()) { + Map.Entry timer = uuidLogTimerEntry; + LogTimer logTimer = timer.getValue(); + if (faction == null) { + faction = Factions.getInstance().getFactionById(logTimer.getFactionId()); + } + + if (type != null) { + Map timers = (Map) logTimer.get(type); + if (timers != null && faction != null) { + logTimer.pushLogs(faction, type); + } + } else if (faction != null) { + Faction finalFaction = faction; + logTimer.keySet().forEach((timerType) -> logTimer.pushLogs(finalFaction, timerType)); + logTimer.clear(); + } + } + + if (type == null) { + getLogTimers().clear(); + } + + } + + public void saveLogs() { + if (saving) { + Bukkit.getLogger().info("Ignoring saveLogs due to saving==true!"); + } else { + saving = true; + + try { + pushPendingLogs(null); + } catch (Exception e) { + Bukkit.getLogger().info("error pushing pending logs: " + e.getMessage()); + e.printStackTrace(); + } + + try { + JSONUtils.saveJSONToFile(logFile, factionLogMap,logToken); + } catch (Exception e1) { + Bukkit.getLogger().info("ERRRO SAVING JSON LOGS: " + e1.getMessage()); + e1.printStackTrace(); + } + + saving = false; + } + } + + public Map getFactionLogMap() { + return factionLogMap; + } + + public Map getLogTimers() { + return logTimers; + } +} diff --git a/src/main/java/com/massivecraft/factions/cmd/audit/FLogType.java b/src/main/java/com/massivecraft/factions/cmd/audit/FLogType.java new file mode 100644 index 00000000..512e63f3 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/cmd/audit/FLogType.java @@ -0,0 +1,52 @@ +package com.massivecraft.factions.cmd.audit; + +import com.massivecraft.factions.util.XMaterial; +import org.bukkit.Material; + +/** + * @author Saser + */ +public enum FLogType { + + INVITES("Roster Edits", XMaterial.WRITABLE_BOOK.parseMaterial(), "&e%s&7 &a%s&7 &e%s", 3), + BANS("Player Bans", XMaterial.ANVIL.parseMaterial(), "&e%s&7 &e%s&6 &e%s", 3), + CHUNK_CLAIMS("Claim Edits", XMaterial.WOODEN_AXE.parseMaterial(), "&e%s&7 %s&7 &e%s&7 near &e%s", 3), + PERM_EDIT_DEFAULTS("Default Perm Edits", XMaterial.WRITTEN_BOOK.parseMaterial(), "&e%s&7 %s&7 %s for &e%s", 4), + BANK_EDIT("/f money Edits", XMaterial.GOLD_INGOT.parseMaterial(), "&e%s&7 %s &e&l$&e%s", 3), + FCHEST_EDIT("/f chest Edits", XMaterial.CHEST.parseMaterial(), "&e%s&7 %s &f%s", 3), + RELATION_CHANGE("Relation Edits", XMaterial.GOLDEN_SWORD.parseMaterial(), "&e%s %s&e'd %s", 3), + FTAG_EDIT("/f tag Edits", XMaterial.NAME_TAG.parseMaterial(), "&e%s&7 set to &e'%s'", 2), + FDESC_EDIT("/f desc Edits", XMaterial.PAPER.parseMaterial(), "&e%s&7 set to &e'%s'", 2), + ROLE_PERM_EDIT("/f promote Edits", XMaterial.WRITTEN_BOOK.parseMaterial(), "&e%s&7&e %s &e%s &7to &e%s", 4), + SPAWNER_EDIT("Spawner Edits", XMaterial.SPAWNER.parseMaterial(), "&e%s&7 %s &e%s&7 %s", 4), + RANK_EDIT("Rank Edits", XMaterial.GOLDEN_HELMET.parseMaterial(), "&e%s&7 set &e%s&7 to %s", 3), + F_TNT("/f tnt Edits", XMaterial.TNT.parseMaterial(), "&e%s&7 %s &e%s", 3); + + private String displayName; + private Material displayMaterial; + private String msg; + private int requiredArgs; + + public String getDisplayName() { + return this.displayName; + } + + public Material getDisplayMaterial() { + return this.displayMaterial; + } + + public String getMsg() { + return this.msg; + } + + public int getRequiredArgs() { + return this.requiredArgs; + } + + FLogType(String displayName, Material displayMaterial, String msg, int requiredArgs) { + this.displayName = displayName; + this.displayMaterial = displayMaterial; + this.msg = msg; + this.requiredArgs = requiredArgs; + } +} diff --git a/src/main/java/com/massivecraft/factions/cmd/audit/FactionLogs.java b/src/main/java/com/massivecraft/factions/cmd/audit/FactionLogs.java new file mode 100644 index 00000000..6746b488 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/cmd/audit/FactionLogs.java @@ -0,0 +1,106 @@ +package com.massivecraft.factions.cmd.audit; + +/** + * @author Saser + */ +import com.google.common.collect.Lists; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; + +import java.text.SimpleDateFormat; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +public class FactionLogs { + private Map> mostRecentLogs = new ConcurrentHashMap<>(); + public static transient SimpleDateFormat format = new SimpleDateFormat("MM/dd hh:mmaa"); + private static transient int MAX_LOG_SIZE = 60; + + public FactionLogs() { + } + + public void log(FLogType type, String... arguments) { + if (type.getRequiredArgs() > arguments.length) { + Bukkit.getLogger().info("INVALID ARGUMENT COUNT MET: " + type.getRequiredArgs() + " REQUIRED: "); + Thread.dumpStack(); + } else { + LinkedList logs = this.mostRecentLogs.computeIfAbsent(type, (lists) -> new LinkedList<>()); + logs.add(new FactionLog(System.currentTimeMillis(), Lists.newArrayList(arguments))); + int maxLog = type == FLogType.F_TNT ? 200 : 60; + if (logs.size() > maxLog) { + logs.pop(); + } + + } + } + + public boolean isEmpty() { + return this.mostRecentLogs.isEmpty(); + } + + public void checkExpired() { + long duration = TimeUnit.DAYS.toMillis(7L); + List toRemove = Lists.newArrayList(); + mostRecentLogs.forEach((logType, logs) -> { + if (logs == null) { + toRemove.add(logType); + } else if (logType != FLogType.F_TNT) { + Iterator iter = logs.iterator(); + while (iter.hasNext()) { + try { + FactionLog log = (FactionLog) iter.next(); + if (log == null || log.isExpired(duration)) { + iter.remove(); + } + } catch (Exception e) { + Bukkit.getLogger().info("ERROR TRYING TO GET next FACTION LOG: " + e.getMessage()); + try { + iter.remove(); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + } + if (logs.size() <= 0) + toRemove.add(logType); + } + }); + toRemove.forEach((rem) -> { + LinkedList linkedList = this.mostRecentLogs.remove(rem); + }); + } + + public Map> getMostRecentLogs() { + return this.mostRecentLogs; + } + + public class FactionLog { + private long t; + private List a; + + public FactionLog(long t, List a) { + this.t = t; + this.a = a; + } + + public boolean isExpired(long duration) { + return System.currentTimeMillis() - this.t >= duration; + } + + public String getLogLine(FLogType type, boolean timestamp) { + String[] args = this.a.toArray(new String[0]); + String timeFormat = ""; + if (timestamp) { + timeFormat = FactionLogs.format.format(this.t); + if (timeFormat.startsWith("0")) { + timeFormat = timeFormat.substring(1); + } + } + return String.format(ChatColor.translateAlternateColorCodes('&', type.getMsg()), (String[])args) + (timestamp ? ChatColor.GRAY + " - " + timeFormat : ""); + } + } +} diff --git a/src/main/java/com/massivecraft/factions/cmd/audit/LogTimer.java b/src/main/java/com/massivecraft/factions/cmd/audit/LogTimer.java new file mode 100644 index 00000000..0a824ea2 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/cmd/audit/LogTimer.java @@ -0,0 +1,126 @@ +package com.massivecraft.factions.cmd.audit; + +/** + * @author Saser + */ +import com.massivecraft.factions.Faction; +import com.massivecraft.factions.FactionsPlugin; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.entity.EntityType; +import org.bukkit.material.MaterialData; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +public class LogTimer extends ConcurrentHashMap> { + private String factionId; + private String username; + + public LogTimer(String username, String factionId) { + this.username = username; + this.factionId = factionId; + } + + public Map getCurrentTimersOrCreate(LogTimer.TimerType type) { + return this.computeIfAbsent(type, (m) -> new ConcurrentHashMap<>()); + } + + public LogTimer.Timer attemptLog(LogTimer.TimerType type, LogTimer.TimerSubType subType, long increment) { + return this.getCurrentTimersOrCreate(type).computeIfAbsent(subType, (e) -> new Timer(System.currentTimeMillis(), 0L, null)).increment(increment); + } + + public void pushLogs(Faction faction, LogTimer.TimerType type) { + StringBuilder soldString = new StringBuilder(); + forEach((timerType, map) -> { + if (timerType == type) { + if (timerType == LogTimer.TimerType.SPAWNER_EDIT) { + map.forEach((subTimer, timer) -> { + Map entityCounts = new HashMap<>(); + Map currentCounts = (Map) timer.getExtraData(); + if (currentCounts != null) { + currentCounts.forEach((data, ints) -> { + EntityType types = EntityType.fromId(data.getData()); + if (types == null) { + Bukkit.getLogger().info("Unable to find EntityType for " + data.getData() + " for " + subTimer + " for fac " + this.factionId + "!"); + } else { + entityCounts.computeIfAbsent(types, (e) -> new AtomicInteger(0)).addAndGet(ints.get()); + } + }); + entityCounts.forEach((entityType, count) -> FactionsPlugin.instance.getFlogManager().log(faction, FLogType.SPAWNER_EDIT, this.username, subTimer == TimerSubType.SPAWNER_BREAK ? "broke" : "placed", count.get() + "x", StringUtils.capitaliseAllWords(entityType.name().toLowerCase().replace("_", " ")))); + } + }); + } + } + }); + this.remove(type); + } + + public String getFactionId() { + return this.factionId; + } + + public String getUsername() { + return this.username; + } + + public class Timer { + private long startTime; + private long count; + private Object extraData; + + LogTimer.Timer increment(long amount) { + this.count += amount; + return this; + } + + public boolean isReadyToLog(long expiration) { + return System.currentTimeMillis() - this.startTime >= expiration; + } + + public Timer(long startTime, long count, Object extraData) { + this.startTime = startTime; + this.count = count; + this.extraData = extraData; + } + + public long getStartTime() { + return this.startTime; + } + + public long getCount() { + return this.count; + } + + public Object getExtraData() { + return this.extraData; + } + + public void setStartTime(long startTime) { + this.startTime = startTime; + } + + public void setCount(long count) { + this.count = count; + } + + public void setExtraData(Object extraData) { + this.extraData = extraData; + } + } + + public enum TimerSubType { + SPAWNER_BREAK, + SPAWNER_PLACE; + TimerSubType() { + } + } + + public enum TimerType { + SPAWNER_EDIT; + TimerType() { + } + } +} diff --git a/src/main/java/com/massivecraft/factions/cmd/claim/CmdAutoClaim.java b/src/main/java/com/massivecraft/factions/cmd/claim/CmdAutoClaim.java index cad94b41..7e562968 100644 --- a/src/main/java/com/massivecraft/factions/cmd/claim/CmdAutoClaim.java +++ b/src/main/java/com/massivecraft/factions/cmd/claim/CmdAutoClaim.java @@ -1,11 +1,15 @@ package com.massivecraft.factions.cmd.claim; +import com.massivecraft.factions.FLocation; import com.massivecraft.factions.Faction; +import com.massivecraft.factions.FactionsPlugin; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Role; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.zcore.fperms.Access; import com.massivecraft.factions.zcore.fperms.PermissableAction; import com.massivecraft.factions.zcore.util.TL; @@ -59,7 +63,7 @@ public class CmdAutoClaim extends FCommand { } context.fPlayer.setAutoClaimFor(forFaction); - + FactionsPlugin.instance.logFactionEvent(forFaction, FLogType.CHUNK_CLAIMS, context.fPlayer.getName(), CC.GreenB + "CLAIMED", "1", new FLocation(context.fPlayer.getPlayer().getLocation()).formatXAndZ(",")); context.msg(TL.COMMAND_AUTOCLAIM_ENABLED, forFaction.describeTo(context.fPlayer)); context.fPlayer.attemptClaim(forFaction, context.fPlayer.getPlayer().getLocation(), true); } diff --git a/src/main/java/com/massivecraft/factions/cmd/claim/CmdClaim.java b/src/main/java/com/massivecraft/factions/cmd/claim/CmdClaim.java index 30334844..be0115c3 100644 --- a/src/main/java/com/massivecraft/factions/cmd/claim/CmdClaim.java +++ b/src/main/java/com/massivecraft/factions/cmd/claim/CmdClaim.java @@ -3,11 +3,14 @@ package com.massivecraft.factions.cmd.claim; import com.massivecraft.factions.Conf; import com.massivecraft.factions.FLocation; import com.massivecraft.factions.Faction; +import com.massivecraft.factions.FactionsPlugin; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Role; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.util.SpiralTask; import com.massivecraft.factions.zcore.fperms.Access; import com.massivecraft.factions.zcore.fperms.PermissableAction; @@ -73,6 +76,7 @@ public class CmdClaim extends FCommand { boolean success = context.fPlayer.attemptClaim(forFaction, this.currentLocation(), true); if (success) { failCount = 0; + FactionsPlugin.instance.logFactionEvent(forFaction, FLogType.CHUNK_CLAIMS, context.fPlayer.getName(), CC.GreenB + "CLAIMED", "1", (new FLocation(context.fPlayer.getPlayer().getLocation())).formatXAndZ(",")); } else if (failCount++ >= limit) { this.stop(); return false; diff --git a/src/main/java/com/massivecraft/factions/cmd/claim/CmdClaimLine.java b/src/main/java/com/massivecraft/factions/cmd/claim/CmdClaimLine.java index daefe0fc..1968808e 100644 --- a/src/main/java/com/massivecraft/factions/cmd/claim/CmdClaimLine.java +++ b/src/main/java/com/massivecraft/factions/cmd/claim/CmdClaimLine.java @@ -1,11 +1,15 @@ package com.massivecraft.factions.cmd.claim; import com.massivecraft.factions.Conf; +import com.massivecraft.factions.FLocation; import com.massivecraft.factions.Faction; +import com.massivecraft.factions.FactionsPlugin; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.struct.Permission; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.zcore.fperms.Access; import com.massivecraft.factions.zcore.fperms.PermissableAction; import com.massivecraft.factions.zcore.util.TL; @@ -83,8 +87,9 @@ public class CmdClaimLine extends FCommand { for (int i = 0; i < amount; i++) { context.fPlayer.attemptClaim(forFaction, location, true); location = location.add(blockFace.getModX() * 16, 0, blockFace.getModZ() * 16); + FactionsPlugin.instance.logFactionEvent(forFaction, FLogType.CHUNK_CLAIMS, context.fPlayer.getName(), CC.GreenB + "CLAIMED", String.valueOf(i), new FLocation(context.player.getLocation()).formatXAndZ(",")); } - } +} @Override public TL getUsageTranslation() { diff --git a/src/main/java/com/massivecraft/factions/cmd/claim/CmdUnclaim.java b/src/main/java/com/massivecraft/factions/cmd/claim/CmdUnclaim.java index 29f7c06e..9c922f08 100644 --- a/src/main/java/com/massivecraft/factions/cmd/claim/CmdUnclaim.java +++ b/src/main/java/com/massivecraft/factions/cmd/claim/CmdUnclaim.java @@ -4,10 +4,12 @@ import com.massivecraft.factions.*; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.event.LandUnclaimEvent; import com.massivecraft.factions.integration.Econ; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Role; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.util.SpiralTask; import com.massivecraft.factions.zcore.fperms.Access; import com.massivecraft.factions.zcore.fperms.PermissableAction; @@ -126,6 +128,7 @@ public class CmdUnclaim extends FCommand { } Board.getInstance().removeAt(target); + FactionsPlugin.instance.logFactionEvent(targetFaction, FLogType.CHUNK_CLAIMS, context.fPlayer.getName(), CC.RedB + "UNCLAIMED", "1", (new FLocation(context.fPlayer.getPlayer().getLocation())).formatXAndZ(",")); targetFaction.msg(TL.COMMAND_UNCLAIM_UNCLAIMED, context.fPlayer.describeTo(targetFaction, true)); context.msg(TL.COMMAND_UNCLAIM_UNCLAIMS); @@ -180,6 +183,7 @@ public class CmdUnclaim extends FCommand { Board.getInstance().removeAt(target); context.faction.msg(TL.COMMAND_UNCLAIM_FACTIONUNCLAIMED, context.fPlayer.describeTo(context.faction, true)); + FactionsPlugin.instance.logFactionEvent(targetFaction, FLogType.CHUNK_CLAIMS, context.fPlayer.getName(), CC.RedB + "UNCLAIMED", "1", (new FLocation(context.fPlayer.getPlayer().getLocation())).formatXAndZ(",")); if (Conf.logLandUnclaims) { FactionsPlugin.getInstance().log(TL.COMMAND_UNCLAIM_LOG.format(context.fPlayer.getName(), target.getCoordString(), targetFaction.getTag())); diff --git a/src/main/java/com/massivecraft/factions/cmd/claim/CmdUnclaimall.java b/src/main/java/com/massivecraft/factions/cmd/claim/CmdUnclaimall.java index 0c0dd287..c1274ead 100644 --- a/src/main/java/com/massivecraft/factions/cmd/claim/CmdUnclaimall.java +++ b/src/main/java/com/massivecraft/factions/cmd/claim/CmdUnclaimall.java @@ -1,15 +1,14 @@ package com.massivecraft.factions.cmd.claim; -import com.massivecraft.factions.Board; -import com.massivecraft.factions.Conf; -import com.massivecraft.factions.Faction; -import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.*; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.event.LandUnclaimAllEvent; import com.massivecraft.factions.integration.Econ; import com.massivecraft.factions.struct.Permission; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.zcore.fperms.PermissableAction; import com.massivecraft.factions.zcore.util.TL; import org.bukkit.Bukkit; @@ -73,9 +72,12 @@ public class CmdUnclaimall extends FCommand { if (unclaimAllEvent.isCancelled()) { return; } + int unclaimed = target.getAllClaims().size(); + Board.getInstance().unclaimAll(target.getId()); context.faction.msg(TL.COMMAND_UNCLAIMALL_UNCLAIMED, context.fPlayer.describeTo(context.faction, true)); + FactionsPlugin.instance.logFactionEvent(context.faction, FLogType.CHUNK_CLAIMS, context.fPlayer.getName(), CC.RedB + "UNCLAIMED", String.valueOf(unclaimed), new FLocation(context.fPlayer.getPlayer().getLocation()).formatXAndZ(",")); if (Conf.logLandUnclaims) { FactionsPlugin.getInstance().log(TL.COMMAND_UNCLAIMALL_LOG.format(context.fPlayer.getName(), context.faction.getTag())); diff --git a/src/main/java/com/massivecraft/factions/cmd/econ/CmdMoneyDeposit.java b/src/main/java/com/massivecraft/factions/cmd/econ/CmdMoneyDeposit.java index c038f574..da445979 100644 --- a/src/main/java/com/massivecraft/factions/cmd/econ/CmdMoneyDeposit.java +++ b/src/main/java/com/massivecraft/factions/cmd/econ/CmdMoneyDeposit.java @@ -5,6 +5,7 @@ import com.massivecraft.factions.FactionsPlugin; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.iface.EconomyParticipator; import com.massivecraft.factions.integration.Econ; import com.massivecraft.factions.struct.Permission; @@ -42,6 +43,8 @@ public class CmdMoneyDeposit extends FCommand { if (success && Conf.logMoneyTransactions) { FactionsPlugin.getInstance().log(ChatColor.stripColor(FactionsPlugin.getInstance().txt.parse(TL.COMMAND_MONEYDEPOSIT_DEPOSITED.toString(), context.fPlayer.getName(), Econ.moneyString(amount), faction.describeTo(null)))); + FactionsPlugin.instance.logFactionEvent(context.faction, FLogType.BANK_EDIT, context.fPlayer.getName(), ChatColor.GREEN + ChatColor.BOLD.toString() + "DEPOSITED", amount + ""); + } } diff --git a/src/main/java/com/massivecraft/factions/cmd/econ/CmdMoneyWithdraw.java b/src/main/java/com/massivecraft/factions/cmd/econ/CmdMoneyWithdraw.java index ee55f1c9..ddedd8ab 100644 --- a/src/main/java/com/massivecraft/factions/cmd/econ/CmdMoneyWithdraw.java +++ b/src/main/java/com/massivecraft/factions/cmd/econ/CmdMoneyWithdraw.java @@ -1,14 +1,17 @@ package com.massivecraft.factions.cmd.econ; import com.massivecraft.factions.Conf; +import com.massivecraft.factions.Faction; import com.massivecraft.factions.FactionsPlugin; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.iface.EconomyParticipator; import com.massivecraft.factions.integration.Econ; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Role; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.zcore.fperms.Access; import com.massivecraft.factions.zcore.fperms.PermissableAction; import com.massivecraft.factions.zcore.util.TL; @@ -52,6 +55,7 @@ public class CmdMoneyWithdraw extends FCommand { if (success && Conf.logMoneyTransactions) { FactionsPlugin.getInstance().log(ChatColor.stripColor(FactionsPlugin.getInstance().txt.parse(TL.COMMAND_MONEYWITHDRAW_WITHDRAW.toString(), context.fPlayer.getName(), Econ.moneyString(amount), faction.describeTo(null)))); + FactionsPlugin.instance.logFactionEvent((Faction) faction, FLogType.BANK_EDIT, context.fPlayer.getName(), CC.RedB + "WITHDREW", amount + ""); } } diff --git a/src/main/java/com/massivecraft/factions/cmd/relational/FRelationCommand.java b/src/main/java/com/massivecraft/factions/cmd/relational/FRelationCommand.java index 1ce0eff1..44599096 100644 --- a/src/main/java/com/massivecraft/factions/cmd/relational/FRelationCommand.java +++ b/src/main/java/com/massivecraft/factions/cmd/relational/FRelationCommand.java @@ -6,6 +6,7 @@ import com.massivecraft.factions.FactionsPlugin; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.event.FactionRelationEvent; import com.massivecraft.factions.event.FactionRelationWishEvent; import com.massivecraft.factions.scoreboards.FTeamWrapper; @@ -83,6 +84,8 @@ public abstract class FRelationCommand extends FCommand { // trigger the faction relation event FactionRelationEvent relationEvent = new FactionRelationEvent(context.faction, them, oldRelation, currentRelation); Bukkit.getServer().getPluginManager().callEvent(relationEvent); + FactionsPlugin.instance.logFactionEvent(context.faction, FLogType.RELATION_CHANGE,context.fPlayer.getName(), this.targetRelation.getColor() + this.targetRelation.name(), oldRelation.getColor() + them.getTag()); + FactionsPlugin.instance.logFactionEvent(them, FLogType.RELATION_CHANGE, oldRelation.getColor() + context.fPlayer.getName(), this.targetRelation.getColor() + this.targetRelation.name(), "your faction"); them.msg(TL.COMMAND_RELATIONS_MUTUAL, currentRelationColor + targetRelation.getTranslation(), currentRelationColor + context.faction.getTag()); context.faction.msg(TL.COMMAND_RELATIONS_MUTUAL, currentRelationColor + targetRelation.getTranslation(), currentRelationColor + them.getTag()); diff --git a/src/main/java/com/massivecraft/factions/cmd/roles/FPromoteCommand.java b/src/main/java/com/massivecraft/factions/cmd/roles/FPromoteCommand.java index 4bb85237..7d82d9e6 100644 --- a/src/main/java/com/massivecraft/factions/cmd/roles/FPromoteCommand.java +++ b/src/main/java/com/massivecraft/factions/cmd/roles/FPromoteCommand.java @@ -1,9 +1,11 @@ package com.massivecraft.factions.cmd.roles; import com.massivecraft.factions.FPlayer; +import com.massivecraft.factions.FactionsPlugin; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Role; import com.massivecraft.factions.zcore.fperms.PermissableAction; @@ -82,6 +84,8 @@ public class FPromoteCommand extends FCommand { } context.msg(TL.COMMAND_PROMOTE_SUCCESS, action, target.getName(), promotion.nicename); + FactionsPlugin.instance.getFlogManager().log(context.faction, FLogType.ROLE_PERM_EDIT, context.fPlayer.getName(), action, target.getName(), promotion.nicename); + } @Override diff --git a/src/main/java/com/massivecraft/factions/cmd/tnt/CmdTnt.java b/src/main/java/com/massivecraft/factions/cmd/tnt/CmdTnt.java index 3f6c6418..3b0ae067 100644 --- a/src/main/java/com/massivecraft/factions/cmd/tnt/CmdTnt.java +++ b/src/main/java/com/massivecraft/factions/cmd/tnt/CmdTnt.java @@ -4,6 +4,7 @@ import com.massivecraft.factions.FactionsPlugin; import com.massivecraft.factions.cmd.CommandContext; import com.massivecraft.factions.cmd.CommandRequirements; import com.massivecraft.factions.cmd.FCommand; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.util.XMaterial; import com.massivecraft.factions.zcore.fperms.PermissableAction; @@ -76,6 +77,7 @@ public class CmdTnt extends FCommand { context.faction.addTnt(amount); context.msg(TL.COMMAND_TNT_DEPOSIT_SUCCESS); + FactionsPlugin.instance.getFlogManager().log(context.faction, FLogType.F_TNT, context.fPlayer.getName(), "DEPOSITED", amount + "x TNT"); context.fPlayer.sendMessage(FactionsPlugin.instance.color(TL.COMMAND_TNT_AMOUNT.toString().replace("{amount}", context.faction.getTnt() + "").replace("{maxAmount}", context.faction.getTntBankLimit() + ""))); return; @@ -113,6 +115,7 @@ public class CmdTnt extends FCommand { context.faction.takeTnt(amount); context.player.updateInventory(); context.msg(TL.COMMAND_TNT_WIDTHDRAW_SUCCESS); + FactionsPlugin.instance.getFlogManager().log(context.faction, FLogType.F_TNT, context.fPlayer.getName(), "WITHDREW", amount + "x TNT"); } } else if (context.args.size() == 1) { if (context.args.get(0).equalsIgnoreCase("addall")) { @@ -136,6 +139,8 @@ public class CmdTnt extends FCommand { context.player.updateInventory(); context.faction.addTnt(invTnt); context.msg(TL.COMMAND_TNT_DEPOSIT_SUCCESS); + FactionsPlugin.instance.getFlogManager().log(context.faction, FLogType.F_TNT, context.fPlayer.getName(), "DEPOSITED", invTnt + "x TNT"); + context.fPlayer.sendMessage(FactionsPlugin.instance.color(TL.COMMAND_TNT_AMOUNT.toString().replace("{amount}", context.faction.getTnt() + "").replace("{maxAmount}", context.faction.getTntBankLimit() + ""))); return; diff --git a/src/main/java/com/massivecraft/factions/listeners/FactionsBlockListener.java b/src/main/java/com/massivecraft/factions/listeners/FactionsBlockListener.java index 170e3e3c..934f5926 100644 --- a/src/main/java/com/massivecraft/factions/listeners/FactionsBlockListener.java +++ b/src/main/java/com/massivecraft/factions/listeners/FactionsBlockListener.java @@ -1,6 +1,8 @@ package com.massivecraft.factions.listeners; import com.massivecraft.factions.*; +import com.massivecraft.factions.cmd.audit.FLogManager; +import com.massivecraft.factions.cmd.audit.LogTimer; import com.massivecraft.factions.integration.Worldguard; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Relation; @@ -15,6 +17,8 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -29,17 +33,23 @@ import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.hanging.HangingBreakByEntityEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.material.MaterialData; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; public class FactionsBlockListener implements Listener { public static HashMap bannerLocations = new HashMap<>(); private HashMap bannerCooldownMap = new HashMap<>(); + private long placeTimer = TimeUnit.SECONDS.toMillis(15L); + public static boolean playerCanBuildDestroyBlock(Player player, Location location, String action, boolean justCheck) { if (Conf.playersWhoBypassAllProtection.contains(player.getName())) return true; @@ -120,8 +130,39 @@ public class FactionsBlockListener implements Listener { return CheckPlayerAccess(me.getPlayer(), me, location, target, target.getAccess(me, action), action, pain); } + public void handleSpawnerUpdate(Faction at, Player player, ItemStack spawnerItem, LogTimer.TimerSubType subType) { + FLogManager manager = FactionsPlugin.instance.getFlogManager(); + LogTimer logTimer = manager.getLogTimers().computeIfAbsent(player.getUniqueId(), e -> new LogTimer(player.getName(), at.getId())); + LogTimer.Timer timer = logTimer.attemptLog(LogTimer.TimerType.SPAWNER_EDIT, subType, 0L); + Map currentCounts = (timer.getExtraData() == null) ? new HashMap<>() : ((Map) timer.getExtraData()); + currentCounts.computeIfAbsent(spawnerItem.getData(), e -> new AtomicInteger(0)).addAndGet(1); + timer.setExtraData(currentCounts); + if (timer.isReadyToLog(this.placeTimer)) { + logTimer.pushLogs(at, LogTimer.TimerType.SPAWNER_EDIT); + } + } + + @EventHandler( + priority = EventPriority.HIGH, + ignoreCancelled = true + ) + public void onPlayerPlace(BlockPlaceEvent event) { + ItemStack item = event.getItemInHand(); + if (item != null && item.getType() == XMaterial.SPAWNER.parseMaterial()) { + Faction at = Board.getInstance().getFactionAt(new FLocation(event.getBlockPlaced())); + if (at != null && at.isNormal()) { + FPlayer fplayer = FPlayers.getInstance().getByPlayer(event.getPlayer()); + if (fplayer != null && at.getRelationTo(fplayer.getFaction()).isAtLeast(Relation.TRUCE)) { + this.handleSpawnerUpdate(at, event.getPlayer(), item, LogTimer.TimerSubType.SPAWNER_PLACE); + } + } + } + } + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBlockPlace(BlockPlaceEvent event) { + Faction at = Board.getInstance().getFactionAt(new FLocation(event.getBlockPlaced())); + if (!event.canBuild()) return; if (event.getBlockPlaced().getType() == Material.FIRE) return; @@ -452,16 +493,26 @@ public class FactionsBlockListener implements Listener { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent event) { - FPlayer fme = FPlayers.getInstance().getByPlayer(event.getPlayer()); - if (!playerCanBuildDestroyBlock(event.getPlayer(), event.getBlock().getLocation(), "destroy", false)) { + Block block = event.getBlock(); + + Faction at = Board.getInstance().getFactionAt(new FLocation(block)); + boolean isSpawner = event.getBlock().getType() == XMaterial.SPAWNER.parseMaterial(); + if (!playerCanBuildDestroyBlock(event.getPlayer(), event.getBlock().getLocation(), !isSpawner ? "destroy" : "mine spawners", false)) { event.setCancelled(true); return; } - if (!fme.hasFaction()) return; - if (event.getBlock().getType() == XMaterial.SPAWNER.parseMaterial() && !fme.isAdminBypassing()) { - Access access = fme.getFaction().getAccess(fme, PermissableAction.SPAWNER); - if (access != Access.ALLOW && fme.getRole() != Role.LEADER) { - fme.msg(TL.GENERIC_FPERM_NOPERMISSION, "mine spawners"); + if (block != null && isSpawner) { + ItemStack item = new ItemStack(block.getType(), 1, (short) block.getData()); + if (at != null && at.isNormal()) { + FPlayer fplayer = FPlayers.getInstance().getByPlayer(event.getPlayer()); + if (fplayer != null) { + BlockState state = block.getState(); + if (state instanceof CreatureSpawner) { + CreatureSpawner spawner = (CreatureSpawner) state; + item.setDurability(spawner.getSpawnedType().getTypeId()); + } + handleSpawnerUpdate(at, event.getPlayer(), item, LogTimer.TimerSubType.SPAWNER_BREAK); + } } } } diff --git a/src/main/java/com/massivecraft/factions/listeners/FactionsPlayerListener.java b/src/main/java/com/massivecraft/factions/listeners/FactionsPlayerListener.java index f54b4553..f3c95f3e 100644 --- a/src/main/java/com/massivecraft/factions/listeners/FactionsPlayerListener.java +++ b/src/main/java/com/massivecraft/factions/listeners/FactionsPlayerListener.java @@ -4,6 +4,7 @@ import com.massivecraft.factions.*; import com.massivecraft.factions.cmd.CmdFGlobal; import com.massivecraft.factions.cmd.CmdFly; import com.massivecraft.factions.cmd.CmdSeeChunk; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.cmd.logout.LogoutHandler; import com.massivecraft.factions.cmd.wild.CmdWild; import com.massivecraft.factions.discord.Discord; @@ -17,6 +18,7 @@ import com.massivecraft.factions.struct.ChatMode; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Relation; import com.massivecraft.factions.struct.Role; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.util.FactionGUI; import com.massivecraft.factions.util.VisualizeUtil; import com.massivecraft.factions.util.XMaterial; @@ -745,6 +747,7 @@ public class FactionsPlayerListener implements Listener { if (me.getAutoClaimFor() != null) { me.attemptClaim(me.getAutoClaimFor(), newLocation, true); + FactionsPlugin.instance.logFactionEvent(me.getAutoClaimFor(), FLogType.CHUNK_CLAIMS, me.getName(), CC.GreenB + "CLAIMED", String.valueOf(1), (new FLocation(player.getLocation())).formatXAndZ(",")); if (Conf.disableFlightOnFactionClaimChange) CmdFly.disableFlight(me); } else if (me.isAutoSafeClaimEnabled()) { if (!Permission.MANAGE_SAFE_ZONE.has(player)) { diff --git a/src/main/java/com/massivecraft/factions/listeners/MenuListener.java b/src/main/java/com/massivecraft/factions/listeners/MenuListener.java new file mode 100644 index 00000000..982b36cc --- /dev/null +++ b/src/main/java/com/massivecraft/factions/listeners/MenuListener.java @@ -0,0 +1,64 @@ +package com.massivecraft.factions.listeners; + +import com.massivecraft.factions.util.serializable.ClickableItemStack; +import com.massivecraft.factions.util.serializable.GUIMenu; +import com.sk89q.worldedit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.ItemStack; + +/** + * @author Saser + */ +public class MenuListener implements Listener { + + public MenuListener() { + } + + @EventHandler + public void onInventoryClick(InventoryClickEvent event) { + if (event.getView().getTitle().equals("Faction Logs")) { + event.setCancelled(true); + } + + Player player = (Player)event.getWhoClicked(); + GUIMenu menu = GUIMenu.getMenus().get(player.getUniqueId()); + if (menu != null) { + event.setCancelled(true); + if (!menu.getName().equals(event.getView().getTitle())) { + event.getView().close(); + return; + } + + ItemStack item = event.getCurrentItem(); + if (item == null) return; + if (event.getRawSlot() >= event.getInventory().getSize()) return; + ClickableItemStack found = menu.getMenuItems().get(event.getRawSlot()); + if (found != null && found.getType() == item.getType() && found.getDurability() == item.getDurability()) { + if (found.getItemCallback() == null) { + return; + } + found.getItemCallback().accept(event); + } + } + } + + @EventHandler + public void onInventoryClose(InventoryCloseEvent event) { + GUIMenu menu = GUIMenu.getMenus().remove(event.getPlayer().getUniqueId()); + if (menu != null && menu.getCloseCallback() != null) { + menu.getCloseCallback().accept(event); + } + } + + @EventHandler + public void onPLayerLeave(PlayerQuitEvent event) { + GUIMenu menu = GUIMenu.getMenus().remove(event.getPlayer().getUniqueId()); + if (menu != null && menu.getCloseCallback() != null) { + menu.getCloseCallback().accept(new InventoryCloseEvent(event.getPlayer().getOpenInventory())); + } + } +} diff --git a/src/main/java/com/massivecraft/factions/struct/Permission.java b/src/main/java/com/massivecraft/factions/struct/Permission.java index 690c4ec1..2b94e19d 100755 --- a/src/main/java/com/massivecraft/factions/struct/Permission.java +++ b/src/main/java/com/massivecraft/factions/struct/Permission.java @@ -18,6 +18,7 @@ public enum Permission { ADMIN_ANY("admin.any"), AHOME("ahome"), ANNOUNCE("announce"), + AUDIT("audit"), AUTOCLAIM("autoclaim"), AUTO_LEAVE_BYPASS("autoleavebypass"), BAN("ban"), diff --git a/src/main/java/com/massivecraft/factions/util/CC.java b/src/main/java/com/massivecraft/factions/util/CC.java new file mode 100644 index 00000000..c6f17e58 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/util/CC.java @@ -0,0 +1,95 @@ +package com.massivecraft.factions.util; + +/** + * @author Saser + */ +import org.bukkit.ChatColor; + +public class CC { + public static String Black = ChatColor.BLACK.toString(); + public static String BlackB = ChatColor.BLACK + ChatColor.BOLD.toString(); + public static String BlackI = ChatColor.BLACK + ChatColor.ITALIC.toString();; + public static String BlackU = ChatColor.BLACK + ChatColor.UNDERLINE.toString(); + public static String DarkBlue = ChatColor.DARK_BLUE.toString(); + public static String DarkBlueB = ChatColor.DARK_BLUE + ChatColor.BOLD.toString(); + public static String DarkBlueI = ChatColor.DARK_BLUE + ChatColor.ITALIC.toString(); + public static String DarkBlueU = ChatColor.DARK_BLUE + ChatColor.UNDERLINE.toString(); + public static String DarkGreen = ChatColor.DARK_GREEN.toString(); + public static String DarkGreenB = ChatColor.DARK_GREEN + ChatColor.BOLD.toString(); + public static String DarkGreenI = ChatColor.DARK_GREEN + ChatColor.ITALIC.toString(); + public static String DarkGreenU = ChatColor.DARK_GREEN + ChatColor.UNDERLINE.toString(); + public static String DarkAqua = ChatColor.DARK_AQUA.toString(); + public static String DarkAquaB = ChatColor.DARK_AQUA + ChatColor.BOLD.toString(); + public static String DarkAquaI = ChatColor.DARK_AQUA + ChatColor.ITALIC.toString(); + public static String DarkAquaU = ChatColor.DARK_AQUA + ChatColor.UNDERLINE.toString(); + public static String DarkRed = ChatColor.DARK_RED.toString(); + public static String DarkRedB = ChatColor.DARK_RED + ChatColor.BOLD.toString(); + public static String DarkRedI = ChatColor.DARK_RED + ChatColor.ITALIC.toString(); + public static String DarkRedU = ChatColor.DARK_RED + ChatColor.UNDERLINE.toString(); + public static String DarkPurple = ChatColor.DARK_PURPLE.toString(); + public static String DarkPurpleB = ChatColor.DARK_PURPLE + ChatColor.BOLD.toString(); + public static String DarkPurpleI = ChatColor.DARK_PURPLE + ChatColor.ITALIC.toString(); + public static String DarkPurpleU = ChatColor.DARK_PURPLE + ChatColor.UNDERLINE.toString(); + public static String Gold = ChatColor.GOLD.toString(); + public static String GoldB = ChatColor.GOLD + ChatColor.BOLD.toString(); + public static String GoldI = ChatColor.GOLD + ChatColor.ITALIC.toString(); + public static String GoldU = ChatColor.GOLD + ChatColor.UNDERLINE.toString(); + public static String Gray = ChatColor.GRAY.toString(); + public static String GrayB = ChatColor.GRAY + ChatColor.BOLD.toString(); + public static String GrayI = ChatColor.GRAY + ChatColor.ITALIC.toString(); + public static String GrayU = ChatColor.GRAY + ChatColor.UNDERLINE.toString(); + public static String DarkGray = ChatColor.DARK_GRAY.toString(); + public static String DarkGrayB = ChatColor.DARK_GRAY + ChatColor.BOLD.toString(); + public static String DarkGrayI = ChatColor.DARK_GRAY + ChatColor.ITALIC.toString(); + public static String DarkGrayU = ChatColor.DARK_GRAY + ChatColor.UNDERLINE.toString(); + public static String Blue = ChatColor.BLUE.toString(); + public static String BlueB = ChatColor.BLUE + ChatColor.BOLD.toString(); + public static String BlueI = ChatColor.BLUE + ChatColor.ITALIC.toString(); + public static String BlueU = ChatColor.BLUE + ChatColor.UNDERLINE.toString(); + public static String Green = ChatColor.GREEN.toString(); + public static String GreenB = ChatColor.GREEN + ChatColor.BOLD.toString(); + public static String GreenI = ChatColor.GREEN + ChatColor.ITALIC.toString(); + public static String GreenU = ChatColor.GREEN + ChatColor.UNDERLINE.toString(); + public static String Aqua = ChatColor.AQUA.toString(); + public static String AquaB = ChatColor.AQUA + ChatColor.BOLD.toString(); + public static String AquaI = ChatColor.AQUA + ChatColor.ITALIC.toString(); + public static String AquaU = ChatColor.AQUA + ChatColor.UNDERLINE.toString(); + public static String Red = ChatColor.RED.toString(); + public static String RedB = ChatColor.RED + ChatColor.BOLD.toString(); + public static String RedI = ChatColor.RED + ChatColor.ITALIC.toString(); + public static String RedU = ChatColor.RED + ChatColor.UNDERLINE.toString(); + public static String LightPurple = ChatColor.LIGHT_PURPLE.toString(); + public static String LightPurpleB = ChatColor.LIGHT_PURPLE + ChatColor.BOLD.toString(); + public static String LightPurpleI = ChatColor.LIGHT_PURPLE + ChatColor.ITALIC.toString(); + public static String LightPurpleU = ChatColor.LIGHT_PURPLE + ChatColor.UNDERLINE.toString(); + public static String Yellow = ChatColor.YELLOW.toString(); + public static String YellowB = ChatColor.YELLOW + ChatColor.BOLD.toString(); + public static String YellowI = ChatColor.YELLOW + ChatColor.ITALIC.toString(); + public static String YellowU = ChatColor.YELLOW + ChatColor.UNDERLINE.toString(); + public static String White = ChatColor.WHITE.toString(); + public static String WhiteB = ChatColor.WHITE + ChatColor.BOLD.toString(); + public static String WhiteI = ChatColor.WHITE + ChatColor.ITALIC.toString(); + public static String WhiteU = ChatColor.WHITE + ChatColor.UNDERLINE.toString(); + public static String Bold = ChatColor.BOLD.toString(); + public static String Strike = ChatColor.STRIKETHROUGH.toString(); + public static String Underline = ChatColor.UNDERLINE.toString(); + public static String Magic = ChatColor.MAGIC.toString(); + public static String Italic = ChatColor.ITALIC.toString(); + public static String Reset = ChatColor.RESET.toString(); + public static String Go = GreenB + " " + Green; + public static String Wait = YellowB + " " + Yellow; + public static String Stop = RedB + " " + Red; + + public static String prefix(char color) { + return translate("&" + color + "&l &" + color); + } + + public static String translate(String string) { + return ChatColor.translateAlternateColorCodes('&', string); + } + + public static String strip(String string) { + return ChatColor.stripColor(string); + } +} + diff --git a/src/main/java/com/massivecraft/factions/util/ClipPlaceholderAPIManager.java b/src/main/java/com/massivecraft/factions/util/ClipPlaceholderAPIManager.java index 7be48c12..3d43d5c4 100644 --- a/src/main/java/com/massivecraft/factions/util/ClipPlaceholderAPIManager.java +++ b/src/main/java/com/massivecraft/factions/util/ClipPlaceholderAPIManager.java @@ -116,17 +116,21 @@ public class ClipPlaceholderAPIManager extends PlaceholderExpansion implements R case "faction_description": return faction.getDescription(); case "faction_claims": - return String.valueOf(faction.getAllClaims().size()); + return fPlayer.hasFaction() ? String.valueOf(faction.getAllClaims().size()) : "0"; + case "faction_maxclaims": + return String.valueOf(Conf.claimedLandsMax); case "faction_founded": return TL.sdf.format(faction.getFoundedDate()); case "faction_joining": return (faction.getOpen() ? TL.COMMAND_SHOW_UNINVITED.toString() : TL.COMMAND_SHOW_INVITATION.toString()); + case "faction_strikes": + return fPlayer.hasFaction() ? String.valueOf(faction.getStrikes()) : "0"; case "faction_peaceful": return faction.isPeaceful() ? Conf.colorNeutral + TL.COMMAND_SHOW_PEACEFUL.toString() : ""; case "faction_tntbank_balance": return String.valueOf(faction.getTnt()); case "faction_points": - return String.valueOf(faction.getPoints()); + return fPlayer.hasFaction() ? String.valueOf(faction.getPoints()) : "0"; case "faction_powerboost": double powerBoost = faction.getPowerBoost(); return (powerBoost == 0.0) ? "" : (powerBoost > 0.0 ? TL.COMMAND_SHOW_BONUS.toString() : TL.COMMAND_SHOW_PENALTY.toString()) + powerBoost + ")"; diff --git a/src/main/java/com/massivecraft/factions/util/FactionWarpsFrame.java b/src/main/java/com/massivecraft/factions/util/FactionWarpsFrame.java index 1aa83f3f..8dbd8425 100644 --- a/src/main/java/com/massivecraft/factions/util/FactionWarpsFrame.java +++ b/src/main/java/com/massivecraft/factions/util/FactionWarpsFrame.java @@ -38,7 +38,11 @@ public class FactionWarpsFrame { GUIItems.add(new GuiItem(buildDummyItem(), e -> e.setCancelled(true))); slots.forEach(slot -> GUIItems.set(slot, new GuiItem(XMaterial.AIR.parseItem()))); for (final Map.Entry warp : fplayer.getFaction().getWarps().entrySet()) { - if (count > slots.size()) continue; + if (slots.size() < fplayer.getFaction().getWarps().entrySet().size()){ + slots.add(slots.get(slots.size()-1)+1); + FactionsPlugin.instance.log("Automatically setting F WARP GUI slot since slot not specified. Head config.yml and add more entries in warp-slots section."); + } + GUIItems.set(slots.get(count), new GuiItem(buildWarpAsset(warp, fplayer.getFaction()), e -> { e.setCancelled(true); fplayer.getPlayer().closeInventory(); diff --git a/src/main/java/com/massivecraft/factions/util/ItemUtil.java b/src/main/java/com/massivecraft/factions/util/ItemUtil.java new file mode 100644 index 00000000..1371e342 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/util/ItemUtil.java @@ -0,0 +1,51 @@ +package com.massivecraft.factions.util; + +/** + * @author Saser + */ +import com.massivecraft.factions.util.XMaterial; +import org.bukkit.Material; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; + +import java.util.HashMap; +import java.util.Map; + +public class ItemUtil { + private static Map cachedSkulls = new HashMap<>(); + + public ItemUtil() { + } + + public static int getItemCount(Inventory inventory) { + if (inventory == null) { + return 0; + } else { + int itemsFound = 0; + + for(int i = 0; i < inventory.getSize(); ++i) { + ItemStack item = inventory.getItem(i); + if (item != null && item.getType() != Material.AIR) { + ++itemsFound; + } + } + + return itemsFound; + } + } + + public static ItemStack createPlayerHead(String name) { + ItemStack skull = cachedSkulls.get(name); + if (skull != null) { + return skull.clone(); + } else { + skull = new ItemStack(XMaterial.PLAYER_HEAD.parseMaterial()); + SkullMeta sm = (SkullMeta)skull.getItemMeta(); + sm.setOwner(name); + skull.setItemMeta(sm); + cachedSkulls.put(name, skull.clone()); + return skull; + } + } +} diff --git a/src/main/java/com/massivecraft/factions/util/JSONUtils.java b/src/main/java/com/massivecraft/factions/util/JSONUtils.java new file mode 100644 index 00000000..d5c6e51f --- /dev/null +++ b/src/main/java/com/massivecraft/factions/util/JSONUtils.java @@ -0,0 +1,101 @@ +package com.massivecraft.factions.util; + +/** + * @author Saser + */ +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.bukkit.Bukkit; + +import java.io.*; +import java.lang.reflect.Type; + +public class JSONUtils { + public static Gson gson = (new GsonBuilder()).enableComplexMapKeySerialization().create(); + + public JSONUtils() { + } + + public static File getOrCreateFile(File parent, String string) throws IOException { + if (!parent.exists()) { + parent.mkdir(); + Bukkit.getLogger().info("Creating directory " + parent.getName()); + } + + File f = new File(parent, string); + if (!f.exists()) { + Bukkit.getLogger().info("Creating new file " + string + " due to it not existing!"); + f.createNewFile(); + } + return f; + } + + public static File getOrCreateFile(String fileName) throws IOException { + File f = new File(fileName); + if (!f.exists()) { + Bukkit.getLogger().info("Creating new file " + fileName + " due to it not existing!"); + f.createNewFile(); + } + return f; + } + + public static Object fromJson(String fileName, Object token) throws IOException { + File f = getOrCreateFile(fileName); + return fromJson(f, token); + } + + public static Object fromJson(File f, Object clazz) throws FileNotFoundException { + return gson.fromJson(new FileReader(f), getTypeFromObject(clazz)); + } + + public static Object fromJson(File f, Object clazz, Object defaultObj) throws FileNotFoundException { + Object retr = gson.fromJson(new FileReader(f), getTypeFromObject(clazz)); + return retr == null ? defaultObj : retr; + } + + public static Object fromJson(File f, Type token) throws FileNotFoundException { + return fromJson(f, token, gson); + } + + public static Object fromJson(File f, Type token, Gson gson) throws FileNotFoundException { + return gson.fromJson(new FileReader(f), token); + } + + public static String toJSON(Object object, Object token) { + return toJSON(object, token, gson); + } + + public static String toJSON(Object object, Object token, Gson gson) { + return gson.toJson(object, getTypeFromObject(token)); + } + + public static boolean saveJSONToFile(String fileName, Object toSave, Object token) throws IOException { + return saveJSONToFile(getOrCreateFile(fileName), toSave, token); + } + + public static boolean saveJSONToFile(File f, Object toSave, Object token, Gson gson) throws IOException { + String str = toJSON(toSave, token, gson); + FileWriter writer = new FileWriter(f); + writer.write(str); + writer.flush(); + writer.close(); + return true; + } + + public static boolean saveJSONToFile(File f, Object toSave, Object token) throws IOException { + try { + return saveJSONToFile(f, toSave, token, gson); + } catch (Throwable var4) { + throw var4; + } + } + + private static Type getTypeFromObject(Object object) { + return object instanceof Type ? (Type)object : getTypeFromClass(object.getClass()); + } + + private static Type getTypeFromClass(Class clazz) { + return TypeToken.of(clazz).getType(); + } +} diff --git a/src/main/java/com/massivecraft/factions/util/serializable/ClickableItemStack.java b/src/main/java/com/massivecraft/factions/util/serializable/ClickableItemStack.java new file mode 100644 index 00000000..d03ac1f3 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/util/serializable/ClickableItemStack.java @@ -0,0 +1,48 @@ +package com.massivecraft.factions.util.serializable; + +/** + * @author Saser + */ +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.List; +import java.util.function.Consumer; + +public class ClickableItemStack extends ItemStack { + private Consumer itemCallback; + + public ClickableItemStack(ItemStack clone) { + super(clone); + } + + public ClickableItemStack setClickCallback(Consumer callback) { + this.itemCallback = callback; + return this; + } + + public ClickableItemStack setDisplayName(String name) { + ItemMeta im = this.getItemMeta(); + im.setDisplayName(name); + this.setItemMeta(im); + return this; + } + + + public ClickableItemStack setLore(List lore) { + ItemMeta im = this.getItemMeta(); + im.setLore(lore); + this.setItemMeta(im); + return this; + } + + public ClickableItemStack setDura(short dura) { + this.setDurability(dura); + return this; + } + + public Consumer getItemCallback() { + return this.itemCallback; + } +} diff --git a/src/main/java/com/massivecraft/factions/util/serializable/GUIMenu.java b/src/main/java/com/massivecraft/factions/util/serializable/GUIMenu.java new file mode 100644 index 00000000..e661fc55 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/util/serializable/GUIMenu.java @@ -0,0 +1,156 @@ +package com.massivecraft.factions.util.serializable; + +/** + * @author Saser + */ +import com.google.common.collect.Lists; +import com.massivecraft.factions.FPlayer; +import com.massivecraft.factions.Faction; +import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.struct.Role; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.MaterialData; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +public abstract class GUIMenu { + protected Inventory menu; + private Map menuItems = new HashMap<>(); + private static Map menus = new HashMap<>(); + private Consumer closeCallback; + private String name; + private int size; + private GUIMenu previousMenu; + + public GUIMenu(String name, int size) { + if (name.length() > 32) { + name = name.substring(0, 32); + } + + this.name = name; + this.size = size; + this.menu = Bukkit.createInventory(null, size, name); + } + + public void setInventorySize(int size) { + if (this.size != size) { + int oldSize = this.size; + this.size = size; + List viewing = Lists.newArrayList(this.menu.getViewers()); + this.menu = Bukkit.createInventory(null, size, this.name); + viewing.forEach((pl) -> { + pl.closeInventory(); + pl.openInventory(this.menu); + menus.put(pl.getUniqueId(), this); + Bukkit.getLogger().info("Reopening Menu for " + pl.getName() + " due to menu changing size from " + oldSize + " -> " + size); + }); + } + } + + public GUIMenu setPreviousMenu(GUIMenu menu) { + this.previousMenu = menu; + return this; + } + + public void setItem(int slot, ClickableItemStack item) { + this.menu.setItem(slot, item); + this.menuItems.put(slot, item); + } + + public abstract void drawItems(); + + private boolean canEditPermissions(Faction faction, FPlayer player) { + Role role = player.getRole(); + if (role != null && role.isAtLeast(Role.COLEADER)) { + Faction theirfac = player.getFaction(); + return theirfac != null && theirfac.isNormal() && theirfac.equals(faction); + } + + return false; + } + + public ClickableItemStack getBackButton(Material data, String name, String... lore) { + return (new ClickableItemStack(new ItemStack(data != null ? data : Material.RED_STAINED_GLASS_PANE, 1, data != null ? (short) 0 : 0 ))).setDisplayName(name != null ? name : ChatColor.RED + ChatColor.BOLD.toString() + "Back").setLore(lore != null ? Lists.newArrayList(lore) : Lists.newArrayList(ChatColor.GRAY + "Click to return to previous menu.")).setClickCallback((e) -> { + if (this.previousMenu != null) { + this.previousMenu.open((Player)e.getWhoClicked()); + } + + }); + } + + protected void clearItems() { + this.getMenuItems().clear(); + this.menu.clear(); + } + + public void open(Player player) { + GUIMenu openMenu = menus.get(player.getUniqueId()); + if (openMenu != null) { + player.closeInventory(); + Bukkit.getScheduler().scheduleSyncDelayedTask(FactionsPlugin.instance, () -> { + this.drawItems(); + player.openInventory(this.menu); + menus.put(player.getUniqueId(), this); + }, 1L); + } else { + this.drawItems(); + player.openInventory(this.menu); + menus.put(player.getUniqueId(), this); + } + + } + + public void fillEmpty(ClickableItemStack item) { + for(int i = 0; i < this.menu.getSize(); ++i) { + ItemStack is = this.menu.getItem(i); + if (is == null || is.getType() == Material.AIR) { + this.setItem(i, item); + } + } + + } + + public static int fitSlots(int size) { + return size <= 9 ? 9 : (size <= 18 ? 18 : (size <= 27 ? 27 : (size <= 36 ? 36 : (size <= 45 ? 45 : (size <= 54 ? 54 : 54))))); + } + + public Map getMenuItems() { + return this.menuItems; + } + + public static Map getMenus() { + return menus; + } + + public Consumer getCloseCallback() { + return this.closeCallback; + } + + public void setCloseCallback(Consumer closeCallback) { + this.closeCallback = closeCallback; + } + + public String getName() { + return this.name; + } + + public int getSize() { + return this.size; + } + + public GUIMenu getPreviousMenu() { + return this.previousMenu; + } +} diff --git a/src/main/java/com/massivecraft/factions/zcore/fperms/gui/PermissableActionFrame.java b/src/main/java/com/massivecraft/factions/zcore/fperms/gui/PermissableActionFrame.java index 5d3cab15..df3f3e40 100644 --- a/src/main/java/com/massivecraft/factions/zcore/fperms/gui/PermissableActionFrame.java +++ b/src/main/java/com/massivecraft/factions/zcore/fperms/gui/PermissableActionFrame.java @@ -6,11 +6,13 @@ import com.github.stefvanschie.inventoryframework.pane.PaginatedPane; import com.massivecraft.factions.FPlayer; import com.massivecraft.factions.Faction; import com.massivecraft.factions.FactionsPlugin; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.util.XMaterial; import com.massivecraft.factions.zcore.fperms.Access; import com.massivecraft.factions.zcore.fperms.Permissable; import com.massivecraft.factions.zcore.fperms.PermissableAction; import com.massivecraft.factions.zcore.util.TL; +import org.bukkit.ChatColor; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -51,10 +53,12 @@ public class PermissableActionFrame { case LEFT: access = Access.ALLOW; success = fplayer.getFaction().setPermission(perm, action, access); + FactionsPlugin.instance.logFactionEvent(fplayer.getFaction(), FLogType.PERM_EDIT_DEFAULTS,fplayer.getName(), ChatColor.GREEN.toString() + ChatColor.BOLD + "ALLOWED", action.getName(), perm.name()); break; case RIGHT: access = Access.DENY; success = fplayer.getFaction().setPermission(perm, action, access); + FactionsPlugin.instance.logFactionEvent(fplayer.getFaction(), FLogType.PERM_EDIT_DEFAULTS,fplayer.getName(), ChatColor.RED.toString() + ChatColor.BOLD + "DENIED", action.getName(), perm.name()); break; case MIDDLE: access = Access.UNDEFINED; 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 8bb049d2..fd074134 100644 --- a/src/main/java/com/massivecraft/factions/zcore/persist/MemoryFPlayer.java +++ b/src/main/java/com/massivecraft/factions/zcore/persist/MemoryFPlayer.java @@ -2,6 +2,7 @@ package com.massivecraft.factions.zcore.persist; import com.massivecraft.factions.*; import com.massivecraft.factions.cmd.CmdFly; +import com.massivecraft.factions.cmd.audit.FLogType; import com.massivecraft.factions.discord.Discord; import com.massivecraft.factions.event.*; import com.massivecraft.factions.event.FactionDisbandEvent.PlayerDisbandReason; @@ -16,6 +17,7 @@ import com.massivecraft.factions.struct.ChatMode; import com.massivecraft.factions.struct.Permission; import com.massivecraft.factions.struct.Relation; import com.massivecraft.factions.struct.Role; +import com.massivecraft.factions.util.CC; import com.massivecraft.factions.util.RelationUtil; import com.massivecraft.factions.util.WarmUpUtil; import com.massivecraft.factions.zcore.fperms.Access; @@ -840,6 +842,8 @@ public abstract class MemoryFPlayer implements FPlayer { } this.resetFactionData(); + FactionsPlugin.instance.logFactionEvent(myFaction, FLogType.INVITES, this.getName(), CC.Red + "left", "the faction"); + setFlying(false); if (myFaction.isNormal() && !perm && myFaction.getFPlayers().isEmpty()) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 3279db3e..1ad61717 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1294,7 +1294,7 @@ fbanners: - SPEED:2 BannerHolo: '&c{Faction}''s War Banner' Placeable: - Warzone: true + Warzone: false Enemy: true #Title when moving between chunks