Skip to content

Commit 824d83e

Browse files
committed
Support guild specific command.
1 parent ac2db6a commit 824d83e

File tree

3 files changed

+110
-62
lines changed

3 files changed

+110
-62
lines changed

build.gradle

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,27 +59,27 @@ repositories {
5959
dependencies {
6060
// Logger
6161
implementation 'org.slf4j:slf4j-api:2.0.6'
62-
implementation 'ch.qos.logback:logback-core:1.4.6'
63-
implementation 'ch.qos.logback:logback-classic:1.4.6'
62+
implementation 'ch.qos.logback:logback-core:1.4.14'
63+
implementation 'ch.qos.logback:logback-classic:1.4.14'
6464

6565
// ClientLib
66-
api 'com.github.NeoBotDevelopment:NeoBotApi:develop-SNAPSHOT'
66+
api 'com.github.NeoBotDevelopment:NeoBotApi:2.2.0'
6767

6868
// Parser
6969
implementation 'com.google.code.gson:gson:2.10.1'
70-
implementation 'com.fasterxml.jackson.core:jackson-core:2.15.2'
71-
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
72-
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2'
70+
implementation 'com.fasterxml.jackson.core:jackson-core:2.16.1'
71+
implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.1'
72+
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.16.1'
7373

7474
// Commons Library
75-
implementation 'commons-io:commons-io:2.13.0'
75+
implementation 'commons-io:commons-io:2.15.1'
7676
implementation 'commons-codec:commons-codec:1.16.0'
77-
implementation 'org.apache.commons:commons-lang3:3.13.0'
77+
implementation 'org.apache.commons:commons-lang3:3.14.0'
7878

7979
// SQL
80-
implementation 'com.mysql:mysql-connector-j:8.1.0'
81-
implementation 'org.mariadb.jdbc:mariadb-java-client:3.1.4'
82-
implementation 'org.xerial:sqlite-jdbc:3.42.0.0'
80+
implementation 'com.mysql:mysql-connector-j:8.2.0'
81+
implementation 'org.mariadb.jdbc:mariadb-java-client:3.3.2'
82+
implementation 'org.xerial:sqlite-jdbc:3.44.1.0'
8383

8484
// Other
8585
implementation 'de.vandermeer:asciitable:0.3.2'

src/main/java/page/nafuchoco/neobot/core/CommandRegistrar.java

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,70 +18,95 @@
1818

1919
import lombok.extern.slf4j.Slf4j;
2020
import lombok.val;
21+
import net.dv8tion.jda.api.entities.Guild;
2122
import net.dv8tion.jda.api.interactions.commands.Command;
2223
import net.dv8tion.jda.api.interactions.commands.build.*;
2324
import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction;
25+
import org.jetbrains.annotations.NotNull;
26+
import org.jetbrains.annotations.Nullable;
2427
import page.nafuchoco.neobot.api.Launcher;
2528
import page.nafuchoco.neobot.api.command.CommandExecutor;
29+
import page.nafuchoco.neobot.api.command.CommandValueOption;
2630

27-
import java.util.ArrayList;
28-
import java.util.Arrays;
29-
import java.util.List;
31+
import java.util.*;
3032

3133
@Slf4j
3234
public abstract class CommandRegistrar {
3335
private final Launcher launcher;
3436

35-
private CommandListUpdateAction updateAction;
36-
private List<Command> registeredCommands = new ArrayList<>();
37-
private boolean globalCommandListUpdated = false;
37+
private CommandListUpdateAction globalUpdateAction;
38+
private final Map<Long, CommandListUpdateAction> guildUpdateActions = new HashMap<>();
39+
private final Map<Long, List<Command>> registeredCommands = new HashMap<>();
40+
private boolean commandListUpdated = false;
3841

3942
protected CommandRegistrar(Launcher launcher) {
4043
this.launcher = launcher;
44+
registeredCommands.put(null, new ArrayList<>());
4145
}
4246

43-
protected void registerCommandToDiscord(CommandExecutor executor) {
47+
protected void registerCommandToDiscord(CommandExecutor executor, Guild guild) {
4448
val command = Commands.slash(executor.getName(), executor.getDescription());
4549
addCommandOptions(command, executor);
46-
addCommands(command);
50+
addCommands(guild, command);
4751
}
4852

49-
protected void unregisterCommandFromDiscord(CommandExecutor executor) {
53+
protected void unregisterCommandFromDiscord(@NotNull CommandExecutor executor, @Nullable Guild guild) {
5054
if (executor == null)
5155
return;
5256

53-
if (globalCommandListUpdated) {
54-
var commandData = registeredCommands.stream().filter(command -> executor.getName().equals(command.getName())).findFirst().orElse(null);
55-
if (commandData != null) {
56-
launcher.getDiscordApi().getShardById(0).deleteCommandById(commandData.getId()).queue();
57-
registeredCommands.remove(commandData);
57+
if (commandListUpdated) {
58+
if (guild == null) {
59+
registeredCommands.get(null).stream().filter(command -> executor.getName().equals(command.getName())).findFirst().ifPresent(command -> {
60+
launcher.getDiscordApi().getShardById(0).deleteCommandById(command.getId()).queue();
61+
registeredCommands.get(null).remove(command);
62+
});
63+
} else {
64+
registeredCommands.get(guild.getIdLong()).stream().filter(command -> executor.getName().equals(command.getName())).findFirst().ifPresent(command -> {
65+
guild.deleteCommandById(command.getId()).queue();
66+
registeredCommands.get(guild.getIdLong()).remove(command);
67+
});
5868
}
5969
} else {
6070
throw new IllegalStateException("Global command list has not been updated yet.");
6171
}
6272
}
6373

64-
private void addCommands(CommandData... commands) {
65-
if (globalCommandListUpdated) {
66-
Arrays.stream(commands).forEach(command -> {
67-
launcher.getDiscordApi().getShardById(0).upsertCommand(command).queue(reg -> registeredCommands.add(reg));
68-
});
74+
private void addCommands(Guild guild, CommandData... commands) {
75+
if (commandListUpdated) {
76+
if (guild == null) {
77+
Arrays.stream(commands).forEach(command -> {
78+
launcher.getDiscordApi().getShardById(0).upsertCommand(command).queue(reg -> registeredCommands.get(null).add(reg));
79+
});
80+
} else {
81+
Arrays.stream(commands).forEach(command -> {
82+
guild.upsertCommand(command).queue(reg -> registeredCommands.computeIfAbsent(guild.getIdLong(), key -> new ArrayList<>()).add(reg));
83+
});
84+
}
6985
} else {
70-
if (updateAction == null)
71-
updateAction = launcher.getDiscordApi().getShardById(0).updateCommands();
86+
if (guild == null) {
87+
if (globalUpdateAction == null)
88+
globalUpdateAction = launcher.getDiscordApi().getShardById(0).updateCommands();
89+
globalUpdateAction.addCommands(commands);
7290

73-
updateAction.addCommands(commands);
91+
} else {
92+
guildUpdateActions.computeIfAbsent(guild.getIdLong(), key -> guild.updateCommands()).addCommands(commands);
93+
}
7494
}
7595
}
7696

7797
private void addCommandOptions(SlashCommandData command, CommandExecutor executor) {
78-
executor.getValueOptions().stream().map(option -> {
98+
executor.getValueOptions().stream()
99+
.sorted(Comparator.comparing(CommandValueOption::required).reversed())
100+
.map(option -> {
79101
val optionData = new OptionData(option.optionType(), option.optionName(), option.optionDescription(), option.required(), option.autoComplete());
80102
if (!option.getChoices().isEmpty()) {
81103
switch (option.optionType()) {
82-
case STRING -> option.getChoices().forEach((key, value) -> optionData.addChoice(key, (String) value));
83-
case INTEGER -> option.getChoices().forEach((key, value) -> optionData.addChoice(key, (Long) value));
84-
case NUMBER -> option.getChoices().forEach((key, value) -> optionData.addChoice(key, (Double) value));
104+
case STRING ->
105+
option.getChoices().forEach((key, value) -> optionData.addChoice(key, (String) value));
106+
case INTEGER ->
107+
option.getChoices().forEach((key, value) -> optionData.addChoice(key, (Long) value));
108+
case NUMBER ->
109+
option.getChoices().forEach((key, value) -> optionData.addChoice(key, (Double) value));
85110
default -> throw new IllegalStateException("Unexpected value: " + option.optionType());
86111
}
87112
}
@@ -95,12 +120,14 @@ private void addCommandOptions(SlashCommandData command, CommandExecutor executo
95120
}
96121

97122
protected void queue() {
98-
updateAction.queue(commands -> registeredCommands = new ArrayList<>(commands));
99-
updateAction = null;
100-
globalCommandListUpdated = true;
123+
globalUpdateAction.queue(commands -> registeredCommands.put(null, new ArrayList<>(commands)));
124+
guildUpdateActions.forEach((guildId, action) -> action.queue(commands -> registeredCommands.computeIfAbsent(guildId, key -> new ArrayList<>(commands))));
125+
globalUpdateAction = null;
126+
guildUpdateActions.clear();
127+
commandListUpdated = true;
101128
}
102129

103130
protected List<Command> getRegisteredCommands() {
104-
return registeredCommands;
131+
return registeredCommands.values().stream().flatMap(Collection::stream).toList();
105132
}
106133
}

src/main/java/page/nafuchoco/neobot/core/DefaultCommandRegistry.java

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
package page.nafuchoco.neobot.core;
1818

1919
import lombok.extern.slf4j.Slf4j;
20+
import net.dv8tion.jda.api.entities.Guild;
21+
import org.jetbrains.annotations.NotNull;
22+
import org.jetbrains.annotations.Nullable;
2023
import page.nafuchoco.neobot.api.Launcher;
2124
import page.nafuchoco.neobot.api.command.CommandExecutor;
2225
import page.nafuchoco.neobot.api.command.CommandGroup;
@@ -30,85 +33,103 @@
3033

3134
@Slf4j
3235
public class DefaultCommandRegistry extends CommandRegistrar implements ICommandRegistry {
36+
private final Launcher launcher;
3337
private final Map<String, CommandGroup> groups = new LinkedHashMap<>();
3438

3539
public DefaultCommandRegistry(Launcher launcher) {
3640
super(launcher);
41+
this.launcher = launcher;
3742
}
3843

3944
@Override
40-
public void registerCommand(CommandExecutor executor, NeoModule module) {
41-
registerCommand(executor, null, module);
42-
}
43-
44-
@Override
45-
public void registerCommand(CommandExecutor executor, String groupName, NeoModule module) {
46-
log.debug("Register command: {}", executor.getName());
45+
public void registerCommand(@NotNull CommandExecutor executor, @Nullable NeoModule module, @Nullable String groupName, @Nullable Guild guild) {
46+
log.debug("Register command: {} ({})", executor.getName(), guild != null ? guild.getName() : "Global");
4747
for (CommandGroup g : groups.values()) {
4848
if (g.getCommands().contains(executor))
4949
throw new IllegalArgumentException("Cannot register a command executor that has already been registered in another command group.");
5050
}
5151

5252
CommandGroup group = groups.computeIfAbsent(groupName, key -> new CommandGroup(groupName));
53-
group.registerCommand(executor, module);
53+
group.registerCommand(executor, module, guild);
5454

55-
registerCommandToDiscord(executor);
55+
registerCommandToDiscord(executor, guild);
5656
}
5757

5858
@Override
59-
public void removeCommand(String name, NeoModule module) {
59+
public void removeCommand(@NotNull String name, @Nullable NeoModule module, @Nullable Guild guild) {
6060
for (CommandGroup g : groups.values())
61-
unregisterCommandFromDiscord(g.removeCommand(name, module));
61+
unregisterCommandFromDiscord(g.removeCommand(name, module, guild), guild);
6262
}
6363

6464
@Override
65-
public void removeCommand(CommandExecutor executor, NeoModule module) {
65+
public void removeCommand(@NotNull CommandExecutor executor, @Nullable NeoModule module, @Nullable Guild guild) {
6666
for (CommandGroup g : groups.values())
67-
g.removeCommand(executor, module);
68-
unregisterCommandFromDiscord(executor);
67+
g.removeCommand(executor, module, guild);
68+
unregisterCommandFromDiscord(executor, guild);
69+
}
70+
71+
@Override
72+
public void removeCommands(@Nullable NeoModule neoModule, @Nullable Guild guild) {
73+
6974
}
7075

7176
@Override
7277
public void removeCommands(NeoModule module) {
7378
for (CommandGroup g : groups.values())
74-
g.removeCommands(module).forEach(this::unregisterCommandFromDiscord);
79+
g.removeCommands(module).forEach((guild, executors) -> {
80+
var guildObj = guild != null ? launcher.getDiscordApi().getGuildById(guild) : null;
81+
executors.forEach(executor -> unregisterCommandFromDiscord(executor, guildObj));
82+
});
7583
}
7684

7785
@Override
7886
public void deleteCommandGroup(String groupName) {
7987
CommandGroup group = groups.remove(groupName);
8088
if (group != null)
81-
group.getCommands().forEach(this::unregisterCommandFromDiscord);
89+
group.getCommands().forEach(executor -> unregisterCommandFromDiscord(executor, null));
8290

8391
}
8492

8593
@Override
8694
public void deleteCommandGroup(CommandGroup commandGroup) {
87-
groups.remove(commandGroup.getGroupName()).getCommands().forEach(this::unregisterCommandFromDiscord);
95+
groups.remove(commandGroup.getGroupName()).getCommands().forEach(executor -> unregisterCommandFromDiscord(executor, null));
8896
}
8997

98+
@NotNull
9099
@Override
91100
public List<CommandGroup> getCommandGroups() {
92101
return new ArrayList<>(groups.values());
93102
}
94103

104+
@NotNull
95105
@Override
96106
public List<String> getCommandGroupsNames() {
97107
return new ArrayList<>(groups.keySet());
98108
}
99109

110+
@Override
111+
public CommandGroup getCommandGroup(String groupName) {
112+
return groups.get(groupName);
113+
}
114+
115+
@NotNull
100116
@Override
101117
public List<CommandExecutor> getCommands() {
102118
return groups.values().stream().flatMap(v -> v.getCommands().stream()).distinct().toList();
103119
}
104120

105121
@Override
106-
public CommandGroup getCommandGroup(String groupName) {
107-
return groups.get(groupName);
122+
public @NotNull List<CommandExecutor> getCommands(@Nullable NeoModule neoModule) {
123+
return groups.values().stream().flatMap(v -> v.getCommands(neoModule).stream()).distinct().toList();
124+
}
125+
126+
@Override
127+
public @NotNull List<CommandExecutor> getCommands(@Nullable Guild guild) {
128+
return groups.values().stream().flatMap(v -> v.getCommands(guild).stream()).distinct().toList();
108129
}
109130

110131
@Override
111-
public CommandExecutor getExecutor(String name) {
132+
public @Nullable CommandExecutor getExecutor(@Nullable Guild guild, String name) {
112133
CommandExecutor executor = null;
113134
List<CommandGroup> groupList = new ArrayList<>(groups.values());
114135
for (int i = 0; i < groupList.size(); i++) {
@@ -117,7 +138,7 @@ public CommandExecutor getExecutor(String name) {
117138
CommandGroup group = groupList.get(i);
118139
if (group != null && !group.isEnabled())
119140
continue;
120-
executor = group.getExecutor(name);
141+
executor = group.getExecutor(guild, name);
121142
}
122143
return executor;
123144
}

0 commit comments

Comments
 (0)