Compare commits

...
27 Commits
Author SHA1 Message Date
Luck 5577e3f590 Jedis requires SLF4J (#1579) 2019-07-14 09:11:54 +01:00
Luck ffe6c24b53 Properly remove "minecraft:" prefixed brigadier aliases 2019-06-03 20:15:29 +01:00
Luck 4e4982a98d Create FUNDING.yml 2019-05-27 10:40:12 +01:00
Luck 7f4f9bb917 Fix build 2019-05-20 23:09:02 +01:00
Luck 8d8024ba5e Fix group changes via the API not properly invalidating caches (#1534) 2019-05-20 10:42:48 +01:00
Luck 2e16b15b0e Change Sender#getNameWithLocation behaviour 2019-05-14 20:32:35 +01:00
Luck 1ebed37297 Remove use-server-properties-name option
This was removed from Minecraft 1.14, and isn't something I feel was ever really necessary to support.
2019-05-11 23:17:59 +01:00
Luck ff37ad176b Update text adapters to latest version (#1525) 2019-05-11 23:12:55 +01:00
Luck d0c5d89e91 Update to expect Velocity shading text 3
This reverts the reflection workaround implemented in f49446011a
2019-05-07 13:59:44 +01:00
Luck f49446011a Update to text 3 2019-05-07 00:23:40 +01:00
Luck d762a0aaa6 Reduce new instance creation further in TristateResult.Factory 2019-04-28 15:35:46 +01:00
Luck 2dc211a91e Don't account for wildcard/default permissions when running require-sender-group-membership-to-modify checks (#1512) 2019-04-24 18:40:27 +01:00
Luck 2c62de9658 Refactor storage type config read 2019-04-23 21:57:43 +01:00
Luck 494ab6787f Update okhttp 2019-04-23 20:45:02 +01:00
Luck b81e8a40a4 Refactor VaultHookManager 2019-04-22 10:27:29 +01:00
Luck 2fd2f4fedb Ignore exception if Brigadier is not supported by the server (#1506)
This error occurs when another plugin/the server shades the brigadier library without relocation on pre 1.13 MC versions.
2019-04-22 09:24:05 +01:00
Luck 493e5d08be Finish refactoring 2019-04-22 09:15:46 +01:00
Chinese Marc 62a834e145 Fix build (#1509) 2019-04-21 21:49:13 +01:00
Luck 241f13c8f1 Package renames 2019-04-20 18:10:31 +01:00
Luck 98ea255667 Refactor blank message sending 2019-04-19 09:46:45 +01:00
Luck 420ec2bf1a Don't attempt to read a boolean 'value' from parent/chatmeta/meta entries in file based storage files (#1505) 2019-04-18 23:14:23 +01:00
Luck 364a494ac6 Fix making changes to group subjects via the Sponge API (#1495) 2019-04-18 22:57:53 +01:00
Luck 821d1cb8dd Fallback to utf8 encoding if utf8mb4 isn't supported (#1497) 2019-04-17 18:44:34 +01:00
Luck 544ffbad19 Add missing javadocs to ConfigKeys 2019-04-06 18:22:19 +01:00
Luck 4fa6cd2577 Add configuration option to perform a post-traversal sort according to the inheritance (weight) rules 2019-04-06 18:20:30 +01:00
Luck 37d1f5efab Improve behaviour of userInGroup and userHasPermission Vault calls 2019-04-03 10:12:24 +01:00
Luck 7cd8e8bf5b Fix NPE in Vault contextForLookup method
Fixes CodeCrafter47/BungeeTabListPlus#415
2019-04-03 10:01:18 +01:00
139 changed files with 793 additions and 600 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
patreon: luckperms
@@ -26,10 +26,12 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.LuckPerms;
import me.lucko.luckperms.api.caching.CachedData;
import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.ContextManager;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.event.EventBus;
import me.lucko.luckperms.api.manager.CachedDataManager;
import me.lucko.luckperms.api.manager.GroupManager;
import me.lucko.luckperms.api.manager.TrackManager;
import me.lucko.luckperms.api.manager.UserManager;
@@ -110,6 +112,15 @@ public interface LuckPermsApi {
*/
@NonNull TrackManager getTrackManager();
/**
* Gets the {@link CachedDataManager}, responsible for managing
* {@link CachedData} instances.
*
* @return the cached data manager
* @since 4.5
*/
@NonNull CachedDataManager getCachedDataManager();
/**
* Schedules the execution of an update task, and returns an encapsulation
* of the task as a {@link CompletableFuture}.
@@ -412,6 +412,14 @@ public interface CachedData {
*/
void invalidateMeta();
/**
* Invalidates all cached {@link PermissionData} and {@link MetaData}
* instances.
*
* @since 4.5
*/
void invalidate();
/**
* Invalidates all of the underlying Permission calculators.
*
@@ -0,0 +1,53 @@
/*
* 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.api.manager;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.caching.CachedData;
/**
* Represents an object responsible for managing {@link CachedData} instances.
*
* @since 4.5
*/
public interface CachedDataManager {
/**
* Invalidate the {@link CachedData} instances for all loaded {@link User}s.
*
* @see CachedData#invalidate()
*/
void invalidateAllUserCaches();
/**
* Invalidate the {@link CachedData} instances for all loaded {@link Group}s.
*
* @see CachedData#invalidate()
*/
void invalidateAllGroupCaches();
}
-1
View File
@@ -56,7 +56,6 @@ subprojects {
}
repositories {
//mavenLocal()
mavenCentral()
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
maven { url 'https://repo.lucko.me/' }
+2 -2
View File
@@ -10,8 +10,8 @@ repositories {
dependencies {
compile project(':common')
compileOnly 'org.spigotmc:spigot-api:1.13.2-R0.1-SNAPSHOT'
compileOnly'net.kyori:text-adapter-bukkit:1.0.2'
compileOnly 'org.spigotmc:spigot-api:1.14-R0.1-SNAPSHOT'
compileOnly 'net.kyori:text-adapter-bukkit:3.0.2'
compileOnly 'me.lucko:commodore:1.3'
compileOnly('net.milkbowl.vault:VaultAPI:1.6') {
exclude(module: 'bukkit')
@@ -212,11 +212,6 @@ public class LPBukkitBootstrap extends JavaPlugin implements LuckPermsBootstrap
return getServer().getVersion() + " - " + getServer().getBukkitVersion();
}
@Override
public String getServerName() {
return getServer().getServerName();
}
@Override
public Path getDataDirectory() {
return getDataFolder().toPath().toAbsolutePath();
@@ -73,7 +73,6 @@ import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.ServicePriority;
import java.io.File;
import java.util.EnumSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -123,7 +122,8 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
@Override
protected Set<Dependency> getGlobalDependencies() {
EnumSet<Dependency> dependencies = EnumSet.of(Dependency.TEXT, Dependency.TEXT_ADAPTER_BUKKIT, Dependency.CAFFEINE, Dependency.OKIO, Dependency.OKHTTP, Dependency.EVENT);
Set<Dependency> dependencies = super.getGlobalDependencies();
dependencies.add(Dependency.TEXT_ADAPTER_BUKKIT);
if (isBrigadierSupported()) {
dependencies.add(Dependency.COMMODORE);
}
@@ -159,7 +159,9 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
try {
LuckPermsBrigadier.register(this, cmd);
} catch (Exception e) {
e.printStackTrace();
if (!(e instanceof RuntimeException && e.getMessage().contains("not supported by the server"))) {
e.printStackTrace();
}
}
}
}
@@ -216,8 +218,8 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
try {
if (force || this.bootstrap.getServer().getPluginManager().isPluginEnabled("Vault")) {
this.vaultHookManager = new VaultHookManager();
this.vaultHookManager.hook(this);
this.vaultHookManager = new VaultHookManager(this);
this.vaultHookManager.hook();
getLogger().info("Registered Vault permission & chat hook.");
}
} catch (Exception e) {
@@ -321,29 +323,29 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
// unhook vault
if (this.vaultHookManager != null) {
this.vaultHookManager.unhook(this);
this.vaultHookManager.unhook();
}
}
public void refreshAutoOp(Player player, boolean callerIsSync) {
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
User user = getUserManager().getIfLoaded(player.getUniqueId());
if (user == null) {
if (callerIsSync) {
player.setOp(false);
} else {
this.bootstrap.getScheduler().executeSync(() -> player.setOp(false));
}
return;
}
if (!getConfiguration().get(ConfigKeys.AUTO_OP)) {
return;
}
User user = getUserManager().getIfLoaded(player.getUniqueId());
boolean value;
if (user != null) {
Map<String, Boolean> permData = user.getCachedData().getPermissionData(this.contextManager.getApplicableContexts(player)).getImmutableBacking();
boolean value = permData.getOrDefault("luckperms.autoop", false);
if (callerIsSync) {
player.setOp(value);
} else {
this.bootstrap.getScheduler().executeSync(() -> player.setOp(value));
}
value = permData.getOrDefault("luckperms.autoop", false);
} else {
value = false;
}
if (callerIsSync) {
player.setOp(value);
} else {
this.bootstrap.getScheduler().executeSync(() -> player.setOp(value));
}
}
@@ -36,7 +36,8 @@ import org.bukkit.permissions.Permission;
* Permission Processor for Bukkits "default" permission system.
*/
public class DefaultsProcessor implements PermissionProcessor {
private static final TristateResult.Factory RESULT_FACTORY = new TristateResult.Factory(DefaultsProcessor.class);
private static final TristateResult.Factory DEFAULT_PERMISSION_MAP_RESULT_FACTORY = new TristateResult.Factory(DefaultsProcessor.class, "default permission map");
private static final TristateResult.Factory PERMISSION_MAP_RESULT_FACTORY = new TristateResult.Factory(DefaultsProcessor.class, "permission map");
private final LPBukkitPlugin plugin;
private final boolean isOp;
@@ -50,13 +51,13 @@ public class DefaultsProcessor implements PermissionProcessor {
public TristateResult hasPermission(String permission) {
Tristate t = this.plugin.getDefaultPermissionMap().lookupDefaultPermission(permission, this.isOp);
if (t != Tristate.UNDEFINED) {
return RESULT_FACTORY.result(t, "default permission map");
return DEFAULT_PERMISSION_MAP_RESULT_FACTORY.result(t);
}
Permission defPerm = this.plugin.getPermissionMap().get(permission);
if (defPerm == null) {
return TristateResult.UNDEFINED;
}
return RESULT_FACTORY.result(Tristate.fromBoolean(defPerm.getDefault().getValue(this.isOp)), "permission map");
return PERMISSION_MAP_RESULT_FACTORY.result(Tristate.fromBoolean(defPerm.getDefault().getValue(this.isOp)));
}
}
@@ -52,7 +52,10 @@ import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.GZIPInputStream;
public class LuckPermsBrigadier {
@@ -80,18 +83,20 @@ public class LuckPermsBrigadier {
private static final class PermissionListener implements Listener {
private final LPBukkitPlugin plugin;
private final Command pluginCommand;
private final List<String> aliases;
private PermissionListener(LPBukkitPlugin plugin, Command pluginCommand) {
this.plugin = plugin;
this.pluginCommand = pluginCommand;
this.aliases = Commodore.getAliases(pluginCommand).stream()
.flatMap(alias -> Stream.of(alias, "minecraft:" + alias))
.collect(Collectors.toList());
}
@EventHandler
public void onCommandSend(PlayerCommandSendEvent e) {
Sender playerAsSender = this.plugin.getSenderFactory().wrap(e.getPlayer());
if (!this.plugin.getCommandManager().hasPermissionForAny(playerAsSender)) {
e.getCommands().removeAll(Commodore.getAliases(this.pluginCommand));
e.getCommands().removeAll(this.aliases);
}
}
}
@@ -31,12 +31,12 @@ import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.LookupSetting;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.cache.LoadingMap;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.context.ContextManager;
import me.lucko.luckperms.common.context.ContextsCache;
import me.lucko.luckperms.common.context.ContextsSupplier;
import me.lucko.luckperms.common.util.CaffeineFactory;
import me.lucko.luckperms.common.util.LoadingMap;
import org.bukkit.entity.Player;
@@ -33,7 +33,7 @@ import com.google.common.collect.Maps;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.buffer.Cache;
import me.lucko.luckperms.common.cache.Cache;
import org.bukkit.permissions.Permission;
import org.bukkit.plugin.PluginManager;
@@ -28,9 +28,9 @@ package me.lucko.luckperms.bukkit.inject.server;
import com.google.common.collect.ForwardingMap;
import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.common.cache.LoadingMap;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.treeview.PermissionRegistry;
import me.lucko.luckperms.common.util.LoadingMap;
import org.bukkit.permissions.Permission;
import org.bukkit.plugin.PluginManager;
@@ -89,10 +89,8 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
return CommandResult.STATE_ERROR;
}
String method = plugin.getConfiguration().get(ConfigKeys.STORAGE_METHOD);
StorageType type = StorageType.parse(method);
if (type == null || type != StorageType.MYSQL) {
StorageType type = plugin.getConfiguration().get(ConfigKeys.STORAGE_METHOD);
if (type != StorageType.MYSQL) {
// We need to load the Hikari/MySQL stuff.
plugin.getDependencyManager().loadStorageDependencies(ImmutableSet.of(StorageType.MYSQL));
}
@@ -28,12 +28,15 @@ package me.lucko.luckperms.bukkit.vault;
import com.google.common.base.Preconditions;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.LookupSetting;
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.cacheddata.type.PermissionCache;
import me.lucko.luckperms.common.calculator.processor.MapProcessor;
import me.lucko.luckperms.common.calculator.result.TristateResult;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.model.Group;
@@ -49,9 +52,11 @@ import net.milkbowl.vault.permission.Permission;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
/**
@@ -189,7 +194,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
if (log()) {
logMsg("#userHasPermission: %s - %s - %s - %s", user.getPlainDisplayName(), contexts.getContexts().toMultimap(), permission, result);
}
return result.asBoolean();
return result != Tristate.UNDEFINED ? result.asBoolean() : org.bukkit.permissions.Permission.DEFAULT_PERMISSION.getValue(contexts.hasSetting(LookupSetting.IS_OP));
}
@Override
@@ -220,7 +225,16 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
public boolean userInGroup(String world, UUID uuid, String group) {
Objects.requireNonNull(uuid, "uuid");
Objects.requireNonNull(group, "group");
return userHasPermission(world, uuid, NodeFactory.groupNode(rewriteGroupName(group)));
PermissionHolder user = lookupUser(uuid);
Contexts contexts = contextForLookup(uuid, world);
PermissionCache permissionData = user.getCachedData().getPermissionData(contexts);
TristateResult result = permissionData.getPermissionValue(NodeFactory.groupNode(rewriteGroupName(group)), PermissionCheckEvent.Origin.THIRD_PARTY_API);
if (log()) {
logMsg("#userInGroup: %s - %s - %s - %s", user.getPlainDisplayName(), contexts.getContexts().toMultimap(), group, result);
}
return result.processorClass() == MapProcessor.class && result.result().asBoolean();
}
@Override
@@ -362,10 +376,10 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
}
// utility method for getting a contexts instance for a given vault lookup.
Contexts contextForLookup(UUID uuid, String world) {
Contexts contextForLookup(@Nullable UUID uuid, @Nullable String world) {
MutableContextSet context;
Player player = this.plugin.getBootstrap().getPlayer(uuid).orElse(null);
Player player = Optional.ofNullable(uuid).flatMap(u -> this.plugin.getBootstrap().getPlayer(u)).orElse(null);
if (player != null) {
context = this.plugin.getContextManager().getApplicableContext(player).mutableCopy();
} else {
@@ -397,7 +411,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
boolean op = false;
if (player != null) {
op = player.isOp();
} else if (uuid.version() == 2) { // npc
} else if (uuid != null && uuid.version() == 2) { // npc
op = this.plugin.getConfiguration().get(ConfigKeys.VAULT_NPC_OP_STATUS);
}
@@ -37,16 +37,20 @@ import org.bukkit.plugin.ServicesManager;
* Handles hooking with the Vault API
*/
public class VaultHookManager {
private final LPBukkitPlugin plugin;
private LuckPermsVaultChat chat = null;
private LuckPermsVaultPermission permission = null;
public VaultHookManager(LPBukkitPlugin plugin) {
this.plugin = plugin;
}
/**
* Registers the LuckPerms implementation of {@link Permission} and {@link Chat} with
* the service manager.
*
* @param plugin the plugin
*/
public void hook(LPBukkitPlugin plugin) {
public void hook() {
try {
if (this.permission == null) {
this.permission = new LuckPermsVaultPermission(plugin);
@@ -67,10 +71,8 @@ public class VaultHookManager {
/**
* Unregisters the LuckPerms Vault hooks, if present.
*
* @param plugin the plugin
*/
public void unhook(LPBukkitPlugin plugin) {
public void unhook() {
final ServicesManager sm = plugin.getBootstrap().getServer().getServicesManager();
if (this.permission != null) {
+13 -4
View File
@@ -367,6 +367,19 @@ meta-formatting:
# => depth-first-post-order See: https://en.wikipedia.org/wiki/Depth-first_search
inheritance-traversal-algorithm: depth-first-pre-order
# If a final sort according to "inheritance rules" should be performed after the traversal algorithm
# has resolved the inheritance tree.
#
# "Inheritance rules" refers to things such as group weightings, primary group status, and the
# natural contextual ordering of the group nodes.
#
# Setting this to 'true' will allow for the inheritance rules to take priority over the structure of
# the inheritance tree.
#
# Effectively when this setting is 'true': the tree is flattened, and rules applied afterwards,
# and when this setting is 'false':, the rules are just applied during each step of the traversal.
post-traversal-inheritance-sort: false
# +----------------------------------------------------------------------------------------------+ #
# | Permission resolution settings | #
# +----------------------------------------------------------------------------------------------+ #
@@ -543,10 +556,6 @@ vault-debug: false
# - Useful if you're having issues with UUID forwarding or data not being loaded.
debug-logins: false
# If LuckPerms should use the "server-name" property from the "server.properties" file as the
# "server" option within LuckPerms.
use-server-properties-name: false
# If LuckPerms should allow usernames with non alphanumeric characters.
#
# - Note that due to the design of the storage implementation, usernames must still be 16 characters
+2 -2
View File
@@ -5,8 +5,8 @@ plugins {
dependencies {
compile project(':common')
compileOnly 'net.md-5:bungeecord-api:1.13-SNAPSHOT'
compileOnly 'net.kyori:text-adapter-bungeecord:1.0.2'
compileOnly 'net.md-5:bungeecord-api:1.14-SNAPSHOT'
compileOnly 'net.kyori:text-adapter-bungeecord:3.0.2'
compileOnly 'com.imaginarycode.minecraft:RedisBungee:0.4'
// migration plugins
@@ -58,7 +58,6 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.EnumSet;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -94,7 +93,9 @@ public class LPBungeePlugin extends AbstractLuckPermsPlugin {
@Override
protected Set<Dependency> getGlobalDependencies() {
return EnumSet.of(Dependency.TEXT, Dependency.TEXT_ADAPTER_BUNGEECORD, Dependency.CAFFEINE, Dependency.OKIO, Dependency.OKHTTP, Dependency.EVENT);
Set<Dependency> dependencies = super.getGlobalDependencies();
dependencies.add(Dependency.TEXT_ADAPTER_BUNGEECORD);
return dependencies;
}
@Override
+13
View File
@@ -375,6 +375,19 @@ meta-formatting:
# => depth-first-post-order See: https://en.wikipedia.org/wiki/Depth-first_search
inheritance-traversal-algorithm: depth-first-pre-order
# If a final sort according to "inheritance rules" should be performed after the traversal algorithm
# has resolved the inheritance tree.
#
# "Inheritance rules" refers to things such as group weightings, primary group status, and the
# natural contextual ordering of the group nodes.
#
# Setting this to 'true' will allow for the inheritance rules to take priority over the structure of
# the inheritance tree.
#
# Effectively when this setting is 'true': the tree is flattened, and rules applied afterwards,
# and when this setting is 'false':, the rules are just applied during each step of the traversal.
post-traversal-inheritance-sort: false
# +----------------------------------------------------------------------------------------------+ #
# | Permission resolution settings | #
# +----------------------------------------------------------------------------------------------+ #
+9 -4
View File
@@ -2,9 +2,14 @@ dependencies {
compile project(':luckperms-api')
compile 'org.checkerframework:checker-qual:2.5.5'
compile('net.kyori:text:1.11-1.6.5') {
compile('net.kyori:text-api:3.0.0') {
exclude(module: 'checker-qual')
exclude(module: 'guava')
}
compile('net.kyori:text-serializer-legacy:3.0.0') {
exclude(module: 'text-api')
}
compile('net.kyori:text-serializer-gson:3.0.0') {
exclude(module: 'text-api')
exclude(module: 'gson')
}
compile('net.kyori:event-api:3.0.0') {
@@ -14,8 +19,8 @@ dependencies {
compile 'com.google.code.gson:gson:2.7'
compile 'com.google.guava:guava:19.0'
compile 'com.github.ben-manes.caffeine:caffeine:2.7.0'
compile 'com.squareup.okhttp3:okhttp:3.13.1'
compile 'com.squareup.okio:okio:1.17.2'
compile 'com.squareup.okhttp3:okhttp:3.14.1'
compile 'com.squareup.okio:okio:1.17.3'
compile('me.lucko.configurate:configurate-core:3.5') {
exclude(module: 'guava')
}
@@ -34,6 +34,7 @@ import me.lucko.luckperms.api.Storage;
import me.lucko.luckperms.api.UuidCache;
import me.lucko.luckperms.api.context.ContextManager;
import me.lucko.luckperms.api.event.EventBus;
import me.lucko.luckperms.api.manager.CachedDataManager;
import me.lucko.luckperms.api.manager.GroupManager;
import me.lucko.luckperms.api.manager.TrackManager;
import me.lucko.luckperms.api.manager.UserManager;
@@ -41,6 +42,7 @@ import me.lucko.luckperms.api.messenger.MessengerProvider;
import me.lucko.luckperms.api.metastacking.MetaStackFactory;
import me.lucko.luckperms.api.platform.PlatformInfo;
import me.lucko.luckperms.common.api.implementation.ApiActionLogger;
import me.lucko.luckperms.common.api.implementation.ApiCachedDataManager;
import me.lucko.luckperms.common.api.implementation.ApiContextManager;
import me.lucko.luckperms.common.api.implementation.ApiGroupManager;
import me.lucko.luckperms.common.api.implementation.ApiMessagingService;
@@ -71,6 +73,7 @@ public class LuckPermsApiProvider implements LuckPermsApi {
private final UserManager userManager;
private final GroupManager groupManager;
private final TrackManager trackManager;
private final CachedDataManager cachedDataManager;
private final ActionLogger actionLogger;
private final ContextManager contextManager;
private final MetaStackFactory metaStackFactory;
@@ -82,6 +85,7 @@ public class LuckPermsApiProvider implements LuckPermsApi {
this.userManager = new ApiUserManager(plugin, plugin.getUserManager());
this.groupManager = new ApiGroupManager(plugin, plugin.getGroupManager());
this.trackManager = new ApiTrackManager(plugin, plugin.getTrackManager());
this.cachedDataManager = new ApiCachedDataManager(plugin.getUserManager(), plugin.getGroupManager());
this.actionLogger = new ApiActionLogger(plugin);
this.contextManager = new ApiContextManager(plugin, plugin.getContextManager());
this.metaStackFactory = new ApiMetaStackFactory(plugin);
@@ -107,6 +111,11 @@ public class LuckPermsApiProvider implements LuckPermsApi {
return this.trackManager;
}
@Override
public @NonNull CachedDataManager getCachedDataManager() {
return this.cachedDataManager;
}
@Override
public @NonNull CompletableFuture<Void> runUpdateTask() {
return this.plugin.getSyncTaskBuffer().request();
@@ -23,33 +23,29 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.context;
package me.lucko.luckperms.common.api.implementation;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.manager.CachedDataManager;
import me.lucko.luckperms.common.model.manager.group.GroupManager;
import me.lucko.luckperms.common.model.manager.user.UserManager;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
public class ApiCachedDataManager implements CachedDataManager {
private final UserManager<?> userManager;
private final GroupManager<?> groupManager;
public final class ContextSetFormatter {
private ContextSetFormatter() {}
public static Optional<String> toMinimalString(ContextSet contextSet) {
Set<Map.Entry<String, String>> entries = contextSet.toSet();
if (entries.isEmpty()) {
return Optional.empty();
}
// effectively: if entries contains any non-server keys
if (entries.stream().anyMatch(pair -> !pair.getKey().equals(Contexts.SERVER_KEY))) {
// return all entries in 'key=value' form
return Optional.of(entries.stream().map(pair -> pair.getKey() + "=" + pair.getValue()).collect(Collectors.joining(";")));
} else {
// just return the server ids, without the 'server='
return Optional.of(entries.stream().map(Map.Entry::getValue).collect(Collectors.joining(";")));
}
public ApiCachedDataManager(UserManager<?> userManager, GroupManager<?> groupManager) {
this.userManager = userManager;
this.groupManager = groupManager;
}
@Override
public void invalidateAllUserCaches() {
this.userManager.invalidateAllUserCaches();
}
@Override
public void invalidateAllGroupCaches() {
this.groupManager.invalidateAllGroupCaches();
}
}
@@ -72,7 +72,7 @@ public class ApiConfiguration implements LPConfiguration {
@Override
public @NonNull String getStorageMethod() {
return this.handle.get(ConfigKeys.STORAGE_METHOD);
return this.handle.get(ConfigKeys.STORAGE_METHOD).getName();
}
@Override
@@ -83,7 +83,7 @@ public class ApiConfiguration implements LPConfiguration {
@Override
public @NonNull Map<String, String> getSplitStorageOptions() {
return this.handle.get(ConfigKeys.SPLIT_STORAGE_OPTIONS).entrySet().stream()
.collect(ImmutableCollectors.toMap(e -> e.getKey().name().toLowerCase(), Map.Entry::getValue));
.collect(ImmutableCollectors.toMap(e -> e.getKey().name().toLowerCase(), e -> e.getValue().getName()));
}
@Override
@@ -75,7 +75,12 @@ public class ApiGroupManager extends ApiAbstractManager<Group, me.lucko.luckperm
@Override
public @NonNull CompletableFuture<Void> saveGroup(me.lucko.luckperms.api.@NonNull Group group) {
Objects.requireNonNull(group, "group");
return this.plugin.getStorage().saveGroup(ApiGroup.cast(group));
return this.plugin.getStorage().saveGroup(ApiGroup.cast(group)).thenRun(() -> {
// invalidate caches - they have potentially been affected by
// this change.
this.plugin.getGroupManager().invalidateAllGroupCaches();
this.plugin.getUserManager().invalidateAllUserCaches();
});
}
@Override
@@ -84,7 +89,13 @@ public class ApiGroupManager extends ApiAbstractManager<Group, me.lucko.luckperm
if (group.getName().equalsIgnoreCase(NodeFactory.DEFAULT_GROUP_NAME)) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
return this.plugin.getStorage().deleteGroup(ApiGroup.cast(group), DeletionCause.API);
return this.plugin.getStorage().deleteGroup(ApiGroup.cast(group), DeletionCause.API).thenRun(() -> {
// invalidate caches - they have potentially been affected by
// this change.
this.plugin.getGroupManager().invalidateAllGroupCaches();
this.plugin.getUserManager().invalidateAllUserCaches();
});
}
@Override
@@ -31,19 +31,12 @@ import me.lucko.luckperms.api.Log;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.api.event.cause.DeletionCause;
import me.lucko.luckperms.common.api.ApiUtils;
import me.lucko.luckperms.common.bulkupdate.comparison.Constraint;
import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.storage.Storage;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
@@ -98,155 +91,130 @@ public class ApiStorage implements me.lucko.luckperms.api.Storage {
@Override
public @NonNull CompletableFuture<Boolean> logAction(@NonNull LogEntry entry) {
Objects.requireNonNull(entry, "entry");
return this.handle.logAction(entry)
return this.plugin.getApiProvider().getActionLogger().submitToStorage(entry)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Log> getLog() {
return this.handle.getLog().<Log>thenApply(ApiLog::new).exceptionally(consumeExceptionToNull());
return this.plugin.getApiProvider().getActionLogger().getLog().exceptionally(consumeExceptionToNull());
}
@Override
public @NonNull CompletableFuture<Boolean> loadUser(@NonNull UUID uuid, String username) {
Objects.requireNonNull(uuid, "uuid");
username = ApiUtils.checkUsername(username, this.plugin);
if (this.plugin.getUserManager().getIfLoaded(uuid) == null) {
this.plugin.getUserManager().getHouseKeeper().registerApiUsage(uuid);
}
return this.handle.loadUser(uuid, username)
return this.plugin.getApiProvider().getUserManager().loadUser(uuid, username)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> saveUser(@NonNull User user) {
Objects.requireNonNull(user, "user");
return this.handle.saveUser(ApiUser.cast(user))
return this.plugin.getApiProvider().getUserManager().saveUser(user)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Set<UUID>> getUniqueUsers() {
return this.handle.getUniqueUsers().exceptionally(consumeExceptionToNull());
return this.plugin.getApiProvider().getUserManager().getUniqueUsers().exceptionally(consumeExceptionToNull());
}
@Override
public @NonNull CompletableFuture<List<HeldPermission<UUID>>> getUsersWithPermission(@NonNull String permission) {
Objects.requireNonNull(permission, "permission");
return this.handle.getUsersWithPermission(Constraint.of(StandardComparison.EQUAL, permission)).exceptionally(consumeExceptionToNull());
return this.plugin.getApiProvider().getUserManager().getWithPermission(permission).exceptionally(consumeExceptionToNull());
}
@Override
public @NonNull CompletableFuture<Boolean> createAndLoadGroup(@NonNull String name) {
Objects.requireNonNull(name, "name");
return this.handle.createAndLoadGroup(ApiUtils.checkName(name), CreationCause.API)
return this.plugin.getApiProvider().getGroupManager().createAndLoadGroup(name)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> loadGroup(@NonNull String name) {
Objects.requireNonNull(name, "name");
return this.handle.loadGroup(ApiUtils.checkName(name))
return this.plugin.getApiProvider().getGroupManager().loadGroup(name)
.thenApply(Optional::isPresent)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> loadAllGroups() {
return this.handle.loadAllGroups()
return this.plugin.getApiProvider().getGroupManager().loadAllGroups()
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> saveGroup(@NonNull Group group) {
Objects.requireNonNull(group, "group");
return this.handle.saveGroup(ApiGroup.cast(group))
return this.plugin.getApiProvider().getGroupManager().saveGroup(group)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> deleteGroup(@NonNull Group group) {
Objects.requireNonNull(group, "group");
if (group.getName().equalsIgnoreCase(NodeFactory.DEFAULT_GROUP_NAME)) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
return this.handle.deleteGroup(ApiGroup.cast(group), DeletionCause.API)
return this.plugin.getApiProvider().getGroupManager().deleteGroup(group)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<List<HeldPermission<String>>> getGroupsWithPermission(@NonNull String permission) {
Objects.requireNonNull(permission, "permission");
return this.handle.getGroupsWithPermission(Constraint.of(StandardComparison.EQUAL, permission)).exceptionally(consumeExceptionToNull());
return this.plugin.getApiProvider().getGroupManager().getWithPermission(permission)
.exceptionally(consumeExceptionToNull());
}
@Override
public @NonNull CompletableFuture<Boolean> createAndLoadTrack(@NonNull String name) {
Objects.requireNonNull(name, "name");
return this.handle.createAndLoadTrack(ApiUtils.checkName(name), CreationCause.API)
return this.plugin.getApiProvider().getTrackManager().createAndLoadTrack(name)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> loadTrack(@NonNull String name) {
Objects.requireNonNull(name, "name");
return this.handle.loadTrack(ApiUtils.checkName(name))
return this.plugin.getApiProvider().getTrackManager().loadTrack(name)
.thenApply(Optional::isPresent)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> loadAllTracks() {
return this.handle.loadAllTracks()
return this.plugin.getApiProvider().getTrackManager().loadAllTracks()
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> saveTrack(@NonNull Track track) {
Objects.requireNonNull(track, "track");
return this.handle.saveTrack(ApiTrack.cast(track))
return this.plugin.getApiProvider().getTrackManager().saveTrack(track)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> deleteTrack(@NonNull Track track) {
Objects.requireNonNull(track, "track");
return this.handle.deleteTrack(ApiTrack.cast(track), DeletionCause.API)
return this.plugin.getApiProvider().getTrackManager().deleteTrack(track)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> saveUUIDData(@NonNull String username, @NonNull UUID uuid) {
Objects.requireNonNull(username, "username");
Objects.requireNonNull(uuid, "uuid");
return this.handle.savePlayerData(uuid, ApiUtils.checkUsername(username, this.plugin))
return this.plugin.getApiProvider().getUserManager().savePlayerData(uuid, username)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<UUID> getUUID(@NonNull String username) {
Objects.requireNonNull(username, "username");
return this.handle.getPlayerUuid(ApiUtils.checkUsername(username, this.plugin));
return this.plugin.getApiProvider().getUserManager().lookupUuid(username).exceptionally(consumeExceptionToNull());
}
@Override
public @NonNull CompletableFuture<String> getName(@NonNull UUID uuid) {
Objects.requireNonNull(uuid, "uuid");
return this.handle.getPlayerName(uuid);
return this.plugin.getApiProvider().getUserManager().lookupUsername(uuid).exceptionally(consumeExceptionToNull());
}
}
@@ -23,7 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.buffer;
package me.lucko.luckperms.common.cache;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerTask;
@@ -23,7 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.buffer;
package me.lucko.luckperms.common.cache;
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -23,7 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.buffer;
package me.lucko.luckperms.common.cache;
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -23,7 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.util;
package me.lucko.luckperms.common.cache;
import com.google.common.collect.ForwardingMap;
@@ -23,7 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.util;
package me.lucko.luckperms.common.cache;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -374,16 +374,17 @@ public abstract class AbstractCachedData implements CachedData {
}
@Override
public final void invalidatePermissionCalculators() {
this.permission.synchronous().asMap().values().forEach(PermissionCache::invalidateCache);
}
public final void invalidate() {
invalidatePermissions();
invalidateMeta();
}
public final void doCacheCleanup() {
@Override
public final void invalidatePermissionCalculators() {
this.permission.synchronous().asMap().values().forEach(PermissionCache::invalidateCache);
}
public final void performCacheCleanup() {
this.permission.synchronous().cleanUp();
this.meta.synchronous().cleanUp();
}
@@ -28,11 +28,11 @@ package me.lucko.luckperms.common.calculator;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.cache.LoadingMap;
import me.lucko.luckperms.common.cacheddata.CacheMetadata;
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
import me.lucko.luckperms.common.calculator.result.TristateResult;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.util.LoadingMap;
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -34,21 +34,11 @@ import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
*/
public final class TristateResult {
private static final Factory NULL_FACTORY = new Factory(null, null);
public static final TristateResult UNDEFINED = new TristateResult(Tristate.UNDEFINED, null, null);
public static TristateResult of(Tristate result, Class<? extends PermissionProcessor> processorClass, String cause) {
if (result == Tristate.UNDEFINED) {
return UNDEFINED;
}
return new TristateResult(result, processorClass, cause);
}
public static TristateResult of(Tristate result, Class<? extends PermissionProcessor> processorClass) {
return of(result, processorClass, null);
}
public static TristateResult of(Tristate result) {
return of(result, null, null);
return NULL_FACTORY.result(result);
}
private final Tristate result;
@@ -73,17 +63,29 @@ public final class TristateResult {
return this.cause;
}
@Override
public String toString() {
return "TristateResult(" +
"result=" + this.result + ", " +
"processorClass=" + this.processorClass + ", " +
"cause=" + this.cause + ')';
}
public static final class Factory {
private final Class<? extends PermissionProcessor> processorClass;
private final TristateResult trueResult;
private final TristateResult falseResult;
public Factory(Class<? extends PermissionProcessor> processorClass) {
public Factory(Class<? extends PermissionProcessor> processorClass, String defaultCause) {
this.processorClass = processorClass;
this.trueResult = of(Tristate.TRUE, processorClass);
this.falseResult = of(Tristate.FALSE, processorClass);
this.trueResult = new TristateResult(Tristate.TRUE, processorClass, defaultCause);
this.falseResult = new TristateResult(Tristate.FALSE, processorClass, defaultCause);
}
public Factory(Class<? extends PermissionProcessor> processorClass) {
this(processorClass, null);
}
public TristateResult result(Tristate result) {
@@ -100,10 +102,10 @@ public final class TristateResult {
}
public TristateResult result(Tristate result, String cause) {
if (cause == null) {
return result(result);
if (result == Tristate.UNDEFINED) {
return UNDEFINED;
}
return of(result, this.processorClass, cause);
return new TristateResult(result, this.processorClass, cause);
}
}
}
@@ -32,7 +32,6 @@ import me.lucko.luckperms.common.command.abstraction.CommandException;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.tabcomplete.TabCompletions;
import me.lucko.luckperms.common.command.utils.ArgumentParser;
import me.lucko.luckperms.common.command.utils.MessageUtils;
import me.lucko.luckperms.common.commands.group.CreateGroup;
import me.lucko.luckperms.common.commands.group.DeleteGroup;
import me.lucko.luckperms.common.commands.group.GroupMainCommand;
@@ -167,7 +166,7 @@ public class CommandManager {
// Handle no arguments
if (arguments.isEmpty() || (arguments.size() == 1 && arguments.get(0).trim().isEmpty())) {
MessageUtils.sendPluginMessage(sender, "&2Running &bLuckPerms v" + this.plugin.getBootstrap().getVersion() + "&2.");
Message.BLANK.send(sender, "&2Running &bLuckPerms v" + this.plugin.getBootstrap().getVersion() + "&2.");
if (hasPermissionForAny(sender)) {
Message.VIEW_AVAILABLE_COMMANDS_PROMPT.send(sender, label);
return CommandResult.SUCCESS;
@@ -271,7 +270,7 @@ public class CommandManager {
}
private void sendCommandUsage(Sender sender, String label) {
MessageUtils.sendPluginMessage(sender, "&2Running &bLuckPerms v" + this.plugin.getBootstrap().getVersion() + "&2.");
Message.BLANK.send(sender, "&2Running &bLuckPerms v" + this.plugin.getBootstrap().getVersion() + "&2.");
this.mainCommands.stream()
.filter(Command::shouldDisplay)
.filter(c -> c.isAuthorized(sender))
@@ -280,7 +279,7 @@ public class CommandManager {
TextComponent component = TextUtils.fromLegacy("&3> &a" + String.format(c.getUsage(), label), AMPERSAND_CHAR)
.toBuilder().applyDeep(comp -> {
comp.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
comp.hoverEvent(HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
"&bCommand: &2" + c.getName(),
"&bDescription: &2" + c.getDescription(),
"&bUsage: &2" + String.format(c.getUsage(), label),
@@ -288,7 +287,7 @@ public class CommandManager {
" ",
"&7Click to auto-complete."
), AMPERSAND_CHAR)));
comp.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, String.format(c.getUsage(), label)));
comp.clickEvent(ClickEvent.suggestCommand(String.format(c.getUsage(), label)));
}).build();
sender.sendMessage(component);
});
@@ -29,6 +29,8 @@ import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.cacheddata.type.PermissionCache;
import me.lucko.luckperms.common.calculator.processor.MapProcessor;
import me.lucko.luckperms.common.calculator.result.TristateResult;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.HolderType;
@@ -302,7 +304,8 @@ public final class ArgumentPermissions {
}
PermissionCache permissionData = user.getCachedData().getPermissionData(Contexts.global().setContexts(contextSet));
return !permissionData.getPermissionValue(NodeFactory.groupNode(targetGroupName), PermissionCheckEvent.Origin.INTERNAL).result().asBoolean();
TristateResult result = permissionData.getPermissionValue(NodeFactory.groupNode(targetGroupName), PermissionCheckEvent.Origin.INTERNAL);
return result.result() != Tristate.TRUE || result.processorClass() != MapProcessor.class;
}
}
@@ -31,7 +31,6 @@ import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.message.Message;
import me.lucko.luckperms.common.sender.Sender;
import java.util.Collection;
import java.util.List;
@@ -40,17 +39,6 @@ import java.util.Map;
public final class MessageUtils {
private MessageUtils() {}
/**
* Sends a message to the sender, formatted with the plugin prefix and color scheme
*
* @param sender the sender to send the message to
* @param message the message content
*/
public static void sendPluginMessage(Sender sender, String message) {
String prefix = Message.PREFIX.asString(sender.getPlugin().getLocaleManager());
sender.sendMessage(Message.colorize(prefix + message));
}
public static String toCommaSep(Collection<String> strings) {
if (strings.isEmpty()) {
return "&bNone";
@@ -86,7 +86,7 @@ public class MetaAddChatMeta extends SharedSubCommand {
DataMutateResult result = holder.setPermission(NodeFactory.buildChatMetaNode(this.type, priority, meta).withExtraContext(context).build());
if (result.asBoolean()) {
TextComponent.Builder builder = Message.ADD_CHATMETA_SUCCESS.asComponent(plugin.getLocaleManager(), holder.getFormattedDisplayName(), this.type.name().toLowerCase(), meta, priority, MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder();
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy(
"¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta,
'¥'
));
@@ -94,7 +94,7 @@ public class MetaAddTempChatMeta extends SharedSubCommand {
duration = ret.getMergedNode().getExpiryUnixTime();
TextComponent.Builder builder = Message.ADD_TEMP_CHATMETA_SUCCESS.asComponent(plugin.getLocaleManager(), holder.getFormattedDisplayName(), this.type.name().toLowerCase(), meta, priority, DurationFormatter.LONG.formatDateDiff(duration), MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder();
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy(
"¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta,
'¥'
));
@@ -47,7 +47,7 @@ import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.Predicates;
import me.lucko.luckperms.common.util.TextUtils;
import net.kyori.text.BuildableComponent;
import net.kyori.text.ComponentBuilder;
import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
@@ -152,7 +152,7 @@ public class MetaInfo extends SharedSubCommand {
}
}
private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(ChatMetaType type, PermissionHolder holder, String label, LocalizedNode node) {
private static Consumer<ComponentBuilder<?, ?>> makeFancy(ChatMetaType type, PermissionHolder holder, String label, LocalizedNode node) {
if (!node.getLocation().equals(holder.getObjectName())) {
// inherited.
Group group = holder.getPlugin().getGroupManager().getIfLoaded(node.getLocation());
@@ -161,14 +161,14 @@ public class MetaInfo extends SharedSubCommand {
}
}
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
"¥3> ¥a" + type.getEntry(node).getKey() + " ¥7- ¥r" + type.getEntry(node).getValue(),
" ",
"¥7Click to remove this " + type.name().toLowerCase() + " from " + holder.getFormattedDisplayName()
), '¥'));
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName(), holder.getType(), false, !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty());
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
ClickEvent clickEvent = ClickEvent.suggestCommand(command);
return component -> {
component.hoverEvent(hoverEvent);
@@ -176,7 +176,7 @@ public class MetaInfo extends SharedSubCommand {
};
}
private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(PermissionHolder holder, String label, LocalizedNode node) {
private static Consumer<ComponentBuilder<?, ?>> makeFancy(PermissionHolder holder, String label, LocalizedNode node) {
if (!node.getLocation().equals(holder.getObjectName())) {
// inherited.
Group group = holder.getPlugin().getGroupManager().getIfLoaded(node.getLocation());
@@ -185,14 +185,14 @@ public class MetaInfo extends SharedSubCommand {
}
}
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
"¥3> ¥r" + node.getMeta().getKey() + " ¥7- ¥r" + node.getMeta().getValue(),
" ",
"¥7Click to remove this meta pair from " + holder.getFormattedDisplayName()
), '¥'));
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName(), holder.getType(), false, !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty());
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
ClickEvent clickEvent = ClickEvent.suggestCommand(command);
return component -> {
component.hoverEvent(hoverEvent);
@@ -105,7 +105,7 @@ public class MetaRemoveChatMeta extends SharedSubCommand {
if (result.asBoolean()) {
TextComponent.Builder builder = Message.REMOVE_CHATMETA_SUCCESS.asComponent(plugin.getLocaleManager(), holder.getFormattedDisplayName(), this.type.name().toLowerCase(), meta, priority, MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder();
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy(
"¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta,
'¥'
));
@@ -105,7 +105,7 @@ public class MetaRemoveTempChatMeta extends SharedSubCommand {
if (result.asBoolean()) {
TextComponent.Builder builder = Message.REMOVE_TEMP_CHATMETA_SUCCESS.asComponent(plugin.getLocaleManager(), holder.getFormattedDisplayName(), this.type.name().toLowerCase(), meta, priority, MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder();
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy(
"¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta,
'¥'
));
@@ -87,7 +87,7 @@ public class MetaSet extends SharedSubCommand {
holder.setPermission(n);
TextComponent.Builder builder = Message.SET_META_SUCCESS.asComponent(plugin.getLocaleManager(), key, value, holder.getFormattedDisplayName(), MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder();
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy(
TextUtils.joinNewline("¥3Raw key: ¥r" + key, "¥3Raw value: ¥r" + value),
'¥'
));
@@ -122,7 +122,7 @@ public class MetaSetChatMeta extends SharedSubCommand {
DataMutateResult result = holder.setPermission(NodeFactory.buildChatMetaNode(this.type, priority, meta).withExtraContext(context).build());
if (result.asBoolean()) {
TextComponent.Builder builder = Message.ADD_CHATMETA_SUCCESS.asComponent(plugin.getLocaleManager(), holder.getFormattedDisplayName(), this.type.name().toLowerCase(), meta, priority, MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder();
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy(
"¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta,
'¥'
));
@@ -92,7 +92,7 @@ public class MetaSetTemp extends SharedSubCommand {
duration = holder.setPermission(n, modifier).getMergedNode().getExpiryUnixTime();
TextComponent.Builder builder = Message.SET_META_TEMP_SUCCESS.asComponent(plugin.getLocaleManager(), key, value, holder.getFormattedDisplayName(), DurationFormatter.LONG.formatDateDiff(duration), MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder();
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy(
TextUtils.joinNewline("¥3Raw key: ¥r" + key, "¥3Raw value: ¥r" + value),
'¥'
));
@@ -134,7 +134,7 @@ public class MetaSetTempChatMeta extends SharedSubCommand {
duration = ret.getMergedNode().getExpiryUnixTime();
TextComponent.Builder builder = Message.ADD_TEMP_CHATMETA_SUCCESS.asComponent(plugin.getLocaleManager(), holder.getFormattedDisplayName(), this.type.name().toLowerCase(), meta, priority, DurationFormatter.LONG.formatDateDiff(duration), MessageUtils.contextSetToString(plugin.getLocaleManager(), context)).toBuilder();
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
HoverEvent event = HoverEvent.showText(TextUtils.fromLegacy(
"¥3Raw " + this.type.name().toLowerCase() + ": ¥r" + meta,
'¥'
));
@@ -81,8 +81,8 @@ public class HolderEditor<T extends PermissionHolder> extends SubCommand<T> {
Message.EDITOR_URL.send(sender);
Component message = TextComponent.builder(url).color(TextColor.AQUA)
.clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to open the editor.").color(TextColor.GRAY)))
.clickEvent(ClickEvent.openUrl(url))
.hoverEvent(HoverEvent.showText(TextComponent.of("Click to open the editor.").color(TextColor.GRAY)))
.build();
sender.sendMessage(message);
@@ -50,7 +50,7 @@ import me.lucko.luckperms.common.util.Iterators;
import me.lucko.luckperms.common.util.Predicates;
import me.lucko.luckperms.common.util.TextUtils;
import net.kyori.text.BuildableComponent;
import net.kyori.text.ComponentBuilder;
import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
@@ -135,15 +135,15 @@ public class ParentInfo extends SharedSubCommand {
return NodeWithContextComparator.reverse().compare(o1, o2);
};
private static Consumer<BuildableComponent.Builder<? ,?>> makeFancy(PermissionHolder holder, String label, Node node) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
private static Consumer<ComponentBuilder<? ,?>> makeFancy(PermissionHolder holder, String label, Node node) {
HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
"&3> &f" + node.getGroupName(),
" ",
"&7Click to remove this parent from " + holder.getFormattedDisplayName()
), CommandManager.AMPERSAND_CHAR));
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName(), holder.getType(), false, !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty());
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
ClickEvent clickEvent = ClickEvent.suggestCommand(command);
return component -> {
component.hoverEvent(hoverEvent);
@@ -50,7 +50,7 @@ import me.lucko.luckperms.common.util.Iterators;
import me.lucko.luckperms.common.util.Predicates;
import me.lucko.luckperms.common.util.TextUtils;
import net.kyori.text.BuildableComponent;
import net.kyori.text.ComponentBuilder;
import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
@@ -137,15 +137,15 @@ public class PermissionInfo extends SharedSubCommand {
return NodeWithContextComparator.reverse().compare(o1, o2);
};
private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(PermissionHolder holder, String label, Node node) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
private static Consumer<ComponentBuilder<?, ?>> makeFancy(PermissionHolder holder, String label, Node node) {
HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
"¥3> " + (node.getValue() ? "¥a" : "¥c") + node.getPermission(),
" ",
"¥7Click to remove this node from " + holder.getFormattedDisplayName()
), '¥'));
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName(), holder.getType(), false, !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty());
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
ClickEvent clickEvent = ClickEvent.suggestCommand(command);
return component -> {
component.hoverEvent(hoverEvent);
@@ -31,6 +31,7 @@ import me.lucko.luckperms.api.HeldPermission;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.bulkupdate.comparison.Constraint;
import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison;
import me.lucko.luckperms.common.cache.LoadingMap;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.command.CommandResult;
import me.lucko.luckperms.common.command.abstraction.SubCommand;
@@ -50,11 +51,10 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.DurationFormatter;
import me.lucko.luckperms.common.util.Iterators;
import me.lucko.luckperms.common.util.LoadingMap;
import me.lucko.luckperms.common.util.Predicates;
import me.lucko.luckperms.common.util.TextUtils;
import net.kyori.text.BuildableComponent;
import net.kyori.text.ComponentBuilder;
import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
@@ -159,15 +159,15 @@ public class GroupListMembers extends SubCommand<Group> {
return " &8(&7expires in " + DurationFormatter.LONG.formatDateDiff(node.getExpiryUnixTime()) + "&8)";
}
private static Consumer<BuildableComponent.Builder<? ,?>> makeFancy(String holderName, HolderType holderType, String label, HeldPermission<?> perm, LuckPermsPlugin plugin) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
private static Consumer<ComponentBuilder<? ,?>> makeFancy(String holderName, HolderType holderType, String label, HeldPermission<?> perm, LuckPermsPlugin plugin) {
HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
"&3> &b" + perm.asNode().getGroupName(),
" ",
"&7Click to remove this parent from " + holderName
), CommandManager.AMPERSAND_CHAR));
String command = "/" + label + " " + NodeFactory.nodeAsCommand(perm.asNode(), holderName, holderType, false, !plugin.getConfiguration().getContextsFile().getDefaultContexts().isEmpty());
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
ClickEvent clickEvent = ClickEvent.suggestCommand(command);
return component -> {
component.hoverEvent(hoverEvent);
@@ -85,8 +85,8 @@ public class ListGroups extends SingleCommand {
}
component = component.toBuilder().applyDeep(c -> {
c.clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/" + label + " group " + group.getName() + " info"));
c.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to view more info about " + group.getName() + ".").color(TextColor.GRAY)));
c.clickEvent(ClickEvent.runCommand("/" + label + " group " + group.getName() + " info"));
c.hoverEvent(HoverEvent.showText(TextComponent.of("Click to view more info about " + group.getName() + ".").color(TextColor.GRAY)));
}).build();
sender.sendMessage(component);
@@ -95,8 +95,8 @@ public class DebugCommand extends SingleCommand {
Message.DEBUG_URL.send(sender);
Component message = TextComponent.builder(pasteUrl).color(TextColor.AQUA)
.clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, pasteUrl))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to open the debugging data.").color(TextColor.GRAY)))
.clickEvent(ClickEvent.openUrl(pasteUrl))
.hoverEvent(HoverEvent.showText(TextComponent.of("Click to open the debugging data.").color(TextColor.GRAY)))
.build();
sender.sendMessage(message);
@@ -118,8 +118,8 @@ public class EditorCommand extends SingleCommand {
Message.EDITOR_URL.send(sender);
Component message = TextComponent.builder(url).color(TextColor.AQUA)
.clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to open the editor.").color(TextColor.GRAY)))
.clickEvent(ClickEvent.openUrl(url))
.hoverEvent(HoverEvent.showText(TextComponent.of("Click to open the editor.").color(TextColor.GRAY)))
.build();
sender.sendMessage(message);
@@ -32,6 +32,7 @@ import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.bulkupdate.comparison.Comparison;
import me.lucko.luckperms.common.bulkupdate.comparison.Constraint;
import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison;
import me.lucko.luckperms.common.cache.LoadingMap;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.command.CommandResult;
import me.lucko.luckperms.common.command.abstraction.SingleCommand;
@@ -51,11 +52,10 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.DurationFormatter;
import me.lucko.luckperms.common.util.Iterators;
import me.lucko.luckperms.common.util.LoadingMap;
import me.lucko.luckperms.common.util.Predicates;
import me.lucko.luckperms.common.util.TextUtils;
import net.kyori.text.BuildableComponent;
import net.kyori.text.ComponentBuilder;
import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
@@ -169,15 +169,15 @@ public class SearchCommand extends SingleCommand {
return " &8(&7expires in " + DurationFormatter.LONG.formatDateDiff(node.getExpiryUnixTime()) + "&8)";
}
private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(String holderName, HolderType holderType, String label, HeldPermission<?> perm, LuckPermsPlugin plugin) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
private static Consumer<ComponentBuilder<?, ?>> makeFancy(String holderName, HolderType holderType, String label, HeldPermission<?> perm, LuckPermsPlugin plugin) {
HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
"&3> " + (perm.asNode().getValue() ? "&a" : "&c") + perm.asNode().getPermission(),
" ",
"&7Click to remove this node from " + holderName
), CommandManager.AMPERSAND_CHAR));
String command = "/" + label + " " + NodeFactory.nodeAsCommand(perm.asNode(), holderName, holderType, false, !plugin.getConfiguration().getContextsFile().getDefaultContexts().isEmpty());
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
ClickEvent clickEvent = ClickEvent.suggestCommand(command);
return component -> {
component.hoverEvent(hoverEvent);
@@ -97,8 +97,8 @@ public class TreeCommand extends SingleCommand {
Message.TREE_URL.send(sender);
Component message = TextComponent.builder(url).color(TextColor.AQUA)
.clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to open the tree view.").color(TextColor.GRAY)))
.clickEvent(ClickEvent.openUrl(url))
.hoverEvent(HoverEvent.showText(TextComponent.of("Click to open the tree view.").color(TextColor.GRAY)))
.build();
sender.sendMessage(message);
@@ -118,8 +118,8 @@ public class VerboseCommand extends SingleCommand {
Message.VERBOSE_RESULTS_URL.send(sender);
Component message = TextComponent.builder(url).color(TextColor.AQUA)
.clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to open the results page.").color(TextColor.GRAY)))
.clickEvent(ClickEvent.openUrl(url))
.hoverEvent(HoverEvent.showText(TextComponent.of("Click to open the results page.").color(TextColor.GRAY)))
.build();
sender.sendMessage(message);
@@ -69,7 +69,7 @@ public class TrackAppend extends SubCommand<Track> {
if (result.asBoolean()) {
Message.TRACK_APPEND_SUCCESS.send(sender, group.getName(), track.getName());
if (track.getGroups().size() > 1) {
Message.EMPTY.send(sender, MessageUtils.listToArrowSep(track.getGroups(), group.getName()));
Message.BLANK.send(sender, MessageUtils.listToArrowSep(track.getGroups(), group.getName()));
}
ExtendedLogEntry.build().actor(sender).acted(track)
@@ -78,7 +78,7 @@ public class TrackInsert extends SubCommand<Track> {
if (result.asBoolean()) {
Message.TRACK_INSERT_SUCCESS.send(sender, group.getName(), track.getName(), pos);
if (track.getGroups().size() > 1) {
Message.EMPTY.send(sender, MessageUtils.listToArrowSep(track.getGroups(), group.getName()));
Message.BLANK.send(sender, MessageUtils.listToArrowSep(track.getGroups(), group.getName()));
}
ExtendedLogEntry.build().actor(sender).acted(track)
@@ -63,7 +63,7 @@ public class TrackRemove extends SubCommand<Track> {
if (result.asBoolean()) {
Message.TRACK_REMOVE_SUCCESS.send(sender, groupName, track.getName());
if (track.getGroups().size() > 1) {
Message.EMPTY.send(sender, MessageUtils.listToArrowSep(track.getGroups()));
Message.BLANK.send(sender, MessageUtils.listToArrowSep(track.getGroups()));
}
ExtendedLogEntry.build().actor(sender).acted(track)
@@ -130,7 +130,7 @@ public class UserDemote extends SubCommand<User> {
Message.USER_DEMOTE_SUCCESS.send(sender, user.getFormattedDisplayName(), track.getName(), groupFrom, groupTo, MessageUtils.contextSetToString(plugin.getLocaleManager(), context));
if (!silent) {
Message.EMPTY.send(sender, MessageUtils.listToArrowSep(track.getGroups(), groupTo, groupFrom, true));
Message.BLANK.send(sender, MessageUtils.listToArrowSep(track.getGroups(), groupTo, groupFrom, true));
}
ExtendedLogEntry.build().actor(sender).acted(user)
@@ -130,7 +130,7 @@ public class UserPromote extends SubCommand<User> {
Message.USER_PROMOTE_SUCCESS.send(sender, user.getFormattedDisplayName(), track.getName(), groupFrom, groupTo, MessageUtils.contextSetToString(plugin.getLocaleManager(), context));
if (!silent) {
Message.EMPTY.send(sender, MessageUtils.listToArrowSep(track.getGroups(), groupFrom, groupTo, false));
Message.BLANK.send(sender, MessageUtils.listToArrowSep(track.getGroups(), groupFrom, groupTo, false));
}
ExtendedLogEntry.build().actor(sender).acted(user)
@@ -43,6 +43,7 @@ import me.lucko.luckperms.common.primarygroup.AllParentsByWeightHolder;
import me.lucko.luckperms.common.primarygroup.ParentsByWeightHolder;
import me.lucko.luckperms.common.primarygroup.PrimaryGroupHolder;
import me.lucko.luckperms.common.primarygroup.StoredHolder;
import me.lucko.luckperms.common.storage.StorageType;
import me.lucko.luckperms.common.storage.implementation.split.SplitStorageType;
import me.lucko.luckperms.common.storage.misc.StorageCredentials;
import me.lucko.luckperms.common.util.ImmutableCollectors;
@@ -75,16 +76,7 @@ public final class ConfigKeys {
/**
* The name of the server
*/
public static final ConfigKey<String> SERVER = customKey(c -> {
if (c.getBoolean("use-server-properties-name", false)) {
String serverName = c.getPlugin().getBootstrap().getServerName();
if (serverName != null && !serverName.equals("Unknown Server")) {
return serverName.toLowerCase();
}
}
return c.getString("server", "global").toLowerCase();
});
public static final ConfigKey<String> SERVER = lowercaseStringKey("server", "global");
/**
* How many minutes to wait between syncs. A value <= 0 will disable syncing.
@@ -263,6 +255,12 @@ public final class ConfigKeys {
}
});
/**
* If a final sort according to "inheritance rules" should be performed after the traversal algorithm
* has resolved the inheritance tree
*/
public static final ConfigKey<Boolean> POST_TRAVERSAL_INHERITANCE_SORT = booleanKey("post-traversal-inheritance-sort", false);
/**
* The configured group weightings
*/
@@ -468,7 +466,9 @@ public final class ConfigKeys {
/**
* The name of the storage method being used
*/
public static final ConfigKey<String> STORAGE_METHOD = enduringKey(lowercaseStringKey("storage-method", "h2"));
public static final ConfigKey<StorageType> STORAGE_METHOD = enduringKey(customKey(c -> {
return StorageType.parse(c.getString("storage-method", "h2"), StorageType.H2);
}));
/**
* If storage files should be monitored for changes
@@ -483,13 +483,13 @@ public final class ConfigKeys {
/**
* The options for split storage
*/
public static final ConfigKey<Map<SplitStorageType, String>> SPLIT_STORAGE_OPTIONS = enduringKey(customKey(c -> {
EnumMap<SplitStorageType, String> map = new EnumMap<>(SplitStorageType.class);
map.put(SplitStorageType.USER, c.getString("split-storage.methods.user", "h2").toLowerCase());
map.put(SplitStorageType.GROUP, c.getString("split-storage.methods.group", "h2").toLowerCase());
map.put(SplitStorageType.TRACK, c.getString("split-storage.methods.track", "h2").toLowerCase());
map.put(SplitStorageType.UUID, c.getString("split-storage.methods.uuid", "h2").toLowerCase());
map.put(SplitStorageType.LOG, c.getString("split-storage.methods.log", "h2").toLowerCase());
public static final ConfigKey<Map<SplitStorageType, StorageType>> SPLIT_STORAGE_OPTIONS = enduringKey(customKey(c -> {
EnumMap<SplitStorageType, StorageType> map = new EnumMap<>(SplitStorageType.class);
map.put(SplitStorageType.USER, StorageType.parse(c.getString("split-storage.methods.user", "h2"), StorageType.H2));
map.put(SplitStorageType.GROUP, StorageType.parse(c.getString("split-storage.methods.group", "h2"), StorageType.H2));
map.put(SplitStorageType.TRACK, StorageType.parse(c.getString("split-storage.methods.track", "h2"), StorageType.H2));
map.put(SplitStorageType.UUID, StorageType.parse(c.getString("split-storage.methods.uuid", "h2"), StorageType.H2));
map.put(SplitStorageType.LOG, StorageType.parse(c.getString("split-storage.methods.log", "h2"), StorageType.H2));
return ImmutableMap.copyOf(map);
}));
@@ -33,7 +33,7 @@ import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.api.context.StaticContextCalculator;
import me.lucko.luckperms.common.buffer.ExpiringCache;
import me.lucko.luckperms.common.cache.ExpiringCache;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
@@ -27,7 +27,7 @@ package me.lucko.luckperms.common.context;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.buffer.ExpiringCache;
import me.lucko.luckperms.common.cache.ExpiringCache;
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -64,23 +64,44 @@ public enum Dependency {
TEXT(
"net{}kyori",
"text",
"1.11-1.6.5",
"I5D0U+Gsd5G3XO+W+4ZyO7Fyc8g7lt/up8oNpetq1W8=",
"text-api",
"3.0.0",
"/d7o/eZkZx/naJE+pMg1KqIzL8TWxWjA4yxjv8/10Cg=",
Relocation.of("text", "net{}kyori{}text")
),
TEXT_SERIALIZER_GSON(
"net{}kyori",
"text-serializer-gson",
"3.0.0",
"zc1ePBBRCjSoNQiNqsBL+6TYRmaUPyEZtj1LhCtViv0=",
Relocation.of("text", "net{}kyori{}text")
),
TEXT_SERIALIZER_LEGACY(
"net{}kyori",
"text-serializer-legacy",
"3.0.0",
"Zns1sKvALAt3Sn0Px+vENv1XQ9y80E1cSzzDN46C9rQ=",
Relocation.of("text", "net{}kyori{}text")
),
TEXT_ADAPTER_BUKKIT(
"net{}kyori",
"text-adapter-bukkit",
"1.0.2",
"jZx0BgSlfyeamadYiE52wlJbQOwSyB4fffPoE526hOk=",
"3.0.2",
"VnbfELmOHV6DVidHJql6gmsCjfhABEnF6q9LTezUrQg=",
Relocation.of("text", "net{}kyori{}text")
),
TEXT_ADAPTER_BUNGEECORD(
"net{}kyori",
"text-adapter-bungeecord",
"1.0.2",
"hj7z8v8AceARfwTPzLzJwZdTqqERN9fPJPhZQAqD1Rc=",
"3.0.2",
"ZmCmc67danKpZru8rJsDppJZ+f8joquULZI8y/YX4ks=",
Relocation.of("text", "net{}kyori{}text")
),
TEXT_ADAPTER_SPONGEAPI(
"net{}kyori",
"text-adapter-spongeapi",
"3.0.2",
"WPWFw1g8niEGgymV9PdyLADMSL6+UQ7FKdtxnJb79JE=",
Relocation.of("text", "net{}kyori{}text")
),
EVENT(
@@ -100,15 +121,15 @@ public enum Dependency {
OKIO(
"com{}squareup{}" + RelocationHelper.OKIO_STRING,
RelocationHelper.OKIO_STRING,
"1.17.2",
"+AzkLS/6xHrUxH4db5gNYE0kfOsaiGcFz0WBqwyf4rg=",
"1.17.3",
"yxja86IIrjirnYJUP/uT4fGF6GPIoOUsw3L/46WPVUk=",
Relocation.of(RelocationHelper.OKIO_STRING, RelocationHelper.OKIO_STRING)
),
OKHTTP(
"com{}squareup{}" + RelocationHelper.OKHTTP3_STRING,
"okhttp",
"3.13.1",
"CrQacT4qY478H0YQ7zTAf+85j517nXmm9UBrd5sAEaU=",
"3.14.1",
"WmvmkWUwdqpk3NNh0uRF5AYLS13IgrH2uknnnd/D5WM=",
Relocation.of(RelocationHelper.OKHTTP3_STRING, RelocationHelper.OKHTTP3_STRING),
Relocation.of(RelocationHelper.OKIO_STRING, RelocationHelper.OKIO_STRING)
),
@@ -175,7 +175,6 @@ public class DependencyManager {
RelocationHandler relocationHandler = getRelocationHandler();
// attempt to remap the jar.
this.plugin.getLogger().info("Attempting to apply relocations to " + input.getFileName().toString() + "...");
relocationHandler.remap(input, output, relocations);
remappedJars.add(new Source(source.dependency, output));
@@ -255,8 +254,6 @@ public class DependencyManager {
"Actual: " + Base64.getEncoder().encodeToString(hash));
}
this.plugin.getLogger().info("Successfully downloaded '" + fileName + "' with matching checksum: " + Base64.getEncoder().encodeToString(hash));
// if the checksum matches, save the content to disk
Files.write(file, bytes);
success = true;
@@ -74,6 +74,8 @@ public class DependencyRegistry {
if (this.plugin.getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
dependencies.add(Dependency.COMMONS_POOL_2);
dependencies.add(Dependency.JEDIS);
dependencies.add(Dependency.SLF4J_API);
dependencies.add(Dependency.SLF4J_SIMPLE);
}
// don't load slf4j if it's already present
@@ -94,11 +96,6 @@ public class DependencyRegistry {
relocations.add(Relocation.of("gson", "com{}google{}gson"));
}
// don't relocate text when running on Velocity
if (dependency == Dependency.TEXT && type == PlatformType.VELOCITY) {
relocations.remove(Relocation.of("text", "net{}kyori{}text"));
}
// relocate yaml within configurate when running velocity
if (dependency == Dependency.CONFIGURATE_YAML && type == PlatformType.VELOCITY) {
relocations.add(Relocation.of("yaml", "org{}yaml{}snakeyaml"));
@@ -30,8 +30,8 @@ import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.api.LuckPermsApi;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.common.cache.LoadingMap;
import me.lucko.luckperms.common.util.ImmutableCollectors;
import me.lucko.luckperms.common.util.LoadingMap;
import me.lucko.luckperms.common.util.PrivateMethodHandles;
import java.lang.reflect.InvocationHandler;
@@ -25,10 +25,10 @@
package me.lucko.luckperms.common.inheritance;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.HolderType;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.comparator.NodeWithContextComparator;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import java.util.Comparator;
@@ -36,10 +36,10 @@ import java.util.Comparator;
/**
* Determines the order of group inheritance in {@link PermissionHolder}.
*/
public class InheritanceComparator implements Comparator<ResolvedGroup> {
private static final Comparator<ResolvedGroup> NULL_ORIGIN = new InheritanceComparator(null).reversed();
public class InheritanceComparator implements Comparator<PermissionHolder> {
private static final Comparator<PermissionHolder> NULL_ORIGIN = new InheritanceComparator(null).reversed();
public static Comparator<ResolvedGroup> getFor(PermissionHolder origin) {
public static Comparator<? super PermissionHolder> getFor(PermissionHolder origin) {
if (origin.getType() == HolderType.USER) {
return new InheritanceComparator(((User) origin)).reversed();
}
@@ -53,25 +53,38 @@ public class InheritanceComparator implements Comparator<ResolvedGroup> {
}
@Override
public int compare(ResolvedGroup o1, ResolvedGroup o2) {
int result = Integer.compare(o1.group().getWeight().orElse(0), o2.group().getWeight().orElse(0));
public int compare(PermissionHolder o1, PermissionHolder o2) {
// if both users, return 0
// if one or the other is a user, give a higher priority to the user
boolean o1IsUser = o1.getType() == HolderType.USER;
boolean o2IsUser = o2.getType() == HolderType.USER;
if (o1IsUser && o2IsUser) {
return 0;
} else if (o1IsUser) {
return 1;
} else if (o2IsUser) {
return -1;
}
Group o1Group = (Group) o1;
Group o2Group = (Group) o2;
int result = Integer.compare(o1.getWeight().orElse(0), o2.getWeight().orElse(0));
if (result != 0) {
return result;
}
// failing differing group weights, check if one of the groups is a primary group
if (this.origin != null) {
result = Boolean.compare(
o1.group().getName().equalsIgnoreCase(this.origin.getPrimaryGroup().getStoredValue().orElse(NodeFactory.DEFAULT_GROUP_NAME)),
o2.group().getName().equalsIgnoreCase(this.origin.getPrimaryGroup().getStoredValue().orElse(NodeFactory.DEFAULT_GROUP_NAME))
return Boolean.compare(
o1Group.getName().equalsIgnoreCase(this.origin.getPrimaryGroup().getStoredValue().orElse(NodeFactory.DEFAULT_GROUP_NAME)),
o2Group.getName().equalsIgnoreCase(this.origin.getPrimaryGroup().getStoredValue().orElse(NodeFactory.DEFAULT_GROUP_NAME))
);
if (result != 0) {
return result;
}
}
// failing weight checks, fallback to which group applies in more specific context
return NodeWithContextComparator.normal().compare(o1.node(), o2.node());
// failing weight/primary group checks, fallback to the node ordering
// this comparator is only ever used by Collections.sort - which is stable. the existing
// ordering of the nodes will therefore apply.
return 0;
}
}
@@ -25,12 +25,60 @@
package me.lucko.luckperms.common.inheritance;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
import me.lucko.luckperms.common.graph.Graph;
import me.lucko.luckperms.common.graph.TraversalAlgorithm;
import me.lucko.luckperms.common.model.PermissionHolder;
import java.util.ArrayList;
import java.util.List;
/**
* A {@link Graph} which represents an "inheritance tree".
*/
public interface InheritanceGraph extends Graph<PermissionHolder> {
/**
* Returns an iterable which will traverse this inheritance graph using the specified
* algorithm starting at the given permission holder start node.
*
* @param algorithm the algorithm to use when traversing
* @param postTraversalSort if a final sort according to inheritance (weight, primary group) rules
* should be performed after the traversal algorithm has completed
* @param startNode the start node in the inheritance graph
* @return an iterable
*/
default Iterable<PermissionHolder> traverse(TraversalAlgorithm algorithm, boolean postTraversalSort, PermissionHolder startNode) {
Iterable<PermissionHolder> traversal = traverse(algorithm, startNode);
// perform post traversal sort if needed
if (postTraversalSort) {
List<PermissionHolder> resolvedTraversal = new ArrayList<>();
for (PermissionHolder node : traversal) {
resolvedTraversal.add(node);
}
resolvedTraversal.sort(startNode.getInheritanceComparator());
traversal = resolvedTraversal;
}
return traversal;
}
/**
* Perform a traversal according to the rules defined in the configuration.
*
* @param configuration the configuration object
* @param startNode the start node in the inheritance graph
* @return an iterable
*/
default Iterable<PermissionHolder> traverse(LuckPermsConfiguration configuration, PermissionHolder startNode) {
return traverse(
configuration.get(ConfigKeys.INHERITANCE_TRAVERSAL_ALGORITHM),
configuration.get(ConfigKeys.POST_TRAVERSAL_INHERITANCE_SORT),
startNode
);
}
}
@@ -33,9 +33,9 @@ import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* Provides {@link InheritanceGraph}s.
@@ -48,14 +48,12 @@ public class InheritanceHandler {
*/
private final InheritanceGraph nonContextualGraph;
// some cached contextual graphs for common Contexts
private final InheritanceGraph allowAllContextualGraph;
// cached contextual graphs for common Contexts
private final InheritanceGraph globalContextualGraph;
public InheritanceHandler(LuckPermsPlugin plugin) {
this.plugin = plugin;
this.nonContextualGraph = new NonContextualGraph(plugin);
this.allowAllContextualGraph = new ContextualGraph(plugin, Contexts.allowAll());
this.globalContextualGraph = new ContextualGraph(plugin, Contexts.global());
}
@@ -65,13 +63,14 @@ public class InheritanceHandler {
public InheritanceGraph getGraph(Contexts contexts) {
if (contexts == Contexts.allowAll()) {
return this.allowAllContextualGraph;
}
if (contexts == Contexts.global()) {
return this.globalContextualGraph;
throw new IllegalArgumentException("Contexts#allowAll passed to contextual #getGraph method");
}
return new ContextualGraph(this.plugin, contexts);
if (contexts == Contexts.global()) {
return this.globalContextualGraph;
} else {
return new ContextualGraph(this.plugin, contexts);
}
}
private static final class NonContextualGraph implements InheritanceGraph {
@@ -83,15 +82,17 @@ public class InheritanceHandler {
@Override
public Iterable<? extends PermissionHolder> successors(PermissionHolder holder) {
Set<ResolvedGroup> successors = new TreeSet<>(holder.getInheritanceComparator());
List<? extends Node> nodes = holder.getOwnGroupNodes();
for (Node n : nodes) {
Set<Group> successors = new LinkedHashSet<>();
for (Node n : holder.getOwnGroupNodes()) {
Group g = this.plugin.getGroupManager().getIfLoaded(n.getGroupName());
if (g != null) {
successors.add(new ResolvedGroup(n, g));
successors.add(g);
}
}
return composeSuccessors(successors);
List<Group> successorsSorted = new ArrayList<>(successors);
successorsSorted.sort(holder.getInheritanceComparator());
return successorsSorted;
}
}
@@ -110,9 +111,8 @@ public class InheritanceHandler {
@Override
public Iterable<? extends PermissionHolder> successors(PermissionHolder holder) {
Set<ResolvedGroup> successors = new TreeSet<>(holder.getInheritanceComparator());
List<? extends Node> nodes = holder.getOwnGroupNodes(this.context.getContexts());
for (Node n : nodes) {
Set<Group> successors = new LinkedHashSet<>();
for (Node n : holder.getOwnGroupNodes(this.context.getContexts())) {
// effectively: if not (we're applying global groups or it's specific anyways)
if (!((this.context.hasSetting(LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER) || n.isServerSpecific()) && (this.context.hasSetting(LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD) || n.isWorldSpecific()))) {
continue;
@@ -120,19 +120,14 @@ public class InheritanceHandler {
Group g = this.plugin.getGroupManager().getIfLoaded(n.getGroupName());
if (g != null) {
successors.add(new ResolvedGroup(n, g));
successors.add(g);
}
}
return composeSuccessors(successors);
}
}
private static Iterable<PermissionHolder> composeSuccessors(Set<ResolvedGroup> successors) {
List<PermissionHolder> holders = new ArrayList<>(successors.size());
for (ResolvedGroup resolvedGroup : successors) {
holders.add(resolvedGroup.group());
List<Group> successorsSorted = new ArrayList<>(successors);
successorsSorted.sort(holder.getInheritanceComparator());
return successorsSorted;
}
return holders;
}
}
@@ -60,7 +60,7 @@ public enum Message {
false
),
EMPTY("{}", true),
BLANK("{}", true),
PLAYER_ONLINE("&aOnline", false),
PLAYER_OFFLINE("&cOffline", false),
LOADING_DATABASE_ERROR("&cA database error occurred whilst loading permissions data. Please try again later.", true),
@@ -28,7 +28,7 @@ package me.lucko.luckperms.common.messaging;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.messenger.Messenger;
import me.lucko.luckperms.api.messenger.MessengerProvider;
import me.lucko.luckperms.common.buffer.BufferedRequest;
import me.lucko.luckperms.common.cache.BufferedRequest;
import me.lucko.luckperms.common.model.User;
public interface InternalMessagingService {
@@ -37,7 +37,7 @@ import me.lucko.luckperms.api.messenger.message.type.LogMessage;
import me.lucko.luckperms.api.messenger.message.type.UpdateMessage;
import me.lucko.luckperms.api.messenger.message.type.UserUpdateMessage;
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
import me.lucko.luckperms.common.buffer.BufferedRequest;
import me.lucko.luckperms.common.cache.BufferedRequest;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.messaging.message.LogMessageImpl;
import me.lucko.luckperms.common.messaging.message.UpdateMessageImpl;
@@ -27,7 +27,7 @@ package me.lucko.luckperms.common.model;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.nodetype.types.DisplayNameType;
import me.lucko.luckperms.common.buffer.Cache;
import me.lucko.luckperms.common.cache.Cache;
import me.lucko.luckperms.common.config.ConfigKeys;
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -29,7 +29,7 @@ import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.nodetype.types.DisplayNameType;
import me.lucko.luckperms.common.api.implementation.ApiGroup;
import me.lucko.luckperms.common.buffer.Cache;
import me.lucko.luckperms.common.cache.Cache;
import me.lucko.luckperms.common.cacheddata.GroupCachedData;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
@@ -35,7 +35,7 @@ import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.StandardNodeEquality;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.buffer.Cache;
import me.lucko.luckperms.common.cache.Cache;
import me.lucko.luckperms.common.context.ContextSetComparator;
import me.lucko.luckperms.common.node.comparator.NodeComparator;
import me.lucko.luckperms.common.node.comparator.NodeWithContextComparator;
@@ -43,10 +43,8 @@ import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.cacheddata.HolderCachedData;
import me.lucko.luckperms.common.cacheddata.type.MetaAccumulator;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.inheritance.InheritanceComparator;
import me.lucko.luckperms.common.inheritance.InheritanceGraph;
import me.lucko.luckperms.common.inheritance.ResolvedGroup;
import me.lucko.luckperms.common.node.comparator.NodeWithContextComparator;
import me.lucko.luckperms.common.node.utils.InheritanceInfo;
import me.lucko.luckperms.common.node.utils.MetaType;
@@ -130,7 +128,7 @@ public abstract class PermissionHolder {
/**
* Comparator used to ordering groups when calculating inheritance
*/
private final Comparator<ResolvedGroup> inheritanceComparator = InheritanceComparator.getFor(this);
private final Comparator<? super PermissionHolder> inheritanceComparator = InheritanceComparator.getFor(this);
/**
* Creates a new instance
@@ -151,7 +149,7 @@ public abstract class PermissionHolder {
return this.ioLock;
}
public Comparator<ResolvedGroup> getInheritanceComparator() {
public Comparator<? super PermissionHolder> getInheritanceComparator() {
return this.inheritanceComparator;
}
@@ -213,18 +211,11 @@ public abstract class PermissionHolder {
*/
public abstract HolderType getType();
/**
* Invalidates the holder's cached data.
*/
public void invalidateCachedData() {
getCachedData().invalidate();
}
protected void invalidateCache() {
this.enduringNodes.invalidate();
this.transientNodes.invalidate();
invalidateCachedData();
getCachedData().invalidate();
getPlugin().getEventFactory().handleDataRecalculate(this);
}
@@ -321,7 +312,7 @@ public abstract class PermissionHolder {
public void accumulateInheritancesTo(List<? super LocalizedNode> accumulator, Contexts context) {
InheritanceGraph graph = this.plugin.getInheritanceHandler().getGraph(context);
Iterable<PermissionHolder> traversal = graph.traverse(this.plugin.getConfiguration().get(ConfigKeys.INHERITANCE_TRAVERSAL_ALGORITHM), this);
Iterable<PermissionHolder> traversal = graph.traverse(this.plugin.getConfiguration(), this);
for (PermissionHolder holder : traversal) {
List<? extends LocalizedNode> nodes = holder.getOwnNodes(context.getContexts());
accumulator.addAll(nodes);
@@ -336,7 +327,7 @@ public abstract class PermissionHolder {
public void accumulateInheritancesTo(List<? super LocalizedNode> accumulator) {
InheritanceGraph graph = this.plugin.getInheritanceHandler().getGraph();
Iterable<PermissionHolder> traversal = graph.traverse(this.plugin.getConfiguration().get(ConfigKeys.INHERITANCE_TRAVERSAL_ALGORITHM), this);
Iterable<PermissionHolder> traversal = graph.traverse(this.plugin.getConfiguration(), this);
for (PermissionHolder holder : traversal) {
List<? extends LocalizedNode> nodes = holder.getOwnNodes();
accumulator.addAll(nodes);
@@ -409,7 +400,7 @@ public abstract class PermissionHolder {
}
InheritanceGraph graph = this.plugin.getInheritanceHandler().getGraph(context);
Iterable<PermissionHolder> traversal = graph.traverse(this.plugin.getConfiguration().get(ConfigKeys.INHERITANCE_TRAVERSAL_ALGORITHM), this);
Iterable<PermissionHolder> traversal = graph.traverse(this.plugin.getConfiguration(), this);
for (PermissionHolder holder : traversal) {
List<? extends LocalizedNode> nodes = holder.getOwnNodes(context.getContexts());
for (LocalizedNode node : nodes) {
@@ -438,7 +429,7 @@ public abstract class PermissionHolder {
}
InheritanceGraph graph = this.plugin.getInheritanceHandler().getGraph();
Iterable<PermissionHolder> traversal = graph.traverse(this.plugin.getConfiguration().get(ConfigKeys.INHERITANCE_TRAVERSAL_ALGORITHM), this);
Iterable<PermissionHolder> traversal = graph.traverse(this.plugin.getConfiguration(), this);
for (PermissionHolder holder : traversal) {
List<? extends LocalizedNode> nodes = holder.getOwnNodes();
for (LocalizedNode node : nodes) {
@@ -28,7 +28,7 @@ package me.lucko.luckperms.common.model;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.api.nodetype.types.WeightType;
import me.lucko.luckperms.common.buffer.Cache;
import me.lucko.luckperms.common.cache.Cache;
import me.lucko.luckperms.common.config.ConfigKeys;
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -27,8 +27,8 @@ package me.lucko.luckperms.common.model.manager;
import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.common.cache.LoadingMap;
import me.lucko.luckperms.common.model.Identifiable;
import me.lucko.luckperms.common.util.LoadingMap;
import java.util.Map;
@@ -77,11 +77,6 @@ public abstract class AbstractManager<I, C extends Identifiable<I>, T extends C>
}
}
@Override
public void unloadAll() {
this.objects.clear();
}
protected I sanitizeIdentifier(I i) {
return i;
}
@@ -86,9 +86,4 @@ public interface Manager<I, C extends Identifiable<I>, T extends C> extends Func
*/
void unload(C object);
/**
* Unloads all objects from the manager
*/
void unloadAll();
}
@@ -26,7 +26,6 @@
package me.lucko.luckperms.common.model.manager.group;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.manager.AbstractManager;
import java.util.Optional;
@@ -67,11 +66,11 @@ public abstract class AbstractGroupManager<T extends Group> extends AbstractMana
@Override
public void invalidateAllGroupCaches() {
getAll().values().forEach(PermissionHolder::invalidateCachedData);
getAll().values().forEach(g -> g.getCachedData().invalidate());
}
@Override
public void invalidateAllPermissionCalculators() {
getAll().values().forEach(p -> p.getCachedData().invalidatePermissionCalculators());
getAll().values().forEach(g -> g.getCachedData().invalidatePermissionCalculators());
}
}
@@ -26,13 +26,11 @@
package me.lucko.luckperms.common.model.manager.user;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.Streams;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.model.UserIdentifier;
import me.lucko.luckperms.common.model.manager.AbstractManager;
@@ -166,12 +164,12 @@ public abstract class AbstractUserManager<T extends User> extends AbstractManage
@Override
public void invalidateAllUserCaches() {
getAll().values().forEach(PermissionHolder::invalidateCachedData);
getAll().values().forEach(u -> u.getCachedData().invalidate());
}
@Override
public void invalidateAllPermissionCalculators() {
getAll().values().forEach(p -> p.getCachedData().invalidatePermissionCalculators());
getAll().values().forEach(u -> u.getCachedData().invalidatePermissionCalculators());
}
/**
@@ -28,7 +28,7 @@ package me.lucko.luckperms.common.node.factory;
import com.google.common.base.Splitter;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.util.PatternCache;
import me.lucko.luckperms.common.cache.PatternCache;
import java.util.Iterator;
import java.util.List;
@@ -37,9 +37,9 @@ import me.lucko.luckperms.api.nodetype.types.PrefixType;
import me.lucko.luckperms.api.nodetype.types.RegexType;
import me.lucko.luckperms.api.nodetype.types.SuffixType;
import me.lucko.luckperms.api.nodetype.types.WeightType;
import me.lucko.luckperms.common.buffer.Cache;
import me.lucko.luckperms.common.cache.Cache;
import me.lucko.luckperms.common.cache.PatternCache;
import me.lucko.luckperms.common.node.factory.LegacyNodeFactory;
import me.lucko.luckperms.common.util.PatternCache;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -56,6 +56,7 @@ import me.lucko.luckperms.common.verbose.VerboseHandler;
import me.lucko.luckperms.common.web.Bytebin;
import java.io.IOException;
import java.util.EnumSet;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -115,7 +116,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
// now the configuration is loaded, we can create a storage factory and load initial dependencies
StorageFactory storageFactory = new StorageFactory(this);
Set<StorageType> storageTypes = storageFactory.getRequiredTypes(StorageType.H2);
Set<StorageType> storageTypes = storageFactory.getRequiredTypes();
this.dependencyManager.loadStorageDependencies(storageTypes);
// register listeners
@@ -132,7 +133,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
}
// initialise storage
this.storage = storageFactory.getInstance(StorageType.H2);
this.storage = storageFactory.getInstance();
this.messagingService = provideMessagingFactory().getInstance();
// setup the update task buffer
@@ -220,8 +221,19 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
getLogger().info("Goodbye!");
}
protected Set<Dependency> getGlobalDependencies() {
return EnumSet.of(
Dependency.TEXT,
Dependency.TEXT_SERIALIZER_GSON,
Dependency.TEXT_SERIALIZER_LEGACY,
Dependency.CAFFEINE,
Dependency.OKIO,
Dependency.OKHTTP,
Dependency.EVENT
);
}
protected abstract void setupSenderFactory();
protected abstract Set<Dependency> getGlobalDependencies();
protected abstract ConfigurationAdapter provideConfigurationAdapter();
protected abstract void registerPlatformListeners();
protected abstract MessagingFactory<?> provideMessagingFactory();
@@ -45,25 +45,15 @@ public class AllParentsByWeightHolder extends ContextualHolder {
protected @NonNull Optional<String> calculateValue(Contexts contexts) {
InheritanceGraph graph = this.user.getPlugin().getInheritanceHandler().getGraph(contexts);
// fully traverse the graph, obtain a list of permission holders the user inherits from
Iterable<PermissionHolder> traversal = graph.traverse(this.user.getPlugin().getConfiguration().get(ConfigKeys.INHERITANCE_TRAVERSAL_ALGORITHM), this.user);
// fully traverse the graph, obtain a list of permission holders the user inherits from in weight order.
Iterable<PermissionHolder> traversal = graph.traverse(this.user.getPlugin().getConfiguration().get(ConfigKeys.INHERITANCE_TRAVERSAL_ALGORITHM), true, this.user);
Group bestGroup = null;
int best = 0;
// return the name of the first found group
for (PermissionHolder holder : traversal) {
if (!(holder instanceof Group)) {
continue;
}
Group g = ((Group) holder);
int weight = g.getWeight().orElse(0);
if (bestGroup == null || g.getWeight().orElse(0) > best) {
bestGroup = g;
best = weight;
if (holder instanceof Group) {
return Optional.of(((Group) holder).getName());
}
}
return bestGroup == null ? Optional.empty() : Optional.of(bestGroup.getName());
return Optional.empty();
}
}
@@ -25,16 +25,19 @@
package me.lucko.luckperms.common.sender;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.context.ContextManager;
import me.lucko.luckperms.common.context.ContextSetFormatter;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import net.kyori.text.Component;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* Wrapper interface to represent a CommandSender/CommandSource within the common command implementations.
@@ -78,16 +81,23 @@ public interface Sender {
return name;
}
String location = ContextSetFormatter.toMinimalString(contextManager.getStaticContext()).orElse(null);
if (location == null) {
ImmutableContextSet staticContext = contextManager.getStaticContext();
String location;
if (staticContext.isEmpty()) {
return name;
} else if (staticContext.size() == 1) {
location = staticContext.iterator().next().getValue();
} else {
Set<String> servers = staticContext.getValues(Contexts.SERVER_KEY);
if (servers.size() == 1) {
location = servers.iterator().next();
} else {
location = staticContext.toSet().stream().map(pair -> pair.getKey() + "=" + pair.getValue()).collect(Collectors.joining(";"));
}
}
if (isConsole()) {
return name.toLowerCase() + "@" + location;
} else {
return name + "@" + location;
}
return name + "@" + location;
}
/**
@@ -26,7 +26,6 @@
package me.lucko.luckperms.common.storage;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
@@ -59,45 +58,20 @@ public class StorageFactory {
this.plugin = plugin;
}
public Set<StorageType> getRequiredTypes(StorageType defaultMethod) {
public Set<StorageType> getRequiredTypes() {
if (this.plugin.getConfiguration().get(ConfigKeys.SPLIT_STORAGE)) {
return this.plugin.getConfiguration().get(ConfigKeys.SPLIT_STORAGE_OPTIONS).entrySet().stream()
.map(e -> {
StorageType type = StorageType.parse(e.getValue());
if (type == null) {
this.plugin.getLogger().severe("Storage method for " + e.getKey() + " - " + e.getValue() + " not recognised. " +
"Using the default instead.");
type = defaultMethod;
}
return type;
})
.collect(ImmutableCollectors.toEnumSet(StorageType.class));
return ImmutableSet.copyOf(this.plugin.getConfiguration().get(ConfigKeys.SPLIT_STORAGE_OPTIONS).values());
} else {
String method = this.plugin.getConfiguration().get(ConfigKeys.STORAGE_METHOD);
StorageType type = StorageType.parse(method);
if (type == null) {
this.plugin.getLogger().severe("Storage method '" + method + "' not recognised. Using the default instead.");
type = defaultMethod;
}
return ImmutableSet.of(type);
return ImmutableSet.of(this.plugin.getConfiguration().get(ConfigKeys.STORAGE_METHOD));
}
}
public Storage getInstance(StorageType defaultMethod) {
public Storage getInstance() {
Storage storage;
if (this.plugin.getConfiguration().get(ConfigKeys.SPLIT_STORAGE)) {
this.plugin.getLogger().info("Loading storage provider... [SPLIT STORAGE]");
Map<SplitStorageType, StorageType> mappedTypes = this.plugin.getConfiguration().get(ConfigKeys.SPLIT_STORAGE_OPTIONS).entrySet().stream()
.map(e -> {
StorageType type = StorageType.parse(e.getValue());
if (type == null) {
type = defaultMethod;
}
return Maps.immutableEntry(e.getKey(), type);
})
.collect(ImmutableCollectors.toEnumMap(SplitStorageType.class, Map.Entry::getKey, Map.Entry::getValue));
Map<SplitStorageType, StorageType> mappedTypes = this.plugin.getConfiguration().get(ConfigKeys.SPLIT_STORAGE_OPTIONS);
Map<StorageType, StorageImplementation> backing = mappedTypes.values().stream()
.distinct()
.collect(ImmutableCollectors.toEnumMap(StorageType.class, e -> e, this::createNewImplementation));
@@ -106,12 +80,7 @@ public class StorageFactory {
storage = new Storage(this.plugin, new SplitStorage(this.plugin, backing, mappedTypes));
} else {
String method = this.plugin.getConfiguration().get(ConfigKeys.STORAGE_METHOD);
StorageType type = StorageType.parse(method);
if (type == null) {
type = defaultMethod;
}
StorageType type = this.plugin.getConfiguration().get(ConfigKeys.STORAGE_METHOD);
this.plugin.getLogger().info("Loading storage provider... [" + type.name() + "]");
storage = makeInstance(type);
}
@@ -63,7 +63,7 @@ public enum StorageType {
this.identifiers = ImmutableList.copyOf(identifiers);
}
public static StorageType parse(String name) {
public static StorageType parse(String name, StorageType def) {
for (StorageType t : values()) {
for (String id : t.getIdentifiers()) {
if (id.equalsIgnoreCase(name)) {
@@ -71,7 +71,7 @@ public enum StorageType {
}
}
}
return null;
return def;
}
public String getName() {
@@ -217,7 +217,6 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
} catch (Exception e) {
throw reportException(uuid.toString(), e);
} finally {
user.invalidateCachedData();
user.getIoLock().unlock();
}
return user;
@@ -273,7 +272,6 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
} catch (Exception e) {
throw reportException(name, e);
} finally {
group.invalidateCachedData();
group.getIoLock().unlock();
}
return group;
@@ -306,7 +304,6 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
throw reportException(name, e);
} finally {
if (group != null) {
group.invalidateCachedData();
group.getIoLock().unlock();
}
}
@@ -456,8 +453,7 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
return this.uuidCache.lookupUsername(uuid);
}
private static NodeDataContainer readAttributes(ConfigurationNode attributes, Function<ConfigurationNode, String> permissionFunction) {
boolean value = attributes.getNode("value").getBoolean(true);
private static NodeDataContainer readMetaAttributes(ConfigurationNode attributes, Function<ConfigurationNode, String> permissionFunction) {
String server = attributes.getNode("server").getString("global");
String world = attributes.getNode("world").getString("global");
long expiry = attributes.getNode("expiry").getLong(0L);
@@ -468,7 +464,7 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
context = ContextSetConfigurateSerializer.deserializeContextSet(contextMap).makeImmutable();
}
return NodeDataContainer.of(permissionFunction.apply(attributes), value, server, world, expiry, context);
return NodeDataContainer.of(permissionFunction.apply(attributes), true, server, world, expiry, context);
}
private static Collection<NodeDataContainer> readAttributes(ConfigurationNode attributes, String permission) {
@@ -561,7 +557,7 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
if (entry == null) {
continue;
}
nodes.add(readAttributes(entry.getValue(), c -> NodeFactory.groupNode(entry.getKey())));
nodes.add(readMetaAttributes(entry.getValue(), c -> NodeFactory.groupNode(entry.getKey())));
}
}
@@ -574,7 +570,7 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
if (entry == null) {
continue;
}
nodes.add(readAttributes(entry.getValue(), c -> NodeFactory.chatMetaNode(chatMetaType, c.getNode("priority").getInt(0), entry.getKey())));
nodes.add(readMetaAttributes(entry.getValue(), c -> NodeFactory.chatMetaNode(chatMetaType, c.getNode("priority").getInt(0), entry.getKey())));
}
}
}
@@ -586,7 +582,7 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
if (entry == null) {
continue;
}
nodes.add(readAttributes(entry.getValue(), c -> NodeFactory.metaNode(entry.getKey(), c.getNode("value").getString("null"))));
nodes.add(readMetaAttributes(entry.getValue(), c -> NodeFactory.metaNode(entry.getKey(), c.getNode("value").getString("null"))));
}
}
@@ -33,7 +33,7 @@ import com.google.gson.stream.JsonWriter;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogEntryJsonSerializer;
import me.lucko.luckperms.common.buffer.BufferedRequest;
import me.lucko.luckperms.common.cache.BufferedRequest;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.util.gson.GsonProvider;
@@ -297,7 +297,6 @@ public class MongoStorage implements StorageImplementation {
}
}
} finally {
user.invalidateCachedData();
user.getIoLock().unlock();
}
return user;
@@ -368,7 +367,6 @@ public class MongoStorage implements StorageImplementation {
}
}
} finally {
group.invalidateCachedData();
group.getIoLock().unlock();
}
return group;
@@ -398,7 +396,6 @@ public class MongoStorage implements StorageImplementation {
}
} finally {
if (group != null) {
group.invalidateCachedData();
group.getIoLock().unlock();
}
}
@@ -61,6 +61,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.sql.BatchUpdateException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@@ -68,6 +69,7 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -173,27 +175,58 @@ public class SqlStorage implements StorageImplementation {
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
List<String> queries = new LinkedList<>();
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("--") || line.startsWith("#")) {
continue;
}
sb.append(line);
// check for end of declaration
if (line.endsWith(";")) {
sb.deleteCharAt(sb.length() - 1);
String result = this.statementProcessor.apply(sb.toString().trim());
if (!result.isEmpty()) {
queries.add(result);
}
// reset
sb = new StringBuilder();
}
}
try (Connection connection = this.connectionFactory.getConnection()) {
boolean utf8mb4Unsupported = false;
try (Statement s = connection.createStatement()) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("--") || line.startsWith("#")) continue;
for (String query : queries) {
s.addBatch(query);
}
sb.append(line);
// check for end of declaration
if (line.endsWith(";")) {
sb.deleteCharAt(sb.length() - 1);
String result = this.statementProcessor.apply(sb.toString().trim());
if (!result.isEmpty()) s.addBatch(result);
// reset
sb = new StringBuilder();
try {
s.executeBatch();
} catch (BatchUpdateException e) {
if (e.getMessage().contains("Unknown character set")) {
utf8mb4Unsupported = true;
} else {
throw e;
}
}
s.executeBatch();
}
// try again
if (utf8mb4Unsupported) {
try (Statement s = connection.createStatement()) {
for (String query : queries) {
s.addBatch(query.replace("utf8mb4", "utf8"));
}
s.executeBatch();
}
}
}
}
@@ -361,7 +394,6 @@ public class SqlStorage implements StorageImplementation {
}
}
} finally {
user.invalidateCachedData();
user.getIoLock().unlock();
}
return user;
@@ -603,7 +635,6 @@ public class SqlStorage implements StorageImplementation {
group.clearNodes();
}
} finally {
group.invalidateCachedData();
group.getIoLock().unlock();
}
return Optional.of(group);
@@ -39,10 +39,10 @@ public class CacheHousekeepingTask implements Runnable {
@Override
public void run() {
for (User user : this.plugin.getUserManager().getAll().values()) {
user.getCachedData().doCacheCleanup();
user.getCachedData().performCacheCleanup();
}
for (Group group : this.plugin.getGroupManager().getAll().values()) {
group.getCachedData().doCacheCleanup();
group.getCachedData().performCacheCleanup();
}
}
}
@@ -26,7 +26,7 @@
package me.lucko.luckperms.common.tasks;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.buffer.BufferedRequest;
import me.lucko.luckperms.common.cache.BufferedRequest;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
@@ -27,7 +27,7 @@ package me.lucko.luckperms.common.util;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
import net.kyori.text.serializer.ComponentSerializers;
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
import java.util.Arrays;
import java.util.stream.Collectors;
@@ -46,19 +46,19 @@ public final class TextUtils {
}
public static TextComponent fromLegacy(String input, char character) {
return ComponentSerializers.LEGACY.deserialize(input, character);
return LegacyComponentSerializer.INSTANCE.deserialize(input, character);
}
public static TextComponent fromLegacy(String input) {
return ComponentSerializers.LEGACY.deserialize(input);
return LegacyComponentSerializer.INSTANCE.deserialize(input);
}
public static String toLegacy(Component component, char character) {
return ComponentSerializers.LEGACY.serialize(component, character);
return LegacyComponentSerializer.INSTANCE.serialize(component, character);
}
public static String toLegacy(Component component) {
return ComponentSerializers.LEGACY.serialize(component);
return LegacyComponentSerializer.INSTANCE.serialize(component);
}
public static String rewritePlaceholders(String input) {
@@ -221,7 +221,7 @@ public class VerboseListener {
}
// send the message
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(hover.stream()), CommandManager.AMPERSAND_CHAR));
HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(hover.stream()), CommandManager.AMPERSAND_CHAR));
TextComponent text = textComponent.toBuilder().applyDeep(comp -> comp.hoverEvent(hoverEvent)).build();
this.notifiedSender.sendMessage(text);
}
+1
View File
@@ -3,6 +3,7 @@ plugins {
}
repositories {
mavenLocal()
maven { url 'https://repo.potestas.xyz/main/' }
}
@@ -168,11 +168,6 @@ public class LPNukkitBootstrap extends PluginBase implements LuckPermsBootstrap
return getServer().getVersion() + " - " + getServer().getNukkitVersion();
}
@Override
public String getServerName() {
return getServer().getServerUniqueId().toString();
}
@Override
public Path getDataDirectory() {
return getDataFolder().toPath().toAbsolutePath();
Loaded 100 of 139 files, more files were not shown because too many files have changed in this diff. Show more