Skip to content

Commit 11865c3

Browse files
Merge pull request #2 from DatAsianBoi123/dev
version 2.1.0
2 parents 18eb0f6 + 45a2039 commit 11865c3

24 files changed

+4817
-59
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.datasiqn</groupId>
88
<artifactId>commandcore</artifactId>
9-
<version>2.0.0</version>
9+
<version>2.1.0</version>
1010

1111
<properties>
1212
<maven.compiler.source>8</maven.compiler.source>
@@ -102,7 +102,7 @@
102102
<dependency>
103103
<groupId>com.github.DatAsianBoi123</groupId>
104104
<artifactId>ResultAPI</artifactId>
105-
<version>99ce07576b</version>
105+
<version>1.2.0</version>
106106
<scope>compile</scope>
107107
</dependency>
108108

src/main/java/com/datasiqn/commandcore/CommandCore.java

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
import com.datasiqn.commandcore.argument.type.ArgumentType;
55
import com.datasiqn.commandcore.command.Command;
66
import com.datasiqn.commandcore.command.CommandContext;
7-
import com.datasiqn.commandcore.command.CommandSource;
87
import com.datasiqn.commandcore.command.builder.ArgumentBuilder;
98
import com.datasiqn.commandcore.command.builder.CommandBuilder;
9+
import com.datasiqn.commandcore.command.source.*;
1010
import com.datasiqn.commandcore.managers.CommandManager;
11-
import com.datasiqn.resultapi.Result;
1211
import org.bukkit.Bukkit;
1312
import org.bukkit.ChatColor;
13+
import org.bukkit.command.BlockCommandSender;
1414
import org.bukkit.command.CommandMap;
1515
import org.bukkit.command.CommandSender;
1616
import org.bukkit.command.PluginCommand;
@@ -83,7 +83,10 @@ public void sendHelpMenu(@NotNull CommandSender sender) {
8383
sender.sendMessage(ChatColor.GOLD + (options.hasCustomPluginName() ? options.getPluginName() : plugin.getName()) + " Commands");
8484
commandManager.getCommandNames(false).stream().sorted().forEach(name -> {
8585
Command command = commandManager.getCommand(name, false);
86-
if (!command.hasPermission() || sender.hasPermission(command.getPermissionString())) sender.sendMessage(ChatColor.YELLOW + " " + name, ChatColor.GRAY + " ↳ " + command.getDescription());
86+
if (!command.hasPermission() || sender.hasPermission(command.getPermissionString())) {
87+
String description = command.hasDescription() ? command.getDescription() : "No description provided";
88+
sender.sendMessage(ChatColor.YELLOW + " " + name, ChatColor.GRAY + " ↳ " + description);
89+
}
8790
});
8891
}
8992

@@ -157,6 +160,7 @@ public static CommandCore getInstance() {
157160
constructor.setAccessible(true);
158161
command = constructor.newInstance(rootCommand, plugin);
159162
command.setAliases(options.getAliases());
163+
command.setDescription("Base plugin command");
160164
commandMap.register(rootCommand, plugin.getName(), command);
161165
} catch (NoSuchFieldException | IllegalAccessException | InvocationTargetException |
162166
InstantiationException | NoSuchMethodException e) {
@@ -227,21 +231,14 @@ public static CommandCore getInstance() {
227231
*/
228232
@Contract(value = "_ -> new", pure = true)
229233
public static @NotNull CommandSource createSource(CommandSender sender) {
230-
return new CommandSource() {
231-
@Override
232-
public @NotNull Result<Player, String> getPlayerChecked() {
233-
return Result.resolve(() -> (Player) sender, error -> "Sender is not a player");
234-
}
235-
236-
@Override
237-
public @NotNull Result<Entity, String> getEntityChecked() {
238-
return Result.resolve(() -> (Entity) sender, error -> "Sender is not an entity");
239-
}
240-
241-
@Override
242-
public @NotNull CommandSender getSender() {
243-
return sender;
244-
}
245-
};
234+
if (sender instanceof Player) {
235+
return new PlayerCommandSource(((Player) sender));
236+
} else if (sender instanceof Entity) {
237+
return new EntityCommandSource(((Entity) sender));
238+
} else if (sender instanceof BlockCommandSender) {
239+
return new BlockCommandSource(((BlockCommandSender) sender));
240+
} else {
241+
return new GenericCommandSource(sender);
242+
}
246243
}
247244
}

src/main/java/com/datasiqn/commandcore/argument/Arguments.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,15 @@ public interface Arguments {
5050
* @return The newly created {@code ArgumentReader}
5151
*/
5252
@NotNull ArgumentReader asReader();
53+
54+
/**
55+
* Checks if {@code i} is smaller than {@code size} and at least 0
56+
* @param i The number to check
57+
* @param size The total size
58+
* @throws IndexOutOfBoundsException If {@code i} {@literal >=} {@code size} or {@code i} {@literal <} 0
59+
*/
60+
static void checkBounds(int i, int size) {
61+
if (i >= size) throw new IndexOutOfBoundsException("index (" + i + ") is greater than total size (" + size + ")");
62+
if (i < 0) throw new IndexOutOfBoundsException("index cannot be negative");
63+
}
5364
}

src/main/java/com/datasiqn/commandcore/argument/StringArgumentReader.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,9 @@ public void jumpTo(int index) {
7474
}
7575
return builder.toString();
7676
}
77+
78+
@Override
79+
public String toString() {
80+
return arg;
81+
}
7782
}

