Clean up friends

This commit is contained in:
Sam 2018-08-04 17:04:40 +01:00 committed by Alexander Meech
parent 507e2ef6ba
commit 419a7d685a
18 changed files with 402 additions and 434 deletions

View File

@ -2,27 +2,28 @@ package mineplex.core.friend;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.Comparator;
import java.util.Collections; import java.util.LinkedHashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.plugin.java.JavaPlugin;
import mineplex.core.MiniDbClientPlugin; import mineplex.core.MiniDbClientPlugin;
import mineplex.core.account.CoreClientManager; import mineplex.core.ReflectivelyCreateMiniPlugin;
import mineplex.core.account.permissions.Permission; import mineplex.core.account.permissions.Permission;
import mineplex.core.account.permissions.PermissionGroup; import mineplex.core.account.permissions.PermissionGroup;
import mineplex.core.common.jsonchat.ChildJsonMessage;
import mineplex.core.common.jsonchat.JsonMessage;
import mineplex.core.common.util.C; import mineplex.core.common.util.C;
import mineplex.core.common.util.F; import mineplex.core.common.util.F;
import mineplex.core.common.util.NautHashMap;
import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilServer;
import mineplex.core.common.util.UtilTime; import mineplex.core.common.util.UtilTime;
import mineplex.core.friend.command.AddFriend; import mineplex.core.friend.command.AddFriend;
@ -38,34 +39,73 @@ import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent; import mineplex.core.updater.event.UpdateEvent;
import mineplex.serverdata.data.PlayerStatus; import mineplex.serverdata.data.PlayerStatus;
@ReflectivelyCreateMiniPlugin
public class FriendManager extends MiniDbClientPlugin<FriendData> public class FriendManager extends MiniDbClientPlugin<FriendData>
{ {
public enum Perm implements Permission public enum Perm implements Permission
{ {
FRIEND_COMMAND, FRIEND_COMMAND,
JOIN_STAFF, JOIN_STAFF,
} }
private static FriendSorter _friendSorter = new FriendSorter(); private static final Comparator<FriendStatus> FRIEND_SORTER = (o1, o2) ->
private PreferencesManager _preferenceManager;
private FriendRepository _repository;
private Portal _portal;
public FriendManager(JavaPlugin plugin, CoreClientManager clientManager, PreferencesManager preferences, Portal portal)
{ {
super("Friends", plugin, clientManager); if (o1.Online && !o2.Online)
{
return 1;
}
_preferenceManager = preferences; if (o2.Online && !o1.Online)
_repository = new FriendRepository(plugin); {
_portal = portal; return -1;
}
// If both online we sort by mutual
if (o1.Online)
{
if (o1.Status == FriendStatusType.Accepted && o2.Status != FriendStatusType.Accepted)
{
return 1;
}
else if (o2.Status == FriendStatusType.Accepted && o1.Status != FriendStatusType.Accepted)
{
return -1;
}
if (o1.Name.compareTo(o2.Name) > 0)
{
return 1;
}
else if (o2.Name.compareTo(o1.Name) > 0)
{
return -1;
}
}
return Long.compare(o2.LastSeenOnline, o1.LastSeenOnline);
};
private static final int FRIENDS_PER_CHAT_PAGE = 20;
private final PreferencesManager _preferenceManager;
private final Portal _portal;
private final FriendRepository _repository;
private FriendManager()
{
super("Friends");
_preferenceManager = require(PreferencesManager.class);
_portal = require(Portal.class);
_repository = new FriendRepository();
generatePermissions(); generatePermissions();
} }
private void generatePermissions() private void generatePermissions()
{ {
PermissionGroup.PLAYER.setPermission(Perm.FRIEND_COMMAND, true, true); PermissionGroup.PLAYER.setPermission(Perm.FRIEND_COMMAND, true, true);
PermissionGroup.TRAINEE.setPermission(Perm.JOIN_STAFF, true, true); PermissionGroup.TRAINEE.setPermission(Perm.JOIN_STAFF, true, true);
} }
@ -97,35 +137,34 @@ public class FriendManager extends MiniDbClientPlugin<FriendData>
@EventHandler @EventHandler
public void updateFriends(UpdateEvent event) public void updateFriends(UpdateEvent event)
{ {
if (event.getType() != UpdateType.SLOW || Bukkit.getOnlinePlayers().size() == 0) if (event.getType() != UpdateType.SLOW || UtilServer.getPlayersCollection().isEmpty())
{
return; return;
}
final Player[] onlinePlayers = UtilServer.getPlayers(); final Player[] onlinePlayers = UtilServer.getPlayers();
Bukkit.getServer().getScheduler().runTaskAsynchronously(_plugin, new Runnable() runAsync(() ->
{ {
public void run() final Map<String, FriendData> newData = _repository.getFriendsForAll(onlinePlayers);
{
final NautHashMap<String, FriendData> newData = _repository.getFriendsForAll(onlinePlayers);
Bukkit.getServer().getScheduler().runTask(_plugin, new Runnable() runSync(() ->
{
for (Player player : Bukkit.getOnlinePlayers())
{ {
public void run() FriendData playerData = Get(player);
FriendData newPlayerData = newData.get(player.getUniqueId().toString());
if (newPlayerData != null)
{ {
for (Player player : Bukkit.getOnlinePlayers()) playerData.setFriends(newPlayerData.getFriends());
{
if (newData.containsKey(player.getUniqueId().toString()))
{
Get(player).setFriends(newData.get(player.getUniqueId().toString()).getFriends());
}
else
{
Get(player).getFriends().clear();
}
}
} }
}); else
} {
playerData.getFriends().clear();
}
}
});
}); });
} }
@ -133,11 +172,12 @@ public class FriendManager extends MiniDbClientPlugin<FriendData>
{ {
if (caller.getName().equalsIgnoreCase(name)) if (caller.getName().equalsIgnoreCase(name))
{ {
caller.sendMessage(F.main(getName(), ChatColor.GRAY + "You cannot add yourself as a friend")); caller.sendMessage(F.main(getName(), "You cannot add yourself as a friend"));
return; return;
} }
boolean update = false; boolean update = false;
for (FriendStatus status : Get(caller).getFriends()) for (FriendStatus status : Get(caller).getFriends())
{ {
if (status.Name.equalsIgnoreCase(name)) if (status.Name.equalsIgnoreCase(name))
@ -149,19 +189,17 @@ public class FriendManager extends MiniDbClientPlugin<FriendData>
} }
else if (status.Status == FriendStatusType.Denied) else if (status.Status == FriendStatusType.Denied)
{ {
caller.sendMessage(F.main(getName(), ChatColor.GREEN + name + ChatColor.GRAY caller.sendMessage(F.main(getName(), F.name(name) + " has denied your friend request."));
+ " has denied your friend request."));
return; return;
} }
else if (status.Status == FriendStatusType.Accepted) else if (status.Status == FriendStatusType.Accepted)
{ {
caller.sendMessage(F.main(getName(), "You are already friends with " + ChatColor.GREEN + name)); caller.sendMessage(F.main(getName(), "You are already friends with " + F.name(name)));
return; return;
} }
else if (status.Status == FriendStatusType.Sent) else if (status.Status == FriendStatusType.Sent)
{ {
caller.sendMessage(F.main(getName(), ChatColor.GREEN + name + ChatColor.GRAY caller.sendMessage(F.main(getName(), F.name(name) + " has yet to respond to your friend request."));
+ " has yet to respond to your friend request."));
return; return;
} }
} }
@ -169,238 +207,263 @@ public class FriendManager extends MiniDbClientPlugin<FriendData>
final boolean updateFinal = update; final boolean updateFinal = update;
Bukkit.getServer().getScheduler().runTaskAsynchronously(getPlugin(), new Runnable() runAsync(() ->
{ {
public void run() if (updateFinal)
{ {
if (updateFinal) String statusType = FriendStatusType.Accepted.toString();
{
_repository.updateFriend(caller.getName(), name, "Accepted");
_repository.updateFriend(name, caller.getName(), "Accepted");
Bukkit.getServer().getScheduler().runTask(_plugin, new Runnable() _repository.updateFriend(caller.getName(), name, statusType);
_repository.updateFriend(name, caller.getName(), statusType);
runSync(() ->
{
for (FriendStatus status : Get(caller).getFriends())
{ {
public void run() if (status.Name.equalsIgnoreCase(name))
{ {
for (Iterator<FriendStatus> statusIterator = Get(caller).getFriends().iterator(); statusIterator status.Status = FriendStatusType.Accepted;
.hasNext();) break;
{
FriendStatus status = statusIterator.next();
if (status.Name.equalsIgnoreCase(name))
{
status.Status = FriendStatusType.Accepted;
break;
}
}
} }
});
}
else
{
_repository.addFriend(caller, name);
Bukkit.getServer().getScheduler().runTask(_plugin, new Runnable()
{
public void run()
{
for (Iterator<FriendStatus> statusIterator = Get(caller).getFriends().iterator(); statusIterator
.hasNext();)
{
FriendStatus status = statusIterator.next();
if (status.Name.equalsIgnoreCase(name))
{
status.Status = FriendStatusType.Sent;
break;
}
}
}
});
}
Bukkit.getServer().getScheduler().runTask(_plugin, new Runnable()
{
public void run()
{
if (updateFinal)
caller.sendMessage(F.main(getName(), "You and " + ChatColor.GREEN + name + ChatColor.GRAY
+ " are now friends!"));
else
caller.sendMessage(F.main(getName(), "Added " + ChatColor.GREEN + name + ChatColor.GRAY
+ " to your friends list!"));
} }
}); });
} }
else
{
_repository.addFriend(caller, name);
runSync(() ->
{
for (FriendStatus status : Get(caller).getFriends())
{
if (status.Name.equalsIgnoreCase(name))
{
status.Status = FriendStatusType.Sent;
break;
}
}
});
}
runSync(() ->
{
if (updateFinal)
{
caller.sendMessage(F.main(getName(), "You and " + F.name(name) + " are now friends!"));
}
else
{
caller.sendMessage(F.main(getName(), "Added " + F.name(name) + " to your friends list!"));
}
});
}); });
} }
public void removeFriend(final Player caller, final String name) public void removeFriend(final Player caller, final String name)
{ {
Bukkit.getServer().getScheduler().runTaskAsynchronously(getPlugin(), new Runnable() runAsync(() ->
{ {
public void run() _repository.removeFriend(caller.getName(), name);
_repository.removeFriend(name, caller.getName());
runSync(() ->
{ {
_repository.removeFriend(caller.getName(), name); for (FriendStatus status : Get(caller).getFriends())
_repository.removeFriend(name, caller.getName());
Bukkit.getServer().getScheduler().runTask(_plugin, new Runnable()
{ {
public void run() if (status.Name.equalsIgnoreCase(name))
{ {
for (Iterator<FriendStatus> statusIterator = Get(caller).getFriends().iterator(); statusIterator status.Status = FriendStatusType.Blocked;
.hasNext();) break;
{
FriendStatus status = statusIterator.next();
if (status.Name.equalsIgnoreCase(name))
{
status.Status = FriendStatusType.Blocked;
break;
}
}
caller.sendMessage(F.main(getName(), "Deleted " + ChatColor.GREEN + name + ChatColor.GRAY
+ " from your friends list!"));
} }
}); }
}
caller.sendMessage(F.main(getName(), "Deleted " + F.name(name) + " from your friends list!"));
});
}); });
} }
public void showFriends(Player caller) public void showFriends(Player caller)
{ {
boolean isStaff = ClientManager.Get(caller).hasPermission(Perm.JOIN_STAFF); boolean isStaff = ClientManager.Get(caller).hasPermission(Perm.JOIN_STAFF);
boolean gotAFriend = false; boolean showPending = _preferenceManager.get(caller).isActive(Preference.PENDING_FRIEND_REQUESTS);
List<FriendStatus> friendStatuses = Get(caller).getFriends(); List<FriendStatus> friendStatuses = Get(caller).getFriends();
Collections.sort(friendStatuses, _friendSorter); friendStatuses.sort(FRIEND_SORTER);
caller.sendMessage(C.cAqua + C.Strike + "======================[" + ChatColor.RESET + C.cWhite + C.Bold + "Friends" caller.sendMessage(C.cAqua + C.Strike + "======================[" + C.cWhiteB + "Friends" + C.cAqua + C.Strike + "]======================");
+ ChatColor.RESET + C.cAqua + C.Strike + "]======================");
List<ChildJsonMessage> sentLines = new ArrayList<>(); // Use a LinkedHashMap so we maintain insertion order
List<ChildJsonMessage> pendingLines = new ArrayList<>(); Map<String, TextComponent> messages = new LinkedHashMap<>();
List<ChildJsonMessage> onlineLines = new ArrayList<>(); String joinCommand = "/server ", friendCommand = "/" + AddFriend.COMMAND, unfriendCommand = "/" + DeleteFriend.COMMAND + " ";
List<ChildJsonMessage> offlineLines = new ArrayList<>();
for (FriendStatus friend : friendStatuses) for (FriendStatus friend : friendStatuses)
{ {
if (friend.Status == FriendStatusType.Blocked || friend.Status == FriendStatusType.Denied) FriendStatusType type = friend.Status;
continue;
if (!_preferenceManager.get(caller).isActive(Preference.PENDING_FRIEND_REQUESTS) && friend.Status == FriendStatusType.Pending) if (type == FriendStatusType.Blocked || type == FriendStatusType.Denied || type == FriendStatusType.Pending && !showPending)
continue;
gotAFriend = true;
ChildJsonMessage message = new JsonMessage("").color("white").extra("").color("white");
if (friend.Status == FriendStatusType.Accepted)
{ {
if (friend.Online) continue;
{ }
if (friend.ServerName.contains("Staff") || friend.ServerName.contains("CUST"))
TextComponent message = new TextComponent();
boolean canJoin = canJoin(friend.ServerName, isStaff);
switch (type)
{
case Accepted:
if (friend.Online)
{ {
if (isStaff && friend.ServerName.contains("Staff")) if (canJoin)
message.add("Teleport").color("green").bold().click("run_command", "/server " + friend.ServerName) {
.hover("show_text", "Teleport to " + friend.Name + "'s server."); TextComponent teleport = new TextComponent("Teleport");
teleport.setColor(ChatColor.GREEN);
teleport.setBold(true);
teleport.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("Teleport to " + friend.Name + "'s Server")
.create()));
teleport.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, joinCommand + friend.ServerName));
message.addExtra(teleport);
}
else else
message.add("No Teleport").color("yellow").bold(); {
TextComponent noTeleport = new TextComponent("No Teleport");
noTeleport.setColor(ChatColor.YELLOW);
noTeleport.setBold(true);
noTeleport.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("You cannot teleport to this server")
.create()));
message.addExtra(noTeleport);
}
message.addExtra(" - ");
}
TextComponent delete = new TextComponent("Delete");
delete.setColor(ChatColor.RED);
delete.setBold(true);
delete.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("Remove " + friend.Name + " from your friend list")
.create()));
delete.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, unfriendCommand + friend.Name));
message.addExtra(delete);
TextComponent name = new TextComponent(friend.Name);
name.setColor(friend.Online ? ChatColor.GREEN : ChatColor.GRAY);
message.addExtra(name);
message.addExtra(" - ");
if (friend.Online)
{
if (canJoin)
{
TextComponent server = new TextComponent(friend.ServerName);
server.setColor(ChatColor.DARK_GREEN);
message.addExtra(server);
}
else
{
TextComponent server = new TextComponent("Private Staff Server");
server.setColor(ChatColor.YELLOW);
message.addExtra(server);
}
} }
else else
message.add("Teleport").color("green").bold().click("run_command", "/server " + friend.ServerName)
.hover("show_text", "Teleport to " + friend.Name + "'s server.");
message.add(" - ").color("white");
message.add("Delete").color("red").bold().click("run_command", "/unfriend " + friend.Name)
.hover("show_text", "Remove " + friend.Name + " from your friends list.");
message.add(" - ").color("white");
message.add(friend.Name).color(friend.Online ? "green" : "gray");
message.add(" - ").color("white");
if (friend.ServerName.contains("Staff") || friend.ServerName.contains("CUST"))
{ {
if (isStaff && friend.ServerName.contains("Staff")) TextComponent offlineFor = new TextComponent("Offline for " + UtilTime.MakeStr(friend.LastSeenOnline));
message.add(friend.ServerName).color("dark_green"); offlineFor.setColor(ChatColor.GRAY);
else message.addExtra(offlineFor);
message.add("Private Staff Server").color("dark_green");
} }
else
message.add(friend.ServerName).color("dark_green");
onlineLines.add(message); break;
} case Pending:
// Offline Friend TextComponent accept = new TextComponent("Accept");
else accept.setColor(ChatColor.GREEN);
{ accept.setBold(true);
message.add("Delete").color("red").bold().click("run_command", "/unfriend " + friend.Name) accept.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("Accept " + friend.Name + "'s friend request")
.hover("show_text", "Remove " + friend.Name + " from your friends list."); .create()));
message.add(" - ").color("white"); accept.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, friendCommand + friend.Name));
message.add(friend.Name).color(friend.Online ? "green" : "gray"); message.addExtra(accept);
message.add(" - ").color("white");
message.add("Offline for ").color("gray").add(UtilTime.MakeStr(friend.LastSeenOnline)).color("gray");
offlineLines.add(message); message.addExtra(" - ");
}
TextComponent deny = new TextComponent("Deny");
deny.setColor(ChatColor.RED);
deny.setBold(true);
deny.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("Deny " + friend.Name + "'s friend request")
.create()));
deny.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, unfriendCommand + friend.Name));
message.addExtra(deny);
message.addExtra(" - ");
TextComponent request = new TextComponent(friend.Name + " Requested Friendship");
request.setColor(ChatColor.GRAY);
message.addExtra(request);
break;
case Sent:
TextComponent cancel = new TextComponent("Cancel");
cancel.setColor(ChatColor.RED);
cancel.setBold(true);
cancel.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("Cancel your friend request to " + friend.Name)
.create()));
cancel.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, unfriendCommand + friend.Name));
message.addExtra(cancel);
break;
} }
// Pending
else if (friend.Status == FriendStatusType.Pending)
{
message.add("Accept").color("green").bold().click("run_command", "/friend " + friend.Name)
.hover("show_text", "Accept " + friend.Name + "'s friend request.");
message.add(" - ").color("white");
message.add("Deny").color("red").bold().click("run_command", "/unfriend " + friend.Name)
.hover("show_text", "Deny " + friend.Name + "'s friend request.");
message.add(" - ").color("white");
message.add(friend.Name + " Requested Friendship").color("gray");
pendingLines.add(message); messages.put(friend.Name, message);
}
// Sent
else if (friend.Status == FriendStatusType.Sent)
{
message.add("Cancel").color("red").bold().click("run_command", "/unfriend " + friend.Name)
.hover("show_text", "Cancel friend request to " + friend.Name);
message.add(" - ").color("white");
message.add(friend.Name + " Friendship Request").color("gray");
sentLines.add(message);
}
} }
// Send In Order if (messages.isEmpty())
for (JsonMessage msg : sentLines)
msg.sendToPlayer(caller);
for (JsonMessage msg : offlineLines)
msg.sendToPlayer(caller);
for (JsonMessage msg : pendingLines)
msg.sendToPlayer(caller);
for (JsonMessage msg : onlineLines)
msg.sendToPlayer(caller);
if (!gotAFriend)
{ {
caller.sendMessage(" "); caller.sendMessage(" ");
caller.sendMessage("Welcome to your Friends List!"); caller.sendMessage("Welcome to your Friends List!");
caller.sendMessage(" "); caller.sendMessage(" ");
caller.sendMessage("To add friends, type " + C.cGreen + "/friend <Player Name>"); caller.sendMessage("To add friends, type " + C.cGreen + "/friend <Player Name>");
caller.sendMessage(" "); caller.sendMessage(" ");
caller.sendMessage("Type " + C.cGreen + "/friend" + ChatColor.RESET + " at any time to interact with your friends!"); caller.sendMessage("Type " + C.cGreen + "/friend" + C.Reset + " at any time to interact with your friends!");
caller.sendMessage(" "); caller.sendMessage(" ");
} }
else
{
messages.values().forEach(textComponent -> caller.spigot().sendMessage(textComponent));
}
ChildJsonMessage message = new JsonMessage("").extra(C.cAqua + C.Strike + "======================"); TextComponent toggle = new TextComponent();
message.add(C.cDAqua + "Toggle GUI").click("run_command", "/friendsdisplay"); TextComponent line = new TextComponent("======================");
line.setColor(ChatColor.AQUA);
line.setStrikethrough(true);
message.hover("show_text", C.cAqua + "Toggle friends to display in an inventory"); TextComponent command = new TextComponent("Toggle GUI");
command.setColor(ChatColor.DARK_AQUA);
command.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("Toggle friends to display in an inventory")
.create()));
command.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/" + FriendsDisplay.COMMAND));
message.add(C.cAqua + C.Strike + "======================"); toggle.addExtra(line);
toggle.addExtra(command);
toggle.addExtra(line);
message.sendToPlayer(caller); caller.spigot().sendMessage(toggle);
}
private boolean canJoin(String serverName, boolean isPlayerStaff)
{
if (serverName == null)
{
return false;
}
boolean staff = serverName.startsWith("Staff"), cust = serverName.startsWith("CUST");
if (staff)
{
return isPlayerStaff;
}
return !cust;
} }
public boolean isFriends(Player player, String friend) public boolean isFriends(Player player, String friend)
@ -418,7 +481,6 @@ public class FriendManager extends MiniDbClientPlugin<FriendData>
return false; return false;
} }
public void updatePlayerStatus(UUID playerUUID, PlayerStatus status) public void updatePlayerStatus(UUID playerUUID, PlayerStatus status)
{ {
_repository.updatePlayerStatus(playerUUID, status); _repository.updatePlayerStatus(playerUUID, status);
@ -438,7 +500,6 @@ public class FriendManager extends MiniDbClientPlugin<FriendData>
@Override @Override
public String getQuery(int accountId, String uuid, String name) public String getQuery(int accountId, String uuid, String name)
{ {
return "SELECT tA.Name, status, tA.lastLogin, now(), uuidTarget FROM accountFriend INNER Join accounts AS fA ON fA.uuid = uuidSource INNER JOIN accounts AS tA ON tA.uuid = uuidTarget WHERE uuidSource = '" return "SELECT tA.Name, status, tA.lastLogin, now(), uuidTarget, favourite, " + FriendRepository.GET_VISIBILITY_QUERY + " FROM accountFriend INNER JOIN accounts AS fA ON fA.uuid = uuidSource INNER JOIN accounts AS tA ON tA.uuid = uuidTarget WHERE uuidSource = '" + uuid + "';";
+ uuid + "';";
} }
} }

