From 875ea468ccbdc19112be3d2fc858b44b69b59d6a Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 4 Apr 2023 13:40:44 +0100 Subject: [PATCH] TagUser Object & Default Tag Groups --- build.gradle | 2 + .../xyz/oribuin/eternaltags/EternalTags.java | 4 +- .../oribuin/eternaltags/hook/Expansion.java | 11 +- .../oribuin/eternaltags/hook/VaultHook.java | 56 ++++++ .../eternaltags/listener/PlayerListeners.java | 5 +- .../manager/ConfigurationManager.java | 42 ++++- .../eternaltags/manager/DataManager.java | 56 +++--- .../eternaltags/manager/TagsManager.java | 177 ++++++++++++++---- .../xyz/oribuin/eternaltags/obj/TagUser.java | 143 ++++++++++++++ src/main/resources/plugin.yml | 6 +- 10 files changed, 428 insertions(+), 74 deletions(-) create mode 100644 src/main/java/xyz/oribuin/eternaltags/hook/VaultHook.java create mode 100644 src/main/java/xyz/oribuin/eternaltags/obj/TagUser.java diff --git a/build.gradle b/build.gradle index 5c3189c..c55b317 100644 --- a/build.gradle +++ b/build.gradle @@ -41,6 +41,8 @@ dependencies { compileOnly 'io.papermc.paper:paper-api:1.19.3-R0.1-SNAPSHOT' compileOnly 'org.jetbrains:annotations:23.0.0' + // Plugins + compileOnly 'com.github.MilkBowl:VaultAPI:1.7' compileOnly 'me.clip:placeholderapi:2.11.3' compileOnly "com.github.oraxen:oraxen:afc4903680" compileOnly 'com.arcaniax:HeadDatabase-API:1.3.1', { diff --git a/src/main/java/xyz/oribuin/eternaltags/EternalTags.java b/src/main/java/xyz/oribuin/eternaltags/EternalTags.java index 502f06c..a593ad4 100644 --- a/src/main/java/xyz/oribuin/eternaltags/EternalTags.java +++ b/src/main/java/xyz/oribuin/eternaltags/EternalTags.java @@ -35,14 +35,14 @@ public void enable() { // Make sure the server has PlaceholderAPI if (!pluginManager.isPluginEnabled("PlaceholderAPI")) { this.getLogger().severe("Please install PlaceholderAPI onto your server to use this plugin."); - this.getServer().getPluginManager().disablePlugin(this); + pluginManager.disablePlugin(this); return; } // Make sure the server is on MC 1.16 if (NMSUtil.getVersionNumber() < 16) { this.getLogger().severe("This plugin only supports 1.16+ Minecraft."); - this.getServer().getPluginManager().disablePlugin(this); + pluginManager.disablePlugin(this); return; } diff --git a/src/main/java/xyz/oribuin/eternaltags/hook/Expansion.java b/src/main/java/xyz/oribuin/eternaltags/hook/Expansion.java index f15a762..2c3bcdd 100644 --- a/src/main/java/xyz/oribuin/eternaltags/hook/Expansion.java +++ b/src/main/java/xyz/oribuin/eternaltags/hook/Expansion.java @@ -3,6 +3,7 @@ import dev.rosewood.rosegarden.utils.HexUtils; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xyz.oribuin.eternaltags.EternalTags; @@ -52,7 +53,15 @@ public String onRequest(@Nullable OfflinePlayer offlineUser, @NotNull String par } } - final Tag activeTag = this.manager.getOfflineUserTag(offlineUser); + // This is the only tag that doesn't require a player + if (params.equalsIgnoreCase("total")) + return String.valueOf(this.manager.getCachedTags().size()); + + Player player = offlineUser.getPlayer(); + if (player == null) + return "Error: Player is null"; + + final Tag activeTag = this.manager.getUserTag(player); return switch (params.toLowerCase()) { // Set bracket placeholders to allow \o/ Placeholder Inception \o/ case "tag" -> this.manager.getDisplayTag(activeTag, offlineUser, ""); diff --git a/src/main/java/xyz/oribuin/eternaltags/hook/VaultHook.java b/src/main/java/xyz/oribuin/eternaltags/hook/VaultHook.java new file mode 100644 index 0000000..54fb448 --- /dev/null +++ b/src/main/java/xyz/oribuin/eternaltags/hook/VaultHook.java @@ -0,0 +1,56 @@ +package xyz.oribuin.eternaltags.hook; + +import net.milkbowl.vault.permission.Permission; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.RegisteredServiceProvider; + +import javax.annotation.Nullable; + +public class VaultHook { + + private static final boolean enabled; + + static { + enabled = Bukkit.getPluginManager().isPluginEnabled("Vault"); + } + + /** + * Get the vault permission instance + * + * @return The permission instance + */ + @Nullable + public static Permission getPermission() { + if (!enabled) + return null; + + RegisteredServiceProvider rsp = Bukkit.getServicesManager().getRegistration(Permission.class); + if (rsp == null) + return null; + + return rsp.getProvider(); + } + + /** + * Get the highest group of a player + * + * @param player The player to get the group of + * @return The highest group of the player + */ + public static String getPrimaryGroup(Player player) { + Permission permission = getPermission(); // Get the permission instance + if (permission == null) + return null; + + return permission.getPrimaryGroup(player); // Get the highest group (This is the group with the highest priority + } + + /** + * @return If vault is enabled or not + */ + public static boolean isEnabled() { + return enabled; + } + +} diff --git a/src/main/java/xyz/oribuin/eternaltags/listener/PlayerListeners.java b/src/main/java/xyz/oribuin/eternaltags/listener/PlayerListeners.java index 45d073b..98cf927 100644 --- a/src/main/java/xyz/oribuin/eternaltags/listener/PlayerListeners.java +++ b/src/main/java/xyz/oribuin/eternaltags/listener/PlayerListeners.java @@ -8,8 +8,6 @@ import xyz.oribuin.eternaltags.manager.DataManager; import xyz.oribuin.eternaltags.manager.TagsManager; -import java.util.List; - public class PlayerListeners implements Listener { private final TagsManager manager = EternalTags.getInstance().getManager(TagsManager.class); @@ -17,8 +15,9 @@ public class PlayerListeners implements Listener { @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { - this.dataManager.loadUser(event.getPlayer().getUniqueId()); // Load the user from the database + this.dataManager.loadUser(event.getPlayer().getUniqueId()); // Load the user from the database this.manager.getUserTag(event.getPlayer()); // Get the user's tag (This will detect default tags or the user's tag) + } @EventHandler diff --git a/src/main/java/xyz/oribuin/eternaltags/manager/ConfigurationManager.java b/src/main/java/xyz/oribuin/eternaltags/manager/ConfigurationManager.java index ba23521..b5d1851 100644 --- a/src/main/java/xyz/oribuin/eternaltags/manager/ConfigurationManager.java +++ b/src/main/java/xyz/oribuin/eternaltags/manager/ConfigurationManager.java @@ -1,26 +1,34 @@ package xyz.oribuin.eternaltags.manager; import dev.rosewood.rosegarden.RosePlugin; +import dev.rosewood.rosegarden.config.CommentedConfigurationSection; import dev.rosewood.rosegarden.config.CommentedFileConfiguration; import dev.rosewood.rosegarden.config.RoseSetting; import dev.rosewood.rosegarden.manager.AbstractConfigurationManager; import xyz.oribuin.eternaltags.EternalTags; +import java.util.HashMap; +import java.util.Map; + public class ConfigurationManager extends AbstractConfigurationManager { public enum Setting implements RoseSetting { - // Tag Settings + // Default Tag Options DEFAULT_TAG("default-tag", "none", "The tag that will show when player does not have an active tag.", "Set to 'none' to disable.", "Set to 'random' to apply a random tag"), + DEFAULT_TAG_GROUPS("default-tag-groups", null, "The groups that will be applied to the player when they join the server.", "Set to 'none' to disable.", "Set to 'random' to apply a random tag", "This requires vault and a vault supported permission plugin."), + DEFAULT_TAG_GROUP_DEFAULT("default-tag-groups.default", "none"), + REMOVE_TAGS("remove-inaccessible-tags", false, "Should a tag be automatically removed if the player doesn't have permission to use it?"), + + // Formatting FORMATTED_PLACEHOLDER("formatted-placeholder", "None", "The placeholder that will show when the player has no active tag."), TAG_UNLOCKED_FORMAT("tag-unlocked-format", "&a&lUnlocked", "The format that will show when the player has the tag unlocked."), TAG_LOCKED_FORMAT("tag-locked-format", "&c&lLocked", "The format that will show when the player has the tag locked."), - REMOVE_TAGS("remove-inaccessible-tags", false, "Should a tag be automatically removed if the player doesn't have permission to use it?"), TAG_PREFIX("tag-prefix", "", "The prefix that will be added in front of the tag in the placeholder"), TAG_SUFFIX("tag-suffix", "", "The suffix that will be added after the tag in the placeholder"), - MYSQL_TAGDATA("save-tagdata-sql", false, "Should the tag data be stored in a MySQL/SQLite database? (Tags that would be saved in tags.yml)"), - PLUGIN_MESSAGING("plugin-messaging", false, "Should the plugin use plugin messaging to sync tag data across servers? (Recommended to keep save-tagdata-sql as false if this is enabled)"), - RE_EQUIP_CLEAR("reequip-clear", false, "Should the player's tag be cleared when they re-equip the same tag?"), DESCRIPTION_DELIMITER("description-delimiter", "\n", "The delimiter that will be used for %eternaltags_tag_description%"), + + // Other Options + RE_EQUIP_CLEAR("reequip-clear", false, "Should the player's tag be cleared when they re-equip the same tag?"), CACHE_GUI_TAGS("cache-gui-tags", true, "Should the tag items be cached? (Keeps the items in memory instead of creating them every time the GUI is opened)", "This will reduce the amount of lag when opening the GUI, but will use more memory.", "This will also make tags with placeholders not update until the plugin is reloaded." @@ -31,7 +39,12 @@ public enum Setting implements RoseSetting { "This will also make categories with placeholders not update until the plugin is reloaded." ), OPEN_CATEGORY_GUI_FIRST("open-category-gui-first", false, "Should the category GUI be opened first when a player types /tags?"), - ; + + // Data Systems + MYSQL_TAGDATA("save-tagdata-sql", false, "Should the tag data be stored in a MySQL/SQLite database? (Tags that would be saved in tags.yml)"), + PLUGIN_MESSAGING("plugin-messaging", false, "Should the plugin use plugin messaging to sync tag data across servers? (Recommended to keep save-tagdata-sql as false if this is enabled)"), + + ; // End of settings private final String key; private final Object defaultValue; @@ -73,6 +86,23 @@ public void setCachedValue(Object value) { public CommentedFileConfiguration getBaseConfig() { return EternalTags.getInstance().getManager(ConfigurationManager.class).getConfig(); } + + @SuppressWarnings("unchecked") + public Map getMap() { + if (this.value instanceof Map) + return (Map) this.value; + + Map map = new HashMap<>(); + CommentedConfigurationSection section = this.getBaseConfig().getConfigurationSection(this.key); + if (section == null) { + this.value = map; + return map; + } + + section.getKeys(false).forEach(key -> map.put(key, section.get(key))); + this.value = map; + return map; + } } public ConfigurationManager(RosePlugin rosePlugin) { diff --git a/src/main/java/xyz/oribuin/eternaltags/manager/DataManager.java b/src/main/java/xyz/oribuin/eternaltags/manager/DataManager.java index 814ee04..6f809d5 100644 --- a/src/main/java/xyz/oribuin/eternaltags/manager/DataManager.java +++ b/src/main/java/xyz/oribuin/eternaltags/manager/DataManager.java @@ -11,6 +11,7 @@ import xyz.oribuin.eternaltags.database.migration._3_ModifyTagDataItems; import xyz.oribuin.eternaltags.obj.Tag; import xyz.oribuin.eternaltags.obj.TagDescription; +import xyz.oribuin.eternaltags.obj.TagUser; import xyz.oribuin.eternaltags.util.TagsUtils; import java.sql.PreparedStatement; @@ -26,8 +27,7 @@ public class DataManager extends AbstractDataManager { - private final Map cachedUsers = new HashMap<>(); - private final Map> cachedFavourites = new HashMap<>(); + private final Map cachedUsers = new HashMap<>(); private final Gson gson = new Gson(); @@ -40,7 +40,6 @@ public void reload() { super.reload(); this.cachedUsers.clear(); - this.cachedFavourites.clear(); } /** @@ -50,9 +49,11 @@ public void reload() { * @param tag The tag */ public void saveUser(@NotNull UUID uuid, @NotNull Tag tag) { - this.cachedUsers.put(uuid, tag); + TagUser user = this.cachedUsers.getOrDefault(uuid, new TagUser(uuid)); + user.setActiveTag(tag.getId()); + this.cachedUsers.put(uuid, user); - final String query = "REPLACE INTO " + this.getTablePrefix() + "tags (player, tagID) VALUES (?, ?)"; + final String query = "REPLACE INTO " + this.getTablePrefix() + "tags (player, tagID) VALUES (?, ?)"; this.async(task -> this.databaseConnector.connect(connection -> { try (PreparedStatement statement = connection.prepareStatement(query)) { statement.setString(1, uuid.toString()); @@ -86,7 +87,7 @@ public void removeUser(final UUID uuid) { * @param id The tag id being removed. */ public void deleteUserTag(String id) { - this.cachedUsers.values().removeIf(tag -> tag.getId().equalsIgnoreCase(id)); + this.cachedUsers.values().removeIf(tag -> tag.getActiveTag() != null && tag.getActiveTag().equalsIgnoreCase(id)); final String query = "DELETE FROM " + this.getTablePrefix() + "tags WHERE tagID = ?"; this.async(task -> this.databaseConnector.connect(connection -> { @@ -103,7 +104,12 @@ public void deleteUserTag(String id) { * @param tag The tag. */ public void updateUsers(Tag tag, List players) { - players.forEach(player -> this.cachedUsers.put(player, tag)); + players.forEach(player -> { + TagUser user = this.cachedUsers.getOrDefault(player, new TagUser(player)); + user.setActiveTag(tag.getId()); + this.cachedUsers.put(player, user); + }); + this.async(task -> this.databaseConnector.connect(connection -> { final String query = "REPLACE INTO " + this.getTablePrefix() + "tags (player, tagID) VALUES (?, ?)"; @@ -125,9 +131,10 @@ public void updateUsers(Tag tag, List players) { * @param tag The tag being added */ public void addFavourite(UUID uuid, Tag tag) { - Map favourites = this.rosePlugin.getManager(TagsManager.class).getUsersFavourites(uuid); - favourites.put(tag.getId(), tag); - this.cachedFavourites.put(uuid, new HashSet<>(favourites.values())); + TagUser user = this.cachedUsers.getOrDefault(uuid, new TagUser(uuid)); + user.getFavourites().add(tag.getId()); + this.cachedUsers.put(uuid, user); + this.async(task -> this.databaseConnector.connect(connection -> { final String query = "INSERT INTO " + this.getTablePrefix() + "favourites (player, tagID) VALUES (?, ?)"; @@ -146,10 +153,9 @@ public void addFavourite(UUID uuid, Tag tag) { * @param tag The tag being removed. */ public void removeFavourite(UUID uuid, Tag tag) { - - final Map favourites = this.rosePlugin.getManager(TagsManager.class).getUsersFavourites(uuid); - favourites.remove(tag.getId()); - this.cachedFavourites.put(uuid, new HashSet<>(favourites.values())); + TagUser user = this.cachedUsers.getOrDefault(uuid, new TagUser(uuid)); + user.getFavourites().remove(tag.getId()); + this.cachedUsers.put(uuid, user); this.async(task -> this.databaseConnector.connect(connection -> { final String query = "DELETE FROM " + this.getTablePrefix() + "favourites WHERE player = ? AND tagID = ?"; @@ -180,8 +186,7 @@ public void clearFavourites(UUID uuid) { * @param uuid The player's uuid */ public void loadUser(@NotNull UUID uuid) { - final TagsManager manager = this.rosePlugin.getManager(TagsManager.class); - final Set favouriteTags = new HashSet<>(); + final TagUser user = new TagUser(uuid); this.async(task -> this.databaseConnector.connect(connection -> { final String selectTag = "SELECT tagID FROM " + this.getTablePrefix() + "tags WHERE player = ?"; @@ -191,7 +196,7 @@ public void loadUser(@NotNull UUID uuid) { statement.setString(1, uuid.toString()); final ResultSet result = statement.executeQuery(); if (result.next()) { - this.cachedUsers.put(uuid, manager.getTagFromId(result.getString(1))); + user.setActiveTag(result.getString(1)); } } @@ -200,10 +205,11 @@ public void loadUser(@NotNull UUID uuid) { statement.setString(1, uuid.toString()); final ResultSet result = statement.executeQuery(); while (result.next()) { - favouriteTags.add(manager.getTagFromId(result.getString(1))); - this.cachedFavourites.put(uuid, favouriteTags); + user.getFavourites().add(result.getString(1)); } } + + this.cachedUsers.put(uuid, user); })); } @@ -228,7 +234,7 @@ public void loadTagData(Map cachedTags) { Tag tag = new Tag(id, result.getString("name"), result.getString("tag")); tag.setPermission(result.getString("permission")); tag.setDescription(description); - tag.setOrder(result.getInt("order"));; + tag.setOrder(result.getInt("order")); tag.setIcon(TagsUtils.deserializeItem(result.getBytes("icon"))); cachedTags.put(id, tag); } @@ -251,7 +257,7 @@ public void saveTagData(@NotNull Tag tag) { statement.setString(4, tag.getTag()); statement.setString(5, tag.getPermission()); statement.setInt(6, tag.getOrder()); - statement.setBytes(7 , tag.getIcon() != null ? TagsUtils.serializeItem(tag.getIcon()) : null); + statement.setBytes(7, tag.getIcon() != null ? TagsUtils.serializeItem(tag.getIcon()) : null); statement.executeUpdate(); } })); @@ -274,7 +280,7 @@ public void saveTagData(Map tags) { statement.setString(4, tag.getTag()); statement.setString(5, tag.getPermission()); statement.setInt(6, tag.getOrder()); - statement.setBytes(7 , tag.getIcon() != null ? TagsUtils.serializeItem(tag.getIcon()) : null); + statement.setBytes(7, tag.getIcon() != null ? TagsUtils.serializeItem(tag.getIcon()) : null); statement.addBatch(); } @@ -319,12 +325,8 @@ private void async(Consumer callback) { this.rosePlugin.getServer().getScheduler().runTaskAsynchronously(rosePlugin, callback); } - public Map getCachedUsers() { + public Map getCachedUsers() { return cachedUsers; } - public Map> getCachedFavourites() { - return cachedFavourites; - } - } diff --git a/src/main/java/xyz/oribuin/eternaltags/manager/TagsManager.java b/src/main/java/xyz/oribuin/eternaltags/manager/TagsManager.java index efd14b6..bd3a52f 100644 --- a/src/main/java/xyz/oribuin/eternaltags/manager/TagsManager.java +++ b/src/main/java/xyz/oribuin/eternaltags/manager/TagsManager.java @@ -17,10 +17,12 @@ import xyz.oribuin.eternaltags.event.TagDeleteEvent; import xyz.oribuin.eternaltags.event.TagSaveEvent; import xyz.oribuin.eternaltags.hook.OraxenHook; +import xyz.oribuin.eternaltags.hook.VaultHook; import xyz.oribuin.eternaltags.listener.BungeeListener; import xyz.oribuin.eternaltags.manager.ConfigurationManager.Setting; import xyz.oribuin.eternaltags.obj.Category; import xyz.oribuin.eternaltags.obj.Tag; +import xyz.oribuin.eternaltags.obj.TagUser; import xyz.oribuin.eternaltags.util.TagsUtils; import java.io.File; @@ -30,8 +32,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Random; -import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; @@ -39,6 +41,7 @@ public class TagsManager extends Manager { + // this is starting to look like im an iridium dev // Cached Tags and Categories private final Map cachedTags = new HashMap<>(); private final Map cachedCategories = new HashMap<>(); @@ -50,8 +53,8 @@ public class TagsManager extends Manager { // Other Values. private boolean categoriesEnabled = true; - private Category defaultCategory; - private Category globalCategory; + private Category defaultCategory, globalCategory; + private Map defaultTagGroups; public TagsManager(RosePlugin plugin) { super(plugin); @@ -59,6 +62,10 @@ public TagsManager(RosePlugin plugin) { @Override public void reload() { + // Load the default tag groups + this.defaultTagGroups = new HashMap<>(); + CommentedConfigurationSection groupSection = Setting.DEFAULT_TAG_GROUPS.getSection(); + groupSection.getKeys(false).forEach(s -> this.defaultTagGroups.put(s, groupSection.getString(s))); // Load categories if enabled, Categories are not saved in mysql so we're not gonna load categories first. this.categoriesFile = TagsUtils.createFile(this.rosePlugin, "categories.yml"); @@ -140,8 +147,6 @@ public void loadTags() { if (itemStack != null) obj.setIcon(itemStack); } - - } if (OraxenHook.enabled()) @@ -280,12 +285,13 @@ public void saveCategory(Category cat) { public void updateActiveTag(Tag tag) { final DataManager data = this.rosePlugin.getManager(DataManager.class); - for (Map.Entry entry : data.getCachedUsers().entrySet()) { - if (entry.getValue() == null) + for (TagUser user : data.getCachedUsers().values()) { + if (user == null) continue; - if (entry.getValue().getId().equalsIgnoreCase(tag.getId())) - data.getCachedUsers().put(entry.getKey(), tag); + if (user.getActiveTag() != null && user.getActiveTag().equalsIgnoreCase(tag.getId())) { + user.setActiveTag(tag.getId()); + } } } @@ -402,7 +408,11 @@ public Tag getTagFromUUID(UUID uuid) { */ @Nullable public Tag getUserTag(@NotNull UUID uuid) { - return this.rosePlugin.getManager(DataManager.class).getCachedUsers().get(uuid); + TagUser user = this.rosePlugin.getManager(DataManager.class).getCachedUsers().get(uuid); + if (user == null) + return null; + + return this.getTagFromId(user.getActiveTag()); } /** @@ -415,17 +425,30 @@ public Tag getUserTag(@NotNull UUID uuid) { @Nullable public Tag getUserTag(@NotNull Player player) { final DataManager dataManager = this.rosePlugin.getManager(DataManager.class); - Tag tag = dataManager.getCachedUsers().get(player.getUniqueId()); + final TagUser user = dataManager.getCachedUsers().getOrDefault(player.getUniqueId(), new TagUser(player)); + Tag tag = this.getTagFromId(user.getActiveTag()); - if (tag == null) { - tag = this.getDefaultTag(player); - dataManager.getCachedUsers().put(player.getUniqueId(), tag); // Assign the default tag to the user. - return tag; // We don't need to check for a permission here, as the default tag should always be available. + // TODO: Add check for if the player is using a default tag. + if (VaultHook.isEnabled() && this.usingGroupDefaults() && user.isUsingDefaultTag()) { // Check if vault is enabled. + tag = this.getDefaultTag(player); // Get the default tag. } - if (Setting.REMOVE_TAGS.getBoolean() && !canUseTag(player, tag)) { - this.rosePlugin.getManager(DataManager.class).removeUser(player.getUniqueId()); // Remove the user's tag. - return null; + // Remove the tag if the player doesn't have the permission to use it. + if (Setting.REMOVE_TAGS.getBoolean() && tag != null && !this.canUseTag(player, tag)) { + dataManager.removeUser(player.getUniqueId()); // Remove the user's tag. + tag = null; + } + + if (tag == null) { + tag = this.getDefaultTag(player); // Get the default tag. + if (tag == null) { + System.out.println("No default tag found for " + player.getName()); + return null; + } + + user.setActiveTag(tag.getId()); + user.setUsingDefaultTag(true); + dataManager.getCachedUsers().put(player.getUniqueId(), user); // Assign the default tag to the user. } return tag; @@ -504,14 +527,12 @@ public void removeFavourite(UUID uuid, Tag tag) { @NotNull public Map getUsersFavourites(UUID uuid) { final Map favourites = new HashMap<>(); - Set tags = this.rosePlugin.getManager(DataManager.class).getCachedFavourites().get(uuid); + final TagUser user = this.rosePlugin.getManager(DataManager.class).getCachedUsers().getOrDefault(uuid, new TagUser(uuid)); - if (tags == null || tags.isEmpty()) - return favourites; - - tags.stream() + user.getFavourites().stream() .filter(Objects::nonNull) - .forEach(tag -> favourites.put(tag.getId().toLowerCase(), tag)); + .forEach(tag -> favourites.put(tag, this.getTagFromId(tag))); + return favourites; } @@ -548,12 +569,39 @@ public boolean checkTagExists(String id) { * @return An optional tag. */ @Nullable - public Tag getTagFromId(String id) { + public Tag getTagFromId(@Nullable String id) { + if (id == null) + return null; + return this.cachedTags.get(id.toLowerCase()); } + @Nullable + public Tag getDefaultTag(@NotNull Player player) { + String defaultTagID = Setting.DEFAULT_TAG.getString(); + + // Check if the default tag is a group. + if (VaultHook.isEnabled() && !this.defaultTagGroups.isEmpty()) { + String group = VaultHook.getPrimaryGroup(player); // Get the highest group of the player. + if (group != null && this.defaultTagGroups.containsKey(group)) { + String tagId = this.defaultTagGroups.get(group); // Get the tag id from the group. + return switch (tagId) { + case "none" -> this.getTagFromId(defaultTagID); + case "random" -> this.getRandomTag(player); + default -> this.getTagFromId(tagId); + }; + } + } + + return switch (defaultTagID) { + case "none" -> null; + case "random" -> this.getRandomTag(player); + default -> this.getTagFromId(defaultTagID); + }; + } + /** - * Get the default tag for a player. + * Get the default tag for an offline player. * * @param player The player * @return The default tag. @@ -562,14 +610,22 @@ public Tag getTagFromId(String id) { public Tag getDefaultTag(@Nullable OfflinePlayer player) { String defaultTagID = Setting.DEFAULT_TAG.getString(); - if (defaultTagID == null || defaultTagID.equalsIgnoreCase("none")) - return null; + return switch (defaultTagID) { + case "none" -> null; + case "random" -> this.getRandomTag(player); + default -> this.getTagFromId(defaultTagID); + }; + } - if (defaultTagID.equalsIgnoreCase("random")) { - return this.getRandomTag(player); - } + /** + * @return Check if the plugin is using group defaults. + */ + public boolean usingGroupDefaults() { + if (this.defaultTagGroups.isEmpty()) // No groups are set. + return false; - return this.getTagFromId(defaultTagID); + // Check if all the groups are set to none. + return this.defaultTagGroups.values().stream().allMatch(tagId -> tagId.equalsIgnoreCase("none")); } /** @@ -688,7 +744,7 @@ public List getAccessibleTagsInCategory(Category category, Player player) { * @param tag The tag * @return If the player has access to the tag */ - public boolean canUseTag(Player player, Tag tag) { + public boolean canUseTag(@NotNull Player player, @NotNull Tag tag) { boolean hasAccessToTag = tag.getPermission() == null || player.hasPermission(tag.getPermission()); // If there's no categories, or all categories are default, then we can just return the tag unlocked status @@ -776,6 +832,61 @@ public Map getTagsWithCategories() { return tagsWithCategories; } + /** + * Does the player have the group tag active? + * + * @param player The player + * @return The tags with categories that the player has access to + */ + public boolean hasPrimaryGroupTag(@NotNull Player player) { + if (!VaultHook.isEnabled() || !this.usingGroupDefaults()) + return false; + + String userTag = Optional.ofNullable(this.getUserTag(player.getUniqueId())) + .map(Tag::getId) + .orElse(null); + + return userTag != null && userTag.equals(this.getGroupTag(player)); + } + + /** + * Get the tag for a group + * + * @param group The group + * @return The tag + */ + @Nullable + public String getGroupTag(String group) { + if (!VaultHook.isEnabled() || !this.usingGroupDefaults()) + return null; + + return this.defaultTagGroups.get(group); + } + + /** + * Get the tag for a group + * + * @param player The player + * @return The tag + */ + @Nullable + public String getGroupTag(@NotNull Player player) { + if (!VaultHook.isEnabled() || !this.usingGroupDefaults()) + return null; + + String group = VaultHook.getPrimaryGroup(player); + String tag = this.defaultTagGroups.get(group); + if (tag == null) + return null; + + return switch (tag) { + case "default" -> Setting.DEFAULT_TAG.getString(); + case "random" -> this.getRandomTag(player).getId(); + case "none" -> null; + default -> this.cachedTags.containsKey(tag) ? tag : null; + }; + } + /** * Get the tag placeholders for the given player * diff --git a/src/main/java/xyz/oribuin/eternaltags/obj/TagUser.java b/src/main/java/xyz/oribuin/eternaltags/obj/TagUser.java new file mode 100644 index 0000000..e56ec8c --- /dev/null +++ b/src/main/java/xyz/oribuin/eternaltags/obj/TagUser.java @@ -0,0 +1,143 @@ +package xyz.oribuin.eternaltags.obj; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +public class TagUser { + + /** + * The UUID of the player this object represents. + */ + private final @NotNull UUID player; + + /** + * The cached player object. + */ + private @Nullable Player cachedPlayer; + + /** + * The active tag of the player. + */ + private @Nullable String activeTag; + + /** + * Whether the player is using the default tag. + */ + private boolean usingDefaultTag; + + /** + * The player's favourite tags. + */ + private@NotNull Set favourites; + + /** + * Create a new TagUser object. + * + * @param player The player to create the object for. + */ + public TagUser(@NotNull UUID player) { + this.player = player; + this.activeTag = null; + this.usingDefaultTag = false; + this.favourites = new HashSet<>(); + } + + /** + * Create a new TagUser object. + * + * @param player The player to create the object for. + */ + public TagUser(@NotNull Player player) { + this.player = player.getUniqueId(); + this.activeTag = null; + this.usingDefaultTag = false; + this.cachedPlayer = player; + this.favourites = new HashSet<>(); + } + + /** + * @return The UUID of the player this object represents. + */ + @NotNull + public UUID getPlayer() { + return this.player; + } + + /** + * @return The cached player object, if null, get the player from the UUID. + */ + @Nullable + public Player getCachedPlayer() { + if (this.cachedPlayer == null) { + this.cachedPlayer = Bukkit.getPlayer(this.player); + } + + return this.cachedPlayer; + } + + /** + * Clear the cached player object. + */ + public void clearCachedPlayer() { + this.cachedPlayer = null; + } + + /** + * @param newPlayer Refresh the cached player object. + * @return The TagUser object. + */ + public TagUser refresh(Player newPlayer) { + this.cachedPlayer = newPlayer; + return this; + } + + /** + * @return The active tag of the player. + */ + @Nullable + public String getActiveTag() { + return this.activeTag; + } + + /** + * @param activeTag Set the active tag of the player. + */ + public void setActiveTag(@Nullable String activeTag) { + this.activeTag = activeTag; + } + + /** + * @return Whether the player is using the default tag. + */ + public boolean isUsingDefaultTag() { + return this.usingDefaultTag; + } + + /** + * @param usingDefaultTag Set whether the player is using the default tag. + */ + public void setUsingDefaultTag(boolean usingDefaultTag) { + this.usingDefaultTag = usingDefaultTag; + } + + /** + * @return The player's favourite tags. + */ + public Set getFavourites() { + return this.favourites; + } + + /** + * @param favourites Set the player's favourite tags. + */ + public void setFavourites(Set favourites) { + this.favourites = favourites; + } + +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index dcc49fd..4e7cbec 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -2,9 +2,11 @@ name: EternalTags main: xyz.oribuin.eternaltags.EternalTags version: '@version@' author: Oribuin -api-version: "1.13" +api-version: "1.16" description: A simple tag plugin alternative to other Tag plugins (With Hex Support) website: https://www.spigotmc.org/resources/eternaltags.91842/ softdepend: + - Vault - PlaceholderAPI - - Oraxen \ No newline at end of file + - Oraxen + - HeadDatabase \ No newline at end of file