src/main/java/com/datasiqn/commandcore/argument/StringArguments.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,21 @@
77
import java.util.List;
88

99
/**
10-
* Represents a list of arguments that are already parsed
10+
* Represents a list of arguments.
11+
* <p>
12+
* Internally, this uses a {@code List<String>} to store arguments and parses the string it every time the user wants an argument.
1113
*/
1214
public class StringArguments implements Arguments {
13-
protected final List<String> allArguments;
15+
private final List<String> allArguments;
16+
private final String stringArguments;
1417

1518
/**
1619
* Creates a new {@code ListArguments}
1720
* @param args The arguments in a string list
1821
*/
1922
public StringArguments(List<String> args) {
2023
allArguments = args;
24+
stringArguments = String.join(" ", allArguments);
2125
}
2226

2327
@Override
@@ -27,23 +31,19 @@ public int size() {
2731

2832
@Override
2933
public @NotNull <T> Result<T, String> getChecked(int i, @NotNull ArgumentType<T> type) {
30-
checkBounds(i);
34+
Arguments.checkBounds(i, size());
3135
return type.parse(new StringArgumentReader(allArguments.get(i)));
3236
}
3337

3438
@Override
3539
public @NotNull String getString(int i) {
36-
checkBounds(i);
40+
Arguments.checkBounds(i, size());
3741
return allArguments.get(i);
3842
}
3943

4044
@Override
4145
public @NotNull ArgumentReader asReader() {
42-
return new StringArgumentReader(String.join(" ", allArguments));
46+
return new StringArgumentReader(stringArguments);
4347
}
4448

45-
private void checkBounds(int i) {
46-
if (i >= size()) throw new IndexOutOfBoundsException("index (" + i + ") is greater than total size (" + size() + ")");
47-
if (i < 0) throw new IndexOutOfBoundsException("index cannot be negative");
48-
}
4949
}

src/main/java/com/datasiqn/commandcore/argument/type/ArgumentType.java

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@
55
import com.datasiqn.commandcore.command.CommandContext;
66
import com.datasiqn.resultapi.None;
77
import com.datasiqn.resultapi.Result;
8+
import org.bukkit.Bukkit;
9+
import org.bukkit.Location;
810
import org.bukkit.Material;
11+
import org.bukkit.World;
12+
import org.bukkit.entity.EntityType;
913
import org.bukkit.entity.Player;
14+
import org.bukkit.loot.LootTable;
1015
import org.bukkit.util.Vector;
1116
import org.jetbrains.annotations.Contract;
1217
import org.jetbrains.annotations.NotNull;
@@ -64,6 +69,33 @@ public interface ArgumentType<T> {
6469
*/
6570
ArgumentType<Vector> VECTOR = new VectorArgumentType();
6671

72+
/**
73+
* {@code ArgumentType} that represents a loaded world
74+
*/
75+
ArgumentType<World> WORLD = new WorldArgumentType();
76+
77+
/**
78+
* {@code ArgumentType} that represents an entity
79+
*/
80+
ArgumentType<EntityType> ENTITY = new EnumArgumentType<>(EntityType.class, "entity");
81+
82+
/**
83+
* {@code ArgumentType} that represents an entity that is living
84+
*/
85+
ArgumentType<EntityType> LIVING_ENTITY = new FilteredEnumArgumentType<>(EntityType.class, EntityType::isAlive, "living entity");
86+
87+
/**
88+
* {@code ArgumentType} that represents an entity that can be spawned using {@link org.bukkit.World#spawnEntity(Location, EntityType)}.
89+
* <br>
90+
* This is the same as the {@code ENTITY} argument type, except that this omits the {@code Player} entity type
91+
*/
92+
ArgumentType<EntityType> SPAWNABLE_ENTITY = new FilteredEnumArgumentType<>(EntityType.class, entityType -> entityType != EntityType.PLAYER, "living entity");
93+
94+
/**
95+
* {@code ArgumentType} that represents a loot table
96+
*/
97+
ArgumentType<LootTable> LOOT_TABLE = new LootTableArgumentType();
98+
6799
/**
68100
* {@code ArgumentType} that represents a material
69101
*/
@@ -136,6 +168,7 @@ class EnumArgumentType<T extends Enum<T>> implements SimpleArgumentType<T> {
136168
private final Class<T> enumClass;
137169
private final String enumName;
138170
private final List<String> tabCompletes;
171+
private final boolean uppercaseValues;
139172

140173
/**
141174
* Creates a new {@code ArgumentType}
@@ -153,6 +186,17 @@ public EnumArgumentType(@NotNull Class<T> enumClass, @NotNull String enumName) {
153186
this.enumClass = enumClass;
154187
this.enumName = enumName;
155188
this.tabCompletes = Arrays.stream(enumClass.getEnumConstants()).map(val -> val.name().toLowerCase(Locale.ROOT)).collect(Collectors.toList());
189+
190+
for (T enumConstant : enumClass.getEnumConstants()) {
191+
for (char letter : enumConstant.name().toCharArray()) {
192+
if (Character.isLetter(letter) && !Character.isUpperCase(letter)) {
193+
this.uppercaseValues = false;
194+
Bukkit.getLogger().warning("[CommandCore] Enum " + enumName + " includes values that aren't in uppercase!");
195+
return;
196+
}
197+
}
198+
}
199+
this.uppercaseValues = true;
156200
}
157201

158202
@Override
@@ -162,7 +206,7 @@ public EnumArgumentType(@NotNull Class<T> enumClass, @NotNull String enumName) {
162206

163207
@Override
164208
public @NotNull Result<T, None> parseWord(String word) {
165-
return Result.resolve(() -> EnumUtils.findEnumInsensitiveCase(enumClass, word));
209+
return Result.resolve(() -> uppercaseValues ? Enum.valueOf(enumClass, word.toUpperCase()) : EnumUtils.findEnumInsensitiveCase(enumClass, word));
166210
}
167211

168212
@Override
@@ -175,10 +219,8 @@ public EnumArgumentType(@NotNull Class<T> enumClass, @NotNull String enumName) {
175219
* Represents a custom {@code ArgumentType} that parses to a filtered enum
176220
* @param <T> The type of the enum
177221
*/
178-
class FilteredEnumArgumentType<T extends Enum<T>> implements SimpleArgumentType<T> {
222+
class FilteredEnumArgumentType<T extends Enum<T>> extends EnumArgumentType<T> {
179223
private final Predicate<T> filter;
180-
private final String enumName;
181-
private final Class<T> enumClass;
182224
private final List<String> tabCompletes;
183225

184226
/**
@@ -188,21 +230,14 @@ class FilteredEnumArgumentType<T extends Enum<T>> implements SimpleArgumentType<
188230
* @param enumName The name of the enum. This is used when displaying an error message (Invalid {{@code enumName}} '{val}'
189231
*/
190232
public FilteredEnumArgumentType(@NotNull Class<T> enumClass, Predicate<T> filter, String enumName) {
191-
this.enumClass = enumClass;
233+
super(enumClass, enumName);
192234
this.filter = filter;
193-
this.enumName = enumName;
194235
this.tabCompletes = Arrays.stream(enumClass.getEnumConstants()).filter(filter).map(val -> val.name().toLowerCase(Locale.ROOT)).collect(Collectors.toList());
195236
}
196237

197-
@Override
198-
public @NotNull String getTypeName() {
199-
return enumName;
200-
}
201-
202238
@Override
203239
public @NotNull Result<T, None> parseWord(String word) {
204-
return Result.resolve(() -> EnumUtils.findEnumInsensitiveCase(enumClass, word))
205-
.andThen(val -> filter.test(val) ? Result.ok(val) : Result.error());
240+
return super.parseWord(word).andThen(val -> filter.test(val) ? Result.ok(val) : Result.error());
206241
}
207242

208243
@Override
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.datasiqn.commandcore.argument.type;
2+
3+
import com.datasiqn.commandcore.command.CommandContext;
4+
import com.datasiqn.resultapi.None;
5+
import com.datasiqn.resultapi.Result;
6+
import org.bukkit.loot.LootTable;
7+
import org.bukkit.loot.LootTables;
8+
import org.jetbrains.annotations.NotNull;
9+
10+
import java.util.Arrays;
11+
import java.util.List;
12+
import java.util.stream.Collectors;
13+
14+
class LootTableArgumentType implements SimpleArgumentType<LootTable> {
15+
private final List<String> tabCompletes = Arrays.stream(LootTables.values()).map(LootTables::name).collect(Collectors.toList());
16+
17+
@Override
18+
public @NotNull String getTypeName() {
19+
return "loot table";
20+
}
21+
22+
@Override
23+
public @NotNull Result<LootTable, None> parseWord(String word) {
24+
return Result.resolve(() -> LootTables.valueOf(word.toUpperCase())).map(LootTables::getLootTable);
25+
}
26+
27+
@Override
28+
public @NotNull List<String> getTabComplete(@NotNull CommandContext context) {
29+
return tabCompletes;
30+
}
31+
}

src/main/java/com/datasiqn/commandcore/argument/type/SimpleArgumentType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public interface SimpleArgumentType<T> extends ArgumentType<T> {
2121
* Parses just a single word
2222
*
2323
* @param word The word
24-
* @return An {@code Optional} containing the parsed value
24+
* @return A {@code Result} containing the parsed value
2525
*/
2626
@NotNull Result<T, None> parseWord(String word);
2727

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.datasiqn.commandcore.argument.type;
2+
3+
import com.datasiqn.commandcore.command.CommandContext;
4+
import com.datasiqn.resultapi.None;
5+
import com.datasiqn.resultapi.Result;
6+
import org.bukkit.Bukkit;
7+
import org.bukkit.World;
8+
import org.jetbrains.annotations.NotNull;
9+
10+
import java.util.List;
11+
import java.util.stream.Collectors;
12+
13+
class WorldArgumentType implements SimpleArgumentType<World> {
14+
@Override
15+
public @NotNull String getTypeName() {
16+
return "world";
17+
}
18+
19+
@Override
20+
public @NotNull Result<World, None> parseWord(String word) {
21+
return Result.ofNullable(Bukkit.getWorld(word), None.NONE);
22+
}
23+
24+
@Override
25+
public @NotNull List<String> getTabComplete(@NotNull CommandContext context) {
26+
return Bukkit.getWorlds().stream().map(World::getName).collect(Collectors.toList());
27+
}
28+
}

src/main/java/com/datasiqn/commandcore/command/CommandContext.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.datasiqn.commandcore.command;
22

33
import com.datasiqn.commandcore.argument.Arguments;
4+
import com.datasiqn.commandcore.command.source.CommandSource;
45
import org.jetbrains.annotations.NotNull;
56

67
/**

src/main/java/com/datasiqn/commandcore/command/builder/BuilderCommand.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,17 @@ public BuilderCommand(@NotNull CommandBuilder commandBuilder, List<String> usage
6565
Result<CommandNode<?>, List<String>> resultNode = current.node;
6666
if (resultNode.isError()) {
6767
if (current.extraInput) {
68-
return Result.error(Collections.singletonList("Expected end of input, but got extra args instead"));
68+
return Result.error(Collections.singletonList("Expected end of input, but got extra parameters instead"));
6969
}
7070
List<String> exceptions = resultNode.unwrapError();
71-
List<String> messages = new ArrayList<>();
72-
List<String> matches = current.args;
73-
messages.add("Invalid parameter '" + matches.get(matches.size() - 1) + "' at position " + matches.size() + ": ");
74-
messages.addAll(exceptions);
75-
return Result.error(messages);
71+
if (exceptions.isEmpty()) exceptions.add("Incorrect argument '" + reader.splice(reader.index()) + "'");
72+
String rootCommand = CommandCore.getInstance().getOptions().getRootCommand();
73+
String label = context.getLabel();
74+
String correctSection = ChatColor.GRAY + rootCommand + " " + label + " " + reader.splice(0, reader.index());
75+
String incorrectParameter = ChatColor.RED.toString() + ChatColor.UNDERLINE + reader.splice(reader.index());
76+
exceptions.add(correctSection + incorrectParameter + ChatColor.RESET + ChatColor.RED + ChatColor.ITALIC + " <--[HERE]");
77+
exceptions.add("");
78+
return Result.error(exceptions);
7679
}
7780
CommandNode<?> node = resultNode.unwrap();
7881
CommandContext newContext = buildContext(context, current);

0 commit comments

Comments
 (0)