rewrite Vault implementation to upgrade requests to uuids instead of downgrade to usernames

This commit is contained in:
Luck 2017-12-23 18:25:23 +00:00
parent 0b72507e2d
commit 5a34fa182a
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
6 changed files with 1335 additions and 617 deletions

View File

@ -0,0 +1,591 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* 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.bukkit.vault;
import net.milkbowl.vault.chat.Chat;
import net.milkbowl.vault.permission.Permission;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.UUID;
import java.util.function.Function;
/**
* An extended abstraction of the Vault {@link Chat} API.
*
* The original Vault API only contained methods to query data by username. Over
* time, the maintainers added additional methods to query by (Offline)Player, but
* in order to keep backwards compatibility with implementations which only supported
* usernames, they implemented the Player query methods and downgraded the requests
* to get a result using the players username.
*
* Whilst this meant the old plugins would still be supported, it made the whole
* API a total mess. This class reverses this decision, and instead upgrades
* requests to use UUIDs. This makes implementing Vault significantly easier for modern
* plugins, and because requests are upgraded instead of being downgraded then upgraded,
* much faster for plugins querying data.
*/
@SuppressWarnings("deprecation")
public abstract class AbstractVaultChat extends Chat {
// when upgrading and forwarding requests, all world strings are passed through this function.
// it lets the overriding class define some custom behaviour for world handling.
protected Function<String, String> worldMappingFunction = Function.identity();
// the permission api instance
private final Permission permissionApi;
public AbstractVaultChat(Permission permissionApi) {
super(permissionApi);
this.permissionApi = permissionApi;
}
@Override
public boolean isEnabled() {
// always return true
return true;
}
// methods subclasses are expected to implement
public abstract String getPlayerPrefix(String world, UUID uuid);
public abstract String getPlayerSuffix(String world, UUID uuid);
public abstract void setPlayerPrefix(String world, UUID uuid, String prefix);
public abstract void setPlayerSuffix(String world, UUID uuid, String suffix);
public abstract String getPlayerInfo(String world, UUID uuid, String key);
public abstract void setPlayerInfo(String world, UUID uuid, String key, Object value);
public abstract String getGroupsPrefix(String world, String name); // note "groups" not "group"
public abstract String getGroupsSuffix(String world, String name); // note "groups" not "group"
public abstract void setGroupsPrefix(String world, String name, String prefix); // note "groups" not "group"
public abstract void setGroupsSuffix(String world, String name, String suffix); // note "groups" not "group"
public abstract String getGroupInfo(String world, String name, String key);
public abstract void setGroupInfo(String world, String name, String key, Object value);
// utility methods for parsing metadata values from strings
private static String strConvert(String s, String def) {
if (s != null) {
return s;
}
return def;
}
private static int intConvert(String s, int def) {
if (s == null) {
return def;
}
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return def;
}
}
private static double doubleConvert(String s, double def) {
if (s == null) {
return def;
}
try {
return Double.parseDouble(s);
} catch (NumberFormatException e) {
return def;
}
}
private static boolean booleanConvert(String s, boolean def) {
if (s == null) {
return def;
}
if (s.equalsIgnoreCase("true")) {
return true;
} else if (s.equalsIgnoreCase("false")) {
return false;
}
return def;
}
// utility methods for upgrading legacy requests
private static UUID player(String player) {
if (player == null) {
return null;
}
return player(Bukkit.getOfflinePlayer(player));
}
private static UUID player(OfflinePlayer player) {
if (player == null) {
return null;
}
return player.getUniqueId();
}
private String world(String world) {
return worldMappingFunction.apply(world);
}
private String world(Player player) {
if (player == null) {
return null;
}
return world(player.getWorld());
}
private String world(World world) {
if (world == null) {
return null;
}
return world(world.getName());
}
@Override
public String getPlayerPrefix(String world, String player) {
return getPlayerPrefix(world(world), player(player));
}
@Override
public String getPlayerPrefix(String world, OfflinePlayer player) {
return getPlayerPrefix(world(world), player(player));
}
@Override
public String getPlayerPrefix(World world, String player) {
return getPlayerPrefix(world(world), player(player));
}
@Override
public String getPlayerPrefix(Player player) {
return getPlayerPrefix(world(player), player(player));
}
@Override
public void setPlayerPrefix(String world, String player, String prefix) {
setPlayerPrefix(world(world), player(player), prefix);
}
@Override
public void setPlayerPrefix(String world, OfflinePlayer player, String prefix) {
setPlayerPrefix(world(world), player(player), prefix);
}
@Override
public void setPlayerPrefix(World world, String player, String prefix) {
setPlayerPrefix(world(world), player(player), prefix);
}
@Override
public void setPlayerPrefix(Player player, String prefix) {
setPlayerPrefix(world(player), player(player), prefix);
}
@Override
public String getPlayerSuffix(String world, String player) {
return getPlayerSuffix(world(world), player(player));
}
@Override
public String getPlayerSuffix(String world, OfflinePlayer player) {
return getPlayerSuffix(world(world), player(player));
}
@Override
public String getPlayerSuffix(World world, String player) {
return getPlayerSuffix(world(world), player(player));
}
@Override
public String getPlayerSuffix(Player player) {
return getPlayerSuffix(world(player), player(player));
}
@Override
public void setPlayerSuffix(String world, String player, String suffix) {
setPlayerSuffix(world(world), player(player), suffix);
}
@Override
public void setPlayerSuffix(String world, OfflinePlayer player, String suffix) {
setPlayerSuffix(world(world), player(player), suffix);
}
@Override
public void setPlayerSuffix(World world, String player, String suffix) {
setPlayerSuffix(world(world), player(player), suffix);
}
@Override
public void setPlayerSuffix(Player player, String suffix) {
setPlayerSuffix(world(player), player(player), suffix);
}
@Override
public String getGroupPrefix(String world, String group) {
return getGroupsPrefix(world(world), group);
}
@Override
public String getGroupPrefix(World world, String group) {
return getGroupsPrefix(world(world), group);
}
@Override
public void setGroupPrefix(String world, String group, String prefix) {
setGroupsPrefix(world(world), group, prefix);
}
@Override
public void setGroupPrefix(World world, String group, String prefix) {
setGroupsPrefix(world(world), group, prefix);
}
@Override
public String getGroupSuffix(String world, String group) {
return getGroupsSuffix(world(world), group);
}
@Override
public String getGroupSuffix(World world, String group) {
return getGroupsSuffix(world(world), group);
}
@Override
public void setGroupSuffix(String world, String group, String suffix) {
setGroupsSuffix(world(world), group, suffix);
}
@Override
public void setGroupSuffix(World world, String group, String suffix) {
setGroupsSuffix(world(world), group, suffix);
}
@Override
public int getPlayerInfoInteger(String world, OfflinePlayer player, String node, int defaultValue) {
return intConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
}
@Override
public int getPlayerInfoInteger(String world, String player, String node, int defaultValue) {
return intConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
}
@Override
public int getPlayerInfoInteger(World world, String player, String node, int defaultValue) {
return intConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
}
@Override
public int getPlayerInfoInteger(Player player, String node, int defaultValue) {
return intConvert(getPlayerInfo(world(player), player(player), node), defaultValue);
}
@Override
public void setPlayerInfoInteger(String world, OfflinePlayer player, String node, int value) {
setPlayerInfo(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoInteger(String world, String player, String node, int value) {
setPlayerInfo(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoInteger(World world, String player, String node, int value) {
setPlayerInfo(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoInteger(Player player, String node, int value) {
setPlayerInfo(world(player), player(player), node, value);
}
@Override
public int getGroupInfoInteger(String world, String group, String node, int defaultValue) {
return intConvert(getGroupInfo(world(world), group, node), defaultValue);
}
@Override
public int getGroupInfoInteger(World world, String group, String node, int defaultValue) {
return intConvert(getGroupInfo(world(world), group, node), defaultValue);
}
@Override
public void setGroupInfoInteger(String world, String group, String node, int value) {
setGroupInfo(world(world), group, node, value);
}
@Override
public void setGroupInfoInteger(World world, String group, String node, int value) {
setGroupInfo(world(world), group, node, value);
}
@Override
public double getPlayerInfoDouble(String world, OfflinePlayer player, String node, double defaultValue) {
return doubleConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
}
@Override
public double getPlayerInfoDouble(String world, String player, String node, double defaultValue) {
return doubleConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
}
@Override
public double getPlayerInfoDouble(World world, String player, String node, double defaultValue) {
return doubleConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
}
@Override
public double getPlayerInfoDouble(Player player, String node, double defaultValue) {
return doubleConvert(getPlayerInfo(world(player), player(player), node), defaultValue);
}
@Override
public void setPlayerInfoDouble(String world, OfflinePlayer player, String node, double value) {
setPlayerInfo(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoDouble(String world, String player, String node, double value) {
setPlayerInfo(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoDouble(World world, String player, String node, double value) {
setPlayerInfo(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoDouble(Player player, String node, double value) {
setPlayerInfo(world(player), player(player), node, value);
}
@Override
public double getGroupInfoDouble(String world, String group, String node, double defaultValue) {
return doubleConvert(getGroupInfo(world(world), group, node), defaultValue);
}
@Override
public double getGroupInfoDouble(World world, String group, String node, double defaultValue) {
return doubleConvert(getGroupInfo(world(world), group, node), defaultValue);
}
@Override
public void setGroupInfoDouble(String world, String group, String node, double value) {
setGroupInfo(world(world), group, node, value);
}
@Override
public void setGroupInfoDouble(World world, String group, String node, double value) {
setGroupInfo(world(world), group, node, value);
}
@Override
public boolean getPlayerInfoBoolean(String world, OfflinePlayer player, String node, boolean defaultValue) {
return booleanConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
}
@Override
public boolean getPlayerInfoBoolean(String world, String player, String node, boolean defaultValue) {
return booleanConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
}
@Override
public boolean getPlayerInfoBoolean(World world, String player, String node, boolean defaultValue) {
return booleanConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
}
@Override
public boolean getPlayerInfoBoolean(Player player, String node, boolean defaultValue) {
return booleanConvert(getPlayerInfo(world(player), player(player), node), defaultValue);
}
@Override
public void setPlayerInfoBoolean(String world, OfflinePlayer player, String node, boolean value) {
setPlayerInfo(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoBoolean(String world, String player, String node, boolean value) {
setPlayerInfo(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoBoolean(World world, String player, String node, boolean value) {
setPlayerInfo(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoBoolean(Player player, String node, boolean value) {
setPlayerInfo(world(player), player(player), node, value);
}
@Override
public boolean getGroupInfoBoolean(String world, String group, String node, boolean defaultValue) {
return booleanConvert(getGroupInfo(world(world), group, node), defaultValue);
}
@Override
public boolean getGroupInfoBoolean(World world, String group, String node, boolean defaultValue) {
return booleanConvert(getGroupInfo(world(world), group, node), defaultValue);
}
@Override
public void setGroupInfoBoolean(String world, String group, String node, boolean value) {
setGroupInfo(world(world), group, node, value);
}
@Override
public void setGroupInfoBoolean(World world, String group, String node, boolean value) {
setGroupInfo(world(world), group, node, value);
}
@Override
public String getPlayerInfoString(String world, OfflinePlayer player, String node, String defaultValue) {
return strConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
}
@Override
public String getPlayerInfoString(String world, String player, String node, String defaultValue) {
return strConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
}
@Override
public String getPlayerInfoString(World world, String player, String node, String defaultValue) {
return strConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
}
@Override
public String getPlayerInfoString(Player player, String node, String defaultValue) {
return strConvert(getPlayerInfo(world(player), player(player), node), defaultValue);
}
@Override
public void setPlayerInfoString(String world, OfflinePlayer player, String node, String value) {
setPlayerInfo(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoString(String world, String player, String node, String value) {
setPlayerInfo(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoString(World world, String player, String node, String value) {
setPlayerInfo(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoString(Player player, String node, String value) {
setPlayerInfo(world(player), player(player), node, value);
}
@Override
public String getGroupInfoString(String world, String group, String node, String defaultValue) {
return strConvert(getGroupInfo(world(world), group, node), defaultValue);
}
@Override
public String getGroupInfoString(World world, String group, String node, String defaultValue) {
return strConvert(getGroupInfo(world(world), group, node), defaultValue);
}
@Override
public void setGroupInfoString(String world, String group, String node, String value) {
setGroupInfo(world(world), group, node, value);
}
@Override
public void setGroupInfoString(World world, String group, String node, String value) {
setGroupInfo(world(world), group, node, value);
}
@Override
public boolean playerInGroup(String world, OfflinePlayer player, String group) {
return permissionApi.playerInGroup(world, player, group);
}
@Override
public boolean playerInGroup(String world, String player, String group) {
return permissionApi.playerInGroup(world, player, group);
}
@Override
public boolean playerInGroup(World world, String player, String group) {
return permissionApi.playerInGroup(world, player, group);
}
@Override
public boolean playerInGroup(Player player, String group) {
return permissionApi.playerInGroup(player, group);
}
@Override
public String[] getPlayerGroups(String world, OfflinePlayer player) {
return permissionApi.getPlayerGroups(world, player);
}
@Override
public String[] getPlayerGroups(String world, String player) {
return permissionApi.getPlayerGroups(world, player);
}
@Override
public String[] getPlayerGroups(World world, String player) {
return permissionApi.getPlayerGroups(world, player);
}
@Override
public String[] getPlayerGroups(Player player) {
return permissionApi.getPlayerGroups(player);
}
@Override
public String getPrimaryGroup(String world, OfflinePlayer player) {
return permissionApi.getPrimaryGroup(world, player);
}
@Override
public String getPrimaryGroup(String world, String player) {
return permissionApi.getPrimaryGroup(world, player);
}
@Override
public String getPrimaryGroup(World world, String player) {
return permissionApi.getPrimaryGroup(world, player);
}
@Override
public String getPrimaryGroup(Player player) {
return permissionApi.getPrimaryGroup(player);
}
@Override
public String[] getGroups() {
return permissionApi.getGroups();
}
}

View File

@ -0,0 +1,335 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* 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.bukkit.vault;
import net.milkbowl.vault.permission.Permission;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.UUID;
import java.util.function.Function;
/**
* An extended abstraction of the Vault {@link Permission} API.
*
* The original Vault API only contained methods to query data by username. Over
* time, the maintainers added additional methods to query by (Offline)Player, but
* in order to keep backwards compatibility with implementations which only supported
* usernames, they implemented the Player query methods and downgraded the requests
* to get a result using the players username.
*
* Whilst this meant the old plugins would still be supported, it made the whole
* API a total mess. This class reverses this decision, and instead upgrades
* requests to use UUIDs. This makes implementing Vault significantly easier for modern
* plugins, and because requests are upgraded instead of being downgraded then upgraded,
* much faster for plugins querying data.
*/
@SuppressWarnings("deprecation")
public abstract class AbstractVaultPermission extends Permission {
// when upgrading and forwarding requests, all world strings are passed through this function.
// it lets the overriding class define some custom behaviour for world handling.
protected Function<String, String> worldMappingFunction = Function.identity();
public AbstractVaultPermission() {
super.plugin = JavaPlugin.getProvidingPlugin(Permission.class);
}
@Override
public boolean isEnabled() {
// always return true
return true;
}
@Override
public boolean hasSuperPermsCompat() {
// always return true
return true;
}
@Override
public boolean hasGroupSupport() {
// always return true
return true;
}
// methods subclasses are expected to implement
public abstract boolean hasPermission(String world, UUID uuid, String permission);
public abstract boolean playerAddPermission(String world, UUID uuid, String permission);
public abstract boolean playerRemovePermission(String world, UUID uuid, String permission);
public abstract boolean playerInGroup(String world, UUID uuid, String group);
public abstract boolean playerAddGroup(String world, UUID uuid, String group);
public abstract boolean playerRemoveGroup(String world, UUID uuid, String group);
public abstract String[] playerGetGroups(String world, UUID uuid);
public abstract String playerPrimaryGroup(String world, UUID uuid);
public abstract boolean groupHasPermission(String world, String name, String permission);
public abstract boolean groupAddPermission(String world, String name, String permission);
public abstract boolean groupRemovePermission(String world, String name, String permission);
// utility methods for upgrading legacy requests
private static UUID player(String player) {
if (player == null) {
return null;
}
return player(Bukkit.getOfflinePlayer(player));
}
private static UUID player(OfflinePlayer player) {
if (player == null) {
return null;
}
return player.getUniqueId();
}
private String world(String world) {
return worldMappingFunction.apply(world);
}
private String world(Player player) {
if (player == null) {
return null;
}
return world(player.getWorld());
}
private String world(World world) {
if (world == null) {
return null;
}
return world(world.getName());
}
@Override
public boolean has(String world, String player, String permission) {
return hasPermission(world(world), player(player), permission);
}
@Override
public boolean has(World world, String player, String permission) {
return hasPermission(world(world), player(player), permission);
}
@Override
public boolean has(Player player, String permission) {
return hasPermission(world(player), player(player), permission);
}
@Override
public boolean playerHas(String world, String player, String permission) {
return hasPermission(world(world), player(player), permission);
}
@Override
public boolean playerHas(World world, String player, String permission) {
return hasPermission(world(world), player(player), permission);
}
@Override
public boolean playerHas(String world, OfflinePlayer player, String permission) {
return hasPermission(world(world), player(player), permission);
}
@Override
public boolean playerHas(Player player, String permission) {
return hasPermission(world(player), player(player), permission);
}
@Override
public boolean playerAdd(String world, String player, String permission) {
return playerAddPermission(world(world), player(player), permission);
}
@Override
public boolean playerAdd(World world, String player, String permission) {
return playerAddPermission(world(world), player(player), permission);
}
@Override
public boolean playerAdd(String world, OfflinePlayer player, String permission) {
return playerAddPermission(world(world), player(player), permission);
}
@Override
public boolean playerAdd(Player player, String permission) {
return playerAddPermission(world(player), player(player), permission);
}
@Override
public boolean playerRemove(String world, String player, String permission) {
return playerRemovePermission(world(world), player(player), permission);
}
@Override
public boolean playerRemove(String world, OfflinePlayer player, String permission) {
return playerRemovePermission(world(world), player(player), permission);
}
@Override
public boolean playerRemove(World world, String player, String permission) {
return playerRemovePermission(world(world), player(player), permission);
}
@Override
public boolean playerRemove(Player player, String permission) {
return playerRemovePermission(world(player), player(player), permission);
}
@Override
public boolean groupHas(String world, String group, String permission) {
return groupHasPermission(world(world), group, permission);
}
@Override
public boolean groupHas(World world, String group, String permission) {
return groupHasPermission(world(world), group, permission);
}
@Override
public boolean groupAdd(String world, String group, String permission) {
return groupAddPermission(world(world), group, permission);
}
@Override
public boolean groupAdd(World world, String group, String permission) {
return groupAddPermission(world(world), group, permission);
}
@Override
public boolean groupRemove(String world, String group, String permission) {
return groupRemovePermission(world(world), group, permission);
}
@Override
public boolean groupRemove(World world, String group, String permission) {
return groupRemovePermission(world(world), group, permission);
}
@Override
public boolean playerInGroup(String world, String player, String group) {
return playerInGroup(world(world), player(player), group);
}
@Override
public boolean playerInGroup(World world, String player, String group) {
return playerInGroup(world(world), player(player), group);
}
@Override
public boolean playerInGroup(String world, OfflinePlayer player, String group) {
return playerInGroup(world(world), player(player), group);
}
@Override
public boolean playerInGroup(Player player, String group) {
return playerInGroup(world(player), player(player), group);
}
@Override
public boolean playerAddGroup(String world, String player, String group) {
return playerAddGroup(world(world), player(player), group);
}
@Override
public boolean playerAddGroup(World world, String player, String group) {
return playerAddGroup(world(world), player(player), group);
}
@Override
public boolean playerAddGroup(String world, OfflinePlayer player, String group) {
return playerAddGroup(world(world), player(player), group);
}
@Override
public boolean playerAddGroup(Player player, String group) {
return playerAddGroup(world(player), player(player), group);
}
@Override
public boolean playerRemoveGroup(String world, String player, String group) {
return playerRemoveGroup(world(world), player(player), group);
}
@Override
public boolean playerRemoveGroup(World world, String player, String group) {
return playerRemoveGroup(world(world), player(player), group);
}
@Override
public boolean playerRemoveGroup(String world, OfflinePlayer player, String group) {
return playerRemoveGroup(world(world), player(player), group);
}
@Override
public boolean playerRemoveGroup(Player player, String group) {
return playerRemoveGroup(world(player), player(player), group);
}
@Override
public String[] getPlayerGroups(String world, String player) {
return playerGetGroups(world(world), player(player));
}
@Override
public String[] getPlayerGroups(World world, String player) {
return playerGetGroups(world(world), player(player));
}
@Override
public String[] getPlayerGroups(String world, OfflinePlayer player) {
return playerGetGroups(world(world), player(player));
}
@Override
public String[] getPlayerGroups(Player player) {
return playerGetGroups(world(player), player(player));
}
@Override
public String getPrimaryGroup(String world, String player) {
return playerPrimaryGroup(world(world), player(player));
}
@Override
public String getPrimaryGroup(World world, String player) {
return playerPrimaryGroup(world(world), player(player));
}
@Override
public String getPrimaryGroup(String world, OfflinePlayer player) {
return playerPrimaryGroup(world(world), player(player));
}
@Override
public String getPrimaryGroup(Player player) {
return playerPrimaryGroup(world(player), player(player));
}
}

View File

@ -25,13 +25,17 @@
package me.lucko.luckperms.bukkit.vault;
import lombok.NonNull;
import com.google.common.base.Preconditions;
import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.caching.MetaData;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.caching.type.MetaAccumulator;
import me.lucko.luckperms.common.caching.type.MetaCache;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
@ -39,8 +43,7 @@ import me.lucko.luckperms.common.node.NodeFactory;
import net.milkbowl.vault.chat.Chat;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.UUID;
/**
* An implementation of the Vault {@link Chat} API using LuckPerms.
@ -59,286 +62,268 @@ import org.bukkit.entity.Player;
* We cannot risk blocking the main thread to load in their data. Again, this is due to crap Vault
* design. There is nothing I can do about it.
*/
public class VaultChatHook extends Chat {
private final VaultPermissionHook perms;
public class VaultChatHook extends AbstractVaultChat {
VaultChatHook(VaultPermissionHook perms) {
super(perms);
this.perms = perms;
// the plugin instance
private final LPBukkitPlugin plugin;
// the vault permission implementation
private final VaultPermissionHook permissionHook;
VaultChatHook(LPBukkitPlugin plugin, VaultPermissionHook permissionHook) {
super(permissionHook);
this.plugin = plugin;
this.permissionHook = permissionHook;
this.worldMappingFunction = world -> permissionHook.isIgnoreWorld() ? null : world;
}
public String getName() {
return perms.getName();
}
public boolean isEnabled() {
return perms.isEnabled();
}
private User getUser(String username) {
Player player = Bukkit.getPlayerExact(username);
return player == null ? null : perms.getPlugin().getUserManager().getIfLoaded(perms.getPlugin().getUuidCache().getUUID(player.getUniqueId()));
return "LuckPerms";
}
@Override
public String getPlayerPrefix(String world, @NonNull String player) {
final User user = getUser(player);
return getHolderChatMeta(user, ChatMetaType.PREFIX, world);
public String getPlayerPrefix(String world, UUID uuid) {
Preconditions.checkNotNull(uuid, "uuid");
User user = getUser(uuid);
if (user == null) {
return null;
}
Contexts contexts = permissionHook.contextForLookup(user, world);
MetaCache metaData = user.getCachedData().getMetaData(contexts);
String ret = metaData.getPrefix();
if (log()) {
logMsg("#getPlayerPrefix: %s - %s - %s", user.getFriendlyName(), contexts.getContexts().toMultimap(), ret);
}
return ret;
}
@Override
public void setPlayerPrefix(String world, @NonNull String player, @NonNull String prefix) {
final User user = getUser(player);
public String getPlayerSuffix(String world, UUID uuid) {
Preconditions.checkNotNull(uuid, "uuid");
User user = getUser(uuid);
if (user == null) {
return null;
}
Contexts contexts = permissionHook.contextForLookup(user, world);
MetaCache metaData = user.getCachedData().getMetaData(contexts);
String ret = metaData.getSuffix();
if (log()) {
logMsg("#getPlayerSuffix: %s - %s - %s", user.getFriendlyName(), contexts.getContexts().toMultimap(), ret);
}
return ret;
}
@Override
public void setPlayerPrefix(String world, UUID uuid, String prefix) {
Preconditions.checkNotNull(uuid, "uuid");
User user = getUser(uuid);
if (user == null) {
return;
}
setChatMeta(user, ChatMetaType.PREFIX, prefix, world);
}
@Override
public String getPlayerSuffix(String world, @NonNull String player) {
final User user = getUser(player);
return getHolderChatMeta(user, ChatMetaType.SUFFIX, world);
}
@Override
public void setPlayerSuffix(String world, @NonNull String player, @NonNull String suffix) {
final User user = getUser(player);
public void setPlayerSuffix(String world, UUID uuid, String suffix) {
Preconditions.checkNotNull(uuid, "uuid");
User user = getUser(uuid);
if (user == null) {
return;
}
setChatMeta(user, ChatMetaType.SUFFIX, suffix, world);
}
@Override
public String getGroupPrefix(String world, @NonNull String group) {
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
return getHolderChatMeta(g, ChatMetaType.PREFIX, world);
}
@Override
public void setGroupPrefix(String world, @NonNull String group, @NonNull String prefix) {
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
setChatMeta(g, ChatMetaType.PREFIX, prefix, world);
}
@Override
public String getGroupSuffix(String world, @NonNull String group) {
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
return getHolderChatMeta(g, ChatMetaType.SUFFIX, world);
}
@Override
public void setGroupSuffix(String world, @NonNull String group, @NonNull String suffix) {
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
setChatMeta(g, ChatMetaType.SUFFIX, suffix, world);
}
@Override
public int getPlayerInfoInteger(String world, @NonNull String player, @NonNull String node, int defaultValue) {
final User user = getUser(player);
try {
return Integer.parseInt(getHolderMeta(user, node, world, String.valueOf(defaultValue)));
} catch (NumberFormatException e) {
return defaultValue;
public String getPlayerInfo(String world, UUID uuid, String key) {
Preconditions.checkNotNull(uuid, "uuid");
Preconditions.checkNotNull(key, "key");
User user = getUser(uuid);
if (user == null) {
return null;
}
}
@Override
public void setPlayerInfoInteger(String world, @NonNull String player, @NonNull String node, int value) {
final User user = getUser(player);
setMeta(user, node, String.valueOf(value), world);
}
@Override
public int getGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int defaultValue) {
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
try {
return Integer.parseInt(getHolderMeta(g, node, world, String.valueOf(defaultValue)));
} catch (NumberFormatException e) {
return defaultValue;
Contexts contexts = permissionHook.contextForLookup(user, world);
MetaCache metaData = user.getCachedData().getMetaData(contexts);
String ret = metaData.getMeta().get(key);
if (log()) {
logMsg("#getPlayerInfo: %s - %s - %s - %s", user.getFriendlyName(), contexts.getContexts().toMultimap(), key, ret);
}
return ret;
}
@Override
public void setGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int value) {
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
setMeta(g, node, String.valueOf(value), world);
}
@Override
public double getPlayerInfoDouble(String world, @NonNull String player, @NonNull String node, double defaultValue) {
final User user = getUser(player);
try {
return Double.parseDouble(getHolderMeta(user, node, world, String.valueOf(defaultValue)));
} catch (NumberFormatException e) {
return defaultValue;
}
}
@Override
public void setPlayerInfoDouble(String world, @NonNull String player, @NonNull String node, double value) {
final User user = getUser(player);
setMeta(user, node, String.valueOf(value), world);
}
@Override
public double getGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double defaultValue) {
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
try {
return Double.parseDouble(getHolderMeta(g, node, world, String.valueOf(defaultValue)));
} catch (NumberFormatException e) {
return defaultValue;
}
}
@Override
public void setGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double value) {
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
setMeta(g, node, String.valueOf(value), world);
}
@Override
public boolean getPlayerInfoBoolean(String world, @NonNull String player, @NonNull String node, boolean defaultValue) {
final User user = getUser(player);
String s = getHolderMeta(user, node, world, String.valueOf(defaultValue));
if (!s.equalsIgnoreCase("true") && !s.equalsIgnoreCase("false")) {
return defaultValue;
}
return Boolean.parseBoolean(s);
}
@Override
public void setPlayerInfoBoolean(String world, @NonNull String player, @NonNull String node, boolean value) {
final User user = getUser(player);
setMeta(user, node, String.valueOf(value), world);
}
@Override
public boolean getGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean defaultValue) {
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
String s = getHolderMeta(g, node, world, String.valueOf(defaultValue));
if (!s.equalsIgnoreCase("true") && !s.equalsIgnoreCase("false")) {
return defaultValue;
}
return Boolean.parseBoolean(s);
}
@Override
public void setGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean value) {
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
setMeta(g, node, String.valueOf(value), world);
}
@Override
public String getPlayerInfoString(String world, @NonNull String player, @NonNull String node, String defaultValue) {
final User user = getUser(player);
return getHolderMeta(user, node, world, defaultValue);
}
@Override
public void setPlayerInfoString(String world, @NonNull String player, @NonNull String node, String value) {
final User user = getUser(player);
setMeta(user, node, value, world);
}
@Override
public String getGroupInfoString(String world, @NonNull String group, @NonNull String node, String defaultValue) {
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
return getHolderMeta(g, node, world, defaultValue);
}
@Override
public void setGroupInfoString(String world, @NonNull String group, @NonNull String node, String value) {
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
setMeta(g, node, value, world);
}
private void setMeta(PermissionHolder holder, String key, String value, String world) {
if (holder == null || key.isEmpty()) {
public void setPlayerInfo(String world, UUID uuid, String key, Object value) {
Preconditions.checkNotNull(uuid, "uuid");
Preconditions.checkNotNull(key, "key");
User user = getUser(uuid);
if (user == null) {
return;
}
setMeta(user, key, value, world);
}
String finalWorld = perms.correctWorld(world);
perms.log("Setting meta: '" + key + "' for " + holder.getObjectName() + " on world " + world + ", server " + perms.getVaultServer());
@Override
public String getGroupsPrefix(String world, String name) {
Preconditions.checkNotNull(name, "name");
Group group = getGroup(name);
if (group == null) {
return null;
}
Contexts contexts = permissionHook.contextForLookup(null, world);
MetaCache metaData = group.getCachedData().getMetaData(contexts);
String ret = metaData.getPrefix();
if (log()) {
logMsg("#getGroupPrefix: %s - %s - %s", group.getName(), contexts.getContexts().toMultimap(), ret);
}
return ret;
}
perms.getExecutor().execute(() -> {
holder.removeIf(n -> n.isMeta() && n.getMeta().getKey().equals(key));
@Override
public String getGroupsSuffix(String world, String name) {
Preconditions.checkNotNull(name, "name");
Group group = getGroup(name);
if (group == null) {
return null;
}
Contexts contexts = permissionHook.contextForLookup(null, world);
MetaCache metaData = group.getCachedData().getMetaData(contexts);
String ret = metaData.getSuffix();
if (log()) {
logMsg("#getGroupSuffix: %s - %s - %s", group.getName(), contexts.getContexts().toMultimap(), ret);
}
return ret;
}
Node.Builder metaNode;
if (key.equalsIgnoreCase(NodeFactory.PREFIX_KEY) || key.equalsIgnoreCase(NodeFactory.SUFFIX_KEY)) {
metaNode = NodeFactory.buildChatMetaNode(ChatMetaType.valueOf(key.toUpperCase()), 100, value);
} else {
metaNode = NodeFactory.buildMetaNode(key, value);
}
@Override
public void setGroupsPrefix(String world, String name, String prefix) {
Preconditions.checkNotNull(name, "name");
Group group = getGroup(name);
if (group == null) {
return;
}
setChatMeta(group, ChatMetaType.PREFIX, prefix, world);
}
metaNode.setServer(perms.getVaultServer());
metaNode.setWorld(finalWorld);
@Override
public void setGroupsSuffix(String world, String name, String suffix) {
Preconditions.checkNotNull(name, "name");
Group group = getGroup(name);
if (group == null) {
return;
}
setChatMeta(group, ChatMetaType.SUFFIX, suffix, world);
}
holder.setPermission(metaNode.build());
perms.holderSave(holder);
});
@Override
public String getGroupInfo(String world, String name, String key) {
Preconditions.checkNotNull(name, "name");
Preconditions.checkNotNull(key, "key");
Group group = getGroup(name);
if (group == null) {
return null;
}
Contexts contexts = permissionHook.contextForLookup(null, world);
MetaCache metaData = group.getCachedData().getMetaData(contexts);
String ret = metaData.getMeta().get(key);
if (log()) {
logMsg("#getGroupInfo: %s - %s - %s - %s", group.getName(), contexts.getContexts().toMultimap(), key, ret);
}
return ret;
}
@Override
public void setGroupInfo(String world, String name, String key, Object value) {
Preconditions.checkNotNull(name, "name");
Preconditions.checkNotNull(key, "key");
Group group = getGroup(name);
if (group == null) {
return;
}
setMeta(group, key, value, world);
}
// utility methods for getting user and group instances
private User getUser(UUID uuid) {
return plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(uuid));
}
private Group getGroup(String name) {
return plugin.getGroupManager().getByDisplayName(name);
}
// logging
private boolean log() {
return plugin.getConfiguration().get(ConfigKeys.VAULT_DEBUG);
}
private void logMsg(String format, Object... args) {
plugin.getLog().info("[VAULT-CHAT] " + String.format(format, args)
.replace(CommandManager.SECTION_CHAR, '$')
.replace(CommandManager.AMPERSAND_CHAR, '$')
);
}
private void setChatMeta(PermissionHolder holder, ChatMetaType type, String value, String world) {
if (holder == null || value.equals("")) {
return;
if (log()) {
logMsg("#setChatMeta: %s - %s - %s - %s", holder.getFriendlyName(), type, value, world);
}
String finalWorld = perms.correctWorld(world);
perms.log("Setting " + type.name().toLowerCase() + " for " + holder.getObjectName() + " on world " + world + ", server " + perms.getVaultServer());
perms.getExecutor().execute(() -> {
permissionHook.getExecutor().execute(() -> {
// remove all prefixes/suffixes directly set on the user/group
holder.removeIf(type::matches);
if (value == null) {
permissionHook.holderSave(holder);
return;
}
// find the max inherited priority & add 10
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, null, perms.createContextForWorldSet(finalWorld));
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, null, createContextForWorldSet(world));
int priority = (type == ChatMetaType.PREFIX ? metaAccumulator.getPrefixes() : metaAccumulator.getSuffixes()).keySet().stream()
.mapToInt(e -> e).max().orElse(0) + 10;
Node.Builder chatMetaNode = NodeFactory.buildChatMetaNode(type, priority, value);
chatMetaNode.setServer(perms.getVaultServer());
chatMetaNode.setWorld(finalWorld);
chatMetaNode.setServer(permissionHook.getVaultServer());
chatMetaNode.setWorld(world);
holder.setPermission(chatMetaNode.build());
perms.holderSave(holder);
permissionHook.holderSave(holder);
});
}
private String getHolderMeta(PermissionHolder holder, String node, String world, String defaultValue) {
if (holder == null) {
return defaultValue;
private void setMeta(PermissionHolder holder, String key, Object value, String world) {
if (log()) {
logMsg("#setMeta: %s - %s - %s - %s", holder.getFriendlyName(), key, value, world);
}
world = perms.correctWorld(world);
permissionHook.getExecutor().execute(() -> {
holder.removeIf(n -> n.isMeta() && n.getMeta().getKey().equals(key));
Contexts contexts;
if (holder.getType().isUser()) {
contexts = perms.createContextForWorldLookup(perms.getPlugin().getPlayer((User) holder), world);
} else {
contexts = perms.createContextForWorldLookup(world);
}
if (value == null) {
permissionHook.holderSave(holder);
return;
}
perms.log("Getting meta: '" + node + "' for holder " + holder.getFriendlyName() + " in contexts " + contexts);
Node.Builder metaNode;
if (key.equalsIgnoreCase(NodeFactory.PREFIX_KEY) || key.equalsIgnoreCase(NodeFactory.SUFFIX_KEY)) {
metaNode = NodeFactory.buildChatMetaNode(ChatMetaType.valueOf(key.toUpperCase()), 100, value.toString());
} else {
metaNode = NodeFactory.buildMetaNode(key, value.toString());
}
String ret = holder.getCachedData().getMetaData(contexts).getMeta().get(node);
return ret != null ? ret : defaultValue;
metaNode.setServer(permissionHook.getVaultServer());
metaNode.setWorld(world);
holder.setPermission(metaNode.build());
permissionHook.holderSave(holder);
});
}
private String getHolderChatMeta(PermissionHolder holder, ChatMetaType type, String world) {
if (holder == null) {
return "";
private Contexts createContextForWorldSet(String world) {
MutableContextSet context = MutableContextSet.create();
if (world != null && !world.equals("") && !world.equalsIgnoreCase("global")) {
context.add(Contexts.WORLD_KEY, world.toLowerCase());
}
world = perms.correctWorld(world);
Contexts contexts;
if (holder.getType().isUser()) {
contexts = perms.createContextForWorldLookup(perms.getPlugin().getPlayer((User) holder), world);
} else {
contexts = perms.createContextForWorldLookup(world);
}
perms.log("Getting " + type.name().toLowerCase() + " for holder " + holder.getFriendlyName() + " in contexts " + contexts);
MetaData data = holder.getCachedData().getMetaData(contexts);
String ret = type == ChatMetaType.PREFIX ? data.getPrefix() : data.getSuffix();
return ret != null ? ret : "";
context.add(Contexts.SERVER_KEY, permissionHook.getVaultServer());
return new Contexts(context, permissionHook.isIncludeGlobal(), true, true, true, true, false);
}
}

View File

@ -1,70 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* 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.bukkit.vault;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import org.bukkit.scheduler.BukkitTask;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
/**
* Sequential executor for Vault modifications
*/
public class VaultExecutor implements Runnable, Executor {
private BukkitTask task = null;
private final Queue<Runnable> tasks = new ConcurrentLinkedQueue<>();
public VaultExecutor(LPBukkitPlugin plugin) {
task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this, 1L, 1L);
}
@Override
public void execute(Runnable r) {
tasks.offer(r);
}
@Override
public void run() {
for (Runnable runnable; (runnable = tasks.poll()) != null; ) {
try {
runnable.run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void close() {
if (task != null) {
task.cancel();
task = null;
}
}
}

View File

@ -56,7 +56,7 @@ public class VaultHookManager {
}
if (chatHook == null) {
chatHook = new VaultChatHook(permissionHook);
chatHook = new VaultChatHook(plugin, permissionHook);
}
final ServicesManager sm = plugin.getServer().getServicesManager();

View File

@ -26,15 +26,17 @@
package me.lucko.luckperms.bukkit.vault;
import lombok.Getter;
import lombok.NonNull;
import com.google.common.base.Preconditions;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.caching.type.PermissionCache;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
@ -44,12 +46,12 @@ import me.lucko.luckperms.common.verbose.CheckOrigin;
import net.milkbowl.vault.permission.Permission;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* An implementation of the Vault {@link Permission} API using LuckPerms.
@ -69,18 +71,18 @@ import org.bukkit.plugin.java.JavaPlugin;
* design. There is nothing I can do about it.
*/
@Getter
public class VaultPermissionHook extends Permission {
public class VaultPermissionHook extends AbstractVaultPermission {
// the plugin instance
private LPBukkitPlugin plugin;
private final LPBukkitPlugin plugin;
// an executor for Vault modifications.
private VaultExecutor executor;
private final Executor executor;
public VaultPermissionHook(LPBukkitPlugin plugin) {
this.plugin = plugin;
super.plugin = JavaPlugin.getProvidingPlugin(Permission.class);
this.executor = new VaultExecutor(plugin);
this.executor = Executors.newSingleThreadExecutor();
this.worldMappingFunction = world -> isIgnoreWorld() ? null : world;
}
@Override
@ -88,90 +90,51 @@ public class VaultPermissionHook extends Permission {
return "LuckPerms";
}
// override this check to delegate to Player#hasPermission
@Override
public boolean isEnabled() {
return plugin.isEnabled();
public boolean has(Player player, String permission) {
return player.hasPermission(permission);
}
// override this check to delegate to Player#hasPermission
@Override
public boolean hasSuperPermsCompat() {
return true;
}
@Override
public boolean hasGroupSupport() {
return true;
}
@Override
public String[] getGroups() {
return plugin.getGroupManager().getAll().values().stream().map(g -> g.getDisplayName().orElse(g.getName())).toArray(String[]::new);
}
@Override
public boolean has(@NonNull CommandSender sender, @NonNull String permission) {
return sender.hasPermission(permission);
}
@Override
public boolean has(@NonNull Player player, @NonNull String permission) {
public boolean playerHas(Player player, String permission) {
return player.hasPermission(permission);
}
@Override
public boolean playerHas(String world, @NonNull String player, @NonNull String permission) {
return playerHas(world, Bukkit.getPlayerExact(player), permission);
public String[] getGroups() {
return plugin.getGroupManager().getAll().values().stream()
.map(g -> g.getDisplayName().orElse(g.getName()))
.toArray(String[]::new);
}
@Override
public boolean playerHas(String world, @NonNull OfflinePlayer player, @NonNull String permission) {
return playerHas(world, player.getPlayer(), permission);
}
public boolean hasPermission(String world, UUID uuid, String permission) {
Preconditions.checkNotNull(uuid, "uuid");
Preconditions.checkNotNull(permission, "permission");
private boolean playerHas(String world, Player player, String permission) {
world = correctWorld(world);
if (player == null) {
return false;
}
User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(player.getUniqueId()));
User user = getUser(uuid);
if (user == null) {
return false;
}
Contexts contexts = createContextForWorldLookup(player, world);
log("Checking if player " + player + " has permission: " + permission + " in contexts " + contexts);
Contexts contexts = contextForLookup(user, world);
PermissionCache permissionData = user.getCachedData().getPermissionData(contexts);
// Effectively fallback to the standard Bukkit #hasPermission check.
return user.getCachedData().getPermissionData(contexts).getPermissionValue(permission, CheckOrigin.INTERNAL).asBoolean();
}
@Override
public boolean playerAdd(String world, @NonNull String player, @NonNull String permission) {
return playerAdd(world, Bukkit.getPlayerExact(player), permission);
}
@SuppressWarnings("deprecation")
@Override
public boolean playerAdd(World world, @NonNull String player, @NonNull String permission) {
return playerAdd(world == null ? null : world.getName(), Bukkit.getPlayerExact(player), permission);
}
@Override
public boolean playerAdd(String world, @NonNull OfflinePlayer player, @NonNull String permission) {
return playerAdd(world, player.getPlayer(), permission);
}
private boolean playerAdd(String world, Player player, String permission) {
world = correctWorld(world);
log("Adding permission to player " + player + ": '" + permission + "' on world " + world + ", server " + getVaultServer());
if (player == null) {
return false;
Tristate result = permissionData.getPermissionValue(permission, CheckOrigin.INTERNAL);
if (log()) {
logMsg("#hasPermission: %s - %s - %s - %s", user.getFriendlyName(), contexts.getContexts().toMultimap(), permission, result);
}
return result.asBoolean();
}
final User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(player.getUniqueId()));
@Override
public boolean playerAddPermission(String world, UUID uuid, String permission) {
Preconditions.checkNotNull(uuid, "uuid");
Preconditions.checkNotNull(permission, "permission");
User user = getUser(uuid);
if (user == null) {
return false;
}
@ -181,30 +144,11 @@ public class VaultPermissionHook extends Permission {
}
@Override
public boolean playerRemove(String world, @NonNull String player, @NonNull String permission) {
return playerRemove(world, Bukkit.getPlayerExact(player), permission);
}
public boolean playerRemovePermission(String world, UUID uuid, String permission) {
Preconditions.checkNotNull(uuid, "uuid");
Preconditions.checkNotNull(permission, "permission");
@Override
public boolean playerRemove(String world, @NonNull OfflinePlayer player, @NonNull String permission) {
return playerRemove(world, player.getPlayer(), permission);
}
@SuppressWarnings("deprecation")
@Override
public boolean playerRemove(World world, @NonNull String player, @NonNull String permission) {
return playerRemove(world == null ? null : world.getName(), Bukkit.getPlayerExact(player), permission);
}
private boolean playerRemove(String world, Player player, String permission) {
world = correctWorld(world);
log("Removing permission from player " + player + ": '" + permission + "' on world " + world + ", server " + getVaultServer());
if (player == null) {
return false;
}
final User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(player.getUniqueId()));
User user = getUser(uuid);
if (user == null) {
return false;
}
@ -214,64 +158,134 @@ public class VaultPermissionHook extends Permission {
}
@Override
public boolean groupHas(String world, @NonNull String groupName, @NonNull String permission) {
world = correctWorld(world);
public boolean playerInGroup(String world, UUID uuid, String group) {
Preconditions.checkNotNull(uuid, "uuid");
Preconditions.checkNotNull(group, "group");
return hasPermission(world, uuid, NodeFactory.groupNode(rewriteGroupName(group)));
}
final Group group = plugin.getGroupManager().getByDisplayName(groupName);
@Override
public boolean playerAddGroup(String world, UUID uuid, String group) {
Preconditions.checkNotNull(uuid, "uuid");
Preconditions.checkNotNull(group, "group");
return checkGroupExists(group) && playerAddPermission(world, uuid, NodeFactory.groupNode(rewriteGroupName(group)));
}
@Override
public boolean playerRemoveGroup(String world, UUID uuid, String group) {
Preconditions.checkNotNull(uuid, "uuid");
Preconditions.checkNotNull(group, "group");
return checkGroupExists(group) && playerRemovePermission(world, uuid, NodeFactory.groupNode(rewriteGroupName(group)));
}
@Override
public String[] playerGetGroups(String world, UUID uuid) {
Preconditions.checkNotNull(uuid, "uuid");
User user = getUser(uuid);
if (user == null) {
return new String[0];
}
ContextSet contexts = contextForLookup(user, world).getContexts();
String[] ret = user.getEnduringNodes().values().stream()
.filter(Node::isGroupNode)
.filter(n -> n.shouldApplyWithContext(contexts))
.map(n -> {
Group group = plugin.getGroupManager().getIfLoaded(n.getGroupName());
if (group != null) {
return group.getDisplayName().orElse(group.getName());
}
return n.getGroupName();
})
.toArray(String[]::new);
if (log()) {
logMsg("#playerGetGroups: %s - %s - %s", user.getFriendlyName(), contexts, Arrays.toString(ret));
}
return ret;
}
@Override
public String playerPrimaryGroup(String world, UUID uuid) {
Preconditions.checkNotNull(uuid, "uuid");
User user = getUser(uuid);
if (user == null) {
return null;
}
String value = user.getPrimaryGroup().getValue();
Group group = getGroup(value);
if (group != null) {
return group.getDisplayName().orElse(group.getName());
}
if (log()) {
logMsg("#playerPrimaryGroup: %s - %s - %s", user.getFriendlyName(), world, value);
}
return value;
}
@Override
public boolean groupHasPermission(String world, String name, String permission) {
Preconditions.checkNotNull(name, "name");
Preconditions.checkNotNull(permission, "permission");
Group group = getGroup(name);
if (group == null) {
return false;
}
Contexts contexts = createContextForWorldLookup(world);
log("Checking if group " + groupName + " has permission: " + permission + " in contexts " + contexts);
Contexts contexts = contextForLookup(null, world);
PermissionCache permissionData = group.getCachedData().getPermissionData(contexts);
// Effectively fallback to the standard Bukkit #hasPermission check.
return group.getCachedData().getPermissionData(createContextForWorldLookup(world)).getPermissionValue(permission, CheckOrigin.INTERNAL).asBoolean();
Tristate result = permissionData.getPermissionValue(permission, CheckOrigin.INTERNAL);
if (log()) {
logMsg("#groupHasPermission: %s - %s - %s - %s", group.getName(), contexts.getContexts().toMultimap(), permission, result);
}
return result.asBoolean();
}
@Override
public boolean groupAdd(String world, @NonNull String groupName, @NonNull String permission) {
world = correctWorld(world);
log("Adding permission to group " + groupName + ": '" + permission + "' on world " + world + ", server " + getVaultServer());
public boolean groupAddPermission(String world, String name, String permission) {
Preconditions.checkNotNull(name, "name");
Preconditions.checkNotNull(permission, "permission");
final Group group = plugin.getGroupManager().getByDisplayName(groupName);
if (group == null) return false;
Group group = getGroup(name);
if (group == null) {
return false;
}
holderAddPermission(group, permission, world);
return true;
}
@Override
public boolean groupRemove(String world, @NonNull String groupName, @NonNull String permission) {
world = correctWorld(world);
log("Removing permission from group " + groupName + ": '" + permission + "' on world " + world + ", server " + getVaultServer());
public boolean groupRemovePermission(String world, String name, String permission) {
Preconditions.checkNotNull(name, "name");
Preconditions.checkNotNull(permission, "permission");
final Group group = plugin.getGroupManager().getByDisplayName(groupName);
if (group == null) return false;
Group group = getGroup(name);
if (group == null) {
return false;
}
holderRemovePermission(group, permission, world);
return true;
}
@Override
public boolean playerInGroup(String world, String player, @NonNull String group) {
return playerHas(world, player, NodeFactory.groupNode(rewriteGroupName(group)));
// utility methods for getting user and group instances
private User getUser(UUID uuid) {
return plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(uuid));
}
@SuppressWarnings("deprecation")
@Override
public boolean playerInGroup(World world, String player, @NonNull String group) {
return playerHas(world, player, NodeFactory.groupNode(rewriteGroupName(group)));
}
@Override
public boolean playerInGroup(String world, OfflinePlayer player, @NonNull String group) {
return playerHas(world, player, NodeFactory.groupNode(rewriteGroupName(group)));
}
@Override
public boolean playerInGroup(Player player, @NonNull String group) {
return playerHas(player, NodeFactory.groupNode(rewriteGroupName(group)));
private Group getGroup(String name) {
return plugin.getGroupManager().getByDisplayName(name);
}
private boolean checkGroupExists(String group) {
@ -286,139 +300,49 @@ public class VaultPermissionHook extends Permission {
return name;
}
@Override
public boolean playerAddGroup(String world, String player, @NonNull String group) {
return checkGroupExists(group) && playerAdd(world, player, NodeFactory.groupNode(rewriteGroupName(group)));
// logging
private boolean log() {
return plugin.getConfiguration().get(ConfigKeys.VAULT_DEBUG);
}
private void logMsg(String format, Object... args) {
plugin.getLog().info("[VAULT-PERMS] " + String.format(format, args)
.replace(CommandManager.SECTION_CHAR, '$')
.replace(CommandManager.AMPERSAND_CHAR, '$')
);
}
@SuppressWarnings("deprecation")
@Override
public boolean playerAddGroup(World world, String player, @NonNull String group) {
return checkGroupExists(group) && playerAdd(world, player, NodeFactory.groupNode(rewriteGroupName(group)));
}
// utility method for getting a contexts instance for a given vault lookup.
Contexts contextForLookup(User user, String world) {
MutableContextSet context;
@Override
public boolean playerAddGroup(String world, OfflinePlayer player, @NonNull String group) {
return checkGroupExists(group) && playerAdd(world, player, NodeFactory.groupNode(rewriteGroupName(group)));
}
@Override
public boolean playerAddGroup(Player player, @NonNull String group) {
return checkGroupExists(group) && playerAdd(player, NodeFactory.groupNode(rewriteGroupName(group)));
}
@Override
public boolean playerRemoveGroup(String world, String player, @NonNull String group) {
return checkGroupExists(group) && playerRemove(world, player, NodeFactory.groupNode(rewriteGroupName(group)));
}
@SuppressWarnings("deprecation")
@Override
public boolean playerRemoveGroup(World world, String player, @NonNull String group) {
return checkGroupExists(group) && playerRemove(world, player, NodeFactory.groupNode(rewriteGroupName(group)));
}
@Override
public boolean playerRemoveGroup(String world, OfflinePlayer player, @NonNull String group) {
return checkGroupExists(group) && playerRemove(world, player, NodeFactory.groupNode(rewriteGroupName(group)));
}
@Override
public boolean playerRemoveGroup(Player player, @NonNull String group) {
return checkGroupExists(group) && playerRemove(player, NodeFactory.groupNode(rewriteGroupName(group)));
}
@Override
public String[] getPlayerGroups(String world, @NonNull String player) {
return getPlayerGroups(world, Bukkit.getPlayerExact(player));
}
@SuppressWarnings("deprecation")
@Override
public String[] getPlayerGroups(World world, @NonNull String player) {
return getPlayerGroups(world == null ? null : world.getName(), Bukkit.getPlayerExact(player));
}
@Override
public String[] getPlayerGroups(String world, @NonNull OfflinePlayer player) {
return getPlayerGroups(world, player.getPlayer());
}
private String[] getPlayerGroups(String world, Player player) {
world = correctWorld(world);
if (player == null) {
return new String[0];
Player player = user == null ? null : plugin.getPlayer(user);
if (player != null) {
context = plugin.getContextManager().getApplicableContext(player).mutableCopy();
} else {
context = plugin.getContextManager().getStaticContext().mutableCopy();
}
User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(player.getUniqueId()));
if (user == null) {
return new String[0];
// if world is null, we want to do a lookup in the players current context
// if world is not null, we want to do a lookup in that specific world
if (world != null && !world.isEmpty()) {
// remove already accumulated worlds
context.removeAll(Contexts.WORLD_KEY);
// add the vault world
context.add(Contexts.WORLD_KEY, world.toLowerCase());
}
ContextSet contexts = createContextForWorldLookup(player, world).getContexts();
log("Getting groups of player: " + player + " in contexts " + contexts);
// if we're using a special vault server
if (useVaultServer()) {
// remove the normal server context from the set
context.remove(Contexts.SERVER_KEY, getServer());
return user.getEnduringNodes().values().stream()
.filter(Node::isGroupNode)
.filter(n -> n.shouldApplyWithContext(contexts))
.map(n -> {
Group group = plugin.getGroupManager().getIfLoaded(n.getGroupName());
if (group != null) {
return group.getDisplayName().orElse(group.getName());
}
return n.getGroupName();
})
.toArray(String[]::new);
}
@Override
public String getPrimaryGroup(String world, @NonNull String player) {
return getPrimaryGroup(Bukkit.getPlayerExact(player));
}
@SuppressWarnings("deprecation")
@Override
public String getPrimaryGroup(World world, @NonNull String player) {
return getPrimaryGroup(Bukkit.getPlayerExact(player));
}
@Override
public String getPrimaryGroup(String world, @NonNull OfflinePlayer player) {
return getPrimaryGroup(player.getPlayer());
}
@Override
public String getPrimaryGroup(Player player) {
log("Getting primary group of player: " + player);
if (player == null) {
return null;
// add the vault specific server
if (!getVaultServer().equals("global")) {
context.add(Contexts.SERVER_KEY, getVaultServer());
}
}
final User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(player.getUniqueId()));
if (user == null) {
return null;
}
String g = user.getPrimaryGroup().getValue();
Group group = plugin.getGroupManager().getByDisplayName(g);
if (group != null) {
return group.getDisplayName().orElse(group.getName());
}
return g;
}
public void log(String s) {
if (plugin.getConfiguration().get(ConfigKeys.VAULT_DEBUG)) {
plugin.getLog().info("[VAULT] " + s);
}
}
String correctWorld(String world) {
return isIgnoreWorld() ? null : world;
return new Contexts(context, isIncludeGlobal(), true, true, true, true, false);
}
// utility methods for modifying the state of PermissionHolders
@ -426,6 +350,11 @@ public class VaultPermissionHook extends Permission {
private void holderAddPermission(PermissionHolder holder, String permission, String world) {
Preconditions.checkNotNull(permission, "permission is null");
Preconditions.checkArgument(!permission.isEmpty(), "permission is an empty string");
if (log()) {
logMsg("#holderAddPermission: %s - %s - %s", holder.getFriendlyName(), permission, world);
}
executor.execute(() -> {
if (holder.setPermission(NodeFactory.make(permission, true, getVaultServer(), world)).asBoolean()) {
holderSave(holder);
@ -436,6 +365,11 @@ public class VaultPermissionHook extends Permission {
private void holderRemovePermission(PermissionHolder holder, String permission, String world) {
Preconditions.checkNotNull(permission, "permission is null");
Preconditions.checkArgument(!permission.isEmpty(), "permission is an empty string");
if (log()) {
logMsg("#holderRemovePermission: %s - %s - %s", holder.getFriendlyName(), permission, world);
}
executor.execute(() -> {
if (holder.unsetPermission(NodeFactory.make(permission, getVaultServer(), world)).asBoolean()) {
holderSave(holder);
@ -454,63 +388,6 @@ public class VaultPermissionHook extends Permission {
}
}
// helper methods to build Contexts instances for different world/server combinations
public Contexts createContextForWorldSet(String world) {
MutableContextSet context = MutableContextSet.create();
if (world != null && !world.equals("") && !world.equalsIgnoreCase("global")) {
context.add(Contexts.WORLD_KEY, world.toLowerCase());
}
context.add(Contexts.SERVER_KEY, getVaultServer());
return new Contexts(context, isIncludeGlobal(), true, true, true, true, false);
}
public Contexts createContextForWorldLookup(String world) {
MutableContextSet context = plugin.getContextManager().getStaticContext().mutableCopy();
if (useVaultServer()) {
// remove already accumulated worlds
context.removeAll(Contexts.WORLD_KEY);
// add the vault world
if (world != null && !world.isEmpty() && !world.equalsIgnoreCase("global")) {
context.add(Contexts.WORLD_KEY, world.toLowerCase());
}
// remove the server context from global
context.remove(Contexts.SERVER_KEY, getServer());
// add the vault specific server
if (!getVaultServer().equals("global")) {
context.add(Contexts.SERVER_KEY, getVaultServer());
}
}
return new Contexts(context, isIncludeGlobal(), true, true, true, true, false);
}
public Contexts createContextForWorldLookup(@NonNull Player player, String world) {
MutableContextSet context = plugin.getContextManager().getApplicableContext(player).mutableCopy();
if (useVaultServer()) {
// remove already accumulated worlds
context.removeAll(Contexts.WORLD_KEY);
// add the vault world
if (world != null && !world.isEmpty() && !world.equalsIgnoreCase("global")) {
context.add(Contexts.WORLD_KEY, world.toLowerCase());
}
// remove the server context from global
context.remove(Contexts.SERVER_KEY, getServer());
// add the vault specific server
if (!getVaultServer().equals("global")) {
context.add(Contexts.SERVER_KEY, getVaultServer());
}
}
return new Contexts(context, isIncludeGlobal(), true, true, true, true, false);
}
// helper methods to just pull values from the config.
String getServer() {
@ -521,10 +398,6 @@ public class VaultPermissionHook extends Permission {
return plugin.getConfiguration().get(ConfigKeys.VAULT_SERVER);
}
boolean useVaultServer() {
return plugin.getConfiguration().get(ConfigKeys.USE_VAULT_SERVER);
}
boolean isIncludeGlobal() {
return plugin.getConfiguration().get(ConfigKeys.VAULT_INCLUDING_GLOBAL);
}
@ -532,4 +405,8 @@ public class VaultPermissionHook extends Permission {
boolean isIgnoreWorld() {
return plugin.getConfiguration().get(ConfigKeys.VAULT_IGNORE_WORLD);
}
private boolean useVaultServer() {
return plugin.getConfiguration().get(ConfigKeys.USE_VAULT_SERVER);
}
}