Skip to content

Commit ab30b98

Browse files
committed
Add basic command system
- Add command classes - Add basic documentation - Add events - Add configuration - Add CommandClientBuilder - Remove common/docs
1 parent cce66e4 commit ab30b98

140 files changed

Lines changed: 1349 additions & 4795 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
/*
2+
* Regnum - A Discord bot clustering system made for Hawk
3+
*
4+
* Copyright (C) 2019 Michael Rittmeister
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see https://www.gnu.org/licenses/.
18+
*/
19+
20+
package me.schlaubi.regnumutils.command;
21+
22+
import cc.hawkbot.regnum.util.DefaultThreadFactory;
23+
import com.google.common.base.Preconditions;
24+
import me.schlaubi.regnumutils.command.configuration.CommandClientConfiguration;
25+
import me.schlaubi.regnumutils.command.configuration.MutableCommandClientConfiguration;
26+
import me.schlaubi.regnumutils.command.listener.MessageEditCommandListener;
27+
import me.schlaubi.regnumutils.command.listener.MessageReceivedCommandListener;
28+
import me.schlaubi.regnumutils.command.listener.SealedCommandListener;
29+
import me.schlaubi.regnumutils.command.spi.Command;
30+
import me.schlaubi.regnumutils.command.spi.Context;
31+
import me.schlaubi.regnumutils.command.spi.permission.PermissionHandler;
32+
import net.dv8tion.jda.api.JDA;
33+
import net.dv8tion.jda.api.entities.Message;
34+
import org.jetbrains.annotations.NotNull;
35+
36+
import java.lang.reflect.InvocationTargetException;
37+
import java.lang.reflect.Modifier;
38+
import java.util.ArrayList;
39+
import java.util.Collection;
40+
import java.util.Collections;
41+
import java.util.List;
42+
import java.util.concurrent.ExecutorService;
43+
import java.util.concurrent.Executors;
44+
import java.util.function.Function;
45+
46+
@SuppressWarnings("unused")
47+
public class CommandClientBuilder {
48+
49+
private ExecutorService executor = Executors.newCachedThreadPool(new DefaultThreadFactory("Command"));
50+
51+
private List<Command> commands = new ArrayList<>();
52+
53+
private PermissionHandler permissionHandler;
54+
55+
private Class<? extends SealedCommandListener> commandListener = MessageReceivedCommandListener.class;
56+
57+
private CommandClientConfiguration configuration = new MutableCommandClientConfiguration();
58+
59+
/**
60+
* Returns the Class of the currently set {@link SealedCommandListener}.
61+
*
62+
* @return the {@link Class}
63+
*/
64+
@NotNull
65+
public Class<? extends SealedCommandListener> getCommandListener() {
66+
return commandListener;
67+
}
68+
69+
/**
70+
* Sets the Class of the currently set {@link SealedCommandListener}.
71+
* Changing this from an {@link MessageReceivedCommandListener} to an {@link MessageEditCommandListener} will also parse {@code MESSAGE_UPDATE} events as commands
72+
*
73+
* @return the {@link CommandClientBuilder}
74+
* @throws IllegalArgumentException when the constructor of the command listener is not public
75+
* @see MessageReceivedCommandListener
76+
* @see MessageEditCommandListener
77+
*/
78+
public CommandClientBuilder setCommandListener(@NotNull Class<? extends SealedCommandListener> commandListener) {
79+
try {
80+
Preconditions.checkArgument(!Modifier.isPublic(commandListener.getConstructor(CommandClient.class).getModifiers()), "The constructor of the command listener must be public!");
81+
} catch (NoSuchMethodException e) {
82+
throw new IllegalArgumentException("A command listener needs a constructor with a command client argument!");
83+
}
84+
this.commandListener = commandListener;
85+
return this;
86+
}
87+
88+
/**
89+
* Returns the executor used to execute {@link Command }s.
90+
*
91+
* @return the {@link ExecutorService}
92+
*/
93+
@NotNull
94+
public ExecutorService getExecutor() {
95+
return executor;
96+
}
97+
98+
/**
99+
* Sets the executor used to execute {@link Command }s.
100+
*
101+
* @param executor the {@link ExecutorService}
102+
* @return the {@link CommandClientBuilder}
103+
*/
104+
@NotNull
105+
public CommandClientBuilder setExecutor(@NotNull ExecutorService executor) {
106+
this.executor = executor;
107+
return this;
108+
}
109+
110+
/**
111+
* Returns all currently registered commands.
112+
*
113+
* @return a {@link List} of {@link Command}s
114+
*/
115+
public List<Command> getCommands() {
116+
return commands;
117+
}
118+
119+
/**
120+
* Sets all currently registered {@link Command}s.
121+
*
122+
* @param commands a {@link List} of {@link Command}s
123+
* @return the {@link CommandClientBuilder}
124+
* @see CommandClientBuilder#registerCommands(Command...)
125+
* @see CommandClientBuilder#registerCommands(Collection)
126+
*/
127+
@NotNull
128+
public CommandClientBuilder setCommands(@NotNull List<Command> commands) {
129+
this.commands = commands;
130+
return this;
131+
}
132+
133+
/**
134+
* Registers commands without overwriting already registered command.
135+
*
136+
* @param commands the {@link Command}s
137+
* @return the {@link CommandClientBuilder}
138+
*/
139+
@SuppressWarnings("WeakerAccess")
140+
@NotNull
141+
public CommandClientBuilder registerCommands(Command... commands) {
142+
Collections.addAll(this.commands, commands);
143+
return this;
144+
}
145+
146+
/**
147+
* Registers commands without overwriting already registered command.
148+
*
149+
* @param commands a {@link Collection} of {@link Command}s
150+
* @return the {@link CommandClientBuilder}
151+
*/
152+
@SuppressWarnings("WeakerAccess")
153+
@NotNull
154+
public CommandClientBuilder registerCommands(Collection<Command> commands) {
155+
this.commands.addAll(commands);
156+
return this;
157+
}
158+
159+
/**
160+
* Returns the currently set permission handler.
161+
*
162+
* @return the {@link PermissionHandler}
163+
*/
164+
@NotNull
165+
public PermissionHandler getPermissionHandler() {
166+
return permissionHandler;
167+
}
168+
169+
/**
170+
* Sets the permission handler to check if a user is allowed to execute a command.
171+
*
172+
* @param permissionHandler the {@link PermissionHandler}
173+
* @return the {@link CommandClientBuilder}
174+
* @see PermissionHandler
175+
*/
176+
@NotNull
177+
public CommandClientBuilder setPermissionHandler(@NotNull PermissionHandler permissionHandler) {
178+
this.permissionHandler = permissionHandler;
179+
return this;
180+
}
181+
182+
/**
183+
* Returns the currently used CommandClientConfiguration.
184+
*
185+
* @return the {@link CommandClientConfiguration}.
186+
*/
187+
@NotNull
188+
public CommandClientConfiguration getConfiguration() {
189+
return configuration;
190+
}
191+
192+
/**
193+
* Sets the currently used CommandClientConfiguration.
194+
*
195+
* @param configuration the {@link CommandClientConfiguration}
196+
* @return the {@link CommandClientBuilder}
197+
*/
198+
@NotNull
199+
public CommandClientBuilder setConfiguration(@NotNull CommandClientConfiguration configuration) {
200+
this.configuration = configuration;
201+
return this;
202+
}
203+
204+
/**
205+
* Sets whether the bot should send typing before it parses commands or not.
206+
*
207+
* @param sendTyping whether the bot should send typing before it parses commands or not.
208+
* @see CommandClientConfiguration#getSendTyping()
209+
* @return the {@link CommandClientBuilder}
210+
* @throws IllegalStateException if the stored {@link CommandClientConfiguration} is a {@link me.schlaubi.regnumutils.command.configuration.ImmutableCommandClientConfiguration}
211+
*/
212+
@NotNull
213+
public CommandClientBuilder sendTyping(boolean sendTyping) {
214+
checkMutablility();
215+
((MutableCommandClientConfiguration) configuration).setSendTyping(sendTyping);
216+
return this;
217+
}
218+
219+
/**
220+
* Sets whether the bot should accept a mention as a command prefix or not.
221+
*
222+
* @param acceptMentionPrefix whether the bot should accept a mention as a command prefix or not
223+
* @see CommandClientConfiguration#getAcceptMentionPrefix()
224+
* @return the {@link CommandClientBuilder}
225+
* @throws IllegalStateException if the stored {@link CommandClientConfiguration} is a {@link me.schlaubi.regnumutils.command.configuration.ImmutableCommandClientConfiguration}
226+
*/
227+
@NotNull
228+
public CommandClientBuilder acceptMentionPrefix(boolean acceptMentionPrefix) {
229+
checkMutablility();
230+
((MutableCommandClientConfiguration) configuration).setAcceptMentionPrefix(acceptMentionPrefix);
231+
return this;
232+
}
233+
234+
/**
235+
* Sets the builder for the permissions message that will get send to a user when {@link Context}'s send methods fails.
236+
*
237+
* @param permissionErrorMessageBuilder the {@link Function}
238+
* @see CommandClientConfiguration#buildPermissionErrorMessage(Context)
239+
* @return the {@link CommandClientBuilder}
240+
* @throws IllegalStateException if the stored {@link CommandClientConfiguration} is a {@link me.schlaubi.regnumutils.command.configuration.ImmutableCommandClientConfiguration}
241+
*/
242+
@NotNull
243+
public CommandClientBuilder setPermissionErrorMessageBuilder(Function<@NotNull Context, @NotNull Message> permissionErrorMessageBuilder) {
244+
checkMutablility();
245+
((MutableCommandClientConfiguration) configuration).setPermissionErrorMessageBuilder(permissionErrorMessageBuilder);
246+
return this;
247+
}
248+
249+
250+
private void checkMutablility() {
251+
Preconditions.checkState(!(configuration instanceof MutableCommandClientConfiguration),
252+
"CommandClientConfiguration must be mutable for helper methods!");
253+
}
254+
255+
private void activate(CommandClient commandClient, JDA jda) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
256+
var listener = commandListener.getConstructor(CommandClient.class).newInstance(commandClient);
257+
jda.addEventListener(listener);
258+
}
259+
260+
/**
261+
* Builds the CommandClient.
262+
*
263+
* @return the build {@link CommandClient}
264+
*/
265+
@NotNull
266+
public CommandClient build() {
267+
throw new UnsupportedOperationException();
268+
}
269+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Regnum - A Discord bot clustering system made for Hawk
3+
*
4+
* Copyright (C) 2019 Michael Rittmeister
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see https://www.gnu.org/licenses/.
18+
*/
19+
20+
package me.schlaubi.regnumutils.command.event;
21+
22+
import me.schlaubi.regnumutils.command.spi.Context;
23+
import net.dv8tion.jda.api.JDA;
24+
import net.dv8tion.jda.api.entities.Guild;
25+
26+
import javax.annotation.Nonnull;
27+
28+
/**
29+
* Event that is fired whenever a {@link me.schlaubi.regnumutils.command.spi.Command} was executed successfully.
30+
*/
31+
@SuppressWarnings("unused")
32+
public class CommandExecutedEvent extends GenericCommandContextEvent {
33+
34+
/**
35+
* Constructs an {@link CommandExecutedEvent}.
36+
* @param api the {@link JDA} instance
37+
* @param responseNumber the response number
38+
* @param guild the {@link Guild} on which the command failed
39+
* @param context the {@link Context} of the command
40+
*/
41+
public CommandExecutedEvent(@Nonnull JDA api, long responseNumber, @Nonnull Guild guild, @Nonnull Context context) {
42+
super(api, responseNumber, guild, context);
43+
}
44+
45+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Regnum - A Discord bot clustering system made for Hawk
3+
*
4+
* Copyright (C) 2019 Michael Rittmeister
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see https://www.gnu.org/licenses/.
18+
*/
19+
20+
package me.schlaubi.regnumutils.command.event;
21+
22+
import me.schlaubi.regnumutils.command.spi.Context;
23+
import net.dv8tion.jda.api.JDA;
24+
import net.dv8tion.jda.api.entities.Guild;
25+
import org.jetbrains.annotations.NotNull;
26+
27+
import javax.annotation.Nonnull;
28+
29+
/**
30+
* Event that gets executed whenever a command fails.
31+
*/
32+
@SuppressWarnings("unused")
33+
public class CommandFailEvent extends GenericCommandContextEvent {
34+
35+
private final Throwable throwable;
36+
37+
/**
38+
* Constructs an {@link CommandFailEvent}.
39+
* @param api the {@link JDA} instance
40+
* @param responseNumber the response number
41+
* @param guild the {@link Guild} on which the command failed
42+
* @param context the {@link Context} of the command
43+
* @param throwable the {@link Throwable} that caused the command to fail
44+
*/
45+
public CommandFailEvent(@Nonnull JDA api, long responseNumber, @Nonnull Guild guild, @NotNull Context context, @NotNull Throwable throwable) {
46+
super(api, responseNumber, guild, context);
47+
this.throwable = throwable;
48+
}
49+
50+
/**
51+
* Returns the error that caused the execution to fail.
52+
* @return the {@link Throwable}
53+
*/
54+
@NotNull
55+
public Throwable getThrowable() {
56+
return throwable;
57+
}
58+
}

0 commit comments

Comments
 (0)