View File

@ -1,43 +0,0 @@
package mineplex.core.friend;
import java.util.Comparator;
import mineplex.core.friend.data.FriendStatus;
public class FriendSorter implements Comparator<FriendStatus>
{
public int compare(FriendStatus a, FriendStatus b)
{
if (a.Online && !b.Online)
{
return 1;
}
if (b.Online && !a.Online)
{
return -1;
}
// If online we sort by mutual
if (a.Online && b.Online)
{
if (a.Status == FriendStatusType.Accepted && b.Status != FriendStatusType.Accepted)
return 1;
else if (b.Status == FriendStatusType.Accepted && a.Status != FriendStatusType.Accepted)
return -1;
if (a.Name.compareTo(b.Name) > 0)
return 1;
else if (b.Name.compareTo(a.Name) > 0)
return -1;
}
if (a.LastSeenOnline < b.LastSeenOnline)
return 1;
if (b.LastSeenOnline < a.LastSeenOnline)
return -1;
return 0;
}
}

View File

@ -0,0 +1,10 @@
package mineplex.core.friend;
public enum FriendVisibility
{
SHOWN,
PRESENCE,
HIDDEN
}

View File

@ -12,9 +12,12 @@ import mineplex.core.preferences.Preference;
public class AddFriend extends CommandBase<FriendManager> public class AddFriend extends CommandBase<FriendManager>
{ {
public static final String COMMAND = "friend";
public AddFriend(FriendManager plugin) public AddFriend(FriendManager plugin)
{ {
super(plugin, FriendManager.Perm.FRIEND_COMMAND, "friends", "friend", "f"); super(plugin, FriendManager.Perm.FRIEND_COMMAND, "friends", COMMAND, "f");
} }
@Override @Override

View File

@ -9,26 +9,28 @@ import mineplex.core.friend.FriendManager;
public class DeleteFriend extends CommandBase<FriendManager> public class DeleteFriend extends CommandBase<FriendManager>
{ {
public static final String COMMAND = "unfriend";
public DeleteFriend(FriendManager plugin) public DeleteFriend(FriendManager plugin)
{ {
super(plugin, FriendManager.Perm.FRIEND_COMMAND, "unfriend"); super(plugin, FriendManager.Perm.FRIEND_COMMAND, COMMAND);
} }
@Override @Override
public void Execute(final Player caller, final String[] args) public void Execute(final Player caller, final String[] args)
{ {
if (args == null) if (args == null)
F.main(Plugin.getName(), "You need to include a player's name."); {
caller.sendMessage(F.main(Plugin.getName(), "You need to include a player's name."));
}
else else
{ {
_commandCenter.GetClientManager().checkPlayerName(caller, args[0], new Callback<String>() _commandCenter.GetClientManager().checkPlayerName(caller, args[0], result ->
{ {
public void run(String result) if (result != null)
{ {
if (result != null) Plugin.removeFriend(caller, result);
{
Plugin.removeFriend(caller, result);
}
} }
}); });
} }

View File

@ -11,9 +11,12 @@ import mineplex.core.preferences.UserPreferences;
public class FriendsDisplay extends CommandBase<FriendManager> public class FriendsDisplay extends CommandBase<FriendManager>
{ {
public static final String COMMAND = "friendsdisplay";
public FriendsDisplay(FriendManager plugin) public FriendsDisplay(FriendManager plugin)
{ {
super(plugin, FriendManager.Perm.FRIEND_COMMAND, "friendsdisplay"); super(plugin, FriendManager.Perm.FRIEND_COMMAND, COMMAND);
} }
@Override @Override

View File

@ -9,39 +9,36 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mineplex.core.database.MinecraftRepository;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import mineplex.core.common.util.NautHashMap;
import mineplex.serverdata.database.DBPool;
import mineplex.serverdata.database.RepositoryBase;
import mineplex.serverdata.database.ResultSetCallable;
import mineplex.serverdata.database.column.ColumnVarChar;
import mineplex.core.friend.FriendStatusType; import mineplex.core.friend.FriendStatusType;
import mineplex.core.friend.FriendVisibility;
import mineplex.serverdata.Region; import mineplex.serverdata.Region;
import mineplex.serverdata.data.DataRepository; import mineplex.serverdata.data.DataRepository;
import mineplex.serverdata.data.PlayerStatus; import mineplex.serverdata.data.PlayerStatus;
import mineplex.serverdata.database.DBPool;
import mineplex.serverdata.database.RepositoryBase;
import mineplex.serverdata.database.column.ColumnVarChar;
import mineplex.serverdata.redis.RedisDataRepository; import mineplex.serverdata.redis.RedisDataRepository;
import mineplex.serverdata.servers.ServerManager;
public class FriendRepository extends RepositoryBase public class FriendRepository extends RepositoryBase
{ {
private static String CREATE_FRIEND_TABLE = "CREATE TABLE IF NOT EXISTS accountFriend (id INT NOT NULL AUTO_INCREMENT, uuidSource VARCHAR(100), uuidTarget VARCHAR(100), status VARCHAR(100), PRIMARY KEY (id), UNIQUE INDEX uuidIndex (uuidSource, uuidTarget));";
private static String RETRIEVE_MULTIPLE_FRIEND_RECORDS = "SELECT uuidSource, tA.Name, status, tA.lastLogin, now(), uuidTarget FROM accountFriend INNER Join accounts AS fA ON fA.uuid = uuidSource INNER JOIN accounts AS tA ON tA.uuid = uuidTarget WHERE uuidSource IN "; private static final String CREATE_FRIEND_TABLE = "CREATE TABLE IF NOT EXISTS accountFriend (id INT NOT NULL AUTO_INCREMENT, uuidSource VARCHAR(100), uuidTarget VARCHAR(100), status VARCHAR(100), PRIMARY KEY (id), UNIQUE INDEX uuidIndex (uuidSource, uuidTarget));";
private static String ADD_FRIEND_RECORD = "INSERT INTO accountFriend (uuidSource, uuidTarget, status, created) SELECT fA.uuid AS uuidSource, tA.uuid AS uuidTarget, ?, now() FROM accounts as fA LEFT JOIN accounts AS tA ON tA.name = ? WHERE fA.name = ?;"; public static final String GET_VISIBILITY_QUERY = "(SELECT accountFriendData.status FROM accountFriendData WHERE accountId = tA.id) AS visibility";
private static String UPDATE_MUTUAL_RECORD = "UPDATE accountFriend AS aF INNER JOIN accounts as fA ON aF.uuidSource = fA.uuid INNER JOIN accounts AS tA ON aF.uuidTarget = tA.uuid SET aF.status = ? WHERE tA.name = ? AND fA.name = ?;"; private static final String RETRIEVE_MULTIPLE_FRIEND_RECORDS = "SELECT uuidSource, tA.Name, status, tA.lastLogin, now(), uuidTarget, favourite, " + GET_VISIBILITY_QUERY + " FROM accountFriend INNER Join accounts AS fA ON fA.uuid = uuidSource INNER JOIN accounts AS tA ON tA.uuid = uuidTarget WHERE uuidSource IN ";
private static String DELETE_FRIEND_RECORD = "DELETE aF FROM accountFriend AS aF INNER JOIN accounts as fA ON aF.uuidSource = fA.uuid INNER JOIN accounts AS tA ON aF.uuidTarget = tA.uuid WHERE fA.name = ? AND tA.name = ?;"; private static final String ADD_FRIEND_RECORD = "INSERT INTO accountFriend (uuidSource, uuidTarget, status, created) SELECT fA.uuid AS uuidSource, tA.uuid AS uuidTarget, ?, now() FROM accounts as fA LEFT JOIN accounts AS tA ON tA.name = ? WHERE fA.name = ?;";
private static final String UPDATE_MUTUAL_RECORD = "UPDATE accountFriend AS aF INNER JOIN accounts as fA ON aF.uuidSource = fA.uuid INNER JOIN accounts AS tA ON aF.uuidTarget = tA.uuid SET aF.status = ? WHERE tA.name = ? AND fA.name = ?;";
private static final String DELETE_FRIEND_RECORD = "DELETE aF FROM accountFriend AS aF INNER JOIN accounts as fA ON aF.uuidSource = fA.uuid INNER JOIN accounts AS tA ON aF.uuidTarget = tA.uuid WHERE fA.name = ? AND tA.name = ?;";
// Repository holding active PlayerStatus data. // Repository holding active PlayerStatus data.
private DataRepository<PlayerStatus> _repository; private final DataRepository<PlayerStatus> _repository;
public FriendRepository(JavaPlugin plugin) public FriendRepository()
{ {
super(DBPool.getAccount()); super(DBPool.getAccount());
_repository = new RedisDataRepository<PlayerStatus>(ServerManager.getMasterConnection(), ServerManager.getSlaveConnection(), _repository = new RedisDataRepository<>(Region.currentRegion(), PlayerStatus.class, "playerStatus");
Region.currentRegion(), PlayerStatus.class, "playerStatus");
} }
public boolean addFriend(final Player caller, String name) public boolean addFriend(final Player caller, String name)
@ -69,49 +66,49 @@ public class FriendRepository extends RepositoryBase
return false; return false;
} }
public NautHashMap<String, FriendData> getFriendsForAll(Player...players) public Map<String, FriendData> getFriendsForAll(Player... players)
{ {
final NautHashMap<String, FriendData> friends = new NautHashMap<String, FriendData>(); final Map<String, FriendData> friends = new HashMap<>();
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(RETRIEVE_MULTIPLE_FRIEND_RECORDS + "("); stringBuilder.append(RETRIEVE_MULTIPLE_FRIEND_RECORDS).append("(");
for (Player player : players) for (Player player : players)
{ {
stringBuilder.append("'" + player.getUniqueId() + "', "); stringBuilder
.append("'")
.append(player.getUniqueId())
.append("', ");
} }
stringBuilder.delete(stringBuilder.length() - 2, stringBuilder.length()); stringBuilder.delete(stringBuilder.length() - 2, stringBuilder.length());
stringBuilder.append(");"); stringBuilder.append(");");
executeQuery(stringBuilder.toString(), new ResultSetCallable() executeQuery(stringBuilder.toString(), resultSet ->
{ {
public void processResultSet(ResultSet resultSet) throws SQLException Set<FriendData> friendDatas = new HashSet<>();
while (resultSet.next())
{ {
Set<FriendData> friendDatas = new HashSet<FriendData>(); FriendStatus friend = new FriendStatus();
while (resultSet.next())
{
FriendStatus friend = new FriendStatus();
String uuidSource = resultSet.getString(1); String uuidSource = resultSet.getString(1);
friend.Name = resultSet.getString(2); friend.Name = resultSet.getString(2);
friend.Status = Enum.valueOf(FriendStatusType.class, resultSet.getString(3)); friend.Status = FriendStatusType.valueOf(resultSet.getString(3));
friend.LastSeenOnline = resultSet.getTimestamp(5).getTime() - resultSet.getTimestamp(4).getTime(); friend.LastSeenOnline = resultSet.getTimestamp(5).getTime() - resultSet.getTimestamp(4).getTime();
friend.UUID = UUID.fromString(resultSet.getString(6)); friend.UUID = UUID.fromString(resultSet.getString(6));
friend.Visibility = FriendVisibility.values()[resultSet.getByte("visibility")];
friend.Favourite = resultSet.getBoolean("favourite");
if (!friends.containsKey(uuidSource)) FriendData data = friends.computeIfAbsent(uuidSource, k -> new FriendData());
friends.put(uuidSource, new FriendData()); data.getFriends().add(friend);
friendDatas.add(data);
}
friends.get(uuidSource).getFriends().add(friend); // Load the server status of friends for all sources.
for (FriendData friendData : friendDatas)
friendDatas.add(friends.get(uuidSource)); {
} loadFriendStatuses(friendData);
// Load the server status of friends for all sources.
for(FriendData friendData : friendDatas)
{
loadFriendStatuses(friendData);
}
} }
}); });
@ -127,11 +124,13 @@ public class FriendRepository extends RepositoryBase
FriendStatus friend = new FriendStatus(); FriendStatus friend = new FriendStatus();
friend.Name = resultSet.getString(1); friend.Name = resultSet.getString(1);
friend.Status = Enum.valueOf(FriendStatusType.class, resultSet.getString(2)); friend.Status = FriendStatusType.valueOf(resultSet.getString(2));
friend.LastSeenOnline = resultSet.getTimestamp(4).getTime() - resultSet.getTimestamp(3).getTime(); friend.LastSeenOnline = resultSet.getTimestamp(4).getTime() - resultSet.getTimestamp(3).getTime();
friend.UUID = UUID.fromString(resultSet.getString(5)); friend.UUID = UUID.fromString(resultSet.getString(5));
friend.ServerName = null; friend.ServerName = null;
friend.Online = (friend.ServerName != null); friend.Online = false;
friend.Visibility = FriendVisibility.values()[resultSet.getByte("visibility")];
friend.Favourite = resultSet.getBoolean("favourite");
friendData.getFriends().add(friend); friendData.getFriends().add(friend);
} }
@ -142,14 +141,15 @@ public class FriendRepository extends RepositoryBase
/** /**
* Load the server status information for a list of {@link FriendStatus}. * Load the server status information for a list of {@link FriendStatus}.
*
* @param friendData - the {@link FriendStatus} object friends server status' are to be updated * @param friendData - the {@link FriendStatus} object friends server status' are to be updated
* @param statuses - the fetched {@link PlayerStatus} associated with all online {@code friends}.
*/ */
public void loadFriendStatuses(FriendData friendData) public void loadFriendStatuses(FriendData friendData)
{ {
// Generate a set of all friend names // Generate a set of all friend names
Set<String> friendUUIDS = new HashSet<>(); Set<String> friendUUIDS = new HashSet<>();
for(FriendStatus status : friendData.getFriends())
for (FriendStatus status : friendData.getFriends())
{ {
friendUUIDS.add(status.UUID.toString()); friendUUIDS.add(status.UUID.toString());
} }
@ -159,7 +159,8 @@ public class FriendRepository extends RepositoryBase
// Load player statuses into a mapping // Load player statuses into a mapping
Map<UUID, PlayerStatus> playerStatuses = new HashMap<>(); Map<UUID, PlayerStatus> playerStatuses = new HashMap<>();
for(PlayerStatus status : statuses)
for (PlayerStatus status : statuses)
{ {
playerStatuses.put(status.getUUID(), status); playerStatuses.put(status.getUUID(), status);
} }
@ -173,18 +174,6 @@ public class FriendRepository extends RepositoryBase
} }
} }
/**
* @param playerName - the name of the player whose current server status is being fetched
* @return the name that the player matching {@code playerName}
* is currently online on, if they are online, null otherwise.
*/
public String fetchPlayerServer(UUID playerUUID)
{
PlayerStatus status = _repository.getElement(playerUUID.toString());
return (status == null) ? null : status.getServer();
}
public void updatePlayerStatus(UUID playerUUID, PlayerStatus status) public void updatePlayerStatus(UUID playerUUID, PlayerStatus status)
{ {
if (status != null) if (status != null)

View File

@ -3,6 +3,7 @@ package mineplex.core.friend.data;
import java.util.UUID; import java.util.UUID;
import mineplex.core.friend.FriendStatusType; import mineplex.core.friend.FriendStatusType;
import mineplex.core.friend.FriendVisibility;
public class FriendStatus public class FriendStatus
{ {
@ -15,4 +16,6 @@ public class FriendStatus
*/ */
public long LastSeenOnline; public long LastSeenOnline;
public FriendStatusType Status; public FriendStatusType Status;
public FriendVisibility Visibility;
public boolean Favourite;
} }

View File

@ -1,24 +0,0 @@
package mineplex.core.friend.redis;
import mineplex.serverdata.commands.ServerCommand;
public class DeleteFriend extends ServerCommand
{
private String _deleter;
private String _deleted;
public String getDeleter() { return _deleter; }
public String getDeleted() { return _deleted; }
public DeleteFriend(String deleter, String deleted)
{
_deleter = deleter;
_deleted = deleted;
}
@Override
public void run()
{
// Utilitizes a callback functionality to seperate dependencies
}
}

View File

@ -1,6 +0,0 @@
package mineplex.core.friend.redis;
public class DeleteFriendHandler
{
}

View File

@ -1,24 +0,0 @@
package mineplex.core.friend.redis;
import mineplex.serverdata.commands.ServerCommand;
public class FriendRequest extends ServerCommand
{
private String _requester;
private String _requested;
public String getRequester() { return _requester; }
public String getRequested() { return _requested; }
public FriendRequest(String requester, String requested)
{
_requester = requester;
_requested = requested;
}
@Override
public void run()
{
// Utilitizes a callback functionality to seperate dependencies
}
}

View File

@ -1,6 +0,0 @@
package mineplex.core.friend.redis;
public class FriendRequestHandler
{
}

View File

@ -162,7 +162,7 @@ public class Clans extends JavaPlugin
EloManager eloManager = new EloManager(this, _clientManager); EloManager eloManager = new EloManager(this, _clientManager);
AchievementManager achievementManager = new AchievementManager(statsManager, _clientManager, _donationManager, incognito, eloManager); AchievementManager achievementManager = new AchievementManager(statsManager, _clientManager, _donationManager, incognito, eloManager);
Chat chat = new Chat(); Chat chat = new Chat();
new MessageManager(this, incognito, _clientManager, preferenceManager, ignoreManager, punish, new FriendManager(this, _clientManager, preferenceManager, portal), chat); new MessageManager(this, incognito, _clientManager, preferenceManager, ignoreManager, punish, require(FriendManager.class), chat);
new MemoryFix(this); new MemoryFix(this);
new FoodDupeFix(this); new FoodDupeFix(this);

View File

@ -140,7 +140,7 @@ public class ClansHub extends JavaPlugin
IgnoreManager ignoreManager = new IgnoreManager(this, clientManager, preferenceManager, portal); IgnoreManager ignoreManager = new IgnoreManager(this, clientManager, preferenceManager, portal);
FriendManager friendManager = new FriendManager(this, clientManager, preferenceManager, portal); FriendManager friendManager = require(FriendManager.class);
StatsManager statsManager = new StatsManager(this, clientManager); StatsManager statsManager = new StatsManager(this, clientManager);
EloManager eloManager = new EloManager(this, clientManager); EloManager eloManager = new EloManager(this, clientManager);

View File

@ -138,7 +138,7 @@ public class Hub extends JavaPlugin implements IRelation
IgnoreManager ignoreManager = new IgnoreManager(this, clientManager, preferenceManager, portal); IgnoreManager ignoreManager = new IgnoreManager(this, clientManager, preferenceManager, portal);
FriendManager friendManager = new FriendManager(this, clientManager, preferenceManager, portal); FriendManager friendManager = require(FriendManager.class);
StatsManager statsManager = new StatsManager(this, clientManager); StatsManager statsManager = new StatsManager(this, clientManager);
EloManager eloManager = new EloManager(this, clientManager); EloManager eloManager = new EloManager(this, clientManager);

View File

@ -164,7 +164,7 @@ public class Arcade extends JavaPlugin
StatsManager statsManager = new StatsManager(this, clientManager); StatsManager statsManager = new StatsManager(this, clientManager);
EloManager eloManager = new EloManager(this, clientManager); EloManager eloManager = new EloManager(this, clientManager);
AchievementManager achievementManager = new AchievementManager(statsManager, clientManager, donationManager, incognito, eloManager); AchievementManager achievementManager = new AchievementManager(statsManager, clientManager, donationManager, incognito, eloManager);
FriendManager friendManager = new FriendManager(this, clientManager, preferenceManager, portal); FriendManager friendManager = require(FriendManager.class);
Chat chat = new Chat(); Chat chat = new Chat();
new MessageManager(this, incognito, clientManager, preferenceManager, ignoreManager, punish, friendManager, chat); new MessageManager(this, incognito, clientManager, preferenceManager, ignoreManager, punish, friendManager, chat);

View File

@ -113,7 +113,7 @@ public class Hub extends JavaPlugin
StatsManager statsManager = new StatsManager(this, _clientManager); StatsManager statsManager = new StatsManager(this, _clientManager);
EloManager eloManager = new EloManager(this, _clientManager); EloManager eloManager = new EloManager(this, _clientManager);
AchievementManager achievementManager = new AchievementManager(statsManager, _clientManager, _donationManager, incognito, eloManager); AchievementManager achievementManager = new AchievementManager(statsManager, _clientManager, _donationManager, incognito, eloManager);
FriendManager friendManager = new FriendManager(this, _clientManager, preferenceManager, portal); FriendManager friendManager = require(FriendManager.class);
Chat chat = new Chat(); Chat chat = new Chat();
new MessageManager(this, incognito, _clientManager, preferenceManager, ignoreManager, punish, friendManager, chat); new MessageManager(this, incognito, _clientManager, preferenceManager, ignoreManager, punish, friendManager, chat);

View File

@ -211,7 +211,7 @@ public class GemHunters extends JavaPlugin
// Chat/Messaging // Chat/Messaging
Chat chat = new Chat(); Chat chat = new Chat();
new MessageManager(this, incognito, clientManager, preferenceManager, ignoreManager, punish, new FriendManager(this, clientManager, preferenceManager, portal), chat); new MessageManager(this, incognito, clientManager, preferenceManager, ignoreManager, punish, require(FriendManager.class), chat);
// Parties // Parties
new PartyManager(); new PartyManager();