Attempts to start proper implementation of the new action cost
All checks were successful
EpicKnarvik97/Blacksmith/pipeline/head This commit looks good
All checks were successful
EpicKnarvik97/Blacksmith/pipeline/head This commit looks good
This commit is contained in:
@@ -2,33 +2,26 @@ package net.knarcraft.blacksmith.util;
|
||||
|
||||
import net.knarcraft.blacksmith.container.ActionCost;
|
||||
import net.knarcraft.blacksmith.formatting.Translatable;
|
||||
import net.knarcraft.blacksmith.property.CostModifyAction;
|
||||
import net.knarcraft.blacksmith.property.CostType;
|
||||
import net.knarcraft.knarlib.formatting.FormatBuilder;
|
||||
import org.bukkit.Bukkit;
|
||||
import net.knarcraft.knarlib.util.TabCompletionHelper;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* A helper class for setting action costs
|
||||
*/
|
||||
public final class CostHelper {
|
||||
|
||||
private static List<String> plugins;
|
||||
private static Map<String, List<String>> permissions;
|
||||
|
||||
private CostHelper() {
|
||||
|
||||
}
|
||||
@@ -38,10 +31,10 @@ public final class CostHelper {
|
||||
*
|
||||
* @param commandSender <p>The command sender to notify of any problems</p>
|
||||
* @param costString <p>The string to parse into a cost</p>
|
||||
* @return <p>The parsed cost</p>
|
||||
* @throws IllegalArgumentException <p>If the specified cost is invalid</p>
|
||||
* @return <p>The parsed cost, or null if not a valid number</p>
|
||||
*/
|
||||
public static double parseSimpleCost(@NotNull CommandSender commandSender,
|
||||
@Nullable
|
||||
public static Double parseSimpleCost(@NotNull CommandSender commandSender,
|
||||
@NotNull String costString) throws IllegalArgumentException {
|
||||
try {
|
||||
double cost = Double.parseDouble(costString);
|
||||
@@ -51,7 +44,7 @@ public final class CostHelper {
|
||||
return cost;
|
||||
} catch (NumberFormatException exception) {
|
||||
new FormatBuilder(Translatable.DOUBLE_COST_REQUIRED).error(commandSender);
|
||||
throw new IllegalArgumentException("Invalid cost given");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,23 +55,19 @@ public final class CostHelper {
|
||||
* @return <p>The available tab-complete options</p>
|
||||
*/
|
||||
public static @Nullable List<String> tabCompleteCost(@NotNull String[] arguments) {
|
||||
if (plugins == null) {
|
||||
loadAvailablePermissions();
|
||||
}
|
||||
|
||||
if (arguments.length == 1) {
|
||||
return List.of("simple", "advanced");
|
||||
} else if (arguments.length == 2) {
|
||||
if (arguments[0].equalsIgnoreCase("simple")) {
|
||||
return List.of("");
|
||||
return List.of();
|
||||
} else {
|
||||
return List.of("add", "set", "clear");
|
||||
return TabCompletionHelper.filterMatchingStartsWith(TabCompletionHelper.getEnumList(CostModifyAction.class), arguments[1]);
|
||||
}
|
||||
} else if (arguments.length == 3) {
|
||||
if (arguments[0].equalsIgnoreCase("simple")) {
|
||||
return List.of("");
|
||||
return List.of();
|
||||
} else {
|
||||
return List.of("economy", "item", "exp", "permission");
|
||||
return TabCompletionHelper.filterMatchingStartsWith(TabCompletionHelper.getEnumList(CostType.class), arguments[2]);
|
||||
}
|
||||
} else if (arguments.length == 4) {
|
||||
CostType costType = CostType.parse(arguments[2]);
|
||||
@@ -86,7 +75,7 @@ public final class CostHelper {
|
||||
return null;
|
||||
}
|
||||
return switch (costType) {
|
||||
case PERMISSION -> tabCompletePermission(arguments[3]);
|
||||
case PERMISSION -> TabCompletionHelper.tabCompletePermission(arguments[3]);
|
||||
case ECONOMY -> List.of("0.5", "1", "10");
|
||||
case EXP -> List.of("1, 5, 10");
|
||||
case ITEM -> List.of();
|
||||
@@ -98,86 +87,123 @@ public final class CostHelper {
|
||||
/**
|
||||
* Modifies the cost of an action
|
||||
*
|
||||
* @param arguments <p>The arguments given by a player</p>
|
||||
* @param oldCost <p>The previous cost of the action</p>
|
||||
* @param player <p>The player attempting to alter the action cost</p>
|
||||
* @param costAction <p>The action to perform on the cost</p>
|
||||
* @param costTypeName <p>The name of the cost to modify, or null if clearing costs</p>
|
||||
* @param costValue <p>The value of the new cost, or null if clearing costs</p>
|
||||
* @param oldCost <p>The previous cost of the action</p>
|
||||
* @param player <p>The player attempting to alter the action cost</p>
|
||||
* @return <p>The modified action cost, or null if something went wrong</p>
|
||||
*/
|
||||
@Nullable
|
||||
public static ActionCost modifyActionCost(@NotNull String[] arguments, @NotNull ActionCost oldCost,
|
||||
public static ActionCost modifyActionCost(@NotNull String costAction, @Nullable String costTypeName,
|
||||
@Nullable String costValue, @NotNull ActionCost oldCost,
|
||||
@NotNull Player player) {
|
||||
CostType costType;
|
||||
if (arguments.length > 2) {
|
||||
costType = CostType.parse(arguments[2]);
|
||||
if (costTypeName != null) {
|
||||
costType = CostType.parse(costTypeName);
|
||||
} else {
|
||||
costType = null;
|
||||
}
|
||||
|
||||
switch (arguments[1].toLowerCase()) {
|
||||
case "add":
|
||||
if (costType == null) {
|
||||
player.sendMessage("Invalid cost type specified!");
|
||||
return null;
|
||||
}
|
||||
return parseCost(costType, Arrays.copyOfRange(arguments, 2, arguments.length), oldCost, player);
|
||||
case "clear":
|
||||
// Clears one or all fields of a cost
|
||||
if (costType == null) {
|
||||
return new ActionCost(0, 0, null, Set.of());
|
||||
} else {
|
||||
return switch (costType) {
|
||||
case EXP -> oldCost.changeExpCost(0);
|
||||
case ITEM -> oldCost.changeItemCost(null);
|
||||
case ECONOMY -> oldCost.changeMonetaryCost(0);
|
||||
case PERMISSION -> oldCost.changePermissionCost(Set.of());
|
||||
};
|
||||
}
|
||||
case "set":
|
||||
if (costType == null) {
|
||||
player.sendMessage("Invalid cost type specified!");
|
||||
return null;
|
||||
}
|
||||
return parseCost(costType, Arrays.copyOfRange(arguments, 2, arguments.length),
|
||||
new ActionCost(0, 0, null, Set.of()), player);
|
||||
default:
|
||||
return null;
|
||||
CostModifyAction action = CostModifyAction.fromString(costAction);
|
||||
if (action == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (action != CostModifyAction.CLEAR && (costType == null || costValue == null)) {
|
||||
player.sendMessage("Invalid cost type or value specified!");
|
||||
return null;
|
||||
}
|
||||
|
||||
return switch (action) {
|
||||
case CLEAR -> clearActionCost(costType, oldCost);
|
||||
case ADD -> addActionCost(costType, costValue, oldCost, player);
|
||||
case SET -> setActionCost(costType, costValue, player);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cost to the specified value
|
||||
*
|
||||
* @param costType <p>The type of cost to set</p>
|
||||
* @param costValue <p>The value of the new cost</p>
|
||||
* @param player <p>The player to alert if the cost cannot be properly set</p>
|
||||
* @return <p>The new action cost</p>
|
||||
*/
|
||||
public static ActionCost setActionCost(@NotNull CostType costType, @NotNull String costValue,
|
||||
@NotNull Player player) {
|
||||
return parseCost(costType, costValue, new ActionCost(), player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies a value for the specified action cost
|
||||
*
|
||||
* @param costType <p>The type of cost to modify</p>
|
||||
* @param costValue <p>The new value of the cost</p>
|
||||
* @param oldCost <p>The cost to modify</p>
|
||||
* @param player <p>The player to alert if the cost cannot be properly set</p>
|
||||
* @return <p>The new action cost</p>
|
||||
*/
|
||||
public static ActionCost addActionCost(@NotNull CostType costType, @NotNull String costValue,
|
||||
@NotNull ActionCost oldCost, @NotNull Player player) {
|
||||
return parseCost(costType, costValue, oldCost, player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears an action cost
|
||||
*
|
||||
* @param costType <p>The type of action cost to clear, or null if clearing all action costs</p>
|
||||
* @param oldCost <p>The old cost to modify, or null if clearing all action costs</p>
|
||||
* @return <p>The modified cost</p>
|
||||
*/
|
||||
public static ActionCost clearActionCost(@Nullable CostType costType, @Nullable ActionCost oldCost) {
|
||||
// Clears one or all fields of a cost
|
||||
if (costType == null || oldCost == null) {
|
||||
return new ActionCost();
|
||||
} else {
|
||||
return switch (costType) {
|
||||
case EXP -> oldCost.changeExpCost(0);
|
||||
case ITEM -> oldCost.changeItemCost(null);
|
||||
case ECONOMY -> oldCost.changeMonetaryCost(0);
|
||||
case PERMISSION -> oldCost.changePermissionCost(Set.of());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an advanced action cost
|
||||
*
|
||||
* @param costType <p>The type of cost to parse</p>
|
||||
* @param arguments <p>The arguments given by the player</p>
|
||||
* @param oldCost <p>The old cost to modify</p>
|
||||
* @param player <p>The player changing the value</p>
|
||||
* @param costType <p>The type of cost to parse</p>
|
||||
* @param value <p>The value to parse</p>
|
||||
* @param oldCost <p>The old cost to modify</p>
|
||||
* @param player <p>The player changing the value</p>
|
||||
* @return <p>The new action cost, or null if the process failed.</p>
|
||||
*/
|
||||
@Nullable
|
||||
private static ActionCost parseCost(@NotNull CostType costType, @NotNull String[] arguments, @NotNull ActionCost oldCost,
|
||||
private static ActionCost parseCost(@NotNull CostType costType, @NotNull String value, @NotNull ActionCost oldCost,
|
||||
@NotNull Player player) {
|
||||
switch (costType) {
|
||||
case ECONOMY:
|
||||
double economyCost = Double.parseDouble(arguments[0]);
|
||||
double economyCost = Double.parseDouble(value);
|
||||
if (economyCost < 0) {
|
||||
player.sendMessage("Cost cannot be negative!");
|
||||
new FormatBuilder("Cost cannot be negative!").error(player);
|
||||
return null;
|
||||
}
|
||||
return oldCost.changeMonetaryCost(economyCost);
|
||||
case ITEM:
|
||||
ItemStack itemCost = player.getInventory().getItemInMainHand();
|
||||
if (itemCost.getType().isAir()) {
|
||||
player.sendMessage("You have no item in your main hand");
|
||||
new FormatBuilder("You have no item in your main hand").error(player);
|
||||
return null;
|
||||
}
|
||||
return oldCost.changeItemCost(itemCost);
|
||||
case PERMISSION:
|
||||
Set<String> permissionSet = new HashSet<>(Arrays.asList(arguments[0].split(",")));
|
||||
Set<String> permissionSet = new HashSet<>(Arrays.asList(value.split(",")));
|
||||
return oldCost.changePermissionCost(permissionSet);
|
||||
case EXP:
|
||||
int expCost = Integer.parseInt(arguments[0]);
|
||||
int expCost = Integer.parseInt(value);
|
||||
if (expCost < 0) {
|
||||
player.sendMessage("Exp cost cannot be negative!");
|
||||
new FormatBuilder("Exp cost cannot be negative!").error(player);
|
||||
return null;
|
||||
}
|
||||
return oldCost.changeExpCost(expCost);
|
||||
@@ -186,103 +212,4 @@ public final class CostHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tab complete value for the permission typed
|
||||
*
|
||||
* @param typedNode <p>The full permission node typed by the player</p>
|
||||
* @return <p>All known valid auto-complete options</p>
|
||||
*/
|
||||
private static @NotNull List<String> tabCompletePermission(@NotNull String typedNode) {
|
||||
StringBuilder permissionListString = new StringBuilder();
|
||||
if (typedNode.contains(",")) {
|
||||
String[] permissionList = typedNode.split(",");
|
||||
for (int i = 0; i < permissionList.length - 1; i++) {
|
||||
permissionListString.append(permissionList[i]);
|
||||
permissionListString.append(",");
|
||||
}
|
||||
typedNode = permissionList[permissionList.length - 1];
|
||||
}
|
||||
String permissionPrefix = permissionListString.toString();
|
||||
List<String> output;
|
||||
if (typedNode.contains(".")) {
|
||||
List<String> matchingPermissions = permissions.get(typedNode.substring(0, typedNode.lastIndexOf(".")));
|
||||
if (matchingPermissions == null) {
|
||||
if (permissionPrefix.isEmpty()) {
|
||||
output = new ArrayList<>();
|
||||
} else {
|
||||
List<String> onlyPrefix = new ArrayList<>();
|
||||
onlyPrefix.add(permissionPrefix);
|
||||
output = onlyPrefix;
|
||||
}
|
||||
} else {
|
||||
//Filter by the typed text
|
||||
output = filterMatching(matchingPermissions, typedNode);
|
||||
}
|
||||
} else {
|
||||
output = plugins;
|
||||
}
|
||||
|
||||
//Add previous permissions in the comma-separated lists as a prefix
|
||||
if (permissionPrefix.isEmpty()) {
|
||||
return output;
|
||||
} else {
|
||||
List<String> prefixed = new ArrayList<>(output.size());
|
||||
for (String matchingCompletion : output) {
|
||||
prefixed.add(permissionPrefix + matchingCompletion);
|
||||
}
|
||||
return prefixed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find completable strings which match the text typed by the command's sender
|
||||
*
|
||||
* @param values <p>The values to filter</p>
|
||||
* @param typedText <p>The text the player has started typing</p>
|
||||
* @return <p>The given string values which start with the player's typed text</p>
|
||||
*/
|
||||
private static @NotNull List<String> filterMatching(@NotNull List<String> values, @NotNull String typedText) {
|
||||
List<String> configValues = new ArrayList<>();
|
||||
for (String value : values) {
|
||||
if (value.toLowerCase().startsWith(typedText.toLowerCase())) {
|
||||
configValues.add(value);
|
||||
}
|
||||
}
|
||||
return configValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all permissions available from bukkit plugins
|
||||
*/
|
||||
private static void loadAvailablePermissions() {
|
||||
plugins = new ArrayList<>();
|
||||
permissions = new HashMap<>();
|
||||
|
||||
for (Permission permission : Bukkit.getPluginManager().getPermissions()) {
|
||||
loadPermission(permission.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a given permission into the proper lists and maps
|
||||
*
|
||||
* @param permissionName <p>The permission to load</p>
|
||||
*/
|
||||
private static void loadPermission(@NotNull String permissionName) {
|
||||
String[] permissionParts = permissionName.split("\\.");
|
||||
if (permissionParts.length == 1 && !plugins.contains(permissionParts[0])) {
|
||||
plugins.add(permissionParts[0]);
|
||||
} else if (permissionParts.length > 1) {
|
||||
StringJoiner pathJoiner = new StringJoiner(".");
|
||||
for (int j = 0; j < permissionParts.length - 1; j++) {
|
||||
pathJoiner.add(permissionParts[j]);
|
||||
}
|
||||
String path = pathJoiner.toString();
|
||||
List<String> permissionList = permissions.computeIfAbsent(path, k -> new ArrayList<>());
|
||||
permissionList.add(permissionName);
|
||||
|
||||
loadPermission(path);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user