Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@

import org.bukkit.command.CommandSender;

import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import com.bencodez.advancedcore.AdvancedCorePlugin;

public abstract class PlayerCommandHandler extends CommandHandler {

private int playerArg = -1;
public abstract class PlayerCommandHandler extends CommandHandler {

private static final String ALL_SELECTOR_SENTINEL = new String("__advancedcore_all_selector__");
private int playerArg = -1;
private final Set<String> allPermissionOverrides = new LinkedHashSet<>();
private final Set<String> legacyAllPermissionAliases = new LinkedHashSet<>();
private final ThreadLocal<Boolean> legacyBulkDispatch = ThreadLocal.withInitial(() -> Boolean.FALSE);

public PlayerCommandHandler(AdvancedCorePlugin plugin) {
super(plugin);
Expand Down Expand Up @@ -39,47 +46,83 @@ public PlayerCommandHandler(AdvancedCorePlugin plugin, String[] args, String per
figureOutPlayerArg();
}

@Override
public void execute(CommandSender sender, String[] args) {
if (playerArg >= 0) {
if (args[playerArg].equalsIgnoreCase("all")) {
if (hasAllPermission(sender)) {
executeAll(sender, args);
}
return;
}
}
executeSinglePlayer(sender, args);
@Override
public boolean runCommand(CommandSender sender, String[] args) {
if (args == null) return false;
if (playerArg < 0 || playerArg >= args.length
|| !"all".equalsIgnoreCase(args[playerArg])) return super.runCommand(sender, args);
String[] preservedArgs = args.clone();
preservedArgs[playerArg] = ALL_SELECTOR_SENTINEL;
boolean legacyAlias = hasLegacyAllPermissionAlias(sender);
if (legacyAlias) legacyBulkDispatch.set(Boolean.TRUE);
try {
return super.runCommand(sender, preservedArgs);
} finally {
if (legacyAlias) legacyBulkDispatch.remove();
}
}

@Override
public boolean hasPerm(CommandSender sender) {
return Boolean.TRUE.equals(legacyBulkDispatch.get()) && hasLegacyAllPermissionAlias(sender)
|| super.hasPerm(sender);
}

@Override
public void execute(CommandSender sender, String[] args) {
String[] schema = getArgs();
if (playerArg < 0 || schema == null || args == null || args.length < schema.length
|| playerArg >= args.length) {
return;
}
if (args[playerArg] == null || args[playerArg].isBlank()) return;
if (args[playerArg].equalsIgnoreCase("all") || args[playerArg] == ALL_SELECTOR_SENTINEL) {
if (hasAllPermission(sender)) {
if (args[playerArg] == ALL_SELECTOR_SENTINEL) args[playerArg] = "all";
executeAll(sender, args);
} else {
String noPermission = formatNoPerms();
if (noPermission != null && !noPermission.isEmpty()) sendMessage(sender, noPermission);
}
return;
}
executeSinglePlayer(sender, args);
}

public abstract void executeAll(CommandSender sender, String[] args);

public abstract void executeSinglePlayer(CommandSender sender, String[] args);

/**
* Checks the stronger permission required for the special {@code all} target.
* The first configured permission is treated as the granular command permission
* and receives an {@code .All} suffix. Any alternative permissions, such as an
* administrator permission, continue to act as overrides.
* Checks the complete authorization required for the special {@code all} target.
* Ordinary command authorization is required first, followed by either one of
* the dedicated bulk permissions or an explicitly configured administrator
* override. Overrides honor the handler's multiple-permission setting.
*
* @param sender command sender
* @return whether bulk execution is authorized
*/
public boolean hasAllPermission(CommandSender sender) {
String permission = getPerm();
if (permission == null || permission.isEmpty()) {
return false;
List<String> configured = configuredPermissions();
if (sender == null || configured.isEmpty()) return false;
if (hasLegacyAllPermissionAlias(sender)) return true;
if (!hasPerm(sender)) return false;
int limit = isAllowMultiplePermissions() ? configured.size() : 1;
for (int i = 0; i < limit; i++) {
String permission = configured.get(i);
// Keep the granular permission and its bulk node paired. A bulk node
// for one alternative must not combine with the base node of another.
if (!sender.hasPermission(permission)) continue;
if (allPermissionOverrides.contains(permission)
|| sender.hasPermission(permission + ".All")) return true;
}
String[] permissions = permission.split(Pattern.quote("|"));
if (sender.hasPermission(permissions[0] + ".All")) {
return true;
}
if (isAllowMultiplePermissions()) {
for (int i = 1; i < permissions.length; i++) {
if (sender.hasPermission(permissions[i])) {
return true;
}
}
return false;
}

private boolean hasLegacyAllPermissionAlias(CommandSender sender) {
if (sender == null) return false;
for (String alias : legacyAllPermissionAliases) {
if (sender.hasPermission(alias)) return true;
}
return false;
}
Expand All @@ -89,24 +132,99 @@ public boolean hasAllPermission(CommandSender sender) {
* command permission. Permission-listing commands can use this without granting
* the bulk permission during ordinary command checks.
*
* @return the dedicated permission for the {@code all} target
* @return dedicated permissions for the {@code all} target
*/
public List<String> getAdditionalPermissions() {
List<String> configured = configuredPermissions();
if (configured.isEmpty()) return Collections.emptyList();
ArrayList<String> permissions = derivedAllPermissions(configured, isAllowMultiplePermissions());
permissions.addAll(legacyAllPermissionAliases);
return Collections.unmodifiableList(permissions);
}

private ArrayList<String> derivedAllPermissions(List<String> configured, boolean includeAlternatives) {
LinkedHashSet<String> permissions = new LinkedHashSet<>();
int limit = includeAlternatives ? configured.size() : 1;
for (int i = 0; i < limit; i++) {
String permission = configured.get(i);
if (!allPermissionOverrides.contains(permission)) permissions.add(permission + ".All");
}
return new ArrayList<>(permissions);
}

/**
* Marks configured permission alternatives that are full administrator
* overrides, rather than granular permissions which need their own
* {@code .All} node. Unknown or malformed values are ignored and can never
* grant bulk access.
*
* @param permissions configured administrator permission alternatives
* @return this handler
*/
public PlayerCommandHandler withAllPermissionOverrides(String... permissions) {
allPermissionOverrides.clear();
List<String> configured = configuredPermissions();
if (permissions == null || configured.isEmpty()) return this;
for (String permission : permissions) {
if (permission != null && configured.contains(permission)) allPermissionOverrides.add(permission);
}
return this;
}

/**
* Retains a previously published permission that represented the complete bulk
* operation by itself. Unlike a normal configured alternative, an alias never
* grants named-player execution.
*/
public PlayerCommandHandler withLegacyAllPermissionAliases(String... permissions) {
legacyAllPermissionAliases.clear();
if (permissions == null) return this;
for (String permission : permissions) {
if (permission != null && !permission.isBlank() && !permission.endsWith(".All")
&& permission.chars().noneMatch(Character::isWhitespace)) {
legacyAllPermissionAliases.add(permission);
}
}
return this;
}

/** Returns the valid administrator alternatives used by bulk authorization. */
public List<String> getAllPermissionOverrides() {
return Collections.unmodifiableList(configuredAllPermissionOverrides());
}

private ArrayList<String> configuredAllPermissionOverrides() {
ArrayList<String> overrides = new ArrayList<>();
for (String permission : configuredPermissions()) {
if (allPermissionOverrides.contains(permission)) overrides.add(permission);
}
return overrides;
}

private List<String> configuredPermissions() {
String permission = getPerm();
if (permission == null || permission.isEmpty()) {
return Collections.emptyList();
if (permission == null || permission.isBlank()) return Collections.emptyList();
String[] values = permission.split(Pattern.quote("|"), -1);
ArrayList<String> permissions = new ArrayList<>(values.length);
for (String value : values) {
if (value.isBlank() || value.endsWith(".All")
|| value.chars().anyMatch(Character::isWhitespace)) return Collections.emptyList();
permissions.add(value);
}
return Collections.singletonList(permission.split(Pattern.quote("|"))[0] + ".All");
return permissions;
}

private void figureOutPlayerArg() {
for (int i = 0; i < getArgs().length; i++) {
if (getArgs()[i].equalsIgnoreCase("(player)")) {
playerArg = i;
return;
}
}
getPlugin().devDebug("Failed to figure out player arg number for: " + getArgs());

private void figureOutPlayerArg() {
playerArg = -1;
String[] args = getArgs();
if (args == null) return;
for (int i = 0; i < args.length; i++) {
if ("(player)".equalsIgnoreCase(args[i])) {
playerArg = i;
return;
}
}
getPlugin().devDebug("Failed to figure out player arg number for: " + java.util.Arrays.toString(args));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public void run() {
});
}, null);
}
});
});

cmds.add(new CommandHandler(plugin, new String[] { "RunSQLQuery", "(List)" }, permPrefix + ".RunSQLQuery",
"Execute sql query", true, true) {
Expand Down Expand Up @@ -247,7 +247,7 @@ public void run() {
}

@Override
public void executeSinglePlayer(CommandSender sender, String[] args) {
public void executeSinglePlayer(CommandSender sender, String[] args) {
AdvancedCoreUser user = plugin.getUserManager().getUser(args[1]);
plugin.getRewardHandler().giveReward(user, args[3], new RewardOptions().setOnline(user.isOnline()));
sender.sendMessage("&cGave " + args[1] + " the reward file " + args[3]);
Expand Down Expand Up @@ -536,52 +536,27 @@ public void execute(CommandSender sender, String[] args) {
});
}

cmds.add(new CommandHandler(plugin, new String[] { "User", "All", "SetData", "(text)", "(text)" },
permPrefix + ".SetAllData", "Set all users data") {

@Override
public void execute(CommandSender sender, String[] args) {
String data = args[4];
if (data.equalsIgnoreCase("\"\"")) {
data = "";
}

final String key = args[3];
final String value = data;

plugin.getUserManager().forEachUserKeys((uuid, columns) -> {
AdvancedCoreUser user = plugin.getUserManager().getUser(uuid, false);
user.userDataFetechMode(UserDataFetchMode.NO_CACHE);
user.getData().setString(key, value);
}, (count) -> {
sender.sendMessage(MessageAPI.colorize("&cSet all users " + key + " to " + args[4]));
});
}
});

cmds.add(new PlayerCommandHandler(plugin, new String[] { "User", "(player)", "SetData", "(text)", "(text)" },
cmds.add(new PlayerCommandHandler(plugin, new String[] { "User", "(player)", "SetData", "(text)", "(text)" },
permPrefix + ".SetData", "Set user data") {

@Override
public void executeAll(CommandSender sender, String[] args) {
if (sender.hasPermission(permPrefix + ".SetAllData")) {
String data = args[4];
if (data.equalsIgnoreCase("\"\"")) {
data = "";
}

final String key = args[3];
final String value = data;

plugin.getUserManager().forEachUserKeys((uuid, columns) -> {
AdvancedCoreUser user = plugin.getUserManager().getUser(uuid, false);
user.userDataFetechMode(UserDataFetchMode.NO_CACHE);
user.getData().setString(key, value);
}, (count) -> {
sender.sendMessage(MessageAPI.colorize("&cSet all users " + key + " to " + args[4]));
});
}
}
@Override
public void executeAll(CommandSender sender, String[] args) {
String data = args[4];
if (data.equalsIgnoreCase("\"\"")) {
data = "";
}

final String key = args[3];
final String value = data;

plugin.getUserManager().forEachUserKeys((uuid, columns) -> {
AdvancedCoreUser user = plugin.getUserManager().getUser(uuid, false);
user.userDataFetechMode(UserDataFetchMode.NO_CACHE);
user.getData().setString(key, value);
}, (count) -> {
sender.sendMessage(MessageAPI.colorize("&cSet all users " + key + " to " + args[4]));
});
}

@Override
public void executeSinglePlayer(CommandSender sender, String[] args) {
Expand All @@ -591,9 +566,9 @@ public void executeSinglePlayer(CommandSender sender, String[] args) {
data = "";
}
user.getData().setString(args[3], data);
sender.sendMessage(MessageAPI.colorize("&cSet " + args[3] + " for " + args[1] + " to " + args[4]));
}
});
sender.sendMessage(MessageAPI.colorize("&cSet " + args[3] + " for " + args[1] + " to " + args[4]));
}
}.withLegacyAllPermissionAliases(permPrefix + ".SetAllData"));

cmds.add(new CommandHandler(plugin, new String[] { "User", "(Player)", "ViewData" }, permPrefix + ".ViewData",
"View playerdata") {
Expand Down
Loading
Loading