From cee15b633300ea1b5c5c29a4efe95f5d552401ea Mon Sep 17 00:00:00 2001 From: Magnus Ulf Date: Fri, 21 Dec 2018 02:41:42 +0100 Subject: [PATCH] Custom ranks --- plugin.yml | 29 +- src/com/massivecraft/factions/Perm.java | 9 +- .../factions/cmd/CmdFactionsRank.java | 381 +----------------- .../factions/cmd/CmdFactionsRankEdit.java | 34 ++ .../cmd/CmdFactionsRankEditCreate.java | 65 +++ .../cmd/CmdFactionsRankEditDelete.java | 64 +++ .../factions/cmd/CmdFactionsRankEditName.java | 57 +++ .../cmd/CmdFactionsRankEditPrefix.java | 50 +++ .../cmd/CmdFactionsRankEditPriority.java | 71 ++++ .../factions/cmd/CmdFactionsRankList.java | 43 ++ .../factions/cmd/CmdFactionsRankSet.java | 341 ++++++++++++++++ .../factions/cmd/CmdFactionsRankShow.java | 56 +++ .../factions/cmd/type/TypeRank.java | 21 + .../massivecraft/factions/entity/Faction.java | 8 +- .../massivecraft/factions/entity/Rank.java | 59 +-- .../migrator/MigratorFaction002Ranks.java | 8 +- 16 files changed, 870 insertions(+), 426 deletions(-) create mode 100644 src/com/massivecraft/factions/cmd/CmdFactionsRankEdit.java create mode 100644 src/com/massivecraft/factions/cmd/CmdFactionsRankEditCreate.java create mode 100644 src/com/massivecraft/factions/cmd/CmdFactionsRankEditDelete.java create mode 100644 src/com/massivecraft/factions/cmd/CmdFactionsRankEditName.java create mode 100644 src/com/massivecraft/factions/cmd/CmdFactionsRankEditPrefix.java create mode 100644 src/com/massivecraft/factions/cmd/CmdFactionsRankEditPriority.java create mode 100644 src/com/massivecraft/factions/cmd/CmdFactionsRankList.java create mode 100644 src/com/massivecraft/factions/cmd/CmdFactionsRankSet.java create mode 100644 src/com/massivecraft/factions/cmd/CmdFactionsRankShow.java diff --git a/plugin.yml b/plugin.yml index 57ae179a..2b25965b 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,4 +1,5 @@ main: ${project.groupId}.${project.name} +main: ${project.groupId}.${project.name} name: ${project.name} version: ${project.version} website: ${project.url} @@ -65,7 +66,14 @@ permissions: factions.powerboost.set: {description: set powerboost, default: false} factions.rank: {description: manage/show ranks, default: false} factions.rank.show: {description: show rank, default: false} - factions.rank.action: {description: change rank, default: false} + factions.rank.set: {description: set rank, default: false} + factions.rank.list: {description: list ranks, default: false} + factions.rank.edit: {description: edit ranks, default: false} + factions.rank.edit.create: {description: create rank, default: false} + factions.rank.edit.name: {description: set rank name, default: false} + factions.rank.edit.prefix: {description: set rank prefix, default: false} + factions.rank.edit.priority: {description: set rank priority, default: false} + factions.rank.edit.delete: {description: delete rank, default: false} factions.relation: {description: manage faction relations, default: false} factions.relation.list: {description: list all factions with certain relation, default: false} factions.relation.set: {description: set relation wish to another faction, default: false} @@ -154,6 +162,16 @@ permissions: factions.powerboost.faction: true factions.powerboost.player: true factions.powerboost.set: true + factions.rank: true + factions.rank.show: true + factions.rank.set: true + factions.rank.list: true + factions.rank.edit: true + factions.rank.edit.create: true + factions.rank.edit.name: true + factions.rank.edit.prefix: true + factions.rank.edit.priority: true + factions.rank.edit.delete: true factions.promote: true factions.relation: true factions.relation.list: true @@ -267,7 +285,14 @@ permissions: factions.powerboost.player: true factions.rank: true factions.rank.show: true - factions.rank.action: true + factions.rank.set: true + factions.rank.list: true + factions.rank.edit: true + factions.rank.edit.create: true + factions.rank.edit.name: true + factions.rank.edit.prefix: true + factions.rank.edit.priority: true + factions.rank.edit.delete: true factions.relation: true factions.relation.list: true factions.relation.set: true diff --git a/src/com/massivecraft/factions/Perm.java b/src/com/massivecraft/factions/Perm.java index aa764bc4..2acc5b7e 100644 --- a/src/com/massivecraft/factions/Perm.java +++ b/src/com/massivecraft/factions/Perm.java @@ -65,7 +65,14 @@ public enum Perm implements Identified POWERBOOST_SET, RANK, RANK_SHOW, - RANK_ACTION, + RANK_SET, + RANK_LIST, + RANK_EDIT, + RANK_EDIT_CREATE, + RANK_EDIT_NAME, + RANK_EDIT_PREFIX, + RANK_EDIT_PRIORITY, + RANK_EDIT_DELETE, RELATION, RELATION_SET, RELATION_LIST, diff --git a/src/com/massivecraft/factions/cmd/CmdFactionsRank.java b/src/com/massivecraft/factions/cmd/CmdFactionsRank.java index 2605887e..9d466b3c 100644 --- a/src/com/massivecraft/factions/cmd/CmdFactionsRank.java +++ b/src/com/massivecraft/factions/cmd/CmdFactionsRank.java @@ -1,387 +1,14 @@ package com.massivecraft.factions.cmd; -import com.massivecraft.factions.Factions; -import com.massivecraft.factions.Perm; -import com.massivecraft.factions.cmd.type.TypeFaction; -import com.massivecraft.factions.cmd.type.TypeMPlayer; -import com.massivecraft.factions.cmd.type.TypeRank; -import com.massivecraft.factions.entity.Faction; -import com.massivecraft.factions.entity.MConf; -import com.massivecraft.factions.entity.MFlag; -import com.massivecraft.factions.entity.MPerm; -import com.massivecraft.factions.entity.MPlayer; -import com.massivecraft.factions.entity.MPlayerColl; -import com.massivecraft.factions.entity.Rank; -import com.massivecraft.factions.event.EventFactionsMembershipChange; -import com.massivecraft.factions.event.EventFactionsMembershipChange.MembershipChangeReason; -import com.massivecraft.factions.event.EventFactionsRankChange; -import com.massivecraft.massivecore.MassiveException; -import com.massivecraft.massivecore.util.Txt; - -import java.util.HashSet; -import java.util.Set; - public class CmdFactionsRank extends FactionsCommand { // -------------------------------------------- // // FIELDS // -------------------------------------------- // - // These fields are set upon perform() and unset afterwards. - - // Target - private Faction targetFaction = null; - private MPlayer target = null; - - // End faction (the faction they are changed to) - private Faction endFaction = null; - private boolean factionChange = false; - - // Ranks - private Rank senderRank = null; - private Rank targetRank = null; - private Rank rank = null; - - // -------------------------------------------- // - // CONSTRUCT - // -------------------------------------------- // - - public CmdFactionsRank() - { - // Parameters - this.addParameter(TypeMPlayer.get(), "player"); - this.addParameter(TypeRank.get(), "rank", "show"); - this.addParameter(TypeFaction.get(), "faction", "their"); - // Too complicated for that - this.setSwapping(false); - } - - // -------------------------------------------- // - // OVERRIDE - // -------------------------------------------- // - - @Override - public void perform() throws MassiveException - { - // This sets target and much other. - this.registerFields(); - - // Sometimes we just want to show the rank. - if ( ! this.argIsSet(1)) - { - if ( ! Perm.RANK_SHOW.has(sender, true)) return; - this.showRank(); - return; - } - - // Permission check. - if ( ! Perm.RANK_ACTION.has(sender, true)) return; - - // Is the player allowed or not. Method can be found later down. - this.ensureAllowed(); - - if (factionChange) - { - this.changeFaction(); - } - - // Does the change make sense. - this.ensureMakesSense(); - - // Event - EventFactionsRankChange event = new EventFactionsRankChange(sender, target, rank); - event.run(); - if (event.isCancelled()) return; - rank = event.getNewRank(); - - // Change the rank. - this.changeRank(); - } + public CmdFactionsRankSet cmdFactionsRankSet = new CmdFactionsRankSet(); + public CmdFactionsRankShow cmdFactionsRankShow = new CmdFactionsRankShow(); + public CmdFactionsRankList cmdFactionsRankList = new CmdFactionsRankList(); + public CmdFactionsRankEdit cmdFactionsRankEdit = new CmdFactionsRankEdit(); - // This is always run after performing a MassiveCommand. - @Override - public void senderFields(boolean set) - { - super.senderFields(set); - - if ( ! set) - { - this.unregisterFields(); - } - } - - // -------------------------------------------- // - // PRIVATE: REGISTER & UNREGISTER - // -------------------------------------------- // - - private void registerFields() throws MassiveException - { - // Getting the target and faction. - target = this.readArg(msender); - targetFaction = target.getFaction(); - - - // Ranks - senderRank = msender.getRank(); - targetRank = target.getRank(); - - endFaction = this.readArgAt(2, targetFaction); - factionChange = (endFaction != targetFaction); - - // Rank if any passed. - if (this.argIsSet(1)) - { - TypeRank typeRank = new TypeRank(endFaction); - rank = typeRank.read(this.argAt(1), sender); - } - - } - - private void unregisterFields() - { - targetFaction = null; - target = null; - - endFaction = null; - factionChange = false; - - senderRank = null; - targetRank = null; - rank = null; - } - - // -------------------------------------------- // - // PRIVATE: ENSURE - // -------------------------------------------- // - - private void ensureAllowed() throws MassiveException - { - // People with permission don't follow the normal rules. - if (msender.isOverriding()) return; - - // If somone gets the leadership of wilderness (Which has happened before). - // We can at least try to limit their powers. - if (endFaction.isNone()) - { - throw new MassiveException().addMsg("%s doesn't use ranks sorry :(", endFaction.getName()); - } - - if (target == msender) - { - // Don't change your own rank. - throw new MassiveException().addMsg("The target player mustn't be yourself."); - } - - if (factionChange) - { - // Don't change peoples faction - throw new MassiveException().addMsg("You can't change %s's faction.", target.describeTo(msender)); - } - - if (!MPerm.getPermRank().has(msender, targetFaction, false)) - { - throw new MassiveException().addMessage(MPerm.getPermRank().createDeniedMessage(msender, targetFaction)); - } - - // The following two if statements could be merged. - // But isn't for the sake of nicer error messages. - if (senderRank == targetRank) - { - // You can't change someones rank if it is equal to yours. - throw new MassiveException().addMsg("%s can't manage eachother.", senderRank.getName()+"s"); - } - - if (senderRank.isLessThan(targetRank)) - { - // You can't change someones rank if it is higher than yours. - throw new MassiveException().addMsg("You can't manage people of higher rank."); - } - - // The following two if statements could be merged. - // But isn't for the sake of nicer error messages. - if (senderRank == rank && !senderRank.isLeader()) - { - // You can't set ranks equal to your own. Unless you are the leader. - throw new MassiveException().addMsg("You can't set ranks equal to your own."); - } - - if (senderRank.isLessThan(rank)) - { - // You can't set ranks higher than your own. - throw new MassiveException().addMsg("You can't set ranks higher than your own."); - } - } - - private void ensureMakesSense() throws MassiveException - { - // Don't change their rank to something they already are. - if (target.getRank() == rank) - { - throw new MassiveException().addMsg("%s is already %s %s.", target.describeTo(msender), Txt.aan(rank.getName()), rank.getName()); - } - } - - // -------------------------------------------- // - // PRIVATE: SHOW - // -------------------------------------------- // - - private void showRank() - { - // Damn you grammar, causing all these checks. - String targetName = target.describeTo(msender, true); - String isAre = (target == msender) ? "are" : "is"; // "you are" or "he is" - - String theAan = (targetRank.isLeader()) ? "the" : Txt.aan(targetRank.getName()); // "a member", "an officer" or "the leader" - String rankName = targetRank.getName().toLowerCase(); - String ofIn = (targetRank.isLeader()) ? "of" : "in"; // "member in" or "leader of" - String factionName = targetFaction.describeTo(msender, true); - if (targetFaction == msenderFaction) - { - // Having the "Y" in "Your faction" being uppercase in the middle of a sentence makes no sense. - factionName = factionName.toLowerCase(); - } - if (targetFaction.isNone()) - { - // Wilderness aka none doesn't use ranks - msg("%s %s factionless", targetName, isAre); - } - else - { - // Derp is a member in Faction - msg("%s %s %s %s %s %s.", targetName, isAre, theAan, rankName, ofIn, factionName); - } - } - - // -------------------------------------------- // - // PRIVATE: CHANGE FACTION - // -------------------------------------------- // - - private void changeFaction() throws MassiveException - { - // Don't change a leader to a new faction. - if (targetRank.isLeader()) - { - throw new MassiveException().addMsg("You cannot remove the present leader. Demote them first."); - } - - // Event - EventFactionsMembershipChange membershipChangeEvent = new EventFactionsMembershipChange(sender, msender, endFaction, MembershipChangeReason.RANK); - membershipChangeEvent.run(); - if (membershipChangeEvent.isCancelled()) throw new MassiveException(); - - // Apply - target.resetFactionData(); - target.setFaction(endFaction); - - // No longer invited. - endFaction.uninvite(target); - - // Create recipients - Set recipients = new HashSet<>(); - recipients.addAll(targetFaction.getMPlayersWhereOnline(true)); - recipients.addAll(endFaction.getMPlayersWhereOnline(true)); - recipients.add(msender); - - // Send message - for (MPlayer recipient : recipients) - { - recipient.msg("%s was moved from %s to %s.", target.describeTo(recipient), targetFaction.describeTo(recipient), endFaction.describeTo(recipient)); - } - - // Derplog - if (MConf.get().logFactionJoin) - { - Factions.get().log(Txt.parse("%s moved %s from %s to %s.", msender.getName(), target.getName(), targetFaction.getName(), endFaction.getName())); - } - - // Now we don't need the old values. - targetFaction = target.getFaction(); - targetRank = target.getRank(); - senderRank = msender.getRank(); // In case they changed their own rank - - } - - // -------------------------------------------- // - // PRIVATE: CHANGE RANK - // -------------------------------------------- // - - private void changeRank() throws MassiveException - { - // In case of leadership change, we do special things not done in other rank changes. - if (rank.isLeader()) - { - this.changeRankLeader(); - } - else - { - this.changeRankOther(); - } - } - - private void changeRankLeader() - { - // If there is a current leader. Demote & inform them. - MPlayer targetFactionCurrentLeader = targetFaction.getLeader(); - if (targetFactionCurrentLeader != null) - { - // Inform & demote the old leader. - targetFactionCurrentLeader.setRank(rank.getRankBelow()); - if (targetFactionCurrentLeader != msender) - { - // They kinda know if they fired the command themself. - targetFactionCurrentLeader.msg("You have been demoted from the position of faction leader by %s.", msender.describeTo(targetFactionCurrentLeader, true)); - } - } - - // Promote the new leader. - target.setRank(rank); - - // Inform everyone, this includes sender and target. - for (MPlayer recipient : MPlayerColl.get().getAllOnline()) - { - String changerName = senderIsConsole ? "A server admin" : msender.describeTo(recipient); - recipient.msg("%s gave %s the leadership of %s.", changerName, target.describeTo(recipient), targetFaction.describeTo(recipient)); - } - } - - private void changeRankOther() throws MassiveException - { - // If the target is currently the leader and faction isn't permanent a new leader should be promoted. - // Sometimes a bug occurs and multiple leaders exist. Then we should be able to demote without promoting new leader - if (targetRank.isLeader() && ( ! MConf.get().permanentFactionsDisableLeaderPromotion || ! targetFaction.getFlag(MFlag.ID_PERMANENT)) && targetFaction.getMPlayersWhereRank(targetFaction.getLeaderRank()).size() == 1) - // This if statement is very long. Should I nest it for readability? - { - targetFaction.promoteNewLeader(); // This might disband the faction. - - // So if the faction disbanded... - if (targetFaction.detached()) - { - // ... we inform the sender. - target.resetFactionData(); - throw new MassiveException().addMsg("The target was a leader and got demoted. The faction disbanded and no rank was set."); - } - } - - // Create recipients - Set recipients = new HashSet<>(); - recipients.addAll(targetFaction.getMPlayers()); - recipients.add(msender); - - // Were they demoted or promoted? - String change = (rank.isLessThan(targetRank) ? "demoted" : "promoted"); - - // The rank will be set before the msg, so they have the appropriate prefix. - target.setRank(rank); - String oldRankName = targetRank.getName().toLowerCase(); - String rankName = rank.getName().toLowerCase(); - - // Send message - for(MPlayer recipient : recipients) - { - String targetName = target.describeTo(recipient, true); - String wasWere = (recipient == target) ? "were" : "was"; - recipient.msg("%s %s %s from %s to %s in %s.", targetName, wasWere, change, oldRankName, rankName, targetFaction.describeTo(msender)); - } - } - } diff --git a/src/com/massivecraft/factions/cmd/CmdFactionsRankEdit.java b/src/com/massivecraft/factions/cmd/CmdFactionsRankEdit.java new file mode 100644 index 00000000..3f12b6e6 --- /dev/null +++ b/src/com/massivecraft/factions/cmd/CmdFactionsRankEdit.java @@ -0,0 +1,34 @@ +package com.massivecraft.factions.cmd; + +import com.massivecraft.factions.entity.Faction; +import com.massivecraft.factions.entity.MPlayer; +import com.massivecraft.massivecore.MassiveException; + +public class CmdFactionsRankEdit extends FactionsCommand +{ + // -------------------------------------------- // + // FIELDS + // -------------------------------------------- // + + public CmdFactionsRankEditCreate cmdFactionsRankEditCreate = new CmdFactionsRankEditCreate(); + public CmdFactionsRankEditDelete cmdFactionsRankEditDelete = new CmdFactionsRankEditDelete(); + public CmdFactionsRankEditName cmdFactionsRankEditName = new CmdFactionsRankEditName(); + public CmdFactionsRankEditPrefix cmdFactionsRankEditPrefix = new CmdFactionsRankEditPrefix(); + public CmdFactionsRankEditPriority cmdFactionsRankEditPriority = new CmdFactionsRankEditPriority(); + + static void ensureAllowed(MPlayer msender, Faction faction) throws MassiveException + { + if (msender.isOverriding()) return; + + if (faction != msender.getFaction()) + { + throw new MassiveException().addMsg("You can't manage ranks outside your own faction."); + } + + if (!msender.getRank().isLeader()) + { + throw new MassiveException().addMsg("Only the leader can create ranks."); + } + } + +} diff --git a/src/com/massivecraft/factions/cmd/CmdFactionsRankEditCreate.java b/src/com/massivecraft/factions/cmd/CmdFactionsRankEditCreate.java new file mode 100644 index 00000000..9403095a --- /dev/null +++ b/src/com/massivecraft/factions/cmd/CmdFactionsRankEditCreate.java @@ -0,0 +1,65 @@ +package com.massivecraft.factions.cmd; + +import com.massivecraft.factions.cmd.type.TypeFaction; +import com.massivecraft.factions.entity.Faction; +import com.massivecraft.factions.entity.Rank; +import com.massivecraft.massivecore.MassiveException; +import com.massivecraft.massivecore.command.type.primitive.TypeInteger; +import com.massivecraft.massivecore.command.type.primitive.TypeString; + +public class CmdFactionsRankEditCreate extends FactionsCommand +{ + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public CmdFactionsRankEditCreate() + { + // Parameters + this.addParameter(TypeString.get(), "name"); + this.addParameter(TypeInteger.get(), "priority"); + this.addParameter("", TypeString.get(), "prefix", "none"); + this.addParameter(TypeFaction.get(), "faction", "you"); + } + + // -------------------------------------------- // + // OVERRIDE + // -------------------------------------------- // + + @Override + public void perform() throws MassiveException + { + // Args + String name = this.readArg(); + Integer priority = this.readArg(); + String prefix = this.readArg(); + Faction faction = this.readArg(msenderFaction); + + CmdFactionsRankEdit.ensureAllowed(msender, faction); + + var ranks = faction.getRanks().getAll(); + + if (ranks.stream().map(Rank::getName).anyMatch(s -> s.equalsIgnoreCase(name))) + { + throw new MassiveException().addMsg("There is already a rank called %s.", name); + } + if (ranks.stream().map(Rank::getPriority).anyMatch(i -> i.equals(priority))) + { + throw new MassiveException().addMsg("There is already a with priority %s.", priority); + } + if (priority > faction.getLeaderRank().getPriority()) + { + throw new MassiveException().addMsg("You can't create a rank of higher priority than the leader rank."); + } + + Rank rank = new Rank(name, priority, prefix); + + faction.getRanks().attach(rank); + + // Inform + msg("You created the rank %s.", rank.getVisual()); + msg("You might want to change its permissions:"); + CmdFactions.get().cmdFactionsPerm.getTemplate(false, true, sender).messageOne(msender); + } + +} diff --git a/src/com/massivecraft/factions/cmd/CmdFactionsRankEditDelete.java b/src/com/massivecraft/factions/cmd/CmdFactionsRankEditDelete.java new file mode 100644 index 00000000..1b4a4cd2 --- /dev/null +++ b/src/com/massivecraft/factions/cmd/CmdFactionsRankEditDelete.java @@ -0,0 +1,64 @@ +package com.massivecraft.factions.cmd; + +import com.massivecraft.factions.cmd.type.TypeFaction; +import com.massivecraft.factions.cmd.type.TypeRank; +import com.massivecraft.factions.entity.Faction; +import com.massivecraft.factions.entity.Rank; +import com.massivecraft.massivecore.MassiveException; +import com.massivecraft.massivecore.command.type.primitive.TypeString; +import com.massivecraft.massivecore.util.Txt; + +import java.util.stream.Collectors; + +public class CmdFactionsRankEditDelete extends FactionsCommand +{ + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public CmdFactionsRankEditDelete() + { + // Parameters + this.addParameter(TypeString.get(), "rank"); + this.addParameter(TypeFaction.get(), "faction", "you"); + } + + // -------------------------------------------- // + // OVERRIDE + // -------------------------------------------- // + + @Override + public void perform() throws MassiveException + { + // Args + Faction faction = this.readArgAt(1, msenderFaction); + + // Rank if any passed. + TypeRank typeRank = new TypeRank(faction); + Rank rank = typeRank.read(this.argAt(0), sender); + + CmdFactionsRankEdit.ensureAllowed(msender, faction); + + var ranks = faction.getRanks().getAll(); + if (ranks.size() <= 2) + { + throw new MassiveException().addMsg("A faction must have at least two ranks."); + } + + var mplayers = faction.getMPlayersWhereRank(rank); + if (!mplayers.isEmpty()) + { + var count = mplayers.size(); + var names = mplayers.stream().map(m -> m.getDisplayName(sender)).collect(Collectors.toList()); + var namesDesc = Txt.implodeCommaAnd(names, Txt.parse("")); + throw new MassiveException().addMsg("This rank is held by %s change their ranks first.", namesDesc); + } + + String visual = rank.getVisual(); + faction.getRanks().detachEntity(rank); + + // Inform + msg("You deleted the rank %s.", visual); + } + +} diff --git a/src/com/massivecraft/factions/cmd/CmdFactionsRankEditName.java b/src/com/massivecraft/factions/cmd/CmdFactionsRankEditName.java new file mode 100644 index 00000000..aeac7784 --- /dev/null +++ b/src/com/massivecraft/factions/cmd/CmdFactionsRankEditName.java @@ -0,0 +1,57 @@ +package com.massivecraft.factions.cmd; + +import com.massivecraft.factions.cmd.type.TypeFaction; +import com.massivecraft.factions.cmd.type.TypeRank; +import com.massivecraft.factions.entity.Faction; +import com.massivecraft.factions.entity.Rank; +import com.massivecraft.massivecore.MassiveException; +import com.massivecraft.massivecore.command.type.primitive.TypeString; + +public class CmdFactionsRankEditName extends FactionsCommand +{ + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public CmdFactionsRankEditName() + { + // Parameters + this.addParameter(TypeRank.get(), "rank"); + this.addParameter(TypeString.get(), "new name"); + this.addParameter(TypeFaction.get(), "faction", "you"); + } + + // -------------------------------------------- // + // OVERRIDE + // -------------------------------------------- // + + @Override + public void perform() throws MassiveException + { + // Args + String name = this.readArgAt(1); + Faction faction = this.readArgAt(2, msenderFaction); + + // Rank if any passed. + TypeRank typeRank = new TypeRank(faction); + Rank rank = typeRank.read(this.argAt(0), sender); + + // Args + + CmdFactionsRankEdit.ensureAllowed(msender, faction); + + var ranks = faction.getRanks().getAll(); + + if (ranks.stream().map(Rank::getName).anyMatch(s -> s.equalsIgnoreCase(name))) + { + throw new MassiveException().addMsg("There is already a rank called %s.", name); + } + + var priorVisual = rank.getVisual(); + rank.setName(name); + + // Visual + msg("You renamed the rank from %s to %s.", priorVisual, rank.getVisual()); + } + +} diff --git a/src/com/massivecraft/factions/cmd/CmdFactionsRankEditPrefix.java b/src/com/massivecraft/factions/cmd/CmdFactionsRankEditPrefix.java new file mode 100644 index 00000000..6bc52829 --- /dev/null +++ b/src/com/massivecraft/factions/cmd/CmdFactionsRankEditPrefix.java @@ -0,0 +1,50 @@ +package com.massivecraft.factions.cmd; + +import com.massivecraft.factions.cmd.type.TypeFaction; +import com.massivecraft.factions.cmd.type.TypeRank; +import com.massivecraft.factions.entity.Faction; +import com.massivecraft.factions.entity.Rank; +import com.massivecraft.massivecore.MassiveException; +import com.massivecraft.massivecore.command.type.primitive.TypeString; + +public class CmdFactionsRankEditPrefix extends FactionsCommand +{ + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public CmdFactionsRankEditPrefix() + { + // Parameters + this.addParameter(TypeRank.get(), "rank"); + this.addParameter(TypeString.get(), "new prefix"); + this.addParameter(TypeFaction.get(), "faction", "you"); + } + + // -------------------------------------------- // + // OVERRIDE + // -------------------------------------------- // + + @Override + public void perform() throws MassiveException + { + // Args + String prefix = this.readArgAt(1); + Faction faction = this.readArgAt(2, msenderFaction); + + // Rank if any passed. + TypeRank typeRank = new TypeRank(faction); + Rank rank = typeRank.read(this.argAt(0), sender); + + // Args + + CmdFactionsRankEdit.ensureAllowed(msender, faction); + + var priorPrefix = rank.getPrefix(); + rank.setPrefix(prefix); + + // Visual + msg("You changed the prefix of %s from %s to %s.", rank.getVisual(), priorPrefix, prefix); + } + +} diff --git a/src/com/massivecraft/factions/cmd/CmdFactionsRankEditPriority.java b/src/com/massivecraft/factions/cmd/CmdFactionsRankEditPriority.java new file mode 100644 index 00000000..14cccada --- /dev/null +++ b/src/com/massivecraft/factions/cmd/CmdFactionsRankEditPriority.java @@ -0,0 +1,71 @@ +package com.massivecraft.factions.cmd; + +import com.massivecraft.factions.cmd.type.TypeFaction; +import com.massivecraft.factions.cmd.type.TypeRank; +import com.massivecraft.factions.entity.Faction; +import com.massivecraft.factions.entity.Rank; +import com.massivecraft.massivecore.MassiveException; +import com.massivecraft.massivecore.command.type.primitive.TypeInteger; + +public class CmdFactionsRankEditPriority extends FactionsCommand +{ + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public CmdFactionsRankEditPriority() + { + // Parameters + this.addParameter(TypeRank.get(), "rank"); + this.addParameter(TypeInteger.get(), "new priority"); + this.addParameter(TypeFaction.get(), "faction", "you"); + } + + // -------------------------------------------- // + // OVERRIDE + // -------------------------------------------- // + + @Override + public void perform() throws MassiveException + { + // Args + Integer priority = this.readArgAt(1); + Faction faction = this.readArgAt(2, msenderFaction); + + // Rank if any passed. + TypeRank typeRank = new TypeRank(faction); + Rank rank = typeRank.read(this.argAt(0), sender); + + CmdFactionsRankEdit.ensureAllowed(msender, faction); + + var ranks = faction.getRanks().getAll(); + + if (ranks.stream().map(Rank::getPriority).anyMatch(s -> s.equals(priority))) + { + throw new MassiveException().addMsg("There is already a rank with the priority %s.", priority); + } + + if (rank.isLeader()) + { + Rank below = rank.getRankBelow(); + if (below.getPriority() > priority) + { + throw new MassiveException().addMsg("The leader rank must have the highest priority."); + } + } + else + { + if (priority >= faction.getLeaderRank().getPriority()) + { + throw new MassiveException().addMsg("No rank can have higher priority than the leader rank."); + } + } + + var priorPriority = rank.getPriority(); + rank.setPriority(priority); + + // Visual + msg("You changed the priority of %s from %s to %s.", rank.getVisual(), priorPriority, priority); + } + +} diff --git a/src/com/massivecraft/factions/cmd/CmdFactionsRankList.java b/src/com/massivecraft/factions/cmd/CmdFactionsRankList.java new file mode 100644 index 00000000..1b8fc91c --- /dev/null +++ b/src/com/massivecraft/factions/cmd/CmdFactionsRankList.java @@ -0,0 +1,43 @@ +package com.massivecraft.factions.cmd; + +import com.massivecraft.factions.cmd.type.TypeFaction; +import com.massivecraft.factions.entity.Faction; +import com.massivecraft.factions.entity.Rank; +import com.massivecraft.massivecore.MassiveException; +import com.massivecraft.massivecore.command.Parameter; +import com.massivecraft.massivecore.pager.Pager; +import com.massivecraft.massivecore.pager.Stringifier; + +import java.util.Comparator; + +public class CmdFactionsRankList extends FactionsCommand +{ + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public CmdFactionsRankList() + { + // Parameters + this.addParameter(Parameter.getPage()); + this.addParameter(TypeFaction.get(), "faction", "you"); + } + + // -------------------------------------------- // + // OVERRIDE + // -------------------------------------------- // + + @Override + public void perform() throws MassiveException + { + final int page = this.readArg(); + Faction faction = this.readArg(msenderFaction); + + var ranks = faction.getRanks().getAll(Comparator.comparingInt(Rank::getPriority).reversed()); + + String title = "Rank list for " + faction.describeTo(msender); + var pager = new Pager(this, title, page, ranks, (Stringifier) (r, i) -> r.getVisual()); + pager.message(); + } + +} diff --git a/src/com/massivecraft/factions/cmd/CmdFactionsRankSet.java b/src/com/massivecraft/factions/cmd/CmdFactionsRankSet.java new file mode 100644 index 00000000..4d58e3e1 --- /dev/null +++ b/src/com/massivecraft/factions/cmd/CmdFactionsRankSet.java @@ -0,0 +1,341 @@ +package com.massivecraft.factions.cmd; + +import com.massivecraft.factions.Factions; +import com.massivecraft.factions.cmd.type.TypeFaction; +import com.massivecraft.factions.cmd.type.TypeMPlayer; +import com.massivecraft.factions.cmd.type.TypeRank; +import com.massivecraft.factions.entity.Faction; +import com.massivecraft.factions.entity.MConf; +import com.massivecraft.factions.entity.MFlag; +import com.massivecraft.factions.entity.MPerm; +import com.massivecraft.factions.entity.MPlayer; +import com.massivecraft.factions.entity.MPlayerColl; +import com.massivecraft.factions.entity.Rank; +import com.massivecraft.factions.event.EventFactionsMembershipChange; +import com.massivecraft.factions.event.EventFactionsMembershipChange.MembershipChangeReason; +import com.massivecraft.factions.event.EventFactionsRankChange; +import com.massivecraft.massivecore.MassiveException; +import com.massivecraft.massivecore.util.Txt; + +import java.util.HashSet; +import java.util.Set; + +public class CmdFactionsRankSet extends FactionsCommand +{ + // -------------------------------------------- // + // FIELDS + // -------------------------------------------- // + // These fields are set upon perform() and unset afterwards. + + // Target + private Faction targetFaction = null; + private MPlayer target = null; + + // End faction (the faction they are changed to) + private Faction endFaction = null; + private boolean factionChange = false; + + // Ranks + private Rank senderRank = null; + private Rank targetRank = null; + private Rank rank = null; + + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public CmdFactionsRankSet() + { + // Parameters + this.addParameter(TypeMPlayer.get(), "player"); + this.addParameter(TypeRank.get(), "rank"); + this.addParameter(TypeFaction.get(), "faction", "their"); + + // Too complicated for that + this.setSwapping(false); + } + + // -------------------------------------------- // + // OVERRIDE + // -------------------------------------------- // + + @Override + public void perform() throws MassiveException + { + // This sets target and much other. + this.registerFields(); + + // Is the player allowed or not. Method can be found later down. + this.ensureAllowed(); + + if (factionChange) + { + this.changeFaction(); + } + + // Does the change make sense. + this.ensureMakesSense(); + + // Event + EventFactionsRankChange event = new EventFactionsRankChange(sender, target, rank); + event.run(); + if (event.isCancelled()) return; + rank = event.getNewRank(); + + // Change the rank. + this.changeRank(); + } + + // This is always run after performing a MassiveCommand. + @Override + public void senderFields(boolean set) + { + super.senderFields(set); + + if ( ! set) + { + this.unregisterFields(); + } + } + + // -------------------------------------------- // + // PRIVATE: REGISTER & UNREGISTER + // -------------------------------------------- // + + private void registerFields() throws MassiveException + { + // Getting the target and faction. + target = this.readArg(msender); + targetFaction = target.getFaction(); + + + // Ranks + senderRank = msender.getRank(); + targetRank = target.getRank(); + + endFaction = this.readArgAt(2, targetFaction); + factionChange = (endFaction != targetFaction); + + // Rank if any passed. + TypeRank typeRank = new TypeRank(endFaction); + rank = typeRank.read(this.argAt(1), sender); + + } + + private void unregisterFields() + { + targetFaction = null; + target = null; + + endFaction = null; + factionChange = false; + + senderRank = null; + targetRank = null; + rank = null; + } + + // -------------------------------------------- // + // PRIVATE: ENSURE + // -------------------------------------------- // + + private void ensureAllowed() throws MassiveException + { + // People with permission don't follow the normal rules. + if (msender.isOverriding()) return; + + // If somone gets the leadership of wilderness (Which has happened before). + // We can at least try to limit their powers. + if (endFaction.isNone()) + { + throw new MassiveException().addMsg("%s doesn't use ranks sorry :(", endFaction.getName()); + } + + if (target == msender) + { + // Don't change your own rank. + throw new MassiveException().addMsg("The target player mustn't be yourself."); + } + + if (factionChange) + { + // Don't change peoples faction + throw new MassiveException().addMsg("You can't change %s's faction.", target.describeTo(msender)); + } + + if (!MPerm.getPermRank().has(msender, targetFaction, false)) + { + throw new MassiveException().addMessage(MPerm.getPermRank().createDeniedMessage(msender, targetFaction)); + } + + // The following two if statements could be merged. + // But isn't for the sake of nicer error messages. + if (senderRank == targetRank) + { + // You can't change someones rank if it is equal to yours. + throw new MassiveException().addMsg("%s can't manage eachother.", senderRank.getName()+"s"); + } + + if (senderRank.isLessThan(targetRank)) + { + // You can't change someones rank if it is higher than yours. + throw new MassiveException().addMsg("You can't manage people of higher rank."); + } + + // The following two if statements could be merged. + // But isn't for the sake of nicer error messages. + if (senderRank == rank && !senderRank.isLeader()) + { + // You can't set ranks equal to your own. Unless you are the leader. + throw new MassiveException().addMsg("You can't set ranks equal to your own."); + } + + if (senderRank.isLessThan(rank)) + { + // You can't set ranks higher than your own. + throw new MassiveException().addMsg("You can't set ranks higher than your own."); + } + } + + private void ensureMakesSense() throws MassiveException + { + // Don't change their rank to something they already are. + if (target.getRank() == rank) + { + throw new MassiveException().addMsg("%s is already %s %s.", target.describeTo(msender), Txt.aan(rank.getName()), rank.getName()); + } + } + + // -------------------------------------------- // + // PRIVATE: CHANGE FACTION + // -------------------------------------------- // + + private void changeFaction() throws MassiveException + { + // Don't change a leader to a new faction. + if (targetRank.isLeader()) + { + throw new MassiveException().addMsg("You cannot remove the present leader. Demote them first."); + } + + // Event + EventFactionsMembershipChange membershipChangeEvent = new EventFactionsMembershipChange(sender, msender, endFaction, MembershipChangeReason.RANK); + membershipChangeEvent.run(); + if (membershipChangeEvent.isCancelled()) throw new MassiveException(); + + // Apply + target.resetFactionData(); + target.setFaction(endFaction); + + // No longer invited. + endFaction.uninvite(target); + + // Create recipients + Set recipients = new HashSet<>(); + recipients.addAll(targetFaction.getMPlayersWhereOnline(true)); + recipients.addAll(endFaction.getMPlayersWhereOnline(true)); + recipients.add(msender); + + // Send message + for (MPlayer recipient : recipients) + { + recipient.msg("%s was moved from %s to %s.", target.describeTo(recipient), targetFaction.describeTo(recipient), endFaction.describeTo(recipient)); + } + + // Derplog + if (MConf.get().logFactionJoin) + { + Factions.get().log(Txt.parse("%s moved %s from %s to %s.", msender.getName(), target.getName(), targetFaction.getName(), endFaction.getName())); + } + + // Now we don't need the old values. + targetFaction = target.getFaction(); + targetRank = target.getRank(); + senderRank = msender.getRank(); // In case they changed their own rank + + } + + // -------------------------------------------- // + // PRIVATE: CHANGE RANK + // -------------------------------------------- // + + private void changeRank() throws MassiveException + { + // In case of leadership change, we do special things not done in other rank changes. + if (rank.isLeader()) + { + this.changeRankLeader(); + } + else + { + this.changeRankOther(); + } + } + + private void changeRankLeader() + { + // If there is a current leader. Demote & inform them. + MPlayer targetFactionCurrentLeader = targetFaction.getLeader(); + if (targetFactionCurrentLeader != null) + { + // Inform & demote the old leader. + targetFactionCurrentLeader.setRank(rank.getRankBelow()); + if (targetFactionCurrentLeader != msender) + { + // They kinda know if they fired the command themself. + targetFactionCurrentLeader.msg("You have been demoted from the position of faction leader by %s.", msender.describeTo(targetFactionCurrentLeader, true)); + } + } + + // Promote the new leader. + target.setRank(rank); + + // Inform everyone, this includes sender and target. + for (MPlayer recipient : MPlayerColl.get().getAllOnline()) + { + String changerName = senderIsConsole ? "A server admin" : msender.describeTo(recipient); + recipient.msg("%s gave %s the leadership of %s.", changerName, target.describeTo(recipient), targetFaction.describeTo(recipient)); + } + } + + private void changeRankOther() throws MassiveException + { + // If the target is currently the leader and faction isn't permanent a new leader should be promoted. + // Sometimes a bug occurs and multiple leaders exist. Then we should be able to demote without promoting new leader + if (targetRank.isLeader() && ( ! MConf.get().permanentFactionsDisableLeaderPromotion || ! targetFaction.getFlag(MFlag.ID_PERMANENT)) && targetFaction.getMPlayersWhereRank(targetFaction.getLeaderRank()).size() == 1) + // This if statement is very long. Should I nest it for readability? + { + targetFaction.promoteNewLeader(); // This might disband the faction. + + // So if the faction disbanded... + if (targetFaction.detached()) + { + // ... we inform the sender. + target.resetFactionData(); + throw new MassiveException().addMsg("The target was a leader and got demoted. The faction disbanded and no rank was set."); + } + } + + // Create recipients + Set recipients = new HashSet<>(); + recipients.addAll(targetFaction.getMPlayers()); + recipients.add(msender); + + // Were they demoted or promoted? + String change = (rank.isLessThan(targetRank) ? "demoted" : "promoted"); + + // The rank will be set before the msg, so they have the appropriate prefix. + target.setRank(rank); + String oldRankName = targetRank.getName().toLowerCase(); + String rankName = rank.getName().toLowerCase(); + + // Send message + for(MPlayer recipient : recipients) + { + String targetName = target.describeTo(recipient, true); + String wasWere = (recipient == target) ? "were" : "was"; + recipient.msg("%s %s %s from %s to %s in %s.", targetName, wasWere, change, oldRankName, rankName, targetFaction.describeTo(msender)); + } + } + +} diff --git a/src/com/massivecraft/factions/cmd/CmdFactionsRankShow.java b/src/com/massivecraft/factions/cmd/CmdFactionsRankShow.java new file mode 100644 index 00000000..14c38af6 --- /dev/null +++ b/src/com/massivecraft/factions/cmd/CmdFactionsRankShow.java @@ -0,0 +1,56 @@ +package com.massivecraft.factions.cmd; + +import com.massivecraft.factions.cmd.type.TypeMPlayer; +import com.massivecraft.factions.entity.MPlayer; +import com.massivecraft.factions.entity.Rank; +import com.massivecraft.massivecore.MassiveException; +import com.massivecraft.massivecore.util.Txt; + +public class CmdFactionsRankShow extends FactionsCommand +{ + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public CmdFactionsRankShow() + { + // Parameters + this.addParameter(TypeMPlayer.get(), "player"); + } + + // -------------------------------------------- // + // OVERRIDE + // -------------------------------------------- // + + @Override + public void perform() throws MassiveException + { + MPlayer target = this.readArg(); + Rank rank = target.getRank(); + + // Damn you grammar, causing all these checks. + String targetName = target.describeTo(msender, true); + String isAre = (target == msender) ? "are" : "is"; // "you are" or "he is" + + String theAan = (rank.isLeader()) ? "the" : Txt.aan(rank.getName()); // "a member", "an officer" or "the leader" + String rankName = rank.getName().toLowerCase(); + String ofIn = (rank.isLeader()) ? "of" : "in"; // "member in" or "leader of" + String factionName = target.getFaction().describeTo(msender, true); + if (target.getFaction() == msenderFaction) + { + // Having the "Y" in "Your faction" being uppercase in the middle of a sentence makes no sense. + factionName = factionName.toLowerCase(); + } + if (target.getFaction().isNone()) + { + // Wilderness aka none doesn't use ranks + msg("%s %s factionless", targetName, isAre); + } + else + { + // Derp is a member in Faction + msg("%s %s %s %s %s %s.", targetName, isAre, theAan, rankName, ofIn, factionName); + } + } + +} diff --git a/src/com/massivecraft/factions/cmd/type/TypeRank.java b/src/com/massivecraft/factions/cmd/type/TypeRank.java index 18449f7d..3b412406 100644 --- a/src/com/massivecraft/factions/cmd/type/TypeRank.java +++ b/src/com/massivecraft/factions/cmd/type/TypeRank.java @@ -4,8 +4,11 @@ import com.massivecraft.factions.Rel; import com.massivecraft.factions.entity.Faction; import com.massivecraft.factions.entity.Rank; import com.massivecraft.massivecore.command.type.TypeAbstractChoice; +import com.massivecraft.massivecore.util.MUtil; +import org.bukkit.command.CommandSender; import java.util.Collections; +import java.util.Set; public class TypeRank extends TypeAbstractChoice { @@ -41,4 +44,22 @@ public class TypeRank extends TypeAbstractChoice private final Faction faction; public Faction getFaction() { return this.faction; } + // -------------------------------------------- // + // OVERRIDE + // -------------------------------------------- // + + @Override + public boolean isValid(String arg, CommandSender sender) + { + // In the generic case accept all + if (this.getAll().isEmpty()) return true; + else return super.isValid(arg, sender); + } + + @Override + public Set getNamesInner(Rank value) + { + return MUtil.set(value.getName(), value.getPrefix() + value.getName()); + } + } diff --git a/src/com/massivecraft/factions/entity/Faction.java b/src/com/massivecraft/factions/entity/Faction.java index 8c7e4091..0b97a8b0 100644 --- a/src/com/massivecraft/factions/entity/Faction.java +++ b/src/com/massivecraft/factions/entity/Faction.java @@ -523,10 +523,10 @@ public class Faction extends Entity implements FactionsParticipator, MP private EntityInternalMap createRankMap() { var ret = new EntityInternalMap<>(this, Rank.class); - Rank leader = new Rank("Leader", 400); - Rank officer = new Rank("Officer", 300); - Rank member = new Rank("Member", 200); - Rank recruit = new Rank("Recruit", 100); + Rank leader = new Rank("Leader", 400, "**"); + Rank officer = new Rank("Officer", 300, "*"); + Rank member = new Rank("Member", 200, "+"); + Rank recruit = new Rank("Recruit", 100, "-"); /*leader.setPermIds(new MassiveList<>(MConf.get().defaultPermsLeader)); officer.setPermIds(new MassiveList<>(MConf.get().defaultPermsOfficer)); diff --git a/src/com/massivecraft/factions/entity/Rank.java b/src/com/massivecraft/factions/entity/Rank.java index 0844d8f5..fc91cfcc 100644 --- a/src/com/massivecraft/factions/entity/Rank.java +++ b/src/com/massivecraft/factions/entity/Rank.java @@ -1,6 +1,7 @@ package com.massivecraft.factions.entity; import com.massivecraft.massivecore.store.EntityInternal; +import org.bukkit.ChatColor; public class Rank extends EntityInternal implements MPerm.MPermable { @@ -28,19 +29,9 @@ public class Rank extends EntityInternal implements MPerm.MPermable public int getPriority() { return this.priority; } public void setPriority(int priority) { this.priority = priority; this.changed(); } - public String getPrefix() - { - String ret = ""; - if (this.isLeader()) ret += "L"; - - if (this.getName().equalsIgnoreCase("Leader")) ret += "**"; - else if (this.getName().equalsIgnoreCase("Officer")) ret += "*"; - else if (this.getName().equalsIgnoreCase("Member")) ret += "+"; - else if (this.getName().equalsIgnoreCase("Recruit")) ret += "-"; - else ret += "="; - - return ret; - } + private String prefix; + public String getPrefix() { return this.prefix; } + public void setPrefix(String prefix) { this.prefix = prefix; this.changed(); } // -------------------------------------------- // // CONSTRUCT @@ -49,13 +40,28 @@ public class Rank extends EntityInternal implements MPerm.MPermable // For GSON private Rank() { - this(null,0); + this(null,0, ""); } - public Rank(String name, int priority) + public Rank(String name, int priority, String prefix) { this.name = name; this.priority = priority; + this.prefix = prefix; + } + + // -------------------------------------------- // + // VISUAL + // -------------------------------------------- // + + public String getVisual() + { + String ret = ""; + ret += ChatColor.GREEN.toString(); + ret += this.getPrefix(); + ret += this.getName(); + ret += " (" + this.getPriority() + ")"; + return ret; } // -------------------------------------------- // @@ -129,27 +135,4 @@ public class Rank extends EntityInternal implements MPerm.MPermable return ret; } - // -------------------------------------------- // - // PERM - // -------------------------------------------- // - - /*public boolean addPerm(MPerm mperm) - { - var ret = this.getPermIds().add(mperm.getId()); - if (ret) this.changed(); - return ret; - } - - public boolean removePerm(MPerm mperm) - { - var ret = this.getPermIds().remove(mperm.getId()); - if (ret) this.changed(); - return ret; - } - - public boolean hasPerm(MPerm mperm) - { - return this.getPermIds().contains(mperm.getId()); - }*/ - } diff --git a/src/com/massivecraft/factions/entity/migrator/MigratorFaction002Ranks.java b/src/com/massivecraft/factions/entity/migrator/MigratorFaction002Ranks.java index 7cf13020..ecfd24c9 100644 --- a/src/com/massivecraft/factions/entity/migrator/MigratorFaction002Ranks.java +++ b/src/com/massivecraft/factions/entity/migrator/MigratorFaction002Ranks.java @@ -41,10 +41,10 @@ public class MigratorFaction002Ranks extends MigratorRoot String idMember = MStore.createId(); String idRecruit = MStore.createId(); - Rank leader = new Rank("Leader", 400); - Rank officer = new Rank("Officer", 300); - Rank member = new Rank("Member", 200); - Rank recruit = new Rank("Recruit", 100); + Rank leader = new Rank("Leader", 400, "**"); + Rank officer = new Rank("Officer", 300, "*"); + Rank member = new Rank("Member", 200, "+"); + Rank recruit = new Rank("Recruit", 100, "-"); Map map = new MassiveMap<>(); map.put(idLeader, leader);