Skip to content

Commit e617b0f

Browse files
committed
Update Command System
1 parent cdee236 commit e617b0f

6 files changed

Lines changed: 100 additions & 49 deletions

File tree

src/main/java/io/github/simplexdev/simplexcore/SimplexCorePlugin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public void init() {
4242
public void start() {
4343
try {
4444
getRegistry().register(this);
45-
getCommandLoader().classpath(Command_info.class).load(this);
45+
getCommandLoader().classpath(this, Command_info.class).load();
4646
getYamlConfig().reload();
4747
getInternals().reload();
4848
//

src/main/java/io/github/simplexdev/simplexcore/command/CommandLoader.java

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package io.github.simplexdev.simplexcore.command;
22

33
import io.github.simplexdev.api.annotations.CommandInfo;
4-
import io.github.simplexdev.simplexcore.command.defaults.DefaultCommand;
4+
import io.github.simplexdev.simplexcore.SimplexCorePlugin;
55
import io.github.simplexdev.simplexcore.module.SimplexModule;
66
import io.github.simplexdev.simplexcore.utils.ReflectionTools;
7-
import io.github.simplexdev.simplexcore.SimplexCorePlugin;
8-
import org.bukkit.Bukkit;
9-
import org.bukkit.command.*;
7+
import org.bukkit.command.CommandExecutor;
8+
import org.bukkit.command.CommandMap;
9+
import org.bukkit.command.PluginCommand;
10+
import org.bukkit.command.TabCompleter;
1011
import org.bukkit.plugin.Plugin;
1112
import org.bukkit.plugin.SimplePluginManager;
1213
import org.jetbrains.annotations.NotNull;
@@ -20,7 +21,10 @@
2021

2122
public final class CommandLoader {
2223
private Reflections reflections;
24+
private ClassLoader classLoader;
25+
private SimplexModule<?> plugin;
2326
private static final CommandLoader instance = new CommandLoader();
27+
private final Registry registry = new Registry();
2428

2529
/**
2630
* @return A Singleton Pattern instance of this class.
@@ -38,38 +42,42 @@ public static CommandLoader getInstance() {
3842
* If the class provided does not have the {@link CommandInfo} annotation, the loader will throw a new
3943
* {@link MissingResourceException} and will not load your plugin's commands.
4044
* If the class provided does not extend {@link SimplexCommand}, the loader will throw a new
41-
* {@link RuntimeException} and your commands will not be loaded.
45+
* {@link CommandLoaderException} and your commands will not be loaded.
4246
* </p>
4347
*
4448
* @param clazz The command class to load from
4549
* @return An instance of this where the classpath has been prepared for loading the commands.
4650
*/
47-
public <T extends SimplexCommand> CommandLoader classpath(Class<T> clazz) {
51+
public <T extends SimplexCommand> CommandLoader classpath(SimplexModule<?> plugin, Class<T> clazz) {
4852
if (clazz == null) {
49-
throw new IllegalStateException("The class provided cannot be found!");
53+
throw new IllegalArgumentException("The class provided cannot be found!");
5054
}
5155

5256
if (!clazz.isAnnotationPresent(CommandInfo.class)) {
5357
throw new MissingResourceException("Cannot register this class as the main resource location!", clazz.getSimpleName(), "@CommandInfo");
5458
}
5559

5660
if (!SimplexCommand.class.isAssignableFrom(clazz)) {
57-
throw new RuntimeException("Your command must extend SimplexCommand.class for it to be used as the reference point for loading commands.");
61+
throw new CommandLoaderException("Your command must extend SimplexCommand.class for it to be used as the reference point for loading commands.");
5862
}
5963

60-
reflections = ReflectionTools.reflect(clazz);
64+
this.reflections = ReflectionTools.reflect(clazz);
65+
this.plugin = plugin;
66+
this.classLoader = plugin.getClass().getClassLoader();
6167

6268
return this;
6369
}
6470

6571
/**
6672
* Loads all the commands from the specified classpath.
67-
* This should be used immediately after {@link CommandLoader#classpath(Class)} has been called.
73+
* This should be used immediately after {@link CommandLoader#classpath(SimplexModule, Class)} has been called.
6874
* If used before, an exception will be thrown, and your commands will not be loaded.
69-
*
70-
* @param plugin An instance of your plugin to assign as the parent plugin for each command.
7175
*/
72-
public void load(SimplexModule<?> plugin) {
76+
public void load() {
77+
if (reflections == null || plugin == null || classLoader == null) {
78+
throw new CommandLoaderException("Please run CommandLoader#classpath(SimplexModule, Class) first!");
79+
}
80+
7381
reflections.getTypesAnnotatedWith(CommandInfo.class).forEach(annotated -> {
7482
CommandInfo info = annotated.getDeclaredAnnotation(CommandInfo.class);
7583

@@ -89,7 +97,7 @@ public void load(SimplexModule<?> plugin) {
8997
return;
9098
}
9199

92-
PluginCommand command = Registry.create(plugin, info.name().toLowerCase());
100+
PluginCommand command = registry.create(plugin, info.name().toLowerCase());
93101
command.setAliases(Arrays.asList(info.aliases().split(",")));
94102
command.setDescription(info.description());
95103
command.setExecutor(getExecutorFromName(info.name()));
@@ -98,7 +106,7 @@ public void load(SimplexModule<?> plugin) {
98106
command.setPermissionMessage(info.permissionMessage());
99107
command.setTabCompleter(getTabFromName(info.name()));
100108
command.setUsage(info.usage());
101-
Registry.registerCommand(command);
109+
registry.registerCommand(command);
102110
});
103111
}
104112

@@ -110,28 +118,27 @@ public void load(SimplexModule<?> plugin) {
110118
* @param name The name of the command.
111119
* @return An instance of the command class as a CommandExecutor.
112120
*/
113-
public CommandExecutor getExecutorFromName(String name) {
114-
for (Class<? extends CommandExecutor> obj : reflections.getSubTypesOf(CommandExecutor.class)) {
121+
private CommandExecutor getExecutorFromName(String name) {
122+
for (Class<? extends SimplexCommand> obj : reflections.getSubTypesOf(SimplexCommand.class)) {
115123
if (!obj.isAnnotationPresent(CommandInfo.class)) {
116-
SimplexCorePlugin.getInstance()
117-
.getLogger().warning(obj.getSimpleName()
124+
plugin.getLogger().warning(obj.getSimpleName()
118125
+ " is missing a required annotation: "
119126
+ CommandInfo.class.getSimpleName());
127+
continue;
120128
}
121129

122130
CommandInfo info = obj.getDeclaredAnnotation(CommandInfo.class);
123131

124132
if (name.equalsIgnoreCase(info.name())) {
125-
try {
126-
Constructor<? extends CommandExecutor> constr = obj.getDeclaredConstructor();
127-
constr.setAccessible(true);
128-
return constr.newInstance();
129-
} catch (ReflectiveOperationException ignored) {
130-
return new DefaultCommand();
133+
Constructor<? extends CommandExecutor> constr =
134+
ReflectionTools.getDeclaredConstructor(obj, SimplexModule.class);
135+
if (constr == null) {
136+
throw new CommandLoaderException("Constructor does not exist! Are you extending SimplexCommand properly?");
131137
}
138+
return ReflectionTools.initConstructor(constr, plugin);
132139
}
133140
}
134-
throw new RuntimeException("Unable to assign a CommandExecutor from the provided classes!");
141+
throw new CommandLoaderException("Unable to assign a CommandExecutor from the provided classes!");
135142
}
136143

137144
/**
@@ -143,52 +150,50 @@ public CommandExecutor getExecutorFromName(String name) {
143150
* @return The command as an instance of TabCompleter
144151
*/
145152
@Nullable
146-
public TabCompleter getTabFromName(String name) {
147-
for (Class<? extends TabCompleter> obj : reflections.getSubTypesOf(TabCompleter.class)) {
153+
private TabCompleter getTabFromName(String name) {
154+
for (Class<? extends SimplexCommand> obj : reflections.getSubTypesOf(SimplexCommand.class)) {
148155
if (!obj.isAnnotationPresent(CommandInfo.class)) {
149-
SimplexCorePlugin.getInstance()
150-
.getLogger().warning(obj.getSimpleName()
156+
plugin.getLogger().warning(obj.getSimpleName()
151157
+ " is missing required annotation: "
152158
+ CommandInfo.class.getSimpleName());
153159
continue;
154160
}
155161

156162
CommandInfo info = obj.getDeclaredAnnotation(CommandInfo.class);
163+
157164
if (name.equalsIgnoreCase(info.name())) {
158-
try {
159-
Constructor<? extends TabCompleter> constr = obj.getDeclaredConstructor();
160-
constr.setAccessible(true);
161-
return constr.newInstance();
162-
} catch (ReflectiveOperationException ignored) {
163-
return new DefaultCommand();
165+
Constructor<? extends TabCompleter> constr = ReflectionTools.getDeclaredConstructor(obj, SimplexModule.class);
166+
if (constr == null) {
167+
throw new CommandLoaderException("Constructor does not exist! Are you extending SimplexCommand properly?");
164168
}
169+
return ReflectionTools.initConstructor(constr, plugin);
165170
}
166171
}
167-
return null;
172+
throw new CommandLoaderException("Unable to assign a TabCompleter from the provided classes!");
168173
}
169174

170175
/**
171176
* Registry class, which forces all necessary fields to accessible.
172177
*/
173-
private static class Registry {
174-
private static final Constructor<PluginCommand> constructor;
175-
private static final Field cmdMapField;
178+
private final class Registry {
179+
private final Constructor<PluginCommand> constructor;
180+
private final Field cmdMapField;
176181

177-
static {
182+
public Registry() {
178183
constructor = ReflectionTools.getDeclaredConstructor(PluginCommand.class, String.class, Plugin.class);
179184
cmdMapField = ReflectionTools.getDeclaredField(SimplePluginManager.class, "commandMap");
180185
}
181186

182-
public static PluginCommand create(@NotNull Plugin plugin, @NotNull String name) {
187+
public PluginCommand create(@NotNull SimplexModule<?> plugin, @NotNull String name) {
183188
return ReflectionTools.initConstructor(constructor, name, plugin);
184189
}
185190

186-
public static void registerCommand(PluginCommand command) {
191+
public void registerCommand(PluginCommand command) {
187192
try {
188-
CommandMap map = (CommandMap) cmdMapField.get(Bukkit.getPluginManager());
193+
CommandMap map = (CommandMap) cmdMapField.get(plugin.getManager());
189194
map.register(command.getName().toLowerCase(), command);
190195
} catch (IllegalAccessException e) {
191-
throw new RuntimeException(e);
196+
throw new CommandLoaderException(e);
192197
}
193198
}
194199
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.github.simplexdev.simplexcore.command;
2+
3+
import org.apache.commons.lang.exception.ExceptionUtils;
4+
5+
public class CommandLoaderException extends RuntimeException {
6+
public CommandLoaderException() {
7+
super("The Command Loader has encountered an exception and has failed to execute properly. " +
8+
"Some commands may not be loaded.");
9+
ExceptionUtils.getMessage(super.getCause());
10+
}
11+
12+
public CommandLoaderException(String msg) {
13+
super(msg);
14+
}
15+
16+
public CommandLoaderException(Throwable th) {
17+
super(th);
18+
}
19+
}

src/main/java/io/github/simplexdev/simplexcore/command/SimplexCommand.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.github.simplexdev.simplexcore.command;
22

33
import io.github.simplexdev.simplexcore.SimplexCorePlugin;
4+
import io.github.simplexdev.simplexcore.module.SimplexModule;
45
import io.github.simplexdev.simplexcore.utils.Utilities;
56
import org.bukkit.command.Command;
67
import org.bukkit.command.CommandExecutor;
@@ -15,13 +16,23 @@
1516
import java.util.UUID;
1617

1718
public abstract class SimplexCommand implements CommandExecutor, TabCompleter {
19+
private final SimplexModule<?> plugin;
20+
21+
public SimplexCommand(SimplexModule<?> plugin) {
22+
this.plugin = plugin;
23+
}
24+
25+
public final SimplexModule<?> getPlugin() {
26+
return plugin;
27+
}
1828

1929
public boolean isPlayer(CommandSender sender) {
2030
return sender instanceof Player;
2131
}
2232

2333
/**
2434
* Gets an online player from their username
35+
*
2536
* @param name The player's username
2637
* @return An instance of {@link Player} which represents the online player in question.
2738
*/
@@ -32,6 +43,7 @@ public Player getPlayer(String name) {
3243

3344
/**
3445
* Gets an online player from their {@link UUID}.
46+
*
3547
* @param uuid The player's UUID
3648
* @return An instance of {@link Player} which represents the online player in question.
3749
*/
@@ -43,6 +55,7 @@ public Player getPlayer(UUID uuid) {
4355
/**
4456
* Gets an instance of {@link Player} based off an instance of {@link CommandSender}.
4557
* This will be null if the condition {CommandSender instanceof Player} is false.
58+
*
4659
* @param sender The CommandSender to cast
4760
* @return An instance of Player relating to CommandSender.
4861
*/
@@ -54,7 +67,8 @@ public Player getPlayer(CommandSender sender) {
5467
/**
5568
* Send a message or a group of messages to a {@link Player}.
5669
* If you want the messages to send on new lines, put \n at the end of each message to send.
57-
* @param player The Player to send a message to
70+
*
71+
* @param player The Player to send a message to
5872
* @param messages The messages to send.
5973
*/
6074
public void playerMsg(Player player, String... messages) {
@@ -66,7 +80,8 @@ public void playerMsg(Player player, String... messages) {
6680
/**
6781
* Send a message or a group of messages to a {@link CommandSender}
6882
* If you want the messages to send on new lines, put \n at the end of each message to send.
69-
* @param sender The CommandSender to send a message to.
83+
*
84+
* @param sender The CommandSender to send a message to.
7085
* @param messages The messages to send.
7186
*/
7287
public void msg(CommandSender sender, String... messages) {
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
package io.github.simplexdev.simplexcore.command.defaults;
22

33
import io.github.simplexdev.api.annotations.CommandInfo;
4+
import io.github.simplexdev.simplexcore.chat.Messages;
45
import io.github.simplexdev.simplexcore.command.SimplexCommand;
6+
import io.github.simplexdev.simplexcore.module.SimplexModule;
57
import org.bukkit.command.Command;
68
import org.bukkit.command.CommandSender;
79
import org.jetbrains.annotations.NotNull;
810

911
@CommandInfo(name = "Info", description = "Gets info on this API / Library.", usage = "/<command>", permission = "simplex.core.info")
1012
public class Command_info extends SimplexCommand {
13+
14+
public Command_info(SimplexModule<?> plugin) {
15+
super(plugin);
16+
}
17+
1118
@Override
1219
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
13-
sender.sendMessage("This is an API!");
20+
sender.sendMessage(Messages.DISCORD.getMessage());
1421
return true;
1522
}
1623
}

src/main/java/io/github/simplexdev/simplexcore/command/defaults/DefaultCommand.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22

33
import io.github.simplexdev.api.annotations.CommandInfo;
44
import io.github.simplexdev.simplexcore.command.SimplexCommand;
5+
import io.github.simplexdev.simplexcore.module.SimplexModule;
56
import org.bukkit.command.Command;
67
import org.bukkit.command.CommandSender;
78
import org.jetbrains.annotations.NotNull;
89

910
@CommandInfo(name = "default", usage = "/<command>", description = "Default plugin command.")
1011
public final class DefaultCommand extends SimplexCommand {
12+
public DefaultCommand(SimplexModule<?> plugin) {
13+
super(plugin);
14+
}
15+
1116
@Override
1217
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
1318
sender.sendMessage("If you are seeing this when running your command, your command didn't register properly.");

0 commit comments

Comments
 (0)