SpongeAPI 8 (#2728)

This commit is contained in:
lucko 2022-02-07 21:10:01 +00:00 committed by GitHub
parent d3029a8467
commit ee79f53612
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 1301 additions and 1707 deletions

View File

@ -29,6 +29,7 @@ import com.github.benmanes.caffeine.cache.LoadingCache;
import me.lucko.luckperms.bungee.LPBungeePlugin;
import me.lucko.luckperms.common.context.manager.ContextManager;
import me.lucko.luckperms.common.context.manager.InlineQueryOptionsSupplier;
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
import me.lucko.luckperms.common.util.CaffeineFactory;
@ -60,9 +61,10 @@ public class BungeeContextManager extends ContextManager<ProxiedPlayer, ProxiedP
throw new NullPointerException("subject");
}
return new InlineQueryOptionsSupplier(subject, this.contextsCache);
return new InlineQueryOptionsSupplier<>(subject, this.contextsCache);
}
// override getContext, getQueryOptions and invalidateCache to skip the QueryOptionsSupplier
@Override
public ImmutableContextSet getContext(ProxiedPlayer subject) {
return getQueryOptions(subject).context();
@ -83,18 +85,4 @@ public class BungeeContextManager extends ContextManager<ProxiedPlayer, ProxiedP
return formQueryOptions(contextSet);
}
private static final class InlineQueryOptionsSupplier implements QueryOptionsSupplier {
private final ProxiedPlayer key;
private final LoadingCache<ProxiedPlayer, QueryOptions> cache;
private InlineQueryOptionsSupplier(ProxiedPlayer key, LoadingCache<ProxiedPlayer, QueryOptions> cache) {
this.key = key;
this.cache = cache;
}
@Override
public QueryOptions getQueryOptions() {
return this.cache.get(this.key);
}
}
}

View File

@ -38,6 +38,7 @@ import me.lucko.luckperms.common.node.utils.NodeJsonSerializer;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.util.CompletableFutures;
import me.lucko.luckperms.common.util.gson.GsonProvider;
import me.lucko.luckperms.common.util.gson.JArray;
import me.lucko.luckperms.common.util.gson.JObject;
@ -193,7 +194,7 @@ public abstract class Exporter implements Runnable {
}
// all of the threads have been scheduled now and are running. we just need to wait for them all to complete
CompletableFuture<Void> overallFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
CompletableFuture<Void> overallFuture = CompletableFutures.allOf(futures);
while (true) {
try {

View File

@ -39,6 +39,7 @@ import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.utils.NodeJsonSerializer;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.CompletableFutures;
import me.lucko.luckperms.common.util.Uuids;
import net.luckperms.api.event.cause.CreationCause;
@ -260,7 +261,7 @@ public class Importer implements Runnable {
}
// all of the threads have been scheduled now and are running. we just need to wait for them all to complete
CompletableFuture<Void> overallFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
CompletableFuture<Void> overallFuture = CompletableFutures.allOf(futures);
this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "All data entries have been processed and scheduled for import - now waiting for the execution to complete."));

View File

