Mostly javadoc, and also some fixes there and there
This commit is contained in:
parent
f976350ee1
commit
54bc8ab99a
@ -1,16 +1,12 @@
|
|||||||
package fr.pandacube.lib.bungee.commands;
|
package fr.pandacube.lib.bungee.commands;
|
||||||
|
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
|
||||||
import com.mojang.brigadier.context.ParsedCommandNode;
|
|
||||||
import com.mojang.brigadier.context.StringRange;
|
import com.mojang.brigadier.context.StringRange;
|
||||||
import com.mojang.brigadier.suggestion.Suggestion;
|
import com.mojang.brigadier.suggestion.Suggestion;
|
||||||
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||||
import com.mojang.brigadier.suggestion.Suggestions;
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
|
||||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||||
import fr.pandacube.lib.commands.BrigadierCommand;
|
import fr.pandacube.lib.commands.BrigadierCommand;
|
||||||
import fr.pandacube.lib.commands.SuggestionsSupplier;
|
import fr.pandacube.lib.commands.SuggestionsSupplier;
|
||||||
import fr.pandacube.lib.reflect.Reflect;
|
|
||||||
import fr.pandacube.lib.util.Log;
|
import fr.pandacube.lib.util.Log;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
@ -18,18 +14,26 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|||||||
import net.md_5.bungee.api.plugin.Command;
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
import net.md_5.bungee.api.plugin.TabExecutor;
|
import net.md_5.bungee.api.plugin.TabExecutor;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class that holds the logic of a specific command to be registered in {@link BungeeBrigadierDispatcher} and
|
||||||
|
* BungeeCord command API.
|
||||||
|
*/
|
||||||
public abstract class BungeeBrigadierCommand extends BrigadierCommand<CommandSender> {
|
public abstract class BungeeBrigadierCommand extends BrigadierCommand<CommandSender> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The command dispatcher.
|
||||||
|
*/
|
||||||
protected BungeeBrigadierDispatcher dispatcher;
|
protected BungeeBrigadierDispatcher dispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instanciate this command isntance.
|
||||||
|
* @param d the dispatcher in which to register this command.
|
||||||
|
*/
|
||||||
public BungeeBrigadierCommand(BungeeBrigadierDispatcher d) {
|
public BungeeBrigadierCommand(BungeeBrigadierDispatcher d) {
|
||||||
if (d == null) {
|
if (d == null) {
|
||||||
throw new IllegalStateException("BungeeBrigadierDispatcher not provided.");
|
throw new IllegalStateException("BungeeBrigadierDispatcher not provided.");
|
||||||
@ -62,12 +66,14 @@ public abstract class BungeeBrigadierCommand extends BrigadierCommand<CommandSen
|
|||||||
.redirect(commandNode)
|
.redirect(commandNode)
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
|
||||||
ProxyServer.getInstance().getPluginManager().registerCommand(dispatcher.plugin, new CommandRelay(alias));
|
ProxyServer.getInstance().getPluginManager().registerCommand(dispatcher.plugin, new CommandRelay(alias));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private class CommandRelay extends Command implements TabExecutor {
|
private class CommandRelay extends Command implements TabExecutor {
|
||||||
private final String alias;
|
private final String alias;
|
||||||
public CommandRelay(String alias) {
|
public CommandRelay(String alias) {
|
||||||
@ -117,9 +123,11 @@ public abstract class BungeeBrigadierCommand extends BrigadierCommand<CommandSen
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the provided {@link SuggestionsSupplier} into a Brigadier’s {@link SuggestionProvider}.
|
||||||
|
* @param suggestions the suggestions to wrap.
|
||||||
|
* @return a {@link SuggestionProvider} generating the suggestions from the provided {@link SuggestionsSupplier}.
|
||||||
|
*/
|
||||||
protected SuggestionProvider<CommandSender> wrapSuggestions(SuggestionsSupplier<CommandSender> suggestions) {
|
protected SuggestionProvider<CommandSender> wrapSuggestions(SuggestionsSupplier<CommandSender> suggestions) {
|
||||||
return wrapSuggestions(suggestions, Function.identity());
|
return wrapSuggestions(suggestions, Function.identity());
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,7 @@
|
|||||||
package fr.pandacube.lib.bungee.commands;
|
package fr.pandacube.lib.bungee.commands;
|
||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
|
||||||
import com.mojang.brigadier.ParseResults;
|
|
||||||
import com.mojang.brigadier.context.CommandContextBuilder;
|
|
||||||
import com.mojang.brigadier.context.StringRange;
|
|
||||||
import com.mojang.brigadier.context.SuggestionContext;
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
||||||
import com.mojang.brigadier.suggestion.Suggestion;
|
|
||||||
import com.mojang.brigadier.suggestion.Suggestions;
|
|
||||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
|
||||||
import com.mojang.brigadier.tree.CommandNode;
|
|
||||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
|
||||||
import fr.pandacube.lib.chat.Chat;
|
import fr.pandacube.lib.chat.Chat;
|
||||||
import fr.pandacube.lib.commands.BrigadierCommand;
|
|
||||||
import fr.pandacube.lib.commands.BrigadierDispatcher;
|
import fr.pandacube.lib.commands.BrigadierDispatcher;
|
||||||
import fr.pandacube.lib.commands.BrigadierSuggestionsUtil;
|
|
||||||
import fr.pandacube.lib.util.Log;
|
|
||||||
import net.kyori.adventure.text.ComponentLike;
|
import net.kyori.adventure.text.ComponentLike;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
@ -25,11 +11,10 @@ import net.md_5.bungee.api.plugin.Listener;
|
|||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import net.md_5.bungee.event.EventHandler;
|
import net.md_5.bungee.event.EventHandler;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
/**
|
||||||
import java.util.Collection;
|
* Implementation of {@link BrigadierDispatcher} that integrates the commands into BungeeCord API, so the players and
|
||||||
import java.util.List;
|
* the console can actually execute them.
|
||||||
import java.util.concurrent.CompletableFuture;
|
*/
|
||||||
|
|
||||||
public class BungeeBrigadierDispatcher extends BrigadierDispatcher<CommandSender> implements Listener {
|
public class BungeeBrigadierDispatcher extends BrigadierDispatcher<CommandSender> implements Listener {
|
||||||
|
|
||||||
|
|
||||||
@ -37,15 +22,20 @@ public class BungeeBrigadierDispatcher extends BrigadierDispatcher<CommandSender
|
|||||||
|
|
||||||
/* package */ final Plugin plugin;
|
/* package */ final Plugin plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance of {@link BungeeBrigadierDispatcher}.
|
||||||
|
* @param pl the plugin that creates this dispatcher.
|
||||||
|
*/
|
||||||
public BungeeBrigadierDispatcher(Plugin pl) {
|
public BungeeBrigadierDispatcher(Plugin pl) {
|
||||||
plugin = pl;
|
plugin = pl;
|
||||||
ProxyServer.getInstance().getPluginManager().registerListener(plugin, this);
|
ProxyServer.getInstance().getPluginManager().registerListener(plugin, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a player sends a chat message. Used to gets the typed command and execute it.
|
||||||
|
* @param event the event.
|
||||||
|
*/
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onChat(ChatEvent event) {
|
public void onChat(ChatEvent event) {
|
||||||
if (!event.getMessage().startsWith("/"))
|
if (!event.getMessage().startsWith("/"))
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package fr.pandacube.lib.bungee.permissions;
|
package fr.pandacube.lib.bungee.permissions;
|
||||||
|
|
||||||
|
import fr.pandacube.lib.db.DB;
|
||||||
|
import fr.pandacube.lib.db.DBConnection;
|
||||||
import fr.pandacube.lib.permissions.Permissions;
|
import fr.pandacube.lib.permissions.Permissions;
|
||||||
import fr.pandacube.lib.players.standalone.StandaloneOnlinePlayer;
|
import fr.pandacube.lib.players.standalone.AbstractOnlinePlayer;
|
||||||
import fr.pandacube.lib.players.standalone.StandalonePlayerManager;
|
import fr.pandacube.lib.players.standalone.AbstractPlayerManager;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
@ -12,13 +14,31 @@ import net.md_5.bungee.api.plugin.Listener;
|
|||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import net.md_5.bungee.event.EventHandler;
|
import net.md_5.bungee.event.EventHandler;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that integrates the {@code pandalib-permissions} system into a BungeeCord instance.
|
||||||
|
* To register the event listener into BungeeCord, use {@link #init(Plugin)}.
|
||||||
|
* The permission system must be initialized first, using {@link Permissions#init(Function)}.
|
||||||
|
* Don’t forget that the permission system also needs a connection to a database, so don’t forget to call
|
||||||
|
* {@link DB#init(DBConnection, String)} with the appropriate parameters before anything.
|
||||||
|
*/
|
||||||
public class PandalibBungeePermissions implements Listener {
|
public class PandalibBungeePermissions implements Listener {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers event listener to redirect permission checks to {@code pandalib-permissions}.
|
||||||
|
* @param bungeePlugin a BungeeCord plugin.
|
||||||
|
*/
|
||||||
public static void init(Plugin bungeePlugin) {
|
public static void init(Plugin bungeePlugin) {
|
||||||
ProxyServer.getInstance().getPluginManager().registerListener(bungeePlugin, new PandalibBungeePermissions());
|
ProxyServer.getInstance().getPluginManager().registerListener(bungeePlugin, new PandalibBungeePermissions());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler called when a plugin asks if a player has a permission.
|
||||||
|
* @param event the permission check event.
|
||||||
|
*/
|
||||||
@EventHandler(priority = Byte.MAX_VALUE)
|
@EventHandler(priority = Byte.MAX_VALUE)
|
||||||
public void onPermissionCheck(PermissionCheckEvent event)
|
public void onPermissionCheck(PermissionCheckEvent event)
|
||||||
{
|
{
|
||||||
@ -37,9 +57,9 @@ public class PandalibBungeePermissions implements Listener {
|
|||||||
String world = null;
|
String world = null;
|
||||||
if (tryPermPlayerManager) {
|
if (tryPermPlayerManager) {
|
||||||
try {
|
try {
|
||||||
StandalonePlayerManager<?, ?> pm = StandalonePlayerManager.getInstance();
|
AbstractPlayerManager<?, ?> pm = AbstractPlayerManager.getInstance();
|
||||||
if (pm != null) {
|
if (pm != null) {
|
||||||
StandaloneOnlinePlayer op = pm.get(p.getUniqueId());
|
AbstractOnlinePlayer op = pm.get(p.getUniqueId());
|
||||||
if (op != null) {
|
if (op != null) {
|
||||||
world = op.getWorldName();
|
world = op.getWorldName();
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@ package fr.pandacube.lib.bungee.players;
|
|||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
|
||||||
import fr.pandacube.lib.players.standalone.StandaloneOffPlayer;
|
import fr.pandacube.lib.players.standalone.AbstractOffPlayer;
|
||||||
|
|
||||||
public interface BungeeOffPlayer extends StandaloneOffPlayer {
|
public interface BungeeOffPlayer extends AbstractOffPlayer {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Related class instances
|
* Related class instances
|
||||||
|
@ -19,11 +19,11 @@ import net.md_5.bungee.protocol.packet.ClientSettings;
|
|||||||
import net.md_5.bungee.protocol.packet.PluginMessage;
|
import net.md_5.bungee.protocol.packet.PluginMessage;
|
||||||
|
|
||||||
import fr.pandacube.lib.chat.Chat;
|
import fr.pandacube.lib.chat.Chat;
|
||||||
import fr.pandacube.lib.players.standalone.StandaloneOnlinePlayer;
|
import fr.pandacube.lib.players.standalone.AbstractOnlinePlayer;
|
||||||
import fr.pandacube.lib.reflect.Reflect;
|
import fr.pandacube.lib.reflect.Reflect;
|
||||||
import fr.pandacube.lib.util.MinecraftVersion;
|
import fr.pandacube.lib.util.MinecraftVersion;
|
||||||
|
|
||||||
public interface BungeeOnlinePlayer extends BungeeOffPlayer, StandaloneOnlinePlayer {
|
public interface BungeeOnlinePlayer extends BungeeOffPlayer, AbstractOnlinePlayer {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* General data and state
|
* General data and state
|
||||||
@ -134,7 +134,7 @@ public interface BungeeOnlinePlayer extends BungeeOffPlayer, StandaloneOnlinePla
|
|||||||
return new BungeeClientOptions(this);
|
return new BungeeClientOptions(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
class BungeeClientOptions implements StandaloneOnlinePlayer.ClientOptions {
|
class BungeeClientOptions implements AbstractOnlinePlayer.ClientOptions {
|
||||||
|
|
||||||
private final BungeeOnlinePlayer op;
|
private final BungeeOnlinePlayer op;
|
||||||
public BungeeClientOptions(BungeeOnlinePlayer op) {
|
public BungeeClientOptions(BungeeOnlinePlayer op) {
|
||||||
|
@ -4,7 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A tree structure of {@link Chat} component intended to be rendered using {@link #render(boolean)}.
|
* A tree structure of {@link Chat} component intended to be rendered in chat using {@link #render(boolean)}.
|
||||||
*/
|
*/
|
||||||
public class ChatTreeNode {
|
public class ChatTreeNode {
|
||||||
|
|
||||||
|
@ -6,91 +6,111 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|||||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import com.mojang.brigadier.context.ParsedCommandNode;
|
import com.mojang.brigadier.context.ParsedCommandNode;
|
||||||
import com.mojang.brigadier.context.StringRange;
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||||
import com.mojang.brigadier.suggestion.Suggestion;
|
|
||||||
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||||
import com.mojang.brigadier.suggestion.Suggestions;
|
|
||||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
|
||||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||||
import fr.pandacube.lib.reflect.Reflect;
|
|
||||||
import fr.pandacube.lib.util.Log;
|
import fr.pandacube.lib.util.Log;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class that holds the logic of a specific command to be integrated in a Brigadier command dispatcher.
|
* Abstract class that holds the logic of a specific command to be integrated in a Brigadier command dispatcher.
|
||||||
* Subclasses may use any mechanism to integrate this command in the environment’s Brigadier instance, during the
|
* Subclasses may use any mechanism to integrate this command in the environment’s Brigadier instance (or in a
|
||||||
* instantiation of this object.
|
* {@link BrigadierDispatcher} instance), during the instantiation of this object.
|
||||||
* @param <S> the command source (or command sender) type.
|
* @param <S> the command source (or command sender) type.
|
||||||
*/
|
*/
|
||||||
public abstract class BrigadierCommand<S> {
|
public abstract class BrigadierCommand<S> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a builder for this command.
|
||||||
|
* Concrete class should include any element in the builder that is needed to build the command (sub-commands and
|
||||||
|
* arguments, requirements, redirection, ...).
|
||||||
|
* If any of the sub-commands and arguments needs to know the {@link LiteralCommandNode} builded from the returned
|
||||||
|
* {@link LiteralArgumentBuilder}, this can be done by overriding {@link #postBuildCommand(LiteralCommandNode)}.
|
||||||
|
* @return a builder for this command.
|
||||||
|
*/
|
||||||
protected abstract LiteralArgumentBuilder<S> buildCommand();
|
protected abstract LiteralArgumentBuilder<S> buildCommand();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to implement if the reference to the command node has to be known when building the subcommands.
|
* Method to override if the reference to the command node has to be known when building the subcommands.
|
||||||
* @param commandNode the command node builded from {@link #buildCommand()}.
|
* @param commandNode the command node builded from {@link #buildCommand()}.
|
||||||
*/
|
*/
|
||||||
protected void postBuildCommand(LiteralCommandNode<S> commandNode) {
|
protected void postBuildCommand(LiteralCommandNode<S> commandNode) {
|
||||||
// default implementation does nothing.
|
// default implementation does nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to override if this command have any aliases.
|
||||||
|
* @return an array of string corresponding to the aliases. This must not include the orignal command name (that
|
||||||
|
* is the name of the literal command node builded from {@link #buildCommand()}).
|
||||||
|
*/
|
||||||
protected String[] getAliases() {
|
protected String[] getAliases() {
|
||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link LiteralArgumentBuilder} that has the provided name.
|
||||||
|
* @param name the name of the command node.
|
||||||
|
* @return a new {@link LiteralArgumentBuilder} that has the provided name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public LiteralArgumentBuilder<S> literal(String name) {
|
public LiteralArgumentBuilder<S> literal(String name) {
|
||||||
return LiteralArgumentBuilder.literal(name);
|
return LiteralArgumentBuilder.literal(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link RequiredArgumentBuilder} that has the provided name.
|
||||||
|
* @param name the name of the command node.
|
||||||
|
* @param type the type of the argument.
|
||||||
|
* @param <T> the argument type.
|
||||||
|
* @return a new {@link RequiredArgumentBuilder} that has the provided name.
|
||||||
|
*/
|
||||||
public <T> RequiredArgumentBuilder<S, T> argument(String name, ArgumentType<T> type) {
|
public <T> RequiredArgumentBuilder<S, T> argument(String name, ArgumentType<T> type) {
|
||||||
return RequiredArgumentBuilder.argument(name, type);
|
return RequiredArgumentBuilder.argument(name, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if the provided command sender is a player.
|
||||||
|
* @param sender the sender to test if it’s a player or not.
|
||||||
|
* @return true if the sender is a player, false otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
public abstract boolean isPlayer(S sender);
|
public abstract boolean isPlayer(S sender);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if the provided command sender is the console.
|
||||||
|
* @param sender the sender to test if it’s the console or not.
|
||||||
|
* @return true if the sender is the console, false otherwise.
|
||||||
|
*/
|
||||||
public abstract boolean isConsole(S sender);
|
public abstract boolean isConsole(S sender);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a {@link Predicate} that tests if the command sender is a player.
|
||||||
|
* @return a {@link Predicate} that tests if the command sender is a player.
|
||||||
|
* @see #isPlayer(Object)
|
||||||
|
*/
|
||||||
public Predicate<S> isPlayer() {
|
public Predicate<S> isPlayer() {
|
||||||
return this::isPlayer;
|
return this::isPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a {@link Predicate} that tests if the command sender is the console.
|
||||||
|
* @return a {@link Predicate} that tests if the command sender is the console.
|
||||||
|
* @see #isConsole(Object)
|
||||||
|
*/
|
||||||
public Predicate<S> isConsole() {
|
public Predicate<S> isConsole() {
|
||||||
return this::isConsole;
|
return this::isConsole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a {@link Predicate} that tests if the command sender has the provided permission.
|
||||||
|
* @param permission the permission tested by the returned predicate on the command sender.
|
||||||
|
* @return a {@link Predicate} that tests if the command sender has the provided permission.
|
||||||
|
*/
|
||||||
public abstract Predicate<S> hasPermission(String permission);
|
public abstract Predicate<S> hasPermission(String permission);
|
||||||
|
|
||||||
|
|
||||||
@ -99,8 +119,15 @@ public abstract class BrigadierCommand<S> {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the literal node is found in the command.
|
||||||
|
* <p>
|
||||||
|
* <b>Be aware that this method search even beyond any fork or redirection, so it may encounter literal nodes that
|
||||||
|
* have the provided name but belong to other commands, so it can produce a false positive.</b>
|
||||||
|
* @param context the context of the command execution.
|
||||||
|
* @param literal the literal command node to search for in the typed command.
|
||||||
|
* @return true if the provided literal is in the typed command, false otherwise.
|
||||||
|
*/
|
||||||
public static boolean isLiteralParsed(CommandContext<?> context, String literal) {
|
public static boolean isLiteralParsed(CommandContext<?> context, String literal) {
|
||||||
for (ParsedCommandNode<?> node : context.getNodes()) {
|
for (ParsedCommandNode<?> node : context.getNodes()) {
|
||||||
if (node.getNode() instanceof LiteralCommandNode<?> lNode
|
if (node.getNode() instanceof LiteralCommandNode<?> lNode
|
||||||
@ -111,24 +138,60 @@ public abstract class BrigadierCommand<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the argument value from the provided context, silently returning null (instead of throwing an exception)
|
||||||
|
* if the argument is not found.
|
||||||
|
* @param context the context of the command execution.
|
||||||
|
* @param argument the argument to search for.
|
||||||
|
* @param type the type of the argument.
|
||||||
|
* @param <T> the argument type.
|
||||||
|
* @return the value of the argument, or null if not found.
|
||||||
|
*/
|
||||||
public static <T> T tryGetArgument(CommandContext<?> context, String argument, Class<T> type) {
|
public static <T> T tryGetArgument(CommandContext<?> context, String argument, Class<T> type) {
|
||||||
return tryGetArgument(context, argument, type, Function.identity(), null);
|
return tryGetArgument(context, argument, type, Function.identity(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <ST, T> T tryGetArgument(CommandContext<?> context, String argument, Class<ST> sourceType, Function<ST, T> transformIfFound) {
|
/**
|
||||||
return tryGetArgument(context, argument, sourceType, transformIfFound, null);
|
* Gets the argument value from the provided context, silently returning a default value (instead of throwing an
|
||||||
}
|
* exception) if the argument is not found.
|
||||||
|
* @param context the context of the command execution.
|
||||||
|
* @param argument the argument to search for.
|
||||||
|
* @param type the type of the argument.
|
||||||
|
* @param deflt the default value if not found.
|
||||||
|
* @param <T> the argument type.
|
||||||
|
* @return the value of the argument, or {@code deflt} if not found.
|
||||||
|
*/
|
||||||
public static <T> T tryGetArgument(CommandContext<?> context, String argument, Class<T> type, T deflt) {
|
public static <T> T tryGetArgument(CommandContext<?> context, String argument, Class<T> type, T deflt) {
|
||||||
return tryGetArgument(context, argument, type, Function.identity(), deflt);
|
return tryGetArgument(context, argument, type, Function.identity(), deflt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the argument value from the provided context and transform it using the provided function, or silently
|
||||||
|
* returning null (instead of throwing an exception) if the argument is not found.
|
||||||
|
* @param context the context of the command execution.
|
||||||
|
* @param argument the argument to search for.
|
||||||
|
* @param sourceType the type of the argument in the command context.
|
||||||
|
* @param transformIfFound the function to transform the argument value before returning.
|
||||||
|
* @param <ST> the argument type in the command context.
|
||||||
|
* @param <T> the returned type.
|
||||||
|
* @return the value of the argument, transformed by {@code transformIfFound}, or null if not found.
|
||||||
|
*/
|
||||||
|
public static <ST, T> T tryGetArgument(CommandContext<?> context, String argument, Class<ST> sourceType, Function<ST, T> transformIfFound) {
|
||||||
|
return tryGetArgument(context, argument, sourceType, transformIfFound, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the argument value from the provided context and transform it using the provided function, or silently
|
||||||
|
* returning a default value (instead of throwing an exception) if the argument is not found.
|
||||||
|
* @param context the context of the command execution.
|
||||||
|
* @param argument the argument to search for.
|
||||||
|
* @param sourceType the type of the argument in the command context.
|
||||||
|
* @param transformIfFound the function to transform the argument value before returning.
|
||||||
|
* @param deflt the default value if not found.
|
||||||
|
* @param <ST> the argument type in the command context.
|
||||||
|
* @param <T> the returned type.
|
||||||
|
* @return the value of the argument, transformed by {@code transformIfFound}, or {@code deflt} if not found.
|
||||||
|
*/
|
||||||
public static <ST, T> T tryGetArgument(CommandContext<?> context, String argument, Class<ST> sourceType, Function<ST, T> transformIfFound, T deflt) {
|
public static <ST, T> T tryGetArgument(CommandContext<?> context, String argument, Class<ST> sourceType, Function<ST, T> transformIfFound, T deflt) {
|
||||||
ST sourceValue;
|
ST sourceValue;
|
||||||
try {
|
try {
|
||||||
@ -140,25 +203,25 @@ public abstract class BrigadierCommand<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of {@link CommandSyntaxException} with the provided message.
|
||||||
|
* @param message the exception message.
|
||||||
|
* @return a new instance of {@link CommandSyntaxException} with the provided message.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static CommandSyntaxException newCommandException(String message) {
|
public static CommandSyntaxException newCommandException(String message) {
|
||||||
return new SimpleCommandExceptionType(new LiteralMessage(message)).create();
|
return new SimpleCommandExceptionType(new LiteralMessage(message)).create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the provided {@link SuggestionsSupplier} into a Brigadier’s {@link SuggestionProvider}.
|
||||||
|
* @param suggestions the suggestions to wrap.
|
||||||
|
* @param senderUnwrapper function to convert the command sender provided by brigadier into the command sender
|
||||||
|
* supported by {@link SuggestionsSupplier}.
|
||||||
|
* @return a {@link SuggestionProvider} generating the suggestions from the provided {@link SuggestionsSupplier}.
|
||||||
|
* @param <AS> the type of command sender supported by the {@link SuggestionsSupplier}.
|
||||||
|
*/
|
||||||
protected <AS> SuggestionProvider<S> wrapSuggestions(SuggestionsSupplier<AS> suggestions, Function<S, AS> senderUnwrapper) {
|
protected <AS> SuggestionProvider<S> wrapSuggestions(SuggestionsSupplier<AS> suggestions, Function<S, AS> senderUnwrapper) {
|
||||||
return (context, builder) -> {
|
return (context, builder) -> {
|
||||||
AS sender = senderUnwrapper.apply(context.getSource());
|
AS sender = senderUnwrapper.apply(context.getSource());
|
||||||
|
@ -11,28 +11,41 @@ import net.kyori.adventure.text.ComponentLike;
|
|||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class that holds a Brigadier {@link CommandDispatcher} instance.
|
||||||
|
* Subclasses contains logic to integrate this commands dispatcher into their environment (like Bungee or CLI app).
|
||||||
|
* @param <S> the command source (or command sender) type.
|
||||||
|
*/
|
||||||
public abstract class BrigadierDispatcher<S> {
|
public abstract class BrigadierDispatcher<S> {
|
||||||
|
|
||||||
|
|
||||||
private final CommandDispatcher<S> dispatcher = new CommandDispatcher<>();
|
private final CommandDispatcher<S> dispatcher = new CommandDispatcher<>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the provided command node into this dispatcher.
|
||||||
|
* @param node the node to register.
|
||||||
|
*/
|
||||||
public void register(LiteralCommandNode<S> node) {
|
public void register(LiteralCommandNode<S> node) {
|
||||||
dispatcher.getRoot().addChild(node);
|
dispatcher.getRoot().addChild(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Brigadier dispatcher.
|
||||||
|
* @return the Brigadier dispatcher.
|
||||||
|
*/
|
||||||
public CommandDispatcher<S> getDispatcher() {
|
public CommandDispatcher<S> getDispatcher() {
|
||||||
return dispatcher;
|
return dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the provided command as the provided sender.
|
||||||
|
* @param sender the command sender.
|
||||||
|
* @param commandWithoutSlash the command, without the eventual slash at the begining.
|
||||||
|
* @return the value returned by the executed command.
|
||||||
|
*/
|
||||||
public int execute(S sender, String commandWithoutSlash) {
|
public int execute(S sender, String commandWithoutSlash) {
|
||||||
ParseResults<S> parsed = dispatcher.parse(commandWithoutSlash, sender);
|
ParseResults<S> parsed = dispatcher.parse(commandWithoutSlash, sender);
|
||||||
|
|
||||||
@ -46,11 +59,15 @@ public abstract class BrigadierDispatcher<S> {
|
|||||||
Log.severe(e);
|
Log.severe(e);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the suggestions for the currenlty being typed command.
|
||||||
|
* @param sender the command sender.
|
||||||
|
* @param buffer the command that is being typed.
|
||||||
|
* @return the suggestions for the currenlty being typed command.
|
||||||
|
*/
|
||||||
public Suggestions getSuggestions(S sender, String buffer) {
|
public Suggestions getSuggestions(S sender, String buffer) {
|
||||||
ParseResults<S> parsed = dispatcher.parse(buffer, sender);
|
ParseResults<S> parsed = dispatcher.parse(buffer, sender);
|
||||||
try {
|
try {
|
||||||
@ -64,10 +81,11 @@ public abstract class BrigadierDispatcher<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the provided message to the sender.
|
||||||
|
* @param sender the sender to send the message to.
|
||||||
|
* @param message the message to send.
|
||||||
|
*/
|
||||||
protected abstract void sendSenderMessage(S sender, ComponentLike message);
|
protected abstract void sendSenderMessage(S sender, ComponentLike message);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package fr.pandacube.lib.commands;
|
package fr.pandacube.lib.commands;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.mojang.brigadier.ParseResults;
|
import com.mojang.brigadier.ParseResults;
|
||||||
import com.mojang.brigadier.context.CommandContextBuilder;
|
import com.mojang.brigadier.context.CommandContextBuilder;
|
||||||
import com.mojang.brigadier.context.StringRange;
|
import com.mojang.brigadier.context.StringRange;
|
||||||
@ -22,7 +23,16 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
public class BrigadierSuggestionsUtil {
|
public class BrigadierSuggestionsUtil {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets suggestions with the provided parsed command.
|
||||||
|
* <p>
|
||||||
|
* This is a reimplementation of {@link CommandDispatcher#getCompletionSuggestions(ParseResults, int)} that
|
||||||
|
* keeps the original ordering of the suggestions.
|
||||||
|
* @param parsed the parsed command.
|
||||||
|
* @return the suggestions.
|
||||||
|
* @param <S> the sender type.
|
||||||
|
* @see CommandDispatcher#getCompletionSuggestions(ParseResults, int)
|
||||||
|
*/
|
||||||
public static <S> CompletableFuture<Suggestions> buildSuggestionBrigadier(ParseResults<S> parsed) {
|
public static <S> CompletableFuture<Suggestions> buildSuggestionBrigadier(ParseResults<S> parsed) {
|
||||||
int cursor = parsed.getReader().getTotalLength();
|
int cursor = parsed.getReader().getTotalLength();
|
||||||
final CommandContextBuilder<S> context = parsed.getContext();
|
final CommandContextBuilder<S> context = parsed.getContext();
|
||||||
@ -55,7 +65,17 @@ public class BrigadierSuggestionsUtil {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// inspired from com.mojang.brigadier.suggestion.Suggestions#merge, but without the sorting part
|
|
||||||
|
/**
|
||||||
|
* Merges the provided {@link Suggestions}.
|
||||||
|
* <p>
|
||||||
|
* This is a reimplementation of {@link Suggestions#merge(String, Collection)} that keeps the original ordering of
|
||||||
|
* the suggestions.
|
||||||
|
* @param input the command on which are based the suggestions.
|
||||||
|
* @param suggestions the {@link Suggestions} to merge.
|
||||||
|
* @return a {@link Suggestions}.
|
||||||
|
* @see Suggestions#create(String, Collection)
|
||||||
|
*/
|
||||||
public static Suggestions mergeSuggestionsOriginalOrdering(String input, Collection<Suggestions> suggestions) {
|
public static Suggestions mergeSuggestionsOriginalOrdering(String input, Collection<Suggestions> suggestions) {
|
||||||
if (suggestions.isEmpty()) {
|
if (suggestions.isEmpty()) {
|
||||||
return new Suggestions(StringRange.at(0), new ArrayList<>(0));
|
return new Suggestions(StringRange.at(0), new ArrayList<>(0));
|
||||||
@ -72,8 +92,16 @@ public class BrigadierSuggestionsUtil {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
// inspired from com.mojang.brigadier.suggestion.Suggestions#create, but without the sorting part
|
* Creates a {@link Suggestions} from the provided Collection of {@link Suggestion}.
|
||||||
|
* <p>
|
||||||
|
* This is a reimplementation of {@link Suggestions#create(String, Collection)} that keeps the original ordering of
|
||||||
|
* the suggestions.
|
||||||
|
* @param command the command on which are based the suggestions.
|
||||||
|
* @param suggestions the Collection of {@link Suggestion}.
|
||||||
|
* @return a {@link Suggestions}.
|
||||||
|
* @see Suggestions#create(String, Collection)
|
||||||
|
*/
|
||||||
public static Suggestions createSuggestionsOriginalOrdering(String command, Collection<Suggestion> suggestions) {
|
public static Suggestions createSuggestionsOriginalOrdering(String command, Collection<Suggestion> suggestions) {
|
||||||
if (suggestions.isEmpty()) {
|
if (suggestions.isEmpty()) {
|
||||||
return new Suggestions(StringRange.at(0), new ArrayList<>(0));
|
return new Suggestions(StringRange.at(0), new ArrayList<>(0));
|
||||||
@ -96,7 +124,7 @@ public class BrigadierSuggestionsUtil {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static CompletableFuture<Suggestions> completableFutureSuggestionsKeepsOriginalOrdering(SuggestionsBuilder builder) {
|
/* package */ static CompletableFuture<Suggestions> completableFutureSuggestionsKeepsOriginalOrdering(SuggestionsBuilder builder) {
|
||||||
return CompletableFuture.completedFuture(
|
return CompletableFuture.completedFuture(
|
||||||
createSuggestionsOriginalOrdering(builder.getInput(), getSuggestionsFromSuggestionsBuilder(builder))
|
createSuggestionsOriginalOrdering(builder.getInput(), getSuggestionsFromSuggestionsBuilder(builder))
|
||||||
);
|
);
|
||||||
|
@ -19,6 +19,11 @@
|
|||||||
<artifactId>pandalib-util</artifactId>
|
<artifactId>pandalib-util</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>fr.pandacube.lib</groupId>
|
||||||
|
<artifactId>pandalib-reflect</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-dbcp2</artifactId>
|
<artifactId>commons-dbcp2</artifactId>
|
||||||
|
@ -14,6 +14,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import fr.pandacube.lib.reflect.Reflect;
|
||||||
import fr.pandacube.lib.util.Log;
|
import fr.pandacube.lib.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -576,7 +577,7 @@ public final class DB {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static <E extends SQLElement<E>> E getElementInstance(ResultSet set, Class<E> elemClass) throws DBException {
|
private static <E extends SQLElement<E>> E getElementInstance(ResultSet set, Class<E> elemClass) throws DBException {
|
||||||
try {
|
try {
|
||||||
E instance = elemClass.getConstructor(int.class).newInstance(set.getInt("id"));
|
E instance = Reflect.ofClass(elemClass).constructor(int.class).instanciate(set.getInt("id"));
|
||||||
|
|
||||||
int fieldCount = set.getMetaData().getColumnCount();
|
int fieldCount = set.getMetaData().getColumnCount();
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ import java.util.concurrent.ExecutionException;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import fr.pandacube.lib.db.DB;
|
||||||
|
import fr.pandacube.lib.db.DBConnection;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@ -23,12 +25,26 @@ import org.bukkit.plugin.java.JavaPlugin;
|
|||||||
import fr.pandacube.lib.permissions.Permissions;
|
import fr.pandacube.lib.permissions.Permissions;
|
||||||
import fr.pandacube.lib.util.Log;
|
import fr.pandacube.lib.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that integrates the {@code pandalib-permissions} system into a Bukkit/Spigot/Paper instance.
|
||||||
|
* The integration is made when calling {@link #init(JavaPlugin, String)}.
|
||||||
|
* The permission system must be initialized first, using {@link Permissions#init(Function)}.
|
||||||
|
* Don’t forget that the permission system also needs a connection to a database, so don’t forget to call
|
||||||
|
* {@link DB#init(DBConnection, String)} with the appropriate parameters before anything.
|
||||||
|
*/
|
||||||
public class PandalibPaperPermissions implements Listener {
|
public class PandalibPaperPermissions implements Listener {
|
||||||
|
|
||||||
/* package */ static JavaPlugin plugin;
|
/* package */ static JavaPlugin plugin;
|
||||||
/* package */ static String serverName;
|
/* package */ static String serverName;
|
||||||
/* package */ static final Map<String, String> permissionMap = new HashMap<>();
|
/* package */ static final Map<String, String> permissionMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integrates the {@code pandalib-permissions} system into the Bukkit server.
|
||||||
|
* @param plugin a Bukkit plugin.
|
||||||
|
* @param serverName the name of the current server, used to fetch server specific permissions. Cannot be null.
|
||||||
|
* If this server in not in a multi-server configuration, use a dummy server name, like
|
||||||
|
* {@code ""} (empty string).
|
||||||
|
*/
|
||||||
public static void init(JavaPlugin plugin, String serverName) {
|
public static void init(JavaPlugin plugin, String serverName) {
|
||||||
PandalibPaperPermissions.plugin = plugin;
|
PandalibPaperPermissions.plugin = plugin;
|
||||||
PandalibPaperPermissions.serverName = serverName;
|
PandalibPaperPermissions.serverName = serverName;
|
||||||
@ -58,6 +74,10 @@ public class PandalibPaperPermissions implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Player login event handler.
|
||||||
|
* @param event the event.
|
||||||
|
*/
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||||
Permissions.clearPlayerCache(event.getPlayer().getUniqueId());
|
Permissions.clearPlayerCache(event.getPlayer().getUniqueId());
|
||||||
@ -67,6 +87,10 @@ public class PandalibPaperPermissions implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Player quit event handler.
|
||||||
|
* @param event the event.
|
||||||
|
*/
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
PermissionsInjectorBukkit.uninject(event.getPlayer());
|
PermissionsInjectorBukkit.uninject(event.getPlayer());
|
||||||
|
@ -29,7 +29,7 @@ import fr.pandacube.lib.permissions.Permissions;
|
|||||||
import fr.pandacube.lib.reflect.Reflect;
|
import fr.pandacube.lib.reflect.Reflect;
|
||||||
import fr.pandacube.lib.util.Log;
|
import fr.pandacube.lib.util.Log;
|
||||||
|
|
||||||
public class PermissionsInjectorBukkit
|
/* package */ class PermissionsInjectorBukkit
|
||||||
{
|
{
|
||||||
|
|
||||||
// to be called : onEnable for console, onPlayerLogin (not Join) (Priority LOWEST) for players
|
// to be called : onEnable for console, onPlayerLogin (not Join) (Priority LOWEST) for players
|
||||||
|
@ -10,7 +10,7 @@ import fr.pandacube.lib.permissions.PermGroup;
|
|||||||
import fr.pandacube.lib.permissions.Permissions;
|
import fr.pandacube.lib.permissions.Permissions;
|
||||||
import fr.pandacube.lib.util.Log;
|
import fr.pandacube.lib.util.Log;
|
||||||
|
|
||||||
public class PermissionsInjectorVault {
|
/* package */ class PermissionsInjectorVault {
|
||||||
|
|
||||||
public static PandaVaultPermission permInstance;
|
public static PandaVaultPermission permInstance;
|
||||||
|
|
||||||
@ -27,12 +27,12 @@ public class PermissionsInjectorVault {
|
|||||||
Log.warning("Vault plugin not detected. Not using it to provide permissions and prefix/suffix." + e.getMessage());
|
Log.warning("Vault plugin not detected. Not using it to provide permissions and prefix/suffix." + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static class PandaVaultPermission extends net.milkbowl.vault.permission.Permission {
|
/* package */ static class PandaVaultPermission extends net.milkbowl.vault.permission.Permission {
|
||||||
|
|
||||||
private PandaVaultPermission() { }
|
private PandaVaultPermission() { }
|
||||||
|
|
||||||
|
@ -13,13 +13,11 @@ import fr.pandacube.lib.permissions.PermPlayer;
|
|||||||
import fr.pandacube.lib.permissions.Permissions;
|
import fr.pandacube.lib.permissions.Permissions;
|
||||||
import fr.pandacube.lib.util.Log;
|
import fr.pandacube.lib.util.Log;
|
||||||
|
|
||||||
public class PermissionsInjectorWEPIF {
|
/* package */ class PermissionsInjectorWEPIF {
|
||||||
|
|
||||||
public static PandaWEPIFPermissionsProvider permInstance;
|
|
||||||
|
|
||||||
public static void inject() {
|
public static void inject() {
|
||||||
try {
|
try {
|
||||||
permInstance = new PandaWEPIFPermissionsProvider();
|
PandaWEPIFPermissionsProvider permInstance = new PandaWEPIFPermissionsProvider();
|
||||||
Bukkit.getServicesManager().register(com.sk89q.wepif.PermissionsProvider.class, permInstance,
|
Bukkit.getServicesManager().register(com.sk89q.wepif.PermissionsProvider.class, permInstance,
|
||||||
PandalibPaperPermissions.plugin, ServicePriority.Highest);
|
PandalibPaperPermissions.plugin, ServicePriority.Highest);
|
||||||
Log.info("Providing permissions through WEPIF");
|
Log.info("Providing permissions through WEPIF");
|
||||||
@ -32,11 +30,11 @@ public class PermissionsInjectorWEPIF {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static class PandaWEPIFPermissionsProvider implements com.sk89q.wepif.PermissionsProvider {
|
/* package */ static class PandaWEPIFPermissionsProvider implements com.sk89q.wepif.PermissionsProvider {
|
||||||
private PandaWEPIFPermissionsProvider() { }
|
private PandaWEPIFPermissionsProvider() { }
|
||||||
|
|
||||||
private PermPlayer getPlayer(OfflinePlayer player) {
|
private PermPlayer getPlayer(OfflinePlayer player) {
|
||||||
|
@ -5,9 +5,9 @@ import org.bukkit.OfflinePlayer;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.scoreboard.Team;
|
import org.bukkit.scoreboard.Team;
|
||||||
|
|
||||||
import fr.pandacube.lib.players.standalone.StandaloneOffPlayer;
|
import fr.pandacube.lib.players.standalone.AbstractOffPlayer;
|
||||||
|
|
||||||
public interface PaperOffPlayer extends StandaloneOffPlayer {
|
public interface PaperOffPlayer extends AbstractOffPlayer {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* General data and state
|
* General data and state
|
||||||
|
@ -21,9 +21,9 @@ import org.bukkit.entity.LivingEntity;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.MainHand;
|
import org.bukkit.inventory.MainHand;
|
||||||
|
|
||||||
import fr.pandacube.lib.players.standalone.StandaloneOnlinePlayer;
|
import fr.pandacube.lib.players.standalone.AbstractOnlinePlayer;
|
||||||
|
|
||||||
public interface PaperOnlinePlayer extends PaperOffPlayer, StandaloneOnlinePlayer {
|
public interface PaperOnlinePlayer extends PaperOffPlayer, AbstractOnlinePlayer {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* General data and state
|
* General data and state
|
||||||
@ -119,7 +119,7 @@ public interface PaperOnlinePlayer extends PaperOffPlayer, StandaloneOnlinePlaye
|
|||||||
@Override
|
@Override
|
||||||
PaperClientOptions getClientOptions();
|
PaperClientOptions getClientOptions();
|
||||||
|
|
||||||
abstract class PaperClientOptions implements StandaloneOnlinePlayer.ClientOptions {
|
abstract class PaperClientOptions implements AbstractOnlinePlayer.ClientOptions {
|
||||||
|
|
||||||
private final PaperOnlinePlayer op;
|
private final PaperOnlinePlayer op;
|
||||||
|
|
||||||
|
@ -16,6 +16,6 @@ public class ServerChunkCache extends ReflectWrapper {
|
|||||||
protected ServerChunkCache(Object obj) {
|
protected ServerChunkCache(Object obj) {
|
||||||
super(obj);
|
super(obj);
|
||||||
|
|
||||||
chunkMap = wrap(wrapReflectEx(() -> FIELD_chunkMap.getValue(obj)));
|
chunkMap = wrap(wrapReflectEx(() -> FIELD_chunkMap.getValue(obj)), ChunkMap.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,13 +65,14 @@
|
|||||||
<exclude>META-INF/*.SF</exclude>
|
<exclude>META-INF/*.SF</exclude>
|
||||||
<exclude>META-INF/*.DSA</exclude>
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
<exclude>META-INF/*.RSA</exclude>
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
|
<exclude>META-INF/MANIFEDT.MF</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
</filter>
|
</filter>
|
||||||
</filters>
|
</filters>
|
||||||
<relocations>
|
<relocations>
|
||||||
<relocation>
|
<relocation>
|
||||||
<pattern>com.fathzer.soft.javaluator</pattern>
|
<pattern>com.fathzer.soft.javaluator</pattern>
|
||||||
<shadedPattern>fr.pandacube.shaded.javaluator</shadedPattern>
|
<shadedPattern>fr.pandacube.lib.permissions.shaded.javaluator</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
</relocations>
|
</relocations>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
@ -8,98 +8,219 @@ import java.util.Set;
|
|||||||
import java.util.stream.LongStream;
|
import java.util.stream.LongStream;
|
||||||
|
|
||||||
import fr.pandacube.lib.chat.ChatTreeNode;
|
import fr.pandacube.lib.chat.ChatTreeNode;
|
||||||
|
import fr.pandacube.lib.permissions.PermissionExpressionParser.LitteralPermissionTester;
|
||||||
import fr.pandacube.lib.permissions.PermissionsCachedBackendReader.CachedEntity;
|
import fr.pandacube.lib.permissions.PermissionsCachedBackendReader.CachedEntity;
|
||||||
import fr.pandacube.lib.permissions.SQLPermissions.EntityType;
|
import fr.pandacube.lib.permissions.SQLPermissions.EntityType;
|
||||||
import fr.pandacube.lib.util.Log;
|
import fr.pandacube.lib.util.Log;
|
||||||
|
|
||||||
public abstract class PermEntity {
|
/**
|
||||||
protected final String name;
|
* Represents an entity in the permission system, either a group or a player.
|
||||||
protected final EntityType type;
|
*/
|
||||||
protected PermEntity(String n, EntityType t) {
|
public sealed abstract class PermEntity permits PermPlayer, PermGroup {
|
||||||
|
/* package */ final String name;
|
||||||
|
/* package */ final EntityType type;
|
||||||
|
/* package */ PermEntity(String n, EntityType t) {
|
||||||
name = n; type = t;
|
name = n; type = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract CachedEntity getBackendEntity();
|
/* package */ abstract CachedEntity getBackendEntity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the groups this entity inherits from.
|
||||||
|
* @return a list of all the groups this entity inherits from.
|
||||||
|
*/
|
||||||
public abstract List<PermGroup> getInheritances();
|
public abstract List<PermGroup> getInheritances();
|
||||||
|
/**
|
||||||
|
* Gets all the group names this entity inherits from.
|
||||||
|
* @return a list of all the group names this entity inherits from.
|
||||||
|
*/
|
||||||
public abstract List<String> getInheritancesString();
|
public abstract List<String> getInheritancesString();
|
||||||
|
/**
|
||||||
|
* Gets the name of this entity.
|
||||||
|
* @return the name of this entity.
|
||||||
|
*/
|
||||||
public abstract String getName();
|
public abstract String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of this entity, as it is stored in the database.
|
||||||
|
* @return the name of this entity, as it is stored in the database.
|
||||||
|
*/
|
||||||
public String getInternalName() {
|
public String getInternalName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if the current entity inherits directly or indirectly from the specified group
|
* Tells if the current entity inherits directly or indirectly from the specified group.
|
||||||
* @param group the group to search for
|
* @param group the group to search for
|
||||||
* @param recursive true to search in the inheritance tree, or false to search only in the inheritance list of the current entity.
|
* @param recursive true to search in the inheritance tree, or false to search only in the inheritance list of the current entity.
|
||||||
|
* @return true if the current entity inherits directly or indirectly from the specified group, false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean inheritsFromGroup(String group, boolean recursive) {
|
public boolean inheritsFromGroup(String group, boolean recursive) {
|
||||||
if (group == null)
|
if (group == null)
|
||||||
return false;
|
return false;
|
||||||
return getInheritances().stream().anyMatch(g -> g.name.equals(group) || (recursive && g.inheritsFromGroup(group, true)));
|
return getInheritances().stream().anyMatch(g -> g.name.equals(group) || (recursive && g.inheritsFromGroup(group, true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the effective prefix of this entity.
|
||||||
|
* It is either the prefix defined directly for this entity, or from inheritance.
|
||||||
|
* @return the effective prefix of this entity.
|
||||||
|
*/
|
||||||
public String getPrefix() {
|
public String getPrefix() {
|
||||||
return Permissions.resolver.getEffectivePrefix(name, type);
|
return Permissions.resolver.getEffectivePrefix(name, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the prefix defined directly for this entity.
|
||||||
|
* @return the prefix defined directly for this entity.
|
||||||
|
*/
|
||||||
public String getSelfPrefix() {
|
public String getSelfPrefix() {
|
||||||
return getBackendEntity().getSelfPrefix();
|
return getBackendEntity().getSelfPrefix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides informations on how the effective prefix of this entity is determined.
|
||||||
|
* @return a {@link ChatTreeNode} providing informations on how the effective prefix of this entity is determined.
|
||||||
|
*/
|
||||||
public ChatTreeNode debugPrefix() {
|
public ChatTreeNode debugPrefix() {
|
||||||
return Permissions.resolver.debugPrefix(name, type);
|
return Permissions.resolver.debugPrefix(name, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the prefix of this entity.
|
||||||
|
* @param prefix the prefix for this entity.
|
||||||
|
*/
|
||||||
public void setSelfPrefix(String prefix) {
|
public void setSelfPrefix(String prefix) {
|
||||||
Permissions.backendWriter.setSelfPrefix(name, type, prefix);
|
Permissions.backendWriter.setSelfPrefix(name, type, prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the effective suffix of this entity.
|
||||||
|
* It is either the suffix defined directly for this entity, or from inheritance.
|
||||||
|
* @return the effective suffix of this entity.
|
||||||
|
*/
|
||||||
public String getSuffix() {
|
public String getSuffix() {
|
||||||
return Permissions.resolver.getEffectiveSuffix(name, type);
|
return Permissions.resolver.getEffectiveSuffix(name, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the suffix defined directly for this entity.
|
||||||
|
* @return the suffix defined directly for this entity.
|
||||||
|
*/
|
||||||
public String getSelfSuffix() {
|
public String getSelfSuffix() {
|
||||||
return getBackendEntity().getSelfSuffix();
|
return getBackendEntity().getSelfSuffix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides informations on how the effective suffix of this entity is determined.
|
||||||
|
* @return a {@link ChatTreeNode} providing informations on how the effective suffix of this entity is determined.
|
||||||
|
*/
|
||||||
public ChatTreeNode debugSuffix() {
|
public ChatTreeNode debugSuffix() {
|
||||||
return Permissions.resolver.debugSuffix(name, type);
|
return Permissions.resolver.debugSuffix(name, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the suffix of this entity.
|
||||||
|
* @param suffix the suffix for this entity.
|
||||||
|
*/
|
||||||
public void setSelfSuffix(String suffix) {
|
public void setSelfSuffix(String suffix) {
|
||||||
Permissions.backendWriter.setSelfSuffix(name, type, suffix);
|
Permissions.backendWriter.setSelfSuffix(name, type, suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the effective list of permissions that applies to this entity out of a specific server and world.
|
||||||
|
* It is either the permissions defined directly for this entity, or from inheritance as long as they are not
|
||||||
|
* overriden.
|
||||||
|
* @return the effective list of permissions that applies to this entity out of a specific server and world.
|
||||||
|
*/
|
||||||
public Map<String, Boolean> listEffectivePermissions() {
|
public Map<String, Boolean> listEffectivePermissions() {
|
||||||
return listEffectivePermissions(null, null);
|
return listEffectivePermissions(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the effective list of permissions that applies to this entity on a specific server.
|
||||||
|
* It is either the permissions defined directly for this entity, or from inheritance as long as they are not
|
||||||
|
* overriden.
|
||||||
|
* @param server the server where the returned permissions apply for this entity.
|
||||||
|
* @return the effective list of permissions that applies to this entity on a specific server.
|
||||||
|
*/
|
||||||
public Map<String, Boolean> listEffectivePermissions(String server) {
|
public Map<String, Boolean> listEffectivePermissions(String server) {
|
||||||
return listEffectivePermissions(server, null);
|
return listEffectivePermissions(server, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the effective list of permissions that applies to this entity on a specific server and world.
|
||||||
|
* It is either the permissions defined directly for this entity, or from inheritance as long as they are not
|
||||||
|
* overriden.
|
||||||
|
* @param server the server containing the world where the returned permissions apply for this entity.
|
||||||
|
* @param world the world in the server where the returned permissions apply for this entity.
|
||||||
|
* @return the effective list of permissions that applies to this entity on a specific server and world.
|
||||||
|
*/
|
||||||
public Map<String, Boolean> listEffectivePermissions(String server, String world) {
|
public Map<String, Boolean> listEffectivePermissions(String server, String world) {
|
||||||
return Permissions.resolver.getEffectivePermissionList(name, type, server, world);
|
return Permissions.resolver.getEffectivePermissionList(name, type, server, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the effective values of the provided permission range prefix that applies to this entity out of a specific
|
||||||
|
* server and world.
|
||||||
|
* It is either the range values defined directly for this entity, or from inheritance as long as they are not
|
||||||
|
* overriden.
|
||||||
|
* @param permissionPrefix the permission range prefix.
|
||||||
|
* @return the effective values of the provided permission range prefix that applies to this entity out of a
|
||||||
|
* specific server and world.
|
||||||
|
*/
|
||||||
public LongStream getPermissionRangeValues(String permissionPrefix) {
|
public LongStream getPermissionRangeValues(String permissionPrefix) {
|
||||||
return getPermissionRangeValues(permissionPrefix, null, null);
|
return getPermissionRangeValues(permissionPrefix, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the effective values of the provided permission range prefix that applies to this entity on a specific
|
||||||
|
* server.
|
||||||
|
* It is either the range values defined directly for this entity, or from inheritance as long as they are not
|
||||||
|
* overriden.
|
||||||
|
* @param permissionPrefix the permission range prefix.
|
||||||
|
* @param server the server where the returned values apply for this entity.
|
||||||
|
* @return the effective values of the provided permission range prefix that applies to this entity on a specific
|
||||||
|
* server.
|
||||||
|
*/
|
||||||
public LongStream getPermissionRangeValues(String permissionPrefix, String server) {
|
public LongStream getPermissionRangeValues(String permissionPrefix, String server) {
|
||||||
return getPermissionRangeValues(permissionPrefix, server, null);
|
return getPermissionRangeValues(permissionPrefix, server, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the effective values of the provided permission range prefix that applies to this entity on a specific
|
||||||
|
* server and world.
|
||||||
|
* It is either the range values defined directly for this entity, or from inheritance as long as they are not
|
||||||
|
* overriden.
|
||||||
|
* @param permissionPrefix the permission range prefix.
|
||||||
|
* @param server the server containing the world where the returned values apply for this entity.
|
||||||
|
* @param world the world in the server where the returned values apply for this entity.
|
||||||
|
* @return the effective values of the provided permission range prefix that applies to this entity on a specific
|
||||||
|
* server and world.
|
||||||
|
*/
|
||||||
public LongStream getPermissionRangeValues(String permissionPrefix, String server, String world) {
|
public LongStream getPermissionRangeValues(String permissionPrefix, String server, String world) {
|
||||||
String prefixWithEndingDot = permissionPrefix.endsWith(".") ? permissionPrefix : (permissionPrefix + ".");
|
String prefixWithEndingDot = permissionPrefix.endsWith(".") ? permissionPrefix : (permissionPrefix + ".");
|
||||||
int prefixLength = prefixWithEndingDot.length();
|
int prefixLength = prefixWithEndingDot.length();
|
||||||
@ -120,106 +241,299 @@ public abstract class PermEntity {
|
|||||||
.mapToLong(longSuffix -> longSuffix)
|
.mapToLong(longSuffix -> longSuffix)
|
||||||
.sorted();
|
.sorted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum effective value of the provided permission range prefix that applies to this entity out of a
|
||||||
|
* specific server and world.
|
||||||
|
* It is either the range values defined directly for this entity, or from inheritance as long as they are not
|
||||||
|
* overriden.
|
||||||
|
* @param permissionPrefix the permission range prefix.
|
||||||
|
* @return the maximum effective value of the provided permission range prefix that applies to this entity out of a
|
||||||
|
* specific server and world.
|
||||||
|
*/
|
||||||
public OptionalLong getPermissionRangeMax(String permissionPrefix) {
|
public OptionalLong getPermissionRangeMax(String permissionPrefix) {
|
||||||
return getPermissionRangeMax(permissionPrefix, null, null);
|
return getPermissionRangeMax(permissionPrefix, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum effective value of the provided permission range prefix that applies to this entity on a
|
||||||
|
* specific server.
|
||||||
|
* It is either the range values defined directly for this entity, or from inheritance as long as they are not
|
||||||
|
* overriden.
|
||||||
|
* @param permissionPrefix the permission range prefix.
|
||||||
|
* @param server the server where the returned value applies for this entity.
|
||||||
|
* @return the maximum effective value of the provided permission range prefix that applies to this entity on a
|
||||||
|
* specific server.
|
||||||
|
*/
|
||||||
public OptionalLong getPermissionRangeMax(String permissionPrefix, String server) {
|
public OptionalLong getPermissionRangeMax(String permissionPrefix, String server) {
|
||||||
return getPermissionRangeMax(permissionPrefix, server, null);
|
return getPermissionRangeMax(permissionPrefix, server, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum effective value of the provided permission range prefix that applies to this entity on a
|
||||||
|
* specific server and world.
|
||||||
|
* It is either the range values defined directly for this entity, or from inheritance as long as they are not
|
||||||
|
* overriden.
|
||||||
|
* @param permissionPrefix the permission range prefix.
|
||||||
|
* @param server the server containing the world where the returned value applies for this entity.
|
||||||
|
* @param world the world in the server where the returned value applies for this entity.
|
||||||
|
* @return the maximum effective value of the provided permission range prefix that applies to this entity on a
|
||||||
|
* specific server and world.
|
||||||
|
*/
|
||||||
public OptionalLong getPermissionRangeMax(String permissionPrefix, String server, String world) {
|
public OptionalLong getPermissionRangeMax(String permissionPrefix, String server, String world) {
|
||||||
return getPermissionRangeValues(permissionPrefix, server, world).max();
|
return getPermissionRangeValues(permissionPrefix, server, world).max();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if this entity has the provided permission out of a specific server and world.
|
||||||
|
* It is either based on the permissions defined directly for this entity, or from inheritance as long as they are
|
||||||
|
* not overriden.
|
||||||
|
* @param permission the permission to ckeck on this entity.
|
||||||
|
* @return true if this entity has the permission, false if it is negated, or null if not known.
|
||||||
|
*/
|
||||||
public Boolean hasPermission(String permission) {
|
public Boolean hasPermission(String permission) {
|
||||||
return hasPermission(permission, null, null);
|
return hasPermission(permission, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if this entity has the provided permission on a specitif server.
|
||||||
|
* It is either based on the permissions defined directly for this entity, or from inheritance as long as they are
|
||||||
|
* not overriden. It also consider permissions that apply on any server.
|
||||||
|
* @param permission the permission to ckeck on this entity.
|
||||||
|
* @param server the server in which to test the permission for this entity.
|
||||||
|
* @return true if this entity has the permission, false if it is negated, or null if not known.
|
||||||
|
*/
|
||||||
public Boolean hasPermission(String permission, String server) {
|
public Boolean hasPermission(String permission, String server) {
|
||||||
return hasPermission(permission, server, null);
|
return hasPermission(permission, server, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if this entity has the provided permission on a specitif server and world.
|
||||||
|
* It is either based on the permissions defined directly for this entity, or from inheritance as long as they are
|
||||||
|
* not overriden. It also consider permissions that apply on any world of that server, and then any server.
|
||||||
|
* @param permission the permission to ckeck on this entity.
|
||||||
|
* @param server the server in which to test the permission for this entity.
|
||||||
|
* @param world the world in which to test the permission for this entity.
|
||||||
|
* @return true if this entity has the permission, false if it is negated, or null if not known.
|
||||||
|
*/
|
||||||
public Boolean hasPermission(String permission, String server, String world) {
|
public Boolean hasPermission(String permission, String server, String world) {
|
||||||
Boolean ret = Permissions.resolver.getEffectivePermission(name, type, permission, server, world);
|
Boolean ret = Permissions.resolver.getEffectivePermission(name, type, permission, server, world);
|
||||||
Log.debug("[Perm] For " + type.toString().toLowerCase() + " " + getName() + ", '" + permission + "' is " + ret);
|
Log.debug("[Perm] For " + type.toString().toLowerCase() + " " + getName() + ", '" + permission + "' is " + ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if this entity has the provided permission on a specitif server and world.
|
||||||
|
* It is either based on the permissions defined directly for this entity, or from inheritance as long as they are
|
||||||
|
* not overriden.
|
||||||
|
* @param permission the permission to ckeck on this entity.
|
||||||
|
* @param server the server in which to test the permission for this entity.
|
||||||
|
* @param world the world in which to test the permission for this entity.
|
||||||
|
* @param deflt the default value is the permission is undefined for this entity.
|
||||||
|
* @return true if this entity has the permission, false if it is negated, or {@code deflt} if not known.
|
||||||
|
*/
|
||||||
public boolean hasPermissionOr(String permission, String server, String world, boolean deflt) {
|
public boolean hasPermissionOr(String permission, String server, String world, boolean deflt) {
|
||||||
Boolean ret = hasPermission(permission, server, world);
|
Boolean ret = hasPermission(permission, server, world);
|
||||||
return ret != null ? ret : deflt;
|
return ret != null ? ret : deflt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates the provided permission expression for this entity.
|
||||||
|
* It uses {@link #hasPermissionOr(String, String, String, boolean)} with {@code false} as a default value, to check
|
||||||
|
* each permission nodes individualy.
|
||||||
|
* @param permExpression the permission expression to evaluate on this entity.
|
||||||
|
* @param server the server in which to test the permission expression for this entity.
|
||||||
|
* @param world the world in which to test the permission expression for this entity.
|
||||||
|
* @return true if this the permission expression evaluates to true, false otherwise.
|
||||||
|
* @see PermissionExpressionParser#evaluate(String, LitteralPermissionTester)
|
||||||
|
*/
|
||||||
public boolean hasPermissionExpression(String permExpression, String server, String world) {
|
public boolean hasPermissionExpression(String permExpression, String server, String world) {
|
||||||
return PermissionExpressionParser.evaluate(permExpression, p -> hasPermissionOr(p, server, world, false));
|
return PermissionExpressionParser.evaluate(permExpression, p -> hasPermissionOr(p, server, world, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides informations on how the effective permission of this entity on the provided permission node is
|
||||||
|
* determined.
|
||||||
|
* @param permission the permission node to debug on this entity.
|
||||||
|
* @return a {@link ChatTreeNode} providing informations on how the effective permission is determined.
|
||||||
|
*/
|
||||||
public ChatTreeNode debugPermission(String permission) {
|
public ChatTreeNode debugPermission(String permission) {
|
||||||
return debugPermission(permission, null, null);
|
return debugPermission(permission, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides informations on how the effective permission of this entity on the provided permission node is
|
||||||
|
* determined.
|
||||||
|
* @param permission the permission node to debug on this entity.
|
||||||
|
* @param server the server in which to test the permission for this entity.
|
||||||
|
* @return a {@link ChatTreeNode} providing informations on how the effective permission is determined.
|
||||||
|
*/
|
||||||
public ChatTreeNode debugPermission(String permission, String server) {
|
public ChatTreeNode debugPermission(String permission, String server) {
|
||||||
return debugPermission(permission, server, null);
|
return debugPermission(permission, server, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides informations on how the effective permission of this entity on the provided permission node is
|
||||||
|
* determined.
|
||||||
|
* @param permission the permission node to debug on this entity.
|
||||||
|
* @param server the server in which to test the permission for this entity.
|
||||||
|
* @param world the world in which to test the permission for this entity.
|
||||||
|
* @return a {@link ChatTreeNode} providing informations on how the effective permission is determined.
|
||||||
|
*/
|
||||||
public ChatTreeNode debugPermission(String permission, String server, String world) {
|
public ChatTreeNode debugPermission(String permission, String server, String world) {
|
||||||
return Permissions.resolver.debugPermission(name, type, permission, server, world);
|
return Permissions.resolver.debugPermission(name, type, permission, server, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the provided permission node to this entity that apply on any server.
|
||||||
|
* @param permission the permission node to add.
|
||||||
|
*/
|
||||||
public void addSelfPermission(String permission) {
|
public void addSelfPermission(String permission) {
|
||||||
addSelfPermission(permission, null, null);
|
addSelfPermission(permission, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the provided permission node to this entity that apply on the provided server.
|
||||||
|
* @param permission the permission node to add.
|
||||||
|
* @param server the server in which to apply the permission.
|
||||||
|
*/
|
||||||
public void addSelfPermission(String permission, String server) {
|
public void addSelfPermission(String permission, String server) {
|
||||||
addSelfPermission(permission, server, null);
|
addSelfPermission(permission, server, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the provided permission node to this entity that apply on the provided server and world.
|
||||||
|
* @param permission the permission node to add.
|
||||||
|
* @param server the server in which to apply the permission.
|
||||||
|
* @param world the world in which to apply the permission.
|
||||||
|
*/
|
||||||
public void addSelfPermission(String permission, String server, String world) {
|
public void addSelfPermission(String permission, String server, String world) {
|
||||||
Permissions.backendWriter.addSelfPermission(name, type, permission, server, world);
|
Permissions.backendWriter.addSelfPermission(name, type, permission, server, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the provided permission node from this entity that applied on any server.
|
||||||
|
* @param permission the permission node to add.
|
||||||
|
*/
|
||||||
public void removeSelfPermission(String permission) {
|
public void removeSelfPermission(String permission) {
|
||||||
removeSelfPermission(permission, null, null);
|
removeSelfPermission(permission, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the provided permission node from this entity that applied on the provided server.
|
||||||
|
* @param permission the permission node to remove.
|
||||||
|
* @param server the server from which to remove the permission.
|
||||||
|
*/
|
||||||
public void removeSelfPermission(String permission, String server) {
|
public void removeSelfPermission(String permission, String server) {
|
||||||
removeSelfPermission(permission, server, null);
|
removeSelfPermission(permission, server, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the provided permission node from this entity that applied on the provided server and world.
|
||||||
|
* @param permission the permission node to remove.
|
||||||
|
* @param server the server from which to remove the permission.
|
||||||
|
* @param world the world from which to remove the permission.
|
||||||
|
*/
|
||||||
public void removeSelfPermission(String permission, String server, String world) {
|
public void removeSelfPermission(String permission, String server, String world) {
|
||||||
Permissions.backendWriter.removeSelfPermission(name, type, permission, server, world);
|
Permissions.backendWriter.removeSelfPermission(name, type, permission, server, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts the number of self permission nodes for this entity.
|
||||||
|
* @return the number of self permission nodes for this entity.
|
||||||
|
*/
|
||||||
public int getSelfPermissionsCount() {
|
public int getSelfPermissionsCount() {
|
||||||
return getSelfPermissionsServerWorldKeys().stream()
|
return getSelfPermissionsServerWorldKeys().stream()
|
||||||
.mapToInt(key -> getSelfPermissions(key.server, key.world).size())
|
.mapToInt(key -> getSelfPermissions(key.server(), key.world()).size())
|
||||||
.sum();
|
.sum();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the server/world attribution that have at least one self permission for this entity.
|
||||||
|
* @return all the server/world attribution that have at least one self permission for this entity.
|
||||||
|
*/
|
||||||
public Set<ServerWorldKey> getSelfPermissionsServerWorldKeys() {
|
public Set<ServerWorldKey> getSelfPermissionsServerWorldKeys() {
|
||||||
return getBackendEntity().getSelfPermissionsServerWorldKeys();
|
return getBackendEntity().getSelfPermissionsServerWorldKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the self permission nodes that apply everywhere for this entity.
|
||||||
|
* @return all the self permission nodes that apply everywhere for this entity.
|
||||||
|
*/
|
||||||
public List<String> getSelfPermissions() {
|
public List<String> getSelfPermissions() {
|
||||||
return getSelfPermissions(null, null);
|
return getSelfPermissions(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the self permission nodes that apply on the provided server for this entity.
|
||||||
|
* @param server the server from which to get the permissions.
|
||||||
|
* @return all the self permission nodes that apply on the provided server for this entity.
|
||||||
|
*/
|
||||||
public List<String> getSelfPermissions(String server) {
|
public List<String> getSelfPermissions(String server) {
|
||||||
return getSelfPermissions(server, null);
|
return getSelfPermissions(server, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the self permission nodes that apply on the provided server and world for this entity.
|
||||||
|
* @param server the server from which to get the permissions.
|
||||||
|
* @param world the world from which to get the permissions.
|
||||||
|
* @return all the self permission nodes that apply on the provided server and world for this entity.
|
||||||
|
*/
|
||||||
public List<String> getSelfPermissions(String server, String world) {
|
public List<String> getSelfPermissions(String server, String world) {
|
||||||
return getBackendEntity().getSelfPermissions(server, world);
|
return getBackendEntity().getSelfPermissions(server, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
|
@ -6,7 +6,10 @@ import java.util.stream.Collectors;
|
|||||||
import fr.pandacube.lib.permissions.PermissionsCachedBackendReader.CachedGroup;
|
import fr.pandacube.lib.permissions.PermissionsCachedBackendReader.CachedGroup;
|
||||||
import fr.pandacube.lib.permissions.SQLPermissions.EntityType;
|
import fr.pandacube.lib.permissions.SQLPermissions.EntityType;
|
||||||
|
|
||||||
public class PermGroup extends PermEntity {
|
/**
|
||||||
|
* Represents an group in the permission system.
|
||||||
|
*/
|
||||||
|
public final class PermGroup extends PermEntity {
|
||||||
/* package */ PermGroup(String name) {
|
/* package */ PermGroup(String name) {
|
||||||
super(name, EntityType.Group);
|
super(name, EntityType.Group);
|
||||||
}
|
}
|
||||||
@ -31,27 +34,54 @@ public class PermGroup extends PermEntity {
|
|||||||
.map(cg -> cg.name)
|
.map(cg -> cg.name)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if this group is a default group.
|
||||||
|
* A player inherits all default groups when they don’t explicitely inherit from at least one group.
|
||||||
|
* @return true if this group is a default group, false otherwise.
|
||||||
|
*/
|
||||||
public boolean isDefault() {
|
public boolean isDefault() {
|
||||||
return getBackendEntity().deflt;
|
return getBackendEntity().deflt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this group as a default group or not.
|
||||||
|
* All players that don’t explicitely inherit from at least one group will either start or stop implicitely
|
||||||
|
* inheriting from this group.
|
||||||
|
* @param deflt true to set this group as default, false to set is as not default.
|
||||||
|
*/
|
||||||
public void setDefault(boolean deflt) {
|
public void setDefault(boolean deflt) {
|
||||||
Permissions.backendWriter.setGroupDefault(name, deflt);
|
Permissions.backendWriter.setGroupDefault(name, deflt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes this group inherit the provided group.
|
||||||
|
* @param group the name of the group to inherit from.
|
||||||
|
*/
|
||||||
public void addInheritance(String group) {
|
public void addInheritance(String group) {
|
||||||
Permissions.backendWriter.addInheritance(name, type, group);
|
Permissions.backendWriter.addInheritance(name, type, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes this group inherit the provided group.
|
||||||
|
* @param group the group to inherit from.
|
||||||
|
*/
|
||||||
public void addInheritance(PermGroup group) {
|
public void addInheritance(PermGroup group) {
|
||||||
addInheritance(group.name);
|
addInheritance(group.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes this group stop inheriting from the provided group.
|
||||||
|
* @param group the name of the group to stop inheriting from.
|
||||||
|
*/
|
||||||
public void removeInheritance(String group) {
|
public void removeInheritance(String group) {
|
||||||
Permissions.backendWriter.removeInheritance(name, type, group);
|
Permissions.backendWriter.removeInheritance(name, type, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes this group stop inheriting from the provided group.
|
||||||
|
* @param group the group to stop inheriting from.
|
||||||
|
*/
|
||||||
public void removeInheritance(PermGroup group) {
|
public void removeInheritance(PermGroup group) {
|
||||||
removeInheritance(group.name);
|
removeInheritance(group.name);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,10 @@ import java.util.stream.Collectors;
|
|||||||
import fr.pandacube.lib.permissions.PermissionsCachedBackendReader.CachedPlayer;
|
import fr.pandacube.lib.permissions.PermissionsCachedBackendReader.CachedPlayer;
|
||||||
import fr.pandacube.lib.permissions.SQLPermissions.EntityType;
|
import fr.pandacube.lib.permissions.SQLPermissions.EntityType;
|
||||||
|
|
||||||
public class PermPlayer extends PermEntity {
|
/**
|
||||||
|
* Represents an player in the permission system.
|
||||||
|
*/
|
||||||
|
public final class PermPlayer extends PermEntity {
|
||||||
private final UUID playerId;
|
private final UUID playerId;
|
||||||
/* package */ PermPlayer(UUID id) {
|
/* package */ PermPlayer(UUID id) {
|
||||||
super(id.toString(), EntityType.User);
|
super(id.toString(), EntityType.User);
|
||||||
@ -29,7 +32,11 @@ public class PermPlayer extends PermEntity {
|
|||||||
.map(cg -> cg.name)
|
.map(cg -> cg.name)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the UUID of this player.
|
||||||
|
* @return the UUID of this player.
|
||||||
|
*/
|
||||||
public UUID getPlayerId() {
|
public UUID getPlayerId() {
|
||||||
return playerId;
|
return playerId;
|
||||||
}
|
}
|
||||||
@ -48,14 +55,18 @@ public class PermPlayer extends PermEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Gets all the groups this player belongs to.
|
||||||
* Alias for {@link #getInheritances()}.
|
* Alias for {@link #getInheritances()}.
|
||||||
|
* @return a list of all the groups this player belongs to.
|
||||||
*/
|
*/
|
||||||
public List<PermGroup> getGroups() {
|
public List<PermGroup> getGroups() {
|
||||||
return getInheritances();
|
return getInheritances();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Gets all the group names this player belongs to.
|
||||||
* Alias for {@link #getInheritances()}.
|
* Alias for {@link #getInheritances()}.
|
||||||
|
* @return a list of all the group names this player belongs to.
|
||||||
*/
|
*/
|
||||||
public List<String> getGroupsString() {
|
public List<String> getGroupsString() {
|
||||||
return getInheritancesString();
|
return getInheritancesString();
|
||||||
@ -65,35 +76,67 @@ public class PermPlayer extends PermEntity {
|
|||||||
* Tells if the player is directly part of a group.
|
* Tells if the player is directly part of a group.
|
||||||
* This is equivalent to {@link #inheritsFromGroup(String, boolean) inheritsFromGroup(group, false)}
|
* This is equivalent to {@link #inheritsFromGroup(String, boolean) inheritsFromGroup(group, false)}
|
||||||
* @param group the group to search for
|
* @param group the group to search for
|
||||||
|
* @return true if the player is directly part of a group, false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean isInGroup(String group) {
|
public boolean isInGroup(String group) {
|
||||||
return inheritsFromGroup(group, false);
|
return inheritsFromGroup(group, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if this player has been assigned to the default groups.
|
||||||
|
* @return true if this player has been assigned to the default groups, or false if this player belongs explicitely
|
||||||
|
* to their groups.
|
||||||
|
*/
|
||||||
public boolean isUsingDefaultGroups() {
|
public boolean isUsingDefaultGroups() {
|
||||||
return getBackendEntity().usingDefaultGroups;
|
return getBackendEntity().usingDefaultGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the group this player will now inheritate, removing all previously inherited groups.
|
||||||
|
* To keep the other inherited groups, use {@link #addGroup(String)}.
|
||||||
|
* @param group the name of the group to inherit from.
|
||||||
|
*/
|
||||||
public void setGroup(String group) {
|
public void setGroup(String group) {
|
||||||
Permissions.backendWriter.setInheritance(name, type, group);
|
Permissions.backendWriter.setInheritance(name, type, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the group this player will now inheritate, removing all previously inherited groups.
|
||||||
|
* To keep the other inherited groups, use {@link #addGroup(PermGroup)}.
|
||||||
|
* @param group the group to inherit from.
|
||||||
|
*/
|
||||||
public void setGroup(PermGroup group) {
|
public void setGroup(PermGroup group) {
|
||||||
setGroup(group.name);
|
setGroup(group.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes this player inherit the provided group, keeping the other groups they already inherits from.
|
||||||
|
* @param group the name of the group to inherit from.
|
||||||
|
*/
|
||||||
public void addGroup(String group) {
|
public void addGroup(String group) {
|
||||||
Permissions.backendWriter.addInheritance(name, type, group);
|
Permissions.backendWriter.addInheritance(name, type, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes this player inherit the provided group, keeping the other groups they already inherits from.
|
||||||
|
* @param group the group to inherit from.
|
||||||
|
*/
|
||||||
public void addGroup(PermGroup group) {
|
public void addGroup(PermGroup group) {
|
||||||
addGroup(group.name);
|
addGroup(group.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes this player stop inheriting from the provided group.
|
||||||
|
* @param group the name of the group to stop inheriting from.
|
||||||
|
*/
|
||||||
public void removeGroup(String group) {
|
public void removeGroup(String group) {
|
||||||
Permissions.backendWriter.removeInheritance(name, type, group);
|
Permissions.backendWriter.removeInheritance(name, type, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes this player stop inheriting from the provided group.
|
||||||
|
* @param group the group to stop inheriting from.
|
||||||
|
*/
|
||||||
public void removeGroup(PermGroup group) {
|
public void removeGroup(PermGroup group) {
|
||||||
removeGroup(group.name);
|
removeGroup(group.name);
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,38 @@ import com.fathzer.soft.javaluator.Operator;
|
|||||||
import com.fathzer.soft.javaluator.Operator.Associativity;
|
import com.fathzer.soft.javaluator.Operator.Associativity;
|
||||||
import com.fathzer.soft.javaluator.Parameters;
|
import com.fathzer.soft.javaluator.Parameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that evaluates a permission string as if it was a boolean expression with permission nodes as variables.
|
||||||
|
* <p>
|
||||||
|
* A permission expression contains permission nodes, boolean operators ({@code "||"}, {@code "&&"} and {@code "!"}) and
|
||||||
|
* literal values {@code "true"} and {@code "false"}.
|
||||||
|
* Here are some example of permission expressions:
|
||||||
|
* <pre>{@code
|
||||||
|
* "p1.cmd"
|
||||||
|
* "!p1.toto"
|
||||||
|
* "p1.cmd!"
|
||||||
|
* "p1.cmd || p1.toto"
|
||||||
|
* "p1.cmd && p1.toto"
|
||||||
|
* "p1.cmd && !p1.toto "
|
||||||
|
* "p1.cmd && true"
|
||||||
|
* "false || p2.cmd"
|
||||||
|
* }</pre>
|
||||||
|
* Notice that spaces around permission nodes and operators does not affect the results of the parsing.
|
||||||
|
*/
|
||||||
public class PermissionExpressionParser {
|
public class PermissionExpressionParser {
|
||||||
|
|
||||||
private static final PermissionEvaluator PERMISSION_EVALUATOR = new PermissionEvaluator();
|
private static final PermissionEvaluator PERMISSION_EVALUATOR = new PermissionEvaluator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate the provided permission expression, testing each permission with the provided permTester.
|
||||||
|
*
|
||||||
|
* @param permString the permission expression to evaluate.
|
||||||
|
* @param permTester a function that gives the value of the provided permission node. It is usually a method
|
||||||
|
* reference to the {@code hasPermission(String)} method the player we want to test the
|
||||||
|
* permissions.
|
||||||
|
* @throws IllegalArgumentException if the expression is not correct.
|
||||||
|
* @return the result of the evaluation of the permission expression.
|
||||||
|
*/
|
||||||
public static boolean evaluate(String permString, LitteralPermissionTester permTester) {
|
public static boolean evaluate(String permString, LitteralPermissionTester permTester) {
|
||||||
try {
|
try {
|
||||||
return PERMISSION_EVALUATOR.evaluate(permString, permTester);
|
return PERMISSION_EVALUATOR.evaluate(permString, permTester);
|
||||||
@ -22,6 +50,9 @@ public class PermissionExpressionParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functional interface that converts a string into a boolean.
|
||||||
|
*/
|
||||||
public interface LitteralPermissionTester extends Function<String, Boolean> { }
|
public interface LitteralPermissionTester extends Function<String, Boolean> { }
|
||||||
|
|
||||||
|
|
||||||
@ -89,41 +120,4 @@ public class PermissionExpressionParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* TODO move to test code
|
|
||||||
public static void main(String[] args) {
|
|
||||||
java.util.List<String> pList = java.util.Arrays.asList("p1.cmd", "p1.toto", "p2.lol");
|
|
||||||
LitteralPermissionTester tester = p -> pList.contains(p);
|
|
||||||
|
|
||||||
for (String permExpr : java.util.Arrays.asList(
|
|
||||||
"p1.cmd", // true
|
|
||||||
"p1.notexist", // false
|
|
||||||
"p2lol.lol", // false
|
|
||||||
"!p1.notexist", // true
|
|
||||||
"!p1.cmd", // false
|
|
||||||
"p1.cmd!", // false
|
|
||||||
"p1.cmd! p2.lol", // exception
|
|
||||||
"p1.cmd || p1.toto", // true || true == true
|
|
||||||
"p1.cmd || p1.notexist", // true || false == true
|
|
||||||
"p1.fefef || p2.lol", // false || true == true
|
|
||||||
"p1.fefef || p2.lolilol", // false || false == false
|
|
||||||
"p1.cmd && p1.toto", // true && true == true
|
|
||||||
"p1.cmd && p1.notexist", // true && false == false
|
|
||||||
"p1.fefef && p2.lol", // false && true == false
|
|
||||||
"p1.fefef && p2.lolilol", // false && false == false
|
|
||||||
"p1.cmd && !p1.toto ", // true && !true == false
|
|
||||||
" !p1.cmd && p1.toto", // !true && true == false
|
|
||||||
"!p1.cmd & p1.toto", // exception
|
|
||||||
"!p1.cmd | p1.toto", // exception
|
|
||||||
"p1.not exist" // exception
|
|
||||||
)) {
|
|
||||||
try {
|
|
||||||
System.out.println(permExpr + " -> " + evaluate(permExpr, tester));
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,13 @@ import fr.pandacube.lib.db.DBConnection;
|
|||||||
import fr.pandacube.lib.db.DBException;
|
import fr.pandacube.lib.db.DBException;
|
||||||
import fr.pandacube.lib.util.Log;
|
import fr.pandacube.lib.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main class for the Pandalib permission system.
|
||||||
|
* <p>
|
||||||
|
* This permission system uses the Pandalib DB API to connect to the database, so the connection to the MySQL must be
|
||||||
|
* established first, using {@link DB#init(DBConnection, String)}.
|
||||||
|
* Then, this class must be initialized using {@link #init(Function)}.
|
||||||
|
*/
|
||||||
public class Permissions {
|
public class Permissions {
|
||||||
|
|
||||||
/* package */ static PermissionsCachedBackendReader backendReader;
|
/* package */ static PermissionsCachedBackendReader backendReader;
|
||||||
@ -20,6 +27,10 @@ public class Permissions {
|
|||||||
/**
|
/**
|
||||||
* Initialize the permission system.
|
* Initialize the permission system.
|
||||||
* The connection to the database needs to be initialized first, using {@link DB#init(DBConnection, String)}.
|
* The connection to the database needs to be initialized first, using {@link DB#init(DBConnection, String)}.
|
||||||
|
* @param playerNameGetter a function to get the player name associated with a UUID. It is used for
|
||||||
|
* and to generate {@link PermPlayer#getName()} and for
|
||||||
|
* {@link PermEntity#debugPermission(String)}.
|
||||||
|
* @throws DBException if an error occurs when interacting with the database.
|
||||||
*/
|
*/
|
||||||
public static void init(Function<UUID, String> playerNameGetter) throws DBException {
|
public static void init(Function<UUID, String> playerNameGetter) throws DBException {
|
||||||
Permissions.playerNameGetter = playerNameGetter == null ? UUID::toString : playerNameGetter;
|
Permissions.playerNameGetter = playerNameGetter == null ? UUID::toString : playerNameGetter;
|
||||||
@ -37,7 +48,18 @@ public class Permissions {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void checkInitialized() {
|
||||||
|
if (backendReader == null) {
|
||||||
|
throw new IllegalStateException("Permissions system not initialized. Check the server logs to check if there is an error during the startup, and check if the init() method is called properly.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the provided special permissions to this permission system.
|
||||||
|
* @param specialPermissions the {@link SpecialPermission}s to add.
|
||||||
|
* @throws IllegalStateException if the permission system was not initialized properly.
|
||||||
|
*/
|
||||||
public static void addSpecialPermissions(SpecialPermission... specialPermissions) {
|
public static void addSpecialPermissions(SpecialPermission... specialPermissions) {
|
||||||
checkInitialized();
|
checkInitialized();
|
||||||
if (specialPermissions == null)
|
if (specialPermissions == null)
|
||||||
@ -45,18 +67,23 @@ public class Permissions {
|
|||||||
resolver.specialPermissions.addAll(Arrays.asList(specialPermissions));
|
resolver.specialPermissions.addAll(Arrays.asList(specialPermissions));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkInitialized() {
|
/**
|
||||||
if (backendReader == null) {
|
* Clears the cached data of a specific player.
|
||||||
throw new IllegalStateException("Permissions system not initialized. Check the server logs to check if there is an error during the startup, and check if the init() method is called properly.");
|
* @param playerId the UUID of the player.
|
||||||
}
|
* @throws IllegalStateException if the permission system was not initialized properly.
|
||||||
}
|
*/
|
||||||
|
|
||||||
public static void clearPlayerCache(UUID playerId) {
|
public static void clearPlayerCache(UUID playerId) {
|
||||||
checkInitialized();
|
checkInitialized();
|
||||||
backendReader.clearPlayerCache(playerId);
|
backendReader.clearPlayerCache(playerId);
|
||||||
resolver.clearPlayerFromCache(playerId);
|
resolver.clearPlayerFromCache(playerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all the cached data (players and groupds) and fetch all the groups data from the database.
|
||||||
|
* The clearing and fetching of the data is made asynchronously in a new thread.
|
||||||
|
* @param then the action to perform after the cache has been updated.
|
||||||
|
* @throws IllegalStateException if the permission system was not initialized properly.
|
||||||
|
*/
|
||||||
public static void clearCache(Runnable then) {
|
public static void clearCache(Runnable then) {
|
||||||
checkInitialized();
|
checkInitialized();
|
||||||
backendReader.clearAndResetCacheAsync(() -> {
|
backendReader.clearAndResetCacheAsync(() -> {
|
||||||
@ -65,13 +92,25 @@ public class Permissions {
|
|||||||
then.run();
|
then.run();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the permission player object.
|
||||||
|
* @param playerId the UUID of the player.
|
||||||
|
* @return the permission player object.
|
||||||
|
* @throws IllegalStateException if the permission system was not initialized properly.
|
||||||
|
*/
|
||||||
public static PermPlayer getPlayer(UUID playerId) {
|
public static PermPlayer getPlayer(UUID playerId) {
|
||||||
checkInitialized();
|
checkInitialized();
|
||||||
return new PermPlayer(playerId);
|
return new PermPlayer(playerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks the permission system to preventively and asynchronoulsy cache the data of the provided player.
|
||||||
|
* This can be called as soon as possible when a player connects, so the permission data of the player are
|
||||||
|
* accessible as soon as possible when they are needed.
|
||||||
|
* @param playerId the UUID of the player.
|
||||||
|
* @throws IllegalStateException if the permission system was not initialized properly.
|
||||||
|
*/
|
||||||
public static void precachePlayerAsync(UUID playerId) {
|
public static void precachePlayerAsync(UUID playerId) {
|
||||||
checkInitialized();
|
checkInitialized();
|
||||||
Thread t = new Thread(() -> {
|
Thread t = new Thread(() -> {
|
||||||
@ -84,23 +123,45 @@ public class Permissions {
|
|||||||
t.setDaemon(true);
|
t.setDaemon(true);
|
||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the permission group object.
|
||||||
|
* @param name the name of the group.
|
||||||
|
* @return the permission group object.
|
||||||
|
* @throws IllegalStateException if the permission system was not initialized properly.
|
||||||
|
*/
|
||||||
public static PermGroup getGroup(String name) {
|
public static PermGroup getGroup(String name) {
|
||||||
checkInitialized();
|
checkInitialized();
|
||||||
return new PermGroup(name);
|
return new PermGroup(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the permission group objects.
|
||||||
|
* @return all the permission group objects.
|
||||||
|
* @throws IllegalStateException if the permission system was not initialized properly.
|
||||||
|
*/
|
||||||
public static List<PermGroup> getGroups() {
|
public static List<PermGroup> getGroups() {
|
||||||
checkInitialized();
|
checkInitialized();
|
||||||
return PermGroup.fromCachedGroups(backendReader.getGroups());
|
return PermGroup.fromCachedGroups(backendReader.getGroups());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the default permission group objects.
|
||||||
|
* @return all the default permission group objects.
|
||||||
|
* @throws IllegalStateException if the permission system was not initialized properly.
|
||||||
|
*/
|
||||||
public static List<PermGroup> getDefaultGroups() {
|
public static List<PermGroup> getDefaultGroups() {
|
||||||
checkInitialized();
|
checkInitialized();
|
||||||
return PermGroup.fromCachedGroups(backendReader.getDefaultGroups());
|
return PermGroup.fromCachedGroups(backendReader.getDefaultGroups());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the full permission list.
|
||||||
|
* @return the full permission list.
|
||||||
|
* @throws IllegalStateException if the permission system was not initialized properly.
|
||||||
|
*/
|
||||||
public static List<String> getFullPermissionsList() {
|
public static List<String> getFullPermissionsList() {
|
||||||
|
checkInitialized();
|
||||||
return backendReader.getFullPermissionsList();
|
return backendReader.getFullPermissionsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ import fr.pandacube.lib.permissions.PermissionsCachedBackendReader.CachedPlayer;
|
|||||||
import fr.pandacube.lib.permissions.SQLPermissions.EntityType;
|
import fr.pandacube.lib.permissions.SQLPermissions.EntityType;
|
||||||
import fr.pandacube.lib.util.Log;
|
import fr.pandacube.lib.util.Log;
|
||||||
|
|
||||||
public class PermissionsResolver {
|
/* package */ class PermissionsResolver {
|
||||||
|
|
||||||
private final PermissionsCachedBackendReader backendReader;
|
private final PermissionsCachedBackendReader backendReader;
|
||||||
|
|
||||||
@ -400,7 +400,7 @@ public class PermissionsResolver {
|
|||||||
ParsedSelfPermission specialPerm = null;
|
ParsedSelfPermission specialPerm = null;
|
||||||
|
|
||||||
for (SpecialPermission spePerm : specialPermissions) {
|
for (SpecialPermission spePerm : specialPermissions) {
|
||||||
if (spePerm.match().match(permission)) {
|
if (spePerm.matcher().match(permission)) {
|
||||||
boolean res = spePerm.tester().test(permP, permission, server, world);
|
boolean res = spePerm.tester().test(permP, permission, server, world);
|
||||||
specialPerm = new ParsedSelfPermission(permission, res, PermType.SPECIAL);
|
specialPerm = new ParsedSelfPermission(permission, res, PermType.SPECIAL);
|
||||||
break;
|
break;
|
||||||
|
@ -3,13 +3,19 @@ package fr.pandacube.lib.permissions;
|
|||||||
import fr.pandacube.lib.db.SQLElement;
|
import fr.pandacube.lib.db.SQLElement;
|
||||||
import fr.pandacube.lib.db.SQLField;
|
import fr.pandacube.lib.db.SQLField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL Table to store the permissions data.
|
||||||
|
*/
|
||||||
public class SQLPermissions extends SQLElement<SQLPermissions> {
|
public class SQLPermissions extends SQLElement<SQLPermissions> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instanciate a new entry in the table.
|
||||||
|
*/
|
||||||
public SQLPermissions() {
|
public SQLPermissions() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SQLPermissions(int id) {
|
private SQLPermissions(int id) {
|
||||||
super(id);
|
super(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,22 +24,45 @@ public class SQLPermissions extends SQLElement<SQLPermissions> {
|
|||||||
return "permissions";
|
return "permissions";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The name of the entity (player id or group name). */
|
||||||
public static final SQLField<SQLPermissions, String> name = field(VARCHAR(64), false);
|
public static final SQLField<SQLPermissions, String> name = field(VARCHAR(64), false);
|
||||||
|
/** The entity type, based on {@link EntityType}. */
|
||||||
public static final SQLField<SQLPermissions, Integer> type = field(TINYINT, false);
|
public static final SQLField<SQLPermissions, Integer> type = field(TINYINT, false);
|
||||||
|
/** The key of the data ("permission", "inheritance", …). */
|
||||||
public static final SQLField<SQLPermissions, String> key = field(VARCHAR(256), false);
|
public static final SQLField<SQLPermissions, String> key = field(VARCHAR(256), false);
|
||||||
|
/** The data value (permission node, name of inherited group, prefix/suffix, …). */
|
||||||
public static final SQLField<SQLPermissions, String> value = field(VARCHAR(256), false);
|
public static final SQLField<SQLPermissions, String> value = field(VARCHAR(256), false);
|
||||||
|
/** The server in which the permission apply. */
|
||||||
public static final SQLField<SQLPermissions, String> server = field(VARCHAR(64), true);
|
public static final SQLField<SQLPermissions, String> server = field(VARCHAR(64), true);
|
||||||
|
/** The world in which the permission apply. */
|
||||||
public static final SQLField<SQLPermissions, String> world = field(VARCHAR(64), true);
|
public static final SQLField<SQLPermissions, String> world = field(VARCHAR(64), true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All possible type of entity type.
|
||||||
|
*/
|
||||||
public enum EntityType {
|
public enum EntityType {
|
||||||
|
/**
|
||||||
|
* User entity type.
|
||||||
|
*/
|
||||||
User,
|
User,
|
||||||
|
/**
|
||||||
|
* Group entity type.
|
||||||
|
*/
|
||||||
Group;
|
Group;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the database value of this entity type.
|
||||||
|
* @return the database value of this entity type.
|
||||||
|
*/
|
||||||
public int getCode() {
|
public int getCode() {
|
||||||
return ordinal();
|
return ordinal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link EntityType} corresponding to the database value.
|
||||||
|
* @param code the database value.
|
||||||
|
* @return the {@link EntityType} corresponding to the database value.
|
||||||
|
*/
|
||||||
public static EntityType getByCode(int code) {
|
public static EntityType getByCode(int code) {
|
||||||
if (code >= 0 && code < values().length)
|
if (code >= 0 && code < values().length)
|
||||||
return values()[code];
|
return values()[code];
|
||||||
|
@ -3,11 +3,14 @@ package fr.pandacube.lib.permissions;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class ServerWorldKey implements Comparable<ServerWorldKey> {
|
/**
|
||||||
public final String server, world;
|
* A pair of string representing a server and world name, used to organize and filter the permission data of a player or
|
||||||
ServerWorldKey(String s, String w) {
|
* group.
|
||||||
server = s; world = w;
|
* @param server the server name, can be null.
|
||||||
}
|
* @param world the world name, can be null.
|
||||||
|
*/
|
||||||
|
public record ServerWorldKey(String server, String world) implements Comparable<ServerWorldKey> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
return obj instanceof ServerWorldKey o
|
return obj instanceof ServerWorldKey o
|
||||||
|
@ -2,14 +2,35 @@ package fr.pandacube.lib.permissions;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a permission node that is based on an arbitrary player state.
|
* Represents a permission node that is based on an arbitrary player state.
|
||||||
|
* @param matcher predicate that tell if the provided permission is our special permission.
|
||||||
|
* @param tester predicate that tell the value of this special permission, based on the parameters.
|
||||||
*/
|
*/
|
||||||
public record SpecialPermission(PermissionMatcher match, PermissionTester tester) {
|
public record SpecialPermission(PermissionMatcher matcher, PermissionTester tester) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate that tell if the provided permission is our special permission.
|
||||||
|
*/
|
||||||
public interface PermissionMatcher {
|
public interface PermissionMatcher {
|
||||||
|
/**
|
||||||
|
* Tells if the provided permission is our special permission.
|
||||||
|
* @param permission the permission to test.
|
||||||
|
* @return true if the provided permission is our special permission, false otherwise.
|
||||||
|
*/
|
||||||
boolean match(String permission);
|
boolean match(String permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate that tell the value of this special permission, based on the parameters.
|
||||||
|
*/
|
||||||
public interface PermissionTester {
|
public interface PermissionTester {
|
||||||
|
/**
|
||||||
|
* Tells the value of this special permission, based on the parameters.
|
||||||
|
* @param player the player to test the permission on.
|
||||||
|
* @param permission the permission to test.
|
||||||
|
* @param server the server on which the player is.
|
||||||
|
* @param world the world in which the player is.
|
||||||
|
* @return the value of this special permission, based on the parameters.
|
||||||
|
*/
|
||||||
boolean test(PermPlayer player, String permission, String server, String world);
|
boolean test(PermPlayer player, String permission, String server, String world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,109 @@
|
|||||||
|
package fr.pandacube.lib.permissions;
|
||||||
|
|
||||||
|
import fr.pandacube.lib.permissions.PermissionExpressionParser.LitteralPermissionTester;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static fr.pandacube.lib.permissions.PermissionExpressionParser.evaluate;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class PermissionExpressionParserTest {
|
||||||
|
|
||||||
|
java.util.List<String> pList = java.util.Arrays.asList("p1.cmd", "p1.toto", "p2.lol");
|
||||||
|
LitteralPermissionTester tester = p -> pList.contains(p);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateTrue() {
|
||||||
|
assertTrue(evaluate("p1.cmd", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateFalse() {
|
||||||
|
assertFalse(evaluate("p1.notexist", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateNegateFalse() {
|
||||||
|
assertTrue(evaluate("!p1.notexist", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateNegateTrue() {
|
||||||
|
assertFalse(evaluate("!p1.cmd", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateRevNegateTrue() {
|
||||||
|
assertFalse(evaluate("p1.cmd!", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateOrBothTrue() {
|
||||||
|
assertTrue(evaluate("p1.cmd || p1.toto", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateOrTrueFalse() {
|
||||||
|
assertTrue(evaluate("p1.cmd || p1.notexist", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateOrFalseTrue() {
|
||||||
|
assertTrue(evaluate("p1.fefef || p2.lol", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateOrBothFalse() {
|
||||||
|
assertFalse(evaluate("p1.fefef || p2.lolilol", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateAndBothTrue() {
|
||||||
|
assertTrue(evaluate("p1.cmd && p1.toto", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateAndTrueFalse() {
|
||||||
|
assertFalse(evaluate("p1.cmd && p1.notexist", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateAndFalseTrue() {
|
||||||
|
assertFalse(evaluate("p1.fefef && p2.lol", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateAndBothFalse() {
|
||||||
|
assertFalse(evaluate("p1.fefef && p2.lolilol", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateAndTrueNegateTrueWithSomeExtraSpaces() {
|
||||||
|
assertFalse(evaluate("p1.cmd && !p1.toto ", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void evaluateAndNegateTrueTrueWithLotOfExtraSpaces() {
|
||||||
|
assertFalse(evaluate(" !p1.cmd && p1.toto ", tester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void evaluateBadSyntax1() {
|
||||||
|
evaluate("p1.cmd! p2.lol", tester);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void evaluateBadSyntax2() {
|
||||||
|
evaluate("!p1.cmd & p1.toto", tester);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void evaluateBadSyntax3() {
|
||||||
|
evaluate("!p1.cmd | p1.toto", tester);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void evaluateBadSyntax4() {
|
||||||
|
evaluate("p1.not exist", tester);
|
||||||
|
}
|
||||||
|
}
|
@ -6,9 +6,12 @@ import java.util.stream.LongStream;
|
|||||||
import fr.pandacube.lib.chat.ChatColorUtil;
|
import fr.pandacube.lib.chat.ChatColorUtil;
|
||||||
import fr.pandacube.lib.permissions.PermPlayer;
|
import fr.pandacube.lib.permissions.PermPlayer;
|
||||||
import fr.pandacube.lib.permissions.Permissions;
|
import fr.pandacube.lib.permissions.Permissions;
|
||||||
import fr.pandacube.lib.players.standalone.StandaloneOffPlayer;
|
import fr.pandacube.lib.players.standalone.AbstractOffPlayer;
|
||||||
|
|
||||||
public interface PermissibleOffPlayer extends StandaloneOffPlayer {
|
/**
|
||||||
|
* Represents a player, either offline or online, with extra methods related to the {@code pandalib-permissions} system.
|
||||||
|
*/
|
||||||
|
public interface PermissibleOffPlayer extends AbstractOffPlayer {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -44,6 +47,7 @@ public interface PermissibleOffPlayer extends StandaloneOffPlayer {
|
|||||||
* Get an updated display name of the user,
|
* Get an updated display name of the user,
|
||||||
* generated using eventual permission’s prefix(es) and suffix(es) of the player,
|
* generated using eventual permission’s prefix(es) and suffix(es) of the player,
|
||||||
* and with color codes translated to Minecraft’s native {@code §}.
|
* and with color codes translated to Minecraft’s native {@code §}.
|
||||||
|
* @return the display name of this player, generated by the permission system.
|
||||||
*/
|
*/
|
||||||
default String getDisplayNameFromPermissionSystem() {
|
default String getDisplayNameFromPermissionSystem() {
|
||||||
PermPlayer permU = getPermissionUser();
|
PermPlayer permU = getPermissionUser();
|
||||||
@ -127,6 +131,8 @@ public interface PermissibleOffPlayer extends StandaloneOffPlayer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the maximum value returned by {@link PermissibleOffPlayer#getPermissionRangeValues(String)}.
|
* Returns the maximum value returned by {@link PermissibleOffPlayer#getPermissionRangeValues(String)}.
|
||||||
|
* @param permissionPrefix the permission prefix to search for.
|
||||||
|
* @return the maximum value for the provided permission range.
|
||||||
*/
|
*/
|
||||||
default OptionalLong getPermissionRangeMax(String permissionPrefix) {
|
default OptionalLong getPermissionRangeMax(String permissionPrefix) {
|
||||||
PermissibleOnlinePlayer online = getOnlineInstance();
|
PermissibleOnlinePlayer online = getOnlineInstance();
|
||||||
@ -139,8 +145,7 @@ public interface PermissibleOffPlayer extends StandaloneOffPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if the this player is part of the specified group
|
* Tells if the this player is part of the specified group.
|
||||||
*
|
|
||||||
* @param group the permissions group
|
* @param group the permissions group
|
||||||
* @return <i>true</i> if this player is part of the group,
|
* @return <i>true</i> if this player is part of the group,
|
||||||
* <i>false</i> otherwise
|
* <i>false</i> otherwise
|
||||||
|
@ -4,9 +4,12 @@ import java.util.OptionalLong;
|
|||||||
import java.util.stream.LongStream;
|
import java.util.stream.LongStream;
|
||||||
|
|
||||||
import fr.pandacube.lib.permissions.PermissionExpressionParser;
|
import fr.pandacube.lib.permissions.PermissionExpressionParser;
|
||||||
import fr.pandacube.lib.players.standalone.StandaloneOnlinePlayer;
|
import fr.pandacube.lib.players.standalone.AbstractOnlinePlayer;
|
||||||
|
|
||||||
public interface PermissibleOnlinePlayer extends PermissibleOffPlayer, StandaloneOnlinePlayer {
|
/**
|
||||||
|
* Represents an online player, with extra methods related to the {@code pandalib-permissions} system.
|
||||||
|
*/
|
||||||
|
public interface PermissibleOnlinePlayer extends PermissibleOffPlayer, AbstractOnlinePlayer {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -16,7 +19,7 @@ public interface PermissibleOnlinePlayer extends PermissibleOffPlayer, Standalon
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The current name of this player
|
* {@inheritDoc}
|
||||||
* @implSpec The implementation is expected to call the environment API
|
* @implSpec The implementation is expected to call the environment API
|
||||||
* (Bukkit/Bungee) to get the name of the player.
|
* (Bukkit/Bungee) to get the name of the player.
|
||||||
*/
|
*/
|
||||||
|
@ -1,140 +0,0 @@
|
|||||||
package fr.pandacube.lib.players.permissible;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import net.kyori.adventure.text.ComponentLike;
|
|
||||||
|
|
||||||
import fr.pandacube.lib.chat.ChatStatic;
|
|
||||||
import fr.pandacube.lib.players.standalone.StandalonePlayerManager;
|
|
||||||
|
|
||||||
public abstract class PermissiblePlayerManager<OP extends PermissibleOnlinePlayer, OF extends PermissibleOffPlayer> extends StandalonePlayerManager<OP, OF> {
|
|
||||||
private static PermissiblePlayerManager<?, ?> instance;
|
|
||||||
|
|
||||||
public static synchronized PermissiblePlayerManager<?, ?> getInstance() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static synchronized void setInstance(PermissiblePlayerManager<?, ?> newInstance) {
|
|
||||||
if (instance != null) {
|
|
||||||
throw new IllegalStateException("cannot have multiple instance of PlayerManager");
|
|
||||||
}
|
|
||||||
instance = newInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PermissiblePlayerManager() {
|
|
||||||
super();
|
|
||||||
setInstance(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void broadcastMessage(ComponentLike message, boolean prefix, boolean console, String permission, UUID sourcePlayer) {
|
|
||||||
Objects.requireNonNull(message, "message cannot be null");
|
|
||||||
|
|
||||||
if (prefix)
|
|
||||||
message = ChatStatic.prefixedAndColored(message.asComponent());
|
|
||||||
|
|
||||||
for (PermissibleOnlinePlayer op : getAll()) {
|
|
||||||
if (permission != null && !(op.hasPermission(permission))) continue;
|
|
||||||
|
|
||||||
if (sourcePlayer != null)
|
|
||||||
op.sendMessage(message, sourcePlayer); // CHAT message with UUID
|
|
||||||
else
|
|
||||||
op.sendMessage(message); // SYSTEM message
|
|
||||||
}
|
|
||||||
if (console)
|
|
||||||
sendMessageToConsole(message.asComponent());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Message broadcasting
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ComponentLike message
|
|
||||||
// boolean prefix
|
|
||||||
// boolean console = (permission == null)
|
|
||||||
// String permission = null
|
|
||||||
// UUID sourcePlayer = null
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcast a message to some or all players, and eventually to the console.
|
|
||||||
*
|
|
||||||
* @param message the message to send.
|
|
||||||
* @param prefix if the server prefix will be prepended to the message.
|
|
||||||
* @param console if the message must be displayed in the console.
|
|
||||||
* @param permission if not null, the message is only sent to player with this permission.
|
|
||||||
* @param sourcePlayer specifiy the eventual player that is the source of the message.
|
|
||||||
* If null, the message will be sent as a SYSTEM chat message.
|
|
||||||
* If not null, the message will be sent as a CHAT message, and will not be sent
|
|
||||||
* to players ignoring the provided player (if implemented).
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException if message is null.
|
|
||||||
*/
|
|
||||||
public static void broadcast(ComponentLike message, boolean prefix, boolean console, String permission, UUID sourcePlayer) {
|
|
||||||
getInstance().broadcastMessage(message, prefix, console, permission, sourcePlayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcast a message to some or all players, and eventually to the console.
|
|
||||||
* <p>
|
|
||||||
* This method assumes this message is not caused by a specific player. To specify the source player, use
|
|
||||||
* {@link #broadcast(ComponentLike, boolean, boolean, String, UUID)}.
|
|
||||||
*
|
|
||||||
* @param message the message to send.
|
|
||||||
* @param prefix if the server prefix will be prepended to the message.
|
|
||||||
* @param console if the message must be displayed in the console.
|
|
||||||
* @param permission if not null, the message is only sent to player with this permission.
|
|
||||||
* @throws IllegalArgumentException if message is null.
|
|
||||||
*/
|
|
||||||
public static void broadcast(ComponentLike message, boolean prefix, boolean console, String permission) {
|
|
||||||
broadcast(message, prefix, console, permission, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcast a message to some or all players, and eventually to the console.
|
|
||||||
* <p>
|
|
||||||
* This method assumes this message is not caused by a specific player. To specify the source player, use
|
|
||||||
* {@link #broadcast(ComponentLike, boolean, String, UUID)}.
|
|
||||||
* <p>
|
|
||||||
* This method decides to send the message to the console depending on whether {@code permission}
|
|
||||||
* is null (will send to console) or not (will not send to console). To specify this behaviour, use
|
|
||||||
* {@link #broadcast(ComponentLike, boolean, boolean, String)}.
|
|
||||||
*
|
|
||||||
* @param message the message to send.
|
|
||||||
* @param prefix if the server prefix will be prepended to the message.
|
|
||||||
* @param permission if not null, the message is only sent to player with this permission (but not to console).
|
|
||||||
* If null, the message will be sent to all players and to console.
|
|
||||||
* @throws IllegalArgumentException if message is null.
|
|
||||||
*/
|
|
||||||
public static void broadcast(ComponentLike message, boolean prefix, String permission) {
|
|
||||||
broadcast(message, prefix, (permission == null), permission, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcast a message to all players, and to the console.
|
|
||||||
* <p>
|
|
||||||
* This method sends the message to the console. To change this behaviour, use
|
|
||||||
* {@link #broadcast(ComponentLike, boolean, boolean, String, UUID)}.
|
|
||||||
*
|
|
||||||
* @param message the message to send.
|
|
||||||
* @param prefix if the server prefix will be prepended to the message.
|
|
||||||
* @param permission if not null, the message is only sent to player with this permission (but not to console).
|
|
||||||
* If null, the message will be sent to all players and to console.
|
|
||||||
* @param sourcePlayer specifiy the eventual player that is the source of the message.
|
|
||||||
* If null, the message will be sent as a SYSTEM chat message.
|
|
||||||
* If not null, the message will be sent as a CHAT message, and will not be sent
|
|
||||||
* to players ignoring the provided player (if implemented).
|
|
||||||
* @throws IllegalArgumentException if message is null.
|
|
||||||
*/
|
|
||||||
public static void broadcast(ComponentLike message, boolean prefix, String permission, UUID sourcePlayer) {
|
|
||||||
broadcast(message, prefix, true, permission, sourcePlayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -2,7 +2,10 @@ package fr.pandacube.lib.players.standalone;
|
|||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface StandaloneOffPlayer {
|
/**
|
||||||
|
* Represents any player, either offline or online.
|
||||||
|
*/
|
||||||
|
public interface AbstractOffPlayer {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -12,20 +15,20 @@ public interface StandaloneOffPlayer {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the ID of the minecraft account.
|
* Returns the {@link UUID} of this player.
|
||||||
*
|
|
||||||
* @return the id of the player
|
* @return the id of the player
|
||||||
*/
|
*/
|
||||||
UUID getUniqueId();
|
UUID getUniqueId();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the last known player name of this player, or null if this player never joined the network.
|
* The last known player name of this player, or null if it is not known.
|
||||||
|
* @return the last known player name of this player, or null if it is not known.
|
||||||
*/
|
*/
|
||||||
String getName();
|
String getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicate if this player is connected to the current node (server or proxy, depending on interface implementation)
|
* Indicate if this player is connected to the current node (server or proxy, depending on interface implementation).
|
||||||
* @return wether the player is online or not
|
* @return wether the player is online or not.
|
||||||
*/
|
*/
|
||||||
boolean isOnline();
|
boolean isOnline();
|
||||||
|
|
||||||
@ -42,8 +45,9 @@ public interface StandaloneOffPlayer {
|
|||||||
/**
|
/**
|
||||||
* Return the online instance of this player, if any exists.
|
* Return the online instance of this player, if any exists.
|
||||||
* May return itself if the current instance already represent an online player.
|
* May return itself if the current instance already represent an online player.
|
||||||
|
* @return the online instance for this player.
|
||||||
*/
|
*/
|
||||||
StandaloneOnlinePlayer getOnlineInstance();
|
AbstractOnlinePlayer getOnlineInstance();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -55,9 +59,9 @@ public interface StandaloneOffPlayer {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the player (if any), with eventual prefix and suffix depending on permission groups
|
* Returns the display name of the player (if any), with eventual prefix and suffix depending on permission groups
|
||||||
* (and team for bukkit implementation)
|
* (and team for bukkit implementation).
|
||||||
* @return the display name of the player
|
* @return the display name of the player.
|
||||||
*/
|
*/
|
||||||
String getDisplayName();
|
String getDisplayName();
|
||||||
|
|
@ -9,7 +9,10 @@ import net.kyori.adventure.text.ComponentLike;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface StandaloneOnlinePlayer extends StandaloneOffPlayer {
|
/**
|
||||||
|
* Represents any online player.
|
||||||
|
*/
|
||||||
|
public interface AbstractOnlinePlayer extends AbstractOffPlayer {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -17,15 +20,19 @@ public interface StandaloneOnlinePlayer extends StandaloneOffPlayer {
|
|||||||
/*
|
/*
|
||||||
* General data and state
|
* General data and state
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The current name of this player
|
* Returns the name of the current server the player is in.
|
||||||
* @apiNote The implementation is expected to call the environment API
|
* The returned value is used by the 'pandalib-permissions' system.
|
||||||
* (Bukkit/Bungee) to get the name of the player.
|
* @return the name of the current server the player is in.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String getServerName();
|
String getServerName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the current world the player is in.
|
||||||
|
* The returned value is used by the 'pandalib-permissions' system.
|
||||||
|
* @return the name of the current world the player is in.
|
||||||
|
*/
|
||||||
String getWorldName();
|
String getWorldName();
|
||||||
|
|
||||||
|
|
||||||
@ -40,6 +47,8 @@ public interface StandaloneOnlinePlayer extends StandaloneOffPlayer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if this online player has the specified permission.
|
* Tells if this online player has the specified permission.
|
||||||
|
* @param permission the permission to test on that player.
|
||||||
|
* @return weither this player has the specified permission or not.
|
||||||
* @implSpec Implementation of this method should call the permission system of their environment (paper/bungee),
|
* @implSpec Implementation of this method should call the permission system of their environment (paper/bungee),
|
||||||
* so this method will work independently of the usage of the 'pandalib-permissions' module.
|
* so this method will work independently of the usage of the 'pandalib-permissions' module.
|
||||||
*/
|
*/
|
||||||
@ -58,15 +67,13 @@ public interface StandaloneOnlinePlayer extends StandaloneOffPlayer {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the provided message in the player’s chat, if
|
* Display the provided message in the player’s chat, if the chat is activated.
|
||||||
* the chat is activated.
|
|
||||||
* @param message the message to display.
|
* @param message the message to display.
|
||||||
*/
|
*/
|
||||||
void sendMessage(Component message);
|
void sendMessage(Component message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the provided message in the player’s chat, if
|
* Display the provided message in the player’s chat, if the chat is activated.
|
||||||
* the chat is activated.
|
|
||||||
* @param message the message to display.
|
* @param message the message to display.
|
||||||
*/
|
*/
|
||||||
default void sendMessage(ComponentLike message) {
|
default void sendMessage(ComponentLike message) {
|
||||||
@ -74,8 +81,7 @@ public interface StandaloneOnlinePlayer extends StandaloneOffPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the provided message in the player’s chat, if
|
* Display the provided message in the player’s chat, if they allows to display CHAT messages.
|
||||||
* they allows to display CHAT messages
|
|
||||||
* @param message the message to display.
|
* @param message the message to display.
|
||||||
* @param sender the player causing the send of this message. Client side filtering may occur.
|
* @param sender the player causing the send of this message. Client side filtering may occur.
|
||||||
* May be null if we don’t want client filtering, but still consider the message as CHAT message.
|
* May be null if we don’t want client filtering, but still consider the message as CHAT message.
|
||||||
@ -86,8 +92,7 @@ public interface StandaloneOnlinePlayer extends StandaloneOffPlayer {
|
|||||||
void sendMessage(Component message, Identified sender);
|
void sendMessage(Component message, Identified sender);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the provided message in the player’s chat, if
|
* Display the provided message in the player’s chat, if they allows to display CHAT messages.
|
||||||
* they allows to display CHAT messages
|
|
||||||
* @param message the message to display
|
* @param message the message to display
|
||||||
* @param sender the player causing the send of this message. Client side filtering may occur.
|
* @param sender the player causing the send of this message. Client side filtering may occur.
|
||||||
* May be null if we don’t want client filtering, but still consider the message as CHAT message.
|
* May be null if we don’t want client filtering, but still consider the message as CHAT message.
|
||||||
@ -100,8 +105,7 @@ public interface StandaloneOnlinePlayer extends StandaloneOffPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the provided message in the player’s chat, if the chat is
|
* Display the provided message in the player’s chat, if the chat is activated, prepended with the server prefix.
|
||||||
* activated, prepended with the server prefix.
|
|
||||||
* @param message the message to display
|
* @param message the message to display
|
||||||
*/
|
*/
|
||||||
default void sendPrefixedMessage(ComponentLike message) {
|
default void sendPrefixedMessage(ComponentLike message) {
|
||||||
@ -131,9 +135,8 @@ public interface StandaloneOnlinePlayer extends StandaloneOffPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the server brand field in the debug menu (F3) of the player
|
* Update the server brand field in the debug menu (F3) of the player (third line in 1.15 debug screen).
|
||||||
* (third line in 1.15 debug screen). Supports ChatColor codes but no
|
* Supports legacy section format but no line break.
|
||||||
* line break.
|
|
||||||
* @param brand the server brand to send to the client.
|
* @param brand the server brand to send to the client.
|
||||||
*/
|
*/
|
||||||
void sendServerBrand(String brand);
|
void sendServerBrand(String brand);
|
||||||
@ -148,47 +151,57 @@ public interface StandaloneOnlinePlayer extends StandaloneOffPlayer {
|
|||||||
/*
|
/*
|
||||||
* Client options
|
* Client options
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current client options of this player.
|
||||||
|
* @return the current client options of this player.
|
||||||
|
*/
|
||||||
ClientOptions getClientOptions();
|
ClientOptions getClientOptions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface providing various configuration values of the Minecraft client.
|
||||||
|
*/
|
||||||
interface ClientOptions {
|
interface ClientOptions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The language of the client interface.
|
||||||
|
* @return language of the client interface.
|
||||||
|
*/
|
||||||
Locale getLocale();
|
Locale getLocale();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The client view distance, in chunks.
|
||||||
|
* @return client view distance, in chunks.
|
||||||
|
*/
|
||||||
int getViewDistance();
|
int getViewDistance();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the chat displays the text colors.
|
||||||
|
* @return true if the chat displays the text colors, false otherwise.
|
||||||
|
*/
|
||||||
boolean hasChatColorEnabled();
|
boolean hasChatColorEnabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if the client is configured to completely hide the chat to the
|
* Tells if the client is configured to completely hide the chat to the player. When this is the case, nothing
|
||||||
* player. When this is the case, nothing is displayed in the chat box,
|
* is displayed in the chat box, and the player can’t send any message or command.
|
||||||
* and the player can’t send any message or command.
|
* @return true if the chat is fully hidden, false otherwise.
|
||||||
* @implSpec if the value is unknown, it is assumed that the chat is
|
|
||||||
* fully visible.
|
|
||||||
*/
|
*/
|
||||||
boolean isChatHidden();
|
boolean isChatHidden();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if the client is configured to display the chat normally.
|
* Tells if the client is configured to display the chat normally. When this is the case, chat messages and
|
||||||
* When this is the case, chat messages and system messages are
|
* system messages are displayed in the chat box, and the player can send messages and commands.
|
||||||
* displayed in the chat box, and the player can send messages and
|
* @return true if the chat is fully visible, false otherwise.
|
||||||
* commands.
|
|
||||||
* @implSpec if the value is unknown, it is assumed that the chat is
|
|
||||||
* fully visible.
|
|
||||||
*/
|
*/
|
||||||
boolean isChatFullyVisible();
|
boolean isChatFullyVisible();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if the client is configured to only display system messages
|
* Tells if the client is configured to only display system messages in the chat.
|
||||||
* in the chat.
|
* When this is the case, chat messages are hidden but system messages are visible in the chat box, and the
|
||||||
* When this is the case, chat messages are hidden but system messages
|
* player can only send commands.
|
||||||
* are visible in the chat box, and the player can only send commands.
|
* @return true if the chat is visible but only shows system messages, false otherwise.
|
||||||
* @implSpec if the value is unknown, it is assumed that the chat is
|
|
||||||
* fully visible.
|
|
||||||
*/
|
*/
|
||||||
boolean isChatOnlyDisplayingSystemMessages();
|
boolean isChatOnlyDisplayingSystemMessages();
|
||||||
|
|
||||||
@ -196,57 +209,85 @@ public interface StandaloneOnlinePlayer extends StandaloneOffPlayer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if the client has configured the main hand on the left.
|
* Tells if the client has configured the main hand on the left.
|
||||||
* @implSpec if the value is unknown, it is assumed that the main hand
|
* @return true if the player’s character is left handed, false otherwise.
|
||||||
* is on the right.
|
|
||||||
*/
|
*/
|
||||||
boolean isLeftHanded();
|
boolean isLeftHanded();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if the client has configured the main hand on the right.
|
* Tells if the client has configured the main hand on the right.
|
||||||
* @implSpec if the value is unknown, it is assumed that the main hand
|
* @return true if the player’s character is right handed, false otherwise.
|
||||||
* is on the right.
|
|
||||||
*/
|
*/
|
||||||
boolean isRightHanded();
|
boolean isRightHanded();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if the client has enabled the filtering of texts on sign and book titles.
|
* Tells if the client has enabled the filtering of texts on sign and book titles.
|
||||||
* Always false as of MC 1.18.
|
* @return true if the client filters swearing in texts, false otherwise.
|
||||||
*/
|
*/
|
||||||
boolean isTextFilteringEnabled();
|
boolean isTextFilteringEnabled();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if the client allows the server to list their player name in the
|
* Tells if the client allows the server to list their player name in the multiplayer menu.
|
||||||
* multiplayer menu.
|
* <b>To respect the player privacy’s configuration, this configuration value must be verified when generating
|
||||||
|
* custom ping response packet (MOTD in multiplayer server’s menu) that includes player names.</b>
|
||||||
|
* @return true if the client allows the server to list their player name in the multiplayer menu, false
|
||||||
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
boolean allowsServerListing();
|
boolean allowsServerListing();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if the cape is enabled on the player’s skin.
|
||||||
|
* @return true if the cape is enabled on the player’s skin, false otherwise.
|
||||||
|
*/
|
||||||
boolean hasSkinCapeEnabled();
|
boolean hasSkinCapeEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if the jacket is enabled on the player’s skin.
|
||||||
|
* @return true if the jacket is enabled on the player’s skin, false otherwise.
|
||||||
|
*/
|
||||||
boolean hasSkinJacketEnabled();
|
boolean hasSkinJacketEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if the left sleeve is enabled on the player’s skin.
|
||||||
|
* @return true if the left sleeve is enabled on the player’s skin, false otherwise.
|
||||||
|
*/
|
||||||
boolean hasSkinLeftSleeveEnabled();
|
boolean hasSkinLeftSleeveEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if the right sleeve is enabled on the player’s skin.
|
||||||
|
* @return true if the right sleeve is enabled on the player’s skin, false otherwise.
|
||||||
|
*/
|
||||||
boolean hasSkinRightSleeveEnabled();
|
boolean hasSkinRightSleeveEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if the left pants is enabled on the player’s skin.
|
||||||
|
* @return true if the left pants is enabled on the player’s skin, false otherwise.
|
||||||
|
*/
|
||||||
boolean hasSkinLeftPantsEnabled();
|
boolean hasSkinLeftPantsEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if the right pants is enabled on the player’s skin.
|
||||||
|
* @return true if the right pants is enabled on the player’s skin, false otherwise.
|
||||||
|
*/
|
||||||
boolean hasSkinRightPantsEnabled();
|
boolean hasSkinRightPantsEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if the hat is enabled on the player’s skin.
|
||||||
|
* @return true if the hat is enabled on the player’s skin, false otherwise.
|
||||||
|
*/
|
||||||
boolean hasSkinHatsEnabled();
|
boolean hasSkinHatsEnabled();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if the player can send chat messages or receive chat messages from
|
* Tells if the player can send chat messages or receive chat messages from other players, according to their client
|
||||||
* other players, according to their client configuration.
|
* configuration.
|
||||||
* <br>
|
* <p>
|
||||||
* Chat messages represent public communication between players. By default,
|
* Chat messages represent public communication between players. By default, it only include actual chat message.
|
||||||
* it only include actual chat message. This method may be used in commands
|
* This method may be used in commands like /me, /afk or the login/logout broadcasted messages.
|
||||||
* like /me, /afk or the login/logout broadcasted messages
|
* @return true if the player can send chat messages or receive chat messages from other players, false otherwise.
|
||||||
*/
|
*/
|
||||||
default boolean canChat() {
|
default boolean canChat() {
|
||||||
return getClientOptions().isChatFullyVisible();
|
return getClientOptions().isChatFullyVisible();
|
@ -0,0 +1,372 @@
|
|||||||
|
package fr.pandacube.lib.players.standalone;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader;
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.ComponentLike;
|
||||||
|
|
||||||
|
import fr.pandacube.lib.chat.ChatStatic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic implementation of a player manager, handling instances of {@link AbstractOffPlayer} and
|
||||||
|
* {@link AbstractOnlinePlayer}.
|
||||||
|
* Subclasses should handle the addition and removal of {@link AbstractOnlinePlayer} instances according to the
|
||||||
|
* currently online players.
|
||||||
|
* @param <OP> the type of subclass of {@link AbstractOnlinePlayer}
|
||||||
|
* @param <OF> the type of subclass of {@link AbstractOffPlayer}
|
||||||
|
*/
|
||||||
|
public abstract class AbstractPlayerManager<OP extends AbstractOnlinePlayer, OF extends AbstractOffPlayer> {
|
||||||
|
private static AbstractPlayerManager<?, ?> instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current instance of player manager.
|
||||||
|
* @return the player manager.
|
||||||
|
*/
|
||||||
|
public static synchronized AbstractPlayerManager<?, ?> getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static synchronized void setInstance(AbstractPlayerManager<?, ?> newInstance) {
|
||||||
|
if (instance != null) {
|
||||||
|
throw new IllegalStateException("cannot have multiple instance of PlayerManager");
|
||||||
|
}
|
||||||
|
instance = newInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final Map<UUID, OP> onlinePlayers = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
|
||||||
|
private final LoadingCache<UUID, OF> offlinePlayers = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterWrite(10, TimeUnit.MINUTES)
|
||||||
|
.build(CacheLoader.from(this::newOffPlayerInstance));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of player manager.
|
||||||
|
*/
|
||||||
|
public AbstractPlayerManager() {
|
||||||
|
setInstance(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the provided player to this player manager.
|
||||||
|
* Usually this is called by a player join event handler.
|
||||||
|
* @param p the player to add.
|
||||||
|
*/
|
||||||
|
protected void addPlayer(OP p) {
|
||||||
|
onlinePlayers.put(p.getUniqueId(), p);
|
||||||
|
offlinePlayers.invalidate(p.getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the player from this player manager.
|
||||||
|
* Usually this is called by a player quit event handler.
|
||||||
|
* @param p the UUID of the player to remove.
|
||||||
|
* @return the player that has been removed.
|
||||||
|
*/
|
||||||
|
protected OP removePlayer(UUID p) {
|
||||||
|
return onlinePlayers.remove(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the online player that has the provided UUID.
|
||||||
|
* @param p the UUID of the player.
|
||||||
|
* @return the online player instance.
|
||||||
|
*/
|
||||||
|
public OP get(UUID p) {
|
||||||
|
return onlinePlayers.get(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if the provided player is online.
|
||||||
|
* @param p the UUID of the player.
|
||||||
|
* @return true if the provided player is online (that is when this player manager contains an online player
|
||||||
|
* instance), false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isOnline(UUID p) {
|
||||||
|
return onlinePlayers.containsKey(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of online player registered in this player manager.
|
||||||
|
* @return the number of online player registered in this player manager.
|
||||||
|
*/
|
||||||
|
public int getPlayerCount() {
|
||||||
|
return onlinePlayers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the online players is this player manager.
|
||||||
|
* @return all the online players is this player manager.
|
||||||
|
*/
|
||||||
|
public List<OP> getAll() {
|
||||||
|
return new ArrayList<>(onlinePlayers.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an instance of {@link AbstractOffPlayer} corresponding to a player with the provided {@link UUID}.
|
||||||
|
* @param p the UUID of the player.
|
||||||
|
* @return an instance of {@link AbstractOffPlayer}. It can be a new instance, an {@link AbstractOnlinePlayer}
|
||||||
|
* instance if the player is online, or a cached instance of {@link AbstractOffPlayer}.
|
||||||
|
*/
|
||||||
|
public OF getOffline(UUID p) {
|
||||||
|
if (p == null)
|
||||||
|
return null;
|
||||||
|
OP online = get(p);
|
||||||
|
if (online != null) {
|
||||||
|
offlinePlayers.invalidate(p);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
OF ret = (OF) online;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
// if not online
|
||||||
|
try {
|
||||||
|
return offlinePlayers.get(p); // load and cache new instance if necessary
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
throw new UncheckedExecutionException(e.getCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance of the appropriate subclass of {@link AbstractOffPlayer}.
|
||||||
|
* @param p the uuid of the player.
|
||||||
|
* @return the new instance of {@link AbstractOffPlayer}.
|
||||||
|
*/
|
||||||
|
protected abstract OF newOffPlayerInstance(UUID p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract method to implement to send a message to the console.
|
||||||
|
* @param message the message to send to the console.
|
||||||
|
*/
|
||||||
|
protected abstract void sendMessageToConsole(Component message);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a message to some or all players, and eventually to the console.
|
||||||
|
*
|
||||||
|
* @param message the message to send.
|
||||||
|
* @param prefix if the server prefix will be prepended to the message.
|
||||||
|
* @param console if the message must be displayed in the console.
|
||||||
|
* @param permission if not null, the message is only sent to player with this permission.
|
||||||
|
* @param sourcePlayer specifiy the eventual player that is the source of the message.
|
||||||
|
* If null, the message will be sent as a SYSTEM chat message.
|
||||||
|
* If not null, the message will be sent as a CHAT message, and will not be sent
|
||||||
|
* to players ignoring the provided player (if implemented).
|
||||||
|
* @throws IllegalArgumentException if message is null.
|
||||||
|
* @implSpec subclasses may override this method, for instance to restrict the players being able to see the message
|
||||||
|
* (like /ignored players).
|
||||||
|
*/
|
||||||
|
public void broadcastMessage(ComponentLike message, boolean prefix, boolean console, String permission, UUID sourcePlayer) {
|
||||||
|
Objects.requireNonNull(message, "message cannot be null");
|
||||||
|
|
||||||
|
if (prefix)
|
||||||
|
message = ChatStatic.prefixedAndColored(message.asComponent());
|
||||||
|
|
||||||
|
for (OP op : getAll()) {
|
||||||
|
if (permission != null && !(op.hasPermission(permission))) continue;
|
||||||
|
|
||||||
|
if (sourcePlayer != null)
|
||||||
|
op.sendMessage(message, sourcePlayer); // CHAT message with UUID
|
||||||
|
else
|
||||||
|
op.sendMessage(message); // SYSTEM message
|
||||||
|
}
|
||||||
|
if (console)
|
||||||
|
sendMessageToConsole(message.asComponent());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Message broadcasting
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a message to some or all players, and eventually to the console.
|
||||||
|
*
|
||||||
|
* @param message the message to send.
|
||||||
|
* @param prefix if the server prefix will be prepended to the message.
|
||||||
|
* @param console if the message must be displayed in the console.
|
||||||
|
* @param permission if not null, the message is only sent to player with this permission.
|
||||||
|
* @param sourcePlayer specifiy the eventual player that is the source of the message.
|
||||||
|
* If null, the message will be sent as a SYSTEM chat message.
|
||||||
|
* If not null, the message will be sent as a CHAT message, and will not be sent
|
||||||
|
* to players ignoring the provided player (if implemented).
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if message is null.
|
||||||
|
*/
|
||||||
|
public static void broadcast(ComponentLike message, boolean prefix, boolean console, String permission, UUID sourcePlayer) {
|
||||||
|
getInstance().broadcastMessage(message, prefix, console, permission, sourcePlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a message to some or all players, and eventually to the console.
|
||||||
|
* <p>
|
||||||
|
* This method assumes this message is not caused by a specific player. To specify the source player, use
|
||||||
|
* {@link #broadcast(ComponentLike, boolean, boolean, String, UUID)}.
|
||||||
|
*
|
||||||
|
* @param message the message to send.
|
||||||
|
* @param prefix if the server prefix will be prepended to the message.
|
||||||
|
* @param console if the message must be displayed in the console.
|
||||||
|
* @param permission if not null, the message is only sent to player with this permission.
|
||||||
|
* @throws IllegalArgumentException if message is null.
|
||||||
|
*/
|
||||||
|
public static void broadcast(ComponentLike message, boolean prefix, boolean console, String permission) {
|
||||||
|
broadcast(message, prefix, console, permission, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a message to some or all players, and eventually to the console.
|
||||||
|
* <p>
|
||||||
|
* This method assumes this message is not caused by a specific player. To specify the source player, use
|
||||||
|
* {@link #broadcast(ComponentLike, boolean, String, UUID)}.
|
||||||
|
* <p>
|
||||||
|
* This method decides to send the message to the console depending on whether {@code permission}
|
||||||
|
* is null (will send to console) or not (will not send to console). To specify this behaviour, use
|
||||||
|
* {@link #broadcast(ComponentLike, boolean, boolean, String)}.
|
||||||
|
*
|
||||||
|
* @param message the message to send.
|
||||||
|
* @param prefix if the server prefix will be prepended to the message.
|
||||||
|
* @param permission if not null, the message is only sent to player with this permission (but not to console).
|
||||||
|
* If null, the message will be sent to all players and to console.
|
||||||
|
* @throws IllegalArgumentException if message is null.
|
||||||
|
*/
|
||||||
|
public static void broadcast(ComponentLike message, boolean prefix, String permission) {
|
||||||
|
broadcast(message, prefix, (permission == null), permission, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a message to all players, and to the console.
|
||||||
|
* <p>
|
||||||
|
* This method sends the message to the console. To change this behaviour, use
|
||||||
|
* {@link #broadcast(ComponentLike, boolean, boolean, String, UUID)}.
|
||||||
|
*
|
||||||
|
* @param message the message to send.
|
||||||
|
* @param prefix if the server prefix will be prepended to the message.
|
||||||
|
* @param permission if not null, the message is only sent to player with this permission (but not to console).
|
||||||
|
* If null, the message will be sent to all players and to console.
|
||||||
|
* @param sourcePlayer specifiy the eventual player that is the source of the message.
|
||||||
|
* If null, the message will be sent as a SYSTEM chat message.
|
||||||
|
* If not null, the message will be sent as a CHAT message, and will not be sent
|
||||||
|
* to players ignoring the provided player (if implemented).
|
||||||
|
* @throws IllegalArgumentException if message is null.
|
||||||
|
*/
|
||||||
|
public static void broadcast(ComponentLike message, boolean prefix, String permission, UUID sourcePlayer) {
|
||||||
|
broadcast(message, prefix, true, permission, sourcePlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a message to some or all players, and eventually to the console.
|
||||||
|
* <p>
|
||||||
|
* This method doesn’t restrict to a specific permission. To change this behaviour, use
|
||||||
|
* {@link #broadcast(ComponentLike, boolean, boolean, String, UUID)}.
|
||||||
|
*
|
||||||
|
* @param message the message to send.
|
||||||
|
* @param prefix if the server prefix will be prepended to the message.
|
||||||
|
* @param console if the message must be displayed in the console.
|
||||||
|
* @param sourcePlayer specifiy the eventual player that is the source of the message.
|
||||||
|
* If null, the message will be sent as a SYSTEM chat message.
|
||||||
|
* If not null, the message will be sent as a CHAT message, and will not be sent
|
||||||
|
* to players ignoring the provided player (if implemented).
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if message is null.
|
||||||
|
*/
|
||||||
|
public static void broadcast(ComponentLike message, boolean prefix, boolean console, UUID sourcePlayer) {
|
||||||
|
getInstance().broadcastMessage(message, prefix, console, null, sourcePlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a message to some or all players, and eventually to the console.
|
||||||
|
* <p>
|
||||||
|
* This method assumes this message is not caused by a specific player. To specify the source player, use
|
||||||
|
* {@link #broadcast(ComponentLike, boolean, boolean, UUID)}.
|
||||||
|
* <p>
|
||||||
|
* This method doesn’t restrict to a specific permission. To change this behaviour, use
|
||||||
|
* {@link #broadcast(ComponentLike, boolean, boolean, String)}.
|
||||||
|
*
|
||||||
|
* @param message the message to send.
|
||||||
|
* @param prefix if the server prefix will be prepended to the message.
|
||||||
|
* @param console if the message must be displayed in the console.
|
||||||
|
* @throws IllegalArgumentException if message is null.
|
||||||
|
*/
|
||||||
|
public static void broadcast(ComponentLike message, boolean prefix, boolean console) {
|
||||||
|
broadcast(message, prefix, console, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a message to all players, and to the console.
|
||||||
|
* <p>
|
||||||
|
* This method sends the message to the console. To change this behaviour, use
|
||||||
|
* {@link #broadcast(ComponentLike, boolean, boolean, UUID)}.
|
||||||
|
* <p>
|
||||||
|
* This method doesn’t restrict to a specific permission. To change this behaviour, use
|
||||||
|
* {@link #broadcast(ComponentLike, boolean, String, UUID)}.
|
||||||
|
*
|
||||||
|
* @param message the message to send.
|
||||||
|
* @param prefix if the server prefix will be prepended to the message.
|
||||||
|
* @param sourcePlayer specifiy the eventual player that is the source of the message.
|
||||||
|
* If null, the message will be sent as a SYSTEM chat message.
|
||||||
|
* If not null, the message will be sent as a CHAT message, and will not be sent
|
||||||
|
* to players ignoring the provided player (if implemented).
|
||||||
|
* @throws IllegalArgumentException if message is null.
|
||||||
|
*/
|
||||||
|
public static void broadcast(ComponentLike message, boolean prefix, UUID sourcePlayer) {
|
||||||
|
broadcast(message, prefix, true, null, sourcePlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a message to all players, and to the console.
|
||||||
|
* <p>
|
||||||
|
* This method assumes this message is not caused by a specific player. To specify the source player, use
|
||||||
|
* {@link #broadcast(ComponentLike, boolean, UUID)}.
|
||||||
|
* <p>
|
||||||
|
* This method sends the message to the console. To change this behaviour, use
|
||||||
|
* {@link #broadcast(ComponentLike, boolean, boolean)}.
|
||||||
|
* <p>
|
||||||
|
* This method doesn’t restrict to a specific permission. To change this behaviour, use
|
||||||
|
* {@link #broadcast(ComponentLike, boolean, String)}.
|
||||||
|
*
|
||||||
|
* @param message the message to send.
|
||||||
|
* @param prefix if the server prefix will be prepended to the message.
|
||||||
|
* @throws IllegalArgumentException if message is null.
|
||||||
|
*/
|
||||||
|
public static void broadcast(ComponentLike message, boolean prefix) {
|
||||||
|
broadcast(message, prefix, true, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,216 +0,0 @@
|
|||||||
package fr.pandacube.lib.players.standalone;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
|
||||||
import com.google.common.cache.CacheLoader;
|
|
||||||
import com.google.common.cache.LoadingCache;
|
|
||||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.ComponentLike;
|
|
||||||
|
|
||||||
import fr.pandacube.lib.chat.ChatStatic;
|
|
||||||
|
|
||||||
public abstract class StandalonePlayerManager<OP extends StandaloneOnlinePlayer, OF extends StandaloneOffPlayer> {
|
|
||||||
private static StandalonePlayerManager<?, ?> instance;
|
|
||||||
|
|
||||||
public static synchronized StandalonePlayerManager<?, ?> getInstance() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static synchronized void setInstance(StandalonePlayerManager<?, ?> newInstance) {
|
|
||||||
if (instance != null) {
|
|
||||||
throw new IllegalStateException("cannot have multiple instance of PlayerManager");
|
|
||||||
}
|
|
||||||
instance = newInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private final Map<UUID, OP> onlinePlayers = Collections.synchronizedMap(new HashMap<>());
|
|
||||||
|
|
||||||
private final LoadingCache<UUID, OF> offlinePlayers = CacheBuilder.newBuilder()
|
|
||||||
.expireAfterWrite(10, TimeUnit.MINUTES)
|
|
||||||
.build(CacheLoader.from(this::newOffPlayerInstance));
|
|
||||||
|
|
||||||
|
|
||||||
public StandalonePlayerManager() {
|
|
||||||
setInstance(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected void addPlayer(OP p) {
|
|
||||||
onlinePlayers.put(p.getUniqueId(), p);
|
|
||||||
offlinePlayers.invalidate(p.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected OP removePlayer(UUID p) {
|
|
||||||
return onlinePlayers.remove(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
public OP get(UUID p) {
|
|
||||||
return onlinePlayers.get(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOnline(UUID p) {
|
|
||||||
return onlinePlayers.containsKey(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPlayerCount() {
|
|
||||||
return onlinePlayers.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<OP> getAll() {
|
|
||||||
return new ArrayList<>(onlinePlayers.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
public OF getOffline(UUID p) {
|
|
||||||
if (p == null)
|
|
||||||
return null;
|
|
||||||
OP online = get(p);
|
|
||||||
if (online != null) {
|
|
||||||
offlinePlayers.invalidate(p);
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
OF ret = (OF) online;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
// if not online
|
|
||||||
try {
|
|
||||||
return offlinePlayers.get(p); // load and cache new instance if necessary
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
throw new UncheckedExecutionException(e.getCause());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected abstract OF newOffPlayerInstance(UUID p);
|
|
||||||
|
|
||||||
protected abstract void sendMessageToConsole(Component message);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void broadcastMessage(ComponentLike message, boolean prefix, boolean console, String permission, UUID sourcePlayer) {
|
|
||||||
Objects.requireNonNull(message, "message cannot be null");
|
|
||||||
|
|
||||||
if (prefix)
|
|
||||||
message = ChatStatic.prefixedAndColored(message.asComponent());
|
|
||||||
|
|
||||||
for (StandaloneOnlinePlayer op : getAll()) {
|
|
||||||
if (sourcePlayer != null)
|
|
||||||
op.sendMessage(message, sourcePlayer); // CHAT message without UUID
|
|
||||||
else
|
|
||||||
op.sendMessage(message); // SYSTEM message
|
|
||||||
}
|
|
||||||
|
|
||||||
if (console)
|
|
||||||
getInstance().sendMessageToConsole(message.asComponent());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Message broadcasting
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ComponentLike message
|
|
||||||
// boolean prefix
|
|
||||||
// boolean console = (permission == null)
|
|
||||||
// UUID sourcePlayer = null
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcast a message to some or all players, and eventually to the console.
|
|
||||||
*
|
|
||||||
* @param message the message to send.
|
|
||||||
* @param prefix if the server prefix will be prepended to the message.
|
|
||||||
* @param console if the message must be displayed in the console.
|
|
||||||
* @param sourcePlayer specifiy the eventual player that is the source of the message.
|
|
||||||
* If null, the message will be sent as a SYSTEM chat message.
|
|
||||||
* If not null, the message will be sent as a CHAT message, and will not be sent
|
|
||||||
* to players ignoring the provided player (if implemented).
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException if message is null.
|
|
||||||
*/
|
|
||||||
public static void broadcast(ComponentLike message, boolean prefix, boolean console, UUID sourcePlayer) {
|
|
||||||
getInstance().broadcastMessage(message, prefix, console, null, sourcePlayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcast a message to some or all players, and eventually to the console.
|
|
||||||
* <p>
|
|
||||||
* This method assumes this message is not caused by a specific player. To specify the source player, use
|
|
||||||
* {@link #broadcast(ComponentLike, boolean, boolean, UUID)}.
|
|
||||||
*
|
|
||||||
* @param message the message to send.
|
|
||||||
* @param prefix if the server prefix will be prepended to the message.
|
|
||||||
* @param console if the message must be displayed in the console.
|
|
||||||
* @throws IllegalArgumentException if message is null.
|
|
||||||
*/
|
|
||||||
public static void broadcast(ComponentLike message, boolean prefix, boolean console) {
|
|
||||||
broadcast(message, prefix, console, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcast a message to all players, and to the console.
|
|
||||||
* <p>
|
|
||||||
* This method sends the message to the console. To change this behaviour, use
|
|
||||||
* {@link #broadcast(ComponentLike, boolean, boolean, UUID)}.
|
|
||||||
*
|
|
||||||
* @param message the message to send.
|
|
||||||
* @param prefix if the server prefix will be prepended to the message.
|
|
||||||
* @param sourcePlayer specifiy the eventual player that is the source of the message.
|
|
||||||
* If null, the message will be sent as a SYSTEM chat message.
|
|
||||||
* If not null, the message will be sent as a CHAT message, and will not be sent
|
|
||||||
* to players ignoring the provided player (if implemented).
|
|
||||||
* @throws IllegalArgumentException if message is null.
|
|
||||||
*/
|
|
||||||
public static void broadcast(ComponentLike message, boolean prefix, UUID sourcePlayer) {
|
|
||||||
broadcast(message, prefix, true, sourcePlayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcast a message to all players, and to the console.
|
|
||||||
* <p>
|
|
||||||
* This method assumes this message is not caused by a specific player. To specify the source player, use
|
|
||||||
* {@link #broadcast(ComponentLike, boolean, UUID)}.
|
|
||||||
* <p>
|
|
||||||
* This method sends the message to the console. To change this behaviour, use
|
|
||||||
* {@link #broadcast(ComponentLike, boolean, boolean)}.
|
|
||||||
*
|
|
||||||
* @param message the message to send.
|
|
||||||
* @param prefix if the server prefix will be prepended to the message.
|
|
||||||
* @throws IllegalArgumentException if message is null.
|
|
||||||
*/
|
|
||||||
public static void broadcast(ComponentLike message, boolean prefix) {
|
|
||||||
broadcast(message, prefix, true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -12,5 +12,9 @@ import java.lang.annotation.Target;
|
|||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface ConcreteWrapper {
|
public @interface ConcreteWrapper {
|
||||||
|
/**
|
||||||
|
* The class representing a dummy implementation of the annotated wrapper interface.
|
||||||
|
* @return the class representing a dummy implementation of the annotated wrapper interface.
|
||||||
|
*/
|
||||||
Class<? extends ReflectWrapper> value();
|
Class<? extends ReflectWrapper> value();
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,11 @@ import java.util.function.Supplier;
|
|||||||
|
|
||||||
import fr.pandacube.lib.util.MappedListView;
|
import fr.pandacube.lib.util.MappedListView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper for a list of wrapped object. It is an extension of {@link MappedListView} that is used to transparently
|
||||||
|
* wrap/unwrap the elements of the backend list.
|
||||||
|
* @param <W> the type of the reflect wrapper for the elements of this list.
|
||||||
|
*/
|
||||||
public class ReflectListWrapper<W extends ReflectWrapperI> extends MappedListView<Object, W> implements ReflectWrapperTypedI<List<Object>> {
|
public class ReflectListWrapper<W extends ReflectWrapperI> extends MappedListView<Object, W> implements ReflectWrapperTypedI<List<Object>> {
|
||||||
|
|
||||||
private final Class<W> expectedWrapperClass;
|
private final Class<W> expectedWrapperClass;
|
||||||
@ -14,11 +19,12 @@ public class ReflectListWrapper<W extends ReflectWrapperI> extends MappedListVie
|
|||||||
this(ArrayList::new, expectedWrapperClass);
|
this(ArrayList::new, expectedWrapperClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
ReflectListWrapper(Supplier<List<?>> listCreator, Class<W> expectedWrapperClass) {
|
/* package */ ReflectListWrapper(Supplier<List<?>> listCreator, Class<W> expectedWrapperClass) {
|
||||||
this((List<Object>) (listCreator == null ? new ArrayList<>() : listCreator.get()), expectedWrapperClass);
|
this((List<Object>) (listCreator == null ? new ArrayList<>() : listCreator.get()), expectedWrapperClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ ReflectListWrapper(List<Object> wrappedList, Class<W> expectedWrapperClass) {
|
/* package */ ReflectListWrapper(List<Object> wrappedList, Class<W> expectedWrapperClass) {
|
||||||
super(wrappedList, el -> ReflectWrapper.wrap(el, expectedWrapperClass), ReflectWrapper::unwrap);
|
super(wrappedList, el -> ReflectWrapper.wrap(el, expectedWrapperClass), ReflectWrapper::unwrap);
|
||||||
this.expectedWrapperClass = expectedWrapperClass;
|
this.expectedWrapperClass = expectedWrapperClass;
|
||||||
|
@ -10,25 +10,79 @@ import java.util.Objects;
|
|||||||
|
|
||||||
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
|
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Superclass of all reflect wrapper objects.
|
||||||
|
*/
|
||||||
public abstract class ReflectWrapper implements ReflectWrapperI {
|
public abstract class ReflectWrapper implements ReflectWrapperI {
|
||||||
|
|
||||||
|
|
||||||
private static final Map<Object, ReflectWrapperI> objectWrapperCache = new MapMaker().weakKeys().makeMap();
|
private static final Map<Object, ReflectWrapperI> objectWrapperCache = new MapMaker().weakKeys().makeMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unwraps the object from the provided reflect wrapper.
|
||||||
|
* @param wr the reflect wrapper from which to get the object.
|
||||||
|
* @return the object from the provided reflect wrapper.
|
||||||
|
*/
|
||||||
public static Object unwrap(ReflectWrapperI wr) {
|
public static Object unwrap(ReflectWrapperI wr) {
|
||||||
return wr == null ? null : wr.__getRuntimeInstance();
|
return wr == null ? null : wr.__getRuntimeInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unwraps the object from the provided reflect wrapper.
|
||||||
|
* @param wr the reflect wrapper from which to get the object.
|
||||||
|
* @param <T> the type of the wrapped object.
|
||||||
|
* @return the object from the provided reflect wrapper.
|
||||||
|
*/
|
||||||
public static <T> T unwrap(ReflectWrapperTypedI<T> wr) {
|
public static <T> T unwrap(ReflectWrapperTypedI<T> wr) {
|
||||||
return wr == null ? null : wr.__getRuntimeInstance();
|
return wr == null ? null : wr.__getRuntimeInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <W extends ReflectWrapperI> W wrap(Object runtimeObj) {
|
/**
|
||||||
|
* Wraps the provided runtime object into a reflect wrapper.
|
||||||
|
* If a wrapper instance is already known, it will return it instead of instanciating a new one.
|
||||||
|
* It is better to call {@link #wrap(Object, Class)} if you know the type of wrapper needed.
|
||||||
|
* @param runtimeObj the object to wrap.
|
||||||
|
* @return the reflect wrapper wrapping the provided object.
|
||||||
|
* @throws ClassCastException if the runtime class of the object is not handled by the expected wrapper class or its
|
||||||
|
* subclasses.
|
||||||
|
* @throws IllegalArgumentException if the runtime class of the object is not handled by any of the registered
|
||||||
|
* wrapper classes.
|
||||||
|
*/
|
||||||
|
public static ReflectWrapperI wrap(Object runtimeObj) {
|
||||||
return wrap(runtimeObj, null);
|
return wrap(runtimeObj, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the provided runtime object (with has a known type) into a reflect wrapper.
|
||||||
|
* If a wrapper instance is already known, it will return it instead of instanciating a new one.
|
||||||
|
* It is better to call {@link #wrap(Object, Class)} if you know the type of wrapper needed.
|
||||||
|
* @param runtimeObj the object to wrap.
|
||||||
|
* @param expectedWrapperClass the reflect wrapper class expected to be returned.
|
||||||
|
* @param <W> the type of the reflect wrapper.
|
||||||
|
* @param <T> the type of the wrapped object.
|
||||||
|
* @return the reflect wrapper wrapping the provided object.
|
||||||
|
* @throws ClassCastException if the runtime class of the object is not handled by the expected wrapper class or its
|
||||||
|
* subclasses.
|
||||||
|
* @throws IllegalArgumentException if the runtime class of the object is not handled by any of the registered
|
||||||
|
* wrapper classes.
|
||||||
|
*/
|
||||||
public static <T, W extends ReflectWrapperTypedI<T>> W wrapTyped(T runtimeObj, Class<W> expectedWrapperClass) {
|
public static <T, W extends ReflectWrapperTypedI<T>> W wrapTyped(T runtimeObj, Class<W> expectedWrapperClass) {
|
||||||
return wrap(runtimeObj, expectedWrapperClass);
|
return wrap(runtimeObj, expectedWrapperClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the provided runtime object into a reflect wrapper.
|
||||||
|
* If a wrapper instance is already known, it will return it instead of instanciating a new one.
|
||||||
|
* It is better to call {@link #wrap(Object, Class)} if you know the type of wrapper needed.
|
||||||
|
* @param runtimeObj the object to wrap.
|
||||||
|
* @param expectedWrapperClass the reflect wrapper class expected to be returned.
|
||||||
|
* @param <W> the type of the reflect wrapper.
|
||||||
|
* @return the reflect wrapper wrapping the provided object.
|
||||||
|
* @throws ClassCastException if the runtime class of the object is not handled by the expected wrapper class or its
|
||||||
|
* subclasses.
|
||||||
|
* @throws IllegalArgumentException if the runtime class of the object is not handled by any of the registered
|
||||||
|
* wrapper classes.
|
||||||
|
*/
|
||||||
public static <W extends ReflectWrapperI> W wrap(Object runtimeObj, Class<W> expectedWrapperClass) {
|
public static <W extends ReflectWrapperI> W wrap(Object runtimeObj, Class<W> expectedWrapperClass) {
|
||||||
if (runtimeObj == null)
|
if (runtimeObj == null)
|
||||||
return null;
|
return null;
|
||||||
@ -73,16 +127,36 @@ public abstract class ReflectWrapper implements ReflectWrapperI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the provided runtime list into a reflect list wrapper.
|
||||||
|
* @param runtimeList the list of runtime object to wrap.
|
||||||
|
* @param expectedWrapperClass the wrapper class of the objects in this list.
|
||||||
|
* @param <W> the type of reflect wrapper for the objects in this list.
|
||||||
|
* @return a reflect list wrapper wrapping the provided list.
|
||||||
|
*/
|
||||||
public static <W extends ReflectWrapperI> ReflectListWrapper<W> wrapList(List<Object> runtimeList, Class<W> expectedWrapperClass) {
|
public static <W extends ReflectWrapperI> ReflectListWrapper<W> wrapList(List<Object> runtimeList, Class<W> expectedWrapperClass) {
|
||||||
return new ReflectListWrapper<>(runtimeList, expectedWrapperClass);
|
return new ReflectListWrapper<>(runtimeList, expectedWrapperClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected final Object reflectObject;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final Object reflectObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instanciate this Reflect Wrapper with the provided object.
|
||||||
|
* Any subclasses should not make their constructor public since the instanciation is managed by {@link #wrap(Object, Class) wrap(...)}.
|
||||||
|
* @param obj the object to wrap. It must be an instance of the {@link #__getRuntimeClass() runtime class} of this
|
||||||
|
* wrapper class.
|
||||||
|
*/
|
||||||
protected ReflectWrapper(Object obj) {
|
protected ReflectWrapper(Object obj) {
|
||||||
Objects.requireNonNull(obj);
|
Objects.requireNonNull(obj);
|
||||||
if (!__getRuntimeClass().isInstance(obj)) {
|
if (!__getRuntimeClass().isInstance(obj)) {
|
||||||
|
@ -1,11 +1,22 @@
|
|||||||
package fr.pandacube.lib.reflect.wrapper;
|
package fr.pandacube.lib.reflect.wrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface implemented by all reflect wrapper objects.
|
||||||
|
*/
|
||||||
public interface ReflectWrapperI {
|
public interface ReflectWrapperI {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the class of the wrapped object.
|
||||||
|
* @return the class of the wrapped object.
|
||||||
|
*/
|
||||||
default Class<?> __getRuntimeClass() {
|
default Class<?> __getRuntimeClass() {
|
||||||
return WrapperRegistry.getRuntimeClassOfWrapperClass(getClass());
|
return WrapperRegistry.getRuntimeClassOfWrapperClass(getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the wrapped object.
|
||||||
|
* @return the wrapped object.
|
||||||
|
*/
|
||||||
Object __getRuntimeInstance();
|
Object __getRuntimeInstance();
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,17 @@
|
|||||||
package fr.pandacube.lib.reflect.wrapper;
|
package fr.pandacube.lib.reflect.wrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Superclass of all reflect wrapper objects which wrapped objet type is statically known.
|
||||||
|
* @param <T> the type (or supertype) of the wrapped object.
|
||||||
|
*/
|
||||||
public abstract class ReflectWrapperTyped<T> extends ReflectWrapper implements ReflectWrapperTypedI<T> {
|
public abstract class ReflectWrapperTyped<T> extends ReflectWrapper implements ReflectWrapperTypedI<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instanciate this Reflect Wrapper with the provided object.
|
||||||
|
* Any subclasses should not make their constructor public since the instanciation is managed by {@link #wrap(Object, Class) wrap(...)}.
|
||||||
|
* @param obj the object to wrap. It must be an instance of the {@link #__getRuntimeClass() runtime class} of this
|
||||||
|
* wrapper class.
|
||||||
|
*/
|
||||||
protected ReflectWrapperTyped(Object obj) {
|
protected ReflectWrapperTyped(Object obj) {
|
||||||
super(obj);
|
super(obj);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package fr.pandacube.lib.reflect.wrapper;
|
package fr.pandacube.lib.reflect.wrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface implemented by all reflect wrapper objects which wrapped objet type is statically known.
|
||||||
|
* @param <T> the type (or supertype) of the wrapped object.
|
||||||
|
*/
|
||||||
public interface ReflectWrapperTypedI<T> extends ReflectWrapperI {
|
public interface ReflectWrapperTypedI<T> extends ReflectWrapperI {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user