Browse Source

More work on parties

nossr50 4 years ago
parent
commit
85ad0ddd17
25 changed files with 187 additions and 307 deletions
  1. 4 0
      Changelog.txt
  2. 0 11
      src/main/java/com/gmail/nossr50/api/exceptions/IncompleteNamespacedKeyRegister.java
  3. 0 9
      src/main/java/com/gmail/nossr50/api/exceptions/InvalidFormulaTypeException.java
  4. 0 9
      src/main/java/com/gmail/nossr50/api/exceptions/InvalidPlayerException.java
  5. 0 13
      src/main/java/com/gmail/nossr50/api/exceptions/InvalidSkillException.java
  6. 0 9
      src/main/java/com/gmail/nossr50/api/exceptions/InvalidXPGainReasonException.java
  7. 0 12
      src/main/java/com/gmail/nossr50/api/exceptions/McMMOPlayerNotFoundException.java
  8. 0 4
      src/main/java/com/gmail/nossr50/api/exceptions/NullPartyException.java
  9. 0 7
      src/main/java/com/gmail/nossr50/api/exceptions/ProfileRetrievalException.java
  10. 0 4
      src/main/java/com/gmail/nossr50/api/exceptions/UnexpectedValueException.java
  11. 7 1
      src/main/java/com/gmail/nossr50/commands/party/PartyChangeOwnerCommand.java
  12. 1 1
      src/main/java/com/gmail/nossr50/datatypes/experience/ExperienceContextBuilder.java
  13. 0 26
      src/main/java/com/gmail/nossr50/datatypes/experience/capture/ExperienceCapture.java
  14. 0 36
      src/main/java/com/gmail/nossr50/datatypes/experience/capture/ExperienceSnapshot.java
  15. 0 31
      src/main/java/com/gmail/nossr50/datatypes/experience/capture/MultiExperienceCapture.java
  16. 4 9
      src/main/java/com/gmail/nossr50/datatypes/experience/context/BlockExperienceContextImpl.java
  17. 4 3
      src/main/java/com/gmail/nossr50/datatypes/experience/context/CombatExperienceContextImpl.java
  18. 0 12
      src/main/java/com/gmail/nossr50/datatypes/experience/context/ExperienceContext.java
  19. 1 0
      src/main/java/com/gmail/nossr50/datatypes/experience/context/NullExperienceContext.java
  20. 0 13
      src/main/java/com/gmail/nossr50/datatypes/experience/context/SharedExperienceContext.java
  21. 0 83
      src/main/java/com/gmail/nossr50/datatypes/party/Party.java
  22. 2 1
      src/main/java/com/gmail/nossr50/datatypes/party/PartyExperienceManager.java
  23. 97 7
      src/main/java/com/gmail/nossr50/datatypes/party/PartyMemberManager.java
  24. 24 6
      src/main/java/com/gmail/nossr50/datatypes/party/PersistentPartyData.java
  25. 43 0
      src/main/java/com/gmail/nossr50/util/player/PartyUtils.java

+ 4 - 0
Changelog.txt

@@ -1,4 +1,8 @@
 Version 2.2.000
+    mcMMO-API is now the library used for mcMMO API
+    Parts of the API have been migrated to mcMMO-API
+    (API) mcMMO makes use of jmal (Java Minecraft Abstraction Library) for some abstraction now
+
     New Skill - Tridents
     New Skill - Crossbows
 

+ 0 - 11
src/main/java/com/gmail/nossr50/api/exceptions/IncompleteNamespacedKeyRegister.java

@@ -1,11 +0,0 @@
-package com.gmail.nossr50.api.exceptions;
-
-import org.jetbrains.annotations.NotNull;
-
-public class IncompleteNamespacedKeyRegister extends RuntimeException {
-    private static final long serialVersionUID = -6905157273569301219L;
-
-    public IncompleteNamespacedKeyRegister(@NotNull String message) {
-        super(message);
-    }
-}

+ 0 - 9
src/main/java/com/gmail/nossr50/api/exceptions/InvalidFormulaTypeException.java

@@ -1,9 +0,0 @@
-package com.gmail.nossr50.api.exceptions;
-
-public class InvalidFormulaTypeException extends RuntimeException {
-    private static final long serialVersionUID = 3368670229490121886L;
-
-    public InvalidFormulaTypeException() {
-        super("That is not a valid FormulaType.");
-    }
-}

