Skip to content

Commit bbbb62a

Browse files
committed
feat: improve code
1 parent 37c271e commit bbbb62a

File tree

7 files changed

+433
-90
lines changed

7 files changed

+433
-90
lines changed

core/src/main/java/fr/traqueur/commands/api/CommandManager.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import fr.traqueur.commands.api.arguments.Arguments;
66
import fr.traqueur.commands.api.arguments.TabCompleter;
77
import fr.traqueur.commands.api.exceptions.ArgumentIncorrectException;
8+
import fr.traqueur.commands.api.exceptions.CommandRegistrationException;
89
import fr.traqueur.commands.api.exceptions.TypeArgumentNotExistException;
910
import fr.traqueur.commands.api.logging.Logger;
1011
import fr.traqueur.commands.api.logging.MessageHandler;
@@ -150,7 +151,7 @@ public void registerCommand(Command<T,S> command) {
150151
this.registerSubCommands(alias, command.getSubcommands());
151152
}
152153
} catch(TypeArgumentNotExistException e) {
153-
throw new RuntimeException(e);
154+
throw new CommandRegistrationException("Failed to register command: " + command.getClass().getSimpleName(), e);
154155
}
155156
}
156157

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package fr.traqueur.commands.api.exceptions;
2+
3+
/**
4+
* Exception thrown when a command registration fails.
5+
* This is a runtime exception as registration failures are typically unrecoverable.
6+
*/
7+
public class CommandRegistrationException extends RuntimeException {
8+
9+
/**
10+
* Constructs a new exception with the specified detail message.
11+
*
12+
* @param message the detail message
13+
*/
14+
public CommandRegistrationException(String message) {
15+
super(message);
16+
}
17+
18+
/**
19+
* Constructs a new exception with the specified detail message and cause.
20+
*
21+
* @param message the detail message
22+
* @param cause the cause of the exception
23+
*/
24+
public CommandRegistrationException(String message, Throwable cause) {
25+
super(message, cause);
26+
}
27+
28+
/**
29+
* Constructs a new exception with the specified cause.
30+
*
31+
* @param cause the cause of the exception
32+
*/
33+
public CommandRegistrationException(Throwable cause) {
34+
super(cause);
35+
}
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package fr.traqueur.commands.api.exceptions;
2+
3+
/**
4+
* Exception thrown when the updater fails to initialize.
5+
* This is a runtime exception as initialization failures are typically unrecoverable.
6+
*/
7+
public class UpdaterInitializationException extends RuntimeException {
8+
9+
/**
10+
* Constructs a new exception with the specified detail message.
11+
*
12+
* @param message the detail message
13+
*/
14+
public UpdaterInitializationException(String message) {
15+
super(message);
16+
}
17+
18+
/**
19+
* Constructs a new exception with the specified detail message and cause.
20+
*
21+
* @param message the detail message
22+
* @param cause the cause of the exception
23+
*/
24+
public UpdaterInitializationException(String message, Throwable cause) {
25+
super(message, cause);
26+
}
27+
28+
/**
29+
* Constructs a new exception with the specified cause.
30+
*
31+
* @param cause the cause of the exception
32+
*/
33+
public UpdaterInitializationException(Throwable cause) {
34+
super(cause);
35+
}
36+
}

core/src/main/java/fr/traqueur/commands/api/models/CommandInvoker.java

Lines changed: 171 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,63 +41,209 @@ public CommandInvoker(CommandManager<T, S> manager) {
4141
* @return true if a command handler was executed or a message sent; false if command not found
4242
*/
4343
public boolean invoke(S source, String base, String[] rawArgs) {
44-
// find matching node
44+
Optional<CommandContext<T, S>> contextOpt = findCommandContext(base, rawArgs);
45+
if (!contextOpt.isPresent()) {
46+
return false;
47+
}
48+
49+
CommandContext<T, S> context = contextOpt.get();
50+
51+
if (!validateCommandExecution(source, context)) {
52+
return true;
53+
}
54+
55+
return executeCommand(source, context);
56+
}
57+
58+
/**
59+
* Find and prepare command context.
60+
* @param base the base command label
61+
* @param rawArgs the raw arguments
62+
* @return the command context if found
63+
*/
64+
private Optional<CommandContext<T, S>> findCommandContext(String base, String[] rawArgs) {
4565
Optional<MatchResult<T, S>> found = manager.getCommands().findNode(base, rawArgs);
46-
if (!found.isPresent()) return false;
66+
if (!found.isPresent()) {
67+
return Optional.empty();
68+
}
69+
4770
MatchResult<T, S> result = found.get();
4871
CommandTree.CommandNode<T, S> node = result.node;
4972
Optional<Command<T, S>> cmdOpt = node.getCommand();
50-
if (!cmdOpt.isPresent()) return false;
73+
74+
if (!cmdOpt.isPresent()) {
75+
return Optional.empty();
76+
}
77+
5178
Command<T, S> command = cmdOpt.get();
5279
String label = node.getFullLabel() != null ? node.getFullLabel() : base;
5380
String[] args = result.args;
5481

55-
// in-game check
82+
return Optional.of(new CommandContext<>(command, label, args));
83+
}
84+
85+
/**
86+
* Validate command execution conditions (in-game, permissions, requirements, usage).
87+
* @param source the command sender
88+
* @param context the command context
89+
* @return true if all validations passed, false otherwise (message already sent to user)
90+
*/
91+
private boolean validateCommandExecution(S source, CommandContext<T, S> context) {
92+
return checkInGameOnly(source, context.command)
93+
&& checkPermission(source, context.command)
94+
&& checkRequirements(source, context.command)
95+
&& checkUsage(source, context);
96+
}
97+
98+
/**
99+
* Check if command requires in-game execution.
100+
* @param source the command sender
101+
* @param command the command to check
102+
* @return true if check passed or not applicable
103+
*/
104+
private boolean checkInGameOnly(S source, Command<T, S> command) {
56105
if (command.inGameOnly() && !manager.getPlatform().isPlayer(source)) {
57106
manager.getPlatform().sendMessage(source, manager.getMessageHandler().getOnlyInGameMessage());
58-
return true;
107+
return false;
59108
}
60-
// permission check
109+
return true;
110+
}
111+
112+
/**
113+
* Check if sender has required permission.
114+
* @param source the command sender
115+
* @param command the command to check
116+
* @return true if check passed or no permission required
117+
*/
118+
private boolean checkPermission(S source, Command<T, S> command) {
61119
String perm = command.getPermission();
62120
if (!perm.isEmpty() && !manager.getPlatform().hasPermission(source, perm)) {
63121
manager.getPlatform().sendMessage(source, manager.getMessageHandler().getNoPermissionMessage());
64-
return true;
122+
return false;
65123
}
66-
// requirements
124+
return true;
125+
}
126+
127+
/**
128+
* Check if all requirements are satisfied.
129+
* @param source the command sender
130+
* @param command the command to check
131+
* @return true if all requirements passed
132+
*/
133+
private boolean checkRequirements(S source, Command<T, S> command) {
67134
for (Requirement<S> req : command.getRequirements()) {
68135
if (!req.check(source)) {
69-
String msg = req.errorMessage().isEmpty()
70-
? manager.getMessageHandler().getRequirementMessage().replace("%requirement%", req.getClass().getSimpleName())
71-
: req.errorMessage();
136+
String msg = buildRequirementMessage(req);
72137
manager.getPlatform().sendMessage(source, msg);
73-
return true;
138+
return false;
74139
}
75140
}
76-
// usage check
141+
return true;
142+
}
143+
144+
/**
145+
* Build error message for failed requirement.
146+
* @param req the failed requirement
147+
* @return the error message
148+
*/
149+
private String buildRequirementMessage(Requirement<S> req) {
150+
return req.errorMessage().isEmpty()
151+
? manager.getMessageHandler().getRequirementMessage()
152+
.replace("%requirement%", req.getClass().getSimpleName())
153+
: req.errorMessage();
154+
}
155+
156+
/**
157+
* Check if argument count is valid.
158+
* @param source the command sender
159+
* @param context the command context
160+
* @return true if usage is correct
161+
*/
162+
private boolean checkUsage(S source, CommandContext<T, S> context) {
163+
Command<T, S> command = context.command;
164+
String[] args = context.args;
165+
77166
int min = command.getArgs().size();
78167
int max = command.isInfiniteArgs() ? Integer.MAX_VALUE : min + command.getOptinalArgs().size();
168+
79169
if (args.length < min || args.length > max) {
80-
String usage = command.getUsage().isEmpty()
81-
? command.generateDefaultUsage(manager.getPlatform(), source, label)
82-
: command.getUsage();
170+
String usage = buildUsageMessage(source, context);
83171
manager.getPlatform().sendMessage(source, usage);
84-
return true;
172+
return false;
85173
}
86-
// parse and execute
174+
return true;
175+
}
176+
177+
/**
178+
* Build usage message for command.
179+
* @param source the command sender
180+
* @param context the command context
181+
* @return the usage message
182+
*/
183+
private String buildUsageMessage(S source, CommandContext<T, S> context) {
184+
Command<T, S> command = context.command;
185+
String label = context.label;
186+
187+
return command.getUsage().isEmpty()
188+
? command.generateDefaultUsage(manager.getPlatform(), source, label)
189+
: command.getUsage();
190+
}
191+
192+
/**
193+
* Execute the command with error handling.
194+
* @param source the command sender
195+
* @param context the command context
196+
* @return true if execution succeeded or error was handled, false for internal errors
197+
*/
198+
private boolean executeCommand(S source, CommandContext<T, S> context) {
87199
try {
88-
Arguments parsed = manager.parse(command, args);
89-
command.execute(source, parsed);
200+
Arguments parsed = manager.parse(context.command, context.args);
201+
context.command.execute(source, parsed);
202+
return true;
90203
} catch (TypeArgumentNotExistException e) {
91-
manager.getPlatform().sendMessage(source, "&cInternal error: invalid argument type");
92-
return false;
204+
return handleTypeArgumentError(source);
93205
} catch (ArgumentIncorrectException e) {
94-
String msg = manager.getMessageHandler().getArgNotRecognized().replace("%arg%", e.getInput());
95-
manager.getPlatform().sendMessage(source, msg);
96-
return true;
206+
return handleArgumentIncorrectError(source, e);
97207
}
208+
}
209+
210+
/**
211+
* Handle type argument not exist error.
212+
* @param source the command sender
213+
* @return false to indicate internal error
214+
*/
215+
private boolean handleTypeArgumentError(S source) {
216+
manager.getPlatform().sendMessage(source, "&cInternal error: invalid argument type");
217+
return false;
218+
}
219+
220+
/**
221+
* Handle incorrect argument error.
222+
* @param source the command sender
223+
* @param e the exception
224+
* @return true to indicate error was handled
225+
*/
226+
private boolean handleArgumentIncorrectError(S source, ArgumentIncorrectException e) {
227+
String msg = manager.getMessageHandler().getArgNotRecognized().replace("%arg%", e.getInput());
228+
manager.getPlatform().sendMessage(source, msg);
98229
return true;
99230
}
100231

232+
/**
233+
* Internal context class to hold command execution data.
234+
*/
235+
private static class CommandContext<T, S> {
236+
final Command<T, S> command;
237+
final String label;
238+
final String[] args;
239+
240+
CommandContext(Command<T, S> command, String label, String[] args) {
241+
this.command = command;
242+
this.label = label;
243+
this.args = args;
244+
}
245+
}
246+
101247
/**
102248
* Suggests command completions based on the provided source, base label, and arguments.
103249
* This method checks for available tab completers and filters suggestions based on the current input.

core/src/main/java/fr/traqueur/commands/api/updater/Updater.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package fr.traqueur.commands.api.updater;
22

3+
import fr.traqueur.commands.api.exceptions.UpdaterInitializationException;
4+
35
import java.io.IOException;
46
import java.net.HttpURLConnection;
57
import java.net.MalformedURLException;
@@ -22,7 +24,7 @@ public class Updater {
2224
try {
2325
URL_LATEST_RELEASE = URI.create("https://api.github.com/repos/Traqueur-dev/CommandsAPI/releases/latest").toURL();
2426
} catch (MalformedURLException e) {
25-
throw new RuntimeException(e);
27+
throw new UpdaterInitializationException("Failed to initialize updater URL", e);
2628
}
2729
}
2830

0 commit comments

Comments
 (0)