@ -33,6 +33,7 @@ import me.lucko.luckperms.common.calculator.CalculatorFactory;
import me.lucko.luckperms.common.calculator.PermissionCalculator;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.util.CaffeineFactory;
import me.lucko.luckperms.common.util.CompletableFutures;
import net.luckperms.api.cacheddata.CachedData;
import net.luckperms.api.cacheddata.CachedDataManager;
@ -241,7 +242,7 @@ public abstract class AbstractCachedDataManager implements CachedDataManager {
@Override
public @NonNull CompletableFuture<Void> reload() {
Set<QueryOptions> keys = this.cache.keySet();
return CompletableFuture.allOf(keys.stream().map(this::reload).toArray(CompletableFuture[]::new));
return CompletableFutures.allOf(keys.stream().map(this::reload));
}
@Override

View File

@ -135,16 +135,28 @@ public abstract class ContextManager<S, P extends S> {
this.calculators.remove(calculator);
}
protected void callContextCalculator(ContextCalculator<? super S> calculator, S subject, ContextConsumer consumer) {
try {
calculator.calculate(subject, consumer);
} catch (Throwable e) {
this.plugin.getLogger().warn("An exception was thrown by " + getCalculatorClass(calculator) + " whilst calculating the context of subject " + subject, e);
}
}
protected void callStaticContextCalculator(StaticContextCalculator calculator, ContextConsumer consumer) {
try {
calculator.calculate(consumer);
} catch (Throwable e) {
this.plugin.getLogger().warn("An exception was thrown by " + getCalculatorClass(calculator) + " whilst calculating static contexts", e);
}
}
protected QueryOptions calculate(S subject) {
ImmutableContextSet.Builder accumulator = new ImmutableContextSetImpl.BuilderImpl();
ContextConsumer consumer = accumulator::add;
for (ContextCalculator<? super S> calculator : this.calculators.calculators()) {
try {
calculator.calculate(subject, consumer);
} catch (Throwable e) {
this.plugin.getLogger().warn("An exception was thrown by " + getCalculatorClass(calculator) + " whilst calculating the context of subject " + subject, e);
}
callContextCalculator(calculator, subject, consumer);
}
return formQueryOptions(subject, accumulator.build());
@ -155,11 +167,7 @@ public abstract class ContextManager<S, P extends S> {
ContextConsumer consumer = accumulator::add;
for (StaticContextCalculator calculator : this.calculators.staticCalculators()) {
try {
calculator.calculate(consumer);
} catch (Throwable e) {
this.plugin.getLogger().warn("An exception was thrown by " + getCalculatorClass(calculator) + " whilst calculating static contexts", e);
}
callStaticContextCalculator(calculator, consumer);
}
return formQueryOptions(accumulator.build());

View File

@ -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.context.manager;
import com.github.benmanes.caffeine.cache.LoadingCache;
import net.luckperms.api.query.QueryOptions;
public final class InlineQueryOptionsSupplier<T> implements QueryOptionsSupplier {
private final T key;
private final LoadingCache<T, QueryOptions> cache;
public InlineQueryOptionsSupplier(T key, LoadingCache<T, QueryOptions> cache) {
this.key = key;
this.cache = cache;
}
@Override
public QueryOptions getQueryOptions() {
return this.cache.get(this.key);
}
}

View File

@ -32,6 +32,7 @@ import me.lucko.luckperms.common.model.manager.AbstractManager;
import me.lucko.luckperms.common.model.manager.group.GroupManager;
import me.lucko.luckperms.common.node.types.Inheritance;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.util.CompletableFutures;
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
import net.luckperms.api.model.data.DataType;
@ -165,11 +166,9 @@ public abstract class AbstractUserManager<T extends User> extends AbstractManage
Set<UUID> ids = new HashSet<>(getAll().keySet());
ids.addAll(this.plugin.getBootstrap().getOnlinePlayers());
CompletableFuture<?>[] loadTasks = ids.stream()
return ids.stream()
.map(id -> this.plugin.getStorage().loadUser(id, null))
.toArray(CompletableFuture[]::new);
return CompletableFuture.allOf(loadTasks);
.collect(CompletableFutures.collector());
}
@Override

View File

@ -34,8 +34,7 @@ import java.nio.file.Path;
public class ReflectionClassPathAppender implements ClassPathAppender {
private final URLClassLoaderAccess classLoaderAccess;
public ReflectionClassPathAppender(LuckPermsBootstrap bootstrap) throws IllegalStateException {
ClassLoader classLoader = bootstrap.getClass().getClassLoader();
public ReflectionClassPathAppender(ClassLoader classLoader) throws IllegalStateException {
if (classLoader instanceof URLClassLoader) {
this.classLoaderAccess = URLClassLoaderAccess.create((URLClassLoader) classLoader);
} else {
@ -43,6 +42,10 @@ public class ReflectionClassPathAppender implements ClassPathAppender {
}
}
public ReflectionClassPathAppender(LuckPermsBootstrap bootstrap) throws IllegalStateException {
this(bootstrap.getClass().getClassLoader());
}
@Override
public void addJarToClasspath(Path file) {
try {

View File

@ -130,7 +130,7 @@ public final class AbstractSender<T> implements Sender {
// A small utility method which splits components built using
// > join(newLine(), components...)
// back into separate components.
private static Iterable<Component> splitNewlines(Component message) {
public static Iterable<Component> splitNewlines(Component message) {
if (message instanceof TextComponent && message.style().isEmpty() && !message.children().isEmpty() && ((TextComponent) message).content().isEmpty()) {
LinkedList<List<Component>> split = new LinkedList<>();
split.add(new ArrayList<>());

View File

@ -23,20 +23,35 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.events;
package me.lucko.luckperms.common.util;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import com.google.common.collect.ImmutableList;
import org.spongepowered.api.event.permission.SubjectDataUpdateEvent;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collector;
import java.util.stream.Stream;
public final class UpdateEventHandler {
private UpdateEventHandler() {}
public final class CompletableFutures {
private CompletableFutures() {}
public static void fireUpdateEvent(LPSpongePlugin plugin, LPSubjectData subjectData) {
plugin.getBootstrap().getScheduler().executeAsync(() -> {
SubjectDataUpdateEvent event = new LPSubjectDataUpdateEvent(plugin, subjectData);
plugin.getBootstrap().getGame().getEventManager().post(event);
});
public static <T extends CompletableFuture<?>> Collector<T, ImmutableList.Builder<T>, CompletableFuture<Void>> collector() {
return Collector.of(
ImmutableList.Builder::new,
ImmutableList.Builder::add,
(l, r) -> l.addAll(r.build()),
builder -> allOf(builder.build())
);
}
public static CompletableFuture<Void> allOf(Stream<? extends CompletableFuture<?>> futures) {
CompletableFuture<?>[] arr = futures.toArray(CompletableFuture[]::new);
return CompletableFuture.allOf(arr);
}
public static CompletableFuture<Void> allOf(Collection<? extends CompletableFuture<?>> futures) {
CompletableFuture<?>[] arr = futures.toArray(new CompletableFuture[0]);
return CompletableFuture.allOf(arr);
}
}

View File

@ -23,6 +23,6 @@ include (
'fabric',
'nukkit',
'nukkit:loader',
'sponge', 'sponge:sponge-service', 'sponge:sponge-service-api6', 'sponge:sponge-service-api7',
'sponge', 'sponge:sponge-service', 'sponge:sponge-service-api8',
'velocity'
)

View File

@ -1,25 +1,17 @@
plugins {
id 'net.kyori.blossom' version '1.3.0'
id 'com.github.johnrengelman.shadow' version '7.0.0'
}
repositories {
maven { url 'https://repo.spongepowered.org/maven' }
maven { url 'https://repo.spongepowered.org/repository/maven-public/' }
}
dependencies {
implementation project(':common')
implementation project(':sponge:sponge-service')
implementation project(':sponge:sponge-service-api6')
implementation project(':sponge:sponge-service-api7')
implementation project(':sponge:sponge-service-api8')
compileOnly('org.spongepowered:spongeapi:7.3.0') {
exclude(module: 'configurate-core')
exclude(module: 'configurate-hocon')
exclude(module: 'configurate-gson')
exclude(module: 'configurate-yaml')
}
annotationProcessor('org.spongepowered:spongeapi:7.3.0') {
compileOnly('org.spongepowered:spongeapi:8.0.0') {
exclude(module: 'configurate-core')
exclude(module: 'configurate-hocon')
exclude(module: 'configurate-gson')
@ -27,9 +19,10 @@ dependencies {
}
}
blossom {
replaceTokenIn('src/main/java/me/lucko/luckperms/sponge/LPSpongeBootstrap.java')
replaceToken '@version@', project.ext.fullVersion
processResources {
filesMatching('META-INF/sponge_plugins.json') {
expand 'pluginVersion': project.ext.fullVersion
}
}
shadowJar {
@ -40,7 +33,7 @@ shadowJar {
include(dependency('me.lucko.luckperms:.*'))
}
relocate 'net.kyori.adventure', 'me.lucko.luckperms.lib.adventure'
//relocate 'net.kyori.adventure', 'me.lucko.luckperms.lib.adventure'
relocate 'net.kyori.event', 'me.lucko.luckperms.lib.eventbus'
relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine'
relocate 'okio', 'me.lucko.luckperms.lib.okio'

View File

@ -1,142 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.proxy.api6;
import me.lucko.luckperms.common.context.ImmutableContextSetImpl;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import net.luckperms.api.util.Tristate;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.text.Text;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public final class DescriptionBuilder implements PermissionDescription.Builder, ProxiedServiceObject {
public static LPPermissionDescription registerDescription(LPPermissionService service, PermissionDescription description) {
//noinspection ConstantConditions
if (description.getOwner() == null) {
return null;
}
return service.registerPermissionDescription(description.getId(), description.getDescription(), description.getOwner());
}
private final @NonNull LPPermissionService service;
private final @NonNull PluginContainer container;
private final @NonNull Map<String, Tristate> roles = new HashMap<>();
private @Nullable String id = null;
private @Nullable Text description = null;
public DescriptionBuilder(@NonNull LPPermissionService service, @NonNull PluginContainer container) {
this.service = Objects.requireNonNull(service, "service");
this.container = Objects.requireNonNull(container, "container");
}
@Override
public PermissionDescription.@NonNull Builder id(@NonNull String id) {
this.id = Objects.requireNonNull(id, "id");
return this;
}
@Override
public PermissionDescription.@NonNull Builder description(@NonNull Text description) {
this.description = Objects.requireNonNull(description, "description");
return this;
}
@Override
public PermissionDescription.@NonNull Builder assign(@NonNull String role, boolean value) {
Objects.requireNonNull(role, "role");
this.roles.put(role, Tristate.of(value));
return this;
}
@Override
public @NonNull PermissionDescription register() throws IllegalStateException {
if (this.id == null) {
throw new IllegalStateException("id cannot be null");
}
LPPermissionDescription description = this.service.registerPermissionDescription(this.id, this.description, this.container);
// Set role-templates
LPSubjectCollection subjects = this.service.getCollection(PermissionService.SUBJECTS_ROLE_TEMPLATE);
for (Map.Entry<String, Tristate> assignment : this.roles.entrySet()) {
LPSubject roleSubject = subjects.loadSubject(assignment.getKey()).join();
roleSubject.getTransientSubjectData().setPermission(ImmutableContextSetImpl.EMPTY, this.id, assignment.getValue());
}
// null stuff so this instance can be reused
this.roles.clear();
this.id = null;
this.description = null;
return description.sponge();
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof DescriptionBuilder)) return false;
final DescriptionBuilder other = (DescriptionBuilder) o;
return this.container.equals(other.container) &&
this.roles.equals(other.roles) &&
Objects.equals(this.id, other.id) &&
Objects.equals(this.description, other.description);
}
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.container.hashCode();
result = result * PRIME + this.roles.hashCode();
result = result * PRIME + (this.id == null ? 43 : this.id.hashCode());
result = result * PRIME + (this.description == null ? 43 : this.description.hashCode());
return result;
}
@Override
public String toString() {
return "SimpleDescriptionBuilder(" +
"container=" + this.container + ", " +
"roles=" + this.roles + ", " +
"id=" + this.id + ", " +
"description=" + this.description + ")";
}
}

View File

@ -1,89 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.proxy.api6;
import me.lucko.luckperms.common.util.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.text.Text;
import java.util.Map;
public final class PermissionDescriptionProxy implements PermissionDescription, ProxiedServiceObject {
private final LPPermissionService service;
private final LPPermissionDescription handle;
public PermissionDescriptionProxy(LPPermissionService service, LPPermissionDescription handle) {
this.service = service;
this.handle = handle;
}
@Override
public @NonNull String getId() {
return this.handle.getId();
}
@Override
public @NonNull Text getDescription() {
return this.handle.getDescription().orElse(Text.EMPTY);
}
@Override
public @NonNull PluginContainer getOwner() {
return this.handle.getOwner().orElseGet(() -> Sponge.getGame().getPluginManager().fromInstance(this.service.getPlugin()).orElseThrow(() -> new RuntimeException("Unable to get LuckPerms instance.")));
}
@Override
public @NonNull Map<Subject, Boolean> getAssignedSubjects(@NonNull String s) {
return this.handle.getAssignedSubjects(s).entrySet().stream()
.collect(ImmutableCollectors.toMap(
e -> new SubjectProxy(this.service, e.getKey().toReference()),
Map.Entry::getValue
));
}
@Override
public boolean equals(Object o) {
return o == this || o instanceof PermissionDescriptionProxy && this.handle.equals(((PermissionDescriptionProxy) o).handle);
}
@Override
public int hashCode() {
return this.handle.hashCode();
}
@Override
public String toString() {
return "luckperms.api6.PermissionDescriptionProxy(handle=" + this.handle + ")";
}
}

View File

@ -1,121 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.proxy.api6;
import me.lucko.luckperms.common.util.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.service.context.ContextCalculator;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
public final class PermissionServiceProxy implements PermissionService, ProxiedServiceObject {
private final LPPermissionService handle;
public PermissionServiceProxy(LPPermissionService handle) {
this.handle = handle;
}
@Override
public @NonNull SubjectCollection getUserSubjects() {
return this.handle.getUserSubjects().sponge();
}
@Override
public @NonNull SubjectCollection getGroupSubjects() {
return this.handle.getGroupSubjects().sponge();
}
@Override
public @NonNull Subject getDefaults() {
return this.handle.getRootDefaults().sponge();
}
@Override
public @NonNull SubjectCollection getSubjects(@NonNull String s) {
return this.handle.getCollection(s).sponge();
}
@Override
public @NonNull Map<String, SubjectCollection> getKnownSubjects() {
return this.handle.getLoadedCollections().entrySet().stream()
.collect(ImmutableCollectors.toMap(
Map.Entry::getKey,
e -> e.getValue().sponge()
));
}
@Override
public Optional<PermissionDescription.Builder> newDescriptionBuilder(@NonNull Object o) {
Optional<PluginContainer> container = Sponge.getGame().getPluginManager().fromInstance(o);
if (!container.isPresent()) {
throw new IllegalArgumentException("Couldn't find a plugin container for " + o.getClass().getSimpleName());
}
return Optional.of(new DescriptionBuilder(this.handle, container.get()));
}
@Override
public @NonNull Optional<PermissionDescription> getDescription(@NonNull String s) {
return this.handle.getDescription(s).map(LPPermissionDescription::sponge);
}
@Override
public @NonNull Collection<PermissionDescription> getDescriptions() {
return this.handle.getDescriptions().stream().map(LPPermissionDescription::sponge).collect(ImmutableCollectors.toSet());
}
@Override
public void registerContextCalculator(@NonNull ContextCalculator<Subject> contextCalculator) {
this.handle.registerContextCalculator(contextCalculator);
}
@Override
public boolean equals(Object o) {
return o == this || o instanceof PermissionServiceProxy && this.handle.equals(((PermissionServiceProxy) o).handle);
}
@Override
public int hashCode() {
return this.handle.hashCode();
}
@Override
public String toString() {
return "luckperms.api6.PermissionServiceProxy(handle=" + this.handle + ")";
}
}

View File

@ -1,128 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.proxy.api6;
import me.lucko.luckperms.common.util.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SuppressWarnings("unchecked")
public final class SubjectCollectionProxy implements SubjectCollection, ProxiedServiceObject {
private final LPPermissionService service;
private final LPSubjectCollection handle;
public SubjectCollectionProxy(LPPermissionService service, LPSubjectCollection handle) {
this.service = service;
this.handle = handle;
}
@Override
public @NonNull String getIdentifier() {
return this.handle.getIdentifier();
}
@Override
public @NonNull Subject get(@NonNull String s) {
// force load the subject.
// after this call, users will expect that the subject is loaded in memory.
return this.handle.loadSubject(s).thenApply(LPSubject::sponge).join();
}
@Override
public boolean hasRegistered(@NonNull String s) {
return this.handle.hasRegistered(s).join();
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull Iterable<Subject> getAllSubjects() {
// this will lazily load all subjects. it will initially just get the identifiers of each subject, and will initialize dummy
// providers for those identifiers. when any methods against the dummy are called, the actual data will be loaded.
// this behaviour should be replaced when CompletableFutures are added to Sponge
return (List) this.handle.getAllIdentifiers()
.thenApply(ids -> ids.stream()
.map(s -> new SubjectProxy(this.service, this.service.getReferenceFactory().obtain(getIdentifier(), s)))
.collect(ImmutableCollectors.toList())
).join();
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull Map<Subject, Boolean> getAllWithPermission(@NonNull String s) {
// again, these methods will lazily load subjects.
return (Map) this.handle.getAllWithPermission(s)
.thenApply(map -> map.entrySet().stream()
.collect(ImmutableCollectors.toMap(
e -> new SubjectProxy(this.service, e.getKey()),
Map.Entry::getValue
))
).join();
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> set, @NonNull String s) {
return (Map) this.handle.getAllWithPermission(CompatibilityUtil.convertContexts(set), s)
.thenApply(map -> map.entrySet().stream()
.collect(ImmutableCollectors.toMap(
e -> new SubjectProxy(this.service, e.getKey()),
Map.Entry::getValue
))
).join();
}
@Override
public @NonNull Subject getDefaults() {
return this.handle.getDefaults().sponge();
}
@Override
public boolean equals(Object o) {
return o == this || o instanceof SubjectCollectionProxy && this.handle.equals(((SubjectCollectionProxy) o).handle);
}
@Override
public int hashCode() {
return this.handle.hashCode();
}
@Override
public String toString() {
return "luckperms.api6.SubjectCollectionProxy(handle=" + this.handle + ")";
}
}

View File

@ -1,211 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.proxy.api6;
import me.lucko.luckperms.common.util.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.util.Tristate;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@SuppressWarnings("unchecked")
public final class SubjectDataProxy implements SubjectData, ProxiedServiceObject {
private final LPPermissionService service;
private final LPSubjectReference ref;
private final boolean enduring;
public SubjectDataProxy(LPPermissionService service, LPSubjectReference ref, boolean enduring) {
this.service = service;
this.ref = ref;
this.enduring = enduring;
}
private CompletableFuture<LPSubjectData> handle() {
return this.enduring ?
this.ref.resolveLp().thenApply(LPSubject::getSubjectData) :
this.ref.resolveLp().thenApply(LPSubject::getTransientSubjectData);
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull Map<Set<Context>, Map<String, Boolean>> getAllPermissions() {
return (Map) handle().thenApply(handle -> handle.getAllPermissions().entrySet().stream()
.collect(ImmutableCollectors.toMap(
e -> CompatibilityUtil.convertContexts(e.getKey()),
Map.Entry::getValue
))).join();
}
@Override
public @NonNull Map<String, Boolean> getPermissions(@NonNull Set<Context> contexts) {
return handle().thenApply(handle -> handle.getPermissions(CompatibilityUtil.convertContexts(contexts))).join();
}
@Override
public boolean setPermission(@NonNull Set<Context> contexts, @NonNull String permission, @NonNull Tristate value) {
handle().thenCompose(handle -> handle.setPermission(
CompatibilityUtil.convertContexts(contexts),
permission,
CompatibilityUtil.convertTristate(value)
));
return true;
}
@Override
public boolean clearPermissions() {
handle().thenCompose(LPSubjectData::clearPermissions);
return true;
}
@Override
public boolean clearPermissions(@NonNull Set<Context> contexts) {
handle().thenCompose(handle -> handle.clearPermissions(CompatibilityUtil.convertContexts(contexts)));
return true;
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull Map<Set<Context>, List<Subject>> getAllParents() {
return (Map) handle().thenApply(handle -> handle.getAllParents().entrySet().stream()
.collect(ImmutableCollectors.toMap(
e -> CompatibilityUtil.convertContexts(e.getKey()),
e -> e.getValue().stream()
.map(s -> new SubjectProxy(this.service, s))
.collect(ImmutableCollectors.toList())
)
)).join();
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull List<Subject> getParents(@NonNull Set<Context> contexts) {
return (List) handle().thenApply(handle -> handle.getParents(CompatibilityUtil.convertContexts(contexts)).stream()
.map(s -> new SubjectProxy(this.service, s))
.collect(ImmutableCollectors.toList())).join();
}
@Override
public boolean addParent(@NonNull Set<Context> contexts, @NonNull Subject parent) {
handle().thenCompose(handle -> handle.addParent(
CompatibilityUtil.convertContexts(contexts),
this.service.getReferenceFactory().obtain(parent)
));
return true;
}
@Override
public boolean removeParent(@NonNull Set<Context> contexts, @NonNull Subject parent) {
handle().thenCompose(handle -> handle.removeParent(
CompatibilityUtil.convertContexts(contexts),
this.service.getReferenceFactory().obtain(parent)
));
return true;
}
@Override
public boolean clearParents() {
handle().thenCompose(LPSubjectData::clearParents);
return true;
}
@Override
public boolean clearParents(@NonNull Set<Context> contexts) {
handle().thenCompose(handle -> handle.clearParents(CompatibilityUtil.convertContexts(contexts)));
return true;
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull Map<Set<Context>, Map<String, String>> getAllOptions() {
return (Map) handle().thenApply(handle -> handle.getAllOptions().entrySet().stream()
.collect(ImmutableCollectors.toMap(
e -> CompatibilityUtil.convertContexts(e.getKey()),
Map.Entry::getValue
))).join();
}
@Override
public @NonNull Map<String, String> getOptions(@NonNull Set<Context> contexts) {
return handle().thenApply(handle -> handle.getOptions(CompatibilityUtil.convertContexts(contexts))).join();
}
@Override
public boolean setOption(@NonNull Set<Context> contexts, @NonNull String key, String value) {
if (value == null) {
handle().thenCompose(handle -> handle.unsetOption(CompatibilityUtil.convertContexts(contexts), key));
} else {
handle().thenCompose(handle -> handle.setOption(CompatibilityUtil.convertContexts(contexts), key, value));
}
return true;
}
@Override
public boolean clearOptions(@NonNull Set<Context> contexts) {
handle().thenCompose(handle -> handle.clearOptions(CompatibilityUtil.convertContexts(contexts)));
return true;
}
@Override
public boolean clearOptions() {
handle().thenCompose(LPSubjectData::clearOptions);
return true;
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof SubjectDataProxy)) return false;
final SubjectDataProxy other = (SubjectDataProxy) o;
return this.ref.equals(other.ref) && this.enduring == other.enduring;
}
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.ref.hashCode();
result = result * PRIME + (this.enduring ? 79 : 97);
return result;
}
@Override
public String toString() {
return "luckperms.api6.SubjectDataProxy(ref=" + this.ref + ", enduring=" + this.enduring + ")";
}
}

View File

@ -1,187 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.proxy.api6;
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
import me.lucko.luckperms.common.util.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import me.lucko.luckperms.sponge.service.model.ProxiedSubject;
import net.luckperms.api.query.QueryOptions;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.util.Tristate;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@SuppressWarnings("unchecked")
public final class SubjectProxy implements Subject, ProxiedSubject, ProxiedServiceObject {
private final LPPermissionService service;
private final LPSubjectReference ref;
private QueryOptionsSupplier queryOptionsSupplier = null;
public SubjectProxy(LPPermissionService service, LPSubjectReference ref) {
this.service = service;
this.ref = ref;
}
private CompletableFuture<LPSubject> handle() {
return this.ref.resolveLp();
}
// lazy init
private QueryOptionsSupplier getContextsCache() {
if (this.queryOptionsSupplier == null) {
this.queryOptionsSupplier = this.service.getContextManager().getCacheFor(this);
}
return this.queryOptionsSupplier;
}
@Override
public @NonNull LPSubjectReference asSubjectReference() {
return this.ref;
}
@Override
public @NonNull QueryOptions getQueryOptions() {
return getContextsCache().getQueryOptions();
}
@Override
public @NonNull Optional<CommandSource> getCommandSource() {
return handle().thenApply(LPSubject::getCommandSource).join();
}
@Override
public @NonNull SubjectCollection getContainingCollection() {
return this.service.getCollection(this.ref.getCollectionIdentifier()).sponge();
}
@Override
public SubjectData getSubjectData() {
return new SubjectDataProxy(this.service, this.ref, true);
}
@Override
public SubjectData getTransientSubjectData() {
return new SubjectDataProxy(this.service, this.ref, false);
}
@Override
public boolean hasPermission(@NonNull Set<Context> contexts, @NonNull String permission) {
return handle().thenApply(handle -> handle.getPermissionValue(CompatibilityUtil.convertContexts(contexts), permission).asBoolean()).join();
}
@Override
public boolean hasPermission(@NonNull String permission) {
return handle().thenApply(handle -> handle.getPermissionValue(getContextsCache().getContextSet(), permission).asBoolean()).join();
}
@Override
public @NonNull Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String permission) {
return handle().thenApply(handle -> CompatibilityUtil.convertTristate(handle.getPermissionValue(CompatibilityUtil.convertContexts(contexts), permission))).join();
}
@Override
public boolean isChildOf(@NonNull Subject parent) {
return handle().thenApply(handle -> handle.isChildOf(
getContextsCache().getContextSet(),
this.service.getReferenceFactory().obtain(parent)
)).join();
}
@Override
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject parent) {
return handle().thenApply(handle -> handle.isChildOf(
CompatibilityUtil.convertContexts(contexts),
this.service.getReferenceFactory().obtain(parent)
)).join();
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull List<Subject> getParents() {
return (List) handle().thenApply(handle -> handle.getParents(getContextsCache().getContextSet()).stream()
.map(s -> new SubjectProxy(this.service, s))
.collect(ImmutableCollectors.toList())).join();
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull List<Subject> getParents(@NonNull Set<Context> contexts) {
return (List) handle().thenApply(handle -> handle.getParents(CompatibilityUtil.convertContexts(contexts)).stream()
.map(s -> new SubjectProxy(this.service, s))
.collect(ImmutableCollectors.toList())).join();
}
@Override
public @NonNull Optional<String> getOption(@NonNull Set<Context> contexts, @NonNull String key) {
return handle().thenApply(handle -> handle.getOption(CompatibilityUtil.convertContexts(contexts), key)).join();
}
@Override
public @NonNull Optional<String> getOption(@NonNull String key) {
return handle().thenApply(handle -> handle.getOption(getContextsCache().getContextSet(), key)).join();
}
@Override
public String getIdentifier() {
return this.ref.getSubjectIdentifier();
}
@Override
public @NonNull Set<Context> getActiveContexts() {
return CompatibilityUtil.convertContexts(getContextsCache().getContextSet());
}
@Override
public boolean equals(Object o) {
return o == this || o instanceof SubjectProxy && this.ref.equals(((SubjectProxy) o).ref);
}
@Override
public int hashCode() {
return this.ref.hashCode();
}
@Override
public String toString() {
return "luckperms.api6.SubjectProxy(ref=" + this.ref + ")";
}
}

View File

@ -1,15 +0,0 @@
repositories {
maven { url 'https://repo.spongepowered.org/maven' }
}
dependencies {
implementation project(':common')
implementation project(':sponge:sponge-service')
compileOnly('org.spongepowered:spongeapi:7.3.0') {
exclude(module: 'configurate-core')
exclude(module: 'configurate-hocon')
exclude(module: 'configurate-gson')
exclude(module: 'configurate-yaml')
}
}

View File

@ -1,12 +1,12 @@
repositories {
maven { url 'https://repo.spongepowered.org/maven' }
maven { url 'https://repo.spongepowered.org/repository/maven-public/' }
}
dependencies {
implementation project(':common')
implementation project(':sponge:sponge-service')
compileOnly('org.spongepowered:spongeapi:6.0.0') {
compileOnly('org.spongepowered:spongeapi:8.0.0') {
exclude(module: 'configurate-core')
exclude(module: 'configurate-hocon')
exclude(module: 'configurate-gson')

View File

@ -23,42 +23,34 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.proxy.api7;
package me.lucko.luckperms.sponge.service.proxy.api8;
import me.lucko.luckperms.common.context.ImmutableContextSetImpl;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPProxiedServiceObject;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import net.kyori.adventure.text.Component;
import net.luckperms.api.util.Tristate;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.text.Text;
import org.spongepowered.plugin.PluginContainer;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public final class DescriptionBuilder implements PermissionDescription.Builder, ProxiedServiceObject {
public static LPPermissionDescription registerDescription(LPPermissionService service, PermissionDescription description) {
if (!description.getOwner().isPresent()) {
return null;
}
return service.registerPermissionDescription(description.getId(), description.getDescription().orElse(null), description.getOwner().get());
}
public final class DescriptionBuilder implements PermissionDescription.Builder, LPProxiedServiceObject {
private final @NonNull LPPermissionService service;
private final @NonNull PluginContainer container;
private final @NonNull Map<String, Tristate> roles = new HashMap<>();
private @Nullable String id = null;
private @Nullable Text description = null;
private @Nullable Component description = null;
public DescriptionBuilder(LPPermissionService service, PluginContainer container) {
this.service = Objects.requireNonNull(service, "service");
@ -72,7 +64,7 @@ public final class DescriptionBuilder implements PermissionDescription.Builder,
}
@Override
public PermissionDescription.@NonNull Builder description(@Nullable Text description) {
public PermissionDescription.@NonNull Builder description(@Nullable Component description) {
this.description = description;
return this;
}
@ -84,6 +76,11 @@ public final class DescriptionBuilder implements PermissionDescription.Builder,
return this;
}
@Override
public PermissionDescription.Builder defaultValue(org.spongepowered.api.util.Tristate defaultValue) {
throw new UnsupportedOperationException("LuckPerms does not support assigning a default value to permission descriptions");
}
@Override
public @NonNull PermissionDescription register() throws IllegalStateException {
if (this.id == null) {
@ -121,13 +118,7 @@ public final class DescriptionBuilder implements PermissionDescription.Builder,
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.container.hashCode();
result = result * PRIME + this.roles.hashCode();
result = result * PRIME + (this.id == null ? 43 : this.id.hashCode());
result = result * PRIME + (this.description == null ? 43 : this.description.hashCode());
return result;
return Objects.hash(this.container, this.roles, this.id, this.description);
}
@Override

View File

@ -23,25 +23,29 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.proxy.api7;
package me.lucko.luckperms.sponge.service.proxy.api8;
import me.lucko.luckperms.common.util.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import me.lucko.luckperms.sponge.service.model.LPProxiedServiceObject;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectReference;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.util.Tristate;
import org.spongepowered.plugin.PluginContainer;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
public final class PermissionDescriptionProxy implements PermissionDescription, ProxiedServiceObject {
public final class PermissionDescriptionProxy implements PermissionDescription, LPProxiedServiceObject {
private final LPPermissionService service;
private final LPPermissionDescription handle;
@ -51,22 +55,27 @@ public final class PermissionDescriptionProxy implements PermissionDescription,
}
@Override
public @NonNull String getId() {
public @NonNull String id() {
return this.handle.getId();
}
@Override
public @NonNull Optional<Text> getDescription() {
public @NonNull Optional<Component> description() {
return this.handle.getDescription();
}
@Override
public @NonNull Optional<PluginContainer> getOwner() {
public @NonNull Optional<PluginContainer> owner() {
return this.handle.getOwner();
}
@Override
public @NonNull Map<Subject, Boolean> getAssignedSubjects(@NonNull String s) {
public Tristate defaultValue() {
return Tristate.UNDEFINED;
}
@Override
public @NonNull Map<Subject, Boolean> assignedSubjects(@NonNull String s) {
return this.handle.getAssignedSubjects(s).entrySet().stream()
.collect(ImmutableCollectors.toMap(
e -> new SubjectProxy(this.service, e.getKey().toReference()),
@ -74,6 +83,37 @@ public final class PermissionDescriptionProxy implements PermissionDescription,
));
}
@Override
public boolean query(Subject subj) {
return subj.hasPermission(this.handle.getId());
}
@Override
public boolean query(Subject subj, String parameter) {
Objects.requireNonNull(parameter, "parameter");
return subj.hasPermission(this.handle.getId() + '.' + parameter);
}
@Override
public boolean query(Subject subj, ResourceKey key) {
return query(subj, key.namespace() + '.' + key.value());
}
@Override
public boolean query(Subject subj, String... parameters) {
if (parameters.length == 0) {
return this.query(subj);
} else if (parameters.length == 1) {
return this.query(subj, parameters[0]);
}
StringBuilder builder = new StringBuilder(this.handle.getId());
for (String parameter : parameters) {
builder.append('.').append(parameter);
}
return subj.hasPermission(builder.toString());
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public @NonNull CompletableFuture<Map<SubjectReference, Boolean>> findAssignedSubjects(@NonNull String s) {
@ -92,6 +132,6 @@ public final class PermissionDescriptionProxy implements PermissionDescription,
@Override
public String toString() {
return "luckperms.api7.PermissionDescriptionProxy(handle=" + this.handle + ")";
return "luckperms.api8.PermissionDescriptionProxy(handle=" + this.handle + ")";
}
}

View File

@ -23,25 +23,28 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.proxy.api7;
package me.lucko.luckperms.sponge.service.proxy.api8;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.common.util.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.PermissionAndContextService;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPProxiedServiceObject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.event.Cause;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.context.ContextCalculator;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectReference;
import org.spongepowered.plugin.PluginContainer;
import java.util.Collection;
import java.util.Locale;
@ -52,7 +55,7 @@ import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
public final class PermissionServiceProxy implements PermissionService, ProxiedServiceObject {
public final class PermissionServiceProxy implements PermissionAndContextService, LPProxiedServiceObject {
private final LPPermissionService handle;
public PermissionServiceProxy(LPPermissionService handle) {
@ -60,22 +63,22 @@ public final class PermissionServiceProxy implements PermissionService, ProxiedS
}
@Override
public @NonNull SubjectCollection getUserSubjects() {
public @NonNull SubjectCollection userSubjects() {
return this.handle.getUserSubjects().sponge();
}
@Override
public @NonNull SubjectCollection getGroupSubjects() {
public @NonNull SubjectCollection groupSubjects() {
return this.handle.getGroupSubjects().sponge();
}
@Override
public @NonNull Subject getDefaults() {
public @NonNull Subject defaults() {
return this.handle.getRootDefaults().sponge();
}
@Override
public @NonNull Predicate<String> getIdentifierValidityPredicate() {
public @NonNull Predicate<String> identifierValidityPredicate() {
return this.handle.getIdentifierValidityPredicate();
}
@ -85,7 +88,7 @@ public final class PermissionServiceProxy implements PermissionService, ProxiedS
}
@Override
public @NonNull Optional<SubjectCollection> getCollection(String s) {
public @NonNull Optional<SubjectCollection> collection(String s) {
return Optional.ofNullable(this.handle.getLoadedCollections().get(s.toLowerCase(Locale.ROOT))).map(LPSubjectCollection::sponge);
}
@ -95,7 +98,7 @@ public final class PermissionServiceProxy implements PermissionService, ProxiedS
}
@Override
public @NonNull Map<String, SubjectCollection> getLoadedCollections() {
public @NonNull Map<String, SubjectCollection> loadedCollections() {
return this.handle.getLoadedCollections().entrySet().stream()
.collect(ImmutableCollectors.toMap(
Map.Entry::getKey,
@ -104,7 +107,7 @@ public final class PermissionServiceProxy implements PermissionService, ProxiedS
}
@Override
public CompletableFuture<Set<String>> getAllIdentifiers() {
public CompletableFuture<? extends Set<String>> allIdentifiers() {
return CompletableFuture.completedFuture(ImmutableSet.copyOf(this.handle.getLoadedCollections().keySet()));
}
@ -114,10 +117,11 @@ public final class PermissionServiceProxy implements PermissionService, ProxiedS
Objects.requireNonNull(subjectIdentifier, "subjectIdentifier");
// test the identifiers
String collection = collectionIdentifier.toLowerCase(Locale.ROOT);
if (collection.equals("user") && !this.handle.getUserSubjects().getIdentifierValidityPredicate().test(subjectIdentifier)) {
if (collectionIdentifier.equalsIgnoreCase(PermissionService.SUBJECTS_USER) &&
!this.handle.getUserSubjects().getIdentifierValidityPredicate().test(subjectIdentifier)) {
throw new IllegalArgumentException("Subject identifier '" + subjectIdentifier + "' does not pass the validity predicate for the user subject collection");
} else if (collection.equals("group") && !this.handle.getGroupSubjects().getIdentifierValidityPredicate().test(subjectIdentifier)) {
} else if (collectionIdentifier.equalsIgnoreCase(PermissionService.SUBJECTS_GROUP) &&
!this.handle.getGroupSubjects().getIdentifierValidityPredicate().test(subjectIdentifier)) {
throw new IllegalArgumentException("Subject identifier '" + subjectIdentifier + "' does not pass the validity predicate for the group subject collection");
}
@ -126,27 +130,32 @@ public final class PermissionServiceProxy implements PermissionService, ProxiedS
}
@Override
public PermissionDescription.Builder newDescriptionBuilder(@NonNull Object o) {
Optional<PluginContainer> container = Sponge.getGame().getPluginManager().fromInstance(o);
if (!container.isPresent()) {
throw new IllegalArgumentException("Couldn't find a plugin container for " + o.getClass().getSimpleName());
}
return new DescriptionBuilder(this.handle, container.get());
public PermissionDescription.Builder newDescriptionBuilder(@NonNull PluginContainer container) {
return new DescriptionBuilder(this.handle, container);
}
@Override
public @NonNull Optional<PermissionDescription> getDescription(@NonNull String s) {
public @NonNull Optional<PermissionDescription> description(@NonNull String s) {
return this.handle.getDescription(s).map(LPPermissionDescription::sponge);
}
@Override
public @NonNull Collection<PermissionDescription> getDescriptions() {
public @NonNull Collection<PermissionDescription> descriptions() {
return this.handle.getDescriptions().stream().map(LPPermissionDescription::sponge).collect(ImmutableCollectors.toSet());
}
@Override
public void registerContextCalculator(@NonNull ContextCalculator<Subject> contextCalculator) {
public Set<Context> contexts() {
return CompatibilityUtil.convertContexts(this.handle.getContextsForCurrentCause());
}
@Override
public Set<Context> contextsFor(Cause cause) {
return CompatibilityUtil.convertContexts(this.handle.getContextsForCurrentCause());
}
@Override
public void registerContextCalculator(@NonNull ContextCalculator contextCalculator) {
this.handle.registerContextCalculator(contextCalculator);
}
@ -162,6 +171,6 @@ public final class PermissionServiceProxy implements PermissionService, ProxiedS
@Override
public String toString() {
return "luckperms.api7.PermissionServiceProxy(handle=" + this.handle + ")";
return "luckperms.api8.PermissionServiceProxy(handle=" + this.handle + ")";
}
}

View File

@ -23,16 +23,15 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.proxy.api7;
package me.lucko.luckperms.sponge.service.proxy.api8;
import me.lucko.luckperms.common.util.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPProxiedServiceObject;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.event.Cause;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectReference;
@ -46,7 +45,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
@SuppressWarnings("unchecked")
public final class SubjectCollectionProxy implements SubjectCollection, ProxiedServiceObject {
public final class SubjectCollectionProxy implements SubjectCollection, LPProxiedServiceObject {
private final LPSubjectCollection handle;
public SubjectCollectionProxy(LPSubjectCollection handle) {
@ -54,12 +53,12 @@ public final class SubjectCollectionProxy implements SubjectCollection, ProxiedS
}
@Override
public @NonNull String getIdentifier() {
public @NonNull String identifier() {
return this.handle.getIdentifier();
}
@Override
public @NonNull Predicate<String> getIdentifierValidityPredicate() {
public @NonNull Predicate<String> identifierValidityPredicate() {
return this.handle.getIdentifierValidityPredicate();
}
@ -69,7 +68,7 @@ public final class SubjectCollectionProxy implements SubjectCollection, ProxiedS
}
@Override
public @NonNull Optional<Subject> getSubject(@NonNull String s) {
public @NonNull Optional<Subject> subject(@NonNull String s) {
return this.handle.getSubject(s).map(LPSubject::sponge);
}
@ -79,18 +78,18 @@ public final class SubjectCollectionProxy implements SubjectCollection, ProxiedS
}
@Override
public @NonNull CompletableFuture<Map<String, Subject>> loadSubjects(@NonNull Set<String> set) {
public @NonNull CompletableFuture<Map<String, Subject>> loadSubjects(@NonNull Iterable<String> set) {
return this.handle.loadSubjects(set).thenApply(subs -> subs.stream().collect(ImmutableCollectors.toMap(lpSubject -> lpSubject.getIdentifier().getName(), LPSubject::sponge)));
}
@Override
public @NonNull Collection<Subject> getLoadedSubjects() {
public @NonNull Collection<Subject> loadedSubjects() {
return this.handle.getLoadedSubjects().stream().map(LPSubject::sponge).collect(ImmutableCollectors.toSet());
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull CompletableFuture<Set<String>> getAllIdentifiers() {
public @NonNull CompletableFuture<Set<String>> allIdentifiers() {
return (CompletableFuture) this.handle.getAllIdentifiers();
}
@ -101,23 +100,23 @@ public final class SubjectCollectionProxy implements SubjectCollection, ProxiedS
throw new IllegalArgumentException("Subject identifier '" + subjectIdentifier + "' does not pass the validity predicate");
}
return this.handle.getService().getReferenceFactory().obtain(getIdentifier(), subjectIdentifier);
return this.handle.getService().getReferenceFactory().obtain(identifier(), subjectIdentifier);
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull CompletableFuture<Map<SubjectReference, Boolean>> getAllWithPermission(@NonNull String s) {
public @NonNull CompletableFuture<Map<SubjectReference, Boolean>> allWithPermission(@NonNull String s) {
return (CompletableFuture) this.handle.getAllWithPermission(s);
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull CompletableFuture<Map<SubjectReference, Boolean>> getAllWithPermission(@NonNull Set<Context> set, @NonNull String s) {
return (CompletableFuture) this.handle.getAllWithPermission(CompatibilityUtil.convertContexts(set), s);
public @NonNull CompletableFuture<Map<SubjectReference, Boolean>> allWithPermission(@NonNull String s, @NonNull Cause cause) {
return (CompletableFuture) this.handle.getAllWithPermission(this.handle.getService().getContextsForCause(cause), s);
}
@Override
public @NonNull Map<Subject, Boolean> getLoadedWithPermission(@NonNull String s) {
public @NonNull Map<Subject, Boolean> loadedWithPermission(@NonNull String s) {
return this.handle.getLoadedWithPermission(s).entrySet().stream()
.collect(ImmutableCollectors.toMap(
sub -> sub.getKey().sponge(),
@ -126,8 +125,8 @@ public final class SubjectCollectionProxy implements SubjectCollection, ProxiedS
}
@Override
public @NonNull Map<Subject, Boolean> getLoadedWithPermission(@NonNull Set<Context> set, @NonNull String s) {
return this.handle.getLoadedWithPermission(CompatibilityUtil.convertContexts(set), s).entrySet().stream()
public @NonNull Map<Subject, Boolean> loadedWithPermission(@NonNull String s, @NonNull Cause cause) {
return this.handle.getLoadedWithPermission(this.handle.getService().getContextsForCause(cause), s).entrySet().stream()
.collect(ImmutableCollectors.toMap(
sub -> sub.getKey().sponge(),
Map.Entry::getValue
@ -135,7 +134,7 @@ public final class SubjectCollectionProxy implements SubjectCollection, ProxiedS
}
@Override
public @NonNull Subject getDefaults() {
public @NonNull Subject defaults() {
return this.handle.getDefaults().sponge();
}
@ -156,7 +155,7 @@ public final class SubjectCollectionProxy implements SubjectCollection, ProxiedS
@Override
public String toString() {
return "luckperms.api7.SubjectCollectionProxy(handle=" + this.handle + ")";
return "luckperms.api8.SubjectCollectionProxy(handle=" + this.handle + ")";
}
}

View File

@ -23,29 +23,36 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.proxy.api7;
package me.lucko.luckperms.sponge.service.proxy.api8;
import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.common.util.CompletableFutures;
import me.lucko.luckperms.common.util.ImmutableCollectors;
import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPProxiedServiceObject;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.service.permission.SubjectReference;
import org.spongepowered.api.service.permission.TransferMethod;
import org.spongepowered.api.util.Tristate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@SuppressWarnings("unchecked")
public final class SubjectDataProxy implements SubjectData, ProxiedServiceObject {
public final class SubjectDataProxy implements SubjectData, LPProxiedServiceObject {
private final LPPermissionService service;
private final LPSubjectReference ref;
private final boolean enduring;
@ -62,9 +69,19 @@ public final class SubjectDataProxy implements SubjectData, ProxiedServiceObject
this.ref.resolveLp().thenApply(LPSubject::getTransientSubjectData);
}
@Override
public Subject subject() {
return handle().thenApply(handle -> handle.getParentSubject().sponge()).join();
}
@Override
public boolean isTransient() {
return !this.enduring;
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull Map<Set<Context>, Map<String, Boolean>> getAllPermissions() {
public @NonNull Map<Set<Context>, Map<String, Boolean>> allPermissions() {
return (Map) handle().thenApply(handle -> handle.getAllPermissions().entrySet().stream()
.collect(ImmutableCollectors.toMap(
e -> CompatibilityUtil.convertContexts(e.getKey()),
@ -73,7 +90,7 @@ public final class SubjectDataProxy implements SubjectData, ProxiedServiceObject
}
@Override
public @NonNull Map<String, Boolean> getPermissions(@NonNull Set<Context> contexts) {
public @NonNull Map<String, Boolean> permissions(@NonNull Set<Context> contexts) {
return handle().thenApply(handle -> handle.getPermissions(CompatibilityUtil.convertContexts(contexts))).join();
}
@ -86,6 +103,43 @@ public final class SubjectDataProxy implements SubjectData, ProxiedServiceObject
));
}
@Override
public CompletableFuture<Boolean> setPermissions(Set<Context> contexts, Map<String, Boolean> permissions, TransferMethod method) {
CompletableFuture<Boolean> fut;
if (method == TransferMethod.OVERWRITE) {
fut = clearPermissions(contexts);
} else {
fut = CompletableFuture.completedFuture(true);
}
return fut.thenCompose(bool -> permissions.entrySet().stream()
.map(entry -> setPermission(contexts, entry.getKey(), Tristate.fromBoolean(entry.getValue())))
.collect(CompletableFutures.collector())
)
.thenApply(x -> true);
}
@Override
public Tristate fallbackPermissionValue(Set<Context> contexts) {
// TODO: check subject type here to return a more appropriate value?
return Tristate.UNDEFINED;
}
@Override
public Map<Set<Context>, Tristate> allFallbackPermissionValues() {
return ImmutableMap.of();
}
@Override
public CompletableFuture<Boolean> setFallbackPermissionValue(Set<Context> contexts, Tristate fallback) {
throw new UnsupportedOperationException("LuckPerms does not support setting fallback permission values");
}
@Override
public CompletableFuture<Boolean> clearFallbackPermissionValues() {
return CompletableFuture.completedFuture(true);
}
@Override
public @NonNull CompletableFuture<Boolean> clearPermissions() {
return handle().thenCompose(LPSubjectData::clearPermissions);
@ -98,7 +152,7 @@ public final class SubjectDataProxy implements SubjectData, ProxiedServiceObject
@SuppressWarnings("rawtypes")
@Override
public @NonNull Map<Set<Context>, List<org.spongepowered.api.service.permission.SubjectReference>> getAllParents() {
public @NonNull Map<Set<Context>, List<org.spongepowered.api.service.permission.SubjectReference>> allParents() {
return (Map) handle().thenApply(handle -> handle.getAllParents().entrySet().stream()
.collect(ImmutableCollectors.toMap(
e -> CompatibilityUtil.convertContexts(e.getKey()),
@ -108,10 +162,15 @@ public final class SubjectDataProxy implements SubjectData, ProxiedServiceObject
@SuppressWarnings("rawtypes")
@Override
public @NonNull List<org.spongepowered.api.service.permission.SubjectReference> getParents(@NonNull Set<Context> contexts) {
public @NonNull List<org.spongepowered.api.service.permission.SubjectReference> parents(@NonNull Set<Context> contexts) {
return (List) handle().thenApply(handle -> handle.getParents(CompatibilityUtil.convertContexts(contexts))).join();
}
@Override
public CompletableFuture<Boolean> setParents(Set<Context> contexts, List<? extends SubjectReference> parents, TransferMethod method) {
return null;
}
@Override
public @NonNull CompletableFuture<Boolean> addParent(@NonNull Set<Context> contexts, org.spongepowered.api.service.permission.@NonNull SubjectReference ref) {
return handle().thenCompose(handle -> handle.addParent(CompatibilityUtil.convertContexts(contexts), this.service.getReferenceFactory().obtain(ref)));
@ -134,7 +193,7 @@ public final class SubjectDataProxy implements SubjectData, ProxiedServiceObject
@SuppressWarnings("rawtypes")
@Override
public @NonNull Map<Set<Context>, Map<String, String>> getAllOptions() {
public @NonNull Map<Set<Context>, Map<String, String>> allOptions() {
return (Map) handle().thenApply(handle -> handle.getAllOptions().entrySet().stream()
.collect(ImmutableCollectors.toMap(
e -> CompatibilityUtil.convertContexts(e.getKey()),
@ -143,7 +202,7 @@ public final class SubjectDataProxy implements SubjectData, ProxiedServiceObject
}
@Override
public @NonNull Map<String, String> getOptions(@NonNull Set<Context> contexts) {
public @NonNull Map<String, String> options(@NonNull Set<Context> contexts) {
return handle().thenApply(handle -> handle.getOptions(CompatibilityUtil.convertContexts(contexts))).join();
}
@ -156,6 +215,11 @@ public final class SubjectDataProxy implements SubjectData, ProxiedServiceObject
}
}
@Override
public CompletableFuture<Boolean> setOptions(Set<Context> contexts, Map<String, String> options, TransferMethod method) {
return null;
}
@Override
public @NonNull CompletableFuture<Boolean> clearOptions() {
return handle().thenCompose(LPSubjectData::clearOptions);
@ -166,6 +230,16 @@ public final class SubjectDataProxy implements SubjectData, ProxiedServiceObject
return handle().thenCompose(handle -> handle.clearOptions(CompatibilityUtil.convertContexts(contexts)));
}
@Override
public CompletableFuture<Boolean> copyFrom(SubjectData other, TransferMethod method) {
return null;
}
@Override
public CompletableFuture<Boolean> moveFrom(SubjectData other, TransferMethod method) {
return null;
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
@ -176,15 +250,11 @@ public final class SubjectDataProxy implements SubjectData, ProxiedServiceObject
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.ref.hashCode();
result = result * PRIME + (this.enduring ? 79 : 97);
return result;
return Objects.hash(this.ref, this.enduring);
}
@Override
public String toString() {
return "luckperms.api7.SubjectDataProxy(ref=" + this.ref + ", enduring=" + this.enduring + ")";
return "luckperms.api8.SubjectDataProxy(ref=" + this.ref + ", enduring=" + this.enduring + ")";
}
}

View File

@ -23,21 +23,23 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.proxy.api7;
package me.lucko.luckperms.sponge.service.proxy.api8;
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPProxiedServiceObject;
import me.lucko.luckperms.sponge.service.model.LPProxiedSubject;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import me.lucko.luckperms.sponge.service.model.ProxiedSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectUser;
import net.luckperms.api.query.QueryOptions;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.event.Cause;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
@ -50,12 +52,10 @@ import java.util.Set;
import java.util.concurrent.CompletableFuture;
@SuppressWarnings("unchecked")
public final class SubjectProxy implements Subject, ProxiedSubject, ProxiedServiceObject {
public final class SubjectProxy implements Subject, LPProxiedSubject, LPProxiedServiceObject {
private final LPPermissionService service;
private final LPSubjectReference ref;
private QueryOptionsSupplier queryOptionsSupplier;
public SubjectProxy(LPPermissionService service, LPSubjectReference ref) {
this.service = service;
this.ref = ref;
@ -65,14 +65,6 @@ public final class SubjectProxy implements Subject, ProxiedSubject, ProxiedServi
return this.ref.resolveLp();
}
// lazy init
private QueryOptionsSupplier queryOptionsCache() {
if (this.queryOptionsSupplier == null) {
this.queryOptionsSupplier = this.service.getContextManager().getCacheFor(this);
}
return this.queryOptionsSupplier;
}
@Override
public @NonNull LPSubjectReference asSubjectReference() {
return this.ref;
@ -80,17 +72,12 @@ public final class SubjectProxy implements Subject, ProxiedSubject, ProxiedServi
@Override
public @NonNull QueryOptions getQueryOptions() {
return queryOptionsCache().getQueryOptions();
return this.service.getContextManager().getQueryOptions(this);
}
@Override
public @NonNull Optional<CommandSource> getCommandSource() {
return handle().thenApply(LPSubject::getCommandSource).join();
}
@Override
public @NonNull SubjectCollection getContainingCollection() {
return this.service.getCollection(this.ref.getCollectionIdentifier()).sponge();
public @NonNull SubjectCollection containingCollection() {
return this.service.getCollection(this.ref.collectionIdentifier()).sponge();
}
@Override
@ -99,75 +86,77 @@ public final class SubjectProxy implements Subject, ProxiedSubject, ProxiedServi
}
@Override
public SubjectData getSubjectData() {
public SubjectData subjectData() {
return new SubjectDataProxy(this.service, this.ref, true);
}
@Override
public SubjectData getTransientSubjectData() {
public SubjectData transientSubjectData() {
return new SubjectDataProxy(this.service, this.ref, false);
}
@Override
public boolean hasPermission(@NonNull Set<Context> contexts, @NonNull String permission) {
return handle().thenApply(handle -> handle.getPermissionValue(CompatibilityUtil.convertContexts(contexts), permission).asBoolean()).join();
public @NonNull Tristate permissionValue(@NonNull String permission, @NonNull Cause cause) {
return handle().thenApply(handle -> CompatibilityUtil.convertTristate(handle.getPermissionValue(this.service.getContextsForCause(cause), permission))).join();
}
@Override
public boolean hasPermission(@NonNull String permission) {
return handle().thenApply(handle -> handle.getPermissionValue(queryOptionsCache().getContextSet(), permission).asBoolean()).join();
}
@Override
public @NonNull Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String permission) {
public @NonNull Tristate permissionValue(@NonNull String permission, @NonNull Set<Context> contexts) {
return handle().thenApply(handle -> CompatibilityUtil.convertTristate(handle.getPermissionValue(CompatibilityUtil.convertContexts(contexts), permission))).join();
}
@Override
public boolean isChildOf(@NonNull SubjectReference parent) {
return handle().thenApply(handle -> handle.isChildOf(queryOptionsCache().getContextSet(), this.service.getReferenceFactory().obtain(parent))).join();
public boolean isChildOf(@NonNull SubjectReference parent, @NonNull Cause cause) {
return handle().thenApply(handle -> handle.isChildOf(this.service.getContextsForCause(cause), this.service.getReferenceFactory().obtain(parent))).join();
}
@Override
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull SubjectReference parent) {
public boolean isChildOf(@NonNull SubjectReference parent, @NonNull Set<Context> contexts) {
return handle().thenApply(handle -> handle.isChildOf(CompatibilityUtil.convertContexts(contexts), this.service.getReferenceFactory().obtain(parent))).join();
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull List<SubjectReference> getParents() {
return (List) handle().thenApply(handle -> handle.getParents(queryOptionsCache().getContextSet())).join();
}
@SuppressWarnings("rawtypes")
@Override
public @NonNull List<SubjectReference> getParents(@NonNull Set<Context> contexts) {
return (List) handle().thenApply(handle -> handle.getParents(CompatibilityUtil.convertContexts(contexts))).join();
public List<? extends SubjectReference> parents(@NonNull Cause cause) {
return handle().thenApply(handle -> handle.getParents(this.service.getContextsForCause(cause))).join();
}
@Override
public @NonNull Optional<String> getOption(@NonNull Set<Context> contexts, @NonNull String key) {
public @NonNull List<? extends SubjectReference> parents(@NonNull Set<Context> contexts) {
return handle().thenApply(handle -> handle.getParents(CompatibilityUtil.convertContexts(contexts))).join();
}
@Override
public Optional<String> option(@NonNull String key, @NonNull Cause cause) {
return handle().thenApply(handle -> handle.getOption(this.service.getContextsForCause(cause), key)).join();
}
@Override
public @NonNull Optional<String> option(@NonNull String key, @NonNull Set<Context> contexts) {
return handle().thenApply(handle -> handle.getOption(CompatibilityUtil.convertContexts(contexts), key)).join();
}
@Override
public @NonNull Optional<String> getOption(@NonNull String key) {
return handle().thenApply(handle -> handle.getOption(queryOptionsCache().getContextSet(), key)).join();
public String identifier() {
return this.ref.subjectIdentifier();
}
@Override
public String getIdentifier() {
return this.ref.getSubjectIdentifier();
}
@Override
public @NonNull Optional<String> getFriendlyIdentifier() {
public @NonNull Optional<String> friendlyIdentifier() {
return handle().thenApply(LPSubject::getFriendlyIdentifier).join();
}
@Override
public @NonNull Set<Context> getActiveContexts() {
return CompatibilityUtil.convertContexts(queryOptionsCache().getContextSet());
public Optional<?> associatedObject() {
if (this.ref.collectionIdentifier().equals(PermissionService.SUBJECTS_USER)) {
LPSubject lpSubject = handle().join();
if (lpSubject instanceof LPSubjectUser) {
ServerPlayer player = ((LPSubjectUser) lpSubject).resolvePlayer().orElse(null);
if (player != null) {
return Optional.of(player);
}
}
}
return Optional.empty();
}
@Override
@ -182,6 +171,6 @@ public final class SubjectProxy implements Subject, ProxiedSubject, ProxiedServi
@Override
public String toString() {
return "luckperms.api7.SubjectProxy(ref=" + this.ref + ")";
return "luckperms.api8.SubjectProxy(ref=" + this.ref + ")";
}
}

View File

@ -1,11 +1,11 @@
repositories {
maven { url 'https://repo.spongepowered.org/maven' }
maven { url 'https://repo.spongepowered.org/repository/maven-public/' }
}
dependencies {
implementation project(':common')
compileOnly('org.spongepowered:spongeapi:7.2.0') {
compileOnly('org.spongepowered:spongeapi:8.0.0') {
exclude(module: 'configurate-core')
exclude(module: 'configurate-hocon')
exclude(module: 'configurate-gson')

View File

@ -23,14 +23,11 @@
* SOFTWARE.
*/
package org.spongepowered.api.event.permission;
package me.lucko.luckperms.sponge.service;
import org.spongepowered.api.event.Event;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.service.context.ContextService;
import org.spongepowered.api.service.permission.PermissionService;
// Copy of https://github.com/SpongePowered/SpongeAPI/blob/api-8/src/main/java/org/spongepowered/api/event/permission/SubjectDataUpdateEvent.java
public interface SubjectDataUpdateEvent extends Event {
public interface PermissionAndContextService extends PermissionService, ContextService {
SubjectData getUpdatedData();
}
}

View File

@ -25,9 +25,10 @@
package me.lucko.luckperms.sponge.service.model;
import org.spongepowered.api.plugin.PluginContainer;
import net.kyori.adventure.text.Component;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.text.Text;
import org.spongepowered.plugin.PluginContainer;
import java.util.Map;
import java.util.Optional;
@ -44,7 +45,7 @@ public interface LPPermissionDescription {
String getId();
Optional<Text> getDescription();
Optional<Component> getDescription();
Optional<PluginContainer> getOwner();

View File

@ -30,14 +30,18 @@ import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.common.context.manager.ContextManager;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.sponge.service.PermissionAndContextService;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.plugin.PluginContainer;
import net.kyori.adventure.text.Component;
import net.luckperms.api.context.ImmutableContextSet;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.event.Cause;
import org.spongepowered.api.service.context.ContextCalculator;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.text.Text;
import org.spongepowered.plugin.PluginContainer;
import java.util.Optional;
import java.util.function.Predicate;
@ -49,11 +53,11 @@ public interface LPPermissionService {
LuckPermsPlugin getPlugin();
ContextManager<Subject, Player> getContextManager();
ContextManager<Subject, ServerPlayer> getContextManager();
SubjectReferenceFactory getReferenceFactory();
PermissionService sponge();
PermissionAndContextService sponge();
LPSubjectCollection getUserSubjects();
@ -69,13 +73,19 @@ public interface LPPermissionService {
ImmutableMap<String, LPSubjectCollection> getLoadedCollections();
LPPermissionDescription registerPermissionDescription(String id, Text description, PluginContainer owner);
LPPermissionDescription registerPermissionDescription(String id, Component description, PluginContainer owner);
Optional<LPPermissionDescription> getDescription(String permission);
ImmutableCollection<LPPermissionDescription> getDescriptions();
void registerContextCalculator(ContextCalculator<Subject> calculator);
void registerContextCalculator(ContextCalculator calculator);
ImmutableContextSet getContextsForCause(Cause cause);
ImmutableContextSet getContextsForCurrentCause();
void fireUpdateEvent(LPSubjectData subjectData);
void invalidateAllCaches();
}

View File

@ -28,6 +28,6 @@ package me.lucko.luckperms.sponge.service.model;
/**
* Marks that an object is a proxy implementation for a PermissionService related class.
*/
public interface ProxiedServiceObject {
public interface LPProxiedServiceObject {
}

View File

@ -33,7 +33,7 @@ import org.spongepowered.api.service.permission.Subject;
/**
* Marks that an object is a proxied representation of a {@link Subject}.
*/
public interface ProxiedSubject extends Subject, ProxiedServiceObject {
public interface LPProxiedSubject extends Subject, LPProxiedServiceObject {
@Override
@NonNull LPSubjectReference asSubjectReference();

View File

@ -33,7 +33,6 @@ import net.luckperms.api.context.ImmutableContextSet;
import net.luckperms.api.query.QueryOptions;
import net.luckperms.api.util.Tristate;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.permission.Subject;
import java.util.Optional;
@ -43,7 +42,7 @@ import java.util.Optional;
*/
public interface LPSubject {
ProxiedSubject sponge();
LPProxiedSubject sponge();
LPPermissionService getService();
@ -59,10 +58,6 @@ public interface LPSubject {
return Optional.empty();
}
default Optional<CommandSource> getCommandSource() {
return Optional.empty();
}
LPSubjectCollection getParentCollection();
LPSubjectData getSubjectData();

View File

@ -35,7 +35,6 @@ import net.luckperms.api.query.dataorder.DataQueryOrder;
import org.spongepowered.api.service.permission.SubjectCollection;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
@ -71,7 +70,7 @@ public interface LPSubjectCollection {
CompletableFuture<Boolean> hasRegistered(String identifier);
CompletableFuture<ImmutableCollection<LPSubject>> loadSubjects(Set<String> identifiers);
CompletableFuture<ImmutableCollection<LPSubject>> loadSubjects(Iterable<String> identifiers);
ImmutableCollection<LPSubject> getLoadedSubjects();

View File

@ -23,20 +23,14 @@
* SOFTWARE.
*/
package org.spongepowered.api.service.permission;
package me.lucko.luckperms.sponge.service.model;
import java.util.concurrent.CompletableFuture;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
/**
* This is included, as the interface didn't exist in API6.
* We just shade it into the LP jar so we can still implement it. :)
*/
public interface SubjectReference {
import java.util.Optional;
String getCollectionIdentifier();
public interface LPSubjectUser extends LPSubject {
String getSubjectIdentifier();
Optional<ServerPlayer> resolvePlayer();
CompletableFuture<Subject> resolve();
}
}

View File

@ -76,12 +76,12 @@ final class CachedSubjectReference implements LPSubjectReference {
}
@Override
public @NonNull String getCollectionIdentifier() {
public @NonNull String collectionIdentifier() {
return this.collectionIdentifier;
}
@Override
public @NonNull String getSubjectIdentifier() {
public @NonNull String subjectIdentifier() {
return this.subjectIdentifier;
}
@ -158,8 +158,8 @@ final class CachedSubjectReference implements LPSubjectReference {
if (o == this) return true;
if (!(o instanceof LPSubjectReference)) return false;
final LPSubjectReference other = (LPSubjectReference) o;
return this.collectionIdentifier.equals(other.getCollectionIdentifier()) &&
this.subjectIdentifier.equals(other.getSubjectIdentifier());
return this.collectionIdentifier.equals(other.collectionIdentifier()) &&
this.subjectIdentifier.equals(other.subjectIdentifier());
}
@Override

View File

@ -30,9 +30,9 @@ import com.google.common.base.Splitter;
import me.lucko.luckperms.common.util.CaffeineFactory;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPProxiedSubject;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.ProxiedSubject;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectReference;
@ -86,11 +86,11 @@ public final class SubjectReferenceFactory {
public LPSubjectReference obtain(Subject subject) {
Objects.requireNonNull(subject, "subject");
if (subject instanceof ProxiedSubject) {
return ((ProxiedSubject) subject).asSubjectReference();
if (subject instanceof LPProxiedSubject) {
return ((LPProxiedSubject) subject).asSubjectReference();
}
return obtain(subject.getContainingCollection().getIdentifier(), subject.getIdentifier());
return obtain(subject.containingCollection().identifier(), subject.identifier());
}
public LPSubjectReference obtain(SubjectReference reference) {
@ -98,7 +98,7 @@ public final class SubjectReferenceFactory {
if (reference instanceof LPSubjectReference) {
return (LPSubjectReference) reference;
} else {
return obtain(reference.getCollectionIdentifier(), reference.getSubjectIdentifier());
return obtain(reference.collectionIdentifier(), reference.subjectIdentifier());
}
}
@ -119,23 +119,15 @@ public final class SubjectReferenceFactory {
private SubjectReferenceAttributes(String collectionId, String id) {
this.collectionId = collectionId.toLowerCase(Locale.ROOT);
this.id = id.toLowerCase(Locale.ROOT);
this.hashCode = calculateHashCode();
this.hashCode = Objects.hash(this.collectionId, this.id);
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof SubjectReferenceAttributes)) return false;
final SubjectReferenceAttributes other = (SubjectReferenceAttributes) o;
return this.collectionId.equals(other.collectionId) && this.id.equals(other.id);
}
private int calculateHashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.collectionId.hashCode();
result = result * PRIME + this.id.hashCode();
return result;
final SubjectReferenceAttributes that = (SubjectReferenceAttributes) o;
return this.collectionId.equals(that.collectionId) && this.id.equals(that.id);
}
@Override

View File

@ -29,33 +29,30 @@ import com.google.inject.Inject;
import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap;
import me.lucko.luckperms.common.plugin.classpath.ClassPathAppender;
import me.lucko.luckperms.common.plugin.classpath.ReflectionClassPathAppender;
import me.lucko.luckperms.common.plugin.logging.Log4jPluginLogger;
import me.lucko.luckperms.common.plugin.logging.PluginLogger;
import me.lucko.luckperms.common.plugin.logging.Slf4jPluginLogger;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
import me.lucko.luckperms.common.util.MoreFiles;
import org.slf4j.Logger;
import net.luckperms.api.platform.Platform;
import org.apache.logging.log4j.Logger;
import org.spongepowered.api.Game;
import org.spongepowered.api.Platform;
import org.spongepowered.api.Platform.Component;
import org.spongepowered.api.Server;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.config.ConfigDir;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.Order;
import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
import org.spongepowered.api.plugin.Dependency;
import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.event.lifecycle.ConstructPluginEvent;
import org.spongepowered.api.event.lifecycle.StoppingEngineEvent;
import org.spongepowered.api.profile.GameProfile;
import org.spongepowered.api.scheduler.AsynchronousExecutor;
import org.spongepowered.api.scheduler.Scheduler;
import org.spongepowered.api.scheduler.SpongeExecutorService;
import org.spongepowered.api.scheduler.SynchronousExecutor;
import org.spongepowered.plugin.PluginContainer;
import org.spongepowered.plugin.builtin.jvm.Plugin;
import org.spongepowered.plugin.metadata.PluginMetadata;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.time.Instant;
import java.util.ArrayList;
@ -69,18 +66,7 @@ import java.util.concurrent.CountDownLatch;
/**
* Bootstrap plugin for LuckPerms running on Sponge.
*/
@Plugin(
id = "luckperms",
name = "LuckPerms",
version = "@version@",
authors = "Luck",
description = "A permissions plugin",
url = "https://luckperms.net",
dependencies = {
// explicit dependency on spongeapi with no defined API version
@Dependency(id = "spongeapi")
}
)
@Plugin("luckperms")
public class LPSpongeBootstrap implements LuckPermsBootstrap {
/**
@ -91,7 +77,7 @@ public class LPSpongeBootstrap implements LuckPermsBootstrap {
/**
* A scheduler adapter for the platform
*/
private final SchedulerAdapter schedulerAdapter;
private final SpongeSchedulerAdapter schedulerAdapter;
/**
* The plugin class path appender
@ -115,33 +101,27 @@ public class LPSpongeBootstrap implements LuckPermsBootstrap {
/**
* Reference to the central {@link Game} instance in the API
*/
@Inject
private Game game;
/**
* Reference to the sponge scheduler
*/
private final Scheduler spongeScheduler;
/**
* Injected configuration directory for the plugin
*/
@Inject
@ConfigDir(sharedRoot = false)
private Path configDirectory;
private final Game game;
/**
* Injected plugin container for the plugin
*/
@Inject
private PluginContainer pluginContainer;
private final PluginContainer pluginContainer;
/**
* Injected configuration directory for the plugin
*/
private final Path configDirectory;
@Inject
public LPSpongeBootstrap(Logger logger, @SynchronousExecutor SpongeExecutorService syncExecutor, @AsynchronousExecutor SpongeExecutorService asyncExecutor) {
this.logger = new Slf4jPluginLogger(logger);
this.spongeScheduler = Sponge.getScheduler();
this.schedulerAdapter = new SpongeSchedulerAdapter(this, this.spongeScheduler, syncExecutor, asyncExecutor);
this.classPathAppender = new ReflectionClassPathAppender(this);
public LPSpongeBootstrap(Logger logger, Game game, PluginContainer pluginContainer, @ConfigDir(sharedRoot = false) Path configDirectory) {
this.logger = new Log4jPluginLogger(logger);
this.game = game;
this.pluginContainer = pluginContainer;
this.configDirectory = configDirectory;
this.schedulerAdapter = new SpongeSchedulerAdapter(this.game, this.pluginContainer);
this.classPathAppender = new SpongeClassPathAppender(this);
this.plugin = new LPSpongePlugin(this);
}
@ -153,7 +133,7 @@ public class LPSpongeBootstrap implements LuckPermsBootstrap {
}
@Override
public SchedulerAdapter getScheduler() {
public SpongeSchedulerAdapter getScheduler() {
return this.schedulerAdapter;
}
@ -163,9 +143,8 @@ public class LPSpongeBootstrap implements LuckPermsBootstrap {
}
// lifecycle
@Listener(order = Order.FIRST)
public void onEnable(GamePreInitializationEvent event) {
public void onEnable(ConstructPluginEvent event) {
this.startTime = Instant.now();
try {
this.plugin.load();
@ -180,13 +159,8 @@ public class LPSpongeBootstrap implements LuckPermsBootstrap {
}
}
@Listener(order = Order.LATE)
public void onLateEnable(GamePreInitializationEvent event) {
this.plugin.lateEnable();
}
@Listener
public void onDisable(GameStoppingServerEvent event) {
public void onDisable(StoppingEngineEvent<Server> event) {
this.plugin.disable();
}
@ -207,22 +181,22 @@ public class LPSpongeBootstrap implements LuckPermsBootstrap {
}
public Optional<Server> getServer() {
return this.game.isServerAvailable() ? Optional.of(this.game.getServer()) : Optional.empty();
}
public Scheduler getSpongeScheduler() {
return this.spongeScheduler;
return this.game.isServerAvailable() ? Optional.of(this.game.server()) : Optional.empty();
}
public PluginContainer getPluginContainer() {
return this.pluginContainer;
}
public void registerListeners(Object obj) {
this.game.eventManager().registerListeners(this.pluginContainer, obj);
}
// provide information about the plugin
@Override
public String getVersion() {
return "@version@";
return this.pluginContainer.metadata().version().toString();
}
@Override
@ -233,25 +207,26 @@ public class LPSpongeBootstrap implements LuckPermsBootstrap {
// provide information about the platform
@Override
public net.luckperms.api.platform.Platform.Type getType() {
return net.luckperms.api.platform.Platform.Type.SPONGE;
public Platform.Type getType() {
return Platform.Type.SPONGE;
}
@Override
public String getServerBrand() {
return this.game.getPlatform().getContainer(Platform.Component.IMPLEMENTATION).getName();
PluginMetadata brandMetadata = this.game.platform().container(Component.IMPLEMENTATION).metadata();
return brandMetadata.name().orElseGet(brandMetadata::id);
}
@Override
public String getServerVersion() {
PluginContainer api = this.game.getPlatform().getContainer(Platform.Component.API);
PluginContainer impl = this.game.getPlatform().getContainer(Platform.Component.IMPLEMENTATION);
return api.getName() + ": " + api.getVersion().orElse("null") + " - " + impl.getName() + ": " + impl.getVersion().orElse("null");
PluginMetadata api = this.game.platform().container(Component.API).metadata();
PluginMetadata impl = this.game.platform().container(Component.IMPLEMENTATION).metadata();
return api.name().orElse("API") + ": " + api.version() + " - " + impl.name().orElse("Impl") + ": " + impl.version();
}
@Override
public Path getDataDirectory() {
Path dataDirectory = this.game.getGameDirectory().toAbsolutePath().resolve("luckperms");
Path dataDirectory = this.game.gameDirectory().toAbsolutePath().resolve("luckperms");
try {
MoreFiles.createDirectoriesIfNotExists(dataDirectory);
} catch (IOException e) {
@ -266,14 +241,19 @@ public class LPSpongeBootstrap implements LuckPermsBootstrap {
}
@Override
public Optional<Player> getPlayer(UUID uniqueId) {
return getServer().flatMap(s -> s.getPlayer(uniqueId));
public InputStream getResourceStream(String path) {
return getClass().getClassLoader().getResourceAsStream(path);
}
@Override
public Optional<ServerPlayer> getPlayer(UUID uniqueId) {
return getServer().flatMap(s -> s.player(uniqueId));
}
@Override
public Optional<UUID> lookupUniqueId(String username) {
return getServer().flatMap(server -> server.getGameProfileManager().get(username)
.thenApply(p -> Optional.of(p.getUniqueId()))
return getServer().flatMap(server -> server.gameProfileManager().profile(username)
.thenApply(p -> Optional.of(p.uniqueId()))
.exceptionally(x -> Optional.empty())
.join()
);
@ -281,8 +261,8 @@ public class LPSpongeBootstrap implements LuckPermsBootstrap {
@Override
public Optional<String> lookupUsername(UUID uniqueId) {
return getServer().flatMap(server -> server.getGameProfileManager().get(uniqueId)
.thenApply(GameProfile::getName)
return getServer().flatMap(server -> server.gameProfileManager().profile(uniqueId)
.thenApply(GameProfile::name)
.exceptionally(x -> Optional.empty())
.join()
);
@ -290,16 +270,16 @@ public class LPSpongeBootstrap implements LuckPermsBootstrap {
@Override
public int getPlayerCount() {
return getServer().map(server -> server.getOnlinePlayers().size()).orElse(0);
return getServer().map(server -> server.onlinePlayers().size()).orElse(0);
}
@Override
public Collection<String> getPlayerList() {
return getServer().map(server -> {
Collection<Player> players = server.getOnlinePlayers();
Collection<ServerPlayer> players = server.onlinePlayers();
List<String> list = new ArrayList<>(players.size());
for (Player player : players) {
list.add(player.getName());
list.add(player.name());
}
return list;
}).orElse(Collections.emptyList());
@ -308,10 +288,10 @@ public class LPSpongeBootstrap implements LuckPermsBootstrap {
@Override
public Collection<UUID> getOnlinePlayers() {
return getServer().map(server -> {
Collection<Player> players = server.getOnlinePlayers();
Collection<ServerPlayer> players = server.onlinePlayers();
List<UUID> list = new ArrayList<>(players.size());
for (Player player : players) {
list.add(player.getUniqueId());
list.add(player.uniqueId());
}
return list;
}).orElse(Collections.emptyList());
@ -319,7 +299,7 @@ public class LPSpongeBootstrap implements LuckPermsBootstrap {
@Override
public boolean isPlayerOnline(UUID uniqueId) {
return getServer().flatMap(server -> server.getPlayer(uniqueId).map(Player::isOnline)).orElse(false);
return getServer().map(server -> server.player(uniqueId).isPresent()).orElse(false);
}
}

View File

@ -27,7 +27,6 @@ package me.lucko.luckperms.sponge;
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
import me.lucko.luckperms.common.calculator.CalculatorFactory;
import me.lucko.luckperms.common.command.abstraction.Command;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.config.generic.adapter.ConfigurationAdapter;
@ -38,34 +37,42 @@ import me.lucko.luckperms.common.messaging.MessagingFactory;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.model.manager.track.StandardTrackManager;
import me.lucko.luckperms.common.plugin.AbstractLuckPermsPlugin;
import me.lucko.luckperms.common.sender.AbstractSender;
import me.lucko.luckperms.common.sender.DummyConsoleSender;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.MoreFiles;
import me.lucko.luckperms.sponge.calculator.SpongeCalculatorFactory;
import me.lucko.luckperms.sponge.commands.SpongeParentCommand;
import me.lucko.luckperms.sponge.context.SpongeContextManager;
import me.lucko.luckperms.sponge.context.SpongePlayerCalculator;
import me.lucko.luckperms.sponge.listeners.SpongeCommandListUpdater;
import me.lucko.luckperms.sponge.listeners.SpongeConnectionListener;
import me.lucko.luckperms.sponge.listeners.SpongePlatformListener;
import me.lucko.luckperms.sponge.messaging.SpongeMessagingFactory;
import me.lucko.luckperms.sponge.model.manager.SpongeGroupManager;
import me.lucko.luckperms.sponge.model.manager.SpongeUserManager;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.ProxyFactory;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.model.ProxiedServiceObject;
import me.lucko.luckperms.sponge.service.model.persisted.PersistedCollection;
import me.lucko.luckperms.sponge.tasks.ServiceCacheHousekeepingTask;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.query.QueryOptions;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.command.Command;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.lifecycle.ProvideServiceEvent;
import org.spongepowered.api.event.lifecycle.RegisterCommandEvent;
import org.spongepowered.api.service.context.ContextService;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.plugin.PluginContainer;
import java.util.Collection;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@ -88,8 +95,6 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
private SpongeContextManager contextManager;
private LuckPermsService service;
private boolean lateLoad = false;
public LPSpongePlugin(LPSpongeBootstrap bootstrap) {
this.bootstrap = bootstrap;
}
@ -107,8 +112,11 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
@Override
protected Set<Dependency> getGlobalDependencies() {
Set<Dependency> dependencies = super.getGlobalDependencies();
dependencies.add(Dependency.ADVENTURE_PLATFORM);
//dependencies.add(Dependency.ADVENTURE_PLATFORM);
//dependencies.add(Dependency.ADVENTURE_PLATFORM_SPONGEAPI);
dependencies.remove(Dependency.ADVENTURE);
dependencies.add(Dependency.CONFIGURATE_CORE);
dependencies.add(Dependency.CONFIGURATE_HOCON);
dependencies.add(Dependency.HOCON_CONFIG);
@ -117,14 +125,14 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
@Override
protected ConfigurationAdapter provideConfigurationAdapter() {
return new SpongeConfigAdapter(this, resolveConfig("luckperms.conf"));
return new SpongeConfigAdapter(this, resolveConfig());
}
@Override
protected void registerPlatformListeners() {
this.connectionListener = new SpongeConnectionListener(this);
this.bootstrap.getGame().getEventManager().registerListeners(this.bootstrap, this.connectionListener);
this.bootstrap.getGame().getEventManager().registerListeners(this.bootstrap, new SpongePlatformListener(this));
this.bootstrap.registerListeners(this.connectionListener);
this.bootstrap.registerListeners(new SpongePlatformListener(this));
}
@Override
@ -135,7 +143,22 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
@Override
protected void registerCommands() {
this.commandManager = new SpongeCommandExecutor(this);
this.bootstrap.getGame().getCommandManager().register(this.bootstrap, this.commandManager, "luckperms", "lp", "perm", "perms", "permission", "permissions");
this.bootstrap.registerListeners(new RegisterCommandsListener(this.bootstrap.getPluginContainer(), this.commandManager));
}
public static final class RegisterCommandsListener {
private final PluginContainer pluginContainer;
private final Command.Raw command;
RegisterCommandsListener(PluginContainer pluginContainer, Command.Raw command) {
this.pluginContainer = pluginContainer;
this.command = command;
}
@Listener
public void onCommandRegister(RegisterCommandEvent<Command.Raw> event) {
event.register(this.pluginContainer, this.command, "luckperms", "lp", "perm", "perms", "permission", "permissions");
}
}
@Override
@ -154,36 +177,46 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
protected void setupContextManager() {
this.contextManager = new SpongeContextManager(this);
SpongePlayerCalculator playerCalculator = new SpongePlayerCalculator(this, getConfiguration().get(ConfigKeys.DISABLED_CONTEXTS));
this.bootstrap.getGame().getEventManager().registerListeners(this.bootstrap, playerCalculator);
SpongePlayerCalculator playerCalculator = new SpongePlayerCalculator(this);
this.bootstrap.registerListeners(playerCalculator);
this.contextManager.registerCalculator(playerCalculator);
}
@Override
protected void setupPlatformHooks() {
getLogger().info("Registering PermissionService...");
this.service = new LuckPermsService(this);
PermissionService oldService = this.bootstrap.getGame().getServiceManager().provide(PermissionService.class).orElse(null);
if (oldService != null && !(oldService instanceof ProxiedServiceObject)) {
//PermissionService oldService = this.bootstrap.getGame().getServiceManager().provide(PermissionService.class).orElse(null);
//if (oldService != null && !(oldService instanceof ProxiedServiceObject)) {
//
// // before registering our permission service, copy any existing permission descriptions
// Collection<PermissionDescription> permissionDescriptions = oldService.getDescriptions();
// for (PermissionDescription description : permissionDescriptions) {
// if (description instanceof ProxiedServiceObject) {
// continue;
// }
// ProxyFactory.registerDescription(this.service, description);
// }
//}
// before registering our permission service, copy any existing permission descriptions
Collection<PermissionDescription> permissionDescriptions = oldService.getDescriptions();
for (PermissionDescription description : permissionDescriptions) {
if (description instanceof ProxiedServiceObject) {
continue;
}
ProxyFactory.registerDescription(this.service, description);
}
this.bootstrap.registerListeners(new RegisterServiceListener(this.service));
}
public static final class RegisterServiceListener {
private final LuckPermsService service;
RegisterServiceListener(LuckPermsService service) {
this.service = service;
}
if (this.bootstrap.getGame().getPluginManager().getPlugin("permissionsex").isPresent()) {
getLogger().warn("Detected PermissionsEx - assuming it's loaded for migration.");
getLogger().warn("Delaying LuckPerms PermissionService registration.");
this.lateLoad = true;
} else {
this.bootstrap.getGame().getServiceManager().setProvider(this.bootstrap, LPPermissionService.class, this.service);
this.bootstrap.getGame().getServiceManager().setProvider(this.bootstrap, PermissionService.class, this.service.sponge());
@Listener
public void onPermissionServiceProvide(ProvideServiceEvent.EngineScoped<PermissionService> event) {
event.suggest(this.service::sponge);
}
@Listener
public void onContextServiceProvide(ProvideServiceEvent.EngineScoped<ContextService> event) {
event.suggest(this.service::sponge);
}
}
@ -194,7 +227,20 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
@Override
protected void registerApiOnPlatform(LuckPerms api) {
this.bootstrap.getGame().getServiceManager().setProvider(this.bootstrap, LuckPerms.class, api);
this.bootstrap.registerListeners(new RegisterApiListener(api));
}
public static final class RegisterApiListener {
private final LuckPerms api;
RegisterApiListener(LuckPerms api) {
this.api = api;
}
@Listener
public void onLuckPermsServiceProvide(ProvideServiceEvent<LuckPerms> event) {
event.suggest(() -> this.api);
}
}
@Override
@ -209,13 +255,10 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
for (CommandPermission perm : CommandPermission.values()) {
this.service.registerPermissionDescription(perm.getPermission(), null, this.bootstrap.getPluginContainer());
}
}
public void lateEnable() {
if (this.lateLoad) {
getLogger().info("Providing late registration of PermissionService...");
this.bootstrap.getGame().getServiceManager().setProvider(this.bootstrap, LPPermissionService.class, this.service);
this.bootstrap.getGame().getServiceManager().setProvider(this.bootstrap, PermissionService.class, this.service.sponge());
// register sponge command list updater
if (getConfiguration().get(ConfigKeys.UPDATE_CLIENT_COMMAND_LIST)) {
getApiProvider().getEventBus().subscribe(new SpongeCommandListUpdater(this));
}
}
@ -229,6 +272,22 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
this.service.invalidateAllCaches();
}
private Path resolveConfig() {
Path path = this.bootstrap.getConfigDirectory().resolve("luckperms.conf");
if (!Files.exists(path)) {
try {
MoreFiles.createDirectoriesIfNotExists(this.bootstrap.getConfigDirectory());
try (InputStream is = getClass().getClassLoader().getResourceAsStream("luckperms.conf")) {
Files.copy(is, path);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return path;
}
@Override
public Optional<QueryOptions> getQueryOptionsForUser(User user) {
return this.bootstrap.getPlayer(user.getUniqueId()).map(player -> this.contextManager.getQueryOptions(player));
@ -238,26 +297,28 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin {
public Stream<Sender> getOnlineSenders() {
return Stream.concat(
Stream.of(getConsoleSender()),
this.bootstrap.getServer().map(server -> server.getOnlinePlayers().stream().map(s -> this.senderFactory.wrap(s))).orElseGet(Stream::empty)
this.bootstrap.getServer().map(server -> server.onlinePlayers().stream().map(s -> this.senderFactory.wrap(s))).orElseGet(Stream::empty)
);
}
@Override
public Sender getConsoleSender() {
if (this.bootstrap.getGame().isServerAvailable()) {
return this.senderFactory.wrap(this.bootstrap.getGame().getServer().getConsole());
return this.senderFactory.wrap(this.bootstrap.getGame().systemSubject());
} else {
return new DummyConsoleSender(this) {
@Override
public void sendMessage(Component message) {
LPSpongePlugin.this.getLogger().info(LegacyComponentSerializer.legacySection().serialize(TranslationManager.render(message)));
for (Component line : AbstractSender.splitNewlines(TranslationManager.render(message))) {
LPSpongePlugin.this.bootstrap.getPluginLogger().info(PlainTextComponentSerializer.plainText().serialize(line));
}
}
};
}
}
@Override
public List<Command<?>> getExtraCommands() {
public List<me.lucko.luckperms.common.command.abstraction.Command<?>> getExtraCommands() {
return Collections.singletonList(new SpongeParentCommand(this));
}

View File

@ -0,0 +1,64 @@
/*
* 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.sponge;
import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap;
import me.lucko.luckperms.common.plugin.classpath.ReflectionClassPathAppender;
import java.lang.reflect.Field;
import java.net.URLClassLoader;
public class SpongeClassPathAppender extends ReflectionClassPathAppender {
private static URLClassLoader extractClassLoaderFromBootstrap(LuckPermsBootstrap bootstrap) {
ClassLoader classLoader = bootstrap.getClass().getClassLoader();
// try to cast directly to URLClassLoader in case things change in the future
if (classLoader instanceof URLClassLoader) {
return (URLClassLoader) classLoader;
}
Class<? extends ClassLoader> classLoaderClass = classLoader.getClass();
if (!classLoaderClass.getName().equals("cpw.mods.modlauncher.TransformingClassLoader")) {
throw new IllegalStateException("ClassLoader is not instance of TransformingClassLoader: " + classLoaderClass.getName());
}
try {
Field delegatedClassLoaderField = classLoaderClass.getDeclaredField("delegatedClassLoader");
delegatedClassLoaderField.setAccessible(true);
Object delegatedClassLoader = delegatedClassLoaderField.get(classLoader);
return (URLClassLoader) delegatedClassLoader;
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public SpongeClassPathAppender(LuckPermsBootstrap bootstrap) throws IllegalStateException {
super(extractClassLoaderFromBootstrap(bootstrap));
}
}

View File

@ -30,23 +30,23 @@ import me.lucko.luckperms.common.command.utils.ArgumentTokenizer;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.sender.Sender;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.api.command.CommandCallable;
import org.spongepowered.api.command.Command;
import org.spongepowered.api.command.CommandCause;
import org.spongepowered.api.command.CommandCompletion;
import org.spongepowered.api.command.CommandResult;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.command.parameter.ArgumentReader;
import org.spongepowered.api.command.selector.Selector;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.selector.Selector;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;
import java.util.List;
import java.util.ListIterator;
import java.util.Optional;
import java.util.stream.Collectors;
public class SpongeCommandExecutor extends CommandManager implements CommandCallable {
public class SpongeCommandExecutor extends CommandManager implements Command.Raw {
private final LPSpongePlugin plugin;
public SpongeCommandExecutor(LPSpongePlugin plugin) {
@ -55,41 +55,44 @@ public class SpongeCommandExecutor extends CommandManager implements CommandCall
}
@Override
public @NonNull CommandResult process(@NonNull CommandSource source, @NonNull String args) {
Sender wrapped = this.plugin.getSenderFactory().wrap(source);
List<String> arguments = resolveSelectors(source, ArgumentTokenizer.EXECUTE.tokenizeInput(args));
public @NonNull CommandResult process(@NonNull CommandCause source, ArgumentReader.@NonNull Mutable args) {
Sender wrapped = this.plugin.getSenderFactory().wrap(source.audience());
List<String> arguments = resolveSelectors(source, ArgumentTokenizer.EXECUTE.tokenizeInput(args.input()));
executeCommand(wrapped, "lp", arguments);
return CommandResult.success();
}
@Override
public @NonNull List<String> getSuggestions(@NonNull CommandSource source, @NonNull String args, @Nullable Location<World> location) {
Sender wrapped = this.plugin.getSenderFactory().wrap(source);
List<String> arguments = resolveSelectors(source, ArgumentTokenizer.TAB_COMPLETE.tokenizeInput(args));
return tabCompleteCommand(wrapped, arguments);
public List<CommandCompletion> complete(@NonNull CommandCause source, ArgumentReader.@NonNull Mutable args) {
Sender wrapped = this.plugin.getSenderFactory().wrap(source.audience());
List<String> arguments = resolveSelectors(source, ArgumentTokenizer.TAB_COMPLETE.tokenizeInput(args.input()));
return tabCompleteCommand(wrapped, arguments)
.stream()
.map(CommandCompletion::of)
.collect(Collectors.toList());
}
@Override
public boolean testPermission(@NonNull CommandSource source) {
public boolean canExecute(CommandCause cause) {
return true; // we run permission checks internally
}
@Override
public @NonNull Optional<Text> getShortDescription(@NonNull CommandSource source) {
return Optional.of(Text.of("Manage permissions"));
public Optional<Component> shortDescription(CommandCause cause) {
return Optional.of(Component.text("Manage permissions"));
}
@Override
public @NonNull Optional<Text> getHelp(@NonNull CommandSource source) {
return Optional.of(Text.of("Run /luckperms to view usage."));
public Optional<Component> extendedDescription(CommandCause cause) {
return Optional.empty();
}
@Override
public @NonNull Text getUsage(@NonNull CommandSource source) {
return Text.of("/luckperms");
public Component usage(CommandCause cause) {
return Component.text("/luckperms");
}
private List<String> resolveSelectors(CommandSource source, List<String> args) {
private List<String> resolveSelectors(CommandCause source, List<String> args) {
if (!this.plugin.getConfiguration().get(ConfigKeys.RESOLVE_COMMAND_SELECTORS)) {
return args;
}
@ -102,7 +105,7 @@ public class SpongeCommandExecutor extends CommandManager implements CommandCall
List<Player> matchedPlayers;
try {
matchedPlayers = Selector.parse(arg).resolve(source).stream()
matchedPlayers = Selector.parse(arg).select(source).stream()
.filter(e -> e instanceof Player)
.map(e -> (Player) e)
.collect(Collectors.toList());
@ -122,7 +125,7 @@ public class SpongeCommandExecutor extends CommandManager implements CommandCall
}
Player player = matchedPlayers.get(0);
it.set(player.getUniqueId().toString());
it.set(player.uniqueId().toString());
}
return args;

View File

@ -29,15 +29,11 @@ import me.lucko.luckperms.common.api.LuckPermsApiProvider;
import me.lucko.luckperms.common.event.AbstractEventBus;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.plugin.PluginContainer;
public class SpongeEventBus extends AbstractEventBus<PluginContainer> {
public SpongeEventBus(LPSpongePlugin plugin, LuckPermsApiProvider apiProvider) {
super(plugin, apiProvider);
// register listener
LPSpongeBootstrap bootstrap = plugin.getBootstrap();
bootstrap.getGame().getEventManager().registerListeners(bootstrap, this);
}
@Override
@ -46,7 +42,7 @@ public class SpongeEventBus extends AbstractEventBus<PluginContainer> {
return (PluginContainer) plugin;
}
PluginContainer pluginContainer = Sponge.getPluginManager().fromInstance(plugin).orElse(null);
PluginContainer pluginContainer = Sponge.pluginManager().fromInstance(plugin).orElse(null);
if (pluginContainer != null) {
return pluginContainer;
}

View File

@ -25,34 +25,45 @@
package me.lucko.luckperms.sponge;
import com.google.common.base.Suppliers;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerTask;
import me.lucko.luckperms.common.util.Iterators;
import org.spongepowered.api.Game;
import org.spongepowered.api.scheduler.ScheduledTask;
import org.spongepowered.api.scheduler.Scheduler;
import org.spongepowered.api.scheduler.SpongeExecutorService;
import org.spongepowered.api.scheduler.Task;
import org.spongepowered.api.scheduler.TaskExecutorService;
import org.spongepowered.plugin.PluginContainer;
import java.util.Collections;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class SpongeSchedulerAdapter implements SchedulerAdapter {
private final LPSpongeBootstrap bootstrap;
private final Scheduler scheduler;
private final SpongeExecutorService sync;
private final SpongeExecutorService async;
private final Set<Task> tasks = Collections.newSetFromMap(new WeakHashMap<>());
public SpongeSchedulerAdapter(LPSpongeBootstrap bootstrap, Scheduler scheduler, SpongeExecutorService sync, SpongeExecutorService async) {
this.bootstrap = bootstrap;
this.scheduler = scheduler;
this.sync = sync;
this.async = async;
private final Game game;
private final PluginContainer pluginContainer;
private final Scheduler asyncScheduler;
private final Supplier<TaskExecutorService> sync;
private final TaskExecutorService async;
private final Set<ScheduledTask> tasks = Collections.newSetFromMap(new WeakHashMap<>());
public SpongeSchedulerAdapter(Game game, PluginContainer pluginContainer) {
this.game = game;
this.pluginContainer = pluginContainer;
this.asyncScheduler = game.asyncScheduler();
this.async = this.asyncScheduler.executor(pluginContainer);
this.sync = Suppliers.memoize(() -> getSyncScheduler().executor(this.pluginContainer));
}
@Override
@ -62,47 +73,40 @@ public class SpongeSchedulerAdapter implements SchedulerAdapter {
@Override
public Executor sync() {
return this.sync;
return this.sync.get();
}
@Override
public void executeAsync(Runnable runnable) {
this.scheduler.createTaskBuilder().async().execute(runnable).submit(this.bootstrap);
public Scheduler getSyncScheduler() {
return this.game.server().scheduler();
}
@Override
public void executeSync(Runnable runnable) {
this.scheduler.createTaskBuilder().execute(runnable).submit(this.bootstrap);
private SchedulerTask submitAsyncTask(Runnable runnable, Consumer<Task.Builder> config) {
Task.Builder builder = Task.builder();
config.accept(builder);
Task task = builder
.execute(runnable)
.plugin(this.pluginContainer)
.build();
ScheduledTask scheduledTask = this.asyncScheduler.submit(task);
this.tasks.add(scheduledTask);
return scheduledTask::cancel;
}
@Override
public SchedulerTask asyncLater(Runnable task, long delay, TimeUnit unit) {
Task t = this.scheduler.createTaskBuilder()
.async()
.delay(delay, unit)
.execute(task)
.submit(this.bootstrap);
this.tasks.add(t);
return t::cancel;
return submitAsyncTask(task, builder -> builder.delay(delay, unit));
}
@Override
public SchedulerTask asyncRepeating(Runnable task, long interval, TimeUnit unit) {
Task t = this.scheduler.createTaskBuilder()
.async()
.interval(interval, unit)
.delay(interval, unit)
.execute(task)
.submit(this.bootstrap);
this.tasks.add(t);
return t::cancel;
return submitAsyncTask(task, builder -> builder.delay(interval, unit).interval(interval, unit));
}
@Override
public void shutdownScheduler() {
Iterators.tryIterate(this.tasks, Task::cancel);
Iterators.tryIterate(this.tasks, ScheduledTask::cancel);
}
@Override

View File

@ -30,50 +30,61 @@ import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.sender.SenderFactory;
import me.lucko.luckperms.sponge.service.CompatibilityUtil;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.luckperms.api.util.Tristate;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.command.source.ConsoleSource;
import org.spongepowered.api.SystemSubject;
import org.spongepowered.api.command.exception.CommandException;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.serializer.TextSerializers;
import org.spongepowered.api.service.permission.Subject;
import java.util.Locale;
import java.util.UUID;
public class SpongeSenderFactory extends SenderFactory<LPSpongePlugin, CommandSource> {
public class SpongeSenderFactory extends SenderFactory<LPSpongePlugin, Audience> {
public SpongeSenderFactory(LPSpongePlugin plugin) {
super(plugin);
}
@Override
protected String getName(CommandSource source) {
protected String getName(Audience source) {
if (source instanceof Player) {
return source.getName();
return ((Player) source).name();
}
return Sender.CONSOLE_NAME;
}
@Override
protected UUID getUniqueId(CommandSource source) {
protected UUID getUniqueId(Audience source) {
if (source instanceof Player) {
return ((Player) source).getUniqueId();
return ((Player) source).uniqueId();
}
return Sender.CONSOLE_UUID;
}
@Override
protected void sendMessage(CommandSource source, Component message) {
source.sendMessage(toNativeText(TranslationManager.render(message, source.getLocale())));
protected void sendMessage(Audience source, Component message) {
Locale locale = null;
if (source instanceof Player) {
locale = ((Player) source).locale();
}
Component rendered = TranslationManager.render(message, locale);
source.sendMessage(rendered);
}
@Override
protected Tristate getPermissionValue(CommandSource source, String node) {
Tristate result = CompatibilityUtil.convertTristate(source.getPermissionValue(source.getActiveContexts(), node));
protected Tristate getPermissionValue(Audience source, String node) {
if (!(source instanceof Subject)) {
throw new IllegalStateException("Source is not a subject");
}
final Subject subject = (Subject) source;
Tristate result = CompatibilityUtil.convertTristate(subject.permissionValue(node));
// check the permdefault
if (result == Tristate.UNDEFINED && source.hasPermission(node)) {
if (result == Tristate.UNDEFINED && subject.hasPermission(node)) {
result = Tristate.TRUE;
}
@ -81,22 +92,30 @@ public class SpongeSenderFactory extends SenderFactory<LPSpongePlugin, CommandSo
}
@Override
protected boolean hasPermission(CommandSource source, String node) {
return source.hasPermission(node);
protected boolean hasPermission(Audience source, String node) {
if (!(source instanceof Subject)) {
throw new IllegalStateException("Source is not a subject");
}
final Subject subject = (Subject) source;
return subject.hasPermission(node);
}
@Override
protected void performCommand(CommandSource source, String command) {
getPlugin().getBootstrap().getGame().getCommandManager().process(source, command);
protected void performCommand(Audience source, String command) {
if (!(source instanceof Subject)) {
throw new IllegalStateException("Source is not a subject");
}
try {
getPlugin().getBootstrap().getGame().server().commandManager().process(((Subject) source), source, command);
} catch (CommandException e) {
// ignore
}
}
@Override
protected boolean isConsole(CommandSource sender) {
return sender instanceof ConsoleSource;
protected boolean isConsole(Audience sender) {
return sender instanceof SystemSubject;
}
public static Text toNativeText(Component component) {
return TextSerializers.JSON.deserialize(GsonComponentSerializer.gson().serialize(component));
}
}

View File

@ -39,8 +39,6 @@ import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import net.luckperms.api.context.ImmutableContextSet;
import org.spongepowered.api.Sponge;
public class ParentAdd extends ChildCommand<LPSubjectData> {
public ParentAdd() {
super(CommandSpec.SPONGE_PARENT_ADD, "add", CommandPermission.SPONGE_PARENT_ADD, Predicates.inRange(0, 1));
@ -52,7 +50,7 @@ public class ParentAdd extends ChildCommand<LPSubjectData> {
String name = args.get(1);
ImmutableContextSet contextSet = args.getContextOrEmpty(2);
LPPermissionService service = Sponge.getServiceManager().provideUnchecked(LPPermissionService.class);
LPPermissionService service = subjectData.getParentSubject().getService();
if (service.getLoadedCollections().keySet().stream().map(String::toLowerCase).noneMatch(s -> s.equalsIgnoreCase(collection))) {
SpongeCommandUtils.sendPrefixed(sender, "Warning: SubjectCollection '&4" + collection + "&c' doesn't already exist.");
}

View File

@ -39,8 +39,6 @@ import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import net.luckperms.api.context.ImmutableContextSet;
import org.spongepowered.api.Sponge;
public class ParentRemove extends ChildCommand<LPSubjectData> {
public ParentRemove() {
super(CommandSpec.SPONGE_PARENT_REMOVE, "remove", CommandPermission.SPONGE_PARENT_REMOVE, Predicates.inRange(0, 1));
@ -52,7 +50,7 @@ public class ParentRemove extends ChildCommand<LPSubjectData> {
String name = args.get(1);
ImmutableContextSet contextSet = args.getContextOrEmpty(2);
LPPermissionService service = Sponge.getServiceManager().provideUnchecked(LPPermissionService.class);
LPPermissionService service = subjectData.getParentSubject().getService();
if (service.getLoadedCollections().keySet().stream().map(String::toLowerCase).noneMatch(s -> s.equalsIgnoreCase(collection))) {
SpongeCommandUtils.sendPrefixed(sender, "Warning: SubjectCollection '&4" + collection + "&c' doesn't exist.");
}

View File

@ -94,9 +94,9 @@ public final class SpongeCommandUtils {
StringBuilder sb = new StringBuilder();
for (LPSubjectReference s : parents) {
sb.append("&3> &a")
.append(s.getSubjectIdentifier())
.append(s.subjectIdentifier())
.append(" &bfrom collection &a")
.append(s.getCollectionIdentifier())
.append(s.collectionIdentifier())
.append("&b.\n");
}
return sb.toString();

View File

@ -28,33 +28,66 @@ package me.lucko.luckperms.sponge.context;
import com.github.benmanes.caffeine.cache.LoadingCache;
import me.lucko.luckperms.common.context.manager.ContextManager;
import me.lucko.luckperms.common.context.manager.QueryOptionsCache;
import me.lucko.luckperms.common.context.manager.InlineQueryOptionsSupplier;
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
import me.lucko.luckperms.common.util.CaffeineFactory;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.service.model.ContextCalculatorProxy;
import me.lucko.luckperms.sponge.service.model.TemporaryCauseHolderSubject;
import net.luckperms.api.context.ContextCalculator;
import net.luckperms.api.context.ContextConsumer;
import net.luckperms.api.context.ImmutableContextSet;
import net.luckperms.api.context.StaticContextCalculator;
import net.luckperms.api.query.QueryOptions;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.event.Cause;
import org.spongepowered.api.service.permission.Subject;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class SpongeContextManager extends ContextManager<Subject, Player> {
public class SpongeContextManager extends ContextManager<Subject, ServerPlayer> {
private final LoadingCache<Subject, QueryOptionsCache<Subject>> subjectCaches = CaffeineFactory.newBuilder()
.expireAfterAccess(1, TimeUnit.MINUTES)
.build(key -> new QueryOptionsCache<>(key, this));
private final LoadingCache<Subject, QueryOptions> contextsCache = CaffeineFactory.newBuilder()
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
.build(this::calculate);
public SpongeContextManager(LPSpongePlugin plugin) {
super(plugin, Subject.class, Player.class);
super(plugin, Subject.class, ServerPlayer.class);
}
@Override
public UUID getUniqueId(Player player) {
return player.getUniqueId();
protected void callContextCalculator(ContextCalculator<? super Subject> calculator, Subject subject, ContextConsumer consumer) {
if (subject instanceof TemporaryCauseHolderSubject) {
Cause cause = ((TemporaryCauseHolderSubject) subject).getCause();
Subject actualSubject = ((TemporaryCauseHolderSubject) subject).getSubject();
if (calculator instanceof ContextCalculatorProxy) {
((ContextCalculatorProxy) calculator).calculate(cause, consumer);
} else if (actualSubject != null) {
calculator.calculate(actualSubject, consumer);
} else if (calculator instanceof StaticContextCalculator) {
((StaticContextCalculator) calculator).calculate(consumer);
} /* else {
// we just have to fail...
// there's no way to call a LuckPerms ContextCalculator if a Subject instance
// doesn't exist for the cause.
} */
} else {
Object associatedObject = subject.associatedObject().orElse(null);
if (associatedObject instanceof Subject) {
calculator.calculate((Subject) associatedObject, consumer);
} else {
calculator.calculate(subject, consumer);
}
}
}
@Override
public UUID getUniqueId(ServerPlayer player) {
return player.uniqueId();
}
@Override
@ -63,15 +96,23 @@ public class SpongeContextManager extends ContextManager<Subject, Player> {
throw new NullPointerException("subject");
}
return this.subjectCaches.get(subject);
return new InlineQueryOptionsSupplier<>(subject, this.contextsCache);
}
// override getContext, getQueryOptions and invalidateCache to skip the QueryOptionsSupplier
@Override
public ImmutableContextSet getContext(Subject subject) {
return getQueryOptions(subject).context();
}
@Override
public QueryOptions getQueryOptions(Subject subject) {
return this.contextsCache.get(subject);
}
@Override
protected void invalidateCache(Subject subject) {
QueryOptionsCache<Subject> cache = this.subjectCaches.getIfPresent(subject);
if (cache != null) {
cache.invalidate();
}
this.contextsCache.invalidate(subject);
}
@Override

View File

@ -37,81 +37,57 @@ import net.luckperms.api.context.DefaultContextKeys;
import net.luckperms.api.context.ImmutableContextSet;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.CatalogType;
import org.spongepowered.api.CatalogTypes;
import org.spongepowered.api.Game;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.data.key.Keys;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.data.Keys;
import org.spongepowered.api.data.value.ValueContainer;
import org.spongepowered.api.entity.Entity;
import org.spongepowered.api.entity.living.Humanoid;
import org.spongepowered.api.entity.living.player.gamemode.GameMode;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.Order;
import org.spongepowered.api.event.entity.MoveEntityEvent;
import org.spongepowered.api.event.entity.living.humanoid.ChangeGameModeEvent;
import org.spongepowered.api.event.entity.ChangeEntityWorldEvent;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.world.DimensionType;
import org.spongepowered.api.world.Locatable;
import org.spongepowered.api.world.World;
import java.util.Set;
import org.spongepowered.api.world.server.ServerWorld;
public class SpongePlayerCalculator implements ContextCalculator<Subject> {
private final LPSpongePlugin plugin;
private final boolean gamemode;
private final boolean world;
private final boolean dimensionType;
public SpongePlayerCalculator(LPSpongePlugin plugin, Set<String> disabled) {
public SpongePlayerCalculator(LPSpongePlugin plugin) {
this.plugin = plugin;
this.gamemode = !disabled.contains(DefaultContextKeys.GAMEMODE_KEY);
this.world = !disabled.contains(DefaultContextKeys.WORLD_KEY);
this.dimensionType = !disabled.contains(DefaultContextKeys.DIMENSION_TYPE_KEY);
}
@Override
public void calculate(@NonNull Subject subject, @NonNull ContextConsumer consumer) {
CommandSource source = subject.getCommandSource().orElse(null);
if (source == null) {
return;
}
if (source instanceof Locatable) {
World world = ((Locatable) source).getWorld();
if (this.dimensionType) {
consumer.accept(DefaultContextKeys.DIMENSION_TYPE_KEY, getCatalogTypeName(world.getDimension().getType()));
}
if (this.world) {
this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).rewriteAndSubmit(world.getName(), consumer);
if (subject instanceof Locatable) {
World<?, ?> world = ((Locatable) subject).world();
consumer.accept(DefaultContextKeys.DIMENSION_TYPE_KEY, getContextKey(world.worldType().key(RegistryTypes.WORLD_TYPE)));
if (world instanceof ServerWorld) {
this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).rewriteAndSubmit(getContextKey(((ServerWorld) world).key()), consumer);
}
}
if (this.gamemode && source instanceof ValueContainer<?>) {
ValueContainer<?> valueContainer = (ValueContainer<?>) source;
valueContainer.get(Keys.GAME_MODE).ifPresent(mode -> consumer.accept(DefaultContextKeys.GAMEMODE_KEY, getCatalogTypeName(mode)));
if (subject instanceof ValueContainer) {
ValueContainer valueContainer = (ValueContainer) subject;
valueContainer.get(Keys.GAME_MODE).ifPresent(mode -> consumer.accept(DefaultContextKeys.GAMEMODE_KEY, getContextKey(mode.key(RegistryTypes.GAME_MODE))));
}
}
@Override
public @NonNull ContextSet estimatePotentialContexts() {
public ContextSet estimatePotentialContexts() {
ImmutableContextSet.Builder builder = new ImmutableContextSetImpl.BuilderImpl();
Game game = this.plugin.getBootstrap().getGame();
if (this.gamemode) {
for (GameMode mode : game.getRegistry().getAllOf(CatalogTypes.GAME_MODE)) {
builder.add(DefaultContextKeys.GAMEMODE_KEY, getCatalogTypeName(mode));
}
}
if (this.dimensionType) {
for (DimensionType dim : game.getRegistry().getAllOf(CatalogTypes.DIMENSION_TYPE)) {
builder.add(DefaultContextKeys.DIMENSION_TYPE_KEY, getCatalogTypeName(dim));
}
}
if (this.world && game.isServerAvailable()) {
for (World world : game.getServer().getWorlds()) {
String worldName = world.getName();
game.registry(RegistryTypes.GAME_MODE).stream().forEach(mode -> {
builder.add(DefaultContextKeys.GAMEMODE_KEY, getContextKey(mode.key(RegistryTypes.GAME_MODE)));
});
game.registry(RegistryTypes.WORLD_TYPE).stream().forEach(dim -> {
builder.add(DefaultContextKeys.DIMENSION_TYPE_KEY, getContextKey(dim.key(RegistryTypes.WORLD_TYPE)));
});
if (game.isServerAvailable()) {
for (ServerWorld world : game.server().worldManager().worlds()) {
String worldName = getContextKey(world.key());
if (Context.isValidValue(worldName)) {
builder.add(DefaultContextKeys.WORLD_KEY, worldName);
}
@ -121,37 +97,29 @@ public class SpongePlayerCalculator implements ContextCalculator<Subject> {
return builder.build();
}
private static String getCatalogTypeName(CatalogType type) {
String id = type.getId();
if (id.startsWith("minecraft:")){
return id.substring("minecraft:".length());
private static String getContextKey(ResourceKey key) {
if (key.namespace().equals("minecraft")) {
return key.value();
}
return id;
return key.formatted();
}
@Listener(order = Order.LAST)
public void onWorldChange(MoveEntityEvent.Teleport e) {
if (!(this.world || this.dimensionType)) {
return;
}
Entity targetEntity = e.getTargetEntity();
public void onWorldChange(ChangeEntityWorldEvent.Post e) {
Entity targetEntity = e.entity();
if (!(targetEntity instanceof Subject)) {
return;
}
if (e.getFromTransform().getExtent().equals(e.getToTransform().getExtent())) {
return;
}
this.plugin.getContextManager().signalContextUpdate((Subject) targetEntity);
}
@Listener(order = Order.LAST)
public void onGameModeChange(ChangeGameModeEvent e) {
Humanoid targetEntity = e.getTargetEntity();
if (this.gamemode && targetEntity instanceof Subject) {
this.plugin.getContextManager().signalContextUpdate((Subject) targetEntity);
}
}
// TODO: find replacement
//@Listener(order = Order.LAST)
//public void onGameModeChange(ChangeGameModeEvent e) {
// Humanoid targetEntity = e.getHumanoid();
// if (targetEntity instanceof Subject) {
// this.plugin.getContextManager().signalContextUpdate((Subject) targetEntity);
// }
//}
}

View File

@ -0,0 +1,108 @@
/*
* 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.sponge.listeners;
import com.github.benmanes.caffeine.cache.LoadingCache;
import me.lucko.luckperms.common.cache.BufferedRequest;
import me.lucko.luckperms.common.event.LuckPermsEventListener;
import me.lucko.luckperms.common.util.CaffeineFactory;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import net.luckperms.api.event.EventBus;
import net.luckperms.api.event.context.ContextUpdateEvent;
import net.luckperms.api.event.user.UserDataRecalculateEvent;
import org.spongepowered.api.command.manager.CommandManager;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* Calls {@link CommandManager#updateCommandTreeForPlayer(ServerPlayer)}
* when a players permissions change.
*/
public class SpongeCommandListUpdater implements LuckPermsEventListener {
private final LPSpongePlugin plugin;
private final LoadingCache<UUID, SendBuffer> sendingBuffers = CaffeineFactory.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build(SendBuffer::new);
public SpongeCommandListUpdater(LPSpongePlugin plugin) {
this.plugin = plugin;
}
@Override
public void bind(EventBus bus) {
bus.subscribe(UserDataRecalculateEvent.class, this::onUserDataRecalculate);
bus.subscribe(ContextUpdateEvent.class, this::onContextUpdate);
}
private void onUserDataRecalculate(UserDataRecalculateEvent e) {
requestUpdate(e.getUser().getUniqueId());
}
private void onContextUpdate(ContextUpdateEvent e) {
e.getSubject(ServerPlayer.class).ifPresent(p -> requestUpdate(p.uniqueId()));
}
private void requestUpdate(UUID uniqueId) {
if (!this.plugin.getBootstrap().isPlayerOnline(uniqueId)) {
return;
}
// Buffer the request to send a commands update.
this.sendingBuffers.get(uniqueId).request();
}
// Called when the buffer times out.
private void sendUpdate(UUID uniqueId) {
this.plugin.getBootstrap().getScheduler().sync().execute(() -> {
ServerPlayer player = this.plugin.getBootstrap().getPlayer(uniqueId).orElse(null);
if (player != null) {
CommandManager commandManager = this.plugin.getBootstrap().getGame().server().commandManager();
commandManager.updateCommandTreeForPlayer(player);
}
});
}
private final class SendBuffer extends BufferedRequest<Void> {
private final UUID uniqueId;
SendBuffer(UUID uniqueId) {
super(500, TimeUnit.MILLISECONDS, SpongeCommandListUpdater.this.plugin.getBootstrap().getScheduler());
this.uniqueId = uniqueId;
}
@Override
protected Void perform() {
sendUpdate(this.uniqueId);
return null;
}
}
}

View File

@ -31,14 +31,11 @@ import me.lucko.luckperms.common.locale.TranslationManager;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.util.AbstractConnectionListener;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.SpongeSenderFactory;
import net.kyori.adventure.text.Component;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.Order;
import org.spongepowered.api.event.filter.IsCancelled;
import org.spongepowered.api.event.network.ClientConnectionEvent;
import org.spongepowered.api.event.network.ServerSideConnectionEvent;
import org.spongepowered.api.profile.GameProfile;
import org.spongepowered.api.util.Tristate;
@ -60,22 +57,22 @@ public class SpongeConnectionListener extends AbstractConnectionListener {
@Listener(order = Order.EARLY)
@IsCancelled(Tristate.UNDEFINED)
public void onClientAuth(ClientConnectionEvent.Auth e) {
public void onClientAuth(ServerSideConnectionEvent.Auth e) {
/* Called when the player first attempts a connection with the server.
Listening on AFTER_PRE priority to allow plugins to modify username / UUID data here. (auth plugins)
Also, give other plugins a chance to cancel the event. */
final GameProfile profile = e.getProfile();
final String username = profile.getName().orElseThrow(() -> new RuntimeException("No username present for user " + profile.getUniqueId()));
final GameProfile profile = e.profile();
final String username = profile.name().orElseThrow(() -> new RuntimeException("No username present for user " + profile.uniqueId()));
if (this.plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
this.plugin.getLogger().info("Processing auth event for " + profile.getUniqueId() + " - " + profile.getName());
this.plugin.getLogger().info("Processing auth event for " + profile.uniqueId() + " - " + profile.name());
}
if (e.isCancelled()) {
// another plugin has disallowed the login.
this.plugin.getLogger().info("Another plugin has cancelled the connection for " + profile.getUniqueId() + " - " + username + ". No permissions data will be loaded.");
this.deniedAsyncLogin.add(profile.getUniqueId());
this.plugin.getLogger().info("Another plugin has cancelled the connection for " + profile.uniqueId() + " - " + username + ". No permissions data will be loaded.");
this.deniedAsyncLogin.add(profile.uniqueId());
return;
}
@ -89,34 +86,32 @@ public class SpongeConnectionListener extends AbstractConnectionListener {
- creating a user instance in the UserManager for this connection.
- setting up cached data. */
try {
User user = loadUser(profile.getUniqueId(), username);
recordConnection(profile.getUniqueId());
this.plugin.getEventDispatcher().dispatchPlayerLoginProcess(profile.getUniqueId(), username, user);
User user = loadUser(profile.uniqueId(), username);
recordConnection(profile.uniqueId());
this.plugin.getEventDispatcher().dispatchPlayerLoginProcess(profile.uniqueId(), username, user);
} catch (Exception ex) {
this.plugin.getLogger().severe("Exception occurred whilst loading data for " + profile.getUniqueId() + " - " + profile.getName(), ex);
this.plugin.getLogger().severe("Exception occurred whilst loading data for " + profile.uniqueId() + " - " + profile.name(), ex);
this.deniedAsyncLogin.add(profile.getUniqueId());
this.deniedAsyncLogin.add(profile.uniqueId());
e.setCancelled(true);
e.setMessageCancelled(false);
Component reason = TranslationManager.render(Message.LOADING_DATABASE_ERROR.build());
e.setMessage(SpongeSenderFactory.toNativeText(reason));
this.plugin.getEventDispatcher().dispatchPlayerLoginProcess(profile.getUniqueId(), username, null);
e.setMessage(TranslationManager.render(Message.LOADING_DATABASE_ERROR.build()));
this.plugin.getEventDispatcher().dispatchPlayerLoginProcess(profile.uniqueId(), username, null);
}
}
@Listener(order = Order.LAST)
@IsCancelled(Tristate.UNDEFINED)
public void onClientAuthMonitor(ClientConnectionEvent.Auth e) {
public void onClientAuthMonitor(ServerSideConnectionEvent.Auth e) {
/* Listen to see if the event was cancelled after we initially handled the connection
If the connection was cancelled here, we need to do something to clean up the data that was loaded. */
// Check to see if this connection was denied at LOW.
if (this.deniedAsyncLogin.remove(e.getProfile().getUniqueId())) {
if (this.deniedAsyncLogin.remove(e.profile().uniqueId())) {
// This is a problem, as they were denied at low priority, but are now being allowed.
if (e.isCancelled()) {
this.plugin.getLogger().severe("Player connection was re-allowed for " + e.getProfile().getUniqueId());
this.plugin.getLogger().severe("Player connection was re-allowed for " + e.profile().uniqueId());
e.setCancelled(true);
}
}
@ -124,59 +119,57 @@ public class SpongeConnectionListener extends AbstractConnectionListener {
@Listener(order = Order.FIRST)
@IsCancelled(Tristate.UNDEFINED)
public void onClientLogin(ClientConnectionEvent.Login e) {
public void onClientLogin(ServerSideConnectionEvent.Login e) {
/* Called when the player starts logging into the server.
At this point, the users data should be present and loaded.
Listening on LOW priority to allow plugins to further modify data here. (auth plugins, etc.) */
final GameProfile profile = e.getProfile();
final GameProfile profile = e.profile();
if (this.plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
this.plugin.getLogger().info("Processing login event for " + profile.getUniqueId() + " - " + profile.getName());
this.plugin.getLogger().info("Processing login event for " + profile.uniqueId() + " - " + profile.name());
}
final User user = this.plugin.getUserManager().getIfLoaded(profile.getUniqueId());
final User user = this.plugin.getUserManager().getIfLoaded(profile.uniqueId());
/* User instance is null for whatever reason. Could be that it was unloaded between asyncpre and now. */
if (user == null) {
this.deniedLogin.add(profile.getUniqueId());
this.deniedLogin.add(profile.uniqueId());
if (!getUniqueConnections().contains(profile.getUniqueId())) {
this.plugin.getLogger().warn("User " + profile.getUniqueId() + " - " + profile.getName() +
if (!getUniqueConnections().contains(profile.uniqueId())) {
this.plugin.getLogger().warn("User " + profile.uniqueId() + " - " + profile.name() +
" doesn't have data pre-loaded, they have never been processed during pre-login in this session." +
" - denying login.");
} else {
this.plugin.getLogger().warn("User " + profile.getUniqueId() + " - " + profile.getName() +
this.plugin.getLogger().warn("User " + profile.uniqueId() + " - " + profile.name() +
" doesn't currently have data pre-loaded, but they have been processed before in this session." +
" - denying login.");
}
e.setCancelled(true);
e.setMessageCancelled(false);
Component reason = TranslationManager.render(Message.LOADING_STATE_ERROR.build());
e.setMessage(SpongeSenderFactory.toNativeText(reason));
e.setMessage(TranslationManager.render(Message.LOADING_STATE_ERROR.build()));
}
}
@Listener(order = Order.LAST)
@IsCancelled(Tristate.UNDEFINED)
public void onClientLoginMonitor(ClientConnectionEvent.Login e) {
public void onClientLoginMonitor(ServerSideConnectionEvent.Login e) {
/* Listen to see if the event was cancelled after we initially handled the login
If the connection was cancelled here, we need to do something to clean up the data that was loaded. */
// Check to see if this connection was denied at LOW. Even if it was denied at LOW, their data will still be present.
if (this.deniedLogin.remove(e.getProfile().getUniqueId())) {
if (this.deniedLogin.remove(e.profile().uniqueId())) {
// This is a problem, as they were denied at low priority, but are now being allowed.
if (!e.isCancelled()) {
this.plugin.getLogger().severe("Player connection was re-allowed for " + e.getProfile().getUniqueId());
this.plugin.getLogger().severe("Player connection was re-allowed for " + e.profile().uniqueId());
e.setCancelled(true);
}
}
}
@Listener(order = Order.POST)
public void onClientLeave(ClientConnectionEvent.Disconnect e) {
handleDisconnect(e.getTargetEntity().getUniqueId());
public void onClientLeave(ServerSideConnectionEvent.Disconnect e) {
handleDisconnect(e.player().uniqueId());
}
}

View File

@ -28,9 +28,9 @@ package me.lucko.luckperms.sponge.listeners;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.command.CommandCause;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.command.SendCommandEvent;
import org.spongepowered.api.event.command.ExecuteCommandEvent;
import java.util.Locale;
@ -42,13 +42,12 @@ public class SpongePlatformListener {
}
@Listener
public void onSendCommand(SendCommandEvent e) {
CommandSource source = e.getCause().first(CommandSource.class).orElse(null);
if (source == null) return;
public void onSendCommand(ExecuteCommandEvent e) {
CommandCause source = e.commandCause();
final String name = e.getCommand().toLowerCase(Locale.ROOT);
if ((name.equals("op") || name.equals("minecraft:op")) && source.hasPermission("minecraft.command.op") || (name.equals("deop") || name.equals("minecraft:deop")) && source.hasPermission("minecraft.command.deop")) {
Message.OP_DISABLED_SPONGE.send(this.plugin.getSenderFactory().wrap(source));
final String name = e.command().toLowerCase(Locale.ROOT);
if (((name.equals("op") || name.equals("minecraft:op")) && source.hasPermission("minecraft.command.op")) || ((name.equals("deop") || name.equals("minecraft:deop")) && source.hasPermission("minecraft.command.deop"))) {
Message.OP_DISABLED_SPONGE.send(this.plugin.getSenderFactory().wrap(source.audience()));
}
}
}

View File

@ -34,12 +34,14 @@ import net.luckperms.api.messenger.Messenger;
import net.luckperms.api.messenger.message.OutgoingMessage;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.Platform;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.network.ChannelBinding;
import org.spongepowered.api.network.ChannelBuf;
import org.spongepowered.api.network.RawDataListener;
import org.spongepowered.api.network.RemoteConnection;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.network.EngineConnectionSide;
import org.spongepowered.api.network.ServerSideConnection;
import org.spongepowered.api.network.channel.ChannelBuf;
import org.spongepowered.api.network.channel.raw.RawDataChannel;
import org.spongepowered.api.network.channel.raw.play.RawPlayDataHandler;
import org.spongepowered.api.scheduler.Task;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
@ -47,13 +49,13 @@ import java.util.concurrent.TimeUnit;
/**
* An implementation of {@link Messenger} using the plugin messaging channels.
*/
public class PluginMessageMessenger implements Messenger, RawDataListener {
private static final String CHANNEL = "luckperms:update";
public class PluginMessageMessenger implements Messenger, RawPlayDataHandler<ServerSideConnection> {
private static final ResourceKey CHANNEL = ResourceKey.of("luckperms", "update");
private final LPSpongePlugin plugin;
private final IncomingMessageConsumer consumer;
private ChannelBinding.RawDataChannel channel = null;
private RawDataChannel channel = null;
public PluginMessageMessenger(LPSpongePlugin plugin, IncomingMessageConsumer consumer) {
this.plugin = plugin;
@ -61,37 +63,43 @@ public class PluginMessageMessenger implements Messenger, RawDataListener {
}
public void init() {
this.channel = this.plugin.getBootstrap().getGame().getChannelRegistrar().createRawChannel(this.plugin.getBootstrap(), CHANNEL);
this.channel.addListener(Platform.Type.SERVER, this);
this.channel = this.plugin.getBootstrap().getGame().channelManager().ofType(CHANNEL, RawDataChannel.class);
this.channel.play().addHandler(EngineConnectionSide.SERVER, this);
}
@Override
public void close() {
if (this.channel != null) {
this.plugin.getBootstrap().getGame().getChannelRegistrar().unbindChannel(this.channel);
this.channel.play().removeHandler(this);
}
}
@Override
public void sendOutgoingMessage(@NonNull OutgoingMessage outgoingMessage) {
this.plugin.getBootstrap().getSpongeScheduler().createTaskBuilder().interval(10, TimeUnit.SECONDS).execute(task -> {
if (!this.plugin.getBootstrap().getGame().isServerAvailable()) {
return;
}
Task t = Task.builder()
.interval(10, TimeUnit.SECONDS)
.execute(task -> {
if (!this.plugin.getBootstrap().getGame().isServerAvailable()) {
return;
}
Collection<Player> players = this.plugin.getBootstrap().getGame().getServer().getOnlinePlayers();
Player p = Iterables.getFirst(players, null);
if (p == null) {
return;
}
Collection<ServerPlayer> players = this.plugin.getBootstrap().getGame().server().onlinePlayers();
ServerPlayer p = Iterables.getFirst(players, null);
if (p == null) {
return;
}
this.channel.sendTo(p, buf -> buf.writeUTF(outgoingMessage.asEncodedString()));
task.cancel();
}).submit(this.plugin.getBootstrap());
this.channel.play().sendTo(p, buf -> buf.writeUTF(outgoingMessage.asEncodedString()));
task.cancel();
})
.plugin(this.plugin.getBootstrap().getPluginContainer())
.build();
this.plugin.getBootstrap().getScheduler().getSyncScheduler().submit(t);
}
@Override
public void handlePayload(@NonNull ChannelBuf buf, @NonNull RemoteConnection connection, Platform.@NonNull Type type) {
public void handlePayload(ChannelBuf buf, ServerSideConnection connection) {
String msg = buf.readUTF();
this.consumer.consumeIncomingMessageAsString(msg);
}

View File

@ -59,7 +59,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
@ -160,7 +159,7 @@ public class SpongeGroupManager extends AbstractGroupManager<SpongeGroup> implem
}
@Override
public CompletableFuture<ImmutableCollection<LPSubject>> loadSubjects(Set<String> identifiers) {
public CompletableFuture<ImmutableCollection<LPSubject>> loadSubjects(Iterable<String> identifiers) {
return CompletableFuture.supplyAsync(() -> {
ImmutableSet.Builder<LPSubject> subjects = ImmutableSet.builder();
for (String id : identifiers) {

View File

@ -58,7 +58,6 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@ -170,7 +169,7 @@ public class SpongeUserManager extends AbstractUserManager<SpongeUser> implement
}
@Override
public CompletableFuture<ImmutableCollection<LPSubject>> loadSubjects(Set<String> identifiers) {
public CompletableFuture<ImmutableCollection<LPSubject>> loadSubjects(Iterable<String> identifiers) {
return CompletableFuture.supplyAsync(() -> {
ImmutableSet.Builder<LPSubject> subjects = ImmutableSet.builder();
for (String id : identifiers) {

View File

@ -39,19 +39,25 @@ import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.SimplePermissionDescription;
import me.lucko.luckperms.sponge.service.model.SubjectDataUpdateEventImpl;
import me.lucko.luckperms.sponge.service.model.TemporaryCauseHolderSubject;
import me.lucko.luckperms.sponge.service.model.persisted.DefaultsCollection;
import me.lucko.luckperms.sponge.service.model.persisted.PersistedCollection;
import me.lucko.luckperms.sponge.service.model.persisted.SubjectStorage;
import me.lucko.luckperms.sponge.service.reference.SubjectReferenceFactory;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.plugin.PluginContainer;
import net.kyori.adventure.text.Component;
import net.luckperms.api.context.ImmutableContextSet;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.event.Cause;
import org.spongepowered.api.event.permission.SubjectDataUpdateEvent;
import org.spongepowered.api.service.context.ContextCalculator;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.text.Text;
import org.spongepowered.plugin.PluginContainer;
import java.util.HashMap;
import java.util.Locale;
@ -74,7 +80,7 @@ public class LuckPermsService implements LPPermissionService {
/**
* A cached proxy of this instance
*/
private final PermissionService spongeProxy;
private final PermissionAndContextService spongeProxy;
/**
* Reference factory, used to obtain {@link LPSubjectReference}s.
@ -135,7 +141,7 @@ public class LuckPermsService implements LPPermissionService {
}
@Override
public PermissionService sponge() {
public PermissionAndContextService sponge() {
return this.spongeProxy;
}
@ -145,7 +151,7 @@ public class LuckPermsService implements LPPermissionService {
}
@Override
public ContextManager<Subject, Player> getContextManager() {
public ContextManager<Subject, ServerPlayer> getContextManager() {
return this.plugin.getContextManager();
}
@ -195,7 +201,7 @@ public class LuckPermsService implements LPPermissionService {
}
@Override
public LPPermissionDescription registerPermissionDescription(String id, Text description, PluginContainer owner) {
public LPPermissionDescription registerPermissionDescription(String id, Component description, PluginContainer owner) {
Objects.requireNonNull(id, "id");
SimplePermissionDescription desc = new SimplePermissionDescription(this, id, description, owner);
this.permissionDescriptions.put(id, desc);
@ -225,11 +231,30 @@ public class LuckPermsService implements LPPermissionService {
}
@Override
public void registerContextCalculator(ContextCalculator<Subject> calculator) {
public void registerContextCalculator(ContextCalculator calculator) {
Objects.requireNonNull(calculator);
this.plugin.getContextManager().registerCalculator(new ContextCalculatorProxy(calculator));
}
@Override
public ImmutableContextSet getContextsForCause(Cause cause) {
Objects.requireNonNull(cause, "cause");
return this.plugin.getContextManager().getContext(new TemporaryCauseHolderSubject(cause));
}
@Override
public ImmutableContextSet getContextsForCurrentCause() {
return getContextsForCause(this.plugin.getBootstrap().getGame().server().causeStackManager().currentCause());
}
@Override
public void fireUpdateEvent(LPSubjectData subjectData) {
this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
SubjectDataUpdateEvent event = new SubjectDataUpdateEventImpl(this.plugin, subjectData);
this.plugin.getBootstrap().getGame().eventManager().post(event);
});
}
@Override
public void invalidateAllCaches() {
for (LPSubjectCollection collection : this.collections.values()) {

View File

@ -27,16 +27,19 @@ package me.lucko.luckperms.sponge.service;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPProxiedSubject;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.model.ProxiedSubject;
import me.lucko.luckperms.sponge.service.proxy.api8.PermissionDescriptionProxy;
import me.lucko.luckperms.sponge.service.proxy.api8.PermissionServiceProxy;
import me.lucko.luckperms.sponge.service.proxy.api8.SubjectCollectionProxy;
import me.lucko.luckperms.sponge.service.proxy.api8.SubjectDataProxy;
import me.lucko.luckperms.sponge.service.proxy.api8.SubjectProxy;
import net.luckperms.api.model.data.DataType;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
@ -46,51 +49,25 @@ import org.spongepowered.api.service.permission.SubjectData;
public final class ProxyFactory {
private ProxyFactory() {}
private static final boolean IS_API_7 = isApi7();
private static boolean isApi7() {
try {
Subject.class.getDeclaredMethod("asSubjectReference");
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
public static PermissionService toSponge(LPPermissionService luckPerms) {
return IS_API_7 ?
new me.lucko.luckperms.sponge.service.proxy.api7.PermissionServiceProxy(luckPerms) :
new me.lucko.luckperms.sponge.service.proxy.api6.PermissionServiceProxy(luckPerms);
public static PermissionAndContextService toSponge(LPPermissionService luckPerms) {
return new PermissionServiceProxy(luckPerms);
}
public static SubjectCollection toSponge(LPSubjectCollection luckPerms) {
return IS_API_7 ?
new me.lucko.luckperms.sponge.service.proxy.api7.SubjectCollectionProxy(luckPerms) :
new me.lucko.luckperms.sponge.service.proxy.api6.SubjectCollectionProxy(luckPerms.getService(), luckPerms);
return new SubjectCollectionProxy(luckPerms);
}
public static ProxiedSubject toSponge(LPSubject luckPerms) {
return IS_API_7 ?
new me.lucko.luckperms.sponge.service.proxy.api7.SubjectProxy(luckPerms.getService(), luckPerms.toReference()) :
new me.lucko.luckperms.sponge.service.proxy.api6.SubjectProxy(luckPerms.getService(), luckPerms.toReference());
public static LPProxiedSubject toSponge(LPSubject luckPerms) {
return new SubjectProxy(luckPerms.getService(), luckPerms.toReference());
}
public static SubjectData toSponge(LPSubjectData luckPerms) {
LPSubject parentSubject = luckPerms.getParentSubject();
return IS_API_7 ?
new me.lucko.luckperms.sponge.service.proxy.api7.SubjectDataProxy(parentSubject.getService(), parentSubject.toReference(), luckPerms.getType() == DataType.NORMAL) :
new me.lucko.luckperms.sponge.service.proxy.api6.SubjectDataProxy(parentSubject.getService(), parentSubject.toReference(), luckPerms.getType() == DataType.NORMAL);
return new SubjectDataProxy(parentSubject.getService(), parentSubject.toReference(), luckPerms.getType() == DataType.NORMAL);
}
public static PermissionDescription toSponge(LPPermissionDescription luckPerms) {
return IS_API_7 ?
new me.lucko.luckperms.sponge.service.proxy.api7.PermissionDescriptionProxy(luckPerms.getService(), luckPerms) :
new me.lucko.luckperms.sponge.service.proxy.api6.PermissionDescriptionProxy(luckPerms.getService(), luckPerms);
}
public static LPPermissionDescription registerDescription(LPPermissionService service, PermissionDescription description) {
return IS_API_7 ?
me.lucko.luckperms.sponge.service.proxy.api7.DescriptionBuilder.registerDescription(service, description) :
me.lucko.luckperms.sponge.service.proxy.api6.DescriptionBuilder.registerDescription(service, description);
return new PermissionDescriptionProxy(luckPerms.getService(), luckPerms);
}
}

View File

@ -30,24 +30,37 @@ import me.lucko.luckperms.common.context.calculator.ForwardingContextCalculator;
import net.luckperms.api.context.ContextConsumer;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.event.Cause;
import org.spongepowered.api.event.EventContext;
import org.spongepowered.api.event.EventContextKeys;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.context.ContextCalculator;
import org.spongepowered.api.service.permission.Subject;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.function.Consumer;
public class ContextCalculatorProxy implements ForwardingContextCalculator<Subject> {
private final ContextCalculator<Subject> delegate;
private final ContextCalculator delegate;
public ContextCalculatorProxy(ContextCalculator<Subject> delegate) {
public ContextCalculatorProxy(ContextCalculator delegate) {
this.delegate = delegate;
}
@Override
public void calculate(@NonNull Subject subject, @NonNull ContextConsumer consumer) {
this.delegate.accumulateContexts(subject, new ForwardingContextSet(consumer));
EventContext eventContext = EventContext.builder()
.add(EventContextKeys.SUBJECT, subject)
.build();
Cause cause = Cause.builder()
.append(subject)
.build(eventContext);
calculate(cause, consumer);
}
public void calculate(@NonNull Cause cause, @NonNull ContextConsumer consumer) {
this.delegate.accumulateContexts(cause, new ForwardingContextConsumer(consumer));
}
@Override
@ -55,42 +68,20 @@ public class ContextCalculatorProxy implements ForwardingContextCalculator<Subje
return this.delegate;
}
private static final class ForwardingContextSet implements Set<Context> {
private static final class ForwardingContextConsumer implements Consumer<Context> {
private final ContextConsumer consumer;
private ForwardingContextSet(ContextConsumer consumer) {
private ForwardingContextConsumer(ContextConsumer consumer) {
this.consumer = consumer;
}
@Override
public boolean add(Context context) {
if (!net.luckperms.api.context.Context.isValidKey(context.getKey()) ||
!net.luckperms.api.context.Context.isValidValue(context.getValue())) {
return false;
public void accept(Context context) {
if (net.luckperms.api.context.Context.isValidKey(context.getKey()) &&
net.luckperms.api.context.Context.isValidValue(context.getValue())) {
this.consumer.accept(context.getKey(), context.getValue());
}
this.consumer.accept(context.getKey(), context.getValue());
return true;
}
@Override
public boolean addAll(@NonNull Collection<? extends Context> c) {
for (Context context : c) {
add(context);
}
return true;
}
@Override public int size() { throw new UnsupportedOperationException(); }
@Override public boolean isEmpty() { throw new UnsupportedOperationException(); }
@Override public boolean contains(Object o) { throw new UnsupportedOperationException(); }
@Override public @NonNull Iterator<Context> iterator() { throw new UnsupportedOperationException(); }
@Override public @NonNull Object[] toArray() { throw new UnsupportedOperationException(); }
@Override public <T> @NonNull T[] toArray(@NonNull T[] a) { throw new UnsupportedOperationException(); }
@Override public boolean remove(Object o) { throw new UnsupportedOperationException(); }
@Override public boolean containsAll(@NonNull Collection<?> c) { throw new UnsupportedOperationException(); }
@Override public boolean retainAll(@NonNull Collection<?> c) { throw new UnsupportedOperationException(); }
@Override public boolean removeAll(@NonNull Collection<?> c) { throw new UnsupportedOperationException(); }
@Override public void clear() { throw new UnsupportedOperationException(); }
}
}

View File

@ -27,10 +27,11 @@ package me.lucko.luckperms.sponge.service.model;
import me.lucko.luckperms.sponge.service.ProxyFactory;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.text.Text;
import org.spongepowered.plugin.PluginContainer;
import java.util.Map;
import java.util.Objects;
@ -41,12 +42,12 @@ public final class SimplePermissionDescription implements LPPermissionDescriptio
private final LPPermissionService service;
private final String id;
private final @Nullable Text description;
private final @Nullable Component description;
private final @Nullable PluginContainer owner;
private PermissionDescription spongeProxy = null;
public SimplePermissionDescription(LPPermissionService service, String id, @Nullable Text description, @Nullable PluginContainer owner) {
public SimplePermissionDescription(LPPermissionService service, String id, @Nullable Component description, @Nullable PluginContainer owner) {
this.service = service;
this.id = Objects.requireNonNull(id, "id");
this.description = description;
@ -72,7 +73,7 @@ public final class SimplePermissionDescription implements LPPermissionDescriptio
}
@Override
public Optional<Text> getDescription() {
public Optional<Component> getDescription() {
return Optional.ofNullable(this.description);
}

View File

@ -23,30 +23,29 @@
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.service.events;
package me.lucko.luckperms.sponge.service.model;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.event.cause.Cause;
import org.spongepowered.api.event.cause.EventContext;
import org.spongepowered.api.event.cause.EventContextKeys;
import org.spongepowered.api.event.Cause;
import org.spongepowered.api.event.EventContext;
import org.spongepowered.api.event.EventContextKeys;
import org.spongepowered.api.event.impl.AbstractEvent;
import org.spongepowered.api.event.permission.SubjectDataUpdateEvent;
import org.spongepowered.api.service.permission.SubjectData;
public class LPSubjectDataUpdateEvent extends AbstractEvent implements SubjectDataUpdateEvent {
public class SubjectDataUpdateEventImpl extends AbstractEvent implements SubjectDataUpdateEvent {
private final LPSpongePlugin plugin;
private final LPSubjectData subjectData;
public LPSubjectDataUpdateEvent(LPSpongePlugin plugin, LPSubjectData subjectData) {
public SubjectDataUpdateEventImpl(LPSpongePlugin plugin, LPSubjectData subjectData) {
this.plugin = plugin;
this.subjectData = subjectData;
}
@Override
public SubjectData getUpdatedData() {
public SubjectData updatedData() {
return this.subjectData.sponge();
}
@ -55,7 +54,7 @@ public class LPSubjectDataUpdateEvent extends AbstractEvent implements SubjectDa
}
@Override
public @NonNull Cause getCause() {
public @NonNull Cause cause() {
EventContext eventContext = EventContext.builder()
.add(EventContextKeys.PLUGIN, this.plugin.getBootstrap().getPluginContainer())
.build();

View File

@ -0,0 +1,108 @@
/*
* 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.sponge.service.model;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.api.event.Cause;
import org.spongepowered.api.event.EventContextKeys;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.service.permission.SubjectReference;
import org.spongepowered.api.util.Tristate;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public class TemporaryCauseHolderSubject implements Subject {
private final @NonNull Cause cause;
private final @Nullable Subject subject;
public TemporaryCauseHolderSubject(@NonNull Cause cause) {
this.cause = cause;
this.subject = subjectFromCause(this.cause);
}
private static Subject subjectFromCause(Cause cause) {
Subject subject = cause.context().get(EventContextKeys.SUBJECT).orElse(null);
if (subject != null) {
return subject;
}
return cause.first(Subject.class).orElse(null);
}
public @NonNull Cause getCause() {
return this.cause;
}
public @Nullable Subject getSubject() {
return this.subject;
}
@Override
public String toString() {
return "CauseSubject(cause=" + this.cause + ')';
}
@Override
public boolean equals(Object o) {
return o == this || (o instanceof TemporaryCauseHolderSubject && this.cause.equals(((TemporaryCauseHolderSubject) o).cause));
}
@Override
public int hashCode() {
return this.cause.hashCode();
}
@Override public SubjectCollection containingCollection() { throw new UnsupportedOperationException(); }
@Override public SubjectReference asSubjectReference() { throw new UnsupportedOperationException(); }
@Override public Optional<?> associatedObject() { throw new UnsupportedOperationException(); }
@Override public Cause contextCause() { throw new UnsupportedOperationException(); }
@Override public boolean isSubjectDataPersisted() { throw new UnsupportedOperationException(); }
@Override public SubjectData subjectData() { throw new UnsupportedOperationException(); }
@Override public SubjectData transientSubjectData() { throw new UnsupportedOperationException(); }
@Override public boolean hasPermission(String permission) { throw new UnsupportedOperationException(); }
@Override public boolean hasPermission(String permission, Cause cause) { throw new UnsupportedOperationException(); }
@Override public boolean hasPermission(String permission, Set<Context> contexts) { throw new UnsupportedOperationException(); }
@Override public Tristate permissionValue(String permission) { throw new UnsupportedOperationException(); }
@Override public Tristate permissionValue(String permission, Cause cause) { throw new UnsupportedOperationException(); }
@Override public Tristate permissionValue(String permission, Set<Context> contexts) { throw new UnsupportedOperationException(); }
@Override public boolean isChildOf(SubjectReference parent) { throw new UnsupportedOperationException(); }
@Override public boolean isChildOf(SubjectReference parent, Cause cause) { throw new UnsupportedOperationException(); }
@Override public boolean isChildOf(SubjectReference parent, Set<Context> contexts) { throw new UnsupportedOperationException(); }
@Override public List<? extends SubjectReference> parents() { throw new UnsupportedOperationException(); }
@Override public List<? extends SubjectReference> parents(Cause cause) { throw new UnsupportedOperationException(); }
@Override public List<? extends SubjectReference> parents(Set<Context> contexts) { throw new UnsupportedOperationException(); }
@Override public Optional<String> option(String key) { throw new UnsupportedOperationException(); }
@Override public Optional<String> option(String key, Cause cause) { throw new UnsupportedOperationException(); }
@Override public Optional<String> option(String key, Set<Context> contexts) { throw new UnsupportedOperationException(); }
@Override public String identifier() { throw new UnsupportedOperationException(); }
@Override public Optional<String> friendlyIdentifier() { throw new UnsupportedOperationException(); }
}

View File

@ -31,8 +31,6 @@ import me.lucko.luckperms.sponge.model.SpongeGroup;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import org.spongepowered.api.command.CommandSource;
import java.util.Optional;
/**
@ -53,11 +51,6 @@ public class GroupSubject extends PermissionHolderSubject<SpongeGroup> implement
return this.parent.getDisplayName();
}
@Override
public Optional<CommandSource> getCommandSource() {
return Optional.empty();
}
@Override
public LPSubjectCollection getParentCollection() {
return this.plugin.getService().getGroupSubjects();

View File

@ -40,10 +40,9 @@ import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.model.SpongeGroup;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.ProxyFactory;
import me.lucko.luckperms.sponge.service.events.UpdateEventHandler;
import me.lucko.luckperms.sponge.service.model.LPProxiedSubject;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectReference;
import me.lucko.luckperms.sponge.service.model.ProxiedSubject;
import net.luckperms.api.context.ImmutableContextSet;
import net.luckperms.api.model.data.DataType;
@ -64,7 +63,7 @@ public abstract class PermissionHolderSubject<T extends PermissionHolder> implem
private final PermissionHolderSubjectData subjectData;
private final PermissionHolderSubjectData transientSubjectData;
private ProxiedSubject spongeSubject = null;
private LPProxiedSubject spongeSubject = null;
PermissionHolderSubject(LPSpongePlugin plugin, T parent) {
this.parent = parent;
@ -74,8 +73,8 @@ public abstract class PermissionHolderSubject<T extends PermissionHolder> implem
}
public void fireUpdateEvent() {
UpdateEventHandler.fireUpdateEvent(this.plugin, this.subjectData);
UpdateEventHandler.fireUpdateEvent(this.plugin, this.transientSubjectData);
this.plugin.getService().fireUpdateEvent(this.subjectData);
this.plugin.getService().fireUpdateEvent(this.transientSubjectData);
}
public T getParent() {
@ -83,7 +82,7 @@ public abstract class PermissionHolderSubject<T extends PermissionHolder> implem
}
@Override
public synchronized ProxiedSubject sponge() {
public synchronized LPProxiedSubject sponge() {
if (this.spongeSubject == null) {
this.spongeSubject = ProxyFactory.toSponge(this);
}
@ -123,8 +122,8 @@ public abstract class PermissionHolderSubject<T extends PermissionHolder> implem
@Override
public boolean isChildOf(ImmutableContextSet contexts, LPSubjectReference parent) {
return parent.getCollectionIdentifier().equals(PermissionService.SUBJECTS_GROUP) &&
getPermissionValue(contexts, Inheritance.key(parent.getSubjectIdentifier())).asBoolean();
return parent.collectionIdentifier().equals(PermissionService.SUBJECTS_GROUP) &&
getPermissionValue(contexts, Inheritance.key(parent.subjectIdentifier())).asBoolean();
}
@Override

View File

@ -184,11 +184,11 @@ public class PermissionHolderSubjectData implements LPSubjectData {
Objects.requireNonNull(contexts, "contexts");
Objects.requireNonNull(subject, "subject");
if (!subject.getCollectionIdentifier().equals(PermissionService.SUBJECTS_GROUP)) {
if (!subject.collectionIdentifier().equals(PermissionService.SUBJECTS_GROUP)) {
return CompletableFuture.completedFuture(false);
}
Node node = Inheritance.builder(subject.getSubjectIdentifier())
Node node = Inheritance.builder(subject.subjectIdentifier())
.withContext(contexts)
.build();
@ -204,11 +204,11 @@ public class PermissionHolderSubjectData implements LPSubjectData {
Objects.requireNonNull(contexts, "contexts");
Objects.requireNonNull(subject, "subject");
if (!subject.getCollectionIdentifier().equals(PermissionService.SUBJECTS_GROUP)) {
if (!subject.collectionIdentifier().equals(PermissionService.SUBJECTS_GROUP)) {
return CompletableFuture.completedFuture(false);
}
Node node = Inheritance.builder(subject.getSubjectIdentifier())
Node node = Inheritance.builder(subject.subjectIdentifier())
.withContext(contexts)
.build();

View File

@ -30,18 +30,17 @@ import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.model.SpongeUser;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.model.LPSubjectUser;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
/**
* Implements {@link LPSubject} for a {@link SpongeUser}.
*/
public final class UserSubject extends PermissionHolderSubject<SpongeUser> implements LPSubject {
public final class UserSubject extends PermissionHolderSubject<SpongeUser> implements LPSubject, LPSubjectUser {
public UserSubject(LPSpongePlugin plugin, SpongeUser parent) {
super(plugin, parent);
}
@ -57,9 +56,12 @@ public final class UserSubject extends PermissionHolderSubject<SpongeUser> imple
}
@Override
public Optional<CommandSource> getCommandSource() {
final UUID uuid = this.parent.getUniqueId();
return Sponge.getServer().getPlayer(uuid).map(Function.identity());
public Optional<ServerPlayer> resolvePlayer() {
if (!Sponge.isServerAvailable()) {
return Optional.empty();
}
return Sponge.server().player(this.parent.getUniqueId());
}
@Override

View File

@ -49,7 +49,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
@ -143,7 +142,7 @@ public class PersistedCollection implements LPSubjectCollection {
}
@Override
public CompletableFuture<ImmutableCollection<LPSubject>> loadSubjects(Set<String> identifiers) {
public CompletableFuture<ImmutableCollection<LPSubject>> loadSubjects(Iterable<String> identifiers) {
ImmutableSet.Builder<LPSubject> subjects = ImmutableSet.builder();
for (String id : identifiers) {
subjects.add(Objects.requireNonNull(this.subjects.get(id.toLowerCase(Locale.ROOT))));

View File

@ -30,20 +30,15 @@ import me.lucko.luckperms.common.model.PermissionHolderIdentifier;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.ProxyFactory;
import me.lucko.luckperms.sponge.service.events.UpdateEventHandler;
import me.lucko.luckperms.sponge.service.model.LPProxiedSubject;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectData;
import me.lucko.luckperms.sponge.service.model.ProxiedSubject;
import me.lucko.luckperms.sponge.service.model.calculated.CalculatedSubject;
import me.lucko.luckperms.sponge.service.model.calculated.CalculatedSubjectData;
import me.lucko.luckperms.sponge.service.model.calculated.MonitoredSubjectData;
import net.luckperms.api.model.data.DataType;
import org.spongepowered.api.command.CommandSource;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
/**
@ -66,7 +61,7 @@ public class PersistedSubject extends CalculatedSubject implements LPSubject {
private final PersistedSubjectData subjectData;
private final CalculatedSubjectData transientSubjectData;
private ProxiedSubject spongeSubject = null;
private LPProxiedSubject spongeSubject = null;
/**
* The save buffer instance for saving changes to disk
@ -89,7 +84,7 @@ public class PersistedSubject extends CalculatedSubject implements LPSubject {
protected void onUpdate(boolean success) {
super.onUpdate(success);
if (success) {
fireUpdateEvent(this);
PersistedSubject.this.service.fireUpdateEvent(this);
}
}
};
@ -97,7 +92,7 @@ public class PersistedSubject extends CalculatedSubject implements LPSubject {
@Override
protected void onUpdate(boolean success) {
if (success) {
fireUpdateEvent(this);
PersistedSubject.this.service.fireUpdateEvent(this);
}
}
};
@ -105,15 +100,6 @@ public class PersistedSubject extends CalculatedSubject implements LPSubject {
this.saveBuffer = new SaveBuffer(service.getPlugin());
}
/**
* Calls the subject data update event for the given {@link LPSubjectData} instance.
*
* @param subjectData the subject data
*/
private void fireUpdateEvent(LPSubjectData subjectData) {
UpdateEventHandler.fireUpdateEvent(this.service.getPlugin(), subjectData);
}
/**
* Loads data into this {@link PersistedSubject} from the given
* {@link SubjectDataContainer} container
@ -149,7 +135,7 @@ public class PersistedSubject extends CalculatedSubject implements LPSubject {
}
@Override
public ProxiedSubject sponge() {
public LPProxiedSubject sponge() {
if (this.spongeSubject == null) {
this.spongeSubject = ProxyFactory.toSponge(this);
}
@ -181,11 +167,6 @@ public class PersistedSubject extends CalculatedSubject implements LPSubject {
return this.transientSubjectData;
}
@Override
public Optional<CommandSource> getCommandSource() {
return Optional.empty();
}
private final class SaveBuffer extends BufferedRequest<Void> {
public SaveBuffer(LuckPermsPlugin plugin) {
super(1, TimeUnit.SECONDS, plugin.getBootstrap().getScheduler());

View File

@ -256,8 +256,8 @@ public class SubjectDataContainer {
JsonArray data = new JsonArray();
for (LPSubjectReference ref : e.getValue()) {
JsonObject parent = new JsonObject();
parent.addProperty("collection", ref.getCollectionIdentifier());
parent.addProperty("subject", ref.getSubjectIdentifier());
parent.addProperty("collection", ref.collectionIdentifier());
parent.addProperty("subject", ref.subjectIdentifier());
data.add(parent);
}
section.add("data", data);

View File

@ -0,0 +1,31 @@
{
"loader": {
"name": "java_plain",
"version": "1.0"
},
"license": "MIT",
"plugins": [
{
"id": "luckperms",
"name": "LuckPerms",
"version": "${pluginVersion}",
"entrypoint": "me.lucko.luckperms.sponge.LPSpongeBootstrap",
"description": "A permissions plugin",
"links": {
"homepage": "https://luckperms.net"
},
"contributors": [
{
"name": "Luck",
"description": "Developer"
}
],
"dependencies": [
{
"id": "spongeapi",
"version": "8.0.0"
}
]
}
]
}

View File

@ -619,6 +619,9 @@ disable-bulkupdate = false
# - When this happens, the plugin will set their primary group back to default.
prevent-primary-group-removal = false
# If LuckPerms should update the list of commands sent to the client when permissions are changed.
update-client-command-list = true
# If LuckPerms should attempt to resolve Vanilla command target selectors for LP commands.
# See here for more info: https://minecraft.gamepedia.com/Commands#Target_selectors
resolve-command-selectors = false