From 0234cf0f744c4c1819f29e9d00c3a25d05dbc2ce Mon Sep 17 00:00:00 2001 From: Dan Mulloy Date: Sun, 14 Jan 2018 10:22:34 -0500 Subject: [PATCH] Fix community servers and the browser --- .../mineplex/core/communities/Community.java | 40 +++++++----- .../core/communities/CommunityManager.java | 64 +++++++++++++++---- .../core/communities/CommunitySetting.java | 7 +- .../communities/gui/CommunitiesGUIPage.java | 6 +- .../gui/browser/CommunityBrowserPage.java | 22 ++++++- .../storage/CommunityRepository.java | 58 ++++++++++++++++- 6 files changed, 161 insertions(+), 36 deletions(-) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/Community.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/Community.java index 0136473fc..048ee7210 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/communities/Community.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/Community.java @@ -1,5 +1,7 @@ package mineplex.core.communities; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -21,9 +23,9 @@ public class Community private long _chatDelay; private GameDisplay _favoriteGame; private PrivacySetting _privacy; + private boolean _showInBrowser; - private transient boolean unloaded = false; - private transient boolean persist = false; + private transient List flags = new ArrayList<>(); public Community(int id, String name) { @@ -110,7 +112,20 @@ public class Community { _privacy = privacy; } - + + public boolean isBrowserFlagSet() + { + return _showInBrowser; + } + + /** + * We don't actually care if they should be shown in the browser, just that the flag has been set + */ + public void setBrowserFlag() + { + _showInBrowser = true; + } + public void sendChat(String chat) { getMembers().values().stream().filter(info -> info.ReadingChat).forEach(member -> UtilPlayer.message(Bukkit.getPlayer(member.UUID), chat)); @@ -126,26 +141,17 @@ public class Community getMembers().values().stream().filter(member -> member.Role.ordinal() <= minimumRole.ordinal()).forEach(member -> UtilPlayer.message(Bukkit.getPlayer(member.UUID), message)); } - public void markUnloaded() + public void setFlag(String flag, boolean value) { - this.unloaded = true; + if (value) flags.add(flag.toLowerCase()); + else flags.remove(flag.toLowerCase()); } - public boolean isUnloaded() + public boolean getFlag(String flag) { - return unloaded; + return flags.contains(flag.toLowerCase()); } - public void persist() - { - this.persist = persist; - } - - public boolean isPersistent() - { - return persist; - } - public static enum PrivacySetting { OPEN("Open to Join"), diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityManager.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityManager.java index f9aca1fa2..e128d6004 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunityManager.java @@ -9,12 +9,15 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.Random; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; import java.util.stream.Collectors; +import com.google.common.collect.Sets; + import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -103,10 +106,13 @@ public class CommunityManager extends MiniDbClientPlugin private final int CACHE_INVALIDATION_SECONDS = 300; // The number of seconds between full communities refreshes public final Pattern ALPHA_NUMERIC_PATTERN = Pattern.compile("[^A-Za-z0-9]"); public final String[] BLOCKED_NAMES = new String[] {"help", "chat", "create", "description", "disband", "invite", "join", "mcs", "rename", "uninvite", "trainee", "mod", "moderator", "srmod", "seniormod", "seniormoderator", "builder", "maplead", "twitch", "youtube", "support", "admin", "administrator", "leader", "dev", "developer", "owner", "party", "mineplex", "mineplexOfficial", "staff", "mineplexstaff", "qualityassurance", "traineemanagement", "modcoordination", "forumninja", "communitymanagement", "event", "socialmedia"}; + private final CommunityRepository _repo; private final Map _loadedCommunities; - public final List BrowserIds = new LinkedList<>(); + private final Random rand = new Random(); + private final List _browserIds = new LinkedList<>(); + private final List _creating = new ArrayList<>(); // private final DataRepository StatusRepository; @@ -135,6 +141,8 @@ public class CommunityManager extends MiniDbClientPlugin _loadedCommunities = new ConcurrentHashMap<>(); + runAsync(() -> _repo.loadBrowserCommunities(_browserIds)); + _clientManager = require(CoreClientManager.class); _clientManager.addStoredProcedureLoginProcessor(new ILoginProcessor() { @@ -180,7 +188,7 @@ public class CommunityManager extends MiniDbClientPlugin _updateCycleCount = 0; // Make sure to include communities that should be unloaded after their update - dirty.stream().filter(Community::isUnloaded).forEach(communities::add); + dirty.stream().filter(com -> com.getFlag("unloaded")).forEach(communities::add); dirty.clear(); communities.addAll(_loadedCommunities.values()); @@ -222,7 +230,7 @@ public class CommunityManager extends MiniDbClientPlugin if (community == null) community = _repo.loadCommunity(_loadedCommunities, comId); - community.persist(); + community.setFlag("persist", true); } generatePermissions(); @@ -265,21 +273,49 @@ public class CommunityManager extends MiniDbClientPlugin _cycling = true; runAsync(() -> { - final List ids = new LinkedList<>(); - _loadedCommunities.values().stream().filter(c -> c.getMembers().size() >= 5 && c.getPrivacySetting() != PrivacySetting.PRIVATE).forEach(c -> ids.add(c.getId())); - - Collections.shuffle(ids); + Collections.shuffle(_browserIds, rand); runSync(() -> { - BrowserIds.clear(); - BrowserIds.addAll(ids); _cycling = false; UtilServer.CallEvent(new CommunityBrowserUpdateEvent()); }); }); } + public List getBrowserIds() + { + return _browserIds; + } + + public void loadCommunitiesForDisplay(List communities) + { + List load = communities.stream().filter(com -> getLoadedCommunity(com) == null).collect(Collectors.toList()); + _repo.loadCommunities(_loadedCommunities, load); + + for (int id : load) + { + Community com = _loadedCommunities.get(id); + if (com != null) + com.setFlag("display", true); + } + } + + public void unloadDisplayCommunities(List unload) + { + unload.stream().filter(com -> + { + Community community = getLoadedCommunity(com); + return community == null || (community.getFlag("display") && !community.getFlag("persist")); + }).forEach(_loadedCommunities::remove); + } + + public void updateBrowserStatus(Community community) + { + _repo.updateBrowserStatus(community, community.getPrivacySetting() != PrivacySetting.PRIVATE + && community.getMembers().size() >= 5); + } + public int getCount() { return _loadedCommunities.size(); @@ -531,7 +567,7 @@ public class CommunityManager extends MiniDbClientPlugin _loadedCommunities.remove(community.getId()); runSync(() -> { - if (BrowserIds.remove(community.getId())) + if (_browserIds.remove(community.getId())) { UtilServer.CallEvent(new CommunityBrowserUpdateEvent()); } @@ -675,6 +711,7 @@ public class CommunityManager extends MiniDbClientPlugin { _repo.deleteInviteToCommunity(community.getId(), playerName); } + updateBrowserStatus(community); }); new CommunityUpdateMembership(community.getId(), sender.getName(), sender.getName(), sender.getUniqueId().toString(), accountId, false, false).publish(); if (fromInvite) @@ -697,6 +734,7 @@ public class CommunityManager extends MiniDbClientPlugin runAsync(() -> { _repo.removeFromCommunity(info.AccountId, community.getId()); + updateBrowserStatus(community); }); new CommunityUpdateMembership(community.getId(), sender.getName(), info.Name, info.UUID.toString(), info.AccountId, false, true).publish(); } @@ -706,6 +744,8 @@ public class CommunityManager extends MiniDbClientPlugin runAsync(() -> { _repo.updateCommunitySetting(setting, community.getId(), newValue); + if (setting == CommunitySetting.PRIVACY) + updateBrowserStatus(community); }); new CommunityUpdateSetting(community.getId(), sender.getName(), setting.toString(), newValue).publish(); } @@ -876,14 +916,14 @@ public class CommunityManager extends MiniDbClientPlugin List communities = Get(player).getCommunities(); for (Community community : communities) { - if (community.isPersistent() + if (community.getFlag("persist") || community.getMembers().keySet().stream().anyMatch(uuid -> !player.getUniqueId().equals(uuid) && Bukkit.getPlayer(uuid) != null)) continue; System.out.println("Unloading community: " + community.getId()); // Unload this community from memory - community.markUnloaded(); + community.setFlag("unloaded", true); _loadedCommunities.remove(community.getId()); } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunitySetting.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunitySetting.java index fc049ac5e..1ae99bbbc 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunitySetting.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/CommunitySetting.java @@ -88,7 +88,12 @@ public enum CommunitySetting Community community = pair.getRight(); community.setDescription(value); - }); + }), + SHOW_IN_BROWSER(8, pair -> + { + pair.getRight().setBrowserFlag(); + }), + ; private int _id; private Callback> _parser; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/CommunitiesGUIPage.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/CommunitiesGUIPage.java index 15bdbaf82..6e7be79ed 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/CommunitiesGUIPage.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/CommunitiesGUIPage.java @@ -23,6 +23,8 @@ public abstract class CommunitiesGUIPage implements Listener protected Player Viewer; protected Inventory Inv; protected Map Buttons = new HashMap<>(); + + protected static CommunityManager _manager; public CommunitiesGUIPage(String name, int rows, Player viewer) { @@ -37,7 +39,9 @@ public abstract class CommunitiesGUIPage implements Listener public static CommunityManager getCommunityManager() { - return Managers.get(CommunityManager.class); + if (_manager == null) + _manager = Managers.require(CommunityManager.class); + return _manager; } public void open() diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/browser/CommunityBrowserPage.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/browser/CommunityBrowserPage.java index 482a40142..0f3a7ee54 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/browser/CommunityBrowserPage.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/gui/browser/CommunityBrowserPage.java @@ -10,6 +10,7 @@ import org.bukkit.event.EventHandler; import mineplex.core.common.util.C; import mineplex.core.communities.CommunityBrowserUpdateEvent; import mineplex.core.communities.CommunityDisbandEvent; +import mineplex.core.communities.CommunityManager; import mineplex.core.communities.gui.ActionButton; import mineplex.core.communities.gui.CommunitiesGUIPage; import mineplex.core.communities.gui.overview.CommunityInvitesPage; @@ -80,11 +81,26 @@ public class CommunityBrowserPage extends CommunitiesGUIPage Buttons.put(53, next); Inv.setItem(53, next.Button); } + + CommunityManager manager = getCommunityManager(); int slot = 18; boolean cleared = false; + + // Unload the old communities + manager.unloadDisplayCommunities(_displaying); + + // Generate the list of ids we're going to display _displaying.clear(); - for (int i = (page - 1) * COMMUNITIES_PER_PAGE; i < (page - 1) * COMMUNITIES_PER_PAGE + COMMUNITIES_PER_PAGE && i < getCommunityManager().BrowserIds.size(); i++) + for (int i = (page - 1) * COMMUNITIES_PER_PAGE; i < (page - 1) * COMMUNITIES_PER_PAGE + COMMUNITIES_PER_PAGE && i < manager.getBrowserIds().size(); i++) + { + _displaying.add(manager.getBrowserIds().get(i)); + } + + // Temporarily load the new ones + manager.loadCommunitiesForDisplay(_displaying); + + for (int i = (page - 1) * COMMUNITIES_PER_PAGE; i < (page - 1) * COMMUNITIES_PER_PAGE + COMMUNITIES_PER_PAGE && i < manager.getBrowserIds().size(); i++) { if (!cleared && !initial) { @@ -96,8 +112,8 @@ public class CommunityBrowserPage extends CommunitiesGUIPage Inv.setItem(clear, null); } } - CommunityBrowserButton button = new CommunityBrowserButton(Viewer, getCommunityManager().getLoadedCommunity(getCommunityManager().BrowserIds.get(i))); - _displaying.add(getCommunityManager().BrowserIds.get(i)); + CommunityBrowserButton button = new CommunityBrowserButton(Viewer, getCommunityManager().getLoadedCommunity(manager.getBrowserIds().get(i))); + // _displaying.add(manager.getBrowserIds().get(i)); Buttons.put(slot, button); Inv.setItem(slot, button.Button); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/communities/storage/CommunityRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/communities/storage/CommunityRepository.java index 0274014e4..bdccd51d2 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/communities/storage/CommunityRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/communities/storage/CommunityRepository.java @@ -2,10 +2,14 @@ package mineplex.core.communities.storage; import java.sql.Connection; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -33,6 +37,7 @@ public class CommunityRepository extends RepositoryBase private static final String GET_COMMUNITY_MEMBERS = "SELECT cm.communityId, cm.accountId, cm.communityRole, ac.name, ac.uuid, ac.lastLogin, cm.readingChat FROM communityMembers cm INNER JOIN accounts ac ON ac.id=cm.accountId"; private static final String GET_COMMUNITY_JOIN_REQUESTS = "SELECT cjr.communityId, cjr.accountId, ac.name, ac.uuid FROM communityJoinRequests cjr INNER JOIN accounts ac ON ac.id=cjr.accountId WHERE cjr.accountId=?;"; private static final String GET_COMMUNITY_SETTINGS = "SELECT communityId, settingId, settingValue FROM communitySettings"; + private static final String GET_PUBLIC_COMMUNITIES = "SELECT communityId FROM communities WHERE settingId=8 AND settingValue='true';"; // Old queries private static final String GET_ALL_COMMUNITIES = "SELECT * FROM communities WHERE region=?;"; @@ -64,20 +69,69 @@ public class CommunityRepository extends RepositoryBase _us = us; } - private ColumnInt[] genIdColumns(String colName, List nums) + /** + * Loads all communities that are eligible to be shown in the browser. + * That is, they have 5 or more members and aren't private. + */ + public void loadBrowserCommunities(final Collection store) { - return nums.stream().map(i -> new ColumnInt(colName, i)).toArray(ColumnInt[]::new); + try (Connection connection = getConnection()) + { + executeQuery(connection, GET_PUBLIC_COMMUNITIES, resultSet -> + { + int id = resultSet.getInt("communityId"); + store.add(id); + }); + } catch (SQLException ex) + { + System.err.println("Failed to load public community IDs"); + ex.printStackTrace(); + } } + /** + * Loads and stores a single community. + */ public Community loadCommunity(final Map store, final int id) { loadInternal(store, Collections.singletonList(id), -1); return store.get(id); } + /** + * Loads all of the provided communities + */ + public void loadCommunities(final Map store, final List load) + { + loadInternal(store, load, -1); + } + + /** + * Loads all of the provided communities and the player's join requests. + */ public void handlePlayerJoin(final Map store, final List load, final int accountId) { loadInternal(store, load, accountId); + + for (int id : load) + { + Community com = store.get(id); + if (com != null && !com.isBrowserFlagSet()) + { + updateBrowserStatus(com, com.getPrivacySetting() != Community.PrivacySetting.PRIVATE + && com.getMembers().size() >= 5); + } + } + } + + public void updateBrowserStatus(Community community, boolean flag) + { + updateCommunitySetting(CommunitySetting.SHOW_IN_BROWSER, community.getId(), String.valueOf(flag)); + } + + private ColumnInt[] genIdColumns(String colName, List nums) + { + return nums.stream().map(i -> new ColumnInt(colName, i)).toArray(ColumnInt[]::new); } private void loadInternal(final Map store, final List load, final int accountId)