Nukkit support (#764)
This commit is contained in:
parent
794455d728
commit
31e436868d
@ -36,7 +36,8 @@ public enum PlatformType {
|
||||
|
||||
BUKKIT("Bukkit"),
|
||||
BUNGEE("Bungee"),
|
||||
SPONGE("Sponge");
|
||||
SPONGE("Sponge"),
|
||||
NUKKIT("Nukkit");
|
||||
|
||||
private final String friendlyName;
|
||||
|
||||
|
@ -244,4 +244,12 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
||||
|
@ -55,7 +55,7 @@ import javax.annotation.Nonnull;
|
||||
*
|
||||
* Injected by {@link InjectorDefaultsMap}.
|
||||
*/
|
||||
public class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
public final class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
// keyset for all instances
|
||||
private static final Set<Boolean> KEY_SET = ImmutableSet.of(Boolean.TRUE, Boolean.FALSE);
|
||||
|
||||
|
@ -56,7 +56,7 @@ import javax.annotation.Nonnull;
|
||||
*
|
||||
* Injected by {@link InjectorPermissionMap}.
|
||||
*/
|
||||
public class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
|
||||
// Uses perm.getName().toLowerCase(java.util.Locale.ENGLISH); to determine the key
|
||||
private final Map<String, Permission> delegate = new ConcurrentHashMap<>();
|
||||
|
@ -33,7 +33,6 @@ import me.lucko.luckperms.common.utils.ImmutableCollectors;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.Collection;
|
||||
@ -56,7 +55,7 @@ import javax.annotation.Nonnull;
|
||||
*
|
||||
* Bukkit for some reason sometimes uses subscription status to determine whether
|
||||
* a permissible has a given node, instead of checking directly with
|
||||
* {@link Permissible#hasPermission(Permission)}.
|
||||
* {@link Permissible#hasPermission(String)}.
|
||||
*
|
||||
* {@link org.bukkit.Server#broadcast(String, String)} is a good example of this.
|
||||
*
|
||||
@ -68,7 +67,7 @@ import javax.annotation.Nonnull;
|
||||
*
|
||||
* Injected by {@link InjectorSubscriptionMap}.
|
||||
*/
|
||||
public class LPSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>> {
|
||||
public final class LPSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>> {
|
||||
|
||||
// the plugin instance
|
||||
final LPBukkitPlugin plugin;
|
||||
@ -151,7 +150,7 @@ public class LPSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>
|
||||
/**
|
||||
* Value map extension which includes LP objects in Permissible related queries.
|
||||
*/
|
||||
public class LPSubscriptionValueMap implements Map<Permissible, Boolean> {
|
||||
public final class LPSubscriptionValueMap implements Map<Permissible, Boolean> {
|
||||
|
||||
// the permission being mapped to this value map
|
||||
private final String permission;
|
||||
@ -159,7 +158,7 @@ public class LPSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>
|
||||
// the backing map
|
||||
private final Map<Permissible, Boolean> backing;
|
||||
|
||||
public LPSubscriptionValueMap(String permission, Map<Permissible, Boolean> backing) {
|
||||
private LPSubscriptionValueMap(String permission, Map<Permissible, Boolean> backing) {
|
||||
this.permission = permission;
|
||||
this.backing = backing;
|
||||
}
|
||||
@ -235,6 +234,11 @@ public class LPSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return Math.max(1, this.backing.size());
|
||||
}
|
||||
|
||||
// just delegate to the backing map
|
||||
|
||||
@Override
|
||||
@ -247,13 +251,6 @@ public class LPSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>
|
||||
return this.backing.remove(key);
|
||||
}
|
||||
|
||||
// the following methods are not used in the current impls of PluginManager, but just delegate them for now
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.backing.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return this.backing.containsValue(value);
|
||||
|
@ -208,6 +208,21 @@ public class ConfigKeys {
|
||||
*/
|
||||
public static final ConfigKey<Boolean> APPLY_BUKKIT_ATTACHMENT_PERMISSIONS = EnduringKey.wrap(BooleanKey.of("apply-bukkit-attachment-permissions", true));
|
||||
|
||||
/**
|
||||
* If Nukkit child permissions are being applied. This setting is ignored on other platforms.
|
||||
*/
|
||||
public static final ConfigKey<Boolean> APPLY_NUKKIT_CHILD_PERMISSIONS = EnduringKey.wrap(BooleanKey.of("apply-nukkit-child-permissions", true));
|
||||
|
||||
/**
|
||||
* If Nukkit default permissions are being applied. This setting is ignored on other platforms.
|
||||
*/
|
||||
public static final ConfigKey<Boolean> APPLY_NUKKIT_DEFAULT_PERMISSIONS = EnduringKey.wrap(BooleanKey.of("apply-nukkit-default-permissions", true));
|
||||
|
||||
/**
|
||||
* If Nukkit attachment permissions are being applied. This setting is ignored on other platforms.
|
||||
*/
|
||||
public static final ConfigKey<Boolean> APPLY_NUKKIT_ATTACHMENT_PERMISSIONS = EnduringKey.wrap(BooleanKey.of("apply-nukkit-attachment-permissions", true));
|
||||
|
||||
/**
|
||||
* If BungeeCord configured permissions are being applied. This setting is ignored on other platforms.
|
||||
*/
|
||||
|
156
nukkit/pom.xml
Normal file
156
nukkit/pom.xml
Normal file
@ -0,0 +1,156 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>luckperms-nukkit</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<build>
|
||||
<defaultGoal>clean package</defaultGoal>
|
||||
<finalName>LuckPerms-Nukkit-${full.version}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${compiler.version}</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>${shade.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<minimizeJar>false</minimizeJar>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<relocations>
|
||||
<!-- shaded dependencies -->
|
||||
<relocation>
|
||||
<pattern>net.kyori.text</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.text</shadedPattern>
|
||||
</relocation>
|
||||
|
||||
<!-- relocated dependencies -->
|
||||
<relocation>
|
||||
<pattern>com.github.benmanes.caffeine</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.caffeine</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>okio</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.okio</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>okhttp3</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.okhttp3</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.mariadb.jdbc</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.mariadb</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.mysql</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.mysql</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.postgresql</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.postgresql</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.zaxxer.hikari</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.hikari</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.mongodb</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.mongodb</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.bson</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.bson</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>redis.clients.jedis</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.apache.commons.pool2</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.commonspool2</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>ninja.leaping.configurate</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.configurate</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.typesafe.config</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.hocon</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<!-- common -->
|
||||
<dependency>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<artifactId>luckperms-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- jsr305 -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- caffeine -->
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>2.6.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Nukkit -->
|
||||
<dependency>
|
||||
<groupId>cn.nukkit</groupId>
|
||||
<artifactId>nukkit</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>nukkit-repo</id>
|
||||
<url>https://repo.potestas.xyz/main/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
@ -0,0 +1,634 @@
|
||||
/*
|
||||
* 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.nukkit;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.LuckPermsApi;
|
||||
import me.lucko.luckperms.api.platform.PlatformType;
|
||||
import me.lucko.luckperms.common.actionlog.LogDispatcher;
|
||||
import me.lucko.luckperms.common.api.ApiRegistrationUtil;
|
||||
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
|
||||
import me.lucko.luckperms.common.buffers.BufferedRequest;
|
||||
import me.lucko.luckperms.common.buffers.UpdateTaskBuffer;
|
||||
import me.lucko.luckperms.common.caching.handlers.CachedStateManager;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.commands.CommandPermission;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.config.AbstractConfiguration;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
|
||||
import me.lucko.luckperms.common.contexts.ContextManager;
|
||||
import me.lucko.luckperms.common.contexts.LuckPermsCalculator;
|
||||
import me.lucko.luckperms.common.dependencies.DependencyManager;
|
||||
import me.lucko.luckperms.common.dependencies.DependencyRegistry;
|
||||
import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader;
|
||||
import me.lucko.luckperms.common.dependencies.classloader.ReflectionClassLoader;
|
||||
import me.lucko.luckperms.common.event.EventFactory;
|
||||
import me.lucko.luckperms.common.inheritance.InheritanceHandler;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.NoopLocaleManager;
|
||||
import me.lucko.luckperms.common.locale.SimpleLocaleManager;
|
||||
import me.lucko.luckperms.common.logging.Logger;
|
||||
import me.lucko.luckperms.common.logging.SenderLogger;
|
||||
import me.lucko.luckperms.common.managers.group.StandardGroupManager;
|
||||
import me.lucko.luckperms.common.managers.track.StandardTrackManager;
|
||||
import me.lucko.luckperms.common.managers.user.StandardUserManager;
|
||||
import me.lucko.luckperms.common.messaging.InternalMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.MessagingFactory;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.Storage;
|
||||
import me.lucko.luckperms.common.storage.StorageFactory;
|
||||
import me.lucko.luckperms.common.storage.StorageType;
|
||||
import me.lucko.luckperms.common.storage.dao.file.FileWatcher;
|
||||
import me.lucko.luckperms.common.tasks.CacheHousekeepingTask;
|
||||
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
|
||||
import me.lucko.luckperms.common.tasks.UpdateTask;
|
||||
import me.lucko.luckperms.common.treeview.PermissionVault;
|
||||
import me.lucko.luckperms.common.verbose.VerboseHandler;
|
||||
import me.lucko.luckperms.nukkit.calculators.NukkitCalculatorFactory;
|
||||
import me.lucko.luckperms.nukkit.contexts.NukkitContextManager;
|
||||
import me.lucko.luckperms.nukkit.contexts.WorldCalculator;
|
||||
import me.lucko.luckperms.nukkit.listeners.NukkitConnectionListener;
|
||||
import me.lucko.luckperms.nukkit.listeners.NukkitPlatformListener;
|
||||
import me.lucko.luckperms.nukkit.model.PermissionDefault;
|
||||
import me.lucko.luckperms.nukkit.model.permissible.LPPermissible;
|
||||
import me.lucko.luckperms.nukkit.model.permissible.PermissibleInjector;
|
||||
import me.lucko.luckperms.nukkit.model.permissible.PermissibleMonitoringInjector;
|
||||
import me.lucko.luckperms.nukkit.model.server.InjectorDefaultsMap;
|
||||
import me.lucko.luckperms.nukkit.model.server.InjectorPermissionMap;
|
||||
import me.lucko.luckperms.nukkit.model.server.InjectorSubscriptionMap;
|
||||
import me.lucko.luckperms.nukkit.model.server.LPDefaultsMap;
|
||||
import me.lucko.luckperms.nukkit.model.server.LPPermissionMap;
|
||||
import me.lucko.luckperms.nukkit.model.server.LPSubscriptionMap;
|
||||
|
||||
import cn.nukkit.Player;
|
||||
import cn.nukkit.command.PluginCommand;
|
||||
import cn.nukkit.event.HandlerList;
|
||||
import cn.nukkit.permission.Permission;
|
||||
import cn.nukkit.plugin.PluginBase;
|
||||
import cn.nukkit.plugin.PluginManager;
|
||||
import cn.nukkit.plugin.service.ServicePriority;
|
||||
import cn.nukkit.utils.Config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* LuckPerms implementation for the Nukkit API.
|
||||
*/
|
||||
public class LPNukkitPlugin extends PluginBase implements LuckPermsPlugin {
|
||||
|
||||
private long startTime;
|
||||
private NukkitSchedulerAdapter scheduler;
|
||||
private NukkitCommandExecutor commandManager;
|
||||
private LuckPermsConfiguration configuration;
|
||||
private StandardUserManager userManager;
|
||||
private StandardGroupManager groupManager;
|
||||
private StandardTrackManager trackManager;
|
||||
private Storage storage;
|
||||
private FileWatcher fileWatcher = null;
|
||||
private InternalMessagingService messagingService = null;
|
||||
private LuckPermsApiProvider apiProvider;
|
||||
private EventFactory eventFactory;
|
||||
private Logger log;
|
||||
private LPSubscriptionMap subscriptionMap;
|
||||
private LPPermissionMap permissionMap;
|
||||
private LPDefaultsMap defaultPermissionMap;
|
||||
private LocaleManager localeManager;
|
||||
private PluginClassLoader pluginClassLoader;
|
||||
private DependencyManager dependencyManager;
|
||||
private InheritanceHandler inheritanceHandler;
|
||||
private CachedStateManager cachedStateManager;
|
||||
private ContextManager<Player> contextManager;
|
||||
private CalculatorFactory calculatorFactory;
|
||||
private BufferedRequest<Void> updateTaskBuffer;
|
||||
private VerboseHandler verboseHandler;
|
||||
private NukkitSenderFactory senderFactory;
|
||||
private PermissionVault permissionVault;
|
||||
private LogDispatcher logDispatcher;
|
||||
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// setup minimal functionality in order to load initial dependencies
|
||||
this.scheduler = new NukkitSchedulerAdapter(this);
|
||||
this.localeManager = new NoopLocaleManager();
|
||||
this.senderFactory = new NukkitSenderFactory(this);
|
||||
this.log = new SenderLogger(this, getConsoleSender());
|
||||
|
||||
this.pluginClassLoader = new ReflectionClassLoader(this);
|
||||
this.dependencyManager = new DependencyManager(this);
|
||||
this.dependencyManager.loadDependencies(DependencyRegistry.GLOBAL_DEPENDENCIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
this.startTime = System.currentTimeMillis();
|
||||
sendStartupBanner(getConsoleSender());
|
||||
this.verboseHandler = new VerboseHandler(this.scheduler.asyncNukkit(), getVersion());
|
||||
this.permissionVault = new PermissionVault(this.scheduler.asyncNukkit());
|
||||
this.logDispatcher = new LogDispatcher(this);
|
||||
|
||||
getLog().info("Loading configuration...");
|
||||
this.configuration = new AbstractConfiguration(this, new NukkitConfigAdapter(this, resolveConfig("config.yml")));
|
||||
this.configuration.loadAll();
|
||||
|
||||
StorageFactory storageFactory = new StorageFactory(this);
|
||||
Set<StorageType> storageTypes = storageFactory.getRequiredTypes(StorageType.H2);
|
||||
this.dependencyManager.loadStorageDependencies(storageTypes);
|
||||
|
||||
// register events
|
||||
NukkitConnectionListener connectionListener = new NukkitConnectionListener(this);
|
||||
getServer().getPluginManager().registerEvents(connectionListener, this);
|
||||
getServer().getPluginManager().registerEvents(new NukkitPlatformListener(this), this);
|
||||
|
||||
if (getConfiguration().get(ConfigKeys.WATCH_FILES)) {
|
||||
this.fileWatcher = new FileWatcher(this);
|
||||
getScheduler().asyncRepeating(this.fileWatcher, 30L);
|
||||
}
|
||||
|
||||
// initialise datastore
|
||||
this.storage = storageFactory.getInstance(StorageType.H2);
|
||||
|
||||
// initialise messaging
|
||||
this.messagingService = new MessagingFactory<>(this).getInstance();
|
||||
|
||||
// setup the update task buffer
|
||||
this.updateTaskBuffer = new UpdateTaskBuffer(this);
|
||||
|
||||
// load locale
|
||||
this.localeManager = new SimpleLocaleManager();
|
||||
this.localeManager.tryLoad(this, new File(getDataFolder(), "lang.yml"));
|
||||
|
||||
// register commands
|
||||
this.commandManager = new NukkitCommandExecutor(this);
|
||||
PluginCommand main = (PluginCommand) getServer().getPluginCommand("luckperms");
|
||||
main.setExecutor(this.commandManager);
|
||||
|
||||
// load internal managers
|
||||
getLog().info("Loading internal permission managers...");
|
||||
this.inheritanceHandler = new InheritanceHandler(this);
|
||||
this.userManager = new StandardUserManager(this);
|
||||
this.groupManager = new StandardGroupManager(this);
|
||||
this.trackManager = new StandardTrackManager(this);
|
||||
this.calculatorFactory = new NukkitCalculatorFactory(this);
|
||||
this.cachedStateManager = new CachedStateManager();
|
||||
|
||||
// setup context manager
|
||||
this.contextManager = new NukkitContextManager(this);
|
||||
this.contextManager.registerCalculator(new WorldCalculator(this));
|
||||
this.contextManager.registerStaticCalculator(new LuckPermsCalculator(getConfiguration()));
|
||||
|
||||
// inject our own custom permission maps
|
||||
Runnable[] injectors = new Runnable[]{
|
||||
new InjectorSubscriptionMap(this),
|
||||
new InjectorPermissionMap(this),
|
||||
new InjectorDefaultsMap(this)
|
||||
};
|
||||
|
||||
for (Runnable injector : injectors) {
|
||||
injector.run();
|
||||
|
||||
// schedule another injection after all plugins have loaded
|
||||
// the entire pluginmanager instance is replaced by some plugins :(
|
||||
this.scheduler.asyncLater(injector, 1L);
|
||||
}
|
||||
|
||||
// inject verbose handlers into internal nukkit objects
|
||||
new PermissibleMonitoringInjector(this).run();
|
||||
|
||||
// register with the LP API
|
||||
this.apiProvider = new LuckPermsApiProvider(this);
|
||||
|
||||
// setup event factory
|
||||
this.eventFactory = new EventFactory(this, this.apiProvider);
|
||||
|
||||
ApiRegistrationUtil.registerProvider(this.apiProvider);
|
||||
getServer().getServiceManager().register(LuckPermsApi.class, this.apiProvider, this, ServicePriority.NORMAL);
|
||||
|
||||
|
||||
// schedule update tasks
|
||||
int mins = getConfiguration().get(ConfigKeys.SYNC_TIME);
|
||||
if (mins > 0) {
|
||||
long ticks = mins * 60 * 20;
|
||||
this.scheduler.asyncRepeating(() -> this.updateTaskBuffer.request(), ticks);
|
||||
}
|
||||
this.scheduler.asyncLater(() -> this.updateTaskBuffer.request(), 40L);
|
||||
|
||||
// run an update instantly.
|
||||
getLog().info("Performing initial data load...");
|
||||
try {
|
||||
new UpdateTask(this, true).run();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
// register tasks
|
||||
this.scheduler.asyncRepeating(new ExpireTemporaryTask(this), 60L);
|
||||
this.scheduler.asyncRepeating(new CacheHousekeepingTask(this), 2400L);
|
||||
|
||||
// register permissions
|
||||
try {
|
||||
PluginManager pm = getServer().getPluginManager();
|
||||
PermissionDefault permDefault = getConfiguration().get(ConfigKeys.COMMANDS_ALLOW_OP) ? PermissionDefault.OP : PermissionDefault.FALSE;
|
||||
|
||||
for (CommandPermission p : CommandPermission.values()) {
|
||||
pm.addPermission(new Permission(p.getPermission(), null, permDefault.toString()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// this throws an exception if the plugin is /reloaded, grr
|
||||
}
|
||||
|
||||
if (!getConfiguration().get(ConfigKeys.OPS_ENABLED)) {
|
||||
Config ops = getServer().getOps();
|
||||
ops.getKeys(false).forEach(ops::remove);
|
||||
}
|
||||
|
||||
// replace the temporary executor when the Nukkit one starts
|
||||
getServer().getScheduler().scheduleTask(this, () -> this.scheduler.setUseFallback(false), true);
|
||||
|
||||
// Load any online users (in the case of a reload)
|
||||
for (Player player : getServer().getOnlinePlayers().values()) {
|
||||
this.scheduler.doAsync(() -> {
|
||||
try {
|
||||
User user = connectionListener.loadUser(player.getUniqueId(), player.getName());
|
||||
if (user != null) {
|
||||
this.scheduler.doSync(() -> {
|
||||
try {
|
||||
LPPermissible lpPermissible = new LPPermissible(player, user, this);
|
||||
PermissibleInjector.inject(player, lpPermissible);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getLog().info("Successfully enabled. (took " + (System.currentTimeMillis() - this.startTime) + "ms)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
// Switch back to the fallback executor, the nukkit one won't allow new tasks
|
||||
this.scheduler.setUseFallback(true);
|
||||
|
||||
this.permissionVault.shutdown();
|
||||
this.verboseHandler.shutdown();
|
||||
|
||||
// uninject from players
|
||||
for (Player player : getServer().getOnlinePlayers().values()) {
|
||||
try {
|
||||
PermissibleInjector.unInject(player, false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
player.setOp(false);
|
||||
}
|
||||
|
||||
final User user = getUserManager().getIfLoaded(player.getUniqueId());
|
||||
if (user != null) {
|
||||
user.getCachedData().invalidateCaches();
|
||||
getUserManager().unload(user);
|
||||
}
|
||||
}
|
||||
|
||||
// uninject custom maps
|
||||
InjectorSubscriptionMap.uninject();
|
||||
InjectorPermissionMap.uninject();
|
||||
InjectorDefaultsMap.uninject();
|
||||
|
||||
getLog().info("Closing storage...");
|
||||
this.storage.shutdown();
|
||||
|
||||
if (this.fileWatcher != null) {
|
||||
this.fileWatcher.close();
|
||||
}
|
||||
|
||||
if (this.messagingService != null) {
|
||||
getLog().info("Closing messaging service...");
|
||||
this.messagingService.close();
|
||||
}
|
||||
|
||||
ApiRegistrationUtil.unregisterProvider();
|
||||
getServer().getServiceManager().cancel(this);
|
||||
|
||||
getLog().info("Shutting down internal scheduler...");
|
||||
this.scheduler.shutdown();
|
||||
|
||||
// Nukkit will do this again when #onDisable completes, but we do it early to prevent NPEs elsewhere.
|
||||
getServer().getScheduler().cancelTask(this);
|
||||
HandlerList.unregisterAll(this);
|
||||
getLog().info("Goodbye!");
|
||||
}
|
||||
|
||||
public void refreshAutoOp(User user, Player player) {
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
Map<String, Boolean> backing = user.getCachedData().getPermissionData(this.contextManager.getApplicableContexts(player)).getImmutableBacking();
|
||||
boolean op = Optional.ofNullable(backing.get("luckperms.autoop")).orElse(false);
|
||||
player.setOp(op);
|
||||
}
|
||||
}
|
||||
|
||||
private File resolveConfig(String file) {
|
||||
File configFile = new File(getDataFolder(), file);
|
||||
|
||||
if (!configFile.exists()) {
|
||||
getDataFolder().mkdirs();
|
||||
saveResource("config.yml", false);
|
||||
}
|
||||
|
||||
return configFile;
|
||||
}
|
||||
|
||||
public LPSubscriptionMap getSubscriptionMap() {
|
||||
return this.subscriptionMap;
|
||||
}
|
||||
|
||||
public void setSubscriptionMap(LPSubscriptionMap subscriptionMap) {
|
||||
this.subscriptionMap = subscriptionMap;
|
||||
}
|
||||
|
||||
public LPPermissionMap getPermissionMap() {
|
||||
return this.permissionMap;
|
||||
}
|
||||
|
||||
public void setPermissionMap(LPPermissionMap permissionMap) {
|
||||
this.permissionMap = permissionMap;
|
||||
}
|
||||
|
||||
public LPDefaultsMap getDefaultPermissionMap() {
|
||||
return this.defaultPermissionMap;
|
||||
}
|
||||
|
||||
public void setDefaultPermissionMap(LPDefaultsMap defaultPermissionMap) {
|
||||
this.defaultPermissionMap = defaultPermissionMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<InternalMessagingService> getMessagingService() {
|
||||
return Optional.ofNullable(this.messagingService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessagingService(InternalMessagingService messagingService) {
|
||||
if (this.messagingService == null) {
|
||||
this.messagingService = messagingService;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<FileWatcher> getFileWatcher() {
|
||||
return Optional.ofNullable(this.fileWatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformType getServerType() {
|
||||
return PlatformType.NUKKIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerBrand() {
|
||||
return getServer().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerVersion() {
|
||||
return getServer().getVersion() + " - " + getServer().getNukkitVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerName() {
|
||||
return getServer().getServerUniqueId().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataDirectory() {
|
||||
return super.getDataFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceStream(String path) {
|
||||
return getResource(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getPlayer(User user) {
|
||||
return getServer().getOnlinePlayers().get(user.getUuid());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<UUID> lookupUuid(String username) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Contexts getContextForUser(User user) {
|
||||
Player player = getPlayer(user);
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
return this.contextManager.getApplicableContexts(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayerCount() {
|
||||
return getServer().getOnlinePlayers().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> getPlayerList() {
|
||||
return getServer().getOnlinePlayers().values().stream().map(Player::getName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<UUID> getOnlinePlayers() {
|
||||
return getServer().getOnlinePlayers().values().stream().map(Player::getUniqueId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayerOnline(UUID external) {
|
||||
Player player = getServer().getOnlinePlayers().get(external);
|
||||
return player != null && player.isOnline();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Sender> getOnlineSenders() {
|
||||
return Stream.concat(
|
||||
Stream.of(getConsoleSender()),
|
||||
getServer().getOnlinePlayers().values().stream().map(p -> getSenderFactory().wrap(p))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sender getConsoleSender() {
|
||||
return getSenderFactory().wrap(getServer().getConsoleSender());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartTime() {
|
||||
return this.startTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NukkitSchedulerAdapter getScheduler() {
|
||||
return this.scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NukkitCommandExecutor getCommandManager() {
|
||||
return this.commandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuckPermsConfiguration getConfiguration() {
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StandardUserManager getUserManager() {
|
||||
return this.userManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StandardGroupManager getGroupManager() {
|
||||
return this.groupManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StandardTrackManager getTrackManager() {
|
||||
return this.trackManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Storage getStorage() {
|
||||
return this.storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuckPermsApiProvider getApiProvider() {
|
||||
return this.apiProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventFactory getEventFactory() {
|
||||
return this.eventFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLog() {
|
||||
return this.log;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocaleManager getLocaleManager() {
|
||||
return this.localeManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginClassLoader getPluginClassLoader() {
|
||||
return this.pluginClassLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencyManager getDependencyManager() {
|
||||
return this.dependencyManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachedStateManager getCachedStateManager() {
|
||||
return this.cachedStateManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextManager<Player> getContextManager() {
|
||||
return this.contextManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InheritanceHandler getInheritanceHandler() {
|
||||
return this.inheritanceHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalculatorFactory getCalculatorFactory() {
|
||||
return this.calculatorFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedRequest<Void> getUpdateTaskBuffer() {
|
||||
return this.updateTaskBuffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VerboseHandler getVerboseHandler() {
|
||||
return this.verboseHandler;
|
||||
}
|
||||
|
||||
public NukkitSenderFactory getSenderFactory() {
|
||||
return this.senderFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionVault getPermissionVault() {
|
||||
return this.permissionVault;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogDispatcher getLogDispatcher() {
|
||||
return this.logDispatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getUniqueConnections() {
|
||||
return this.uniqueConnections;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.nukkit;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
import me.lucko.luckperms.common.commands.CommandManager;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
|
||||
import cn.nukkit.command.Command;
|
||||
import cn.nukkit.command.CommandExecutor;
|
||||
import cn.nukkit.command.CommandSender;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class NukkitCommandExecutor extends CommandManager implements CommandExecutor {
|
||||
private static final Splitter ARGUMENT_SPLITTER = Splitter.on(COMMAND_SEPARATOR_PATTERN).omitEmptyStrings();
|
||||
private static final Joiner ARGUMENT_JOINER = Joiner.on(' ');
|
||||
|
||||
private final LPNukkitPlugin plugin;
|
||||
|
||||
NukkitCommandExecutor(LPNukkitPlugin plugin) {
|
||||
super(plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
Sender lpSender = this.plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = stripQuotes(ARGUMENT_SPLITTER.splitToList(ARGUMENT_JOINER.join(args)));
|
||||
|
||||
onCommand(lpSender, label, arguments);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.nukkit;
|
||||
|
||||
import me.lucko.luckperms.common.config.adapter.AbstractConfigurationAdapter;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import cn.nukkit.utils.Config;
|
||||
import cn.nukkit.utils.ConfigSection;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class NukkitConfigAdapter extends AbstractConfigurationAdapter implements ConfigurationAdapter {
|
||||
|
||||
private final File file;
|
||||
private Config configuration;
|
||||
|
||||
public NukkitConfigAdapter(LuckPermsPlugin plugin, File file) {
|
||||
super(plugin);
|
||||
this.file = file;
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
this.configuration = new Config(this.file, Config.YAML);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String path) {
|
||||
return this.configuration.exists(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(String path, String def) {
|
||||
return this.configuration.getString(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(String path, int def) {
|
||||
return this.configuration.getInt(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(String path, boolean def) {
|
||||
return this.configuration.getBoolean(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getList(String path, List<String> def) {
|
||||
List<String> ret = this.configuration.getStringList(path);
|
||||
return ret == null ? def : ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getObjectList(String path, List<String> def) {
|
||||
ConfigSection section = this.configuration.getSection(path);
|
||||
if (section == null) {
|
||||
return def;
|
||||
}
|
||||
|
||||
Set<String> keys = section.getKeys(false);
|
||||
return keys == null ? def : new ArrayList<>(keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getMap(String path, Map<String, String> def) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
ConfigSection section = this.configuration.getSection(path);
|
||||
if (section == null) {
|
||||
return def;
|
||||
}
|
||||
|
||||
for (String key : section.getKeys(false)) {
|
||||
map.put(key, section.getString(key));
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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.nukkit;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerTask;
|
||||
import me.lucko.luckperms.common.utils.SafeIteration;
|
||||
|
||||
import cn.nukkit.scheduler.ServerScheduler;
|
||||
import cn.nukkit.scheduler.TaskHandler;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class NukkitSchedulerAdapter implements SchedulerAdapter {
|
||||
private final LPNukkitPlugin plugin;
|
||||
|
||||
private final ExecutorService asyncFallback;
|
||||
private final Executor asyncNukkit;
|
||||
private final Executor sync;
|
||||
private final Executor async;
|
||||
|
||||
private boolean useFallback = true;
|
||||
|
||||
private final Set<SchedulerTask> tasks = ConcurrentHashMap.newKeySet();
|
||||
|
||||
public NukkitSchedulerAdapter(LPNukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
this.sync = new SyncExecutor();
|
||||
this.asyncFallback = new FallbackAsyncExecutor();
|
||||
this.asyncNukkit = new NukkitAsyncExecutor();
|
||||
this.async = new AsyncExecutor();
|
||||
}
|
||||
|
||||
private ServerScheduler scheduler() {
|
||||
return this.plugin.getServer().getScheduler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAsync(Runnable runnable) {
|
||||
async().execute(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSync(Runnable runnable) {
|
||||
sync().execute(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks) {
|
||||
SchedulerTask task = new NukkitSchedulerTask(scheduler().scheduleDelayedRepeatingTask(this.plugin, runnable, (int) intervalTicks, (int) intervalTicks, true));
|
||||
this.tasks.add(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask syncRepeating(Runnable runnable, long intervalTicks) {
|
||||
SchedulerTask task = new NukkitSchedulerTask(scheduler().scheduleDelayedRepeatingTask(this.plugin, runnable, (int) intervalTicks, (int) intervalTicks, false));
|
||||
this.tasks.add(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask asyncLater(Runnable runnable, long delayTicks) {
|
||||
return new NukkitSchedulerTask(scheduler().scheduleDelayedTask(this.plugin, runnable, (int) delayTicks, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask syncLater(Runnable runnable, long delayTicks) {
|
||||
return new NukkitSchedulerTask(scheduler().scheduleDelayedTask(this.plugin, runnable, (int) delayTicks, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
SafeIteration.iterate(this.tasks, SchedulerTask::cancel);
|
||||
|
||||
// wait for executor
|
||||
this.asyncFallback.shutdown();
|
||||
try {
|
||||
this.asyncFallback.awaitTermination(30, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ExecutorService asyncFallback() {
|
||||
return this.asyncFallback;
|
||||
}
|
||||
|
||||
public Executor asyncNukkit() {
|
||||
return this.asyncNukkit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor sync() {
|
||||
return this.sync;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor async() {
|
||||
return this.async;
|
||||
}
|
||||
|
||||
public void setUseFallback(boolean useFallback) {
|
||||
this.useFallback = useFallback;
|
||||
}
|
||||
|
||||
private final class SyncExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(@Nonnull Runnable runnable) {
|
||||
NukkitSchedulerAdapter.this.plugin.getServer().getScheduler().scheduleTask(NukkitSchedulerAdapter.this.plugin, runnable, false);
|
||||
}
|
||||
}
|
||||
|
||||
private final class AsyncExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(@Nonnull Runnable runnable) {
|
||||
if (NukkitSchedulerAdapter.this.useFallback || !NukkitSchedulerAdapter.this.plugin.isEnabled()) {
|
||||
NukkitSchedulerAdapter.this.asyncFallback.execute(runnable);
|
||||
} else {
|
||||
NukkitSchedulerAdapter.this.asyncNukkit.execute(runnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class NukkitAsyncExecutor implements Executor {
|
||||
@Override
|
||||
public void execute(@Nonnull Runnable runnable) {
|
||||
NukkitSchedulerAdapter.this.plugin.getServer().getScheduler().scheduleTask(NukkitSchedulerAdapter.this.plugin, runnable, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class FallbackAsyncExecutor extends ThreadPoolExecutor {
|
||||
private FallbackAsyncExecutor() {
|
||||
super(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>(), new ThreadFactoryBuilder().setNameFormat("luckperms-fallback-%d").build());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class NukkitSchedulerTask implements SchedulerTask {
|
||||
private final TaskHandler task;
|
||||
|
||||
private NukkitSchedulerTask(TaskHandler task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.task.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.nukkit;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.common.commands.CommandManager;
|
||||
import me.lucko.luckperms.common.commands.sender.SenderFactory;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
|
||||
import cn.nukkit.Player;
|
||||
import cn.nukkit.command.CommandSender;
|
||||
import cn.nukkit.command.ConsoleCommandSender;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class NukkitSenderFactory extends SenderFactory<CommandSender> {
|
||||
public NukkitSenderFactory(LuckPermsPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName(CommandSender sender) {
|
||||
if (sender instanceof Player) {
|
||||
return sender.getName();
|
||||
}
|
||||
return CommandManager.CONSOLE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UUID getUuid(CommandSender sender) {
|
||||
if (sender instanceof Player) {
|
||||
return ((Player) sender).getUniqueId();
|
||||
}
|
||||
return CommandManager.CONSOLE_UUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, String s) {
|
||||
// we can safely send async for players and the console
|
||||
if (sender instanceof Player || sender instanceof ConsoleCommandSender) {
|
||||
sender.sendMessage(s);
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise, send the message sync
|
||||
getPlugin().getScheduler().doSync(new SyncMessengerAgent(sender, s));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, Component message) {
|
||||
// Fallback to legacy format
|
||||
sendMessage(sender, TextUtils.toLegacy(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Tristate getPermissionValue(CommandSender sender, String node) {
|
||||
boolean isSet = sender.isPermissionSet(node);
|
||||
boolean val = sender.hasPermission(node);
|
||||
|
||||
return !isSet ? val ? Tristate.TRUE : Tristate.UNDEFINED : Tristate.fromBoolean(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasPermission(CommandSender sender, String node) {
|
||||
return sender.hasPermission(node);
|
||||
}
|
||||
|
||||
private static final class SyncMessengerAgent implements Runnable {
|
||||
private final CommandSender sender;
|
||||
private final String message;
|
||||
|
||||
private SyncMessengerAgent(CommandSender sender, String message) {
|
||||
this.sender = sender;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.sender.sendMessage(this.message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.nukkit.calculators;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.processors.MapProcessor;
|
||||
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
||||
import me.lucko.luckperms.common.processors.RegexProcessor;
|
||||
import me.lucko.luckperms.common.processors.WildcardProcessor;
|
||||
import me.lucko.luckperms.common.references.HolderType;
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
import me.lucko.luckperms.nukkit.processors.ChildProcessor;
|
||||
import me.lucko.luckperms.nukkit.processors.DefaultsProcessor;
|
||||
|
||||
public class NukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
private final LPNukkitPlugin plugin;
|
||||
|
||||
public NukkitCalculatorFactory(LPNukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionCalculator build(Contexts contexts, PermissionCalculatorMetadata metadata) {
|
||||
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
|
||||
|
||||
processors.add(new MapProcessor());
|
||||
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_NUKKIT_CHILD_PERMISSIONS)) {
|
||||
processors.add(new ChildProcessor(this.plugin));
|
||||
}
|
||||
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) {
|
||||
processors.add(new RegexProcessor());
|
||||
}
|
||||
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_WILDCARDS)) {
|
||||
processors.add(new WildcardProcessor());
|
||||
}
|
||||
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_NUKKIT_DEFAULT_PERMISSIONS) && metadata.getHolderType() == HolderType.USER) {
|
||||
processors.add(new DefaultsProcessor(this.plugin, contexts.isOp()));
|
||||
}
|
||||
|
||||
return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build()));
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.nukkit.contexts;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.contexts.AbstractContextManager;
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
|
||||
import cn.nukkit.Player;
|
||||
|
||||
public class NukkitContextManager extends AbstractContextManager<Player> {
|
||||
public NukkitContextManager(LPNukkitPlugin plugin) {
|
||||
super(plugin, Player.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Contexts formContexts(Player subject, ImmutableContextSet contextSet) {
|
||||
return new Contexts(
|
||||
contextSet,
|
||||
this.plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
|
||||
this.plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
|
||||
true,
|
||||
this.plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
|
||||
this.plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
|
||||
subject.isOp()
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.nukkit.contexts;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.context.ContextCalculator;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import cn.nukkit.Player;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class WorldCalculator implements ContextCalculator<Player> {
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
public WorldCalculator(LuckPermsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public MutableContextSet giveApplicableContext(@Nonnull Player subject, @Nonnull MutableContextSet accumulator) {
|
||||
String world = subject.getLevel().getName().toLowerCase();
|
||||
while (!accumulator.has(Contexts.WORLD_KEY, world)) {
|
||||
accumulator.add(Contexts.WORLD_KEY, world);
|
||||
world = this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(world, world).toLowerCase();
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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.nukkit.listeners;
|
||||
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.utils.AbstractLoginListener;
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
import me.lucko.luckperms.nukkit.model.permissible.LPPermissible;
|
||||
import me.lucko.luckperms.nukkit.model.permissible.PermissibleInjector;
|
||||
|
||||
import cn.nukkit.Player;
|
||||
import cn.nukkit.event.EventHandler;
|
||||
import cn.nukkit.event.EventPriority;
|
||||
import cn.nukkit.event.Listener;
|
||||
import cn.nukkit.event.player.PlayerAsyncPreLoginEvent;
|
||||
import cn.nukkit.event.player.PlayerLoginEvent;
|
||||
import cn.nukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class NukkitConnectionListener extends AbstractLoginListener implements Listener {
|
||||
private final LPNukkitPlugin plugin;
|
||||
|
||||
private final Set<UUID> deniedAsyncLogin = Collections.synchronizedSet(new HashSet<>());
|
||||
private final Set<UUID> deniedLogin = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
public NukkitConnectionListener(LPNukkitPlugin plugin) {
|
||||
super(plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onPlayerPreLogin(PlayerAsyncPreLoginEvent e) {
|
||||
/* Called when the player first attempts a connection with the server.
|
||||
Listening on LOW priority to allow plugins to modify username / UUID data here. (auth plugins) */
|
||||
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
|
||||
this.plugin.getLog().info("Processing pre-login for " + e.getUuid() + " - " + e.getName());
|
||||
}
|
||||
|
||||
this.plugin.getUniqueConnections().add(e.getUuid());
|
||||
|
||||
/* Actually process the login for the connection.
|
||||
We do this here to delay the login until the data is ready.
|
||||
If the login gets cancelled later on, then this will be cleaned up.
|
||||
|
||||
This includes:
|
||||
- loading uuid data
|
||||
- loading permissions
|
||||
- creating a user instance in the UserManager for this connection.
|
||||
- setting up cached data. */
|
||||
try {
|
||||
User user = loadUser(e.getUuid(), e.getName());
|
||||
this.plugin.getEventFactory().handleUserLoginProcess(e.getUuid(), e.getName(), user);
|
||||
} catch (Exception ex) {
|
||||
this.plugin.getLog().severe("Exception occurred whilst loading data for " + e.getUuid() + " - " + e.getName());
|
||||
ex.printStackTrace();
|
||||
|
||||
// deny the connection
|
||||
this.deniedAsyncLogin.add(e.getUuid());
|
||||
e.disAllow(Message.LOADING_ERROR.asString(this.plugin.getLocaleManager()));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerPreLoginMonitor(PlayerAsyncPreLoginEvent 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.getUuid())) {
|
||||
// their data was never loaded at LOW priority, now check to see if they have been magically allowed since then.
|
||||
|
||||
// This is a problem, as they were denied at low priority, but are now being allowed.
|
||||
if (e.getLoginResult() == PlayerAsyncPreLoginEvent.LoginResult.SUCCESS) {
|
||||
this.plugin.getLog().severe("Player connection was re-allowed for " + e.getUuid());
|
||||
e.disAllow("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerLogin(PlayerLoginEvent e) {
|
||||
/* Called when the player starts logging into the server.
|
||||
At this point, the users data should be present and loaded. */
|
||||
|
||||
final Player player = e.getPlayer();
|
||||
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
|
||||
this.plugin.getLog().info("Processing login for " + player.getUniqueId() + " - " + player.getName());
|
||||
}
|
||||
|
||||
final User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId());
|
||||
|
||||
/* User instance is null for whatever reason. Could be that it was unloaded between asyncpre and now. */
|
||||
if (user == null) {
|
||||
this.deniedLogin.add(e.getPlayer().getUniqueId());
|
||||
|
||||
this.plugin.getLog().warn("User " + player.getUniqueId() + " - " + player.getName() + " doesn't have data pre-loaded. - denying login.");
|
||||
e.setCancelled();
|
||||
e.setKickMessage(Message.LOADING_ERROR.asString(this.plugin.getLocaleManager()));
|
||||
return;
|
||||
}
|
||||
|
||||
// User instance is there, now we can inject our custom Permissible into the player.
|
||||
// Care should be taken at this stage to ensure that async tasks which manipulate nukkit data check that the player is still online.
|
||||
try {
|
||||
// Make a new permissible for the user
|
||||
LPPermissible lpPermissible = new LPPermissible(player, user, this.plugin);
|
||||
|
||||
// Inject into the player
|
||||
PermissibleInjector.inject(player, lpPermissible);
|
||||
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
this.plugin.refreshAutoOp(user, player);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerLoginMonitor(PlayerLoginEvent 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.
|
||||
boolean denied = false;
|
||||
if (this.deniedLogin.remove(e.getPlayer().getUniqueId())) {
|
||||
denied = true;
|
||||
|
||||
// This is a problem, as they were denied at low priority, but are now being allowed.
|
||||
if (!e.isCancelled()) {
|
||||
this.plugin.getLog().severe("Player connection was re-allowed for " + e.getPlayer().getUniqueId());
|
||||
e.setCancelled();
|
||||
}
|
||||
}
|
||||
|
||||
// Login event was cancelled by another plugin since we first loaded their data
|
||||
if (denied || e.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// everything is going well. login was processed ok, this is just to refresh auto-op status.
|
||||
this.plugin.refreshAutoOp(this.plugin.getUserManager().getIfLoaded(e.getPlayer().getUniqueId()), e.getPlayer());
|
||||
}
|
||||
|
||||
// Wait until the last priority to unload, so plugins can still perform permission checks on this event
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(PlayerQuitEvent e) {
|
||||
final Player player = e.getPlayer();
|
||||
|
||||
// Remove the custom permissible
|
||||
try {
|
||||
PermissibleInjector.unInject(player, true);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
// Handle auto op
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
player.setOp(false);
|
||||
}
|
||||
|
||||
// Register with the housekeeper, so the User's instance will stick
|
||||
// around for a bit after they disconnect
|
||||
this.plugin.getUserManager().getHouseKeeper().registerUsage(player.getUniqueId());
|
||||
|
||||
// force a clear of transient nodes
|
||||
this.plugin.getScheduler().doAsync(() -> {
|
||||
User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId());
|
||||
if (user != null) {
|
||||
user.clearTransientNodes();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.nukkit.listeners;
|
||||
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
|
||||
import cn.nukkit.Player;
|
||||
import cn.nukkit.command.CommandSender;
|
||||
import cn.nukkit.event.Cancellable;
|
||||
import cn.nukkit.event.EventHandler;
|
||||
import cn.nukkit.event.EventPriority;
|
||||
import cn.nukkit.event.Listener;
|
||||
import cn.nukkit.event.entity.EntityLevelChangeEvent;
|
||||
import cn.nukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import cn.nukkit.event.server.RemoteServerCommandEvent;
|
||||
import cn.nukkit.event.server.ServerCommandEvent;
|
||||
|
||||
public class NukkitPlatformListener implements Listener {
|
||||
private final LPNukkitPlugin plugin;
|
||||
|
||||
public NukkitPlatformListener(LPNukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerCommand(PlayerCommandPreprocessEvent e) {
|
||||
handleCommand(e.getPlayer(), e.getMessage().toLowerCase(), e);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerCommand(ServerCommandEvent e) {
|
||||
handleCommand(e.getSender(), e.getCommand().toLowerCase(), e);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onRemoteServerCommand(RemoteServerCommandEvent e) {
|
||||
handleCommand(e.getSender(), e.getCommand().toLowerCase(), e);
|
||||
}
|
||||
|
||||
private void handleCommand(CommandSender sender, String s, Cancellable event) {
|
||||
if (s.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.OPS_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s.charAt(0) == '/') {
|
||||
s = s.substring(1);
|
||||
}
|
||||
|
||||
if (s.startsWith("minecraft:")) {
|
||||
s = s.substring("minecraft:".length());
|
||||
}
|
||||
|
||||
if (s.equals("op") || s.startsWith("op ") || s.equals("deop") || s.startsWith("deop ")) {
|
||||
event.setCancelled(true);
|
||||
sender.sendMessage(Message.OP_DISABLED.asString(this.plugin.getLocaleManager()));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onWorldChange(EntityLevelChangeEvent e) {
|
||||
if (e.getEntity() instanceof Player) {
|
||||
Player player = (Player) e.getEntity();
|
||||
this.plugin.getContextManager().invalidateCache(player);
|
||||
this.plugin.refreshAutoOp(this.plugin.getUserManager().getIfLoaded(player.getUniqueId()), player);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.nukkit.model;
|
||||
|
||||
import cn.nukkit.permission.Permission;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the possible default values for permissions
|
||||
*/
|
||||
public enum PermissionDefault {
|
||||
TRUE("true") {
|
||||
@Override
|
||||
public boolean getValue(boolean op) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
FALSE("false") {
|
||||
@Override
|
||||
public boolean getValue(boolean op) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
OP("op", "isop", "operator", "isoperator", "admin", "isadmin") {
|
||||
@Override
|
||||
public boolean getValue(boolean op) {
|
||||
return op;
|
||||
}
|
||||
},
|
||||
NOT_OP("!op", "notop", "!operator", "notoperator", "!admin", "notadmin") {
|
||||
@Override
|
||||
public boolean getValue(boolean op) {
|
||||
return !op;
|
||||
}
|
||||
};
|
||||
|
||||
private final String[] names;
|
||||
private static final Map<String, PermissionDefault> LOOKUP = new HashMap<>();
|
||||
|
||||
PermissionDefault(String... names) {
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the value of this PermissionDefault for the given operator
|
||||
* value
|
||||
*
|
||||
* @param op If the target is op
|
||||
* @return True if the default should be true, or false
|
||||
*/
|
||||
public abstract boolean getValue(boolean op);
|
||||
|
||||
/**
|
||||
* Looks up a PermissionDefault by name
|
||||
*
|
||||
* @param name Name of the default
|
||||
* @return Specified value, or null if not found
|
||||
*/
|
||||
@Nullable
|
||||
public static PermissionDefault getByName(String name) {
|
||||
return LOOKUP.get(name.toLowerCase().replaceAll("[^a-z!]", ""));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PermissionDefault fromPermission(@Nullable Permission permission) {
|
||||
if (permission == null) {
|
||||
return null;
|
||||
}
|
||||
return getByName(permission.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.names[0];
|
||||
}
|
||||
|
||||
static {
|
||||
for (PermissionDefault value : values()) {
|
||||
for (String name : value.names) {
|
||||
LOOKUP.put(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.nukkit.model.dummy;
|
||||
|
||||
import cn.nukkit.permission.PermissibleBase;
|
||||
import cn.nukkit.permission.Permission;
|
||||
import cn.nukkit.permission.PermissionAttachment;
|
||||
import cn.nukkit.permission.PermissionAttachmentInfo;
|
||||
import cn.nukkit.plugin.Plugin;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public class DummyPermissibleBase extends PermissibleBase {
|
||||
private static final Field ATTACHMENTS_FIELD;
|
||||
private static final Field PERMISSIONS_FIELD;
|
||||
|
||||
static {
|
||||
try {
|
||||
ATTACHMENTS_FIELD = PermissibleBase.class.getDeclaredField("attachments");
|
||||
ATTACHMENTS_FIELD.setAccessible(true);
|
||||
|
||||
PERMISSIONS_FIELD = PermissibleBase.class.getDeclaredField("permissions");
|
||||
PERMISSIONS_FIELD.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void nullFields(PermissibleBase permissibleBase) {
|
||||
try {
|
||||
ATTACHMENTS_FIELD.set(permissibleBase, null);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
try {
|
||||
PERMISSIONS_FIELD.set(permissibleBase, null);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
public static final DummyPermissibleBase INSTANCE = new DummyPermissibleBase();
|
||||
|
||||
private DummyPermissibleBase() {
|
||||
super(null);
|
||||
nullFields(this);
|
||||
}
|
||||
|
||||
@Override public boolean isOp() { return false; }
|
||||
@Override public void setOp(boolean value) {}
|
||||
@Override public boolean isPermissionSet(String name) { return false; }
|
||||
@Override public boolean isPermissionSet(Permission perm) { return false; }
|
||||
@Override public boolean hasPermission(String inName) { return false; }
|
||||
@Override public boolean hasPermission(Permission perm) { return false; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name, Boolean value) { return null; }
|
||||
@Override public void removeAttachment(PermissionAttachment attachment) {}
|
||||
@Override public void recalculatePermissions() {}
|
||||
@Override public void clearPermissions() {}
|
||||
@Override public Map<String, PermissionAttachmentInfo> getEffectivePermissions() { return Collections.emptyMap(); }
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.nukkit.model.dummy;
|
||||
import cn.nukkit.Server;
|
||||
import cn.nukkit.command.Command;
|
||||
import cn.nukkit.command.CommandSender;
|
||||
import cn.nukkit.plugin.Plugin;
|
||||
import cn.nukkit.plugin.PluginDescription;
|
||||
import cn.nukkit.plugin.PluginLoader;
|
||||
import cn.nukkit.plugin.PluginLogger;
|
||||
import cn.nukkit.utils.Config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Dummy plugin instance
|
||||
*/
|
||||
public class DummyPlugin implements Plugin {
|
||||
public static final DummyPlugin INSTANCE = new DummyPlugin();
|
||||
|
||||
private DummyPlugin() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public File getDataFolder() { return null; }
|
||||
@Override public PluginDescription getDescription() { return null; }
|
||||
@Override public Config getConfig() { return null; }
|
||||
@Override public InputStream getResource(String s) { return null; }
|
||||
@Override public boolean saveResource(String s) { return false; }
|
||||
@Override public void saveConfig() {}
|
||||
@Override public void saveDefaultConfig() {}
|
||||
@Override public boolean saveResource(String s, boolean b) { return false; }
|
||||
@Override public boolean saveResource(String s, String s1, boolean b) { return false; }
|
||||
@Override public void reloadConfig() {}
|
||||
@Override public PluginLoader getPluginLoader() { return null; }
|
||||
@Override public Server getServer() { return null; }
|
||||
@Override public void onDisable() {}
|
||||
@Override public void onLoad() {}
|
||||
@Override public void onEnable() {}
|
||||
@Override public PluginLogger getLogger() { return null; }
|
||||
@Override public String getName() { return null; }
|
||||
@Override public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) { return false; }
|
||||
|
||||
}
|
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* 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.nukkit.model.permissible;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
import me.lucko.luckperms.nukkit.model.PermissionDefault;
|
||||
|
||||
import cn.nukkit.Player;
|
||||
import cn.nukkit.permission.PermissibleBase;
|
||||
import cn.nukkit.permission.Permission;
|
||||
import cn.nukkit.permission.PermissionAttachment;
|
||||
import cn.nukkit.permission.PermissionAttachmentInfo;
|
||||
import cn.nukkit.plugin.Plugin;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* PermissibleBase for LuckPerms.
|
||||
*
|
||||
* This class overrides all methods defined in PermissibleBase, and provides custom handling
|
||||
* from LuckPerms.
|
||||
*
|
||||
* This means that all permission checks made for a player are handled directly by the plugin.
|
||||
* Method behaviour is retained, but alternate implementation is used.
|
||||
*
|
||||
* "Hot" method calls, (namely #hasPermission) are significantly faster than the base implementation.
|
||||
*
|
||||
* This class is **thread safe**. This means that when LuckPerms is installed on the server,
|
||||
* is is safe to call Player#hasPermission asynchronously.
|
||||
*/
|
||||
public class LPPermissible extends PermissibleBase {
|
||||
|
||||
// the LuckPerms user this permissible references.
|
||||
private final User user;
|
||||
|
||||
// the player this permissible is injected into.
|
||||
private final Player player;
|
||||
|
||||
// the luckperms plugin instance
|
||||
private final LPNukkitPlugin plugin;
|
||||
|
||||
// the players previous permissible. (the one they had before this one was injected)
|
||||
private PermissibleBase oldPermissible = null;
|
||||
|
||||
// if the permissible is currently active.
|
||||
private final AtomicBoolean active = new AtomicBoolean(false);
|
||||
|
||||
// the attachments hooked onto the permissible.
|
||||
// this collection is only modified by the attachments themselves
|
||||
final Set<LPPermissionAttachment> attachments = ConcurrentHashMap.newKeySet();
|
||||
|
||||
public LPPermissible(Player player, User user, LPNukkitPlugin plugin) {
|
||||
super(player);
|
||||
this.user = Objects.requireNonNull(user, "user");
|
||||
this.player = Objects.requireNonNull(player, "player");
|
||||
this.plugin = Objects.requireNonNull(plugin, "plugin");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(String permission) {
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
Tristate ts = this.user.getCachedData().getPermissionData(calculateContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||
return ts != Tristate.UNDEFINED || PermissionDefault.OP.getValue(isOp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(Permission permission) {
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
Tristate ts = this.user.getCachedData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this.plugin.getConfiguration().get(ConfigKeys.APPLY_NUKKIT_DEFAULT_PERMISSIONS)) {
|
||||
return PermissionDefault.OP.getValue(isOp());
|
||||
} else {
|
||||
PermissionDefault def = PermissionDefault.fromPermission(permission);
|
||||
return def != null && def.getValue(isOp());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
Tristate ts = this.user.getCachedData().getPermissionData(calculateContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
||||
return ts != Tristate.UNDEFINED ? ts.asBoolean() : PermissionDefault.OP.getValue(isOp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Permission permission) {
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
Tristate ts = this.user.getCachedData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
return ts.asBoolean();
|
||||
}
|
||||
|
||||
if (!this.plugin.getConfiguration().get(ConfigKeys.APPLY_NUKKIT_DEFAULT_PERMISSIONS)) {
|
||||
return PermissionDefault.OP.getValue(isOp());
|
||||
} else {
|
||||
PermissionDefault def = PermissionDefault.fromPermission(permission);
|
||||
return def != null && def.getValue(isOp());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds attachments to this permissible.
|
||||
*
|
||||
* @param attachments the attachments to add
|
||||
*/
|
||||
public void convertAndAddAttachments(Collection<PermissionAttachment> attachments) {
|
||||
for (PermissionAttachment attachment : attachments) {
|
||||
new LPPermissionAttachment(this, attachment).hook();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@link Contexts} instance for the player.
|
||||
* Values are determined using the plugins ContextManager.
|
||||
*
|
||||
* @return the calculated contexts for the player.
|
||||
*/
|
||||
private Contexts calculateContexts() {
|
||||
return this.plugin.getContextManager().getApplicableContexts(this.player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOp(boolean value) {
|
||||
this.player.setOp(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, PermissionAttachmentInfo> getEffectivePermissions() {
|
||||
Set<Map.Entry<String, Boolean>> permissions = this.user.getCachedData().getPermissionData(calculateContexts()).getImmutableBacking().entrySet();
|
||||
Map<String, PermissionAttachmentInfo> ret = new HashMap<>(permissions.size());
|
||||
|
||||
for (Map.Entry<String, Boolean> entry : permissions) {
|
||||
ret.put(entry.getKey(), new PermissionAttachmentInfo(this.player, entry.getKey(), null, entry.getValue()));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LPPermissionAttachment addAttachment(Plugin plugin) {
|
||||
if (plugin == null) {
|
||||
throw new NullPointerException("plugin");
|
||||
}
|
||||
|
||||
LPPermissionAttachment ret = new LPPermissionAttachment(this, plugin);
|
||||
ret.hook();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String permission) {
|
||||
if (plugin == null) {
|
||||
throw new NullPointerException("plugin");
|
||||
}
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
PermissionAttachment ret = addAttachment(plugin);
|
||||
ret.setPermission(permission, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String permission, Boolean value) {
|
||||
if (plugin == null) {
|
||||
throw new NullPointerException("plugin");
|
||||
}
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
PermissionAttachment ret = addAttachment(plugin);
|
||||
ret.setPermission(permission, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttachment(PermissionAttachment attachment) {
|
||||
if (attachment == null) {
|
||||
throw new NullPointerException("attachment");
|
||||
}
|
||||
|
||||
if (!(attachment instanceof LPPermissionAttachment)) {
|
||||
throw new IllegalArgumentException("Given attachment is not a LPPermissionAttachment.");
|
||||
}
|
||||
|
||||
LPPermissionAttachment a = ((LPPermissionAttachment) attachment);
|
||||
if (a.getPermissible() != this) {
|
||||
throw new IllegalArgumentException("Attachment does not belong to this permissible.");
|
||||
}
|
||||
|
||||
a.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recalculatePermissions() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearPermissions() {
|
||||
this.attachments.forEach(LPPermissionAttachment::remove);
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return this.user;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
public LPNukkitPlugin getPlugin() {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
public PermissibleBase getOldPermissible() {
|
||||
return this.oldPermissible;
|
||||
}
|
||||
|
||||
public AtomicBoolean getActive() {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
public void setOldPermissible(PermissibleBase oldPermissible) {
|
||||
this.oldPermissible = oldPermissible;
|
||||
}
|
||||
}
|
@ -0,0 +1,432 @@
|
||||
/*
|
||||
* 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.nukkit.model.permissible;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.node.ImmutableTransientNode;
|
||||
import me.lucko.luckperms.common.node.NodeFactory;
|
||||
import me.lucko.luckperms.nukkit.model.dummy.DummyPlugin;
|
||||
|
||||
import cn.nukkit.permission.Permission;
|
||||
import cn.nukkit.permission.PermissionAttachment;
|
||||
import cn.nukkit.permission.PermissionRemovedExecutor;
|
||||
import cn.nukkit.plugin.Plugin;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* PermissionAttachment for LuckPerms.
|
||||
*
|
||||
* Applies all permissions directly to the backing user instance via transient nodes.
|
||||
*/
|
||||
public class LPPermissionAttachment extends PermissionAttachment {
|
||||
|
||||
/**
|
||||
* The field in PermissionAttachment where the attachments applied permissions
|
||||
* are *usually* held.
|
||||
*/
|
||||
private static final Field PERMISSION_ATTACHMENT_PERMISSIONS_FIELD;
|
||||
|
||||
static {
|
||||
try {
|
||||
PERMISSION_ATTACHMENT_PERMISSIONS_FIELD = PermissionAttachment.class.getDeclaredField("permissions");
|
||||
PERMISSION_ATTACHMENT_PERMISSIONS_FIELD.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The parent LPPermissible
|
||||
*/
|
||||
private final LPPermissible permissible;
|
||||
|
||||
/**
|
||||
* The plugin which "owns" this attachment, may be null
|
||||
*/
|
||||
private final Plugin owner;
|
||||
|
||||
/**
|
||||
* The permissions being applied by this attachment
|
||||
*/
|
||||
private final Map<String, Boolean> perms = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
/**
|
||||
* If the attachment has been applied to the user
|
||||
*/
|
||||
private boolean hooked = false;
|
||||
|
||||
/**
|
||||
* Callback to run when the attachment is removed
|
||||
*/
|
||||
private PermissionRemovedExecutor removalCallback = null;
|
||||
|
||||
public LPPermissionAttachment(LPPermissible permissible, Plugin owner) {
|
||||
super(DummyPlugin.INSTANCE, null);
|
||||
this.permissible = permissible;
|
||||
this.owner = owner;
|
||||
|
||||
injectFakeMap();
|
||||
}
|
||||
|
||||
public LPPermissionAttachment(LPPermissible permissible, PermissionAttachment nukkit) {
|
||||
super(DummyPlugin.INSTANCE, null);
|
||||
this.permissible = permissible;
|
||||
this.owner = null;
|
||||
|
||||
// copy
|
||||
this.perms.putAll(nukkit.getPermissions());
|
||||
|
||||
injectFakeMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects a fake 'permissions' map into the superclass, for (clever/dumb??) plugins
|
||||
* which attempt to modify attachment permissions using reflection to get around the slow nukkit
|
||||
* behaviour in the base PermissionAttachment implementation.
|
||||
*
|
||||
* The fake map proxies calls back to the methods on this attachment
|
||||
*/
|
||||
private void injectFakeMap() {
|
||||
// inner class - this proxies calls back to us
|
||||
FakeBackingMap fakeMap = new FakeBackingMap();
|
||||
|
||||
try {
|
||||
// the field we need to modify is in the superclass - it has private
|
||||
// and final modifiers so we have to use reflection to modify it.
|
||||
PERMISSION_ATTACHMENT_PERMISSIONS_FIELD.set(this, fakeMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public LPPermissible getPermissible() {
|
||||
return this.permissible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionRemovedExecutor getRemovalCallback() {
|
||||
return this.removalCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemovalCallback(PermissionRemovedExecutor removalCallback) {
|
||||
this.removalCallback = removalCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks this attachment with the parent {@link User} instance.
|
||||
*/
|
||||
public void hook() {
|
||||
this.hooked = true;
|
||||
this.permissible.attachments.add(this);
|
||||
for (Map.Entry<String, Boolean> entry : this.perms.entrySet()) {
|
||||
if (entry.getKey() == null || entry.getKey().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
setPermissionInternal(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void setPermissionInternal(String name, boolean value) {
|
||||
if (!this.permissible.getPlugin().getConfiguration().get(ConfigKeys.APPLY_NUKKIT_ATTACHMENT_PERMISSIONS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// construct a node for the permission being set
|
||||
// we use the servers static context to *try* to ensure that the node will apply
|
||||
Node node = NodeFactory.builder(name)
|
||||
.setValue(value)
|
||||
.withExtraContext(this.permissible.getPlugin().getContextManager().getStaticContext())
|
||||
.build();
|
||||
|
||||
// convert the constructed node to a transient node instance to refer back to this attachment
|
||||
ImmutableTransientNode<LPPermissionAttachment> transientNode = ImmutableTransientNode.of(node, this);
|
||||
|
||||
// set the transient node
|
||||
User user = this.permissible.getUser();
|
||||
if (user.setTransientPermission(transientNode).asBoolean()) {
|
||||
user.reloadCachedData();
|
||||
}
|
||||
}
|
||||
|
||||
private void unsetPermissionInternal(String name) {
|
||||
if (!this.permissible.getPlugin().getConfiguration().get(ConfigKeys.APPLY_NUKKIT_ATTACHMENT_PERMISSIONS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove transient permissions from the holder which were added by this attachment & equal the permission
|
||||
User user = this.permissible.getUser();
|
||||
if (user.removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name))) {
|
||||
user.reloadCachedData();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearInternal() {
|
||||
// remove all transient permissions added by this attachment
|
||||
User user = this.permissible.getUser();
|
||||
if (user.removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this)) {
|
||||
user.reloadCachedData();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (!this.hooked) {
|
||||
return;
|
||||
}
|
||||
|
||||
// clear the internal permissions
|
||||
clearInternal();
|
||||
|
||||
// run the callback
|
||||
if (this.removalCallback != null) {
|
||||
this.removalCallback.attachmentRemoved(this);
|
||||
}
|
||||
|
||||
// unhook from the permissible
|
||||
this.hooked = false;
|
||||
this.permissible.attachments.remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(String name, boolean value) {
|
||||
Objects.requireNonNull(name, "name is null");
|
||||
Preconditions.checkArgument(!name.isEmpty(), "name is empty");
|
||||
|
||||
String permission = name.toLowerCase();
|
||||
|
||||
Boolean previous = this.perms.put(permission, value);
|
||||
if (previous != null && previous == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if we're not hooked, then don't actually apply the change
|
||||
// it will get applied on hook - if that ever happens
|
||||
if (!this.hooked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (previous != null) {
|
||||
unsetPermissionInternal(permission);
|
||||
}
|
||||
|
||||
setPermissionInternal(permission, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(Permission permission, boolean value) {
|
||||
setPermission(permission.getName(), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermissions(Map<String, Boolean> permissions) {
|
||||
for (Map.Entry<String, Boolean> entry : permissions.entrySet()) {
|
||||
setPermission(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermission(String name, boolean value) {
|
||||
Objects.requireNonNull(name, "name is null");
|
||||
Preconditions.checkArgument(!name.isEmpty(), "name is empty");
|
||||
|
||||
String permission = name.toLowerCase();
|
||||
|
||||
Boolean previous = this.perms.remove(permission);
|
||||
if (previous == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if we're not hooked, then don't actually apply the change
|
||||
// it will get applied on hook - if that ever happens
|
||||
if (!this.hooked) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsetPermissionInternal(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermission(Permission permission, boolean value) {
|
||||
unsetPermission(permission.getName(), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermissions(List<String> permissions) {
|
||||
for (String perm : permissions) {
|
||||
unsetPermission(perm, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearPermissions() {
|
||||
this.perms.clear();
|
||||
clearInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> getPermissions() {
|
||||
return this.perms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plugin getPlugin() {
|
||||
return this.owner != null ? this.owner : this.permissible.getPlugin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A fake map to be injected into the superclass. This implementation simply
|
||||
* proxies calls back to this attachment instance.
|
||||
*
|
||||
* Some (clever/dumb??) plugins attempt to modify attachment permissions using reflection
|
||||
* to get around the slow nukkit behaviour in the base PermissionAttachment implementation.
|
||||
*
|
||||
* An instance of this map is injected into the super instance so these plugins continue
|
||||
* to work with LuckPerms.
|
||||
*/
|
||||
private final class FakeBackingMap implements Map<String, Boolean> {
|
||||
|
||||
@Override
|
||||
public Boolean put(String key, Boolean value) {
|
||||
// grab the previous result, so we can still satisfy the method signature of Map
|
||||
Boolean previous = LPPermissionAttachment.this.perms.get(key);
|
||||
|
||||
// proxy the call back through the PermissionAttachment instance
|
||||
setPermission(key, value);
|
||||
|
||||
// return the previous value
|
||||
return previous;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean remove(Object key) {
|
||||
// we only accept string keys
|
||||
if (!(key instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String permission = ((String) key);
|
||||
|
||||
// grab the previous result, so we can still satisfy the method signature of Map
|
||||
Boolean previous = LPPermissionAttachment.this.perms.get(permission);
|
||||
|
||||
// proxy the call back through the PermissionAttachment instance
|
||||
unsetPermission(permission, true);
|
||||
|
||||
// return the previous value
|
||||
return previous;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends Boolean> m) {
|
||||
for (Map.Entry<? extends String, ? extends Boolean> entry : m.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
// remove the permissions which have already been applied
|
||||
if (LPPermissionAttachment.this.hooked) {
|
||||
clearInternal();
|
||||
}
|
||||
|
||||
// clear the backing map
|
||||
LPPermissionAttachment.this.perms.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
// return the size of the permissions map - probably the most accurate value we have
|
||||
return LPPermissionAttachment.this.perms.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
// return if the permissions map is empty - again probably the most accurate thing
|
||||
// we can return
|
||||
return LPPermissionAttachment.this.perms.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
// just proxy
|
||||
return LPPermissionAttachment.this.perms.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
// just proxy
|
||||
return LPPermissionAttachment.this.perms.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean get(Object key) {
|
||||
// just proxy
|
||||
return LPPermissionAttachment.this.perms.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
// just proxy
|
||||
return LPPermissionAttachment.this.perms.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Boolean> values() {
|
||||
// just proxy
|
||||
return LPPermissionAttachment.this.perms.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, Boolean>> entrySet() {
|
||||
// just proxy
|
||||
return LPPermissionAttachment.this.perms.entrySet();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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.nukkit.model.permissible;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||
import me.lucko.luckperms.common.verbose.VerboseHandler;
|
||||
import me.lucko.luckperms.nukkit.model.dummy.DummyPermissibleBase;
|
||||
|
||||
import cn.nukkit.permission.PermissibleBase;
|
||||
import cn.nukkit.permission.Permission;
|
||||
import cn.nukkit.permission.PermissionAttachment;
|
||||
import cn.nukkit.permission.PermissionAttachmentInfo;
|
||||
import cn.nukkit.plugin.Plugin;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A PermissibleBase extension which logs permission checks to the
|
||||
* plugin's {@link VerboseHandler} facility.
|
||||
*
|
||||
* Method calls are forwarded to the delegate permissible.
|
||||
*/
|
||||
public class MonitoredPermissibleBase extends PermissibleBase {
|
||||
private final LuckPermsPlugin plugin;
|
||||
private final PermissibleBase delegate;
|
||||
private final String name;
|
||||
|
||||
// remains false until the object has been constructed
|
||||
// necessary to catch the superclass call to #recalculatePermissions on init
|
||||
@SuppressWarnings("UnusedAssignment")
|
||||
private boolean initialised = false;
|
||||
|
||||
public MonitoredPermissibleBase(LuckPermsPlugin plugin, PermissibleBase delegate, String name) {
|
||||
super(null);
|
||||
DummyPermissibleBase.nullFields(this);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.delegate = delegate;
|
||||
this.name = name;
|
||||
this.initialised = true;
|
||||
|
||||
// since we effectively cancel the execution of this call in the super
|
||||
// constructor we need to call it again.
|
||||
recalculatePermissions();
|
||||
}
|
||||
|
||||
private void logCheck(CheckOrigin origin, String permission, boolean result) {
|
||||
this.plugin.getVerboseHandler().offerCheckData(origin, this.name, ContextSet.empty(), permission, Tristate.fromBoolean(result));
|
||||
this.plugin.getPermissionVault().offer(permission);
|
||||
}
|
||||
|
||||
PermissibleBase getDelegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(String permission) {
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
final boolean result = this.delegate.isPermissionSet(permission);
|
||||
logCheck(CheckOrigin.PLATFORM_LOOKUP_CHECK, permission, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(Permission permission) {
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
final boolean result = this.delegate.isPermissionSet(permission);
|
||||
logCheck(CheckOrigin.PLATFORM_LOOKUP_CHECK, permission.getName(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
final boolean result = this.delegate.hasPermission(permission);
|
||||
logCheck(CheckOrigin.PLATFORM_PERMISSION_CHECK, permission, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Permission permission) {
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
final boolean result = this.delegate.hasPermission(permission);
|
||||
logCheck(CheckOrigin.PLATFORM_PERMISSION_CHECK, permission.getName(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recalculatePermissions() {
|
||||
if (!this.initialised) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.delegate.recalculatePermissions();
|
||||
}
|
||||
|
||||
// just forward calls to the delegate permissible
|
||||
@Override public boolean isOp() { return this.delegate.isOp(); }
|
||||
@Override public void setOp(boolean value) { this.delegate.setOp(value); }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name, Boolean value) { return this.delegate.addAttachment(plugin, name, value); }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name) { return this.delegate.addAttachment(plugin, name); }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin) { return this.delegate.addAttachment(plugin); }
|
||||
@Override public void removeAttachment(PermissionAttachment attachment) { this.delegate.removeAttachment(attachment); }
|
||||
@Override public void clearPermissions() { this.delegate.clearPermissions(); }
|
||||
@Override public Map<String, PermissionAttachmentInfo> getEffectivePermissions() { return this.delegate.getEffectivePermissions(); }
|
||||
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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.nukkit.model.permissible;
|
||||
|
||||
import me.lucko.luckperms.nukkit.model.dummy.DummyPermissibleBase;
|
||||
|
||||
import cn.nukkit.Player;
|
||||
import cn.nukkit.permission.PermissibleBase;
|
||||
import cn.nukkit.permission.PermissionAttachment;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Injects a {@link LPPermissible} into a {@link Player}.
|
||||
*
|
||||
* This allows LuckPerms to directly intercept permission checks and take over all handling of
|
||||
* checks made by plugins.
|
||||
*/
|
||||
public final class PermissibleInjector {
|
||||
|
||||
/**
|
||||
* All permission checks made on standard Nukkit objects are effectively proxied to a
|
||||
* {@link PermissibleBase} object, held as a variable on the object.
|
||||
*
|
||||
* This field is where the permissible is stored on a Player.
|
||||
*/
|
||||
private static final Field PLAYER_PERMISSIBLE_FIELD;
|
||||
|
||||
/**
|
||||
* The field where attachments are stored on a permissible base.
|
||||
*/
|
||||
private static final Field PERMISSIBLE_BASE_ATTACHMENTS_FIELD;
|
||||
|
||||
static {
|
||||
try {
|
||||
// Try to load the permissible field.
|
||||
PLAYER_PERMISSIBLE_FIELD = Player.class.getDeclaredField("perm");
|
||||
PLAYER_PERMISSIBLE_FIELD.setAccessible(true);
|
||||
|
||||
// Try to load the attachments field.
|
||||
PERMISSIBLE_BASE_ATTACHMENTS_FIELD = PermissibleBase.class.getDeclaredField("attachments");
|
||||
PERMISSIBLE_BASE_ATTACHMENTS_FIELD.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects a {@link LPPermissible} into a {@link Player}.
|
||||
*
|
||||
* @param player the player to inject into
|
||||
* @param newPermissible the permissible to inject
|
||||
* @throws Exception propagates any exceptions which were thrown during injection
|
||||
*/
|
||||
public static void inject(Player player, LPPermissible newPermissible) throws Exception {
|
||||
|
||||
// get the existing PermissibleBase held by the player
|
||||
PermissibleBase oldPermissible = (PermissibleBase) PLAYER_PERMISSIBLE_FIELD.get(player);
|
||||
|
||||
// seems we have already injected into this player.
|
||||
if (oldPermissible instanceof LPPermissible) {
|
||||
throw new IllegalStateException("LPPermissible already injected into player " + player.toString());
|
||||
}
|
||||
|
||||
// Move attachments over from the old permissible
|
||||
|
||||
//noinspection unchecked
|
||||
Set<PermissionAttachment> attachments = (Set<PermissionAttachment>) PERMISSIBLE_BASE_ATTACHMENTS_FIELD.get(oldPermissible);
|
||||
|
||||
newPermissible.convertAndAddAttachments(attachments);
|
||||
attachments.clear();
|
||||
oldPermissible.clearPermissions();
|
||||
|
||||
// Setup the new permissible
|
||||
newPermissible.getActive().set(true);
|
||||
newPermissible.setOldPermissible(oldPermissible);
|
||||
|
||||
// inject the new instance
|
||||
PLAYER_PERMISSIBLE_FIELD.set(player, newPermissible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninjects a {@link LPPermissible} from a {@link Player}.
|
||||
*
|
||||
* @param player the player to uninject from
|
||||
* @param dummy if the replacement permissible should be a dummy.
|
||||
* @throws Exception propagates any exceptions which were thrown during uninjection
|
||||
*/
|
||||
public static void unInject(Player player, boolean dummy) throws Exception {
|
||||
|
||||
// gets the players current permissible.
|
||||
PermissibleBase permissible = (PermissibleBase) PLAYER_PERMISSIBLE_FIELD.get(player);
|
||||
|
||||
// only uninject if the permissible was a luckperms one.
|
||||
if (permissible instanceof LPPermissible) {
|
||||
LPPermissible lpPermissible = ((LPPermissible) permissible);
|
||||
|
||||
// clear all permissions
|
||||
lpPermissible.clearPermissions();
|
||||
|
||||
// set to inactive
|
||||
lpPermissible.getActive().set(false);
|
||||
|
||||
// handle the replacement permissible.
|
||||
if (dummy) {
|
||||
// just inject a dummy class. this is used when we know the player is about to quit the server.
|
||||
PLAYER_PERMISSIBLE_FIELD.set(player, DummyPermissibleBase.INSTANCE);
|
||||
|
||||
} else {
|
||||
PermissibleBase newPb = lpPermissible.getOldPermissible();
|
||||
if (newPb == null) {
|
||||
newPb = new PermissibleBase(player);
|
||||
}
|
||||
|
||||
PLAYER_PERMISSIBLE_FIELD.set(player, newPb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PermissibleInjector() {}
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.nukkit.model.permissible;
|
||||
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
|
||||
import cn.nukkit.command.ConsoleCommandSender;
|
||||
import cn.nukkit.permission.PermissibleBase;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Injects {@link MonitoredPermissibleBase}s into non-player permissibles on
|
||||
* the server so their checks can be monitored by the verbose facility.
|
||||
*/
|
||||
public class PermissibleMonitoringInjector implements Runnable {
|
||||
private final LPNukkitPlugin plugin;
|
||||
|
||||
public PermissibleMonitoringInjector(LPNukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
injectConsole();
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private MonitoredPermissibleBase wrap(PermissibleBase permBase, String name) {
|
||||
Objects.requireNonNull(permBase, "permBase");
|
||||
|
||||
// unwrap any previous injection
|
||||
if (permBase instanceof MonitoredPermissibleBase) {
|
||||
permBase = ((MonitoredPermissibleBase) permBase).getDelegate();
|
||||
}
|
||||
|
||||
// create a monitored instance which delegates to the previous PermissibleBase
|
||||
return new MonitoredPermissibleBase(this.plugin, permBase, name);
|
||||
}
|
||||
|
||||
private void injectConsole() throws Exception {
|
||||
ConsoleCommandSender consoleSender = this.plugin.getServer().getConsoleSender();
|
||||
|
||||
// get the perm field
|
||||
Field permField = ConsoleCommandSender.class.getDeclaredField("perm");
|
||||
permField.setAccessible(true);
|
||||
|
||||
// get the PermissibleBase instance
|
||||
PermissibleBase permBase = (PermissibleBase) permField.get(consoleSender);
|
||||
|
||||
// create a monitored instance which delegates to the previous PermissibleBase
|
||||
MonitoredPermissibleBase newPermBase = wrap(permBase, "internal/console");
|
||||
|
||||
// inject the monitored instance
|
||||
permField.set(consoleSender, newPermBase);
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.nukkit.model.server;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
|
||||
import cn.nukkit.Server;
|
||||
import cn.nukkit.permission.Permission;
|
||||
import cn.nukkit.plugin.PluginManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Injects a {@link LPDefaultsMap} info the {@link PluginManager}.
|
||||
*/
|
||||
public class InjectorDefaultsMap implements Runnable {
|
||||
private static final Field OP_DEFAULT_PERMISSIONS_FIELD;
|
||||
private static final Field NON_OP_DEFAULT_PERMISSIONS_FIELD;
|
||||
|
||||
static {
|
||||
Field opPermissionsField = null;
|
||||
try {
|
||||
opPermissionsField = PluginManager.class.getDeclaredField("defaultPermsOp");
|
||||
opPermissionsField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
OP_DEFAULT_PERMISSIONS_FIELD = opPermissionsField;
|
||||
|
||||
Field nonOpPermissionsField = null;
|
||||
try {
|
||||
nonOpPermissionsField = PluginManager.class.getDeclaredField("defaultPerms");
|
||||
nonOpPermissionsField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
NON_OP_DEFAULT_PERMISSIONS_FIELD = nonOpPermissionsField;
|
||||
}
|
||||
|
||||
private final LPNukkitPlugin plugin;
|
||||
|
||||
public InjectorDefaultsMap(LPNukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
LPDefaultsMap ret = inject();
|
||||
if (ret != null) {
|
||||
this.plugin.setDefaultPermissionMap(ret);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.plugin.getLog().severe("Exception occurred whilst injecting LuckPerms Default Permission map.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private LPDefaultsMap inject() throws Exception {
|
||||
Objects.requireNonNull(OP_DEFAULT_PERMISSIONS_FIELD, "OP_DEFAULT_PERMISSIONS_FIELD");
|
||||
Objects.requireNonNull(NON_OP_DEFAULT_PERMISSIONS_FIELD, "NON_OP_DEFAULT_PERMISSIONS_FIELD");
|
||||
|
||||
PluginManager pluginManager = this.plugin.getServer().getPluginManager();
|
||||
|
||||
Object opMap = OP_DEFAULT_PERMISSIONS_FIELD.get(pluginManager);
|
||||
Object nonOpMap = NON_OP_DEFAULT_PERMISSIONS_FIELD.get(pluginManager);
|
||||
|
||||
if (opMap instanceof LPDefaultsMap.DefaultPermissionSet && ((LPDefaultsMap.DefaultPermissionSet) opMap).parent.plugin == this.plugin) {
|
||||
if (nonOpMap instanceof LPDefaultsMap.DefaultPermissionSet && ((LPDefaultsMap.DefaultPermissionSet) nonOpMap).parent.plugin == this.plugin) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
Map<String, Permission> castedOpMap = (Map<String, Permission>) opMap;
|
||||
|
||||
//noinspection unchecked
|
||||
Map<String, Permission> castedNonOpMap = (Map<String, Permission>) nonOpMap;
|
||||
|
||||
// make a new map & inject it
|
||||
LPDefaultsMap newMap = new LPDefaultsMap(this.plugin, ImmutableMap.of(true, castedOpMap, false, castedNonOpMap));
|
||||
OP_DEFAULT_PERMISSIONS_FIELD.set(pluginManager, newMap.getOpPermissions());
|
||||
NON_OP_DEFAULT_PERMISSIONS_FIELD.set(pluginManager, newMap.getNonOpPermissions());
|
||||
return newMap;
|
||||
}
|
||||
|
||||
public static void uninject() {
|
||||
try {
|
||||
Objects.requireNonNull(OP_DEFAULT_PERMISSIONS_FIELD, "OP_DEFAULT_PERMISSIONS_FIELD");
|
||||
Objects.requireNonNull(NON_OP_DEFAULT_PERMISSIONS_FIELD, "NON_OP_DEFAULT_PERMISSIONS_FIELD");
|
||||
PluginManager pluginManager = Server.getInstance().getPluginManager();
|
||||
{
|
||||
Object map = OP_DEFAULT_PERMISSIONS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPDefaultsMap.DefaultPermissionSet) {
|
||||
LPDefaultsMap.DefaultPermissionSet lpMap = (LPDefaultsMap.DefaultPermissionSet) map;
|
||||
OP_DEFAULT_PERMISSIONS_FIELD.set(pluginManager, new HashMap<>(lpMap));
|
||||
}
|
||||
}
|
||||
{
|
||||
Object map = NON_OP_DEFAULT_PERMISSIONS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPDefaultsMap.DefaultPermissionSet) {
|
||||
LPDefaultsMap.DefaultPermissionSet lpMap = (LPDefaultsMap.DefaultPermissionSet) map;
|
||||
NON_OP_DEFAULT_PERMISSIONS_FIELD.set(pluginManager, new HashMap<>(lpMap));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -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.nukkit.model.server;
|
||||
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
|
||||
import cn.nukkit.Server;
|
||||
import cn.nukkit.permission.Permission;
|
||||
import cn.nukkit.plugin.PluginManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Injects a {@link LPPermissionMap} into the {@link PluginManager}.
|
||||
*/
|
||||
public class InjectorPermissionMap implements Runnable {
|
||||
private static final Field PERMISSIONS_FIELD;
|
||||
|
||||
static {
|
||||
Field permissionsField = null;
|
||||
try {
|
||||
permissionsField = PluginManager.class.getDeclaredField("permissions");
|
||||
permissionsField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
PERMISSIONS_FIELD = permissionsField;
|
||||
}
|
||||
|
||||
private final LPNukkitPlugin plugin;
|
||||
|
||||
public InjectorPermissionMap(LPNukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
LPPermissionMap ret = inject();
|
||||
if (ret != null) {
|
||||
this.plugin.setPermissionMap(ret);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.plugin.getLog().severe("Exception occurred whilst injecting LuckPerms Permission map.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private LPPermissionMap inject() throws Exception {
|
||||
Objects.requireNonNull(PERMISSIONS_FIELD, "PERMISSIONS_FIELD");
|
||||
PluginManager pluginManager = this.plugin.getServer().getPluginManager();
|
||||
|
||||
Object map = PERMISSIONS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPPermissionMap && ((LPPermissionMap) map).plugin == this.plugin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
Map<String, Permission> castedMap = (Map<String, Permission>) map;
|
||||
|
||||
// make a new map & inject it
|
||||
LPPermissionMap newMap = new LPPermissionMap(this.plugin, castedMap);
|
||||
PERMISSIONS_FIELD.set(pluginManager, newMap);
|
||||
return newMap;
|
||||
}
|
||||
|
||||
public static void uninject() {
|
||||
try {
|
||||
Objects.requireNonNull(PERMISSIONS_FIELD, "PERMISSIONS_FIELD");
|
||||
PluginManager pluginManager = Server.getInstance().getPluginManager();
|
||||
|
||||
Object map = PERMISSIONS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPPermissionMap) {
|
||||
LPPermissionMap lpMap = (LPPermissionMap) map;
|
||||
PERMISSIONS_FIELD.set(pluginManager, new HashMap<>(lpMap));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.nukkit.model.server;
|
||||
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
|
||||
import cn.nukkit.Server;
|
||||
import cn.nukkit.permission.Permissible;
|
||||
import cn.nukkit.plugin.PluginManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Injects a {@link LPSubscriptionMap} into the {@link PluginManager}.
|
||||
*/
|
||||
public class InjectorSubscriptionMap implements Runnable {
|
||||
private static final Field PERM_SUBS_FIELD;
|
||||
|
||||
static {
|
||||
Field permSubsField = null;
|
||||
try {
|
||||
permSubsField = PluginManager.class.getDeclaredField("permSubs");
|
||||
permSubsField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
PERM_SUBS_FIELD = permSubsField;
|
||||
}
|
||||
|
||||
private final LPNukkitPlugin plugin;
|
||||
|
||||
public InjectorSubscriptionMap(LPNukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
LPSubscriptionMap ret = inject();
|
||||
if (ret != null) {
|
||||
this.plugin.setSubscriptionMap(ret);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.plugin.getLog().severe("Exception occurred whilst injecting LuckPerms Permission Subscription map.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private LPSubscriptionMap inject() throws Exception {
|
||||
Objects.requireNonNull(PERM_SUBS_FIELD, "PERM_SUBS_FIELD");
|
||||
PluginManager pluginManager = this.plugin.getServer().getPluginManager();
|
||||
|
||||
Object map = PERM_SUBS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPSubscriptionMap) {
|
||||
if (((LPSubscriptionMap) map).plugin == this.plugin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
map = ((LPSubscriptionMap) map).detach();
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
Map<String, Set<Permissible>> castedMap = (Map<String, Set<Permissible>>) map;
|
||||
|
||||
// make a new subscription map & inject it
|
||||
LPSubscriptionMap newMap = new LPSubscriptionMap(this.plugin, castedMap);
|
||||
PERM_SUBS_FIELD.set(pluginManager, newMap);
|
||||
return newMap;
|
||||
}
|
||||
|
||||
public static void uninject() {
|
||||
try {
|
||||
Objects.requireNonNull(PERM_SUBS_FIELD, "PERM_SUBS_FIELD");
|
||||
PluginManager pluginManager = Server.getInstance().getPluginManager();
|
||||
|
||||
Object map = PERM_SUBS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPSubscriptionMap) {
|
||||
LPSubscriptionMap lpMap = (LPSubscriptionMap) map;
|
||||
PERM_SUBS_FIELD.set(pluginManager, lpMap.detach());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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.nukkit.model.server;
|
||||
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
|
||||
import cn.nukkit.permission.Permission;
|
||||
import cn.nukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* A replacement map for the 'defaultPerms' instance in Nukkit's SimplePluginManager.
|
||||
*
|
||||
* This instance allows LuckPerms to intercept calls to
|
||||
* {@link PluginManager#addPermission(Permission)}, specifically regarding
|
||||
* the default nature of the permission.
|
||||
*
|
||||
* Injected by {@link InjectorDefaultsMap}.
|
||||
*/
|
||||
public final class LPDefaultsMap {
|
||||
|
||||
// the plugin
|
||||
final LPNukkitPlugin plugin;
|
||||
|
||||
// the two values in the map
|
||||
private final Map<String, Permission> opSet = new DefaultPermissionSet(true);
|
||||
private final Map<String, Permission> nonOpSet = new DefaultPermissionSet(false);
|
||||
|
||||
// fully resolved defaults (accounts for child permissions too)
|
||||
private Map<String, Boolean> resolvedOpDefaults = ImmutableMap.of();
|
||||
private Map<String, Boolean> resolvedNonOpDefaults = ImmutableMap.of();
|
||||
|
||||
public LPDefaultsMap(LPNukkitPlugin plugin, Map<Boolean, Map<String, Permission>> existingData) {
|
||||
this.plugin = plugin;
|
||||
this.opSet.putAll(existingData.getOrDefault(Boolean.TRUE, Collections.emptyMap()));
|
||||
this.nonOpSet.putAll(existingData.getOrDefault(Boolean.FALSE, Collections.emptyMap()));
|
||||
refreshOp();
|
||||
refreshNonOp();
|
||||
}
|
||||
|
||||
public Map<String, Permission> getOpPermissions() {
|
||||
return this.opSet;
|
||||
}
|
||||
|
||||
public Map<String, Permission> getNonOpPermissions() {
|
||||
return this.nonOpSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries whether a given permission should be granted by default.
|
||||
*
|
||||
* @param permission the permission to query
|
||||
* @param isOp if the player is op
|
||||
* @return a tristate result
|
||||
*/
|
||||
public Tristate lookupDefaultPermission(String permission, boolean isOp) {
|
||||
Map<String, Boolean> map = isOp ? this.resolvedOpDefaults : this.resolvedNonOpDefaults;
|
||||
return Tristate.fromNullableBoolean(map.get(permission));
|
||||
}
|
||||
|
||||
private void refresh(boolean op) {
|
||||
if (op) {
|
||||
refreshOp();
|
||||
} else {
|
||||
refreshNonOp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the op data in this provider.
|
||||
*/
|
||||
private void refreshOp() {
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
for (Permission perm : getOpPermissions().values()) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
builder.put(name, true);
|
||||
for (Map.Entry<String, Boolean> child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
builder.putIfAbsent(child.getKey(), child.getValue());
|
||||
}
|
||||
}
|
||||
this.resolvedOpDefaults = ImmutableMap.copyOf(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the non op data in this provider.
|
||||
*/
|
||||
private void refreshNonOp() {
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
for (Permission perm : getNonOpPermissions().values()) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
builder.put(name, true);
|
||||
for (Map.Entry<String, Boolean> child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
builder.putIfAbsent(child.getKey(), child.getValue());
|
||||
}
|
||||
}
|
||||
this.resolvedNonOpDefaults = ImmutableMap.copyOf(builder);
|
||||
}
|
||||
|
||||
final class DefaultPermissionSet extends ForwardingMap<String, Permission> {
|
||||
final LPDefaultsMap parent = LPDefaultsMap.this;
|
||||
|
||||
private final Map<String, Permission> delegate = new ConcurrentHashMap<>();
|
||||
private final boolean op;
|
||||
|
||||
private DefaultPermissionSet(boolean op) {
|
||||
this.op = op;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Permission> delegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission put(String key, Permission value) {
|
||||
Permission ret = super.put(key, value);
|
||||
refresh(this.op);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission putIfAbsent(String key, Permission value) {
|
||||
Permission ret = super.putIfAbsent(key, value);
|
||||
refresh(this.op);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends Permission> map) {
|
||||
super.putAll(map);
|
||||
refresh(this.op);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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.nukkit.model.server;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.treeview.PermissionVault;
|
||||
|
||||
import cn.nukkit.permission.Permission;
|
||||
import cn.nukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.annotation.CheckForNull;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* A replacement map for the 'permissions' instance in Nukkit's SimplePluginManager.
|
||||
*
|
||||
* This instance allows LuckPerms to intercept calls to
|
||||
* {@link PluginManager#addPermission(Permission)} and record permissions in the
|
||||
* {@link PermissionVault}.
|
||||
*
|
||||
* It also allows us to pre-determine child permission relationships.
|
||||
*
|
||||
* Injected by {@link InjectorPermissionMap}.
|
||||
*/
|
||||
public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
|
||||
// Uses perm.getName().toLowerCase(java.util.Locale.ENGLISH); to determine the key
|
||||
private final Map<String, Permission> delegate = new ConcurrentHashMap<>();
|
||||
|
||||
// cache from permission --> children
|
||||
private final LoadingCache<String, Map<String, Boolean>> trueChildPermissions = Caffeine.newBuilder()
|
||||
.build(new ChildPermissionResolver(true));
|
||||
|
||||
private final LoadingCache<String, Map<String, Boolean>> falseChildPermissions = Caffeine.newBuilder()
|
||||
.build(new ChildPermissionResolver(false));
|
||||
|
||||
/**
|
||||
* The plugin instance
|
||||
*/
|
||||
final LuckPermsPlugin plugin;
|
||||
|
||||
public LPPermissionMap(LuckPermsPlugin plugin, Map<String, Permission> existingData) {
|
||||
this.plugin = plugin;
|
||||
putAll(existingData);
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getChildPermissions(String permission, boolean value) {
|
||||
return value ? this.trueChildPermissions.get(permission) : this.falseChildPermissions.get(permission);
|
||||
}
|
||||
|
||||
private void update() {
|
||||
this.trueChildPermissions.invalidateAll();
|
||||
this.falseChildPermissions.invalidateAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Permission> delegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission put(@Nonnull String key, @Nonnull Permission value) {
|
||||
this.plugin.getPermissionVault().offer(key);
|
||||
Permission ret = super.put(key, value);
|
||||
update();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@Nonnull Map<? extends String, ? extends Permission> m) {
|
||||
this.plugin.getPermissionVault().offerAll(m.keySet());
|
||||
super.putAll(m);
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission putIfAbsent(String key, Permission value) {
|
||||
this.plugin.getPermissionVault().offer(key);
|
||||
Permission ret = super.putIfAbsent(key, value);
|
||||
update();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private final class ChildPermissionResolver implements CacheLoader<String, Map<String, Boolean>> {
|
||||
private final boolean value;
|
||||
|
||||
private ChildPermissionResolver(boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@CheckForNull
|
||||
@Override
|
||||
public Map<String, Boolean> load(@Nonnull String key) {
|
||||
Map<String, Boolean> children = new HashMap<>();
|
||||
resolveChildren(children, Collections.singletonMap(key, this.value), false);
|
||||
children.remove(key, this.value);
|
||||
return ImmutableMap.copyOf(children);
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveChildren(Map<String, Boolean> accumulator, Map<String, Boolean> children, boolean invert) {
|
||||
// iterate through the current known children.
|
||||
// the first time this method is called for a given permission, the children map will contain only the permission itself.
|
||||
for (Map.Entry<String, Boolean> e : children.entrySet()) {
|
||||
if (accumulator.containsKey(e.getKey())) {
|
||||
continue; // Prevent infinite loops
|
||||
}
|
||||
|
||||
// xor the value using the parent (nukkit logic, not mine)
|
||||
boolean value = e.getValue() ^ invert;
|
||||
accumulator.put(e.getKey().toLowerCase(), value);
|
||||
|
||||
// lookup any deeper children & resolve if present
|
||||
Permission perm = this.delegate.get(e.getKey());
|
||||
if (perm != null) {
|
||||
resolveChildren(accumulator, perm.getChildren(), !value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,259 @@
|
||||
/*
|
||||
* 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.nukkit.model.server;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
|
||||
import cn.nukkit.permission.Permissible;
|
||||
import cn.nukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A replacement map for the 'permSubs' instance in Nukkit's SimplePluginManager.
|
||||
*
|
||||
* This instance allows LuckPerms to intercept calls to
|
||||
* {@link PluginManager#subscribeToPermission(String, Permissible)},
|
||||
* {@link PluginManager#unsubscribeFromPermission(String, Permissible)} and
|
||||
* {@link PluginManager#getPermissionSubscriptions(String)}.
|
||||
*
|
||||
* Nukkit for some reason sometimes uses subscription status to determine whether
|
||||
* a permissible has a given node, instead of checking directly with
|
||||
* {@link Permissible#hasPermission(String)}.
|
||||
*
|
||||
* In order to implement predicable Nukkit behaviour, LP has two options:
|
||||
* 1) register subscriptions for all players as normal, or
|
||||
* 2) inject it's own map instance to proxy calls to {@link PluginManager#getPermissionSubscriptions(String)} back to LuckPerms.
|
||||
*
|
||||
* This class implements option 2 above. It is preferred because it is faster & uses less memory
|
||||
*
|
||||
* Injected by {@link InjectorSubscriptionMap}.
|
||||
*/
|
||||
public final class LPSubscriptionMap extends HashMap<String, Set<Permissible>> {
|
||||
|
||||
// the plugin instance
|
||||
final LPNukkitPlugin plugin;
|
||||
|
||||
public LPSubscriptionMap(LPNukkitPlugin plugin, Map<String, Set<Permissible>> existingData) {
|
||||
super(existingData);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/*
|
||||
* The get method is the only one which is actually used by SimplePluginManager
|
||||
* we override it to always return a value - which means the null check in
|
||||
* subscribeToDefaultPerms always fails - soo, we don't have to worry too much
|
||||
* about implementing #put.
|
||||
*
|
||||
* we also ensure all returns are LPSubscriptionValueMaps. this extension
|
||||
* will also delegate checks to online players - meaning we don't ever
|
||||
* have to register their subscriptions with the plugin manager.
|
||||
*/
|
||||
@Override
|
||||
public Set<Permissible> get(Object key) {
|
||||
if (key == null || !(key instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String permission = ((String) key);
|
||||
|
||||
Set<Permissible> result = super.get(key);
|
||||
|
||||
if (result == null) {
|
||||
// calculate a new map - always!
|
||||
result = new LPSubscriptionValueSet(permission);
|
||||
super.put(permission, result);
|
||||
} else if (!(result instanceof LPSubscriptionValueSet)) {
|
||||
// ensure return type is a LPSubscriptionMap
|
||||
result = new LPSubscriptionValueSet(permission, result);
|
||||
super.put(permission, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Permissible> put(String key, Set<Permissible> value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("Map value cannot be null");
|
||||
}
|
||||
|
||||
// ensure values are LP subscription maps
|
||||
if (!(value instanceof LPSubscriptionValueSet)) {
|
||||
value = new LPSubscriptionValueSet(key, value);
|
||||
}
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
// if the key isn't null and is a string, #get will always return a value for it
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return key != null && key instanceof String;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this map back to a standard HashMap
|
||||
*
|
||||
* @return a standard representation of this map
|
||||
*/
|
||||
public Map<String, Set<Permissible>> detach() {
|
||||
Map<String, Set<Permissible>> ret = new HashMap<>();
|
||||
|
||||
for (Map.Entry<String, Set<Permissible>> ent : entrySet()) {
|
||||
if (ent.getValue() instanceof LPSubscriptionValueSet) {
|
||||
Set<Permissible> backing = ((LPSubscriptionValueSet) ent.getValue()).backing;
|
||||
Set<Permissible> copy; (copy = Collections.newSetFromMap(new WeakHashMap<>(backing.size()))).addAll(backing);
|
||||
ret.put(ent.getKey(), copy);
|
||||
} else {
|
||||
ret.put(ent.getKey(), ent.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value map extension which includes LP objects in Permissible related queries.
|
||||
*/
|
||||
public final class LPSubscriptionValueSet implements Set<Permissible> {
|
||||
|
||||
// the permission being mapped to this value map
|
||||
private final String permission;
|
||||
|
||||
// the backing map
|
||||
private final Set<Permissible> backing;
|
||||
|
||||
private LPSubscriptionValueSet(String permission, Set<Permissible> content) {
|
||||
this.permission = permission;
|
||||
this.backing = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
|
||||
if (content != null) {
|
||||
this.backing.addAll(content);
|
||||
}
|
||||
}
|
||||
|
||||
private LPSubscriptionValueSet(String permission) {
|
||||
this(permission, null);
|
||||
}
|
||||
|
||||
private Sets.SetView<Permissible> getContentView() {
|
||||
// gather players (LPPermissibles)
|
||||
Set<Permissible> players = LPSubscriptionMap.this.plugin.getServer().getOnlinePlayers().values().stream()
|
||||
.filter(player -> player.isPermissionSet(this.permission))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
return Sets.union(players, this.backing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object key) {
|
||||
// try the backing map
|
||||
if (this.backing.contains(key)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// then try the permissible
|
||||
if (key instanceof Permissible) {
|
||||
Permissible p = (Permissible) key;
|
||||
return p.isPermissionSet(this.permission);
|
||||
}
|
||||
|
||||
// no result
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
// we never want to remove this map from the parent - since it just gets recreated
|
||||
// on subsequent calls
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return Math.max(1, this.backing.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Permissible> iterator() {
|
||||
return getContentView().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return getContentView().toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return getContentView().toArray(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Permissible permissible) {
|
||||
return this.backing.add(permissible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends Permissible> c) {
|
||||
return this.backing.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return this.backing.remove(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return getContentView().containsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return this.backing.retainAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return this.backing.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.backing.clear();
|
||||
}
|
||||
}
|
||||
}
|
@ -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.nukkit.processors;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.common.processors.AbstractPermissionProcessor;
|
||||
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Permission Processor for Nukkits "child" permission system.
|
||||
*/
|
||||
public class ChildProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
|
||||
private final LPNukkitPlugin plugin;
|
||||
private Map<String, Boolean> childPermissions = Collections.emptyMap();
|
||||
|
||||
public ChildProcessor(LPNukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate hasPermission(String permission) {
|
||||
return Tristate.fromNullableBoolean(this.childPermissions.get(permission));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
Map<String, Boolean> builder = new ConcurrentHashMap<>();
|
||||
for (Map.Entry<String, Boolean> e : this.sourceMap.entrySet()) {
|
||||
Map<String, Boolean> children = this.plugin.getPermissionMap().getChildPermissions(e.getKey(), e.getValue());
|
||||
if (children != null) {
|
||||
builder.putAll(children);
|
||||
}
|
||||
}
|
||||
this.childPermissions = builder;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.nukkit.processors;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
||||
import me.lucko.luckperms.nukkit.LPNukkitPlugin;
|
||||
import me.lucko.luckperms.nukkit.model.PermissionDefault;
|
||||
|
||||
/**
|
||||
* Permission Processor for Nukkits "default" permission system.
|
||||
*/
|
||||
public class DefaultsProcessor implements PermissionProcessor {
|
||||
private final LPNukkitPlugin plugin;
|
||||
private final boolean isOp;
|
||||
|
||||
public DefaultsProcessor(LPNukkitPlugin plugin, boolean isOp) {
|
||||
this.plugin = plugin;
|
||||
this.isOp = isOp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate hasPermission(String permission) {
|
||||
Tristate t = this.plugin.getDefaultPermissionMap().lookupDefaultPermission(permission, this.isOp);
|
||||
if (t != Tristate.UNDEFINED) {
|
||||
return t;
|
||||
}
|
||||
|
||||
PermissionDefault def = PermissionDefault.fromPermission(this.plugin.getPermissionMap().get(permission));
|
||||
return def == null ? Tristate.UNDEFINED : Tristate.fromBoolean(def.getValue(this.isOp));
|
||||
}
|
||||
}
|
459
nukkit/src/main/resources/config.yml
Normal file
459
nukkit/src/main/resources/config.yml
Normal file
@ -0,0 +1,459 @@
|
||||
####################################################################################################
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
# | __ __ ___ __ __ | #
|
||||
# | | | | / ` |__/ |__) |__ |__) |\/| /__` | #
|
||||
# | |___ \__/ \__, | \ | |___ | \ | | .__/ | #
|
||||
# | | #
|
||||
# | | #
|
||||
# | SOURCE CODE: https://github.com/lucko/LuckPerms | #
|
||||
# | WIKI: https://github.com/lucko/LuckPerms/wiki | #
|
||||
# | BUG REPORTS: https://github.com/lucko/LuckPerms/issues | #
|
||||
# | | #
|
||||
# | Each option in this file is documented and explained here: | #
|
||||
# | ==> https://github.com/lucko/LuckPerms/wiki/Configuration | #
|
||||
# | | #
|
||||
# | New options are not added to this file automatically. Default values are used if an | #
|
||||
# | option cannot be found. The latest config versions can be obtained at the link above. | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
####################################################################################################
|
||||
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
# | General | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
|
||||
# The name of the server, used for server specific permissions. Set to 'global' to disable.
|
||||
server: global
|
||||
|
||||
# If users on this server should have their global permissions applied.
|
||||
# If set to false, only server specific permissions will apply for users on this server
|
||||
include-global: true
|
||||
|
||||
# If users on this server should have their global world permissions applied.
|
||||
# If set to false, only world specific permissions will apply for users on this server
|
||||
include-global-world: true
|
||||
|
||||
# If users on this server should have global (non-server specific) groups applied
|
||||
apply-global-groups: true
|
||||
|
||||
# If users on this server should have global (non-world specific) groups applied
|
||||
apply-global-world-groups: true
|
||||
|
||||
# If the servers own UUID cache/lookup facility should be used when there is no record for a player
|
||||
# in the LuckPerms cache.
|
||||
use-server-uuid-cache: false
|
||||
|
||||
# If LuckPerms should use the "server-name" property from the "server.properties"
|
||||
# file as the "server" option within LuckPerms.
|
||||
use-server-properties-name: false
|
||||
|
||||
# If set to true, LuckPerms will allow usernames with non alphanumeric characters.
|
||||
#
|
||||
# Note that due to the design of the storage implementation, usernames must still be
|
||||
# 16 characters or less.
|
||||
allow-invalid-usernames: false
|
||||
|
||||
# If LuckPerms should produce extra logging output when it handles logins.
|
||||
# Useful if you're having issues with UUID forwarding or data not being loaded.
|
||||
debug-logins: false
|
||||
|
||||
# If the plugin should send log notifications to users whenever permissions are modified.
|
||||
log-notify: true
|
||||
|
||||
# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in
|
||||
# this list, the value assigned will be sent forward for permission calculation instead.
|
||||
world-rewrite:
|
||||
# world_nether: world
|
||||
# world_the_end: world
|
||||
|
||||
# Controls how temporary permissions/parents/meta should be accumulated
|
||||
#
|
||||
# The default behaviour is "deny"
|
||||
# If "accumulate": durations will be added to the existing expiry time
|
||||
# If "replace": durations will be replaced if the new duration is later than the current expiration
|
||||
# If "deny": the command will just fail if you try to add another node with the same expiry
|
||||
temporary-add-behaviour: deny
|
||||
|
||||
# How should LuckPerms determine a users "primary" group.
|
||||
#
|
||||
# Available Options:
|
||||
# -> stored use the value stored against the users record in the file/database
|
||||
# -> parents-by-weight just use the users most highly weighted parent
|
||||
# -> all-parents-by-weight same as above, but calculates based upon all parents inherited from both
|
||||
# directly and indirectly
|
||||
primary-group-calculation: parents-by-weight
|
||||
|
||||
# If set to false, the plugin will allow a Users primary group to be removed with the
|
||||
# 'parent remove' command, and will set their primary group back to default.
|
||||
prevent-primary-group-removal: false
|
||||
|
||||
# If the plugin should check for "extra" permissions with users run LP commands.
|
||||
#
|
||||
# These extra permissions allow finer control over what users can do with each command, and
|
||||
# who they have access to edit.
|
||||
#
|
||||
# The permissions are *not* static, unlike the 'base' permisssions, and will depend upon the
|
||||
# arguments given within the command.
|
||||
argument-based-command-permissions: false
|
||||
|
||||
|
||||
|
||||
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
# | Permission Calculation | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
|
||||
# If the plugin should apply wildcard permissions.
|
||||
# If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered
|
||||
# permissions matching the wildcard.
|
||||
apply-wildcards: true
|
||||
|
||||
# If the plugin should parse regex permissions.
|
||||
# If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the
|
||||
# node, and resolve & apply all registered permissions matching the regex.
|
||||
apply-regex: true
|
||||
|
||||
# If the plugin should complete and apply shorthand permissions.
|
||||
# If set to true, LuckPerms will detect and expand shorthand node patterns.
|
||||
apply-shorthand: true
|
||||
|
||||
# If the plugin should apply Nukkit child permissions.
|
||||
# Plugin authors can define custom permissions structures for their plugin, which will be resolved
|
||||
# and used by LuckPerms if this setting is enabled.
|
||||
apply-nukkit-child-permissions: true
|
||||
|
||||
# If the plugin should apply Nukkit default permissions.
|
||||
# Plugin authors can define permissions which should be given to all users by default, or setup
|
||||
# permissions which should/shouldn't be given to opped players.
|
||||
# If this option is set to false, LuckPerms will ignore these defaults.
|
||||
apply-nukkit-default-permissions: true
|
||||
|
||||
# If the plugin should apply attachment permissions.
|
||||
# Other plugins on the server are able to add their own "permission attachments" to players. This
|
||||
# allows them to grant players additional permissions which last until the end of the session, or
|
||||
# until they're removed. If this option is set to false, LuckPerms will not include these attachment
|
||||
# permissions when considering if a player should have access to a certain permission.
|
||||
apply-nukkit-attachment-permissions: true
|
||||
|
||||
# The algorithm LuckPerms should use when traversing the "inheritance tree".
|
||||
#
|
||||
# The valid options are:
|
||||
# - breadth-first
|
||||
# - depth-first-pre-order
|
||||
# - depth-first-post-order
|
||||
#
|
||||
# See here for information about the differences between each algorithm.
|
||||
# - https://en.wikipedia.org/wiki/Breadth-first_search
|
||||
# - https://en.wikipedia.org/wiki/Depth-first_search
|
||||
inheritance-traversal-algorithm: depth-first-pre-order
|
||||
|
||||
# Define special group weights for this server.
|
||||
# Default is just 0.
|
||||
group-weight:
|
||||
# admin: 10
|
||||
|
||||
|
||||
|
||||
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
# | Meta Formatting & Stacking | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
|
||||
# Allows you to setup prefix/suffix stacking options.
|
||||
#
|
||||
# Available formats:
|
||||
# - highest
|
||||
# - lowest
|
||||
# - highest_own
|
||||
# - lowest_own
|
||||
# - highest_inherited
|
||||
# - lowest_inherited
|
||||
# - highest_on_track_<track>
|
||||
# - lowest_on_track_<track>
|
||||
# - highest_not_on_track_<track>
|
||||
# - lowest_not_on_track_<track>
|
||||
#
|
||||
# Each element is added in the order listed.
|
||||
meta-formatting:
|
||||
prefix:
|
||||
format:
|
||||
- "highest"
|
||||
start-spacer: ""
|
||||
middle-spacer: " "
|
||||
end-spacer: ""
|
||||
suffix:
|
||||
format:
|
||||
- "highest"
|
||||
start-spacer: ""
|
||||
middle-spacer: " "
|
||||
end-spacer: ""
|
||||
|
||||
|
||||
|
||||
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
# | OP (Server Operator) Settings | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
|
||||
# If the vanilla OP system is enabled. If set to false, all users will be de-opped, and the op/deop
|
||||
# commands will be disabled.
|
||||
enable-ops: true
|
||||
|
||||
# If set to true, any user with the permission "luckperms.autoop" will automatically be granted
|
||||
# server operator status. This permission can be inherited, or set on specific servers/worlds,
|
||||
# temporarily, etc.
|
||||
#
|
||||
# Additionally, setting this to true will force the "enable-ops" option above to false. All users
|
||||
# will be de-opped unless they have the permission node, and the op/deop commands will be disabled.
|
||||
#
|
||||
# It is important to note that this setting is only checked when a player first joins the server,
|
||||
# and when they switch worlds. Therefore, simply removing this permission from a user will not
|
||||
# automatically de-op them. A player needs to relog to have the change take effect.
|
||||
#
|
||||
# It is recommended that you use this option instead of assigning a single '*' permission.
|
||||
auto-op: false
|
||||
|
||||
# If opped players should be allowed to use LuckPerms commands. Set to false to only allow users who
|
||||
# have the permissions access to the commands
|
||||
commands-allow-op: true
|
||||
|
||||
|
||||
|
||||
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
# | Vault | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
|
||||
# If the vault-server option below should be used.
|
||||
# When this option is set to false, the server value defined above under "server" is used.
|
||||
use-vault-server: false
|
||||
|
||||
# The name of the server used within Vault operations. If you don't want Vault operations to be
|
||||
# server specific, set this to "global".
|
||||
#
|
||||
# Will only take effect if use-vault-server is set to true above.
|
||||
vault-server: global
|
||||
|
||||
# If global permissions should be considered when retrieving meta or player groups
|
||||
vault-include-global: true
|
||||
|
||||
# If Vault operations should ignore any world arguments if supplied.
|
||||
vault-ignore-world: false
|
||||
|
||||
# If LuckPerms should print debugging info to console when a plugin uses a Vault function
|
||||
vault-debug: false
|
||||
|
||||
|
||||
|
||||
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
# | Storage | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
|
||||
# Which storage method the plugin should use.
|
||||
#
|
||||
# See: https://github.com/lucko/LuckPerms/wiki/Choosing-a-Storage-type
|
||||
# Currently supported: mysql, mariadb, postgresql, sqlite, h2, json, yaml, hocon, mongodb
|
||||
#
|
||||
# Fill out connection info below if you're using MySQL, MariaDB, PostgreSQL or MongoDB
|
||||
# If your MySQL server supports it, the "mariadb" option is preferred over "mysql".
|
||||
storage-method: h2
|
||||
|
||||
# When using a file-based storage type, LuckPerms can monitor the data files for changes, and then
|
||||
# schedule automatic updates when changes are detected.
|
||||
#
|
||||
# If you don't want this to happen, set this option to false.
|
||||
watch-files: true
|
||||
|
||||
# This block enables support for split datastores.
|
||||
split-storage:
|
||||
enabled: false
|
||||
methods:
|
||||
user: h2
|
||||
group: h2
|
||||
track: h2
|
||||
uuid: h2
|
||||
log: h2
|
||||
|
||||
data:
|
||||
# Uses standard DB engine port by default
|
||||
# MySQL: 3306, PostgreSQL: 5432, MongoDB: 27017
|
||||
# Specify as "host:port" if differs
|
||||
address: localhost
|
||||
|
||||
database: minecraft
|
||||
username: root
|
||||
password: ''
|
||||
|
||||
# These settings apply to the MySQL connection pool.
|
||||
# The default values will be suitable for the majority of users.
|
||||
# Do not change these settings unless you know what you're doing!
|
||||
pool-settings:
|
||||
|
||||
# Sets the maximum size of the MySQL connection pool.
|
||||
# Basically this value will determine the maximum number of actual
|
||||
# connections to the database backend.
|
||||
#
|
||||
# More information about determining the size of connection pools can be found here:
|
||||
# https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
|
||||
maximum-pool-size: 10
|
||||
|
||||
# Sets the minimum number of idle connections that the pool will try to maintain.
|
||||
#
|
||||
# For maximum performance and responsiveness to spike demands, it is recommended to not set
|
||||
# this value and instead allow the pool to act as a fixed size connection pool.
|
||||
# (set this value to the same as 'maximum-pool-size')
|
||||
minimum-idle: 10
|
||||
|
||||
# This setting controls the maximum lifetime of a connection in the pool in milliseconds.
|
||||
# The value should be at least 30 seconds less than any database or infrastructure imposed
|
||||
# connection time limit.
|
||||
maximum-lifetime: 1800000 # 30 minutes
|
||||
|
||||
# This setting controls the maximum number of milliseconds that the plugin will wait for a
|
||||
# connection from the pool, before timing out.
|
||||
connection-timeout: 5000 # 5 seconds
|
||||
|
||||
# This setting allows you to define extra properties for connections.
|
||||
properties:
|
||||
useUnicode: true
|
||||
characterEncoding: utf8
|
||||
|
||||
# The prefix for all LuckPerms tables. Change this is you want to use different tables for
|
||||
# different servers.
|
||||
#
|
||||
# This should *not* be set to "lp_" if you have previously ran LuckPerms v2.16.81 or earlier with
|
||||
# this database.
|
||||
table_prefix: 'luckperms_'
|
||||
|
||||
# The prefix to use for all LuckPerms collections. Change this if you want to use different
|
||||
# collections for different servers. The default is no prefix.
|
||||
mongodb_collection_prefix: ''
|
||||
|
||||
# This option controls how frequently LuckPerms will perform a sync task.
|
||||
# A sync task will refresh all data from the storage, and ensure that the most up-to-date data is
|
||||
# being used by the plugin.
|
||||
#
|
||||
# This is disabled by default, as most users will not need it. However, if you're using a remote
|
||||
# storage type without a messaging service setup, you may wish to set this value to something like
|
||||
# 3.
|
||||
#
|
||||
# Set to -1 to disable the task completely.
|
||||
sync-minutes: -1
|
||||
|
||||
# Settings for the messaging service
|
||||
#
|
||||
# If enabled and configured, LuckPerms will use the messaging system to inform other
|
||||
# connected servers of changes. Use the command "/luckperms networksync" to push changes.
|
||||
# Data is NOT stored using this service. It is only used as a messaging platform.
|
||||
#
|
||||
# If you decide to enable this feature, you should set "sync-minutes" to -1, as there is no need for
|
||||
# LuckPerms to poll the database for changes.
|
||||
#
|
||||
# Available options:
|
||||
# -> bungee uses the plugin messaging channels. Must be enabled on all connected servers to work.
|
||||
# -> lilypad uses lilypad pub sub to push changes. You need to have the LilyPad-Connect plugin
|
||||
# installed.
|
||||
# -> redis uses redis pub sub to push changes. Your redis server must be configured below.
|
||||
# -> none nothing
|
||||
messaging-service: none
|
||||
|
||||
# If LuckPerms should automatically push updates after a change has been made with a command.
|
||||
auto-push-updates: true
|
||||
|
||||
# If LuckPerms should push logging entries to connected servers via the messaging service.
|
||||
push-log-entries: true
|
||||
|
||||
# If LuckPerms should broadcast received logging entries to players on this platform.
|
||||
#
|
||||
# If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you should
|
||||
# set this option to false on either your backends or your proxies, to avoid players being messaged
|
||||
# twice about log entries.
|
||||
broadcast-received-log-entries: true
|
||||
|
||||
# Settings for Redis.
|
||||
# Port 6379 is used by default; set address to "host:port" if differs
|
||||
redis:
|
||||
enabled: false
|
||||
address: localhost
|
||||
password: ''
|
||||
|
||||
|
||||
|
||||
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
# | Default Assignments | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
|
||||
# This section allows you to define defaults to give users whenever they connect to the server.
|
||||
# The default assignments are highly configurable and conditional.
|
||||
#
|
||||
# There is one default assignment built into LuckPerms, which will add all users to the "default"
|
||||
# group if they are not a member of any other group. This setting cannot be disabled. However, you
|
||||
# can use this section to add more of your own.
|
||||
#
|
||||
# IMPORTANT:
|
||||
# In order to save storage space, LuckPerms does not store users who have no permissions defined,
|
||||
# and are only a member of the default group. Adding default assignments to this section will negate
|
||||
# this effect. It is HIGHLY RECCOMENDED that instead of assigning defaults here, you add permissions
|
||||
# to the "default" group, or set the "default" group to inherit other groups, and then use the
|
||||
# group-name-rewrite rule above.
|
||||
#
|
||||
# It is also important to note that these rules are considered every time a player logs into the
|
||||
# server, and are applied directly to the user's data. Simply removing a rule here will not reverse
|
||||
# the effect of that rule on any users who have already had it applied to them.
|
||||
#
|
||||
# The "has" and "lacks" conditions below support standard boolean logic, using the 'and' & 'or'
|
||||
# characters used in Java.
|
||||
# e.g. "(some.other.permission | some.permission.other) & some.thing.else" == a user has
|
||||
# 'some.other.permission', or 'some.permission.other', and they also have 'some.thing.else'
|
||||
#
|
||||
# Groups are represented by the permission node: group.<group name>
|
||||
# Per server and per world nodes are represented by "server-world/permission" or "server/permission"
|
||||
#
|
||||
# Within conditions, permission nodes MUST be escaped using "<" and ">". See the example below.
|
||||
#
|
||||
# Explanation of the examples below: (they're just to demonstrate the features & use cases)
|
||||
#
|
||||
# rule1:
|
||||
# If a user is either in the vip or vip+ group, and they have the "titles.titlecollector" permission
|
||||
# set to true, and the "some.random.permission" set to false... if they're not in the group
|
||||
# "prison_titlepack" on the "prison" server, then give add them to the "prison_titlepack" group on
|
||||
# the "prison" server, and remove "some.random.permission".
|
||||
#
|
||||
# rule2:
|
||||
# If the user isn't in any of the following groups on the skyblock server: sb_level1, sb_level2,
|
||||
# sb_level3, then add them to sb_level1 on the skyblock server.
|
||||
#
|
||||
# rule3:
|
||||
# If the user is a member of the default group, remove them from default, add them to member, and
|
||||
# set their primary group to member.
|
||||
#
|
||||
# WARNING: Unlike internal commands, this system does not ensure that a group exists before adding
|
||||
# a user to it. It also does not unsure that a user is a member of a group before making that group
|
||||
# their primary group.
|
||||
#
|
||||
# Before you use "give: group.<name>" or "set-primary-group", make sure that the group exists, and
|
||||
# that the user is a member of the group.
|
||||
default-assignments:
|
||||
# rule1:
|
||||
# if:
|
||||
# has-true: (<group.vip> | <group.vip+>) & <titles.tilecollector>
|
||||
# has-false: <some.random.permission>
|
||||
# lacks: <prison/group.prison_titlepack>
|
||||
# give:
|
||||
# - prison/group.prison_titlepack
|
||||
# take:
|
||||
# - some.random.permission
|
||||
# rule2:
|
||||
# if:
|
||||
# lacks: <skyblock/group.sb_level1> & <skyblock/group.sb_level2> & <skyblock/group.sb_level3>
|
||||
# give:
|
||||
# - skyblock/group.sb_level1
|
||||
# rule3:
|
||||
# if:
|
||||
# has-true: <group.default>
|
||||
# take:
|
||||
# - group.default
|
||||
# give:
|
||||
# - group.member
|
||||
# set-primary-group: member
|
14
nukkit/src/main/resources/plugin.yml
Normal file
14
nukkit/src/main/resources/plugin.yml
Normal file
@ -0,0 +1,14 @@
|
||||
name: LuckPerms
|
||||
version: ${full.version}
|
||||
api: ["1.0.5"]
|
||||
description: A permissions plugin
|
||||
author: Luck
|
||||
website: https://github.com/lucko/LuckPerms
|
||||
|
||||
main: me.lucko.luckperms.nukkit.LPNukkitPlugin
|
||||
load: STARTUP
|
||||
|
||||
commands:
|
||||
luckperms:
|
||||
description: Manage permissions
|
||||
aliases: [lp, perm, perms, permission, permissions]
|
9
pom.xml
9
pom.xml
@ -17,6 +17,7 @@
|
||||
<module>sponge/sponge-service-api6</module>
|
||||
<module>sponge/sponge-service-api7</module>
|
||||
<module>sponge</module>
|
||||
<module>nukkit</module>
|
||||
</modules>
|
||||
|
||||
<name>LuckPerms</name>
|
||||
@ -152,14 +153,6 @@
|
||||
<id>luck-repo</id>
|
||||
<url>https://repo.lucko.me/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>sponge-repo</id>
|
||||
<url>https://repo.spongepowered.org/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
||||
|
@ -157,4 +157,11 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sponge-repo</id>
|
||||
<url>https://repo.spongepowered.org/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
||||
|
@ -54,4 +54,11 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sponge-repo</id>
|
||||
<url>https://repo.spongepowered.org/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
||||
|
@ -54,4 +54,11 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sponge-repo</id>
|
||||
<url>https://repo.spongepowered.org/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
||||
|
@ -55,4 +55,11 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sponge-repo</id>
|
||||
<url>https://repo.spongepowered.org/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
||||
|
Loading…
Reference in New Issue
Block a user