From 21d0c9ab0e1d69524a6ec943c0949ed8c0c4aa71 Mon Sep 17 00:00:00 2001 From: Luck Date: Tue, 23 Aug 2016 19:32:58 +0100 Subject: [PATCH] Add some PlaceholderAPI placeholders --- bukkit-placeholders/pom.xml | 52 ++++ .../LuckPermsPlaceholderExpansion.java | 247 ++++++++++++++++++ .../luckperms/api/vault/VaultChatHook.java | 11 +- .../luckperms/utils/ArgumentChecker.java | 8 + pom.xml | 5 + 5 files changed, 318 insertions(+), 5 deletions(-) create mode 100644 bukkit-placeholders/pom.xml create mode 100644 bukkit-placeholders/src/main/java/me/lucko/luckperms/api/placeholders/LuckPermsPlaceholderExpansion.java diff --git a/bukkit-placeholders/pom.xml b/bukkit-placeholders/pom.xml new file mode 100644 index 00000000..366c8ab0 --- /dev/null +++ b/bukkit-placeholders/pom.xml @@ -0,0 +1,52 @@ + + + + luckperms + me.lucko.luckperms + 2.5-SNAPSHOT + + 4.0.0 + + luckperms-bukkit-placeholders + + LuckPermsPlaceholderExpansion + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + + + + + + me.lucko.luckperms + luckperms-api + ${project.version} + compile + + + + org.bukkit + bukkit + 1.8.8-R0.1-SNAPSHOT + provided + + + + me.clip + placeholderapi + 2.2.0 + provided + + + + diff --git a/bukkit-placeholders/src/main/java/me/lucko/luckperms/api/placeholders/LuckPermsPlaceholderExpansion.java b/bukkit-placeholders/src/main/java/me/lucko/luckperms/api/placeholders/LuckPermsPlaceholderExpansion.java new file mode 100644 index 00000000..f2843eb1 --- /dev/null +++ b/bukkit-placeholders/src/main/java/me/lucko/luckperms/api/placeholders/LuckPermsPlaceholderExpansion.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api.placeholders; + +import me.clip.placeholderapi.PlaceholderAPIPlugin; +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import me.clip.placeholderapi.util.TimeUtil; +import me.lucko.luckperms.api.LuckPermsApi; +import me.lucko.luckperms.api.Track; +import me.lucko.luckperms.api.User; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.Map; +import java.util.Optional; +import java.util.regex.Pattern; + +/* + * PlaceholderAPI Expansion for LuckPerms, implemented using the LuckPerms API. + * + * Placeholders: + * - group_name + * - has_permission_ + * - inherits_permission_ + * - in_group_ + * - inherits_group_ + * - on_track_ + * - expiry_time_ + * - group_expiry_time_ + * - prefix + * - suffix + * - meta_ + */ +public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion { + private static final String IDENTIFIER = "LuckPerms"; + private static final String PLUGIN_NAME = "LuckPerms"; + private static final String AUTHOR = "Luck"; + + private LuckPermsApi api = null; + + @Override + public boolean canRegister() { + return Bukkit.getServicesManager().isProvidedFor(LuckPermsApi.class); + } + + @Override + public boolean register() { + if (!canRegister()) { + return false; + } + + api = Bukkit.getServicesManager().getRegistration(LuckPermsApi.class).getProvider(); + return super.register(); + } + + @Override + public String getVersion() { + return api == null ? "null" : api.getVersion(); + } + + @Override + public String onPlaceholderRequest(Player player, String identifier) { + if (player == null || api == null) { + return ""; + } + + Optional u = api.getUserSafe(player.getUniqueId()); + if (!u.isPresent()) { + return ""; + } + + identifier = identifier.toLowerCase(); + final User user = u.get(); + + if (identifier.equalsIgnoreCase("group_name")) { + return user.getPrimaryGroup(); + } + + if (identifier.startsWith("has_permission_") && identifier.length() > "has_permission_".length()) { + String node = identifier.substring("has_permission_".length()); + return formatBoolean(user.hasPermission(node, true)); + } + + if (identifier.startsWith("inherits_permission_") && identifier.length() > "inherits_permission_".length()) { + String node = identifier.substring("inherits_permission_".length()); + return formatBoolean(user.inheritsPermission(node, true)); + } + + if (identifier.startsWith("in_group_") && identifier.length() > "in_group_".length()) { + String groupName = identifier.substring("in_group_".length()); + return formatBoolean(user.getGroupNames().contains(groupName)); + } + + if (identifier.startsWith("inherits_group_") && identifier.length() > "inherits_group_".length()) { + String groupName = identifier.substring("inherits_group_".length()); + return formatBoolean(user.getLocalGroups("global").contains(groupName)); + } + + if (identifier.startsWith("on_track_") && identifier.length() > "on_track_".length()) { + String trackName = identifier.substring("on_track_".length()); + + Optional track = api.getTrackSafe(trackName); + if (!track.isPresent()) return ""; + + return formatBoolean(track.get().containsGroup(user.getPrimaryGroup())); + } + + if (identifier.startsWith("expiry_time_") && identifier.length() > "expiry_time_".length()) { + String node = identifier.substring("expiry_time_".length()); + + + long currentTime = System.currentTimeMillis() / 1000L; + Map, Long> temps = user.getTemporaryNodes(); + + for (Map.Entry, Long> e : temps.entrySet()) { + if (!e.getKey().getKey().equalsIgnoreCase(node)) { + continue; + } + + return TimeUtil.getTime((int) (e.getValue() - currentTime)); + } + + return ""; + } + + if (identifier.startsWith("group_expiry_time_") && identifier.length() > "group_expiry_time_".length()) { + String node = "group." + identifier.substring("group_expiry_time_".length()); + + long currentTime = System.currentTimeMillis() / 1000L; + Map, Long> temps = user.getTemporaryNodes(); + + for (Map.Entry, Long> e : temps.entrySet()) { + if (!e.getKey().getKey().equalsIgnoreCase(node)) { + continue; + } + + return TimeUtil.getTime((int) (e.getValue() - currentTime)); + } + + return ""; + } + + if (identifier.equalsIgnoreCase("prefix")) { + return getChatMeta(PREFIX_PATTERN, user); + } + + if (identifier.equalsIgnoreCase("suffix")) { + return getChatMeta(SUFFIX_PATTERN, user); + } + + if (identifier.startsWith("meta_") && identifier.length() > "meta_".length()) { + String node = "meta." + escapeCharacters(identifier.substring("meta_".length())) + "."; + Map nodes = user.getNodes(); + + for (Map.Entry e : nodes.entrySet()) { + if (!e.getValue()) continue; + if (!e.getKey().toLowerCase().startsWith(node)) continue; + + String meta = e.getKey().substring(node.length()); + return unescapeCharacters(meta); + } + + return ""; + } + + return null; + } + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public String getPlugin() { + return PLUGIN_NAME; + } + + @Override + public String getAuthor() { + return AUTHOR; + } + + private static String formatBoolean(boolean b) { + return b ? PlaceholderAPIPlugin.booleanTrue() : PlaceholderAPIPlugin.booleanFalse(); + } + + private static String escapeCharacters(String s) { + s = s.replace(".", "{SEP}"); + s = s.replace("/", "{FSEP}"); + s = s.replace("$", "{DSEP}"); + + return s; + } + + private static String unescapeCharacters(String s) { + s = s.replace("{SEP}", "."); + s = s.replace("{FSEP}", "/"); + s = s.replace("{DSEP}", "$"); + + return s; + } + + private static final Pattern PREFIX_PATTERN = Pattern.compile("(?i)prefix\\.\\d+\\..*"); + private static final Pattern SUFFIX_PATTERN = Pattern.compile("(?i)suffix\\.\\d+\\..*"); + private static final Pattern DOT_PATTERN = Pattern.compile("\\."); + + private static String getChatMeta(Pattern pattern, User user) { + int priority = 0; + String meta = null; + for (Map.Entry e : user.getLocalPermissions(null, null).entrySet()) { + if (!e.getValue()) continue; + + if (pattern.matcher(e.getKey()).matches()) { + String[] parts = DOT_PATTERN.split(e.getKey(), 3); + int p = Integer.parseInt(parts[1]); + + if (meta == null || p > priority) { + meta = parts[2]; + priority = p; + } + } + } + + return meta == null ? "" : unescapeCharacters(meta); + } +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultChatHook.java b/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultChatHook.java index 8d9d2c15..cb03ebf5 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultChatHook.java +++ b/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultChatHook.java @@ -37,6 +37,7 @@ import java.util.Map; import java.util.regex.Pattern; import static me.lucko.luckperms.utils.ArgumentChecker.escapeCharacters; +import static me.lucko.luckperms.utils.ArgumentChecker.unescapeCharacters; /** * Provides the Vault Chat service through the use of normal permission nodes. @@ -117,7 +118,7 @@ class VaultChatHook extends Chat { } try { - return Integer.parseInt(parts[2]); + return Integer.parseInt(unescapeCharacters(parts[2])); } catch (Throwable t) { return defaultValue; } @@ -146,7 +147,7 @@ class VaultChatHook extends Chat { } try { - return Double.parseDouble(parts[2]); + return Double.parseDouble(unescapeCharacters(parts[2])); } catch (Throwable t) { return defaultValue; } @@ -175,7 +176,7 @@ class VaultChatHook extends Chat { } try { - return Boolean.parseBoolean(parts[2]); + return Boolean.parseBoolean(unescapeCharacters(parts[2])); } catch (Throwable t) { return defaultValue; } @@ -203,7 +204,7 @@ class VaultChatHook extends Chat { continue; } - return parts[2]; + return unescapeCharacters(parts[2]); } return defaultValue; @@ -228,7 +229,7 @@ class VaultChatHook extends Chat { } } - return meta == null ? "" : meta; + return meta == null ? "" : unescapeCharacters(meta); } public String getPlayerPrefix(String world, @NonNull String player) { diff --git a/common/src/main/java/me/lucko/luckperms/utils/ArgumentChecker.java b/common/src/main/java/me/lucko/luckperms/utils/ArgumentChecker.java index 1bc8efbb..b45a4fc9 100644 --- a/common/src/main/java/me/lucko/luckperms/utils/ArgumentChecker.java +++ b/common/src/main/java/me/lucko/luckperms/utils/ArgumentChecker.java @@ -56,4 +56,12 @@ public class ArgumentChecker { return s; } + public static String unescapeCharacters(String s) { + s = s.replace("{SEP}", "."); + s = s.replace("{FSEP}", "/"); + s = s.replace("{DSEP}", "$"); + + return s; + } + } diff --git a/pom.xml b/pom.xml index 49aa5679..f4a10883 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,7 @@ common api bukkit + bukkit-placeholders bungee sponge @@ -83,5 +84,9 @@ bungeeperms-repo http://repo.wea-ondara.net/repository/public/ + + placeholderapi + http://repo.extendedclip.com/content/repositories/placeholderapi/ +