Refactor PlayerManager API + little fixes in Chat API

This commit is contained in:
2022-07-21 02:19:28 +02:00
parent d4471f2845
commit f4d436671c
23 changed files with 781 additions and 1824 deletions

View File

@@ -0,0 +1,153 @@
package fr.pandacube.lib.players.permissible;
import java.util.OptionalLong;
import java.util.stream.LongStream;
import fr.pandacube.lib.chat.ChatColorUtil;
import fr.pandacube.lib.permissions.PermPlayer;
import fr.pandacube.lib.permissions.Permissions;
import fr.pandacube.lib.players.standalone.StandaloneOffPlayer;
public interface PermissibleOffPlayer extends StandaloneOffPlayer {
/*
* Related class instances
*/
/**
* Return the online instance of this player, if any exists.
* May return itself if the current instance already represent an online player.
*/
PermissibleOnlinePlayer getOnlineInstance();
/**
* Get the permission instance of this player. This will never return null.
* @return the permission instance of this player
*/
default PermPlayer getPermissionUser() {
return Permissions.getPlayer(getUniqueId());
}
/*
* Display name
*/
/**
* Get an updated display name of the user,
* generated using eventual permissions prefix(es) and suffix(es) of the player,
* and with color codes translated to Minecrafts native {@code §}.
*/
default String getDisplayNameFromPermissionSystem() {
PermPlayer permU = getPermissionUser();
return ChatColorUtil.translateAlternateColorCodes('&',
permU.getPrefix() + getName() + permU.getSuffix());
}
/*
* Permissions and groups
*/
/**
* Tells if this player has the specified permission.
* If the player is online, this will redirect the
* method call to the {@link PermissibleOnlinePlayer} instance,
* that MUST override this current method to avoid recussive
* loop.
* If the player is offline, it just call the Pandacube
* permission system.
* @param permission the permission node to test
* @return whether this player has the provided permission
*/
default boolean hasPermission(String permission) {
PermissibleOnlinePlayer online = getOnlineInstance();
if (online != null)
return online.hasPermission(permission);
// at this point, the player is offline
return getPermissionUser().hasPermissionOr(permission, null, null, false);
}
/**
* Tells if this player has the permission resulted from the provided expression.
* If the player is online, this will redirect the
* method call to the {@link PermissibleOnlinePlayer} instance,
* that MUST override this current method to avoid recussive
* loop.
* If the player is offline, it just call the Pandacube
* permission system.
* @param permissionExpression the permission node to test
* @return whether this player has the provided permission
*/
default boolean hasPermissionExpression(String permissionExpression) {
PermissibleOnlinePlayer online = getOnlineInstance();
if (online != null)
return online.hasPermissionExpression(permissionExpression);
// at this point, the player is offline
return getPermissionUser().hasPermissionExpression(permissionExpression, null, null);
}
/**
* Lists all the values for a set of permission indicating an integer in a range.
* <p>
* A permission range is used to easily attribute a number to a group or player,
* like the maximum number of homes allowed. For instance, if the player has the permission
* {@code essentials.home.12}, this method would return a stream containing the value 12,
* if the parameter {@code permissionPrefix} is {@code "essentials.home."}.
* <p>
* The use of a stream allow the caller to get either the maximum, the minimum, or do any
* other treatment to the values.
* @param permissionPrefix the permission prefix to search for.
* @return a LongStream containing all the values found for the specified permission prefix.
*/
default LongStream getPermissionRangeValues(String permissionPrefix) {
PermissibleOnlinePlayer online = getOnlineInstance();
if (online != null)
return online.getPermissionRangeValues(permissionPrefix);
// at this point, the player is offline
return getPermissionUser().getPermissionRangeValues(permissionPrefix, null, null);
}
/**
* Returns the maximum value returned by {@link PermissibleOffPlayer#getPermissionRangeValues(String)}.
*/
default OptionalLong getPermissionRangeMax(String permissionPrefix) {
PermissibleOnlinePlayer online = getOnlineInstance();
if (online != null)
return online.getPermissionRangeMax(permissionPrefix);
// at this point, the player is offline
return getPermissionUser().getPermissionRangeMax(permissionPrefix, null, null);
}
/**
* Tells if the this player is part of the specified group
*
* @param group the permissions group
* @return <i>true</i> if this player is part of the group,
* <i>false</i> otherwise
*/
default boolean isInGroup(String group) {
return getPermissionUser().isInGroup(group);
}
}

View File

@@ -0,0 +1,72 @@
package fr.pandacube.lib.players.permissible;
import java.util.OptionalLong;
import java.util.stream.LongStream;
import fr.pandacube.lib.players.standalone.StandaloneOnlinePlayer;
public interface PermissibleOnlinePlayer extends PermissibleOffPlayer, StandaloneOnlinePlayer {
/*
* General data and state
*/
/**
* @return The current name of this player
* @implSpec The implementation is expected to call the environment API
* (Bukkit/Bungee) to get the name of the player.
*/
String getName();
/*
* Permissions and groups
*/
/**
* Tells if this online player has the specified permission.
* @implSpec the implementation of this method must not directly or
* indirectly call the method {@link PermissibleOffPlayer#hasPermission(String)},
* or it may result in a {@link StackOverflowError}.
*/
boolean hasPermission(String permission);
/**
* Tells if this online player has the permission resulted from the provided expression.
* @implSpec the implementation of this method must not directly or
* indirectly call the method {@link PermissibleOffPlayer#hasPermissionExpression(String)},
* or it may result in a {@link StackOverflowError}.
*/
boolean hasPermissionExpression(String permission);
/**
* Lists all the values for a set of permission indicating an integer in a range.
* <p>
* A permission range is used to easily attribute a number to a group or player,
* like the maximum number of homes allowed. For instance, if the player has the permission
* {@code essentials.home.12}, this method would return a stream containing the value 12,
* if the parameter {@code permissionPrefix} is {@code "essentials.home."}.
* <p>
* The use of a stream allow the caller to get either the maximum, the minimum, or do any
* other treatment to the values.
* @param permissionPrefix the permission prefix to search for.
* @return a LongStream containing all the values found for the specified permission prefix.
*/
LongStream getPermissionRangeValues(String permissionPrefix);
/**
* Returns the maximum value returned by {@link PermissibleOffPlayer#getPermissionRangeValues(String)}.
*/
OptionalLong getPermissionRangeMax(String permissionPrefix);
}

View File

@@ -0,0 +1,140 @@
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);
}
}