diff --git a/pom.xml b/pom.xml index 0659e44e2..9898cca3a 100644 --- a/pom.xml +++ b/pom.xml @@ -266,6 +266,12 @@ http://repo.onarandombox.com/content/groups/public + + + luck-repo + https://repo.lucko.me/ + + vault-repo @@ -441,6 +447,14 @@ + + + me.lucko.luckperms + luckperms-api + 3.4-SNAPSHOT + provided + + ru.tehkode diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java index 2f443ccac..a1ed91c09 100644 --- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java +++ b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java @@ -3,6 +3,7 @@ package fr.xephi.authme.permission; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.permission.handlers.BPermissionsHandler; +import fr.xephi.authme.permission.handlers.LuckPermsHandler; import fr.xephi.authme.permission.handlers.PermissionHandler; import fr.xephi.authme.permission.handlers.PermissionHandlerException; import fr.xephi.authme.permission.handlers.PermissionsExHandler; @@ -111,6 +112,8 @@ public class PermissionsManager implements Reloadable { } switch (type) { + case LUCK_PERMS: + return new LuckPermsHandler(); case PERMISSIONS_EX: return new PermissionsExHandler(); case Z_PERMISSIONS: diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsSystemType.java b/src/main/java/fr/xephi/authme/permission/PermissionsSystemType.java index bfa8fa115..0a87d46cf 100644 --- a/src/main/java/fr/xephi/authme/permission/PermissionsSystemType.java +++ b/src/main/java/fr/xephi/authme/permission/PermissionsSystemType.java @@ -5,6 +5,11 @@ package fr.xephi.authme.permission; */ public enum PermissionsSystemType { + /** + * LuckPerms. + */ + LUCK_PERMS("LuckPerms", "LuckPerms"), + /** * Permissions Ex. */ diff --git a/src/main/java/fr/xephi/authme/permission/handlers/LuckPermsHandler.java b/src/main/java/fr/xephi/authme/permission/handlers/LuckPermsHandler.java new file mode 100644 index 000000000..c9074b0c4 --- /dev/null +++ b/src/main/java/fr/xephi/authme/permission/handlers/LuckPermsHandler.java @@ -0,0 +1,216 @@ +package fr.xephi.authme.permission.handlers; + +import fr.xephi.authme.permission.PermissionNode; +import fr.xephi.authme.permission.PermissionsSystemType; +import me.lucko.luckperms.LuckPerms; +import me.lucko.luckperms.api.DataMutateResult; +import me.lucko.luckperms.api.Group; +import me.lucko.luckperms.api.LuckPermsApi; +import me.lucko.luckperms.api.Node; +import me.lucko.luckperms.api.User; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * Handler for LuckPerms. + * + * @see LuckPerms SpigotMC page + * @see LuckPerms on Github + */ +public class LuckPermsHandler implements PermissionHandler { + + private LuckPermsApi luckPermsApi; + + public LuckPermsHandler() throws PermissionHandlerException { + try { + luckPermsApi = LuckPerms.getApi(); + } catch (IllegalStateException e) { + e.printStackTrace(); + throw new PermissionHandlerException("Could not get api of LuckPerms"); + } + } + + private User getUser(String playerName) { + Player player = Bukkit.getPlayerExact(playerName); + if (player != null) { + return getUser(player); + } + + UUID uuid = luckPermsApi.getStorage().getUUID(playerName).join(); + if (uuid == null) { + return null; + } + + return getUser(uuid); + } + + private User getUser(OfflinePlayer player) { + return getUser(player.getUniqueId()); + } + + private User getUser(UUID playerUuid) { + User user = luckPermsApi.getUser(playerUuid); + if (user == null) { + // user not loaded, we need to load them from the storage. + // this is a blocking call. + luckPermsApi.getStorage().loadUser(playerUuid).join(); + + // then grab a new instance + user = luckPermsApi.getUser(playerUuid); + } + return user; + } + + private void saveUser(User user) { + luckPermsApi.getStorage().saveUser(user) + .thenAcceptAsync(wasSuccessful -> { + if (!wasSuccessful) { + return; + } + user.refreshPermissions(); + }, luckPermsApi.getStorage().getAsyncExecutor()); + } + + private void cleanupUser(User user) { + if (Bukkit.getPlayer(user.getUuid()) != null) { + luckPermsApi.cleanupUser(user); + } + } + + @Override + public boolean addToGroup(OfflinePlayer player, String group) { + Group newGroup = luckPermsApi.getGroup(group); + if (newGroup == null) { + return false; + } + + User user = getUser(player); + if (user == null) { + return false; + } + + DataMutateResult result = user.setPermissionUnchecked(luckPermsApi.getNodeFactory().makeGroupNode(newGroup).build()); + if (result == DataMutateResult.FAIL) { + return false; + } + + saveUser(user); + cleanupUser(user); + + return true; + } + + @Override + public boolean hasGroupSupport() { + return true; + } + + @Override + public boolean hasPermissionOffline(String name, PermissionNode node) { + User user = getUser(name); + if (user == null) { + return false; + } + + Node permissionNode = luckPermsApi.getNodeFactory().newBuilder(node.getNode()).build(); + boolean result = user.hasPermission(permissionNode).asBoolean(); + + cleanupUser(user); + return result; + } + + @Override + public boolean isInGroup(OfflinePlayer player, String group) { + User user = getUser(player); + if (user == null) { + return false; + } + + Group permissionGroup = luckPermsApi.getGroup(group); + boolean result = permissionGroup != null && user.isInGroup(permissionGroup); + + cleanupUser(user); + return result; + } + + @Override + public boolean removeFromGroup(OfflinePlayer player, String group) { + User user = getUser(player); + if (user == null) { + return false; + } + + Group permissionGroup = luckPermsApi.getGroup(group); + if (permissionGroup == null) { + return false; + } + + Node groupNode = luckPermsApi.getNodeFactory().makeGroupNode(permissionGroup).build(); + boolean result = user.unsetPermissionUnchecked(groupNode) != DataMutateResult.FAIL; + + cleanupUser(user); + return result; + } + + @Override + public boolean setGroup(OfflinePlayer player, String group) { + User user = getUser(player); + if (user == null) { + return false; + } + Group permissionGroup = luckPermsApi.getGroup(group); + if (permissionGroup == null) { + return false; + } + Node groupNode = luckPermsApi.getNodeFactory().makeGroupNode(permissionGroup).build(); + DataMutateResult result = user.setPermissionUnchecked(groupNode); + if (result == DataMutateResult.FAIL) { + return false; + } + user.clearMatching(node -> node.isGroupNode() && !node.getGroupName().equals(permissionGroup.getName())); + + saveUser(user); + cleanupUser(user); + return true; + } + + @Override + public List getGroups(OfflinePlayer player) { + User user = getUser(player); + if (user == null) { + return Collections.emptyList(); + } + + List result = user.getOwnNodes().stream() + .filter(Node::isGroupNode) + .map(n -> luckPermsApi.getGroupSafe(n.getGroupName())) + .filter(Optional::isPresent) + .map(Optional::get) + .distinct() + .sorted((o1, o2) -> { + if (o1.getName().equals(user.getPrimaryGroup()) || o2.getName().equals(user.getPrimaryGroup())) { + return o1.getName().equals(user.getPrimaryGroup()) ? 1 : -1; + } + + int i = Integer.compare(o2.getWeight().orElse(0), o1.getWeight().orElse(0)); + return i != 0 ? i : o1.getName().compareToIgnoreCase(o2.getName()); + }) + .map(Group::getName) + .collect(Collectors.toList()); + + cleanupUser(user); + return result; + } + + @Override + public PermissionsSystemType getPermissionSystem() { + return PermissionsSystemType.LUCK_PERMS; + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 472faef6c..d0d38ad2d 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -6,6 +6,7 @@ main: ${bukkitplugin.main} version: ${bukkitplugin.version} softdepend: - Vault + - LuckPerms - PermissionsEx - bPermissions - zPermissions