Various performance optimizations
This commit is contained in:
parent
a0be1c7c48
commit
18f09f9862
@ -25,95 +25,16 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.AbstractJavaScheduler;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerTask;
|
||||
import me.lucko.luckperms.common.utils.Iterators;
|
||||
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class BukkitSchedulerAdapter implements SchedulerAdapter {
|
||||
private final LPBukkitBootstrap bootstrap;
|
||||
|
||||
private final ExecutorService asyncFallback;
|
||||
private final Executor asyncBukkit;
|
||||
public class BukkitSchedulerAdapter extends AbstractJavaScheduler implements SchedulerAdapter {
|
||||
private final Executor sync;
|
||||
private final Executor async;
|
||||
|
||||
private boolean useFallback = true;
|
||||
|
||||
private final Set<SchedulerTask> tasks = ConcurrentHashMap.newKeySet();
|
||||
|
||||
public BukkitSchedulerAdapter(LPBukkitBootstrap bootstrap) {
|
||||
this.bootstrap = bootstrap;
|
||||
|
||||
this.sync = new SyncExecutor();
|
||||
this.asyncFallback = new FallbackAsyncExecutor();
|
||||
this.asyncBukkit = new BukkitAsyncExecutor();
|
||||
this.async = new AsyncExecutor();
|
||||
}
|
||||
|
||||
private BukkitScheduler scheduler() {
|
||||
return this.bootstrap.getServer().getScheduler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAsync(Runnable runnable) {
|
||||
async().execute(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSync(Runnable runnable) {
|
||||
sync().execute(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks) {
|
||||
SchedulerTask task = new BukkitSchedulerTask(scheduler().runTaskTimerAsynchronously(this.bootstrap, runnable, intervalTicks, intervalTicks));
|
||||
this.tasks.add(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask syncRepeating(Runnable runnable, long intervalTicks) {
|
||||
SchedulerTask task = new BukkitSchedulerTask(scheduler().runTaskTimer(this.bootstrap, runnable, intervalTicks, intervalTicks));
|
||||
this.tasks.add(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncLater(Runnable runnable, long delayTicks) {
|
||||
return new BukkitSchedulerTask(scheduler().runTaskLaterAsynchronously(this.bootstrap, runnable, delayTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask syncLater(Runnable runnable, long delayTicks) {
|
||||
return new BukkitSchedulerTask(scheduler().runTaskLater(this.bootstrap, runnable, delayTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
Iterators.iterate(this.tasks, SchedulerTask::cancel);
|
||||
|
||||
// wait for executor
|
||||
this.asyncFallback.shutdown();
|
||||
try {
|
||||
this.asyncFallback.awaitTermination(30, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.sync = r -> bootstrap.getServer().getScheduler().scheduleSyncDelayedTask(bootstrap, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -121,62 +42,4 @@ public class BukkitSchedulerAdapter implements SchedulerAdapter {
|
||||
return this.sync;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor async() {
|
||||
return this.async;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor platformAsync() {
|
||||
return this.asyncBukkit;
|
||||
}
|
||||
|
||||
public void setUseFallback(boolean useFallback) {
|
||||
this.useFallback = useFallback;
|
||||
}
|
||||
|
||||
private final class SyncExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(@Nonnull Runnable runnable) {
|
||||
BukkitSchedulerAdapter.this.bootstrap.getServer().getScheduler().scheduleSyncDelayedTask(BukkitSchedulerAdapter.this.bootstrap, runnable);
|
||||
}
|
||||
}
|
||||
|
||||
private final class AsyncExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(@Nonnull Runnable runnable) {
|
||||
if (BukkitSchedulerAdapter.this.useFallback || !BukkitSchedulerAdapter.this.bootstrap.isEnabled()) {
|
||||
BukkitSchedulerAdapter.this.asyncFallback.execute(runnable);
|
||||
} else {
|
||||
BukkitSchedulerAdapter.this.asyncBukkit.execute(runnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class BukkitAsyncExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(@Nonnull Runnable runnable) {
|
||||
BukkitSchedulerAdapter.this.bootstrap.getServer().getScheduler().runTaskAsynchronously(BukkitSchedulerAdapter.this.bootstrap, runnable);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class FallbackAsyncExecutor extends ThreadPoolExecutor {
|
||||
private FallbackAsyncExecutor() {
|
||||
super(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>(), new ThreadFactoryBuilder().setNameFormat("luckperms-fallback-%d").build());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class BukkitSchedulerTask implements SchedulerTask {
|
||||
private final BukkitTask task;
|
||||
|
||||
private BukkitSchedulerTask(BukkitTask task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.task.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class BukkitSenderFactory extends SenderFactory<CommandSender> {
|
||||
}
|
||||
|
||||
// otherwise, send the message sync
|
||||
getPlugin().getBootstrap().getScheduler().doSync(new SyncMessengerAgent(sender, s));
|
||||
getPlugin().getBootstrap().getScheduler().executeSync(new SyncMessengerAgent(sender, s));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,7 +46,7 @@ import me.lucko.luckperms.bukkit.model.server.LPSubscriptionMap;
|
||||
import me.lucko.luckperms.bukkit.vault.VaultHookManager;
|
||||
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
|
||||
import me.lucko.luckperms.common.api.delegates.model.ApiUser;
|
||||
import me.lucko.luckperms.common.calculators.PlatformCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
@ -78,6 +78,7 @@ import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@ -152,7 +153,7 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PlatformCalculatorFactory provideCalculatorFactory() {
|
||||
protected CalculatorFactory provideCalculatorFactory() {
|
||||
return new BukkitCalculatorFactory(this);
|
||||
}
|
||||
|
||||
@ -177,7 +178,7 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
|
||||
// schedule another injection after all plugins have loaded
|
||||
// the entire pluginmanager instance is replaced by some plugins :(
|
||||
this.bootstrap.getScheduler().asyncLater(injector, 1L);
|
||||
this.bootstrap.getServer().getScheduler().runTaskLaterAsynchronously(this.bootstrap, injector, 1);
|
||||
}
|
||||
|
||||
// Provide vault support
|
||||
@ -214,8 +215,8 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
protected void registerHousekeepingTasks() {
|
||||
this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 60L);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2400L);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 3, TimeUnit.SECONDS);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -234,7 +235,7 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
|
||||
// remove all operators on startup if they're disabled
|
||||
if (!getConfiguration().get(ConfigKeys.OPS_ENABLED)) {
|
||||
this.bootstrap.getScheduler().platformAsync().execute(() -> {
|
||||
this.bootstrap.getServer().getScheduler().runTaskAsynchronously(this.bootstrap, () -> {
|
||||
for (OfflinePlayer player : this.bootstrap.getServer().getOperators()) {
|
||||
player.setOp(false);
|
||||
}
|
||||
@ -250,16 +251,13 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
});
|
||||
}
|
||||
|
||||
// replace the temporary executor when the Bukkit one starts
|
||||
this.bootstrap.getServer().getScheduler().runTaskAsynchronously(this.bootstrap, () -> this.bootstrap.getScheduler().setUseFallback(false));
|
||||
|
||||
// Load any online users (in the case of a reload)
|
||||
for (Player player : this.bootstrap.getServer().getOnlinePlayers()) {
|
||||
this.bootstrap.getScheduler().doAsync(() -> {
|
||||
this.bootstrap.getScheduler().executeAsync(() -> {
|
||||
try {
|
||||
User user = this.connectionListener.loadUser(player.getUniqueId(), player.getName());
|
||||
if (user != null) {
|
||||
this.bootstrap.getScheduler().doSync(() -> {
|
||||
this.bootstrap.getScheduler().executeSync(() -> {
|
||||
try {
|
||||
LPPermissible lpPermissible = new LPPermissible(player, user, this);
|
||||
PermissibleInjector.inject(player, lpPermissible);
|
||||
@ -275,12 +273,6 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performEarlyDisableTasks() {
|
||||
// Switch back to the fallback executor, the bukkit one won't allow new tasks
|
||||
this.bootstrap.getScheduler().setUseFallback(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removePlatformHooks() {
|
||||
// uninject from players
|
||||
|
@ -32,7 +32,7 @@ import me.lucko.luckperms.api.LookupSetting;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.bukkit.processors.ChildProcessor;
|
||||
import me.lucko.luckperms.bukkit.processors.DefaultsProcessor;
|
||||
import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
@ -42,7 +42,7 @@ import me.lucko.luckperms.common.processors.PermissionProcessor;
|
||||
import me.lucko.luckperms.common.processors.RegexProcessor;
|
||||
import me.lucko.luckperms.common.processors.WildcardProcessor;
|
||||
|
||||
public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
public class BukkitCalculatorFactory implements CalculatorFactory {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
public BukkitCalculatorFactory(LPBukkitPlugin plugin) {
|
||||
@ -71,6 +71,6 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
processors.add(new DefaultsProcessor(this.plugin, contexts.hasSetting(LookupSetting.IS_OP)));
|
||||
}
|
||||
|
||||
return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build()));
|
||||
return new PermissionCalculator(this.plugin, metadata, processors.build());
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
this.plugin.getUserManager().getHouseKeeper().registerUsage(player.getUniqueId());
|
||||
|
||||
// force a clear of transient nodes
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId());
|
||||
if (user != null) {
|
||||
user.clearTransientNodes();
|
||||
|
@ -87,7 +87,7 @@ public class LilyPadMessenger implements Messenger {
|
||||
|
||||
@EventListener
|
||||
public void onMessage(MessageEvent event) {
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
try {
|
||||
String channel = event.getChannel();
|
||||
|
||||
|
@ -189,7 +189,6 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
||||
|
||||
// remove transient permissions from the holder which were added by this attachment & equal the permission
|
||||
User user = this.permissible.getUser();
|
||||
|
||||
user.removeIfTransient(LocalizedNode.composedPredicate(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name)));
|
||||
}
|
||||
|
||||
|
@ -33,6 +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.buffers.Cache;
|
||||
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
@ -67,8 +68,8 @@ public final class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
private final Set<Permission> nonOpSet = new DefaultPermissionSet(false);
|
||||
|
||||
// fully resolved defaults (accounts for child permissions too)
|
||||
private Map<String, Boolean> resolvedOpDefaults = ImmutableMap.of();
|
||||
private Map<String, Boolean> resolvedNonOpDefaults = ImmutableMap.of();
|
||||
private DefaultsCache opCache = new DefaultsCache(true);
|
||||
private DefaultsCache nonOpCache = new DefaultsCache(false);
|
||||
|
||||
// #values and #entrySet results - both immutable
|
||||
private final Collection<Set<Permission>> values = ImmutableList.of(this.opSet, this.nonOpSet);
|
||||
@ -81,16 +82,20 @@ public final class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
this.plugin = plugin;
|
||||
this.opSet.addAll(existingData.getOrDefault(Boolean.TRUE, Collections.emptySet()));
|
||||
this.nonOpSet.addAll(existingData.getOrDefault(Boolean.FALSE, Collections.emptySet()));
|
||||
refreshOp();
|
||||
refreshNonOp();
|
||||
}
|
||||
|
||||
public Set<Permission> getOpPermissions() {
|
||||
return this.opSet;
|
||||
@Override
|
||||
public Set<Permission> get(Object key) {
|
||||
boolean b = (boolean) key;
|
||||
return b ? this.opSet : this.nonOpSet;
|
||||
}
|
||||
|
||||
public Set<Permission> getNonOpPermissions() {
|
||||
return this.nonOpSet;
|
||||
private DefaultsCache getCache(boolean op) {
|
||||
return op ? this.opCache : this.nonOpCache;
|
||||
}
|
||||
|
||||
private void invalidate(boolean op) {
|
||||
getCache(op).invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,54 +106,10 @@ public final class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
* @return a tristate result
|
||||
*/
|
||||
public Tristate lookupDefaultPermission(String permission, boolean isOp) {
|
||||
Map<String, Boolean> map = isOp ? this.resolvedOpDefaults : this.resolvedNonOpDefaults;
|
||||
Map<String, Boolean> map = getCache(isOp).get();
|
||||
return Tristate.fromNullableBoolean(map.get(permission));
|
||||
}
|
||||
|
||||
private void refresh(boolean op) {
|
||||
if (op) {
|
||||
refreshOp();
|
||||
} else {
|
||||
refreshNonOp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the op data in this provider.
|
||||
*/
|
||||
private void refreshOp() {
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
for (Permission perm : getOpPermissions()) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
builder.put(name, true);
|
||||
for (Map.Entry<String, Boolean> child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
builder.putIfAbsent(child.getKey(), child.getValue());
|
||||
}
|
||||
}
|
||||
this.resolvedOpDefaults = ImmutableMap.copyOf(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the non op data in this provider.
|
||||
*/
|
||||
private void refreshNonOp() {
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
for (Permission perm : getNonOpPermissions()) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
builder.put(name, true);
|
||||
for (Map.Entry<String, Boolean> child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
builder.putIfAbsent(child.getKey(), child.getValue());
|
||||
}
|
||||
}
|
||||
this.resolvedNonOpDefaults = ImmutableMap.copyOf(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Permission> get(Object key) {
|
||||
boolean b = (boolean) key;
|
||||
return b ? this.opSet : this.nonOpSet;
|
||||
}
|
||||
|
||||
// return wrappers around this map impl
|
||||
@Nonnull @Override public Collection<Set<Permission>> values() { return this.values; }
|
||||
@Nonnull @Override public Set<Entry<Boolean, Set<Permission>>> entrySet() { return this.entrySet; }
|
||||
@ -166,11 +127,33 @@ public final class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
@Override public void putAll(@Nonnull Map<? extends Boolean, ? extends Set<Permission>> m) { throw new UnsupportedOperationException(); }
|
||||
@Override public void clear() { throw new UnsupportedOperationException(); }
|
||||
|
||||
private final class DefaultsCache extends Cache<Map<String, Boolean>> {
|
||||
private final boolean op;
|
||||
|
||||
DefaultsCache(boolean op) {
|
||||
this.op = op;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected Map<String, Boolean> supply() {
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
for (Permission perm : LPDefaultsMap.this.get(this.op)) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
builder.put(name, true);
|
||||
for (Map.Entry<String, Boolean> child : LPDefaultsMap.this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
builder.putIfAbsent(child.getKey(), child.getValue());
|
||||
}
|
||||
}
|
||||
return ImmutableMap.copyOf(builder);
|
||||
}
|
||||
}
|
||||
|
||||
private final class DefaultPermissionSet extends ForwardingSet<Permission> {
|
||||
private final Set<Permission> delegate = ConcurrentHashMap.newKeySet();
|
||||
private final boolean op;
|
||||
|
||||
private DefaultPermissionSet(boolean op) {
|
||||
DefaultPermissionSet(boolean op) {
|
||||
this.op = op;
|
||||
}
|
||||
|
||||
@ -182,14 +165,14 @@ public final class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
@Override
|
||||
public boolean add(@Nonnull Permission element) {
|
||||
boolean ret = super.add(element);
|
||||
refresh(this.op);
|
||||
invalidate(this.op);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(@Nonnull Collection<? extends Permission> collection) {
|
||||
boolean ret = super.addAll(collection);
|
||||
refresh(this.op);
|
||||
invalidate(this.op);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -25,104 +25,56 @@
|
||||
|
||||
package me.lucko.luckperms.bungee;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerTask;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.utils.Iterators;
|
||||
|
||||
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
||||
import net.md_5.bungee.api.scheduler.TaskScheduler;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BungeeSchedulerAdapter implements SchedulerAdapter {
|
||||
|
||||
// the number of ticks which occur in a second - this is a server implementation detail
|
||||
public static final int TICKS_PER_SECOND = 20;
|
||||
// the number of milliseconds in a second - constant
|
||||
public static final int MILLISECONDS_PER_SECOND = 1000;
|
||||
// the number of milliseconds in a tick - assuming the server runs at a perfect tick rate
|
||||
public static final int MILLISECONDS_PER_TICK = MILLISECONDS_PER_SECOND / TICKS_PER_SECOND;
|
||||
|
||||
private static long ticksToMillis(long ticks) {
|
||||
return ticks * MILLISECONDS_PER_TICK;
|
||||
}
|
||||
|
||||
private final LPBungeeBootstrap bootstrap;
|
||||
|
||||
private final Executor asyncExecutor;
|
||||
private final Set<SchedulerTask> tasks = ConcurrentHashMap.newKeySet();
|
||||
private final Executor executor;
|
||||
private final Set<ScheduledTask> tasks = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
|
||||
public BungeeSchedulerAdapter(LPBungeeBootstrap bootstrap) {
|
||||
this.bootstrap = bootstrap;
|
||||
this.asyncExecutor = r -> bootstrap.getProxy().getScheduler().runAsync(bootstrap, r);
|
||||
}
|
||||
|
||||
private TaskScheduler scheduler() {
|
||||
return this.bootstrap.getProxy().getScheduler();
|
||||
this.executor = r -> bootstrap.getProxy().getScheduler().runAsync(bootstrap, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor async() {
|
||||
return this.asyncExecutor;
|
||||
return this.executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor sync() {
|
||||
return this.asyncExecutor;
|
||||
return this.executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAsync(Runnable runnable) {
|
||||
this.asyncExecutor.execute(runnable);
|
||||
public SchedulerTask asyncLater(Runnable task, long delay, TimeUnit unit) {
|
||||
ScheduledTask t = this.bootstrap.getProxy().getScheduler().schedule(this.bootstrap, task, delay, unit);
|
||||
this.tasks.add(t);
|
||||
return t::cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSync(Runnable runnable) {
|
||||
doAsync(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks) {
|
||||
long millis = ticksToMillis(intervalTicks);
|
||||
SchedulerTask task = new BungeeSchedulerTask(scheduler().schedule(this.bootstrap, runnable, millis, millis, TimeUnit.MILLISECONDS));
|
||||
this.tasks.add(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask syncRepeating(Runnable runnable, long intervalTicks) {
|
||||
return asyncRepeating(runnable, intervalTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncLater(Runnable runnable, long delayTicks) {
|
||||
return new BungeeSchedulerTask(scheduler().schedule(this.bootstrap, runnable, ticksToMillis(delayTicks), TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask syncLater(Runnable runnable, long delayTicks) {
|
||||
return asyncLater(runnable, delayTicks);
|
||||
public SchedulerTask asyncRepeating(Runnable task, long interval, TimeUnit unit) {
|
||||
ScheduledTask t = this.bootstrap.getProxy().getScheduler().schedule(this.bootstrap, task, interval, interval, unit);
|
||||
this.tasks.add(t);
|
||||
return t::cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
Iterators.iterate(this.tasks, SchedulerTask::cancel);
|
||||
}
|
||||
|
||||
private static final class BungeeSchedulerTask implements SchedulerTask {
|
||||
private final ScheduledTask task;
|
||||
|
||||
private BungeeSchedulerTask(ScheduledTask task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.task.cancel();
|
||||
}
|
||||
Iterators.iterate(this.tasks, ScheduledTask::cancel);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ import me.lucko.luckperms.api.platform.PlatformType;
|
||||
import me.lucko.luckperms.bungee.util.RedisBungeeUtil;
|
||||
import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader;
|
||||
import me.lucko.luckperms.common.dependencies.classloader.ReflectionClassLoader;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
|
@ -35,7 +35,7 @@ import me.lucko.luckperms.bungee.listeners.BungeeConnectionListener;
|
||||
import me.lucko.luckperms.bungee.listeners.BungeePermissionCheckListener;
|
||||
import me.lucko.luckperms.bungee.messaging.BungeeMessagingFactory;
|
||||
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
|
||||
import me.lucko.luckperms.common.calculators.PlatformCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.command.CommandManager;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
import me.lucko.luckperms.common.contexts.ContextManager;
|
||||
@ -61,6 +61,7 @@ import java.nio.file.Files;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@ -130,7 +131,7 @@ public class LPBungeePlugin extends AbstractLuckPermsPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PlatformCalculatorFactory provideCalculatorFactory() {
|
||||
protected CalculatorFactory provideCalculatorFactory() {
|
||||
return new BungeeCalculatorFactory(this);
|
||||
}
|
||||
|
||||
@ -161,8 +162,8 @@ public class LPBungeePlugin extends AbstractLuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
protected void registerHousekeepingTasks() {
|
||||
this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 60L);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2400L);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 3, TimeUnit.SECONDS);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,7 +29,7 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
@ -38,7 +38,7 @@ import me.lucko.luckperms.common.processors.PermissionProcessor;
|
||||
import me.lucko.luckperms.common.processors.RegexProcessor;
|
||||
import me.lucko.luckperms.common.processors.WildcardProcessor;
|
||||
|
||||
public class BungeeCalculatorFactory extends AbstractCalculatorFactory {
|
||||
public class BungeeCalculatorFactory implements CalculatorFactory {
|
||||
private final LPBungeePlugin plugin;
|
||||
|
||||
public BungeeCalculatorFactory(LPBungeePlugin plugin) {
|
||||
@ -59,6 +59,6 @@ public class BungeeCalculatorFactory extends AbstractCalculatorFactory {
|
||||
processors.add(new WildcardProcessor());
|
||||
}
|
||||
|
||||
return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build()));
|
||||
return new PermissionCalculator(this.plugin, metadata, processors.build());
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ public class BungeeConnectionListener extends AbstractConnectionListener impleme
|
||||
this.plugin.getLogger().info("Processing pre-login for " + c.getUniqueId() + " - " + c.getName());
|
||||
}
|
||||
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
recordConnection(c.getUniqueId());
|
||||
|
||||
/* Actually process the login for the connection.
|
||||
@ -139,7 +139,7 @@ public class BungeeConnectionListener extends AbstractConnectionListener impleme
|
||||
this.plugin.getUserManager().getHouseKeeper().registerUsage(player.getUniqueId());
|
||||
|
||||
// force a clear of transient nodes
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId());
|
||||
if (user != null) {
|
||||
user.clearTransientNodes();
|
||||
|
@ -97,7 +97,7 @@ public class BungeeMessenger implements Messenger, Listener {
|
||||
|
||||
if (this.consumer.consumeIncomingMessageAsString(msg)) {
|
||||
// Forward to other servers
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
for (ServerInfo server : this.plugin.getBootstrap().getProxy().getServers().values()) {
|
||||
server.sendData(CHANNEL, data, true);
|
||||
}
|
||||
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.calculators;
|
||||
|
||||
import com.google.common.collect.MapMaker;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class AbstractCalculatorFactory implements PlatformCalculatorFactory {
|
||||
private final Set<PermissionCalculator> calculators = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
|
||||
|
||||
protected PermissionCalculator registerCalculator(PermissionCalculator calculator) {
|
||||
this.calculators.add(calculator);
|
||||
return calculator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateAll() {
|
||||
for (PermissionCalculator calculator : this.calculators) {
|
||||
calculator.invalidateCache();
|
||||
}
|
||||
}
|
||||
}
|
@ -44,7 +44,6 @@ import me.lucko.luckperms.common.node.comparator.NodeWithContextComparator;
|
||||
import me.lucko.luckperms.common.node.factory.NodeFactory;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.utils.CollationKeyCache;
|
||||
import me.lucko.luckperms.common.utils.DurationFormatter;
|
||||
import me.lucko.luckperms.common.utils.Iterators;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
@ -126,7 +125,7 @@ public class ParentInfo extends SharedSubCommand {
|
||||
}
|
||||
|
||||
private static final Comparator<LocalizedNode> ALPHABETICAL_NODE_COMPARATOR = (o1, o2) -> {
|
||||
int i = CollationKeyCache.compareStrings(o1.getGroupName(), o2.getGroupName());
|
||||
int i = o1.getGroupName().compareTo(o2.getGroupName());
|
||||
if (i != 0) {
|
||||
return i;
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ import me.lucko.luckperms.common.node.comparator.NodeWithContextComparator;
|
||||
import me.lucko.luckperms.common.node.factory.NodeFactory;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.utils.CollationKeyCache;
|
||||
import me.lucko.luckperms.common.utils.DurationFormatter;
|
||||
import me.lucko.luckperms.common.utils.Iterators;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
@ -129,7 +128,7 @@ public class PermissionInfo extends SharedSubCommand {
|
||||
}
|
||||
|
||||
private static final Comparator<LocalizedNode> ALPHABETICAL_NODE_COMPARATOR = (o1, o2) -> {
|
||||
int i = CollationKeyCache.compareStrings(o1.getPermission(), o2.getPermission());
|
||||
int i = o1.getPermission().compareTo(o2.getPermission());
|
||||
if (i != 0) {
|
||||
return i;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
package me.lucko.luckperms.common.commands.log;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.command.CommandResult;
|
||||
import me.lucko.luckperms.common.command.abstraction.SubCommand;
|
||||
@ -54,7 +55,7 @@ public class LogNotify extends SubCommand<Log> {
|
||||
return false;
|
||||
}
|
||||
|
||||
Optional<? extends Node> ret = user.getOwnNodes().stream()
|
||||
Optional<? extends Node> ret = user.enduringData().immutable().get(ContextSet.empty()).stream()
|
||||
.filter(n -> n.getPermission().equalsIgnoreCase("luckperms.log.notify.ignoring"))
|
||||
.findFirst();
|
||||
|
||||
@ -74,7 +75,7 @@ public class LogNotify extends SubCommand<Log> {
|
||||
user.setPermission(NodeFactory.make("luckperms.log.notify.ignoring"));
|
||||
} else {
|
||||
// remove the perm
|
||||
user.removeIf(n -> n.getPermission().equalsIgnoreCase("luckperms.log.notify.ignoring"));
|
||||
user.removeIf(ContextSet.empty(), n -> n.getPermission().equalsIgnoreCase("luckperms.log.notify.ignoring"));
|
||||
}
|
||||
|
||||
plugin.getStorage().saveUser(user).join();
|
||||
|
@ -85,7 +85,7 @@ public class ExportCommand extends SingleCommand {
|
||||
Exporter exporter = new Exporter(plugin, sender, path, includeUsers);
|
||||
|
||||
// Run the exporter in its own thread.
|
||||
plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
try {
|
||||
exporter.run();
|
||||
} finally {
|
||||
|
@ -86,7 +86,7 @@ public class ImportCommand extends SingleCommand {
|
||||
Importer importer = new Importer(plugin.getCommandManager(), sender, commands);
|
||||
|
||||
// Run the importer in its own thread.
|
||||
plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
try {
|
||||
importer.run();
|
||||
} finally {
|
||||
|
@ -25,34 +25,31 @@
|
||||
|
||||
package me.lucko.luckperms.common.config;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
|
||||
import me.lucko.luckperms.common.api.delegates.misc.ApiConfiguration;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
import me.lucko.luckperms.common.config.keys.EnduringKey;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An abstract implementation of {@link LuckPermsConfiguration}, backed by a cache.
|
||||
* An abstract implementation of {@link LuckPermsConfiguration}.
|
||||
*
|
||||
* <p>Values are loaded into memory on init.</p>
|
||||
*/
|
||||
public class AbstractConfiguration implements LuckPermsConfiguration, CacheLoader<ConfigKey<?>, Optional<Object>> {
|
||||
public class AbstractConfiguration implements LuckPermsConfiguration {
|
||||
|
||||
// the loading cache for config keys --> their value
|
||||
// the value is wrapped in an optional as null values don't get cached.
|
||||
private final LoadingCache<ConfigKey<?>, Optional<Object>> cache = Caffeine.newBuilder().build(this);
|
||||
/**
|
||||
* The configurations loaded values.
|
||||
*
|
||||
* <p>The value corresponding to each key is stored at the index defined
|
||||
* by {@link ConfigKey#ordinal()}.</p>
|
||||
*/
|
||||
private Object[] values = null;
|
||||
|
||||
// the plugin instance
|
||||
private final LuckPermsPlugin plugin;
|
||||
// the adapter used to read values
|
||||
private final ConfigurationAdapter adapter;
|
||||
|
||||
// the api delegate
|
||||
private final ApiConfiguration delegate = new ApiConfiguration(this);
|
||||
// the contextsfile handler
|
||||
@ -61,6 +58,52 @@ public class AbstractConfiguration implements LuckPermsConfiguration, CacheLoade
|
||||
public AbstractConfiguration(LuckPermsPlugin plugin, ConfigurationAdapter adapter) {
|
||||
this.plugin = plugin;
|
||||
this.adapter = adapter;
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T get(ConfigKey<T> key) {
|
||||
return (T) this.values[key.ordinal()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void load() {
|
||||
// get the map of all keys
|
||||
Map<String, ConfigKey<?>> keys = ConfigKeys.getAllKeys();
|
||||
|
||||
// if this is a reload operation
|
||||
boolean reload = true;
|
||||
|
||||
// if values are null, must be loading for the first time
|
||||
if (this.values == null) {
|
||||
this.values = new Object[keys.size()];
|
||||
reload = false;
|
||||
}
|
||||
|
||||
// load a value for each key.
|
||||
for (ConfigKey<?> key : keys.values()) {
|
||||
// don't reload enduring keys.
|
||||
if (reload && key instanceof EnduringKey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// load the value for the key
|
||||
Object value = key.get(this.adapter);
|
||||
this.values[key.ordinal()] = value;
|
||||
}
|
||||
|
||||
// load the contexts file
|
||||
this.contextsFile.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
this.adapter.reload();
|
||||
load();
|
||||
|
||||
getPlugin().getEventFactory().handleConfigReload();
|
||||
}
|
||||
|
||||
public ConfigurationAdapter getAdapter() {
|
||||
@ -81,36 +124,4 @@ public class AbstractConfiguration implements LuckPermsConfiguration, CacheLoade
|
||||
public ContextsFile getContextsFile() {
|
||||
return this.contextsFile;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T get(ConfigKey<T> key) {
|
||||
Optional<Object> ret = this.cache.get(key);
|
||||
if (ret == null) {
|
||||
return null;
|
||||
}
|
||||
return (T) ret.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAll() {
|
||||
ConfigKeys.getAllKeys().values().forEach(this.cache::get);
|
||||
this.contextsFile.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
this.adapter.reload();
|
||||
|
||||
Set<ConfigKey<?>> toInvalidate = this.cache.asMap().keySet().stream().filter(k -> !(k instanceof EnduringKey)).collect(Collectors.toSet());
|
||||
this.cache.invalidateAll(toInvalidate);
|
||||
|
||||
loadAll();
|
||||
getPlugin().getEventFactory().handleConfigReload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Object> load(@Nonnull ConfigKey<?> key) {
|
||||
return Optional.ofNullable(key.get(this.adapter));
|
||||
}
|
||||
}
|
||||
|
@ -23,17 +23,17 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.calculators;
|
||||
package me.lucko.luckperms.common.config;
|
||||
|
||||
/**
|
||||
* Extension of {@link CalculatorFactory} which keeps a record of produced
|
||||
* calculators and provides a means to invalidate them all in bulk.
|
||||
*/
|
||||
public interface PlatformCalculatorFactory extends CalculatorFactory {
|
||||
public abstract class BaseConfigKey<T> implements ConfigKey<T> {
|
||||
int ordinal = -1;
|
||||
|
||||
/**
|
||||
* Invalidates all calculators build by this factory
|
||||
*/
|
||||
void invalidateAll();
|
||||
protected BaseConfigKey() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int ordinal() {
|
||||
return this.ordinal;
|
||||
}
|
||||
}
|
@ -34,6 +34,16 @@ import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
*/
|
||||
public interface ConfigKey<T> {
|
||||
|
||||
/**
|
||||
* Gets the position of this key within the {@link ConfigKeys} enum.
|
||||
*
|
||||
* <p>This is lazily set when the configuration is loaded for the first time, during the
|
||||
* execution of {@link ConfigKeys#getAllKeys()}.</p>
|
||||
*
|
||||
* @return the position
|
||||
*/
|
||||
int ordinal();
|
||||
|
||||
/**
|
||||
* Resolves and returns the value mapped to this key using the given config instance.
|
||||
*
|
||||
|
@ -33,8 +33,8 @@ import me.lucko.luckperms.api.LookupSetting;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import me.lucko.luckperms.common.assignments.AssignmentRule;
|
||||
import me.lucko.luckperms.common.config.keys.AbstractKey;
|
||||
import me.lucko.luckperms.common.config.keys.BooleanKey;
|
||||
import me.lucko.luckperms.common.config.keys.CustomKey;
|
||||
import me.lucko.luckperms.common.config.keys.EnduringKey;
|
||||
import me.lucko.luckperms.common.config.keys.LowercaseStringKey;
|
||||
import me.lucko.luckperms.common.config.keys.MapKey;
|
||||
@ -64,13 +64,16 @@ import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* All of the {@link ConfigKey}s used by LuckPerms.
|
||||
*
|
||||
* <p>The {@link #getAllKeys()} method and associated behaviour allows this class to behave
|
||||
* a bit like an enum with generics.</p>
|
||||
*/
|
||||
public class ConfigKeys {
|
||||
public final class ConfigKeys {
|
||||
|
||||
/**
|
||||
* The name of the server
|
||||
*/
|
||||
public static final ConfigKey<String> SERVER = AbstractKey.of(c -> {
|
||||
public static final ConfigKey<String> SERVER = CustomKey.of(c -> {
|
||||
if (c.getBoolean("use-server-properties-name", false)) {
|
||||
String serverName = c.getPlugin().getBootstrap().getServerName();
|
||||
if (serverName != null && !serverName.equals("Unknown Server")) {
|
||||
@ -84,7 +87,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* How many minutes to wait between syncs. A value <= 0 will disable syncing.
|
||||
*/
|
||||
public static final ConfigKey<Integer> SYNC_TIME = EnduringKey.wrap(AbstractKey.of(c -> {
|
||||
public static final ConfigKey<Integer> SYNC_TIME = EnduringKey.wrap(CustomKey.of(c -> {
|
||||
int val = c.getInt("sync-minutes", -1);
|
||||
if (val == -1) {
|
||||
val = c.getInt("data.sync-minutes", -1);
|
||||
@ -95,7 +98,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* The lookup settings for contexts (care should be taken to not mutate this method)
|
||||
*/
|
||||
public static final ConfigKey<EnumSet<LookupSetting>> LOOKUP_SETTINGS = AbstractKey.of(c -> {
|
||||
public static final ConfigKey<EnumSet<LookupSetting>> LOOKUP_SETTINGS = CustomKey.of(c -> {
|
||||
return EnumSet.copyOf(Contexts.of(
|
||||
ContextSet.empty(),
|
||||
c.getBoolean("include-global", true),
|
||||
@ -130,7 +133,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* Controls how temporary add commands should behave
|
||||
*/
|
||||
public static final ConfigKey<TemporaryModifier> TEMPORARY_ADD_BEHAVIOUR = AbstractKey.of(c -> {
|
||||
public static final ConfigKey<TemporaryModifier> TEMPORARY_ADD_BEHAVIOUR = CustomKey.of(c -> {
|
||||
String option = c.getString("temporary-add-behaviour", "deny").toLowerCase();
|
||||
if (!option.equals("deny") && !option.equals("replace") && !option.equals("accumulate")) {
|
||||
option = "deny";
|
||||
@ -142,7 +145,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* How primary groups should be calculated.
|
||||
*/
|
||||
public static final ConfigKey<String> PRIMARY_GROUP_CALCULATION_METHOD = EnduringKey.wrap(AbstractKey.of(c -> {
|
||||
public static final ConfigKey<String> PRIMARY_GROUP_CALCULATION_METHOD = EnduringKey.wrap(CustomKey.of(c -> {
|
||||
String option = c.getString("primary-group-calculation", "stored").toLowerCase();
|
||||
if (!option.equals("stored") && !option.equals("parents-by-weight") && !option.equals("all-parents-by-weight")) {
|
||||
option = "stored";
|
||||
@ -154,7 +157,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* A function to create primary group holder instances based upon the {@link #PRIMARY_GROUP_CALCULATION_METHOD} setting.
|
||||
*/
|
||||
public static final ConfigKey<Function<User, PrimaryGroupHolder>> PRIMARY_GROUP_CALCULATION = EnduringKey.wrap(AbstractKey.of(c -> {
|
||||
public static final ConfigKey<Function<User, PrimaryGroupHolder>> PRIMARY_GROUP_CALCULATION = EnduringKey.wrap(CustomKey.of(c -> {
|
||||
String option = PRIMARY_GROUP_CALCULATION_METHOD.get(c);
|
||||
switch (option) {
|
||||
case "stored":
|
||||
@ -245,7 +248,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* The algorithm LuckPerms should use when traversing the "inheritance tree"
|
||||
*/
|
||||
public static final ConfigKey<TraversalAlgorithm> INHERITANCE_TRAVERSAL_ALGORITHM = AbstractKey.of(c -> {
|
||||
public static final ConfigKey<TraversalAlgorithm> INHERITANCE_TRAVERSAL_ALGORITHM = CustomKey.of(c -> {
|
||||
String value = c.getString("inheritance-traversal-algorithm", "depth-first-pre-order");
|
||||
switch (value.toLowerCase()) {
|
||||
case "breadth-first":
|
||||
@ -260,7 +263,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* The configured group weightings
|
||||
*/
|
||||
public static final ConfigKey<Map<String, Integer>> GROUP_WEIGHTS = AbstractKey.of(c -> {
|
||||
public static final ConfigKey<Map<String, Integer>> GROUP_WEIGHTS = CustomKey.of(c -> {
|
||||
return c.getMap("group-weight", ImmutableMap.of()).entrySet().stream().collect(ImmutableCollectors.toMap(
|
||||
e -> e.getKey().toLowerCase(),
|
||||
e -> {
|
||||
@ -276,7 +279,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* Creates a new prefix MetaStack element based upon the configured values.
|
||||
*/
|
||||
public static final ConfigKey<MetaStackDefinition> PREFIX_FORMATTING_OPTIONS = AbstractKey.of(l -> {
|
||||
public static final ConfigKey<MetaStackDefinition> PREFIX_FORMATTING_OPTIONS = CustomKey.of(l -> {
|
||||
List<String> format = l.getList("meta-formatting.prefix.format", new ArrayList<>());
|
||||
if (format.isEmpty()) {
|
||||
format.add("highest");
|
||||
@ -291,7 +294,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* Creates a new suffix MetaStack element based upon the configured values.
|
||||
*/
|
||||
public static final ConfigKey<MetaStackDefinition> SUFFIX_FORMATTING_OPTIONS = AbstractKey.of(l -> {
|
||||
public static final ConfigKey<MetaStackDefinition> SUFFIX_FORMATTING_OPTIONS = CustomKey.of(l -> {
|
||||
List<String> format = l.getList("meta-formatting.suffix.format", new ArrayList<>());
|
||||
if (format.isEmpty()) {
|
||||
format.add("highest");
|
||||
@ -316,7 +319,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* If server operators should be enabled. Only used by the Bukkit platform.
|
||||
*/
|
||||
public static final ConfigKey<Boolean> OPS_ENABLED = EnduringKey.wrap(AbstractKey.of(c -> !AUTO_OP.get(c) && c.getBoolean("enable-ops", true)));
|
||||
public static final ConfigKey<Boolean> OPS_ENABLED = EnduringKey.wrap(CustomKey.of(c -> !AUTO_OP.get(c) && c.getBoolean("enable-ops", true)));
|
||||
|
||||
/**
|
||||
* If server operators should be able to use LuckPerms commands by default. Only used by the Bukkit platform.
|
||||
@ -331,7 +334,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* The name of the server to use for Vault.
|
||||
*/
|
||||
public static final ConfigKey<String> VAULT_SERVER = AbstractKey.of(c -> {
|
||||
public static final ConfigKey<String> VAULT_SERVER = CustomKey.of(c -> {
|
||||
// default to true for backwards compatibility
|
||||
if (USE_VAULT_SERVER.get(c)) {
|
||||
return c.getString("vault-server", "global").toLowerCase();
|
||||
@ -358,7 +361,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* The world rewrites map
|
||||
*/
|
||||
public static final ConfigKey<Map<String, String>> WORLD_REWRITES = AbstractKey.of(c -> {
|
||||
public static final ConfigKey<Map<String, String>> WORLD_REWRITES = CustomKey.of(c -> {
|
||||
return c.getMap("world-rewrite", ImmutableMap.of()).entrySet().stream()
|
||||
.collect(ImmutableCollectors.toMap(
|
||||
e -> e.getKey().toLowerCase(),
|
||||
@ -374,7 +377,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* The default assignments being applied by the plugin
|
||||
*/
|
||||
public static final ConfigKey<List<AssignmentRule>> DEFAULT_ASSIGNMENTS = AbstractKey.of(c -> {
|
||||
public static final ConfigKey<List<AssignmentRule>> DEFAULT_ASSIGNMENTS = CustomKey.of(c -> {
|
||||
return c.getObjectList("default-assignments", ImmutableList.of()).stream().map(name -> {
|
||||
String hasTrue = c.getString("default-assignments." + name + ".if.has-true", null);
|
||||
String hasFalse = c.getString("default-assignments." + name + ".if.has-false", null);
|
||||
@ -389,7 +392,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* The database settings, username, password, etc for use by any database
|
||||
*/
|
||||
public static final ConfigKey<StorageCredentials> DATABASE_VALUES = EnduringKey.wrap(AbstractKey.of(c -> {
|
||||
public static final ConfigKey<StorageCredentials> DATABASE_VALUES = EnduringKey.wrap(CustomKey.of(c -> {
|
||||
int maxPoolSize = c.getInt("data.pool-settings.maximum-pool-size", c.getInt("data.pool-size", 10));
|
||||
int minIdle = c.getInt("data.pool-settings.minimum-idle", maxPoolSize);
|
||||
int maxLifetime = c.getInt("data.pool-settings.maximum-lifetime", 1800000);
|
||||
@ -438,7 +441,7 @@ public class ConfigKeys {
|
||||
/**
|
||||
* The options for split storage
|
||||
*/
|
||||
public static final ConfigKey<Map<SplitStorageType, String>> SPLIT_STORAGE_OPTIONS = EnduringKey.wrap(AbstractKey.of(c -> {
|
||||
public static final ConfigKey<Map<SplitStorageType, String>> SPLIT_STORAGE_OPTIONS = EnduringKey.wrap(CustomKey.of(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());
|
||||
@ -511,15 +514,25 @@ public class ConfigKeys {
|
||||
|
||||
try {
|
||||
Field[] values = ConfigKeys.class.getFields();
|
||||
int counter = 0;
|
||||
|
||||
for (Field f : values) {
|
||||
// ignore non-static fields
|
||||
if (!Modifier.isStatic(f.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object val = f.get(null);
|
||||
if (val instanceof ConfigKey<?>) {
|
||||
keys.put(f.getName(), (ConfigKey<?>) val);
|
||||
// ignore fields that aren't configkeys
|
||||
if (!ConfigKey.class.equals(f.getType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the key instance
|
||||
BaseConfigKey<?> key = (BaseConfigKey<?>) f.get(null);
|
||||
// set the ordinal value of the key.
|
||||
key.ordinal = counter++;
|
||||
// add the key to the return map
|
||||
keys.put(f.getName(), key);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -60,9 +60,9 @@ public interface LuckPermsConfiguration {
|
||||
void reload();
|
||||
|
||||
/**
|
||||
* Pre-loads all configuration keys into the cache.
|
||||
* Loads all configuration values.
|
||||
*/
|
||||
void loadAll();
|
||||
void load();
|
||||
|
||||
/**
|
||||
* Gets the value of a given context key.
|
||||
|
@ -25,10 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.common.config.keys;
|
||||
|
||||
import me.lucko.luckperms.common.config.ConfigKey;
|
||||
import me.lucko.luckperms.common.config.BaseConfigKey;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
|
||||
public class BooleanKey implements ConfigKey<Boolean> {
|
||||
public class BooleanKey extends BaseConfigKey<Boolean> {
|
||||
public static BooleanKey of(String path, boolean def) {
|
||||
return new BooleanKey(path, def);
|
||||
}
|
||||
|
@ -25,19 +25,19 @@
|
||||
|
||||
package me.lucko.luckperms.common.config.keys;
|
||||
|
||||
import me.lucko.luckperms.common.config.ConfigKey;
|
||||
import me.lucko.luckperms.common.config.BaseConfigKey;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class AbstractKey<T> implements ConfigKey<T> {
|
||||
public static <T> AbstractKey<T> of(Function<ConfigurationAdapter, T> function) {
|
||||
return new AbstractKey<>(function);
|
||||
public class CustomKey<T> extends BaseConfigKey<T> {
|
||||
public static <T> CustomKey<T> of(Function<ConfigurationAdapter, T> function) {
|
||||
return new CustomKey<>(function);
|
||||
}
|
||||
|
||||
private final Function<ConfigurationAdapter, T> function;
|
||||
|
||||
private AbstractKey(Function<ConfigurationAdapter, T> function) {
|
||||
private CustomKey(Function<ConfigurationAdapter, T> function) {
|
||||
this.function = function;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.common.config.keys;
|
||||
|
||||
import me.lucko.luckperms.common.config.BaseConfigKey;
|
||||
import me.lucko.luckperms.common.config.ConfigKey;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
|
||||
@ -32,7 +33,7 @@ import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
* Wrapper class to mark a config key as enduring (doesn't change in the event of a reload)
|
||||
* @param <T>
|
||||
*/
|
||||
public class EnduringKey<T> implements ConfigKey<T> {
|
||||
public class EnduringKey<T> extends BaseConfigKey<T> {
|
||||
|
||||
public static <T> EnduringKey<T> wrap(ConfigKey<T> delegate) {
|
||||
return new EnduringKey<>(delegate);
|
||||
|
@ -25,10 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.common.config.keys;
|
||||
|
||||
import me.lucko.luckperms.common.config.ConfigKey;
|
||||
import me.lucko.luckperms.common.config.BaseConfigKey;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
|
||||
public class IntegerKey implements ConfigKey<Integer> {
|
||||
public class IntegerKey extends BaseConfigKey<Integer> {
|
||||
public static IntegerKey of(String path, int def) {
|
||||
return new IntegerKey(path, def);
|
||||
}
|
||||
|
@ -25,10 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.common.config.keys;
|
||||
|
||||
import me.lucko.luckperms.common.config.ConfigKey;
|
||||
import me.lucko.luckperms.common.config.BaseConfigKey;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
|
||||
public class LowercaseStringKey implements ConfigKey<String> {
|
||||
public class LowercaseStringKey extends BaseConfigKey<String> {
|
||||
public static LowercaseStringKey of(String path, String def) {
|
||||
return new LowercaseStringKey(path, def);
|
||||
}
|
||||
|
@ -27,12 +27,12 @@ package me.lucko.luckperms.common.config.keys;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import me.lucko.luckperms.common.config.ConfigKey;
|
||||
import me.lucko.luckperms.common.config.BaseConfigKey;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class MapKey implements ConfigKey<Map<String, String>> {
|
||||
public class MapKey extends BaseConfigKey<Map<String, String>> {
|
||||
public static MapKey of(String path) {
|
||||
return new MapKey(path);
|
||||
}
|
||||
|
@ -25,10 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.common.config.keys;
|
||||
|
||||
import me.lucko.luckperms.common.config.ConfigKey;
|
||||
import me.lucko.luckperms.common.config.BaseConfigKey;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
|
||||
public class StringKey implements ConfigKey<String> {
|
||||
public class StringKey extends BaseConfigKey<String> {
|
||||
public static StringKey of(String path, String def) {
|
||||
return new StringKey(path, def);
|
||||
}
|
||||
|
@ -221,6 +221,6 @@ public abstract class AbstractEventBus<P> implements EventBus, AutoCloseable {
|
||||
if (event instanceof Cancellable) {
|
||||
throw new IllegalArgumentException("cannot call Cancellable event async");
|
||||
}
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> fireEvent(event));
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> fireEvent(event));
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,6 @@
|
||||
|
||||
package me.lucko.luckperms.common.inheritance;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.LookupSetting;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
@ -38,7 +35,6 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Provides {@link InheritanceGraph}s.
|
||||
@ -51,17 +47,15 @@ public class InheritanceHandler {
|
||||
*/
|
||||
private final InheritanceGraph nonContextualGraph;
|
||||
|
||||
/**
|
||||
* Cache of contextual inheritance graph instances
|
||||
*/
|
||||
private final LoadingCache<Contexts, InheritanceGraph> contextualGraphs;
|
||||
// some cached contextual graphs for common Contexts
|
||||
private final InheritanceGraph allowAllContextualGraph;
|
||||
private final InheritanceGraph globalContextualGraph;
|
||||
|
||||
public InheritanceHandler(LuckPermsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.nonContextualGraph = new NonContextualGraph(plugin);
|
||||
this.contextualGraphs = Caffeine.newBuilder()
|
||||
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||
.build(key -> new ContextualGraph(this.plugin, key));
|
||||
this.allowAllContextualGraph = new ContextualGraph(plugin, Contexts.allowAll());
|
||||
this.globalContextualGraph = new ContextualGraph(plugin, Contexts.global());
|
||||
}
|
||||
|
||||
public InheritanceGraph getGraph() {
|
||||
@ -69,7 +63,14 @@ public class InheritanceHandler {
|
||||
}
|
||||
|
||||
public InheritanceGraph getGraph(Contexts contexts) {
|
||||
return this.contextualGraphs.get(contexts);
|
||||
if (contexts == Contexts.allowAll()) {
|
||||
return this.allowAllContextualGraph;
|
||||
}
|
||||
if (contexts == Contexts.global()) {
|
||||
return this.globalContextualGraph;
|
||||
}
|
||||
|
||||
return new ContextualGraph(this.plugin, contexts);
|
||||
}
|
||||
|
||||
private static final class NonContextualGraph implements InheritanceGraph {
|
||||
|
@ -37,6 +37,7 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class AbstractUserManager<T extends User> extends AbstractManager<UserIdentifier, User, T> implements UserManager<T> {
|
||||
|
||||
@ -46,7 +47,7 @@ public abstract class AbstractUserManager<T extends User> extends AbstractManage
|
||||
public AbstractUserManager(LuckPermsPlugin plugin, UserHousekeeper.TimeoutSettings timeoutSettings) {
|
||||
this.plugin = plugin;
|
||||
this.housekeeper = new UserHousekeeper(plugin, this, timeoutSettings);
|
||||
this.plugin.getBootstrap().getScheduler().asyncRepeating(this.housekeeper, 200L); // every 10 seconds
|
||||
this.plugin.getBootstrap().getScheduler().asyncRepeating(this.housekeeper, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -102,7 +102,7 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco
|
||||
|
||||
@Override
|
||||
public void pushUpdate() {
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
UUID requestId = generatePingId();
|
||||
this.plugin.getLogger().info("[" + getName() + " Messaging] Sending ping with id: " + requestId);
|
||||
this.messenger.sendOutgoingMessage(new UpdateMessageImpl(requestId));
|
||||
@ -111,7 +111,7 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco
|
||||
|
||||
@Override
|
||||
public void pushUserUpdate(User user) {
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
UUID requestId = generatePingId();
|
||||
this.plugin.getLogger().info("[" + getName() + " Messaging] Sending user ping for '" + user.getFriendlyName() + "' with id: " + requestId);
|
||||
this.messenger.sendOutgoingMessage(new UserUpdateMessageImpl(requestId, user.getUuid()));
|
||||
@ -120,7 +120,7 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco
|
||||
|
||||
@Override
|
||||
public void pushLog(LogEntry logEntry) {
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
UUID requestId = generatePingId();
|
||||
|
||||
if (this.plugin.getEventFactory().handleLogNetworkPublish(!this.plugin.getConfiguration().get(ConfigKeys.PUSH_LOG_ENTRIES), requestId, logEntry)) {
|
||||
|
@ -65,7 +65,7 @@ public class RedisMessenger implements Messenger {
|
||||
this.jedisPool = new JedisPool(new JedisPoolConfig(), host, port, 0, password);
|
||||
}
|
||||
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
this.sub = new LPSub(this);
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.subscribe(this.sub, CHANNEL);
|
||||
|
@ -27,12 +27,13 @@ package me.lucko.luckperms.common.messaging.sql;
|
||||
|
||||
import me.lucko.luckperms.api.messenger.IncomingMessageConsumer;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerTask;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.storage.dao.sql.SqlDao;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class SqlMessenger extends AbstractSqlMessenger {
|
||||
private final LuckPermsPlugin plugin;
|
||||
@ -57,8 +58,8 @@ public class SqlMessenger extends AbstractSqlMessenger {
|
||||
|
||||
// schedule poll tasks
|
||||
SchedulerAdapter scheduler = this.plugin.getBootstrap().getScheduler();
|
||||
this.pollTask = scheduler.asyncRepeating(this::pollMessages, 20L);
|
||||
this.housekeepingTask = scheduler.asyncRepeating(this::runHousekeeping, 20L * 30);
|
||||
this.pollTask = scheduler.asyncRepeating(this::pollMessages, 1, TimeUnit.SECONDS);
|
||||
this.housekeepingTask = scheduler.asyncRepeating(this::runHousekeeping, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -26,7 +26,6 @@
|
||||
package me.lucko.luckperms.common.node.comparator;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.common.utils.CollationKeyCache;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
@ -65,6 +64,6 @@ public class NodeComparator implements Comparator<Node> {
|
||||
return o1.getWildcardLevel() > o2.getWildcardLevel() ? 1 : -1;
|
||||
}
|
||||
|
||||
return CollationKeyCache.compareStrings(o1.getPermission(), o2.getPermission()) == 1 ? -1 : 1;
|
||||
return o1.getPermission().compareTo(o2.getPermission()) > 0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
package me.lucko.luckperms.common.node.comparator;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.common.utils.CollationKeyCache;
|
||||
import me.lucko.luckperms.common.contexts.ContextSetComparator;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
@ -58,35 +58,16 @@ public class NodeWithContextComparator implements Comparator<Node> {
|
||||
return o1.isOverride() ? 1 : -1;
|
||||
}
|
||||
|
||||
if (o1.isServerSpecific() != o2.isServerSpecific()) {
|
||||
return o1.isServerSpecific() ? 1 : -1;
|
||||
int i = ContextSetComparator.normal().compare(
|
||||
o1.getFullContexts().makeImmutable(),
|
||||
o2.getFullContexts().makeImmutable()
|
||||
);
|
||||
|
||||
if (i != 0) {
|
||||
return i;
|
||||
}
|
||||
|
||||
if (o1.isWorldSpecific() != o2.isWorldSpecific()) {
|
||||
return o1.isWorldSpecific() ? 1 : -1;
|
||||
}
|
||||
|
||||
if (o1.getContexts().size() != o2.getContexts().size()) {
|
||||
return o1.getContexts().size() > o2.getContexts().size() ? 1 : -1;
|
||||
}
|
||||
|
||||
if (o1.isTemporary() != o2.isTemporary()) {
|
||||
return o1.isTemporary() ? 1 : -1;
|
||||
}
|
||||
|
||||
if (o1.isWildcard() != o2.isWildcard()) {
|
||||
return o1.isWildcard() ? 1 : -1;
|
||||
}
|
||||
|
||||
if (o1.isTemporary()) {
|
||||
return o1.getSecondsTilExpiry() < o2.getSecondsTilExpiry() ? 1 : -1;
|
||||
}
|
||||
|
||||
if (o1.isWildcard()) {
|
||||
return o1.getWildcardLevel() > o2.getWildcardLevel() ? 1 : -1;
|
||||
}
|
||||
|
||||
return CollationKeyCache.compareStrings(o1.getPermission(), o2.getPermission()) == 1 ? -1 : 1;
|
||||
return NodeComparator.normal().compare(o1, o2);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ import javax.annotation.Nonnull;
|
||||
|
||||
public abstract class ForwardingNode implements Node {
|
||||
|
||||
protected abstract Node delegate();
|
||||
public abstract Node delegate();
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
@ -52,7 +52,7 @@ public final class ImmutableLocalizedNode extends ForwardingNode implements Loca
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node delegate() {
|
||||
public Node delegate() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,6 @@ public final class ImmutableNode implements Node {
|
||||
|
||||
|
||||
// cached state
|
||||
|
||||
private final Optional<String> optServer;
|
||||
private final Optional<String> optWorld;
|
||||
|
||||
|
@ -48,7 +48,7 @@ public final class ImmutableTransientNode<O> extends ForwardingNode implements N
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node delegate() {
|
||||
public Node delegate() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ import me.lucko.luckperms.common.api.ApiRegistrationUtil;
|
||||
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
|
||||
import me.lucko.luckperms.common.buffers.BufferedRequest;
|
||||
import me.lucko.luckperms.common.buffers.UpdateTaskBuffer;
|
||||
import me.lucko.luckperms.common.calculators.PlatformCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.command.utils.MessageUtils;
|
||||
import me.lucko.luckperms.common.config.AbstractConfiguration;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
@ -61,6 +61,7 @@ import me.lucko.luckperms.common.verbose.VerboseHandler;
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
|
||||
@ -79,7 +80,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
private InternalMessagingService messagingService = null;
|
||||
private BufferedRequest<Void> updateTaskBuffer;
|
||||
private InheritanceHandler inheritanceHandler;
|
||||
private PlatformCalculatorFactory calculatorFactory;
|
||||
private CalculatorFactory calculatorFactory;
|
||||
private LuckPermsApiProvider apiProvider;
|
||||
private EventFactory eventFactory;
|
||||
|
||||
@ -101,14 +102,13 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
displayBanner(getConsoleSender());
|
||||
|
||||
// load some utilities early
|
||||
this.verboseHandler = new VerboseHandler();
|
||||
this.permissionRegistry = new PermissionRegistry();
|
||||
this.verboseHandler = new VerboseHandler(getBootstrap().getScheduler());
|
||||
this.permissionRegistry = new PermissionRegistry(getBootstrap().getScheduler());
|
||||
this.logDispatcher = new LogDispatcher(this);
|
||||
|
||||
// load configuration
|
||||
getLogger().info("Loading configuration...");
|
||||
this.configuration = new AbstractConfiguration(this, provideConfigurationAdapter());
|
||||
this.configuration.loadAll();
|
||||
|
||||
// load locale
|
||||
this.localeManager = new SimpleLocaleManager();
|
||||
@ -168,10 +168,9 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
// schedule update tasks
|
||||
int mins = getConfiguration().get(ConfigKeys.SYNC_TIME);
|
||||
if (mins > 0) {
|
||||
long ticks = mins * 60 * 20;
|
||||
getBootstrap().getScheduler().asyncRepeating(() -> this.updateTaskBuffer.request(), ticks);
|
||||
getBootstrap().getScheduler().asyncRepeating(() -> this.updateTaskBuffer.request(), mins, TimeUnit.MINUTES);
|
||||
}
|
||||
getBootstrap().getScheduler().asyncLater(() -> this.updateTaskBuffer.request(), 40L);
|
||||
getBootstrap().getScheduler().asyncLater(() -> this.updateTaskBuffer.request(), 2, TimeUnit.SECONDS);
|
||||
|
||||
// run an update instantly.
|
||||
getLogger().info("Performing initial data load...");
|
||||
@ -191,9 +190,6 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
}
|
||||
|
||||
public final void disable() {
|
||||
// perform initial disable tasks
|
||||
performEarlyDisableTasks();
|
||||
|
||||
// shutdown permission vault and verbose handler tasks
|
||||
this.permissionRegistry.stop();
|
||||
this.verboseHandler.stop();
|
||||
@ -233,7 +229,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
protected abstract MessagingFactory<?> provideMessagingFactory();
|
||||
protected abstract void registerCommands();
|
||||
protected abstract void setupManagers();
|
||||
protected abstract PlatformCalculatorFactory provideCalculatorFactory();
|
||||
protected abstract CalculatorFactory provideCalculatorFactory();
|
||||
protected abstract void setupContextManager();
|
||||
protected abstract void setupPlatformHooks();
|
||||
protected abstract AbstractEventBus provideEventBus(LuckPermsApiProvider apiProvider);
|
||||
@ -241,7 +237,6 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
protected abstract void registerHousekeepingTasks();
|
||||
protected abstract void performFinalSetup();
|
||||
|
||||
protected void performEarlyDisableTasks() {}
|
||||
protected void removePlatformHooks() {}
|
||||
|
||||
@Override
|
||||
@ -312,7 +307,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformCalculatorFactory getCalculatorFactory() {
|
||||
public CalculatorFactory getCalculatorFactory() {
|
||||
return this.calculatorFactory;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ package me.lucko.luckperms.common.plugin.bootstrap;
|
||||
|
||||
import me.lucko.luckperms.api.platform.PlatformType;
|
||||
import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.common.plugin.scheduler;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.SchedulerTask;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Abstract implementation of {@link SchedulerAdapter} using a {@link ScheduledExecutorService}.
|
||||
*/
|
||||
public abstract class AbstractJavaScheduler implements SchedulerAdapter {
|
||||
private final ScheduledExecutorService asyncExecutor = new AsyncExecutor();
|
||||
|
||||
@Override
|
||||
public Executor async() {
|
||||
return this.asyncExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncLater(Runnable task, long delay, TimeUnit unit) {
|
||||
ScheduledFuture<?> future = this.asyncExecutor.schedule(new WrappedRunnable(task), delay, unit);
|
||||
return () -> future.cancel(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncRepeating(Runnable task, long interval, TimeUnit unit) {
|
||||
ScheduledFuture<?> future = this.asyncExecutor.scheduleAtFixedRate(new WrappedRunnable(task), interval, interval, unit);
|
||||
return () -> future.cancel(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
this.asyncExecutor.shutdown();
|
||||
try {
|
||||
this.asyncExecutor.awaitTermination(1, TimeUnit.MINUTES);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class WrappedRunnable implements Runnable {
|
||||
private final Runnable delegate;
|
||||
|
||||
WrappedRunnable(Runnable delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
this.delegate.run();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class AsyncExecutor extends ScheduledThreadPoolExecutor {
|
||||
AsyncExecutor() {
|
||||
super(4, new ThreadFactoryBuilder().setNameFormat("luckperms-%d").build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
super.execute(new WrappedRunnable(command));
|
||||
}
|
||||
}
|
||||
}
|
@ -23,9 +23,12 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.plugin;
|
||||
package me.lucko.luckperms.common.plugin.scheduler;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.SchedulerTask;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A scheduler for running tasks using the systems provided by the platform
|
||||
@ -39,10 +42,6 @@ public interface SchedulerAdapter {
|
||||
*/
|
||||
Executor async();
|
||||
|
||||
default Executor platformAsync() {
|
||||
return async();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a sync executor instance
|
||||
*
|
||||
@ -51,46 +50,42 @@ public interface SchedulerAdapter {
|
||||
Executor sync();
|
||||
|
||||
/**
|
||||
* Executes a runnable async
|
||||
* Executes a task async
|
||||
*
|
||||
* @param runnable the runnable
|
||||
* @param task the task
|
||||
*/
|
||||
void doAsync(Runnable runnable);
|
||||
default void executeAsync(Runnable task) {
|
||||
async().execute(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a runnable sync
|
||||
* Executes a task sync
|
||||
*
|
||||
* @param runnable the runnable
|
||||
* @param task the task
|
||||
*/
|
||||
void doSync(Runnable runnable);
|
||||
default void executeSync(Runnable task) {
|
||||
sync().execute(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a runnable repeatedly until the plugin disables. Will wait for the interval before the first iteration of the task is ran.
|
||||
* @param runnable the runnable
|
||||
* @param intervalTicks the interval in ticks.
|
||||
* Executes the given task with a delay.
|
||||
*
|
||||
* @param task the task
|
||||
* @param delay the delay
|
||||
* @param unit the unit of delay
|
||||
* @return the resultant task instance
|
||||
*/
|
||||
SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks);
|
||||
SchedulerTask asyncLater(Runnable task, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Runs a runnable repeatedly until the plugin disables. Will wait for the interval before the first iteration of the task is ran.
|
||||
* @param runnable the runnable
|
||||
* @param intervalTicks the interval in ticks.
|
||||
* Executes the given task repeatedly at a given interval.
|
||||
*
|
||||
* @param task the task
|
||||
* @param interval the interval
|
||||
* @param unit the unit of interval
|
||||
* @return the resultant task instance
|
||||
*/
|
||||
SchedulerTask syncRepeating(Runnable runnable, long intervalTicks);
|
||||
|
||||
/**
|
||||
* Runs a runnable with a delay
|
||||
* @param runnable the runnable
|
||||
* @param delayTicks the delay in ticks
|
||||
*/
|
||||
SchedulerTask asyncLater(Runnable runnable, long delayTicks);
|
||||
|
||||
/**
|
||||
* Runs a runnable with a delay
|
||||
* @param runnable the runnable
|
||||
* @param delayTicks the delay in ticks
|
||||
*/
|
||||
SchedulerTask syncLater(Runnable runnable, long delayTicks);
|
||||
SchedulerTask asyncRepeating(Runnable task, long interval, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Shuts down this executor instance
|
@ -61,8 +61,8 @@ public class FileWatcher {
|
||||
this.basePath = basePath;
|
||||
this.watchService = basePath.getFileSystem().newWatchService();
|
||||
|
||||
plugin.getBootstrap().getScheduler().asyncLater(this::initLocations, 25L);
|
||||
plugin.getBootstrap().getScheduler().asyncRepeating(this::tick, 10L);
|
||||
plugin.getBootstrap().getScheduler().asyncLater(this::initLocations, 5, TimeUnit.SECONDS);
|
||||
plugin.getBootstrap().getScheduler().asyncRepeating(this::tick, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public WatchedLocation getWatcher(Path path) {
|
||||
|
@ -28,6 +28,7 @@ package me.lucko.luckperms.common.treeview;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.utils.RepeatingTask;
|
||||
|
||||
import java.util.Collection;
|
||||
@ -55,8 +56,8 @@ public class PermissionRegistry extends RepeatingTask {
|
||||
// a queue of permission strings to be processed by the tree
|
||||
private final Queue<String> queue;
|
||||
|
||||
public PermissionRegistry() {
|
||||
super(1000, TimeUnit.MILLISECONDS, "luckperms-permission-vault");
|
||||
public PermissionRegistry(SchedulerAdapter scheduler) {
|
||||
super(scheduler, 1, TimeUnit.SECONDS);
|
||||
this.rootNode = new TreeNode();
|
||||
this.knownPermissions = ConcurrentHashMap.newKeySet(3000);
|
||||
this.queue = new ConcurrentLinkedQueue<>();
|
||||
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.utils;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
|
||||
import java.text.CollationKey;
|
||||
import java.text.Collator;
|
||||
import java.util.Comparator;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class CollationKeyCache implements Comparator<String> {
|
||||
private static final CollationKeyCache INSTANCE = new CollationKeyCache();
|
||||
|
||||
private static final Collator COLLATOR;
|
||||
static {
|
||||
COLLATOR = Collator.getInstance(Locale.ENGLISH);
|
||||
COLLATOR.setStrength(Collator.IDENTICAL);
|
||||
COLLATOR.setDecomposition(Collator.FULL_DECOMPOSITION);
|
||||
}
|
||||
|
||||
private static final LoadingCache<String, CollationKey> CACHE = Caffeine.newBuilder()
|
||||
.maximumSize(5000)
|
||||
.expireAfterAccess(5, TimeUnit.MINUTES)
|
||||
.build(COLLATOR::getCollationKey);
|
||||
|
||||
public static Comparator<String> comparator() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private CollationKeyCache() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return compareStrings(o1, o2);
|
||||
}
|
||||
|
||||
public static int compareStrings(String o1, String o2) {
|
||||
//noinspection StringEquality
|
||||
if (o1 == o2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
CollationKey o1c = CACHE.get(o1);
|
||||
CollationKey o2c = CACHE.get(o2);
|
||||
|
||||
if (o1c != null && o2c != null) {
|
||||
int i = o1c.compareTo(o2c);
|
||||
if (i != 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignored
|
||||
}
|
||||
|
||||
// fallback to standard string comparison
|
||||
return o1.compareTo(o2);
|
||||
}
|
||||
}
|
@ -25,8 +25,8 @@
|
||||
|
||||
package me.lucko.luckperms.common.utils;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.google.common.collect.ForwardingSet;
|
||||
|
||||
import java.util.Collection;
|
||||
@ -36,22 +36,22 @@ import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* A bad expiring set implementation using Caffeine caches
|
||||
* A simple expiring set implementation using Caffeine caches
|
||||
*
|
||||
* @param <E> element type
|
||||
*/
|
||||
public class ExpiringSet<E> extends ForwardingSet<E> {
|
||||
private final LoadingCache<E, Boolean> cache;
|
||||
private final Cache<E, Boolean> cache;
|
||||
private final Set<E> setView;
|
||||
|
||||
public ExpiringSet(long duration, TimeUnit unit) {
|
||||
this.cache = Caffeine.newBuilder().expireAfterAccess(duration, unit).build(key -> Boolean.TRUE);
|
||||
this.cache = Caffeine.newBuilder().expireAfterAccess(duration, unit).build();
|
||||
this.setView = this.cache.asMap().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E element) {
|
||||
this.cache.get(element); // simply requesting the element from the cache is sufficient.
|
||||
this.cache.put(element, Boolean.TRUE);
|
||||
|
||||
// we don't care about the return value
|
||||
return true;
|
||||
|
@ -69,12 +69,12 @@ public final class PatternCache {
|
||||
private final Pattern instance;
|
||||
private final PatternSyntaxException ex;
|
||||
|
||||
public CachedPattern(Pattern instance) {
|
||||
CachedPattern(Pattern instance) {
|
||||
this.instance = instance;
|
||||
this.ex = null;
|
||||
}
|
||||
|
||||
public CachedPattern(PatternSyntaxException ex) {
|
||||
CachedPattern(PatternSyntaxException ex) {
|
||||
this.instance = null;
|
||||
this.ex = ex;
|
||||
}
|
||||
|
@ -25,20 +25,16 @@
|
||||
|
||||
package me.lucko.luckperms.common.utils;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerTask;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class RepeatingTask {
|
||||
private final SchedulerTask task;
|
||||
|
||||
// the executor thread
|
||||
private final ScheduledExecutorService executor;
|
||||
|
||||
protected RepeatingTask(long time, TimeUnit unit, String nameFormat) {
|
||||
this.executor = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setNameFormat(nameFormat).build());
|
||||
this.executor.scheduleAtFixedRate(this::run, time, time, unit);
|
||||
protected RepeatingTask(SchedulerAdapter scheduler, long time, TimeUnit unit) {
|
||||
this.task = scheduler.asyncRepeating(this::run, time, unit);
|
||||
}
|
||||
|
||||
private void run() {
|
||||
@ -52,11 +48,6 @@ public abstract class RepeatingTask {
|
||||
protected abstract void tick();
|
||||
|
||||
public void stop() {
|
||||
this.executor.shutdown();
|
||||
try {
|
||||
this.executor.awaitTermination(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.task.cancel();
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ package me.lucko.luckperms.common.verbose;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.utils.RepeatingTask;
|
||||
|
||||
@ -51,8 +52,8 @@ public class VerboseHandler extends RepeatingTask {
|
||||
// if there are any listeners currently registered
|
||||
private boolean listening = false;
|
||||
|
||||
public VerboseHandler() {
|
||||
super(100, TimeUnit.MILLISECONDS, "luckperms-verbose");
|
||||
public VerboseHandler(SchedulerAdapter scheduler) {
|
||||
super(scheduler, 100, TimeUnit.MILLISECONDS);
|
||||
this.listeners = new ConcurrentHashMap<>();
|
||||
this.queue = new ConcurrentLinkedQueue<>();
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ import me.lucko.luckperms.api.LuckPermsApi;
|
||||
import me.lucko.luckperms.api.event.user.UserDataRecalculateEvent;
|
||||
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
|
||||
import me.lucko.luckperms.common.api.delegates.model.ApiUser;
|
||||
import me.lucko.luckperms.common.calculators.PlatformCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
@ -75,6 +75,7 @@ import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@ -145,7 +146,7 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PlatformCalculatorFactory provideCalculatorFactory() {
|
||||
protected CalculatorFactory provideCalculatorFactory() {
|
||||
return new NukkitCalculatorFactory(this);
|
||||
}
|
||||
|
||||
@ -170,7 +171,7 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
|
||||
// schedule another injection after all plugins have loaded
|
||||
// the entire pluginmanager instance is replaced by some plugins :(
|
||||
this.bootstrap.getScheduler().asyncLater(injector, 1L);
|
||||
this.bootstrap.getServer().getScheduler().scheduleDelayedTask(this.bootstrap, injector, 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,8 +187,8 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
protected void registerHousekeepingTasks() {
|
||||
this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 60L);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2400L);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 3, TimeUnit.SECONDS);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -219,16 +220,13 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
});
|
||||
}
|
||||
|
||||
// replace the temporary executor when the Nukkit one starts
|
||||
this.bootstrap.getServer().getScheduler().scheduleTask(this.bootstrap, () -> this.bootstrap.getScheduler().setUseFallback(false), true);
|
||||
|
||||
// Load any online users (in the case of a reload)
|
||||
for (Player player : this.bootstrap.getServer().getOnlinePlayers().values()) {
|
||||
this.bootstrap.getScheduler().doAsync(() -> {
|
||||
this.bootstrap.getScheduler().executeAsync(() -> {
|
||||
try {
|
||||
User user = this.connectionListener.loadUser(player.getUniqueId(), player.getName());
|
||||
if (user != null) {
|
||||
this.bootstrap.getScheduler().doSync(() -> {
|
||||
this.bootstrap.getScheduler().executeSync(() -> {
|
||||
try {
|
||||
LPPermissible lpPermissible = new LPPermissible(player, user, this);
|
||||
PermissibleInjector.inject(player, lpPermissible);
|
||||
@ -244,12 +242,6 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performEarlyDisableTasks() {
|
||||
// Switch back to the fallback executor, the nukkit one won't allow new tasks
|
||||
this.bootstrap.getScheduler().setUseFallback(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removePlatformHooks() {
|
||||
// uninject from players
|
||||
|
@ -25,95 +25,16 @@
|
||||
|
||||
package me.lucko.luckperms.nukkit;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.AbstractJavaScheduler;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerTask;
|
||||
import me.lucko.luckperms.common.utils.Iterators;
|
||||
|
||||
import cn.nukkit.scheduler.ServerScheduler;
|
||||
import cn.nukkit.scheduler.TaskHandler;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class NukkitSchedulerAdapter implements SchedulerAdapter {
|
||||
private final LPNukkitBootstrap bootstrap;
|
||||
|
||||
private final ExecutorService asyncFallback;
|
||||
private final Executor asyncNukkit;
|
||||
public class NukkitSchedulerAdapter extends AbstractJavaScheduler implements SchedulerAdapter {
|
||||
private final Executor sync;
|
||||
private final Executor async;
|
||||
|
||||
private boolean useFallback = true;
|
||||
|
||||
private final Set<SchedulerTask> tasks = ConcurrentHashMap.newKeySet();
|
||||
|
||||
public NukkitSchedulerAdapter(LPNukkitBootstrap bootstrap) {
|
||||
this.bootstrap = bootstrap;
|
||||
|
||||
this.sync = new SyncExecutor();
|
||||
this.asyncFallback = new FallbackAsyncExecutor();
|
||||
this.asyncNukkit = new NukkitAsyncExecutor();
|
||||
this.async = new AsyncExecutor();
|
||||
}
|
||||
|
||||
private ServerScheduler scheduler() {
|
||||
return this.bootstrap.getServer().getScheduler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAsync(Runnable runnable) {
|
||||
async().execute(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSync(Runnable runnable) {
|
||||
sync().execute(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks) {
|
||||
SchedulerTask task = new NukkitSchedulerTask(scheduler().scheduleDelayedRepeatingTask(this.bootstrap, runnable, (int) intervalTicks, (int) intervalTicks, true));
|
||||
this.tasks.add(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask syncRepeating(Runnable runnable, long intervalTicks) {
|
||||
SchedulerTask task = new NukkitSchedulerTask(scheduler().scheduleDelayedRepeatingTask(this.bootstrap, runnable, (int) intervalTicks, (int) intervalTicks, false));
|
||||
this.tasks.add(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncLater(Runnable runnable, long delayTicks) {
|
||||
return new NukkitSchedulerTask(scheduler().scheduleDelayedTask(this.bootstrap, runnable, (int) delayTicks, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask syncLater(Runnable runnable, long delayTicks) {
|
||||
return new NukkitSchedulerTask(scheduler().scheduleDelayedTask(this.bootstrap, runnable, (int) delayTicks, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
Iterators.iterate(this.tasks, SchedulerTask::cancel);
|
||||
|
||||
// wait for executor
|
||||
this.asyncFallback.shutdown();
|
||||
try {
|
||||
this.asyncFallback.awaitTermination(30, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.sync = r -> bootstrap.getServer().getScheduler().scheduleTask(bootstrap, r, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -121,62 +42,4 @@ public class NukkitSchedulerAdapter implements SchedulerAdapter {
|
||||
return this.sync;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor async() {
|
||||
return this.async;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor platformAsync() {
|
||||
return this.asyncNukkit;
|
||||
}
|
||||
|
||||
public void setUseFallback(boolean useFallback) {
|
||||
this.useFallback = useFallback;
|
||||
}
|
||||
|
||||
private final class SyncExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(@Nonnull Runnable runnable) {
|
||||
NukkitSchedulerAdapter.this.bootstrap.getServer().getScheduler().scheduleTask(NukkitSchedulerAdapter.this.bootstrap, runnable, false);
|
||||
}
|
||||
}
|
||||
|
||||
private final class AsyncExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(@Nonnull Runnable runnable) {
|
||||
if (NukkitSchedulerAdapter.this.useFallback || !NukkitSchedulerAdapter.this.bootstrap.isEnabled()) {
|
||||
NukkitSchedulerAdapter.this.asyncFallback.execute(runnable);
|
||||
} else {
|
||||
NukkitSchedulerAdapter.this.asyncNukkit.execute(runnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class NukkitAsyncExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(@Nonnull Runnable runnable) {
|
||||
NukkitSchedulerAdapter.this.bootstrap.getServer().getScheduler().scheduleTask(NukkitSchedulerAdapter.this.bootstrap, runnable, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class FallbackAsyncExecutor extends ThreadPoolExecutor {
|
||||
private FallbackAsyncExecutor() {
|
||||
super(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>(), new ThreadFactoryBuilder().setNameFormat("luckperms-fallback-%d").build());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class NukkitSchedulerTask implements SchedulerTask {
|
||||
private final TaskHandler task;
|
||||
|
||||
private NukkitSchedulerTask(TaskHandler task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.task.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ public class NukkitSenderFactory extends SenderFactory<CommandSender> {
|
||||
}
|
||||
|
||||
// otherwise, send the message sync
|
||||
getPlugin().getBootstrap().getScheduler().doSync(new SyncMessengerAgent(sender, s));
|
||||
getPlugin().getBootstrap().getScheduler().executeSync(new SyncMessengerAgent(sender, s));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,7 +29,7 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.LookupSetting;
|
||||
import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
@ -42,7 +42,7 @@ import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
import me.lucko.luckperms.nukkit.processors.ChildProcessor;
|
||||
import me.lucko.luckperms.nukkit.processors.DefaultsProcessor;
|
||||
|
||||
public class NukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
public class NukkitCalculatorFactory implements CalculatorFactory {
|
||||
private final LPNukkitPlugin plugin;
|
||||
|
||||
public NukkitCalculatorFactory(LPNukkitPlugin plugin) {
|
||||
@ -71,6 +71,6 @@ public class NukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
processors.add(new DefaultsProcessor(this.plugin, contexts.hasSetting(LookupSetting.IS_OP)));
|
||||
}
|
||||
|
||||
return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build()));
|
||||
return new PermissionCalculator(this.plugin, metadata, processors.build());
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ public class NukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
this.plugin.getUserManager().getHouseKeeper().registerUsage(player.getUniqueId());
|
||||
|
||||
// force a clear of transient nodes
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId());
|
||||
if (user != null) {
|
||||
user.clearTransientNodes();
|
||||
|
@ -29,6 +29,7 @@ import com.google.common.collect.ForwardingMap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.common.buffers.Cache;
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
|
||||
import cn.nukkit.permission.Permission;
|
||||
@ -39,6 +40,8 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* A replacement map for the 'defaultPerms' instance in Nukkit's SimplePluginManager.
|
||||
*
|
||||
@ -58,15 +61,13 @@ public final class LPDefaultsMap {
|
||||
private final Map<String, Permission> nonOpSet = new DefaultPermissionSet(false);
|
||||
|
||||
// fully resolved defaults (accounts for child permissions too)
|
||||
private Map<String, Boolean> resolvedOpDefaults = ImmutableMap.of();
|
||||
private Map<String, Boolean> resolvedNonOpDefaults = ImmutableMap.of();
|
||||
private DefaultsCache opCache = new DefaultsCache(true);
|
||||
private DefaultsCache nonOpCache = new DefaultsCache(false);
|
||||
|
||||
public LPDefaultsMap(LPNukkitPlugin plugin, Map<Boolean, Map<String, Permission>> existingData) {
|
||||
this.plugin = plugin;
|
||||
this.opSet.putAll(existingData.getOrDefault(Boolean.TRUE, Collections.emptyMap()));
|
||||
this.nonOpSet.putAll(existingData.getOrDefault(Boolean.FALSE, Collections.emptyMap()));
|
||||
refreshOp();
|
||||
refreshNonOp();
|
||||
}
|
||||
|
||||
public Map<String, Permission> getOpPermissions() {
|
||||
@ -77,6 +78,18 @@ public final class LPDefaultsMap {
|
||||
return this.nonOpSet;
|
||||
}
|
||||
|
||||
public Map<String, Permission> get(boolean op) {
|
||||
return op ? this.opSet : this.nonOpSet;
|
||||
}
|
||||
|
||||
private DefaultsCache getCache(boolean op) {
|
||||
return op ? this.opCache : this.nonOpCache;
|
||||
}
|
||||
|
||||
private void invalidate(boolean op) {
|
||||
getCache(op).invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries whether a given permission should be granted by default.
|
||||
*
|
||||
@ -85,55 +98,17 @@ public final class LPDefaultsMap {
|
||||
* @return a tristate result
|
||||
*/
|
||||
public Tristate lookupDefaultPermission(String permission, boolean isOp) {
|
||||
Map<String, Boolean> map = isOp ? this.resolvedOpDefaults : this.resolvedNonOpDefaults;
|
||||
Map<String, Boolean> map = getCache(isOp).get();
|
||||
return Tristate.fromNullableBoolean(map.get(permission));
|
||||
}
|
||||
|
||||
private void refresh(boolean op) {
|
||||
if (op) {
|
||||
refreshOp();
|
||||
} else {
|
||||
refreshNonOp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the op data in this provider.
|
||||
*/
|
||||
private void refreshOp() {
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
for (Permission perm : getOpPermissions().values()) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
builder.put(name, true);
|
||||
for (Map.Entry<String, Boolean> child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
builder.putIfAbsent(child.getKey(), child.getValue());
|
||||
}
|
||||
}
|
||||
this.resolvedOpDefaults = ImmutableMap.copyOf(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the non op data in this provider.
|
||||
*/
|
||||
private void refreshNonOp() {
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
for (Permission perm : getNonOpPermissions().values()) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
builder.put(name, true);
|
||||
for (Map.Entry<String, Boolean> child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
builder.putIfAbsent(child.getKey(), child.getValue());
|
||||
}
|
||||
}
|
||||
this.resolvedNonOpDefaults = ImmutableMap.copyOf(builder);
|
||||
}
|
||||
|
||||
final class DefaultPermissionSet extends ForwardingMap<String, Permission> {
|
||||
final LPDefaultsMap parent = LPDefaultsMap.this;
|
||||
|
||||
private final Map<String, Permission> delegate = new ConcurrentHashMap<>();
|
||||
private final boolean op;
|
||||
|
||||
private DefaultPermissionSet(boolean op) {
|
||||
DefaultPermissionSet(boolean op) {
|
||||
this.op = op;
|
||||
}
|
||||
|
||||
@ -145,21 +120,43 @@ public final class LPDefaultsMap {
|
||||
@Override
|
||||
public Permission put(String key, Permission value) {
|
||||
Permission ret = super.put(key, value);
|
||||
refresh(this.op);
|
||||
invalidate(this.op);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission putIfAbsent(String key, Permission value) {
|
||||
Permission ret = super.putIfAbsent(key, value);
|
||||
refresh(this.op);
|
||||
invalidate(this.op);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends Permission> map) {
|
||||
super.putAll(map);
|
||||
refresh(this.op);
|
||||
invalidate(this.op);
|
||||
}
|
||||
}
|
||||
|
||||
private final class DefaultsCache extends Cache<Map<String, Boolean>> {
|
||||
private final boolean op;
|
||||
|
||||
DefaultsCache(boolean op) {
|
||||
this.op = op;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected Map<String, Boolean> supply() {
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
for (Permission perm : LPDefaultsMap.this.get(this.op).values()) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
builder.put(name, true);
|
||||
for (Map.Entry<String, Boolean> child : LPDefaultsMap.this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
builder.putIfAbsent(child.getKey(), child.getValue());
|
||||
}
|
||||
}
|
||||
return ImmutableMap.copyOf(builder);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
package me.lucko.luckperms.sponge.service;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
@ -39,19 +37,12 @@ import org.spongepowered.api.service.context.Context;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Utility class for converting between Sponge and LuckPerms context and tristate classes
|
||||
*/
|
||||
public final class CompatibilityUtil {
|
||||
private static final LoadingCache<Set<Context>, ImmutableContextSet> SPONGE_TO_LP_CACHE = Caffeine.newBuilder()
|
||||
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||
.build(ImmutableContextSet::fromEntries);
|
||||
|
||||
private static final LoadingCache<ImmutableContextSet, Set<Context>> LP_TO_SPONGE_CACHE = Caffeine.newBuilder()
|
||||
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||
.build(DelegatingImmutableContextSet::new);
|
||||
private static final Set<Context> EMPTY = ImmutableSet.of();
|
||||
|
||||
public static ImmutableContextSet convertContexts(Set<Context> contexts) {
|
||||
Objects.requireNonNull(contexts, "contexts");
|
||||
@ -60,12 +51,21 @@ public final class CompatibilityUtil {
|
||||
return ((DelegatingContextSet) contexts).getDelegate().makeImmutable();
|
||||
}
|
||||
|
||||
return SPONGE_TO_LP_CACHE.get(ImmutableSet.copyOf(contexts));
|
||||
if (contexts.isEmpty()) {
|
||||
return ImmutableContextSet.empty();
|
||||
}
|
||||
|
||||
return ImmutableContextSet.fromEntries(contexts);
|
||||
}
|
||||
|
||||
public static Set<Context> convertContexts(ContextSet contexts) {
|
||||
Objects.requireNonNull(contexts, "contexts");
|
||||
return LP_TO_SPONGE_CACHE.get(contexts.makeImmutable());
|
||||
|
||||
if (contexts.isEmpty()) {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
return new DelegatingImmutableContextSet(contexts.makeImmutable());
|
||||
}
|
||||
|
||||
public static org.spongepowered.api.util.Tristate convertTristate(Tristate tristate) {
|
||||
|
@ -60,12 +60,13 @@ public final class SubjectReferenceFactory {
|
||||
*
|
||||
* It's perfectly ok if two instances of the same SubjectReference exist. (hence the 1 hour expiry)
|
||||
*/
|
||||
private final LoadingCache<SubjectReferenceAttributes, CachedSubjectReference> referenceCache = Caffeine.newBuilder()
|
||||
.expireAfterAccess(1, TimeUnit.HOURS)
|
||||
.build(a -> new CachedSubjectReference(SubjectReferenceFactory.this.service, a.collectionId, a.id));
|
||||
private final LoadingCache<SubjectReferenceAttributes, CachedSubjectReference> referenceCache;
|
||||
|
||||
public SubjectReferenceFactory(LPPermissionService service) {
|
||||
this.service = service;
|
||||
this.referenceCache = Caffeine.newBuilder()
|
||||
.expireAfterAccess(1, TimeUnit.HOURS)
|
||||
.build(a -> new CachedSubjectReference(this.service, a.collectionId, a.id));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
@ -30,8 +30,8 @@ import com.google.inject.Inject;
|
||||
import me.lucko.luckperms.api.platform.PlatformType;
|
||||
import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader;
|
||||
import me.lucko.luckperms.common.dependencies.classloader.ReflectionClassLoader;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.utils.MoreFiles;
|
||||
import me.lucko.luckperms.sponge.utils.VersionData;
|
||||
|
||||
|
@ -28,7 +28,7 @@ package me.lucko.luckperms.sponge;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.LuckPermsApi;
|
||||
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
|
||||
import me.lucko.luckperms.common.calculators.PlatformCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.command.CommandManager;
|
||||
import me.lucko.luckperms.common.command.abstraction.Command;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
@ -75,6 +75,7 @@ import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@ -146,7 +147,7 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PlatformCalculatorFactory provideCalculatorFactory() {
|
||||
protected CalculatorFactory provideCalculatorFactory() {
|
||||
return new SpongeCalculatorFactory(this);
|
||||
}
|
||||
|
||||
@ -189,9 +190,9 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
protected void registerHousekeepingTasks() {
|
||||
this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 60L);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2400L);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new ServiceCacheHousekeepingTask(this.service), 2400L);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 3, TimeUnit.SECONDS);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2, TimeUnit.MINUTES);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new ServiceCacheHousekeepingTask(this.service), 2, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,17 +25,19 @@
|
||||
|
||||
package me.lucko.luckperms.sponge;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerTask;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.utils.Iterators;
|
||||
|
||||
import org.spongepowered.api.scheduler.Scheduler;
|
||||
import org.spongepowered.api.scheduler.SpongeExecutorService;
|
||||
import org.spongepowered.api.scheduler.Task;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class SpongeSchedulerAdapter implements SchedulerAdapter {
|
||||
private final LPSpongeBootstrap bootstrap;
|
||||
@ -44,7 +46,7 @@ public class SpongeSchedulerAdapter implements SchedulerAdapter {
|
||||
private final SpongeExecutorService sync;
|
||||
private final SpongeExecutorService async;
|
||||
|
||||
private final Set<SchedulerTask> tasks = ConcurrentHashMap.newKeySet();
|
||||
private final Set<Task> tasks = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
|
||||
public SpongeSchedulerAdapter(LPSpongeBootstrap bootstrap, Scheduler scheduler, SpongeExecutorService sync, SpongeExecutorService async) {
|
||||
this.bootstrap = bootstrap;
|
||||
@ -64,82 +66,43 @@ public class SpongeSchedulerAdapter implements SchedulerAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAsync(Runnable runnable) {
|
||||
public void executeAsync(Runnable runnable) {
|
||||
this.scheduler.createTaskBuilder().async().execute(runnable).submit(this.bootstrap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSync(Runnable runnable) {
|
||||
public void executeSync(Runnable runnable) {
|
||||
this.scheduler.createTaskBuilder().execute(runnable).submit(this.bootstrap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks) {
|
||||
Task task = this.scheduler.createTaskBuilder()
|
||||
public SchedulerTask asyncLater(Runnable task, long delay, TimeUnit unit) {
|
||||
Task t = this.scheduler.createTaskBuilder()
|
||||
.async()
|
||||
.intervalTicks(intervalTicks)
|
||||
.delayTicks(intervalTicks)
|
||||
.execute(runnable)
|
||||
.delay(delay, unit)
|
||||
.execute(task)
|
||||
.submit(this.bootstrap);
|
||||
|
||||
SchedulerTask wrapped = new SpongeSchedulerTask(task);
|
||||
this.tasks.add(wrapped);
|
||||
return wrapped;
|
||||
this.tasks.add(t);
|
||||
return t::cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask syncRepeating(Runnable runnable, long intervalTicks) {
|
||||
Task task = this.scheduler.createTaskBuilder()
|
||||
.intervalTicks(intervalTicks)
|
||||
.delayTicks(intervalTicks)
|
||||
.execute(runnable)
|
||||
.submit(this.bootstrap);
|
||||
|
||||
SchedulerTask wrapped = new SpongeSchedulerTask(task);
|
||||
this.tasks.add(wrapped);
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncLater(Runnable runnable, long delayTicks) {
|
||||
Task task = this.scheduler.createTaskBuilder()
|
||||
public SchedulerTask asyncRepeating(Runnable task, long interval, TimeUnit unit) {
|
||||
Task t = this.scheduler.createTaskBuilder()
|
||||
.async()
|
||||
.delayTicks(delayTicks)
|
||||
.execute(runnable)
|
||||
.interval(interval, unit)
|
||||
.delay(interval, unit)
|
||||
.execute(task)
|
||||
.submit(this.bootstrap);
|
||||
|
||||
SchedulerTask wrapped = new SpongeSchedulerTask(task);
|
||||
this.tasks.add(wrapped);
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask syncLater(Runnable runnable, long delayTicks) {
|
||||
Task task = this.scheduler.createTaskBuilder()
|
||||
.delayTicks(delayTicks)
|
||||
.execute(runnable)
|
||||
.submit(this.bootstrap);
|
||||
|
||||
SchedulerTask wrapped = new SpongeSchedulerTask(task);
|
||||
this.tasks.add(wrapped);
|
||||
return wrapped;
|
||||
this.tasks.add(t);
|
||||
return t::cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
Iterators.iterate(this.tasks, SchedulerTask::cancel);
|
||||
Iterators.iterate(this.tasks, Task::cancel);
|
||||
}
|
||||
|
||||
private static final class SpongeSchedulerTask implements SchedulerTask {
|
||||
private final Task task;
|
||||
|
||||
private SpongeSchedulerTask(Task task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.task.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ package me.lucko.luckperms.sponge.calculators;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
@ -41,7 +41,7 @@ import me.lucko.luckperms.sponge.processors.GroupDefaultsProcessor;
|
||||
import me.lucko.luckperms.sponge.processors.SpongeWildcardProcessor;
|
||||
import me.lucko.luckperms.sponge.processors.UserDefaultsProcessor;
|
||||
|
||||
public class SpongeCalculatorFactory extends AbstractCalculatorFactory {
|
||||
public class SpongeCalculatorFactory implements CalculatorFactory {
|
||||
private final LPSpongePlugin plugin;
|
||||
|
||||
public SpongeCalculatorFactory(LPSpongePlugin plugin) {
|
||||
@ -74,6 +74,6 @@ public class SpongeCalculatorFactory extends AbstractCalculatorFactory {
|
||||
}
|
||||
}
|
||||
|
||||
return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build()));
|
||||
return new PermissionCalculator(this.plugin, metadata, processors.build());
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ public class SpongeConnectionListener extends AbstractConnectionListener {
|
||||
this.plugin.getUserManager().getHouseKeeper().registerUsage(player.getUniqueId());
|
||||
|
||||
// force a clear of transient nodes
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId());
|
||||
if (user != null) {
|
||||
user.clearTransientNodes();
|
||||
|
@ -237,8 +237,6 @@ public class LuckPermsService implements LPPermissionService {
|
||||
subject.invalidateCaches();
|
||||
}
|
||||
}
|
||||
|
||||
this.plugin.getCalculatorFactory().invalidateAll();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ public class UpdateEventHandlerImpl implements UpdateEventHandler {
|
||||
|
||||
@Override
|
||||
public void fireUpdateEvent(LPSubjectData subjectData) {
|
||||
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
|
||||
SubjectDataUpdateEvent event = new LPSubjectDataUpdateEvent(this.plugin, subjectData);
|
||||
this.plugin.getBootstrap().getGame().getEventManager().post(event);
|
||||
});
|
||||
|
@ -161,7 +161,7 @@ public abstract class HolderSubject<T extends PermissionHolder> implements LPSub
|
||||
@Override
|
||||
public void invalidateCaches() {
|
||||
// invalidate for all changes
|
||||
this.parent.getCachedData().invalidate();
|
||||
this.parent.invalidateCachedData();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ import com.google.gson.JsonObject;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.common.contexts.ContextSetComparator;
|
||||
import me.lucko.luckperms.common.contexts.ContextSetJsonSerializer;
|
||||
import me.lucko.luckperms.common.utils.CollationKeyCache;
|
||||
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData;
|
||||
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
|
||||
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
|
||||
@ -204,7 +203,7 @@ public class SubjectDataContainer {
|
||||
|
||||
// sort alphabetically.
|
||||
List<Map.Entry<String, Boolean>> perms = new ArrayList<>(e.getValue().entrySet());
|
||||
perms.sort(Map.Entry.comparingByKey(CollationKeyCache.comparator()));
|
||||
perms.sort(Map.Entry.comparingByKey());
|
||||
|
||||
for (Map.Entry<String, Boolean> ent : perms) {
|
||||
data.addProperty(ent.getKey(), ent.getValue());
|
||||
@ -228,7 +227,7 @@ public class SubjectDataContainer {
|
||||
|
||||
// sort alphabetically.
|
||||
List<Map.Entry<String, String>> opts = new ArrayList<>(e.getValue().entrySet());
|
||||
opts.sort(Map.Entry.comparingByKey(CollationKeyCache.comparator()));
|
||||
opts.sort(Map.Entry.comparingByKey());
|
||||
|
||||
for (Map.Entry<String, String> ent : opts) {
|
||||
data.addProperty(ent.getKey(), ent.getValue());
|
||||
|
Loading…
Reference in New Issue
Block a user