Adds more unfinished code for parsing and tab-completing advanced 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:
parent
42ca42c571
commit
ad5066af4b
2
pom.xml
2
pom.xml
@ -65,7 +65,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.21.3-R0.1-SNAPSHOT</version>
|
<version>1.21.4-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -3,16 +3,31 @@ package net.knarcraft.blacksmith.command;
|
|||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.container.ActionCost;
|
import net.knarcraft.blacksmith.container.ActionCost;
|
||||||
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
||||||
|
import net.knarcraft.blacksmith.property.CostType;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.TabExecutor;
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.permissions.Permission;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
public class CostCommand implements TabExecutor {
|
public class CostCommand implements TabExecutor {
|
||||||
|
|
||||||
|
private static List<String> plugins;
|
||||||
|
private static Map<String, List<String>> permissions;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] arguments) {
|
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] arguments) {
|
||||||
//TODO: Whenever a cost is specified (not for the per-material and per-enchantment costs), allow either a simple
|
//TODO: Whenever a cost is specified (not for the per-material and per-enchantment costs), allow either a simple
|
||||||
@ -20,33 +35,27 @@ public class CostCommand implements TabExecutor {
|
|||||||
// TODO: The command should look like "blacksmithEdit <option> <simple|advanced> <double|economy|item|permission|exp>
|
// TODO: The command should look like "blacksmithEdit <option> <simple|advanced> <double|economy|item|permission|exp>
|
||||||
// <double|blank/null|comma-separated-string|integer>"
|
// <double|blank/null|comma-separated-string|integer>"
|
||||||
|
|
||||||
|
if (!(commandSender instanceof Player player)) {
|
||||||
|
commandSender.sendMessage("This command can only be used by players");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: Check arguments size
|
//TODO: Check arguments size
|
||||||
if (arguments.length < 2) {
|
if (arguments.length < 2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActionCost oldCost = new ActionCost(0, 0, null, Set.of());
|
||||||
|
|
||||||
ActionCost actionCost;
|
ActionCost actionCost;
|
||||||
|
|
||||||
switch (arguments[0]) {
|
switch (arguments[0].toLowerCase()) {
|
||||||
case "simple":
|
case "simple":
|
||||||
// TODO: Do something with the cost
|
// TODO: Do something with the cost
|
||||||
double cost = parseSimpleCost(commandSender, arguments[1]);
|
double cost = parseSimpleCost(commandSender, arguments[1]);
|
||||||
break;
|
break;
|
||||||
case "advanced":
|
case "advanced":
|
||||||
switch (arguments[1]) {
|
actionCost = modifyActionCost(arguments, oldCost, player);
|
||||||
case "economy":
|
|
||||||
// TODO: Expect the next argument to be the cost
|
|
||||||
break;
|
|
||||||
case "item":
|
|
||||||
// TODO: The next argument would either be "null" to clear the value, or "mainHand" to use the item in the player's main hand
|
|
||||||
break;
|
|
||||||
case "permission":
|
|
||||||
// TODO: The next argument will be a comma-separated list of permissions
|
|
||||||
break;
|
|
||||||
case "exp":
|
|
||||||
// TODO: Expect the next argument to be an integer
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@ -56,10 +65,129 @@ public class CostCommand implements TabExecutor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command,
|
public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command,
|
||||||
@NotNull String s, @NotNull String[] strings) {
|
@NotNull String s, @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("");
|
||||||
|
} else {
|
||||||
|
return List.of("add", "set", "clear");
|
||||||
|
}
|
||||||
|
} else if (arguments.length == 3) {
|
||||||
|
if (arguments[0].equalsIgnoreCase("simple")) {
|
||||||
|
return List.of("");
|
||||||
|
} else {
|
||||||
|
return List.of("economy", "item", "exp", "permission");
|
||||||
|
}
|
||||||
|
} else if (arguments.length == 4) {
|
||||||
|
CostType costType = CostType.parse(arguments[2]);
|
||||||
|
if (costType == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return switch (costType) {
|
||||||
|
case PERMISSION -> tabCompletePermission(arguments[3]);
|
||||||
|
case ECONOMY -> List.of("0.5", "1", "10");
|
||||||
|
case EXP -> List.of("1, 5, 10");
|
||||||
|
case ITEM -> List.of();
|
||||||
|
};
|
||||||
|
}
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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>
|
||||||
|
* @return <p>The modified action cost, or null if something went wrong</p>
|
||||||
|
*/
|
||||||
|
private ActionCost modifyActionCost(@NotNull String[] arguments, @NotNull ActionCost oldCost, @NotNull Player player) {
|
||||||
|
CostType costType;
|
||||||
|
if (arguments.length > 2) {
|
||||||
|
costType = CostType.parse(arguments[2]);
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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>
|
||||||
|
* @return <p>The new action cost, or null if the process failed.</p>
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private ActionCost parseCost(@NotNull CostType costType, @NotNull String[] arguments, @NotNull ActionCost oldCost,
|
||||||
|
@NotNull Player player) {
|
||||||
|
switch (costType) {
|
||||||
|
case ECONOMY:
|
||||||
|
double economyCost = Double.parseDouble(arguments[0]);
|
||||||
|
if (economyCost < 0) {
|
||||||
|
player.sendMessage("Cost cannot be negative!");
|
||||||
|
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");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return oldCost.changeItemCost(itemCost);
|
||||||
|
case PERMISSION:
|
||||||
|
Set<String> permissionSet = new HashSet<>(Arrays.asList(arguments[0].split(",")));
|
||||||
|
return oldCost.changePermissionCost(permissionSet);
|
||||||
|
case EXP:
|
||||||
|
int expCost = Integer.parseInt(arguments[0]);
|
||||||
|
if (expCost < 0) {
|
||||||
|
player.sendMessage("Exp cost cannot be negative!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return oldCost.changeExpCost(expCost);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a simple double cost
|
* Parses a simple double cost
|
||||||
*
|
*
|
||||||
@ -83,4 +211,103 @@ public class CostCommand implements TabExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 @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 @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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,46 @@ import java.util.Set;
|
|||||||
public record ActionCost(double monetaryCost, int expCost, @Nullable ItemStack itemCost,
|
public record ActionCost(double monetaryCost, int expCost, @Nullable ItemStack itemCost,
|
||||||
@NotNull Set<String> requiredPermissions) implements ConfigurationSerializable {
|
@NotNull Set<String> requiredPermissions) implements ConfigurationSerializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the monetary cost of this action
|
||||||
|
*
|
||||||
|
* @param monetaryCost <p>The new monetary cost</p>
|
||||||
|
* @return <p>The resulting action cost</p>
|
||||||
|
*/
|
||||||
|
public ActionCost changeMonetaryCost(double monetaryCost) {
|
||||||
|
return new ActionCost(monetaryCost, this.expCost, this.itemCost, this.requiredPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the experience cost of this action
|
||||||
|
*
|
||||||
|
* @param expCost <p>The new experience cost</p>
|
||||||
|
* @return <p>The resulting action cost</p>
|
||||||
|
*/
|
||||||
|
public ActionCost changeExpCost(int expCost) {
|
||||||
|
return new ActionCost(this.monetaryCost, expCost, this.itemCost, this.requiredPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the item cost of this action
|
||||||
|
*
|
||||||
|
* @param itemCost <p>The new item cost</p>
|
||||||
|
* @return <p>The resulting action cost</p>
|
||||||
|
*/
|
||||||
|
public ActionCost changeItemCost(@Nullable ItemStack itemCost) {
|
||||||
|
return new ActionCost(this.monetaryCost, this.expCost, itemCost, this.requiredPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the permission cost of this action
|
||||||
|
*
|
||||||
|
* @param requiredPermissions <p>The new permission cost</p>
|
||||||
|
* @return <p>The resulting action cost</p>
|
||||||
|
*/
|
||||||
|
public ActionCost changePermissionCost(@NotNull Set<String> requiredPermissions) {
|
||||||
|
return new ActionCost(this.monetaryCost, this.expCost, this.itemCost, requiredPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public String displayCost() {
|
public String displayCost() {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
package net.knarcraft.blacksmith.property;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of costs applicable to an advanced cost configuration
|
||||||
|
*/
|
||||||
|
public enum CostType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A monetary cost from an economy plugin
|
||||||
|
*/
|
||||||
|
ECONOMY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A permission requirement, rather than a cost
|
||||||
|
*/
|
||||||
|
PERMISSION,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In-game experience levels
|
||||||
|
*/
|
||||||
|
EXP,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specific item is consumed
|
||||||
|
*/
|
||||||
|
ITEM,
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a text string denoting a cost type
|
||||||
|
*
|
||||||
|
* @param input <p>The input to parse</p>
|
||||||
|
* @return <p>The parsed cost type, or null if not matched</p>
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static CostType parse(@NotNull String input) {
|
||||||
|
String normalized = input.trim().toUpperCase();
|
||||||
|
for (CostType costType : CostType.values()) {
|
||||||
|
if (normalized.equals(costType.name())) {
|
||||||
|
return costType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user