Final bits of API refactoring, add group data caches, fix issue with LPPermissionAttachment fake map injection
This commit is contained in:
parent
d75b29f51d
commit
a115ff8ce2
@ -25,7 +25,10 @@
|
|||||||
|
|
||||||
package me.lucko.luckperms.api;
|
package me.lucko.luckperms.api;
|
||||||
|
|
||||||
|
import me.lucko.luckperms.api.caching.GroupData;
|
||||||
|
|
||||||
import java.util.OptionalInt;
|
import java.util.OptionalInt;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
@ -51,4 +54,23 @@ public interface Group extends PermissionHolder {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
OptionalInt getWeight();
|
OptionalInt getWeight();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the groups's {@link GroupData} cache.
|
||||||
|
*
|
||||||
|
* @return the groups cached data.
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
GroupData getCachedData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes and applies any changes to the cached group data.
|
||||||
|
*
|
||||||
|
* @return the task future
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
CompletableFuture<Void> refreshCachedData();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ package me.lucko.luckperms.api;
|
|||||||
import com.google.common.collect.ImmutableSetMultimap;
|
import com.google.common.collect.ImmutableSetMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
|
import me.lucko.luckperms.api.caching.CachedData;
|
||||||
import me.lucko.luckperms.api.context.ContextSet;
|
import me.lucko.luckperms.api.context.ContextSet;
|
||||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||||
|
|
||||||
@ -70,6 +71,15 @@ public interface PermissionHolder {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
String getFriendlyName();
|
String getFriendlyName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the holders {@link CachedData} cache.
|
||||||
|
*
|
||||||
|
* @return the holders cached data.
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
CachedData getCachedData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the backing multimap containing every permission this holder has.
|
* Gets the backing multimap containing every permission this holder has.
|
||||||
*
|
*
|
||||||
|
@ -84,6 +84,7 @@ public interface User extends PermissionHolder {
|
|||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
@Override
|
||||||
UserData getCachedData();
|
UserData getCachedData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
404
api/src/main/java/me/lucko/luckperms/api/caching/CachedData.java
Normal file
404
api/src/main/java/me/lucko/luckperms/api/caching/CachedData.java
Normal file
@ -0,0 +1,404 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of LuckPerms, licensed under the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.lucko.luckperms.api.caching;
|
||||||
|
|
||||||
|
import me.lucko.luckperms.api.Contexts;
|
||||||
|
import me.lucko.luckperms.api.PermissionHolder;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds cached permission and meta lookup data for a {@link PermissionHolder}.
|
||||||
|
*
|
||||||
|
* <p>All calls will account for inheritance, as well as any default data provided by
|
||||||
|
* the platform. This calls are heavily cached and are therefore fast.</p>
|
||||||
|
*
|
||||||
|
* <p>For meta, both methods accepting {@link Contexts} and {@link MetaContexts} are provided. The only difference is that
|
||||||
|
* the latter allows you to define how the meta stack should be structured internally. Where {@link Contexts} are passed, the
|
||||||
|
* values from the configuration are used.</p>
|
||||||
|
*
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public interface CachedData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets PermissionData from the cache, given a specified context.
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to get the permission data in
|
||||||
|
* @return a permission data instance
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
PermissionData getPermissionData(@Nonnull Contexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets MetaData from the cache, given a specified context.
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to get the permission data in
|
||||||
|
* @return a meta data instance
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
MetaData getMetaData(@Nonnull MetaContexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets MetaData from the cache, given a specified context.
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to get the permission data in
|
||||||
|
* @return a meta data instance
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
MetaData getMetaData(@Nonnull Contexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates permission data, bypassing the cache.
|
||||||
|
*
|
||||||
|
* <p>The result of this operation is calculated each time the method is called.
|
||||||
|
* The result is not added to the internal cache.</p>
|
||||||
|
*
|
||||||
|
* <p>It is therefore highly recommended to use {@link #getPermissionData(Contexts)} instead.</p>
|
||||||
|
*
|
||||||
|
* <p>The use cases of this method are more around constructing one-time
|
||||||
|
* instances of {@link PermissionData}, without adding the result to the cache.</p>
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to get permission data in
|
||||||
|
* @return a permission data instance
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
PermissionData calculatePermissions(@Nonnull Contexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates meta data, bypassing the cache.
|
||||||
|
*
|
||||||
|
* <p>The result of this operation is calculated each time the method is called.
|
||||||
|
* The result is not added to the internal cache.</p>
|
||||||
|
*
|
||||||
|
* <p>It is therefore highly recommended to use {@link #getMetaData(MetaContexts)} instead.</p>
|
||||||
|
*
|
||||||
|
* <p>The use cases of this method are more around constructing one-time
|
||||||
|
* instances of {@link MetaData}, without adding the result to the cache.</p>
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to get meta data in
|
||||||
|
* @return a meta data instance
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
MetaData calculateMeta(@Nonnull MetaContexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates meta data, bypassing the cache.
|
||||||
|
*
|
||||||
|
* <p>The result of this operation is calculated each time the method is called.
|
||||||
|
* The result is not added to the internal cache.</p>
|
||||||
|
*
|
||||||
|
* <p>It is therefore highly recommended to use {@link #getMetaData(Contexts)} instead.</p>
|
||||||
|
*
|
||||||
|
* <p>The use cases of this method are more around constructing one-time
|
||||||
|
* instances of {@link MetaData}, without adding the result to the cache.</p>
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to get meta data in
|
||||||
|
* @return a meta data instance
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
MetaData calculateMeta(@Nonnull Contexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Re)calculates permission data for a given context.
|
||||||
|
*
|
||||||
|
* <p>This method returns immediately in all cases. The (re)calculation is
|
||||||
|
* performed asynchronously and applied to the cache in the background.</p>
|
||||||
|
*
|
||||||
|
* <p>If there was a previous {@link PermissionData} instance associated with
|
||||||
|
* the given {@link Contexts}, then that instance will continue to be returned by
|
||||||
|
* {@link #getPermissionData(Contexts)} until the recalculation is completed.</p>
|
||||||
|
*
|
||||||
|
* <p>If there was no value calculated and cached prior to the call of this
|
||||||
|
* method, then one will be calculated.</p>
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to recalculate in.
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
*/
|
||||||
|
void recalculatePermissions(@Nonnull Contexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Re)calculates meta data for a given context.
|
||||||
|
*
|
||||||
|
* <p>This method returns immediately in all cases. The (re)calculation is
|
||||||
|
* performed asynchronously and applied to the cache in the background.</p>
|
||||||
|
*
|
||||||
|
* <p>If there was a previous {@link MetaData} instance associated with
|
||||||
|
* the given {@link MetaContexts}, then that instance will continue to be returned by
|
||||||
|
* {@link #getMetaData(MetaContexts)} until the recalculation is completed.</p>
|
||||||
|
*
|
||||||
|
* <p>If there was no value calculated and cached prior to the call of this
|
||||||
|
* method, then one will be calculated.</p>
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to recalculate in.
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
void recalculateMeta(@Nonnull MetaContexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Re)calculates meta data for a given context.
|
||||||
|
*
|
||||||
|
* <p>This method returns immediately in all cases. The (re)calculation is
|
||||||
|
* performed asynchronously and applied to the cache in the background.</p>
|
||||||
|
*
|
||||||
|
* <p>If there was a previous {@link MetaData} instance associated with
|
||||||
|
* the given {@link Contexts}, then that instance will continue to be returned by
|
||||||
|
* {@link #getMetaData(Contexts)} until the recalculation is completed.</p>
|
||||||
|
*
|
||||||
|
* <p>If there was no value calculated and cached prior to the call of this
|
||||||
|
* method, then one will be calculated.</p>
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to recalculate in.
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
*/
|
||||||
|
void recalculateMeta(@Nonnull Contexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Re)loads permission data for a given context.
|
||||||
|
*
|
||||||
|
* <p>Unlike {@link #recalculatePermissions(Contexts)}, this method immediately
|
||||||
|
* invalidates any previous {@link PermissionData} values contained within the cache,
|
||||||
|
* and then schedules a task to reload a new {@link PermissionData} instance to
|
||||||
|
* replace the one which was invalidated.</p>
|
||||||
|
*
|
||||||
|
* <p>The invalidation happens immediately during the execution of this method.
|
||||||
|
* The result of the re-computation encapsulated by the future.</p>
|
||||||
|
*
|
||||||
|
* <p>Subsequent calls to {@link #getPermissionData(Contexts)} will block until
|
||||||
|
* the result of this operation is complete.</p>
|
||||||
|
*
|
||||||
|
* <p>If there was no value calculated and cached prior to the call of this
|
||||||
|
* method, then one will be calculated.</p>
|
||||||
|
*
|
||||||
|
* <p>This method returns a Future so users can optionally choose to wait
|
||||||
|
* until the recalculation has been performed.</p>
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to reload in.
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
CompletableFuture<? extends PermissionData> reloadPermissions(@Nonnull Contexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Re)loads meta data for a given context.
|
||||||
|
*
|
||||||
|
* <p>Unlike {@link #recalculateMeta(MetaContexts)}, this method immediately
|
||||||
|
* invalidates any previous {@link MetaData} values contained within the cache,
|
||||||
|
* and then schedules a task to reload a new {@link MetaData} instance to
|
||||||
|
* replace the one which was invalidated.</p>
|
||||||
|
*
|
||||||
|
* <p>The invalidation happens immediately during the execution of this method.
|
||||||
|
* The result of the re-computation encapsulated by the future.</p>
|
||||||
|
*
|
||||||
|
* <p>Subsequent calls to {@link #getMetaData(MetaContexts)} will block until
|
||||||
|
* the result of this operation is complete.</p>
|
||||||
|
*
|
||||||
|
* <p>If there was no value calculated and cached prior to the call of this
|
||||||
|
* method, then one will be calculated.</p>
|
||||||
|
*
|
||||||
|
* <p>This method returns a Future so users can optionally choose to wait
|
||||||
|
* until the recalculation has been performed.</p>
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to reload in.
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
CompletableFuture<? extends MetaData> reloadMeta(@Nonnull MetaContexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Re)loads meta data for a given context.
|
||||||
|
*
|
||||||
|
* <p>Unlike {@link #recalculateMeta(Contexts)}, this method immediately
|
||||||
|
* invalidates any previous {@link MetaData} values contained within the cache,
|
||||||
|
* and then schedules a task to reload a new {@link MetaData} instance to
|
||||||
|
* replace the one which was invalidated.</p>
|
||||||
|
*
|
||||||
|
* <p>The invalidation happens immediately during the execution of this method.
|
||||||
|
* The result of the re-computation encapsulated by the future.</p>
|
||||||
|
*
|
||||||
|
* <p>Subsequent calls to {@link #getMetaData(Contexts)} will block until
|
||||||
|
* the result of this operation is complete.</p>
|
||||||
|
*
|
||||||
|
* <p>If there was no value calculated and cached prior to the call of this
|
||||||
|
* method, then one will be calculated.</p>
|
||||||
|
*
|
||||||
|
* <p>This method returns a Future so users can optionally choose to wait
|
||||||
|
* until the recalculation has been performed.</p>
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to reload in.
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
CompletableFuture<? extends MetaData> reloadMeta(@Nonnull Contexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalculates permission data for all known contexts.
|
||||||
|
*
|
||||||
|
* <p>This method returns immediately. The recalculation is performed
|
||||||
|
* asynchronously and applied to the cache in the background.</p>
|
||||||
|
*
|
||||||
|
* <p>The previous {@link PermissionData} instances will continue to be returned
|
||||||
|
* by {@link #getPermissionData(Contexts)} until the recalculation is completed.</p>
|
||||||
|
*/
|
||||||
|
void recalculatePermissions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalculates meta data for all known contexts.
|
||||||
|
*
|
||||||
|
* <p>This method returns immediately. The recalculation is performed
|
||||||
|
* asynchronously and applied to the cache in the background.</p>
|
||||||
|
*
|
||||||
|
* <p>The previous {@link MetaData} instances will continue to be returned
|
||||||
|
* by {@link #getMetaData(MetaContexts)} and {@link #getMetaData(Contexts)}
|
||||||
|
* until the recalculation is completed.</p>
|
||||||
|
*/
|
||||||
|
void recalculateMeta();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reloads permission data for all known contexts.
|
||||||
|
*
|
||||||
|
* <p>Unlike {@link #recalculatePermissions()}, this method immediately
|
||||||
|
* invalidates all previous {@link PermissionData} values contained within the cache,
|
||||||
|
* and then schedules a task to reload a new {@link PermissionData} instances to
|
||||||
|
* replace the ones which were invalidated.</p>
|
||||||
|
*
|
||||||
|
* <p>The invalidation happens immediately during the execution of this method.
|
||||||
|
* The result of the re-computation encapsulated by the future.</p>
|
||||||
|
*
|
||||||
|
* <p>Subsequent calls to {@link #getPermissionData(Contexts)} will block until
|
||||||
|
* the result of this operation is complete.</p>
|
||||||
|
*
|
||||||
|
* <p>This method returns a Future so users can optionally choose to wait
|
||||||
|
* until the recalculation has been performed.</p>
|
||||||
|
*
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
CompletableFuture<Void> reloadPermissions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reloads meta data for all known contexts.
|
||||||
|
*
|
||||||
|
* <p>Unlike {@link #recalculateMeta()}, this method immediately
|
||||||
|
* invalidates all previous {@link MetaData} values contained within the cache,
|
||||||
|
* and then schedules a task to reload a new {@link MetaData} instances to
|
||||||
|
* replace the ones which were invalidated.</p>
|
||||||
|
*
|
||||||
|
* <p>The invalidation happens immediately during the execution of this method.
|
||||||
|
* The result of the re-computation encapsulated by the future.</p>
|
||||||
|
*
|
||||||
|
* <p>Subsequent calls to {@link #getMetaData(MetaContexts)} and
|
||||||
|
* {@link #getMetaData(Contexts)} will block until the result of this operation
|
||||||
|
* is complete.</p>
|
||||||
|
*
|
||||||
|
* <p>This method returns a Future so users can optionally choose to wait
|
||||||
|
* until the recalculation has been performed.</p>
|
||||||
|
*
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
CompletableFuture<Void> reloadMeta();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-calculates and caches {@link PermissionData} and {@link MetaData}
|
||||||
|
* instances for the given contexts.
|
||||||
|
*
|
||||||
|
* <p>If the cache already contains a value for the given context,
|
||||||
|
* no action is taken.</p>
|
||||||
|
*
|
||||||
|
* <p>This method blocks until the calculation is completed.</p>
|
||||||
|
*
|
||||||
|
* @param contexts a set of contexts
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
*/
|
||||||
|
default void preCalculate(@Nonnull Set<Contexts> contexts) {
|
||||||
|
contexts.forEach(this::preCalculate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-calculates and caches {@link PermissionData} and {@link MetaData}
|
||||||
|
* instances for a given context.
|
||||||
|
*
|
||||||
|
* <p>If the cache already contains a value for the given context,
|
||||||
|
* no action is taken.</p>
|
||||||
|
*
|
||||||
|
* <p>This method blocks until the calculation is completed.</p>
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to pre-calculate for
|
||||||
|
* @throws NullPointerException if contexts is null
|
||||||
|
*/
|
||||||
|
void preCalculate(@Nonnull Contexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates any cached {@link PermissionData} instances mapped to the given
|
||||||
|
* {@link Contexts}.
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to invalidate for
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
void invalidatePermissions(@Nonnull Contexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates any cached {@link MetaData} instances mapped to the given
|
||||||
|
* {@link MetaContexts}.
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to invalidate for
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
void invalidateMeta(@Nonnull MetaContexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates any cached {@link MetaData} instances mapped to the given
|
||||||
|
* {@link Contexts}.
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to invalidate for
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
void invalidateMeta(@Nonnull Contexts contexts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates all of the underlying Permission calculators.
|
||||||
|
*
|
||||||
|
* <p>Can be called to allow for an update in defaults.</p>
|
||||||
|
*/
|
||||||
|
void invalidatePermissionCalculators();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of LuckPerms, licensed under the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.lucko.luckperms.api.caching;
|
||||||
|
|
||||||
|
import me.lucko.luckperms.api.Contexts;
|
||||||
|
import me.lucko.luckperms.api.Group;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds cached permission and meta lookup data for a {@link Group}.
|
||||||
|
*
|
||||||
|
* <p>All calls will account for inheritance, as well as any default data provided
|
||||||
|
* by the platform. This calls are heavily cached and are therefore fast.</p>
|
||||||
|
*
|
||||||
|
* <p>For meta, both methods accepting {@link Contexts} and {@link MetaContexts} are provided. The only difference is that
|
||||||
|
* the latter allows you to define how the meta stack should be structured internally. Where {@link Contexts} are passed, the
|
||||||
|
* values from the configuration are used.</p>
|
||||||
|
*
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public interface GroupData extends CachedData {
|
||||||
|
|
||||||
|
}
|
@ -26,16 +26,13 @@
|
|||||||
package me.lucko.luckperms.api.caching;
|
package me.lucko.luckperms.api.caching;
|
||||||
|
|
||||||
import me.lucko.luckperms.api.Contexts;
|
import me.lucko.luckperms.api.Contexts;
|
||||||
|
import me.lucko.luckperms.api.User;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds cached permission and meta lookup data for a {@link me.lucko.luckperms.api.User}.
|
* Holds cached permission and meta lookup data for a {@link User}.
|
||||||
*
|
*
|
||||||
* <p>Data is only likely to be available for online users. All calls will account for inheritance, as well as any
|
* <p>All calls will account for inheritance, as well as any default data provided by
|
||||||
* default data provided by the platform. This calls are heavily cached and are therefore fast.</p>
|
* the platform. This calls are heavily cached and are therefore fast.</p>
|
||||||
*
|
*
|
||||||
* <p>For meta, both methods accepting {@link Contexts} and {@link MetaContexts} are provided. The only difference is that
|
* <p>For meta, both methods accepting {@link Contexts} and {@link MetaContexts} are provided. The only difference is that
|
||||||
* the latter allows you to define how the meta stack should be structured internally. Where {@link Contexts} are passed, the
|
* the latter allows you to define how the meta stack should be structured internally. Where {@link Contexts} are passed, the
|
||||||
@ -43,143 +40,6 @@ import javax.annotation.Nonnull;
|
|||||||
*
|
*
|
||||||
* @since 2.13
|
* @since 2.13
|
||||||
*/
|
*/
|
||||||
public interface UserData {
|
public interface UserData extends CachedData {
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets PermissionData from the cache, given a specified context.
|
|
||||||
*
|
|
||||||
* <p>If the data is not cached, it is calculated. Therefore, this call could be costly.</p>
|
|
||||||
*
|
|
||||||
* @param contexts the contexts to get the permission data in
|
|
||||||
* @return a permission data instance
|
|
||||||
* @throws NullPointerException if contexts is null
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
PermissionData getPermissionData(@Nonnull Contexts contexts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets MetaData from the cache, given a specified context.
|
|
||||||
*
|
|
||||||
* <p>If the data is not cached, it is calculated. Therefore, this call could be costly.</p>
|
|
||||||
*
|
|
||||||
* @param contexts the contexts to get the permission data in
|
|
||||||
* @return a meta data instance
|
|
||||||
* @throws NullPointerException if contexts is null
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
MetaData getMetaData(@Nonnull MetaContexts contexts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets MetaData from the cache, given a specified context.
|
|
||||||
*
|
|
||||||
* <p>If the data is not cached, it is calculated. Therefore, this call could be costly.</p>
|
|
||||||
*
|
|
||||||
* @param contexts the contexts to get the permission data in
|
|
||||||
* @return a meta data instance
|
|
||||||
* @throws NullPointerException if contexts is null
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
MetaData getMetaData(@Nonnull Contexts contexts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates permission data, bypassing the cache.
|
|
||||||
*
|
|
||||||
* @param contexts the contexts to get permission data in
|
|
||||||
* @return a permission data instance
|
|
||||||
* @throws NullPointerException if contexts is null
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
PermissionData calculatePermissions(@Nonnull Contexts contexts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates meta data, bypassing the cache.
|
|
||||||
*
|
|
||||||
* @param contexts the contexts to get meta data in
|
|
||||||
* @return a meta data instance
|
|
||||||
* @throws NullPointerException if contexts is null
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
MetaData calculateMeta(@Nonnull MetaContexts contexts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates meta data, bypassing the cache.
|
|
||||||
*
|
|
||||||
* @param contexts the contexts to get meta data in
|
|
||||||
* @return a meta data instance
|
|
||||||
* @throws NullPointerException if contexts is null
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
MetaData calculateMeta(@Nonnull Contexts contexts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates permission data and stores it in the cache.
|
|
||||||
*
|
|
||||||
* <p>If there is already data cached for the given contexts, and if the resultant output is different,
|
|
||||||
* the cached value is updated.</p>
|
|
||||||
*
|
|
||||||
* @param contexts the contexts to recalculate in.
|
|
||||||
* @throws NullPointerException if contexts is null
|
|
||||||
*/
|
|
||||||
void recalculatePermissions(@Nonnull Contexts contexts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates meta data and stores it in the cache.
|
|
||||||
*
|
|
||||||
* <p>If there is already data cached for the given contexts, and if the resultant output is different,
|
|
||||||
* the cached value is updated.</p>
|
|
||||||
*
|
|
||||||
* @param contexts the contexts to recalculate in.
|
|
||||||
* @throws NullPointerException if contexts is null
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
void recalculateMeta(@Nonnull MetaContexts contexts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates meta data and stores it in the cache.
|
|
||||||
*
|
|
||||||
* <p>If there is already data cached for the given contexts, and if the resultant output is different,
|
|
||||||
* the cached value is updated.</p>
|
|
||||||
*
|
|
||||||
* @param contexts the contexts to recalculate in.
|
|
||||||
* @throws NullPointerException if contexts is null
|
|
||||||
*/
|
|
||||||
void recalculateMeta(@Nonnull Contexts contexts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls {@link #recalculatePermissions(Contexts)} for all current loaded contexts
|
|
||||||
*/
|
|
||||||
void recalculatePermissions();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls {@link #recalculateMeta(Contexts)} for all current loaded contexts
|
|
||||||
*/
|
|
||||||
void recalculateMeta();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls {@link #preCalculate(Contexts)} for the given contexts
|
|
||||||
*
|
|
||||||
* @param contexts a set of contexts
|
|
||||||
* @throws NullPointerException if contexts is null
|
|
||||||
*/
|
|
||||||
void preCalculate(@Nonnull Set<Contexts> contexts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures that PermissionData and MetaData is cached for a context.
|
|
||||||
*
|
|
||||||
* <p>If the cache does not contain any data for the context, it will be calculated and saved.</p>
|
|
||||||
*
|
|
||||||
* @param contexts the contexts to pre-calculate for
|
|
||||||
* @throws NullPointerException if contexts is null
|
|
||||||
*/
|
|
||||||
void preCalculate(@Nonnull Contexts contexts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidates all of the underlying Permission calculators.
|
|
||||||
*
|
|
||||||
* <p>Can be called to allow for an update in defaults.</p>
|
|
||||||
*/
|
|
||||||
void invalidatePermissionCalculators();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of LuckPerms, licensed under the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.lucko.luckperms.api.event.group;
|
||||||
|
|
||||||
|
import me.lucko.luckperms.api.Group;
|
||||||
|
import me.lucko.luckperms.api.caching.GroupData;
|
||||||
|
import me.lucko.luckperms.api.event.LuckPermsEvent;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a groups {@link GroupData} is loaded.
|
||||||
|
*
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public interface GroupCacheLoadEvent extends LuckPermsEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the group whose data was loaded
|
||||||
|
*
|
||||||
|
* @return the group
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
Group getGroup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the data that was loaded
|
||||||
|
*
|
||||||
|
* @return the loaded data
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
GroupData getLoadedData();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of LuckPerms, licensed under the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.lucko.luckperms.api.event.group;
|
||||||
|
|
||||||
|
import me.lucko.luckperms.api.Group;
|
||||||
|
import me.lucko.luckperms.api.caching.GroupData;
|
||||||
|
import me.lucko.luckperms.api.event.LuckPermsEvent;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a groups cached data is refreshed
|
||||||
|
*
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public interface GroupDataRecalculateEvent extends LuckPermsEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the group whose data was recalculated
|
||||||
|
*
|
||||||
|
* @return the group
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
Group getGroup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the data that was recalculated
|
||||||
|
*
|
||||||
|
* @return the data
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
GroupData getData();
|
||||||
|
|
||||||
|
}
|
@ -36,8 +36,8 @@ import me.lucko.luckperms.bukkit.contexts.WorldCalculator;
|
|||||||
import me.lucko.luckperms.bukkit.listeners.BukkitConnectionListener;
|
import me.lucko.luckperms.bukkit.listeners.BukkitConnectionListener;
|
||||||
import me.lucko.luckperms.bukkit.listeners.BukkitPlatformListener;
|
import me.lucko.luckperms.bukkit.listeners.BukkitPlatformListener;
|
||||||
import me.lucko.luckperms.bukkit.messaging.BukkitMessagingFactory;
|
import me.lucko.luckperms.bukkit.messaging.BukkitMessagingFactory;
|
||||||
import me.lucko.luckperms.bukkit.model.Injector;
|
|
||||||
import me.lucko.luckperms.bukkit.model.LPPermissible;
|
import me.lucko.luckperms.bukkit.model.LPPermissible;
|
||||||
|
import me.lucko.luckperms.bukkit.model.PermissibleInjector;
|
||||||
import me.lucko.luckperms.bukkit.model.SubscriptionMapInjector;
|
import me.lucko.luckperms.bukkit.model.SubscriptionMapInjector;
|
||||||
import me.lucko.luckperms.bukkit.processors.BukkitProcessorsSetupTask;
|
import me.lucko.luckperms.bukkit.processors.BukkitProcessorsSetupTask;
|
||||||
import me.lucko.luckperms.bukkit.processors.ChildPermissionProvider;
|
import me.lucko.luckperms.bukkit.processors.ChildPermissionProvider;
|
||||||
@ -305,7 +305,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
|||||||
scheduler.doSync(() -> {
|
scheduler.doSync(() -> {
|
||||||
try {
|
try {
|
||||||
LPPermissible lpPermissible = new LPPermissible(player, user, this);
|
LPPermissible lpPermissible = new LPPermissible(player, user, this);
|
||||||
Injector.inject(player, lpPermissible);
|
PermissibleInjector.inject(player, lpPermissible);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -335,7 +335,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
|||||||
// uninject from players
|
// uninject from players
|
||||||
for (Player player : getServer().getOnlinePlayers()) {
|
for (Player player : getServer().getOnlinePlayers()) {
|
||||||
try {
|
try {
|
||||||
Injector.unInject(player, false);
|
PermissibleInjector.unInject(player, false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -346,7 +346,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
|||||||
|
|
||||||
final User user = getUserManager().getIfLoaded(getUuidCache().getUUID(player.getUniqueId()));
|
final User user = getUserManager().getIfLoaded(getUuidCache().getUUID(player.getUniqueId()));
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
user.getUserData().invalidateCaches();
|
user.getCachedData().invalidateCaches();
|
||||||
getUserManager().unload(user);
|
getUserManager().unload(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -406,7 +406,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||||
Map<String, Boolean> backing = user.getUserData().getPermissionData(contextManager.getApplicableContexts(player)).getImmutableBacking();
|
Map<String, Boolean> backing = user.getCachedData().getPermissionData(contextManager.getApplicableContexts(player)).getImmutableBacking();
|
||||||
boolean op = Optional.ofNullable(backing.get("luckperms.autoop")).orElse(false);
|
boolean op = Optional.ofNullable(backing.get("luckperms.autoop")).orElse(false);
|
||||||
player.setOp(op);
|
player.setOp(op);
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@ import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
|||||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||||
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||||
import me.lucko.luckperms.common.model.User;
|
|
||||||
import me.lucko.luckperms.common.processors.MapProcessor;
|
import me.lucko.luckperms.common.processors.MapProcessor;
|
||||||
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
||||||
import me.lucko.luckperms.common.processors.RegexProcessor;
|
import me.lucko.luckperms.common.processors.RegexProcessor;
|
||||||
@ -50,7 +49,7 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
|
|||||||
private final LPBukkitPlugin plugin;
|
private final LPBukkitPlugin plugin;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PermissionCalculator build(Contexts contexts, User user) {
|
public PermissionCalculator build(Contexts contexts, PermissionCalculatorMetadata metadata) {
|
||||||
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
|
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
|
||||||
|
|
||||||
processors.add(new MapProcessor());
|
processors.add(new MapProcessor());
|
||||||
@ -71,8 +70,7 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
|
|||||||
processors.add(new DefaultsProcessor(contexts.isOp(), plugin.getDefaultsProvider()));
|
processors.add(new DefaultsProcessor(contexts.isOp(), plugin.getDefaultsProvider()));
|
||||||
}
|
}
|
||||||
|
|
||||||
PermissionCalculatorMetadata meta = PermissionCalculatorMetadata.of(user.getFriendlyName(), contexts.getContexts());
|
return registerCalculator(new PermissionCalculator(plugin, metadata, processors.build()));
|
||||||
return registerCalculator(new PermissionCalculator(plugin, meta, processors.build()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -28,8 +28,8 @@ package me.lucko.luckperms.bukkit.listeners;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||||
import me.lucko.luckperms.bukkit.model.Injector;
|
|
||||||
import me.lucko.luckperms.bukkit.model.LPPermissible;
|
import me.lucko.luckperms.bukkit.model.LPPermissible;
|
||||||
|
import me.lucko.luckperms.bukkit.model.PermissibleInjector;
|
||||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||||
import me.lucko.luckperms.common.locale.Message;
|
import me.lucko.luckperms.common.locale.Message;
|
||||||
import me.lucko.luckperms.common.model.User;
|
import me.lucko.luckperms.common.model.User;
|
||||||
@ -165,7 +165,7 @@ public class BukkitConnectionListener implements Listener {
|
|||||||
LPPermissible lpPermissible = new LPPermissible(player, user, plugin);
|
LPPermissible lpPermissible = new LPPermissible(player, user, plugin);
|
||||||
|
|
||||||
// Inject into the player
|
// Inject into the player
|
||||||
Injector.inject(player, lpPermissible);
|
PermissibleInjector.inject(player, lpPermissible);
|
||||||
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
@ -209,7 +209,7 @@ public class BukkitConnectionListener implements Listener {
|
|||||||
|
|
||||||
// Remove the custom permissible
|
// Remove the custom permissible
|
||||||
try {
|
try {
|
||||||
Injector.unInject(player, true);
|
PermissibleInjector.unInject(player, true);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -96,13 +96,13 @@ public class LPPermissible extends PermissibleBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPermissionSet(@NonNull String permission) {
|
public boolean isPermissionSet(@NonNull String permission) {
|
||||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
Tristate ts = user.getCachedData().getPermissionData(calculateContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||||
return ts != Tristate.UNDEFINED || Permission.DEFAULT_PERMISSION.getValue(isOp());
|
return ts != Tristate.UNDEFINED || Permission.DEFAULT_PERMISSION.getValue(isOp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPermissionSet(@NonNull Permission permission) {
|
public boolean isPermissionSet(@NonNull Permission permission) {
|
||||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
Tristate ts = user.getCachedData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||||
if (ts != Tristate.UNDEFINED) {
|
if (ts != Tristate.UNDEFINED) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -116,13 +116,13 @@ public class LPPermissible extends PermissibleBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPermission(@NonNull String permission) {
|
public boolean hasPermission(@NonNull String permission) {
|
||||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
Tristate ts = user.getCachedData().getPermissionData(calculateContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
||||||
return ts != Tristate.UNDEFINED ? ts.asBoolean() : Permission.DEFAULT_PERMISSION.getValue(isOp());
|
return ts != Tristate.UNDEFINED ? ts.asBoolean() : Permission.DEFAULT_PERMISSION.getValue(isOp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPermission(@NonNull Permission permission) {
|
public boolean hasPermission(@NonNull Permission permission) {
|
||||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
Tristate ts = user.getCachedData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
||||||
if (ts != Tristate.UNDEFINED) {
|
if (ts != Tristate.UNDEFINED) {
|
||||||
return ts.asBoolean();
|
return ts.asBoolean();
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ public class LPPermissible extends PermissibleBase {
|
|||||||
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||||
perms.addAll(
|
perms.addAll(
|
||||||
user.getUserData().getPermissionData(calculateContexts()).getImmutableBacking().entrySet().stream()
|
user.getCachedData().getPermissionData(calculateContexts()).getImmutableBacking().entrySet().stream()
|
||||||
.map(e -> new PermissionAttachmentInfo(player, e.getKey(), null, e.getValue()))
|
.map(e -> new PermissionAttachmentInfo(player, e.getKey(), null, e.getValue()))
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
);
|
);
|
||||||
|
@ -36,7 +36,6 @@ import me.lucko.luckperms.common.model.User;
|
|||||||
import me.lucko.luckperms.common.node.ImmutableTransientNode;
|
import me.lucko.luckperms.common.node.ImmutableTransientNode;
|
||||||
import me.lucko.luckperms.common.node.NodeFactory;
|
import me.lucko.luckperms.common.node.NodeFactory;
|
||||||
|
|
||||||
import org.bukkit.permissions.PermissibleBase;
|
|
||||||
import org.bukkit.permissions.PermissionAttachment;
|
import org.bukkit.permissions.PermissionAttachment;
|
||||||
import org.bukkit.permissions.PermissionRemovedExecutor;
|
import org.bukkit.permissions.PermissionRemovedExecutor;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
@ -64,7 +63,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
|||||||
static {
|
static {
|
||||||
Field permissionAttachmentPermissionsField;
|
Field permissionAttachmentPermissionsField;
|
||||||
try {
|
try {
|
||||||
permissionAttachmentPermissionsField = PermissibleBase.class.getDeclaredField("permissions");
|
permissionAttachmentPermissionsField = PermissionAttachment.class.getDeclaredField("permissions");
|
||||||
permissionAttachmentPermissionsField.setAccessible(true);
|
permissionAttachmentPermissionsField.setAccessible(true);
|
||||||
} catch (NoSuchFieldException e) {
|
} catch (NoSuchFieldException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@ -131,9 +130,8 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
|||||||
FakeBackingMap fakeMap = new FakeBackingMap();
|
FakeBackingMap fakeMap = new FakeBackingMap();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// what's this doing, ay?
|
// the field we need to modify is in the superclass - it has private
|
||||||
// the field we need to modify is in the superclass - it's set to private
|
// and final modifiers so we have to use reflection to modify it.
|
||||||
// so we have to use reflection to modify it.
|
|
||||||
PERMISSION_ATTACHMENT_PERMISSIONS_FIELD.set(this, fakeMap);
|
PERMISSION_ATTACHMENT_PERMISSIONS_FIELD.set(this, fakeMap);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -172,7 +170,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
|||||||
// set the transient node
|
// set the transient node
|
||||||
User user = permissible.getUser();
|
User user = permissible.getUser();
|
||||||
if (user.setTransientPermission(transientNode).asBoolean()) {
|
if (user.setTransientPermission(transientNode).asBoolean()) {
|
||||||
user.getRefreshBuffer().request();
|
user.reloadCachedData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +182,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
|||||||
// remove transient permissions from the holder which were added by this attachment & equal the permission
|
// remove transient permissions from the holder which were added by this attachment & equal the permission
|
||||||
User user = permissible.getUser();
|
User user = permissible.getUser();
|
||||||
if (user.removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name))) {
|
if (user.removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name))) {
|
||||||
user.getRefreshBuffer().request();
|
user.reloadCachedData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +190,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
|||||||
// remove all transient permissions added by this attachment
|
// remove all transient permissions added by this attachment
|
||||||
User user = permissible.getUser();
|
User user = permissible.getUser();
|
||||||
if (user.removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this)) {
|
if (user.removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this)) {
|
||||||
user.getRefreshBuffer().request();
|
user.reloadCachedData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +226,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we're not hooked, thn don't actually apply the change
|
// if we're not hooked, then don't actually apply the change
|
||||||
// it will get applied on hook - if that ever happens
|
// it will get applied on hook - if that ever happens
|
||||||
if (!hooked) {
|
if (!hooked) {
|
||||||
return;
|
return;
|
||||||
@ -253,7 +251,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we're not hooked, thn don't actually apply the change
|
// if we're not hooked, then don't actually apply the change
|
||||||
// it will get applied on hook - if that ever happens
|
// it will get applied on hook - if that ever happens
|
||||||
if (!hooked) {
|
if (!hooked) {
|
||||||
return;
|
return;
|
||||||
@ -296,7 +294,6 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean put(String key, Boolean value) {
|
public Boolean put(String key, Boolean value) {
|
||||||
|
|
||||||
// grab the previous result, so we can still satisfy the method signature of Map
|
// grab the previous result, so we can still satisfy the method signature of Map
|
||||||
Boolean previous = perms.get(key);
|
Boolean previous = perms.get(key);
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ public class LPSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// then try the map, if we haven't already
|
// then try the permissible, if we haven't already
|
||||||
if (!isPlayer && key instanceof Permissible) {
|
if (!isPlayer && key instanceof Permissible) {
|
||||||
Permissible p = (Permissible) key;
|
Permissible p = (Permissible) key;
|
||||||
if (p.isPermissionSet(permission)) {
|
if (p.isPermissionSet(permission)) {
|
||||||
@ -195,8 +195,8 @@ public class LPSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsKey(Object key) {
|
public boolean containsKey(Object key) {
|
||||||
// check the backing map, as well as if the permissible has the perm set
|
// delegate through the get method
|
||||||
return backing.containsKey(key) || (key instanceof Permissible && ((Permissible) key).isPermissionSet(permission));
|
return get(key) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -43,7 +43,7 @@ import java.util.List;
|
|||||||
* checks made by plugins.
|
* checks made by plugins.
|
||||||
*/
|
*/
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class Injector {
|
public class PermissibleInjector {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All permission checks made on standard Bukkit objects are effectively proxied to a
|
* All permission checks made on standard Bukkit objects are effectively proxied to a
|
@ -304,7 +304,7 @@ public class VaultChatHook extends Chat {
|
|||||||
world = perms.correctWorld(world);
|
world = perms.correctWorld(world);
|
||||||
perms.log("Getting meta: '" + node + "' for user " + user.getFriendlyName() + " on world " + world + ", server " + perms.getServer());
|
perms.log("Getting meta: '" + node + "' for user " + user.getFriendlyName() + " on world " + world + ", server " + perms.getServer());
|
||||||
|
|
||||||
String ret = user.getUserData().getMetaData(perms.createContextForWorldLookup(perms.getPlugin().getPlayer(user), world)).getMeta().get(node);
|
String ret = user.getCachedData().getMetaData(perms.createContextForWorldLookup(perms.getPlugin().getPlayer(user), world)).getMeta().get(node);
|
||||||
return ret != null ? ret : defaultValue;
|
return ret != null ? ret : defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +316,7 @@ public class VaultChatHook extends Chat {
|
|||||||
world = perms.correctWorld(world);
|
world = perms.correctWorld(world);
|
||||||
perms.log("Getting " + type.name().toLowerCase() + " for user " + user.getFriendlyName() + " on world " + world + ", server " + perms.getServer());
|
perms.log("Getting " + type.name().toLowerCase() + " for user " + user.getFriendlyName() + " on world " + world + ", server " + perms.getServer());
|
||||||
|
|
||||||
MetaData data = user.getUserData().getMetaData(perms.createContextForWorldLookup(perms.getPlugin().getPlayer(user), world));
|
MetaData data = user.getCachedData().getMetaData(perms.createContextForWorldLookup(perms.getPlugin().getPlayer(user), world));
|
||||||
String ret = type == ChatMetaType.PREFIX ? data.getPrefix() : data.getSuffix();
|
String ret = type == ChatMetaType.PREFIX ? data.getPrefix() : data.getSuffix();
|
||||||
return ret != null ? ret : "";
|
return ret != null ? ret : "";
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ public class VaultPermissionHook extends Permission {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Effectively fallback to the standard Bukkit #hasPermission check.
|
// Effectively fallback to the standard Bukkit #hasPermission check.
|
||||||
return user.getUserData().getPermissionData(createContextForWorldLookup(player, world)).getPermissionValue(permission, CheckOrigin.INTERNAL).asBoolean();
|
return user.getCachedData().getPermissionData(createContextForWorldLookup(player, world)).getPermissionValue(permission, CheckOrigin.INTERNAL).asBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -54,16 +54,16 @@ public class BungeeConfigAdapter implements ConfigurationAdapter {
|
|||||||
|
|
||||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||||
private File makeFile(String file) throws IOException {
|
private File makeFile(String file) throws IOException {
|
||||||
File cfg = new File(plugin.getDataFolder(), file);
|
File configFile = new File(plugin.getDataFolder(), file);
|
||||||
|
|
||||||
if (!cfg.exists()) {
|
if (!configFile.exists()) {
|
||||||
plugin.getDataFolder().mkdir();
|
plugin.getDataFolder().mkdir();
|
||||||
try (InputStream is = plugin.getResourceAsStream(file)) {
|
try (InputStream is = plugin.getResourceAsStream(file)) {
|
||||||
Files.copy(is, cfg.toPath());
|
Files.copy(is, configFile.toPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cfg;
|
return configFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -35,7 +35,6 @@ import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
|||||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||||
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||||
import me.lucko.luckperms.common.model.User;
|
|
||||||
import me.lucko.luckperms.common.processors.MapProcessor;
|
import me.lucko.luckperms.common.processors.MapProcessor;
|
||||||
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
||||||
import me.lucko.luckperms.common.processors.RegexProcessor;
|
import me.lucko.luckperms.common.processors.RegexProcessor;
|
||||||
@ -48,7 +47,7 @@ public class BungeeCalculatorFactory extends AbstractCalculatorFactory {
|
|||||||
private final LPBungeePlugin plugin;
|
private final LPBungeePlugin plugin;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PermissionCalculator build(Contexts contexts, User user) {
|
public PermissionCalculator build(Contexts contexts, PermissionCalculatorMetadata metadata) {
|
||||||
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
|
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
|
||||||
|
|
||||||
processors.add(new MapProcessor());
|
processors.add(new MapProcessor());
|
||||||
@ -61,8 +60,7 @@ public class BungeeCalculatorFactory extends AbstractCalculatorFactory {
|
|||||||
processors.add(new WildcardProcessor());
|
processors.add(new WildcardProcessor());
|
||||||
}
|
}
|
||||||
|
|
||||||
PermissionCalculatorMetadata meta = PermissionCalculatorMetadata.of(user.getFriendlyName(), contexts.getContexts());
|
return registerCalculator(new PermissionCalculator(plugin, metadata, processors.build()));
|
||||||
return registerCalculator(new PermissionCalculator(plugin, meta, processors.build()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -60,7 +60,7 @@ public class BungeePermissionCheckListener implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Contexts contexts = plugin.getContextManager().getApplicableContexts(player);
|
Contexts contexts = plugin.getContextManager().getApplicableContexts(player);
|
||||||
Tristate result = user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission(), CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
Tristate result = user.getCachedData().getPermissionData(contexts).getPermissionValue(e.getPermission(), CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
||||||
if (result == Tristate.UNDEFINED && plugin.getConfiguration().get(ConfigKeys.APPLY_BUNGEE_CONFIG_PERMISSIONS)) {
|
if (result == Tristate.UNDEFINED && plugin.getConfiguration().get(ConfigKeys.APPLY_BUNGEE_CONFIG_PERMISSIONS)) {
|
||||||
return; // just use the result provided by the proxy when the event was created
|
return; // just use the result provided by the proxy when the event was created
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ public class BungeePermissionCheckListener implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Contexts contexts = plugin.getContextManager().getApplicableContexts(player);
|
Contexts contexts = plugin.getContextManager().getApplicableContexts(player);
|
||||||
Tristate result = user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission(), CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
Tristate result = user.getCachedData().getPermissionData(contexts).getPermissionValue(e.getPermission(), CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||||
if (result == Tristate.UNDEFINED && plugin.getConfiguration().get(ConfigKeys.APPLY_BUNGEE_CONFIG_PERMISSIONS)) {
|
if (result == Tristate.UNDEFINED && plugin.getConfiguration().get(ConfigKeys.APPLY_BUNGEE_CONFIG_PERMISSIONS)) {
|
||||||
return; // just use the result provided by the proxy when the event was created
|
return; // just use the result provided by the proxy when the event was created
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,10 @@ import lombok.NonNull;
|
|||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
import me.lucko.luckperms.api.Group;
|
import me.lucko.luckperms.api.Group;
|
||||||
|
import me.lucko.luckperms.api.caching.GroupData;
|
||||||
|
|
||||||
import java.util.OptionalInt;
|
import java.util.OptionalInt;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public final class ApiGroup extends ApiPermissionHolder implements Group {
|
public final class ApiGroup extends ApiPermissionHolder implements Group {
|
||||||
public static me.lucko.luckperms.common.model.Group cast(Group g) {
|
public static me.lucko.luckperms.common.model.Group cast(Group g) {
|
||||||
@ -59,6 +61,16 @@ public final class ApiGroup extends ApiPermissionHolder implements Group {
|
|||||||
return handle.getWeight();
|
return handle.getWeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupData getCachedData() {
|
||||||
|
return handle.getCachedData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Void> refreshCachedData() {
|
||||||
|
return handle.getRefreshBuffer().request();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (o == this) return true;
|
if (o == this) return true;
|
||||||
if (!(o instanceof ApiGroup)) return false;
|
if (!(o instanceof ApiGroup)) return false;
|
||||||
|
@ -38,6 +38,7 @@ import me.lucko.luckperms.api.LocalizedNode;
|
|||||||
import me.lucko.luckperms.api.Node;
|
import me.lucko.luckperms.api.Node;
|
||||||
import me.lucko.luckperms.api.PermissionHolder;
|
import me.lucko.luckperms.api.PermissionHolder;
|
||||||
import me.lucko.luckperms.api.Tristate;
|
import me.lucko.luckperms.api.Tristate;
|
||||||
|
import me.lucko.luckperms.api.caching.CachedData;
|
||||||
import me.lucko.luckperms.api.context.ContextSet;
|
import me.lucko.luckperms.api.context.ContextSet;
|
||||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||||
import me.lucko.luckperms.common.model.Group;
|
import me.lucko.luckperms.common.model.Group;
|
||||||
@ -71,6 +72,11 @@ public class ApiPermissionHolder implements PermissionHolder {
|
|||||||
return handle.getFriendlyName();
|
return handle.getFriendlyName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CachedData getCachedData() {
|
||||||
|
return handle.getCachedData();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImmutableSetMultimap<ImmutableContextSet, Node> getNodes() {
|
public ImmutableSetMultimap<ImmutableContextSet, Node> getNodes() {
|
||||||
return handle.getEnduringNodes();
|
return handle.getEnduringNodes();
|
||||||
|
@ -82,7 +82,7 @@ public final class ApiUser extends ApiPermissionHolder implements User {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserData getCachedData() {
|
public UserData getCachedData() {
|
||||||
return handle.getUserData();
|
return handle.getCachedData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.caching;
|
||||||
|
|
||||||
|
import me.lucko.luckperms.api.caching.GroupData;
|
||||||
|
import me.lucko.luckperms.common.model.Group;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds an easily accessible cache of a groups's data in a number of contexts
|
||||||
|
*/
|
||||||
|
public class GroupCache extends HolderCache<Group> implements GroupData {
|
||||||
|
|
||||||
|
public GroupCache(Group holder) {
|
||||||
|
super(holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getHolderName() {
|
||||||
|
return holder.getName();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,295 @@
|
|||||||
|
/*
|
||||||
|
* 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.caching;
|
||||||
|
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
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.api.ChatMetaType;
|
||||||
|
import me.lucko.luckperms.api.Contexts;
|
||||||
|
import me.lucko.luckperms.api.caching.CachedData;
|
||||||
|
import me.lucko.luckperms.api.caching.MetaContexts;
|
||||||
|
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||||
|
import me.lucko.luckperms.common.metastacking.SimpleMetaStack;
|
||||||
|
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||||
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds an easily accessible cache of a holders data in a number of contexts
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public abstract class HolderCache<T extends PermissionHolder> implements CachedData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The holder whom this data instance is representing
|
||||||
|
*/
|
||||||
|
protected final T holder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cache used for {@link PermissionCache} instances.
|
||||||
|
*/
|
||||||
|
private final LoadingCache<Contexts, PermissionCache> permission = Caffeine.newBuilder()
|
||||||
|
.expireAfterAccess(2, TimeUnit.MINUTES)
|
||||||
|
.build(new PermissionCacheLoader());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cache used for {@link MetaCache} instances.
|
||||||
|
*/
|
||||||
|
private final LoadingCache<MetaContexts, MetaCache> meta = Caffeine.newBuilder()
|
||||||
|
.expireAfterAccess(2, TimeUnit.MINUTES)
|
||||||
|
.build(new MetaCacheLoader());
|
||||||
|
|
||||||
|
protected abstract String getHolderName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates a {@link PermissionCache} instance.
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to calculate in
|
||||||
|
* @param data an old data instance to try to reuse - ignored if null
|
||||||
|
* @return the calculated instance
|
||||||
|
*/
|
||||||
|
private PermissionCache calculatePermissions(@NonNull Contexts contexts, PermissionCache data) {
|
||||||
|
if (data == null) {
|
||||||
|
data = new PermissionCache(contexts, getHolderName(), holder.getPlugin().getCalculatorFactory());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contexts == Contexts.allowAll()) {
|
||||||
|
data.setPermissions(holder.exportNodesAndShorthand(true));
|
||||||
|
} else {
|
||||||
|
data.setPermissions(holder.exportNodesAndShorthand(contexts, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates a {@link MetaCache} instance.
|
||||||
|
*
|
||||||
|
* @param contexts the contexts to calculate in
|
||||||
|
* @param data an old data instance to try to reuse - ignored if null
|
||||||
|
* @return the calculated instance
|
||||||
|
*/
|
||||||
|
private MetaCache calculateMeta(@NonNull MetaContexts contexts, MetaCache data) {
|
||||||
|
if (data == null) {
|
||||||
|
data = new MetaCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contexts.getContexts() == Contexts.allowAll()) {
|
||||||
|
data.loadMeta(holder.accumulateMeta(newAccumulator(contexts), null));
|
||||||
|
} else {
|
||||||
|
data.loadMeta(holder.accumulateMeta(newAccumulator(contexts), null, contexts.getContexts()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PermissionCache getPermissionData(@NonNull Contexts contexts) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return permission.get(contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MetaCache getMetaData(@NonNull MetaContexts contexts) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return meta.get(contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MetaCache getMetaData(@NonNull Contexts contexts) {
|
||||||
|
return getMetaData(makeFromMetaContextsConfig(contexts, holder.getPlugin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PermissionCache calculatePermissions(@NonNull Contexts contexts) {
|
||||||
|
return calculatePermissions(contexts, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MetaCache calculateMeta(@NonNull MetaContexts contexts) {
|
||||||
|
return calculateMeta(contexts, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MetaCache calculateMeta(@NonNull Contexts contexts) {
|
||||||
|
return calculateMeta(makeFromMetaContextsConfig(contexts, holder.getPlugin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recalculatePermissions(@NonNull Contexts contexts) {
|
||||||
|
permission.refresh(contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recalculateMeta(@NonNull MetaContexts contexts) {
|
||||||
|
meta.refresh(contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recalculateMeta(@NonNull Contexts contexts) {
|
||||||
|
recalculateMeta(makeFromMetaContextsConfig(contexts, holder.getPlugin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<PermissionCache> reloadPermissions(@NonNull Contexts contexts) {
|
||||||
|
// get the previous value - to use when recalculating
|
||||||
|
PermissionCache previous = permission.getIfPresent(contexts);
|
||||||
|
|
||||||
|
// invalidate the entry
|
||||||
|
permission.invalidate(contexts);
|
||||||
|
|
||||||
|
// repopulate the cache
|
||||||
|
return CompletableFuture.supplyAsync(() -> permission.get(contexts, c -> calculatePermissions(c, previous)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<MetaCache> reloadMeta(@NonNull MetaContexts contexts) {
|
||||||
|
// get the previous value - to use when recalculating
|
||||||
|
MetaCache previous = meta.getIfPresent(contexts);
|
||||||
|
|
||||||
|
// invalidate the entry
|
||||||
|
meta.invalidate(contexts);
|
||||||
|
|
||||||
|
// repopulate the cache
|
||||||
|
return CompletableFuture.supplyAsync(() -> meta.get(contexts, c -> calculateMeta(c, previous)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<MetaCache> reloadMeta(@NonNull Contexts contexts) {
|
||||||
|
return reloadMeta(makeFromMetaContextsConfig(contexts, holder.getPlugin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recalculatePermissions() {
|
||||||
|
Set<Contexts> keys = permission.asMap().keySet();
|
||||||
|
keys.forEach(this::recalculatePermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recalculateMeta() {
|
||||||
|
Set<MetaContexts> keys = meta.asMap().keySet();
|
||||||
|
keys.forEach(this::recalculateMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Void> reloadPermissions() {
|
||||||
|
Set<Contexts> keys = new HashSet<>(permission.asMap().keySet());
|
||||||
|
return CompletableFuture.allOf(keys.stream().map(this::reloadPermissions).toArray(CompletableFuture[]::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Void> reloadMeta() {
|
||||||
|
Set<MetaContexts> keys = new HashSet<>(meta.asMap().keySet());
|
||||||
|
return CompletableFuture.allOf(keys.stream().map(this::reloadMeta).toArray(CompletableFuture[]::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preCalculate(@NonNull Contexts contexts) {
|
||||||
|
// pre-calculate just by requesting the data from this cache.
|
||||||
|
// if the data isn't already loaded, it will be calculated.
|
||||||
|
getPermissionData(contexts);
|
||||||
|
getMetaData(contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidatePermissions(Contexts contexts) {
|
||||||
|
permission.invalidate(contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidateMeta(MetaContexts contexts) {
|
||||||
|
meta.invalidate(contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidateMeta(Contexts contexts) {
|
||||||
|
meta.invalidate(makeFromMetaContextsConfig(contexts, holder.getPlugin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidatePermissionCalculators() {
|
||||||
|
permission.asMap().values().forEach(PermissionCache::invalidateCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalidateCaches() {
|
||||||
|
permission.invalidateAll();
|
||||||
|
meta.invalidateAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doCacheCleanup() {
|
||||||
|
permission.cleanUp();
|
||||||
|
meta.cleanUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class PermissionCacheLoader implements CacheLoader<Contexts, PermissionCache> {
|
||||||
|
@Override
|
||||||
|
public PermissionCache load(Contexts contexts) {
|
||||||
|
return calculatePermissions(contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PermissionCache reload(Contexts contexts, PermissionCache oldData) {
|
||||||
|
return calculatePermissions(contexts, oldData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class MetaCacheLoader implements CacheLoader<MetaContexts, MetaCache> {
|
||||||
|
@Override
|
||||||
|
public MetaCache load(MetaContexts contexts) {
|
||||||
|
return calculateMeta(contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MetaCache reload(MetaContexts contexts, MetaCache oldData) {
|
||||||
|
return calculateMeta(contexts, oldData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MetaContexts makeFromMetaContextsConfig(Contexts contexts, LuckPermsPlugin plugin) {
|
||||||
|
return new MetaContexts(
|
||||||
|
contexts,
|
||||||
|
plugin.getConfiguration().get(ConfigKeys.PREFIX_FORMATTING_OPTIONS),
|
||||||
|
plugin.getConfiguration().get(ConfigKeys.SUFFIX_FORMATTING_OPTIONS)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MetaAccumulator newAccumulator(MetaContexts contexts) {
|
||||||
|
return new MetaAccumulator(
|
||||||
|
new SimpleMetaStack(contexts.getPrefixStackDefinition(), ChatMetaType.PREFIX),
|
||||||
|
new SimpleMetaStack(contexts.getSuffixStackDefinition(), ChatMetaType.SUFFIX)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -45,7 +45,7 @@ import java.util.concurrent.locks.ReadWriteLock;
|
|||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds a user's cached meta for a given context
|
* Holds cached meta for a given context
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
|
@ -32,7 +32,7 @@ import me.lucko.luckperms.api.Tristate;
|
|||||||
import me.lucko.luckperms.api.caching.PermissionData;
|
import me.lucko.luckperms.api.caching.PermissionData;
|
||||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||||
import me.lucko.luckperms.common.model.User;
|
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -40,7 +40,7 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds a user's cached permissions for a given context
|
* Holds cached permissions data for a given context
|
||||||
*/
|
*/
|
||||||
public class PermissionCache implements PermissionData {
|
public class PermissionCache implements PermissionData {
|
||||||
|
|
||||||
@ -61,11 +61,13 @@ public class PermissionCache implements PermissionData {
|
|||||||
*/
|
*/
|
||||||
private final PermissionCalculator calculator;
|
private final PermissionCalculator calculator;
|
||||||
|
|
||||||
public PermissionCache(Contexts contexts, User user, CalculatorFactory calculatorFactory) {
|
public PermissionCache(Contexts contexts, String friendlyName, CalculatorFactory calculatorFactory) {
|
||||||
permissions = new ConcurrentHashMap<>();
|
permissions = new ConcurrentHashMap<>();
|
||||||
permissionsUnmodifiable = Collections.unmodifiableMap(permissions);
|
permissionsUnmodifiable = Collections.unmodifiableMap(permissions);
|
||||||
|
|
||||||
calculator = calculatorFactory.build(contexts, user);
|
PermissionCalculatorMetadata metadata = PermissionCalculatorMetadata.of(friendlyName, contexts.getContexts());
|
||||||
|
|
||||||
|
calculator = calculatorFactory.build(contexts, metadata);
|
||||||
calculator.updateBacking(permissions); // Initial setup.
|
calculator.updateBacking(permissions); // Initial setup.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,16 +76,16 @@ public class PermissionCache implements PermissionData {
|
|||||||
calculator.invalidateCache();
|
calculator.invalidateCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPermissions(Map<String, Boolean> permissions) {
|
private void setPermissionsInternal(Map<String, Boolean> permissions) {
|
||||||
this.permissions.clear();
|
this.permissions.clear();
|
||||||
this.permissions.putAll(permissions);
|
this.permissions.putAll(permissions);
|
||||||
calculator.updateBacking(this.permissions);
|
calculator.updateBacking(this.permissions);
|
||||||
invalidateCache();
|
invalidateCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void comparePermissions(Map<String, Boolean> toApply) {
|
public void setPermissions(Map<String, Boolean> toApply) {
|
||||||
if (!permissions.equals(toApply)) {
|
if (!permissions.equals(toApply)) {
|
||||||
setPermissions(toApply);
|
setPermissionsInternal(toApply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,198 +25,20 @@
|
|||||||
|
|
||||||
package me.lucko.luckperms.common.caching;
|
package me.lucko.luckperms.common.caching;
|
||||||
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
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.api.ChatMetaType;
|
|
||||||
import me.lucko.luckperms.api.Contexts;
|
|
||||||
import me.lucko.luckperms.api.caching.MetaContexts;
|
|
||||||
import me.lucko.luckperms.api.caching.UserData;
|
import me.lucko.luckperms.api.caching.UserData;
|
||||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
|
||||||
import me.lucko.luckperms.common.metastacking.SimpleMetaStack;
|
|
||||||
import me.lucko.luckperms.common.model.User;
|
import me.lucko.luckperms.common.model.User;
|
||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds an easily accessible cache of a user's data in a number of contexts
|
* Holds an easily accessible cache of a user's data in a number of contexts
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
public class UserCache extends HolderCache<User> implements UserData {
|
||||||
public class UserCache implements UserData {
|
|
||||||
|
|
||||||
/**
|
public UserCache(User holder) {
|
||||||
* The user whom this data instance is representing
|
super(holder);
|
||||||
*/
|
|
||||||
private final User user;
|
|
||||||
|
|
||||||
private final LoadingCache<Contexts, PermissionCache> permission = Caffeine.newBuilder()
|
|
||||||
.expireAfterAccess(2, TimeUnit.MINUTES)
|
|
||||||
.build(new PermissionCacheLoader());
|
|
||||||
|
|
||||||
private final LoadingCache<MetaContexts, MetaCache> meta = Caffeine.newBuilder()
|
|
||||||
.expireAfterAccess(2, TimeUnit.MINUTES)
|
|
||||||
.build(new MetaCacheLoader());
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PermissionCache getPermissionData(@NonNull Contexts contexts) {
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
return permission.get(contexts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MetaCache getMetaData(@NonNull MetaContexts contexts) {
|
protected String getHolderName() {
|
||||||
//noinspection ConstantConditions
|
return holder.getFriendlyName();
|
||||||
return meta.get(contexts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public MetaCache getMetaData(@NonNull Contexts contexts) {
|
|
||||||
// just create a MetaContexts instance using the values in the config
|
|
||||||
return getMetaData(makeFromMetaContextsConfig(contexts, user.getPlugin()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PermissionCache calculatePermissions(@NonNull Contexts contexts) {
|
|
||||||
PermissionCache data = new PermissionCache(contexts, user, user.getPlugin().getCalculatorFactory());
|
|
||||||
|
|
||||||
if (contexts == Contexts.allowAll()) {
|
|
||||||
data.setPermissions(user.exportNodesAndShorthand(true));
|
|
||||||
} else {
|
|
||||||
data.setPermissions(user.exportNodesAndShorthand(contexts, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MetaCache calculateMeta(@NonNull MetaContexts contexts) {
|
|
||||||
MetaCache data = new MetaCache();
|
|
||||||
|
|
||||||
if (contexts.getContexts() == Contexts.allowAll()) {
|
|
||||||
data.loadMeta(user.accumulateMeta(newAccumulator(contexts), null));
|
|
||||||
} else {
|
|
||||||
data.loadMeta(user.accumulateMeta(newAccumulator(contexts), null, contexts.getContexts()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MetaCache calculateMeta(@NonNull Contexts contexts) {
|
|
||||||
// just create a MetaContexts instance using the values in the config
|
|
||||||
return calculateMeta(makeFromMetaContextsConfig(contexts, user.getPlugin()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void recalculatePermissions(@NonNull Contexts contexts) {
|
|
||||||
permission.refresh(contexts);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void recalculateMeta(@NonNull MetaContexts contexts) {
|
|
||||||
meta.refresh(contexts);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void recalculateMeta(@NonNull Contexts contexts) {
|
|
||||||
recalculateMeta(makeFromMetaContextsConfig(contexts, user.getPlugin()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void recalculatePermissions() {
|
|
||||||
Set<Contexts> keys = permission.asMap().keySet();
|
|
||||||
keys.forEach(this::recalculatePermissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void recalculateMeta() {
|
|
||||||
Set<MetaContexts> keys = meta.asMap().keySet();
|
|
||||||
keys.forEach(this::recalculateMeta);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void preCalculate(@NonNull Set<Contexts> contexts) {
|
|
||||||
contexts.forEach(this::preCalculate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void preCalculate(@NonNull Contexts contexts) {
|
|
||||||
// pre-calculate just by requesting the data from this cache.
|
|
||||||
// if the data isn't already loaded, it will be calculated.
|
|
||||||
getPermissionData(contexts);
|
|
||||||
getMetaData(contexts);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void invalidateCaches() {
|
|
||||||
permission.invalidateAll();
|
|
||||||
meta.invalidateAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invalidatePermissionCalculators() {
|
|
||||||
permission.asMap().values().forEach(PermissionCache::invalidateCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doCacheCleanup() {
|
|
||||||
permission.cleanUp();
|
|
||||||
meta.cleanUp();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class PermissionCacheLoader implements CacheLoader<Contexts, PermissionCache> {
|
|
||||||
@Override
|
|
||||||
public PermissionCache load(Contexts contexts) {
|
|
||||||
return calculatePermissions(contexts);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PermissionCache reload(Contexts contexts, PermissionCache oldData) {
|
|
||||||
if (contexts == Contexts.allowAll()) {
|
|
||||||
oldData.comparePermissions(user.exportNodesAndShorthand(true));
|
|
||||||
} else {
|
|
||||||
oldData.comparePermissions(user.exportNodesAndShorthand(contexts, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
return oldData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class MetaCacheLoader implements CacheLoader<MetaContexts, MetaCache> {
|
|
||||||
@Override
|
|
||||||
public MetaCache load(MetaContexts contexts) {
|
|
||||||
return calculateMeta(contexts);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MetaCache reload(MetaContexts contexts, MetaCache oldData) {
|
|
||||||
if (contexts.getContexts() == Contexts.allowAll()) {
|
|
||||||
oldData.loadMeta(user.accumulateMeta(newAccumulator(contexts), null));
|
|
||||||
} else {
|
|
||||||
oldData.loadMeta(user.accumulateMeta(newAccumulator(contexts), null, contexts.getContexts()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return oldData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MetaContexts makeFromMetaContextsConfig(Contexts contexts, LuckPermsPlugin plugin) {
|
|
||||||
return new MetaContexts(
|
|
||||||
contexts,
|
|
||||||
plugin.getConfiguration().get(ConfigKeys.PREFIX_FORMATTING_OPTIONS),
|
|
||||||
plugin.getConfiguration().get(ConfigKeys.SUFFIX_FORMATTING_OPTIONS)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MetaAccumulator newAccumulator(MetaContexts contexts) {
|
|
||||||
return new MetaAccumulator(
|
|
||||||
new SimpleMetaStack(contexts.getPrefixStackDefinition(), ChatMetaType.PREFIX),
|
|
||||||
new SimpleMetaStack(contexts.getSuffixStackDefinition(), ChatMetaType.SUFFIX)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
package me.lucko.luckperms.common.calculators;
|
package me.lucko.luckperms.common.calculators;
|
||||||
|
|
||||||
import me.lucko.luckperms.api.Contexts;
|
import me.lucko.luckperms.api.Contexts;
|
||||||
import me.lucko.luckperms.common.model.User;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -39,10 +38,10 @@ public interface CalculatorFactory {
|
|||||||
* Builds a PermissionCalculator for the user in the given context
|
* Builds a PermissionCalculator for the user in the given context
|
||||||
*
|
*
|
||||||
* @param contexts the contexts to build the calculator in
|
* @param contexts the contexts to build the calculator in
|
||||||
* @param user the user to build for
|
* @param metadata the calculator metadata
|
||||||
* @return a permission calculator instance
|
* @return a permission calculator instance
|
||||||
*/
|
*/
|
||||||
PermissionCalculator build(Contexts contexts, User user);
|
PermissionCalculator build(Contexts contexts, PermissionCalculatorMetadata metadata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the processors which are currently being added to built calculators
|
* Gets the processors which are currently being added to built calculators
|
||||||
|
@ -68,7 +68,7 @@ public class CheckCommand extends SingleCommand {
|
|||||||
return CommandResult.STATE_ERROR;
|
return CommandResult.STATE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tristate tristate = user.getUserData().getPermissionData(plugin.getContextForUser(user)).getPermissionValue(permission, CheckOrigin.INTERNAL);
|
Tristate tristate = user.getCachedData().getPermissionData(plugin.getContextForUser(user)).getPermissionValue(permission, CheckOrigin.INTERNAL);
|
||||||
Message.CHECK_RESULT.send(sender, user.getFriendlyName(), permission, Util.formatTristate(tristate));
|
Message.CHECK_RESULT.send(sender, user.getFriendlyName(), permission, Util.formatTristate(tristate));
|
||||||
return CommandResult.SUCCESS;
|
return CommandResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ public class TreeCommand extends SingleCommand {
|
|||||||
return CommandResult.STATE_ERROR;
|
return CommandResult.STATE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
PermissionCache permissionData = user.getUserData().getPermissionData(plugin.getContextForUser(user));
|
PermissionCache permissionData = user.getCachedData().getPermissionData(plugin.getContextForUser(user));
|
||||||
TreeView view = TreeViewBuilder.newBuilder().rootPosition(selection).maxLevels(maxLevel).build(plugin.getPermissionVault());
|
TreeView view = TreeViewBuilder.newBuilder().rootPosition(selection).maxLevels(maxLevel).build(plugin.getPermissionVault());
|
||||||
|
|
||||||
if (!view.hasData()) {
|
if (!view.hasData()) {
|
||||||
|
@ -106,7 +106,7 @@ public class UserInfo extends SubCommand<User> {
|
|||||||
.map(e -> Util.contextToString(e.getKey(), e.getValue()))
|
.map(e -> Util.contextToString(e.getKey(), e.getValue()))
|
||||||
.collect(Collectors.joining(" "));
|
.collect(Collectors.joining(" "));
|
||||||
|
|
||||||
MetaData meta = user.getUserData().getMetaData(contexts);
|
MetaData meta = user.getCachedData().getMetaData(contexts);
|
||||||
if (meta.getPrefix() != null) {
|
if (meta.getPrefix() != null) {
|
||||||
prefix = "&f\"" + meta.getPrefix() + "&f\"";
|
prefix = "&f\"" + meta.getPrefix() + "&f\"";
|
||||||
}
|
}
|
||||||
|
@ -32,13 +32,16 @@ import com.google.common.collect.ImmutableSet;
|
|||||||
|
|
||||||
import me.lucko.luckperms.api.LogEntry;
|
import me.lucko.luckperms.api.LogEntry;
|
||||||
import me.lucko.luckperms.api.Node;
|
import me.lucko.luckperms.api.Node;
|
||||||
|
import me.lucko.luckperms.api.caching.GroupData;
|
||||||
import me.lucko.luckperms.api.caching.UserData;
|
import me.lucko.luckperms.api.caching.UserData;
|
||||||
import me.lucko.luckperms.api.event.LuckPermsEvent;
|
import me.lucko.luckperms.api.event.LuckPermsEvent;
|
||||||
import me.lucko.luckperms.api.event.cause.CreationCause;
|
import me.lucko.luckperms.api.event.cause.CreationCause;
|
||||||
import me.lucko.luckperms.api.event.cause.DeletionCause;
|
import me.lucko.luckperms.api.event.cause.DeletionCause;
|
||||||
import me.lucko.luckperms.api.event.log.LogBroadcastEvent;
|
import me.lucko.luckperms.api.event.log.LogBroadcastEvent;
|
||||||
import me.lucko.luckperms.common.event.impl.EventConfigReload;
|
import me.lucko.luckperms.common.event.impl.EventConfigReload;
|
||||||
|
import me.lucko.luckperms.common.event.impl.EventGroupCacheLoad;
|
||||||
import me.lucko.luckperms.common.event.impl.EventGroupCreate;
|
import me.lucko.luckperms.common.event.impl.EventGroupCreate;
|
||||||
|
import me.lucko.luckperms.common.event.impl.EventGroupDataRecalculate;
|
||||||
import me.lucko.luckperms.common.event.impl.EventGroupDelete;
|
import me.lucko.luckperms.common.event.impl.EventGroupDelete;
|
||||||
import me.lucko.luckperms.common.event.impl.EventGroupLoad;
|
import me.lucko.luckperms.common.event.impl.EventGroupLoad;
|
||||||
import me.lucko.luckperms.common.event.impl.EventGroupLoadAll;
|
import me.lucko.luckperms.common.event.impl.EventGroupLoadAll;
|
||||||
@ -88,11 +91,21 @@ public final class EventFactory {
|
|||||||
eventBus.fireEvent(event);
|
eventBus.fireEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handleGroupCacheLoad(Group group, GroupData data) {
|
||||||
|
EventGroupCacheLoad event = new EventGroupCacheLoad(group.getDelegate(), data);
|
||||||
|
fireEventAsync(event);
|
||||||
|
}
|
||||||
|
|
||||||
public void handleGroupCreate(Group group, CreationCause cause) {
|
public void handleGroupCreate(Group group, CreationCause cause) {
|
||||||
EventGroupCreate event = new EventGroupCreate(group.getDelegate(), cause);
|
EventGroupCreate event = new EventGroupCreate(group.getDelegate(), cause);
|
||||||
fireEventAsync(event);
|
fireEventAsync(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handleGroupDataRecalculate(Group group, GroupData data) {
|
||||||
|
EventGroupDataRecalculate event = new EventGroupDataRecalculate(group.getDelegate(), data);
|
||||||
|
fireEventAsync(event);
|
||||||
|
}
|
||||||
|
|
||||||
public void handleGroupDelete(Group group, DeletionCause cause) {
|
public void handleGroupDelete(Group group, DeletionCause cause) {
|
||||||
EventGroupDelete event = new EventGroupDelete(group.getName(), ImmutableSet.copyOf(group.getEnduringNodes().values()), cause);
|
EventGroupDelete event = new EventGroupDelete(group.getName(), ImmutableSet.copyOf(group.getEnduringNodes().values()), cause);
|
||||||
fireEventAsync(event);
|
fireEventAsync(event);
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.event.impl;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import me.lucko.luckperms.api.Group;
|
||||||
|
import me.lucko.luckperms.api.caching.GroupData;
|
||||||
|
import me.lucko.luckperms.api.event.group.GroupCacheLoadEvent;
|
||||||
|
import me.lucko.luckperms.common.event.AbstractEvent;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class EventGroupCacheLoad extends AbstractEvent implements GroupCacheLoadEvent {
|
||||||
|
|
||||||
|
private final Group group;
|
||||||
|
private final GroupData loadedData;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.event.impl;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import me.lucko.luckperms.api.Group;
|
||||||
|
import me.lucko.luckperms.api.caching.GroupData;
|
||||||
|
import me.lucko.luckperms.api.event.group.GroupDataRecalculateEvent;
|
||||||
|
import me.lucko.luckperms.common.event.AbstractEvent;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class EventGroupDataRecalculate extends AbstractEvent implements GroupDataRecalculateEvent {
|
||||||
|
|
||||||
|
private final Group group;
|
||||||
|
private final GroupData data;
|
||||||
|
|
||||||
|
}
|
@ -101,7 +101,7 @@ public class GenericUserManager extends AbstractManager<UserIdentifier, User> im
|
|||||||
plugin.getScheduler().asyncLater(() -> {
|
plugin.getScheduler().asyncLater(() -> {
|
||||||
User user = getIfLoaded(plugin.getUuidCache().getUUID(uuid));
|
User user = getIfLoaded(plugin.getUuidCache().getUUID(uuid));
|
||||||
if (user != null && !plugin.isPlayerOnline(uuid)) {
|
if (user != null && !plugin.isPlayerOnline(uuid)) {
|
||||||
user.getUserData().invalidateCaches();
|
user.getCachedData().invalidateCaches();
|
||||||
unload(user);
|
unload(user);
|
||||||
plugin.getUuidCache().clearCache(uuid);
|
plugin.getUuidCache().clearCache(uuid);
|
||||||
}
|
}
|
||||||
|
@ -32,12 +32,15 @@ import lombok.ToString;
|
|||||||
import me.lucko.luckperms.api.Node;
|
import me.lucko.luckperms.api.Node;
|
||||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||||
import me.lucko.luckperms.common.api.delegates.model.ApiGroup;
|
import me.lucko.luckperms.common.api.delegates.model.ApiGroup;
|
||||||
|
import me.lucko.luckperms.common.buffers.BufferedRequest;
|
||||||
|
import me.lucko.luckperms.common.caching.GroupCache;
|
||||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
import me.lucko.luckperms.common.references.GroupReference;
|
import me.lucko.luckperms.common.references.GroupReference;
|
||||||
import me.lucko.luckperms.common.references.Identifiable;
|
import me.lucko.luckperms.common.references.Identifiable;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
@ToString(of = {"name"})
|
@ToString(of = {"name"})
|
||||||
@EqualsAndHashCode(of = {"name"}, callSuper = false)
|
@EqualsAndHashCode(of = {"name"}, callSuper = false)
|
||||||
@ -52,9 +55,25 @@ public class Group extends PermissionHolder implements Identifiable<String> {
|
|||||||
@Getter
|
@Getter
|
||||||
private final ApiGroup delegate = new ApiGroup(this);
|
private final ApiGroup delegate = new ApiGroup(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The groups data cache instance
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final GroupCache cachedData;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private BufferedRequest<Void> refreshBuffer;
|
||||||
|
|
||||||
public Group(String name, LuckPermsPlugin plugin) {
|
public Group(String name, LuckPermsPlugin plugin) {
|
||||||
super(name, plugin);
|
super(name, plugin);
|
||||||
this.name = name.toLowerCase();
|
this.name = name.toLowerCase();
|
||||||
|
|
||||||
|
this.refreshBuffer = new GroupRefreshBuffer(plugin, this);
|
||||||
|
this.cachedData = new GroupCache(this);
|
||||||
|
getPlugin().getApiProvider().getEventFactory().handleGroupCacheLoad(this, cachedData);
|
||||||
|
|
||||||
|
// invalidate out caches when data is updated
|
||||||
|
getStateListeners().add(() -> refreshBuffer.request());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -91,4 +110,25 @@ public class Group extends PermissionHolder implements Identifiable<String> {
|
|||||||
public GroupReference toReference() {
|
public GroupReference toReference() {
|
||||||
return GroupReference.of(getId());
|
return GroupReference.of(getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<Void> reloadCachedData() {
|
||||||
|
return CompletableFuture.allOf(cachedData.reloadPermissions(), cachedData.reloadMeta()).thenAccept(n -> {
|
||||||
|
getPlugin().getApiProvider().getEventFactory().handleGroupDataRecalculate(this, cachedData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class GroupRefreshBuffer extends BufferedRequest<Void> {
|
||||||
|
private final Group group;
|
||||||
|
|
||||||
|
private GroupRefreshBuffer(LuckPermsPlugin plugin, Group group) {
|
||||||
|
super(50L, 5L, plugin.getScheduler().async());
|
||||||
|
this.group = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void perform() {
|
||||||
|
return group.reloadCachedData().join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ import me.lucko.luckperms.api.context.ContextSet;
|
|||||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||||
import me.lucko.luckperms.common.api.delegates.model.ApiPermissionHolder;
|
import me.lucko.luckperms.common.api.delegates.model.ApiPermissionHolder;
|
||||||
import me.lucko.luckperms.common.buffers.Cache;
|
import me.lucko.luckperms.common.buffers.Cache;
|
||||||
|
import me.lucko.luckperms.common.caching.HolderCache;
|
||||||
import me.lucko.luckperms.common.caching.MetaAccumulator;
|
import me.lucko.luckperms.common.caching.MetaAccumulator;
|
||||||
import me.lucko.luckperms.common.caching.handlers.StateListener;
|
import me.lucko.luckperms.common.caching.handlers.StateListener;
|
||||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||||
@ -250,6 +251,13 @@ public abstract class PermissionHolder {
|
|||||||
*/
|
*/
|
||||||
public abstract String getFriendlyName();
|
public abstract String getFriendlyName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the holders cached data
|
||||||
|
*
|
||||||
|
* @return the holders cached data
|
||||||
|
*/
|
||||||
|
public abstract HolderCache<?> getCachedData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forms a HolderReference for this PermissionHolder.
|
* Forms a HolderReference for this PermissionHolder.
|
||||||
*
|
*
|
||||||
|
@ -42,6 +42,7 @@ import me.lucko.luckperms.common.references.UserReference;
|
|||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
@ToString(of = {"uuid"})
|
@ToString(of = {"uuid"})
|
||||||
@EqualsAndHashCode(of = {"uuid"}, callSuper = false)
|
@EqualsAndHashCode(of = {"uuid"}, callSuper = false)
|
||||||
@ -65,10 +66,10 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
|
|||||||
private final PrimaryGroupHolder primaryGroup;
|
private final PrimaryGroupHolder primaryGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The users data cache instance, if present.
|
* The users data cache instance
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private final UserCache userData;
|
private final UserCache cachedData;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private BufferedRequest<Void> refreshBuffer;
|
private BufferedRequest<Void> refreshBuffer;
|
||||||
@ -83,8 +84,8 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
|
|||||||
this.refreshBuffer = new UserRefreshBuffer(plugin, this);
|
this.refreshBuffer = new UserRefreshBuffer(plugin, this);
|
||||||
this.primaryGroup = plugin.getConfiguration().get(ConfigKeys.PRIMARY_GROUP_CALCULATION).apply(this);
|
this.primaryGroup = plugin.getConfiguration().get(ConfigKeys.PRIMARY_GROUP_CALCULATION).apply(this);
|
||||||
|
|
||||||
this.userData = new UserCache(this);
|
this.cachedData = new UserCache(this);
|
||||||
getPlugin().getApiProvider().getEventFactory().handleUserCacheLoad(this, userData);
|
getPlugin().getApiProvider().getEventFactory().handleUserCacheLoad(this, cachedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public User(UUID uuid, String name, LuckPermsPlugin plugin) {
|
public User(UUID uuid, String name, LuckPermsPlugin plugin) {
|
||||||
@ -95,8 +96,8 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
|
|||||||
this.refreshBuffer = new UserRefreshBuffer(plugin, this);
|
this.refreshBuffer = new UserRefreshBuffer(plugin, this);
|
||||||
this.primaryGroup = plugin.getConfiguration().get(ConfigKeys.PRIMARY_GROUP_CALCULATION).apply(this);
|
this.primaryGroup = plugin.getConfiguration().get(ConfigKeys.PRIMARY_GROUP_CALCULATION).apply(this);
|
||||||
|
|
||||||
this.userData = new UserCache(this);
|
this.cachedData = new UserCache(this);
|
||||||
getPlugin().getApiProvider().getEventFactory().handleUserCacheLoad(this, userData);
|
getPlugin().getApiProvider().getEventFactory().handleUserCacheLoad(this, cachedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -168,24 +169,20 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
|
|||||||
* Sets up the UserData cache
|
* Sets up the UserData cache
|
||||||
* Blocking call.
|
* Blocking call.
|
||||||
*/
|
*/
|
||||||
public synchronized void preCalculateData() {
|
public void preCalculateData() {
|
||||||
// first try to refresh any existing permissions
|
// first try to refresh any existing permissions
|
||||||
refreshPermissions();
|
refreshBuffer.requestDirectly();
|
||||||
|
|
||||||
// pre-calc the allowall & global contexts
|
// pre-calc the allowall & global contexts
|
||||||
// since contexts change so frequently, it's not worth trying to calculate any more than this.
|
// since contexts change so frequently, it's not worth trying to calculate any more than this.
|
||||||
userData.preCalculate(Contexts.allowAll());
|
cachedData.preCalculate(Contexts.allowAll());
|
||||||
userData.preCalculate(Contexts.global());
|
cachedData.preCalculate(Contexts.global());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public CompletableFuture<Void> reloadCachedData() {
|
||||||
* Refresh and re-assign the users permissions
|
return CompletableFuture.allOf(cachedData.reloadPermissions(), cachedData.reloadMeta()).thenAccept(n -> {
|
||||||
* Blocking call.
|
getPlugin().getApiProvider().getEventFactory().handleUserDataRecalculate(this, cachedData);
|
||||||
*/
|
});
|
||||||
private synchronized void refreshPermissions() {
|
|
||||||
userData.recalculatePermissions();
|
|
||||||
userData.recalculateMeta();
|
|
||||||
getPlugin().getApiProvider().getEventFactory().handleUserDataRecalculate(this, userData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -213,14 +210,13 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
|
|||||||
private final User user;
|
private final User user;
|
||||||
|
|
||||||
private UserRefreshBuffer(LuckPermsPlugin plugin, User user) {
|
private UserRefreshBuffer(LuckPermsPlugin plugin, User user) {
|
||||||
super(250L, 50L, plugin.getScheduler().async());
|
super(50L, 5L, plugin.getScheduler().async());
|
||||||
this.user = user;
|
this.user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void perform() {
|
protected Void perform() {
|
||||||
user.refreshPermissions();
|
return user.reloadCachedData().join();
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,6 +400,7 @@ public abstract class ConfigurateDao extends AbstractDao {
|
|||||||
} finally {
|
} finally {
|
||||||
user.getIoLock().unlock();
|
user.getIoLock().unlock();
|
||||||
}
|
}
|
||||||
|
user.getRefreshBuffer().requestDirectly();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,6 +496,7 @@ public abstract class ConfigurateDao extends AbstractDao {
|
|||||||
} finally {
|
} finally {
|
||||||
group.getIoLock().unlock();
|
group.getIoLock().unlock();
|
||||||
}
|
}
|
||||||
|
group.getRefreshBuffer().requestDirectly();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,6 +530,7 @@ public abstract class ConfigurateDao extends AbstractDao {
|
|||||||
group.getIoLock().unlock();
|
group.getIoLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
group.getRefreshBuffer().requestDirectly();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,8 +331,8 @@ public class MongoDao extends AbstractDao {
|
|||||||
return reportException(e);
|
return reportException(e);
|
||||||
} finally {
|
} finally {
|
||||||
user.getIoLock().unlock();
|
user.getIoLock().unlock();
|
||||||
user.getRefreshBuffer().requestDirectly();
|
|
||||||
}
|
}
|
||||||
|
user.getRefreshBuffer().requestDirectly();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,6 +433,7 @@ public class MongoDao extends AbstractDao {
|
|||||||
} finally {
|
} finally {
|
||||||
group.getIoLock().unlock();
|
group.getIoLock().unlock();
|
||||||
}
|
}
|
||||||
|
group.getRefreshBuffer().requestDirectly();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,22 +445,23 @@ public class MongoDao extends AbstractDao {
|
|||||||
MongoCollection<Document> c = database.getCollection(prefix + "groups");
|
MongoCollection<Document> c = database.getCollection(prefix + "groups");
|
||||||
|
|
||||||
try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) {
|
try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) {
|
||||||
if (cursor.hasNext()) {
|
if (!cursor.hasNext()) {
|
||||||
Document d = cursor.next();
|
return false;
|
||||||
|
|
||||||
group.setEnduringNodes(revert((Map<String, Boolean>) d.get("perms")).entrySet().stream()
|
|
||||||
.map(e -> NodeFactory.fromSerializedNode(e.getKey(), e.getValue()))
|
|
||||||
.collect(Collectors.toSet())
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
Document d = cursor.next();
|
||||||
|
group.setEnduringNodes(revert((Map<String, Boolean>) d.get("perms")).entrySet().stream()
|
||||||
|
.map(e -> NodeFactory.fromSerializedNode(e.getKey(), e.getValue()))
|
||||||
|
.collect(Collectors.toSet())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return reportException(e);
|
return reportException(e);
|
||||||
} finally {
|
} finally {
|
||||||
group.getIoLock().unlock();
|
group.getIoLock().unlock();
|
||||||
}
|
}
|
||||||
|
group.getRefreshBuffer().requestDirectly();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -388,12 +388,11 @@ public class SqlDao extends AbstractDao {
|
|||||||
plugin.getUserManager().giveDefaultIfNeeded(user, false);
|
plugin.getUserManager().giveDefaultIfNeeded(user, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
} finally {
|
} finally {
|
||||||
user.getIoLock().unlock();
|
user.getIoLock().unlock();
|
||||||
user.getRefreshBuffer().requestDirectly();
|
|
||||||
}
|
}
|
||||||
|
user.getRefreshBuffer().requestDirectly();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -659,11 +658,11 @@ public class SqlDao extends AbstractDao {
|
|||||||
} else {
|
} else {
|
||||||
group.clearNodes();
|
group.clearNodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
} finally {
|
} finally {
|
||||||
group.getIoLock().unlock();
|
group.getIoLock().unlock();
|
||||||
}
|
}
|
||||||
|
group.getRefreshBuffer().requestDirectly();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -27,6 +27,7 @@ package me.lucko.luckperms.common.tasks;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import me.lucko.luckperms.common.model.Group;
|
||||||
import me.lucko.luckperms.common.model.User;
|
import me.lucko.luckperms.common.model.User;
|
||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
|
|
||||||
@ -37,7 +38,10 @@ public class CacheHousekeepingTask implements Runnable {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (User user : plugin.getUserManager().getAll().values()) {
|
for (User user : plugin.getUserManager().getAll().values()) {
|
||||||
user.getUserData().doCacheCleanup();
|
user.getCachedData().doCacheCleanup();
|
||||||
|
}
|
||||||
|
for (Group group : plugin.getGroupManager().getAll().values()) {
|
||||||
|
group.getCachedData().doCacheCleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,10 +102,4 @@ public class LoginHelper {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void refreshPlayer(LuckPermsPlugin plugin, UUID uuid) {
|
|
||||||
final User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(uuid));
|
|
||||||
if (user != null) {
|
|
||||||
user.getRefreshBuffer().requestDirectly();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,6 @@ import com.google.common.collect.ImmutableCollection;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
import me.lucko.luckperms.api.Contexts;
|
|
||||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
|
||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
|
|
||||||
import org.spongepowered.api.plugin.PluginContainer;
|
import org.spongepowered.api.plugin.PluginContainer;
|
||||||
@ -83,7 +81,5 @@ public interface LPPermissionService {
|
|||||||
// utils
|
// utils
|
||||||
ImmutableList<SubjectReference> sortSubjects(Collection<SubjectReference> s);
|
ImmutableList<SubjectReference> sortSubjects(Collection<SubjectReference> s);
|
||||||
|
|
||||||
Contexts calculateContexts(ImmutableContextSet contextSet);
|
|
||||||
|
|
||||||
void invalidateAllCaches(LPSubject.CacheLevel cacheLevel);
|
void invalidateAllCaches(LPSubject.CacheLevel cacheLevel);
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
|||||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||||
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||||
import me.lucko.luckperms.common.model.User;
|
|
||||||
import me.lucko.luckperms.common.processors.MapProcessor;
|
import me.lucko.luckperms.common.processors.MapProcessor;
|
||||||
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
||||||
import me.lucko.luckperms.common.processors.RegexProcessor;
|
import me.lucko.luckperms.common.processors.RegexProcessor;
|
||||||
@ -50,7 +49,7 @@ public class SpongeCalculatorFactory extends AbstractCalculatorFactory {
|
|||||||
private final LPSpongePlugin plugin;
|
private final LPSpongePlugin plugin;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PermissionCalculator build(Contexts contexts, User user) {
|
public PermissionCalculator build(Contexts contexts, PermissionCalculatorMetadata metadata) {
|
||||||
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
|
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
|
||||||
|
|
||||||
processors.add(new MapProcessor());
|
processors.add(new MapProcessor());
|
||||||
@ -71,8 +70,7 @@ public class SpongeCalculatorFactory extends AbstractCalculatorFactory {
|
|||||||
processors.add(new DefaultsProcessor(plugin.getService(), contexts.getContexts().makeImmutable()));
|
processors.add(new DefaultsProcessor(plugin.getService(), contexts.getContexts().makeImmutable()));
|
||||||
}
|
}
|
||||||
|
|
||||||
PermissionCalculatorMetadata meta = PermissionCalculatorMetadata.of(user.getFriendlyName(), contexts.getContexts());
|
return registerCalculator(new PermissionCalculator(plugin, metadata, processors.build()));
|
||||||
return registerCalculator(new PermissionCalculator(plugin, meta, processors.build()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -171,12 +171,6 @@ public class SpongeConnectionListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Listener(order = Order.EARLY)
|
|
||||||
public void onClientJoin(ClientConnectionEvent.Join e) {
|
|
||||||
// Refresh permissions again
|
|
||||||
plugin.getScheduler().doAsync(() -> LoginHelper.refreshPlayer(plugin, e.getTargetEntity().getUniqueId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Listener(order = Order.POST)
|
@Listener(order = Order.POST)
|
||||||
public void onClientLeave(ClientConnectionEvent.Disconnect e) {
|
public void onClientLeave(ClientConnectionEvent.Disconnect e) {
|
||||||
/* We don't actually remove the user instance here, as Sponge likes to keep performing checks
|
/* We don't actually remove the user instance here, as Sponge likes to keep performing checks
|
||||||
|
@ -27,38 +27,27 @@ package me.lucko.luckperms.sponge.model;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
|
||||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ListMultimap;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
import me.lucko.luckperms.api.ChatMetaType;
|
|
||||||
import me.lucko.luckperms.api.LocalizedNode;
|
|
||||||
import me.lucko.luckperms.api.Node;
|
|
||||||
import me.lucko.luckperms.api.Tristate;
|
import me.lucko.luckperms.api.Tristate;
|
||||||
|
import me.lucko.luckperms.api.caching.MetaData;
|
||||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||||
import me.lucko.luckperms.common.caching.MetaAccumulator;
|
|
||||||
import me.lucko.luckperms.common.model.Group;
|
import me.lucko.luckperms.common.model.Group;
|
||||||
|
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||||
import me.lucko.luckperms.sponge.LPSpongePlugin;
|
import me.lucko.luckperms.sponge.LPSpongePlugin;
|
||||||
import me.lucko.luckperms.sponge.service.LuckPermsService;
|
import me.lucko.luckperms.sponge.service.LuckPermsService;
|
||||||
import me.lucko.luckperms.sponge.service.LuckPermsSubjectData;
|
import me.lucko.luckperms.sponge.service.LuckPermsSubjectData;
|
||||||
import me.lucko.luckperms.sponge.service.ProxyFactory;
|
import me.lucko.luckperms.sponge.service.ProxyFactory;
|
||||||
import me.lucko.luckperms.sponge.service.model.CompatibilityUtil;
|
|
||||||
import me.lucko.luckperms.sponge.service.model.LPSubject;
|
import me.lucko.luckperms.sponge.service.model.LPSubject;
|
||||||
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
|
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
|
||||||
import me.lucko.luckperms.sponge.service.model.SubjectReference;
|
import me.lucko.luckperms.sponge.service.model.SubjectReference;
|
||||||
|
|
||||||
import org.spongepowered.api.command.CommandSource;
|
import org.spongepowered.api.command.CommandSource;
|
||||||
import org.spongepowered.api.service.permission.NodeTree;
|
|
||||||
import org.spongepowered.api.service.permission.PermissionService;
|
import org.spongepowered.api.service.permission.PermissionService;
|
||||||
import org.spongepowered.api.service.permission.Subject;
|
import org.spongepowered.api.service.permission.Subject;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class SpongeGroup extends Group {
|
public class SpongeGroup extends Group {
|
||||||
|
|
||||||
@ -74,11 +63,7 @@ public class SpongeGroup extends Group {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class GroupSubject implements LPSubject {
|
public static class GroupSubject implements LPSubject {
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final SpongeGroup parent;
|
private final SpongeGroup parent;
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final LPSpongePlugin plugin;
|
private final LPSpongePlugin plugin;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ -87,61 +72,11 @@ public class SpongeGroup extends Group {
|
|||||||
@Getter
|
@Getter
|
||||||
private final LuckPermsSubjectData transientSubjectData;
|
private final LuckPermsSubjectData transientSubjectData;
|
||||||
|
|
||||||
private final LoadingCache<ImmutableContextSet, NodeTree> permissionCache = Caffeine.newBuilder()
|
|
||||||
.expireAfterAccess(10, TimeUnit.MINUTES)
|
|
||||||
.build(contexts -> {
|
|
||||||
// TODO move this away from NodeTree
|
|
||||||
Map<String, Boolean> permissions = getParent().getAllNodes(getPlugin().getService().calculateContexts(contexts)).stream()
|
|
||||||
.map(LocalizedNode::getNode)
|
|
||||||
.collect(Collectors.toMap(Node::getPermission, Node::getValuePrimitive));
|
|
||||||
|
|
||||||
return NodeTree.of(permissions);
|
|
||||||
});
|
|
||||||
|
|
||||||
private final LoadingCache<ImmutableContextSet, ImmutableList<SubjectReference>> parentCache = Caffeine.newBuilder()
|
|
||||||
.expireAfterWrite(10, TimeUnit.MINUTES)
|
|
||||||
.build(contexts -> {
|
|
||||||
Set<SubjectReference> subjects = getParent().getAllNodes(getPlugin().getService().calculateContexts(contexts)).stream()
|
|
||||||
.map(LocalizedNode::getNode)
|
|
||||||
.filter(Node::isGroupNode)
|
|
||||||
.map(Node::getGroupName)
|
|
||||||
.distinct()
|
|
||||||
.map(n -> Optional.ofNullable(getPlugin().getGroupManager().getIfLoaded(n)))
|
|
||||||
.filter(Optional::isPresent)
|
|
||||||
.map(Optional::get)
|
|
||||||
.map(SpongeGroup::sponge)
|
|
||||||
.map(LPSubject::toReference)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
|
||||||
subjects.addAll(getPlugin().getService().getGroupSubjects().getDefaults().getParents(contexts));
|
|
||||||
subjects.addAll(getPlugin().getService().getDefaults().getParents(contexts));
|
|
||||||
|
|
||||||
return getService().sortSubjects(subjects);
|
|
||||||
});
|
|
||||||
|
|
||||||
private GroupSubject(LPSpongePlugin plugin, SpongeGroup parent) {
|
private GroupSubject(LPSpongePlugin plugin, SpongeGroup parent) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.subjectData = new LuckPermsSubjectData(true, plugin.getService(), parent, this);
|
this.subjectData = new LuckPermsSubjectData(true, plugin.getService(), parent, this);
|
||||||
this.transientSubjectData = new LuckPermsSubjectData(false, plugin.getService(), parent, this);
|
this.transientSubjectData = new LuckPermsSubjectData(false, plugin.getService(), parent, this);
|
||||||
|
|
||||||
parent.getStateListeners().add(() -> invalidateCaches(CacheLevel.PERMISSION));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invalidateCaches(CacheLevel type) {
|
|
||||||
if (type == CacheLevel.OPTION) {
|
|
||||||
return; // don't invalidate for option changes
|
|
||||||
}
|
|
||||||
|
|
||||||
permissionCache.invalidateAll();
|
|
||||||
parentCache.invalidateAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void performCleanup() {
|
|
||||||
permissionCache.cleanUp();
|
|
||||||
parentCache.cleanUp();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -176,19 +111,7 @@ public class SpongeGroup extends Group {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Tristate getPermissionValue(ImmutableContextSet contexts, String permission) {
|
public Tristate getPermissionValue(ImmutableContextSet contexts, String permission) {
|
||||||
NodeTree nt = permissionCache.get(contexts);
|
return parent.getCachedData().getPermissionData(plugin.getContextManager().formContexts(contexts)).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||||
Tristate t = CompatibilityUtil.convertTristate(nt.get(permission));
|
|
||||||
if (t != Tristate.UNDEFINED) {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
t = plugin.getService().getGroupSubjects().getDefaults().getPermissionValue(contexts, permission);
|
|
||||||
if (t != Tristate.UNDEFINED) {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
t = plugin.getService().getDefaults().getPermissionValue(contexts, permission);
|
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -198,29 +121,48 @@ public class SpongeGroup extends Group {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImmutableList<SubjectReference> getParents(ImmutableContextSet contexts) {
|
public ImmutableList<SubjectReference> getParents(ImmutableContextSet contexts) {
|
||||||
return parentCache.get(contexts);
|
ImmutableSet.Builder<SubjectReference> subjects = ImmutableSet.builder();
|
||||||
|
|
||||||
|
for (String perm : parent.getCachedData().getPermissionData(plugin.getContextManager().formContexts(contexts)).getImmutableBacking().keySet()) {
|
||||||
|
if (!perm.startsWith("group.")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String groupName = perm.substring("group.".length());
|
||||||
|
if (plugin.getGroupManager().isLoaded(groupName)) {
|
||||||
|
subjects.add(plugin.getService().getGroupSubjects().loadSubject(groupName).join().toReference());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subjects.addAll(plugin.getService().getGroupSubjects().getDefaults().getParents(contexts));
|
||||||
|
subjects.addAll(plugin.getService().getDefaults().getParents(contexts));
|
||||||
|
|
||||||
|
return getService().sortSubjects(subjects.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<String> getOption(ImmutableContextSet contexts, String s) {
|
public Optional<String> getOption(ImmutableContextSet contexts, String s) {
|
||||||
Optional<String> option;
|
MetaData data = parent.getCachedData().getMetaData(plugin.getContextManager().formContexts(contexts));
|
||||||
if (s.equalsIgnoreCase("prefix")) {
|
if (s.equalsIgnoreCase("prefix")) {
|
||||||
option = getChatMeta(contexts, ChatMetaType.PREFIX);
|
if (data.getPrefix() != null) {
|
||||||
|
return Optional.of(data.getPrefix());
|
||||||
} else if (s.equalsIgnoreCase("suffix")) {
|
}
|
||||||
option = getChatMeta(contexts, ChatMetaType.SUFFIX);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
option = getMeta(contexts, s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (option.isPresent()) {
|
if (s.equalsIgnoreCase("suffix")) {
|
||||||
return option;
|
if (data.getSuffix() != null) {
|
||||||
|
return Optional.of(data.getSuffix());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
option = plugin.getService().getGroupSubjects().getDefaults().getOption(contexts, s);
|
String val = data.getMeta().get(s);
|
||||||
if (option.isPresent()) {
|
if (val != null) {
|
||||||
return option;
|
return Optional.of(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<String> v = plugin.getService().getGroupSubjects().getDefaults().getOption(contexts, s);
|
||||||
|
if (v.isPresent()) {
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
return plugin.getService().getDefaults().getOption(contexts, s);
|
return plugin.getService().getDefaults().getOption(contexts, s);
|
||||||
@ -231,16 +173,11 @@ public class SpongeGroup extends Group {
|
|||||||
return plugin.getContextManager().getApplicableContext(this.sponge());
|
return plugin.getContextManager().getApplicableContext(this.sponge());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<String> getChatMeta(ImmutableContextSet contexts, ChatMetaType type) {
|
@Override
|
||||||
MetaAccumulator metaAccumulator = parent.accumulateMeta(null, null, plugin.getService().calculateContexts(contexts));
|
public void invalidateCaches(CacheLevel cacheLevel) {
|
||||||
return Optional.ofNullable(metaAccumulator.getStack(type).toFormattedString());
|
// invalidate for all changes
|
||||||
}
|
parent.getCachedData().invalidateCaches();
|
||||||
|
|
||||||
private Optional<String> getMeta(ImmutableContextSet contexts, String key) {
|
|
||||||
MetaAccumulator metaAccumulator = parent.accumulateMeta(null, null, plugin.getService().calculateContexts(contexts));
|
|
||||||
ListMultimap<String, String> meta = metaAccumulator.getMeta();
|
|
||||||
List<String> ret = meta.get(key);
|
|
||||||
return ret.isEmpty() ? Optional.empty() : Optional.of(ret.get(0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -45,12 +45,12 @@ import me.lucko.luckperms.sponge.service.model.SubjectReference;
|
|||||||
|
|
||||||
import org.spongepowered.api.Sponge;
|
import org.spongepowered.api.Sponge;
|
||||||
import org.spongepowered.api.command.CommandSource;
|
import org.spongepowered.api.command.CommandSource;
|
||||||
import org.spongepowered.api.entity.living.player.Player;
|
|
||||||
import org.spongepowered.api.service.permission.PermissionService;
|
import org.spongepowered.api.service.permission.PermissionService;
|
||||||
import org.spongepowered.api.service.permission.Subject;
|
import org.spongepowered.api.service.permission.Subject;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class SpongeUser extends User {
|
public class SpongeUser extends User {
|
||||||
|
|
||||||
@ -100,13 +100,7 @@ public class SpongeUser extends User {
|
|||||||
@Override
|
@Override
|
||||||
public Optional<CommandSource> getCommandSource() {
|
public Optional<CommandSource> getCommandSource() {
|
||||||
final UUID uuid = plugin.getUuidCache().getExternalUUID(parent.getUuid());
|
final UUID uuid = plugin.getUuidCache().getExternalUUID(parent.getUuid());
|
||||||
|
return Sponge.getServer().getPlayer(uuid).map(Function.identity());
|
||||||
Optional<Player> p = Sponge.getServer().getPlayer(uuid);
|
|
||||||
if (p.isPresent()) {
|
|
||||||
return Optional.of(p.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -126,7 +120,7 @@ public class SpongeUser extends User {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Tristate getPermissionValue(ImmutableContextSet contexts, String permission) {
|
public Tristate getPermissionValue(ImmutableContextSet contexts, String permission) {
|
||||||
return parent.getUserData().getPermissionData(plugin.getService().calculateContexts(contexts)).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
return parent.getCachedData().getPermissionData(plugin.getContextManager().formContexts(contexts)).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -138,7 +132,7 @@ public class SpongeUser extends User {
|
|||||||
public ImmutableList<SubjectReference> getParents(ImmutableContextSet contexts) {
|
public ImmutableList<SubjectReference> getParents(ImmutableContextSet contexts) {
|
||||||
ImmutableSet.Builder<SubjectReference> subjects = ImmutableSet.builder();
|
ImmutableSet.Builder<SubjectReference> subjects = ImmutableSet.builder();
|
||||||
|
|
||||||
for (String perm : parent.getUserData().getPermissionData(plugin.getService().calculateContexts(contexts)).getImmutableBacking().keySet()) {
|
for (String perm : parent.getCachedData().getPermissionData(plugin.getContextManager().formContexts(contexts)).getImmutableBacking().keySet()) {
|
||||||
if (!perm.startsWith("group.")) {
|
if (!perm.startsWith("group.")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -157,7 +151,7 @@ public class SpongeUser extends User {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<String> getOption(ImmutableContextSet contexts, String s) {
|
public Optional<String> getOption(ImmutableContextSet contexts, String s) {
|
||||||
MetaData data = parent.getUserData().getMetaData(plugin.getService().calculateContexts(contexts));
|
MetaData data = parent.getCachedData().getMetaData(plugin.getContextManager().formContexts(contexts));
|
||||||
if (s.equalsIgnoreCase("prefix")) {
|
if (s.equalsIgnoreCase("prefix")) {
|
||||||
if (data.getPrefix() != null) {
|
if (data.getPrefix() != null) {
|
||||||
return Optional.of(data.getPrefix());
|
return Optional.of(data.getPrefix());
|
||||||
@ -191,7 +185,7 @@ public class SpongeUser extends User {
|
|||||||
@Override
|
@Override
|
||||||
public void invalidateCaches(CacheLevel cacheLevel) {
|
public void invalidateCaches(CacheLevel cacheLevel) {
|
||||||
// invalidate for all changes
|
// invalidate for all changes
|
||||||
parent.getUserData().invalidateCaches();
|
parent.getCachedData().invalidateCaches();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +35,6 @@ import com.google.common.collect.ImmutableList;
|
|||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
import me.lucko.luckperms.api.Contexts;
|
|
||||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
|
||||||
import me.lucko.luckperms.common.model.Group;
|
import me.lucko.luckperms.common.model.Group;
|
||||||
import me.lucko.luckperms.common.utils.Predicates;
|
import me.lucko.luckperms.common.utils.Predicates;
|
||||||
import me.lucko.luckperms.sponge.LPSpongePlugin;
|
import me.lucko.luckperms.sponge.LPSpongePlugin;
|
||||||
@ -230,11 +228,6 @@ public class LuckPermsService implements LPPermissionService {
|
|||||||
return ImmutableList.copyOf(ret);
|
return ImmutableList.copyOf(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Contexts calculateContexts(ImmutableContextSet contextSet) {
|
|
||||||
return plugin.getContextManager().formContexts(null, contextSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invalidateAllCaches(LPSubject.CacheLevel cacheLevel) {
|
public void invalidateAllCaches(LPSubject.CacheLevel cacheLevel) {
|
||||||
for (LPSubjectCollection collection : collections.asMap().values()) {
|
for (LPSubjectCollection collection : collections.asMap().values()) {
|
||||||
|
@ -353,7 +353,7 @@ public class LuckPermsSubjectData implements LPSubjectData {
|
|||||||
|
|
||||||
toRemove.forEach(makeUnsetConsumer(enduring));
|
toRemove.forEach(makeUnsetConsumer(enduring));
|
||||||
|
|
||||||
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, null, service.calculateContexts(context));
|
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, null, service.getPlugin().getContextManager().formContexts(context));
|
||||||
int priority = metaAccumulator.getChatMeta(type).keySet().stream().mapToInt(e -> e).max().orElse(0);
|
int priority = metaAccumulator.getChatMeta(type).keySet().stream().mapToInt(e -> e).max().orElse(0);
|
||||||
priority += 10;
|
priority += 10;
|
||||||
|
|
||||||
@ -451,23 +451,21 @@ public class LuckPermsSubjectData implements LPSubjectData {
|
|||||||
} else {
|
} else {
|
||||||
if (t instanceof User) {
|
if (t instanceof User) {
|
||||||
User user = ((User) t);
|
User user = ((User) t);
|
||||||
return service.getPlugin().getStorage().saveUser(user).thenApplyAsync(success -> {
|
return service.getPlugin().getStorage().saveUser(user).thenComposeAsync(success -> {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return null;
|
return CompletableFuture.completedFuture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
user.getRefreshBuffer().request().join();
|
return user.getRefreshBuffer().request();
|
||||||
return null;
|
|
||||||
}, service.getPlugin().getScheduler().async());
|
}, service.getPlugin().getScheduler().async());
|
||||||
} else {
|
} else {
|
||||||
Group group = ((Group) t);
|
Group group = ((Group) t);
|
||||||
return service.getPlugin().getStorage().saveGroup(group).thenApplyAsync(success -> {
|
return service.getPlugin().getStorage().saveGroup(group).thenComposeAsync(success -> {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return null;
|
return CompletableFuture.completedFuture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
service.getPlugin().getUpdateTaskBuffer().request().join();
|
return service.getPlugin().getUpdateTaskBuffer().request();
|
||||||
return null;
|
|
||||||
}, service.getPlugin().getScheduler().async());
|
}, service.getPlugin().getScheduler().async());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user