+ 0 - 9
src/main/java/com/gmail/nossr50/api/exceptions/InvalidPlayerException.java

@@ -1,9 +0,0 @@
-package com.gmail.nossr50.api.exceptions;
-
-public class InvalidPlayerException extends RuntimeException {
-    private static final long serialVersionUID = 907213002618581385L;
-
-    public InvalidPlayerException() {
-        super("That player does not exist in the database.");
-    }
-}

+ 0 - 13
src/main/java/com/gmail/nossr50/api/exceptions/InvalidSkillException.java

@@ -1,13 +0,0 @@
-package com.gmail.nossr50.api.exceptions;
-
-public class InvalidSkillException extends RuntimeException {
-    private static final long serialVersionUID = 942705284195791157L;
-
-    public InvalidSkillException() {
-        super("That is not a valid skill.");
-    }
-
-    public InvalidSkillException(String msg) {
-        super(msg);
-    }
-}

+ 0 - 9
src/main/java/com/gmail/nossr50/api/exceptions/InvalidXPGainReasonException.java

@@ -1,9 +0,0 @@
-package com.gmail.nossr50.api.exceptions;
-
-public class InvalidXPGainReasonException extends RuntimeException {
-    private static final long serialVersionUID = 4427052841957931157L;
-
-    public InvalidXPGainReasonException() {
-        super("That is not a valid XPGainReason.");
-    }
-}

+ 0 - 12
src/main/java/com/gmail/nossr50/api/exceptions/McMMOPlayerNotFoundException.java

@@ -1,12 +0,0 @@
-package com.gmail.nossr50.api.exceptions;
-
-import org.bukkit.entity.Player;
-import org.jetbrains.annotations.NotNull;
-
-public class McMMOPlayerNotFoundException extends RuntimeException {
-    private static final long serialVersionUID = 761917904993202836L;
-
-    public McMMOPlayerNotFoundException(@NotNull Player player) {
-        super("McMMOPlayer object was not found for [NOTE: This can mean the profile is not loaded yet!] : " + player.getName() + " " + player.getUniqueId());
-    }
-}

+ 0 - 4
src/main/java/com/gmail/nossr50/api/exceptions/NullPartyException.java

@@ -1,4 +0,0 @@
-package com.gmail.nossr50.api.exceptions;
-
-public class NullPartyException extends RuntimeException {
-}

+ 0 - 7
src/main/java/com/gmail/nossr50/api/exceptions/ProfileRetrievalException.java

@@ -1,7 +0,0 @@
-package com.gmail.nossr50.api.exceptions;
-
-public class ProfileRetrievalException extends RuntimeException {
-    public ProfileRetrievalException(String message) {
-        super(message);
-    }
-}

+ 0 - 4
src/main/java/com/gmail/nossr50/api/exceptions/UnexpectedValueException.java

@@ -1,4 +0,0 @@
-package com.gmail.nossr50.api.exceptions;
-
-public class UnexpectedValueException extends RuntimeException {
-}

+ 7 - 1
src/main/java/com/gmail/nossr50/commands/party/PartyChangeOwnerCommand.java

@@ -24,7 +24,13 @@ public class PartyChangeOwnerCommand implements CommandExecutor {
             String targetName = CommandUtils.getMatchedPlayerName(args[1]);
             OfflinePlayer target = mcMMO.p.getServer().getOfflinePlayer(targetName);
 
-            if (!playerParty.hasMember(target.getUniqueId())) {
+            if(playerParty == null) {
+                //TODO: Localize
+                sender.sendMessage("Party is null!");
+                return true;
+            }
+
+            if (!playerParty.getPartyMemberManager().hasMember(target.getUniqueId())) {
                 sender.sendMessage(LocaleLoader.getString("Party.NotInYourParty", targetName));
                 return true;
             }

+ 1 - 1
src/main/java/com/gmail/nossr50/datatypes/experience/ExperienceContextBuilder.java

@@ -1,6 +1,6 @@
 package com.gmail.nossr50.datatypes.experience;
 
-import com.gmail.nossr50.datatypes.experience.context.NullExperienceContext;
+import com.neetgames.mcmmo.experience.context.NullExperienceContext;
 import org.jetbrains.annotations.NotNull;
 
 public class ExperienceContextBuilder {

+ 0 - 26
src/main/java/com/gmail/nossr50/datatypes/experience/capture/ExperienceCapture.java

@@ -1,26 +0,0 @@
-package com.gmail.nossr50.datatypes.experience.capture;
-
-import com.gmail.nossr50.datatypes.experience.context.ExperienceContext;
-import com.neetgames.mcmmo.skill.SkillIdentity;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.HashSet;
-
-public class ExperienceCapture {
-    private @NotNull ExperienceContext experienceContext;
-    private @NotNull HashSet<SkillIdentity> affectedSkills;
-
-    public ExperienceCapture(@NotNull ExperienceContext experienceContext, @NotNull HashSet<SkillIdentity> affectedSkills) {
-        this.experienceContext = experienceContext;
-        this.affectedSkills = affectedSkills;
-    }
-
-    /**
-     * Check whether or not a skill is targeted in this experience capture
-     * @param skillIdentity target skill
-     * @return true if this skill is targeted in this experience capture
-     */
-    public boolean isSkillAffected(@NotNull SkillIdentity skillIdentity) {
-        return affectedSkills.contains(skillIdentity);
-    }
-}

+ 0 - 36
src/main/java/com/gmail/nossr50/datatypes/experience/capture/ExperienceSnapshot.java

@@ -1,36 +0,0 @@
-package com.gmail.nossr50.datatypes.experience.capture;
-
-import com.gmail.nossr50.datatypes.player.PlayerProfile;
-import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
-import com.gmail.nossr50.datatypes.skills.SkillIdentity;
-import org.jetbrains.annotations.NotNull;
-
-public interface ExperienceSnapshot {
-    /**
-     * Check whether or not a skill is targeted in this experience capture
-     *
-     * @param skillIdentity target skill
-     * @return true if this skill is targeted in this experience capture
-     */
-    boolean isSkillAffected(@NotNull SkillIdentity skillIdentity);
-
-    /**
-     * Check whether or not a skill is targeted in this experience capture
-     *
-     * @param skillId target skill
-     * @return true if this skill is targeted in this experience capture
-     */
-    boolean isSkillAffected(@NotNull String skillId);
-
-    /**
-     * Check whether or not a skill is targeted in this experience capture
-     *
-     * @param primarySkillType target skill
-     * @return true if this skill is targeted in this experience capture
-     * @deprecated the {@link PrimarySkillType} type is going to be phased out in favour of {@link SkillIdentity} at some point in the future
-     */
-    @Deprecated
-    boolean isSkillAffected(@NotNull PrimarySkillType primarySkillType);
-
-    @NotNull PlayerProfile[] getPlayers();
-}

+ 0 - 31
src/main/java/com/gmail/nossr50/datatypes/experience/capture/MultiExperienceCapture.java

@@ -1,31 +0,0 @@
-package com.gmail.nossr50.datatypes.experience;
-
-import com.gmail.nossr50.datatypes.experience.capture.ExperienceCapture;
-import com.gmail.nossr50.datatypes.experience.context.ExperienceContext;
-import com.gmail.nossr50.datatypes.skills.SkillIdentity;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.HashSet;
-
-public class MultiExperienceCapture extends ExperienceCapture {
-    private @NotNull ExperienceContext experienceContext;
-    private @NotNull HashSet<SkillIdentity> affectedSkills;
-
-    public ExperienceCapture(@NotNull ExperienceContext experienceContext, @NotNull HashSet<SkillIdentity> affectedSkills) {
-        this.experienceContext = experienceContext;
-        this.affectedSkills = affectedSkills;
-    }
-
-    public MultiExperienceCapture(@NotNull ExperienceContext experienceContext, @NotNull HashSet<SkillIdentity> affectedSkills) {
-        super(experienceContext, affectedSkills);
-    }
-
-    /**
-     * Check whether or not a skill is targeted in this experience capture
-     * @param skillIdentity target skill
-     * @return true if this skill is targeted in this experience capture
-     */
-    public boolean isSkillAffected(@NotNull SkillIdentity skillIdentity) {
-        return affectedSkills.contains(skillIdentity);
-    }
-}

+ 4 - 9
src/main/java/com/gmail/nossr50/datatypes/experience/context/BlockExperienceContext.java → src/main/java/com/gmail/nossr50/datatypes/experience/context/BlockExperienceContextImpl.java

@@ -1,14 +1,14 @@
 package com.gmail.nossr50.datatypes.experience.context;
 
-import org.bukkit.block.Block;
+import com.neetgames.jmal.Block;
+import com.neetgames.mcmmo.experience.context.BlockExperienceContext;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public class BlockExperienceContext implements ExperienceContext {
-
+public class BlockExperienceContextImpl implements BlockExperienceContext {
     @NotNull Block blockExperienceContext;
 
-    public BlockExperienceContext(@NotNull Block block) {
+    public BlockExperienceContextImpl(@NotNull Block block) {
         this.blockExperienceContext = block;
     }
 
@@ -18,11 +18,6 @@ public class BlockExperienceContext implements ExperienceContext {
         return blockExperienceContext;
     }
 
-    /**
-     * Get the Block involved in this experience context
-     *
-     * @return the {@link Block} involved in this experience context
-     */
     public @NotNull Block getBlockExperienceContext() {
         return blockExperienceContext;
     }

+ 4 - 3
src/main/java/com/gmail/nossr50/datatypes/experience/context/CombatContext.java → src/main/java/com/gmail/nossr50/datatypes/experience/context/CombatExperienceContextImpl.java

@@ -1,14 +1,15 @@
 package com.gmail.nossr50.datatypes.experience.context;
 
-import org.bukkit.entity.LivingEntity;
+import com.neetgames.jmal.LivingEntity;
+import com.neetgames.mcmmo.experience.context.CombatExperienceContext;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-public class CombatContext implements ExperienceContext {
+public class CombatExperienceContextImpl implements CombatExperienceContext {
 
     private final @NotNull LivingEntity livingEntity;
 
-    public CombatContext(@NotNull LivingEntity livingEntity) {
+    public CombatExperienceContextImpl(@NotNull LivingEntity livingEntity) {
         this.livingEntity = livingEntity;
     }
 

+ 0 - 12
src/main/java/com/gmail/nossr50/datatypes/experience/context/ExperienceContext.java

@@ -1,12 +0,0 @@
-package com.gmail.nossr50.datatypes.experience.context;
-
-import javax.annotation.Nullable;
-
-public interface ExperienceContext {
-    /**
-     * The source for this experience gain, can be anything from a block to an entity, etc
-     * Context is available as long as it can be
-     * @return the context (source) of this experience
-     */
-    @Nullable Object getContext();
-}

+ 1 - 0
src/main/java/com/gmail/nossr50/datatypes/experience/context/NullExperienceContext.java

@@ -1,5 +1,6 @@
 package com.gmail.nossr50.datatypes.experience.context;
 
+import com.neetgames.mcmmo.experience.context.ExperienceContext;
 import org.jetbrains.annotations.Nullable;
 
 /**

+ 0 - 13
src/main/java/com/gmail/nossr50/datatypes/experience/context/SharedExperienceContext.java

@@ -1,13 +0,0 @@
-package com.gmail.nossr50.datatypes.experience.context;
-
-import com.gmail.nossr50.datatypes.player.McMMOPlayer;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-public interface SharedExperienceContext {
-    /**
-     * The {@link McMMOPlayer} who originally gained the XP that was then shared
-     * @return the {@link McMMOPlayer} to which this experience context originates
-     */
-    @NotNull McMMOPlayer getSharedContextSource();
-}

+ 0 - 83
src/main/java/com/gmail/nossr50/datatypes/party/Party.java

@@ -49,62 +49,6 @@ public class Party {
         return persistentPartyData.getPartyName();
     }
 
-    public void setLeader(UUID newPartyLeader) {
-        this.partyMemberManager = ;
-    }
-
-    public boolean hasMember(Player player) {
-        return hasMember(player.getUniqueId());
-    }
-
-    public boolean hasMember(OfflinePlayer offlinePlayer) {
-        return hasMember(offlinePlayer.getUniqueId());
-    }
-
-    public boolean hasMember(UUID playerUUID) {
-        for(PartyMember partyMember : getPartyMembers()) {
-            if(partyMember.getUniqueId().equals(playerUUID))
-                return true;
-        }
-
-        return false;
-    }
-
-    public boolean hasMember(String playerName) {
-        for(PartyMember partyMember : getPartyMembers()) {
-            if(partyMember.getName().equalsIgnoreCase(playerName))
-                return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Makes a formatted list of party members based on the perspective of a target player
-     * Players that are hidden will be shown as offline (formatted in the same way)
-     * Party leader will be formatted a specific way as well
-     * @param player target player to use as POV
-     * @return formatted list of party members from the POV of a player
-     */
-    public String createMembersList(Player player) {
-        StringBuilder memberList = new StringBuilder();
-        List<String> coloredNames = new ArrayList<>();
-
-        for(UUID playerUUID : members.keySet()) {
-            OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerUUID);
-
-            if(offlinePlayer.isOnline() && player.canSee((Player) offlinePlayer)) {
-                ChatColor onlineColor = leader.getUniqueId().equals(playerUUID) ? ChatColor.GOLD : ChatColor.GREEN;
-                coloredNames.add(onlineColor + offlinePlayer.getName());
-            } else {
-                coloredNames.add(ChatColor.DARK_GRAY + members.get(playerUUID));
-            }
-        }
-
-        buildChatMessage(memberList, coloredNames.toArray(new String[0]));
-        return memberList.toString();
-    }
-
     private void buildChatMessage(@NotNull StringBuilder stringBuilder, String @NotNull [] names) {
         for(int i = 0; i < names.length; i++) {
             if(i + 1 >= names.length) {
@@ -118,33 +62,6 @@ public class Party {
         }
     }
 
-    /**
-     * Get the near party members.
-     *
-     * @param mmoPlayer The player to check
-     * @return the near party members
-     */
-    public List<Player> getNearMembers(McMMOPlayer mmoPlayer) {
-        List<Player> nearMembers = new ArrayList<>();
-        Party party = mmoPlayer.getParty();
-
-        if (party != null) {
-            Player player = mmoPlayer.getPlayer();
-            double range = Config.getInstance().getPartyShareRange();
-
-            for (PartyMember partyMember : party.getPartyMembers()) {
-                if (!player.getUniqueId().equals(partyMember.getOfflinePlayer().getUniqueId())
-                        && partyMember.getOfflinePlayer().isOnline()
-                        && partyMember.getOfflinePlayer().getPlayer() != null
-                        && Misc.isNear(player.getLocation(), partyMember.getOfflinePlayer().getPlayer().getLocation(), range)) {
-                    nearMembers.add(partyMember.getOfflinePlayer().getPlayer());
-                }
-            }
-        }
-
-        return nearMembers;
-    }
-
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;

+ 2 - 1
src/main/java/com/gmail/nossr50/datatypes/party/PartyExperienceManager.java

@@ -9,6 +9,7 @@ import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundType;
 import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
 
 import java.text.DecimalFormat;
 
@@ -111,7 +112,7 @@ public class PartyExperienceManager {
         return (mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType)) * (getPartyMembers().size() + Config.getInstance().getPartyXpCurveMultiplier());
     }
 
-    public String getXpToLevelPercentage() {
+    public @NotNull String getXpToLevelPercentage() {
         DecimalFormat percent = new DecimalFormat("##0.00%");
         return percent.format(this.getXp() / getXpToLevel());
     }

+ 97 - 7
src/main/java/com/gmail/nossr50/datatypes/party/PartyMemberManager.java

@@ -1,35 +1,55 @@
 package com.gmail.nossr50.datatypes.party;
 
+import com.gmail.nossr50.config.Config;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.util.Misc;
 import org.bukkit.OfflinePlayer;
 import org.bukkit.entity.Player;
 import org.jetbrains.annotations.NotNull;
 
-import java.util.HashSet;
-import java.util.Set;
+import java.util.*;
 
 public class PartyMemberManager {
 
     private final @NotNull PersistentPartyData persistentPartyData;
     
-    public PartyMemberManager(@NotNull PersistentPartyData persistentPartyData, @NotNull HashSet<PartyMember> partyMembers) {
+    public PartyMemberManager(@NotNull PersistentPartyData persistentPartyData) {
         this.persistentPartyData = persistentPartyData;
     }
 
+    /**
+     * Grab all party members for this party
+     *
+     * @return all party members
+     */
     public @NotNull Set<PartyMember> getPartyMembers() {
         return persistentPartyData.getPartyMembers();
     }
 
-    public void addPartyMember(OfflinePlayer player, PartyMemberRank partyMemberRank) {
+    /**
+     * Add a {@link PartyMember} to this {@link Party} with a designated rank
+     * If you are adding a {@link PartyMemberRank} of Leader, any existing party leaders will be demoted to a regular member of the party
+     *
+     * @param playerUUID target player's uuid
+     * @param partyMemberRank target rank
+     */
+    public void addPartyMember(@NotNull UUID playerUUID, @NotNull PartyMemberRank partyMemberRank) {
         //TODO: Prevent adding multiple leaders
         //TODO: Call event
-        partyMembers.add(new PartyMember(player, partyMemberRank));
+        persistentPartyData.getPartyMembers().add(new PartyMember(playerUUID, partyMemberRank));
     }
 
-    public HashSet<PartyMember> getVisibleMembers(Player player)
+    /**
+     * Get party members that are "Visible" to a target {@link Player}
+     *
+     * @param player target {@link Player}
+     * @return returns a {@link HashSet<PartyMember>} which are visible to the player
+     */
+    public @NotNull HashSet<PartyMember> getVisibleMembers(@NotNull Player player)
     {
         HashSet<PartyMember> visibleMembers = new HashSet<>();
 
-        for(PartyMember partyMember : partyMembers)
+        for(PartyMember partyMember : persistentPartyData.getPartyMembers())
         {
             if(partyMember.getOfflinePlayer().getPlayer() == null)
                 continue;
@@ -40,4 +60,74 @@ public class PartyMemberManager {
 
         return visibleMembers;
     }
+
+    /**
+     * Change the leader of a party to the provided UUID
+     *
+     * @param playerUUID the UUID of the new party leader
+     */
+    public void changeLeader(@NotNull UUID playerUUID) {
+        //TODO: implementation
+    }
+
+    public boolean hasMember(@NotNull UUID playerUUID) {
+        for(PartyMember partyMember : persistentPartyData.getPartyMembers()) {
+            if(partyMember.getUniqueId().equals(playerUUID))
+                return true;
+        }
+        return false;
+    }
+
+    public boolean hasMember(@NotNull Player player) {
+        return hasMember(player.getUniqueId());
+    }
+
+    public boolean hasMember(@NotNull OfflinePlayer offlinePlayer) {
+        return hasMember(offlinePlayer.getUniqueId());
+    }
+
+    /**
+     * Checks for a party member by player name, this method is unreliable and should be avoided.
+     * Not case sensitive
+     *
+     * @param playerName target player name
+     * @return true if the a matching player is found
+     * @deprecated Unreliable, use UUID instead
+     */
+    @Deprecated
+    public boolean hasMember(@NotNull String playerName) {
+        for(PartyMember partyMember : getPartyMembers()) {
+            if(partyMember.getName().equalsIgnoreCase(playerName))
+                return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Get the near party members.
+     *
+     * @param mmoPlayer The player to check
+     * @return the near party members
+     */
+    public List<Player> getNearMembers(McMMOPlayer mmoPlayer) {
+        List<Player> nearMembers = new ArrayList<>();
+        Party party = mmoPlayer.getParty();
+
+        if (party != null) {
+            Player player = mmoPlayer.getPlayer();
+            double range = Config.getInstance().getPartyShareRange();
+
+            for (PartyMember partyMember : party.getPartyMembers()) {
+                if (!player.getUniqueId().equals(partyMember.getOfflinePlayer().getUniqueId())
+                        && partyMember.getOfflinePlayer().isOnline()
+                        && partyMember.getOfflinePlayer().getPlayer() != null
+                        && Misc.isNear(player.getLocation(), partyMember.getOfflinePlayer().getPlayer().getLocation(), range)) {
+                    nearMembers.add(partyMember.getOfflinePlayer().getPlayer());
+                }
+            }
+        }
+
+        return nearMembers;
+    }
 }

+ 24 - 6
src/main/java/com/gmail/nossr50/datatypes/party/PersistentPartyData.java

@@ -4,10 +4,11 @@ import com.gmail.nossr50.datatypes.dirtydata.DirtyData;
 import com.gmail.nossr50.datatypes.dirtydata.DirtySet;
 import com.gmail.nossr50.datatypes.mutableprimitives.MutableBoolean;
 import com.gmail.nossr50.datatypes.mutableprimitives.MutableString;
-import com.google.common.base.Objects;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.HashSet;
+import java.util.Objects;
 import java.util.Set;
 
 public class PersistentPartyData {
@@ -15,6 +16,7 @@ public class PersistentPartyData {
     private final @NotNull MutableBoolean dirtyFlag; //Dirty values in this class will change this flag as needed
     private final @NotNull DirtyData<MutableString> partyName;
     private final @NotNull DirtySet<PartyMember> partyMembers; //TODO: Add cache for subsets
+    private @Nullable PartyMember partyLeaderRef;
 
     public PersistentPartyData(@NotNull String partyName,
                                @NotNull Set<PartyMember> partyMembers) {
@@ -23,11 +25,28 @@ public class PersistentPartyData {
         this.partyMembers = new DirtySet<>(new HashSet<>(partyMembers), dirtyFlag);
     }
 
-    public String getPartyName() {
+    private void initPartyLeaderRef() {
+        for(PartyMember partyMember : getPartyMembers()) {
+            if(partyMember.getPartyMemberRank() == PartyMemberRank.LEADER) {
+                partyLeaderRef = partyMember;
+                break;
+            }
+        }
+
+        if(partyLeaderRef == null)
+            throw new RuntimeException("Party leader is null!");
+    }
+
+    public @Nullable PartyMember getPartyLeader() {
+        return partyLeaderRef;
+    }
+
+
+    public @NotNull String getPartyName() {
         return partyName.getData().getImmutableCopy();
     }
 
-    public Set<PartyMember> getPartyMembers() {
+    public @NotNull Set<PartyMember> getPartyMembers() {
         return partyMembers;
     }
 
@@ -40,12 +59,11 @@ public class PersistentPartyData {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         PersistentPartyData that = (PersistentPartyData) o;
-        return Objects.equal(getPartyName(), that.getPartyName()) &&
-                Objects.equal(getPartyMembers(), that.getPartyMembers());
+        return partyName.equals(that.partyName) && partyMembers.equals(that.partyMembers) && Objects.equals(partyLeaderRef, that.partyLeaderRef);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(getPartyName(), getPartyMembers());
+        return Objects.hash(partyName, partyMembers, partyLeaderRef);
     }
 }

+ 43 - 0
src/main/java/com/gmail/nossr50/util/player/PartyUtils.java

@@ -3,10 +3,53 @@ package com.gmail.nossr50.util.player;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.party.PartyFeature;
+import com.gmail.nossr50.datatypes.party.PartyMember;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
 import org.jetbrains.annotations.NotNull;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
 public class PartyUtils {
     public static boolean isAllowed(@NotNull Party party, @NotNull PartyFeature partyFeature) {
         return party.getPartyExperienceManager().getLevel() >= Config.getInstance().getPartyFeatureUnlockLevel(partyFeature);
     }
+
+    /**
+     * Makes a formatted list of party members based on the perspective of a target player
+     * Players that are hidden will be shown as offline (formatted in the same way)
+     * Party leader will be formatted a specific way as well
+     *
+     * @param party target party
+     * @param partyMember this player will be used for POV styling
+     * @return formatted list of party members from the POV of a player
+     */
+    public String createMembersList(@NotNull Party party, @NotNull PartyMember partyMember) {
+        StringBuilder memberList = new StringBuilder();
+        List<String> coloredNames = new ArrayList<>();
+
+        //Party member should always be online when this code is executed
+        Player player = partyMember.getOfflinePlayer().getPlayer();
+
+        if(player == null)
+            return "NULL PARTY LIST";
+
+        for(PartyMember otherPartyMember : party.getPartyMembers()) {
+            OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(otherPartyMember.getUniqueId());
+
+            if(offlinePlayer.isOnline() && player.canSee((Player) offlinePlayer)) {
+                ChatColor onlineColor = party.getPartyMemberManager().get.getUniqueId().equals(otherPartyMember.getUniqueId()) ? ChatColor.GOLD : ChatColor.GREEN;
+                coloredNames.add(onlineColor + offlinePlayer.getName());
+            } else {
+                coloredNames.add(ChatColor.DARK_GRAY + members.get(playerUUID));
+            }
+        }
+
+        buildChatMessage(memberList, coloredNames.toArray(new String[0]));
+        return memberList.toString();
+    }
 }