mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2024-11-01 08:39:31 +01:00
Add combined Minecraft & Discord commands
This commit is contained in:
parent
4700adaaf9
commit
df5a253b48
@ -179,6 +179,12 @@ public class Command implements JDAEntity<CommandData> {
|
||||
return Collections.unmodifiableList(subCommandGroups);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Unmodifiable
|
||||
public List<Command> getSubCommands() {
|
||||
return Collections.unmodifiableList(subCommands);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Unmodifiable
|
||||
public List<CommandOption> getOptions() {
|
||||
|
@ -29,8 +29,9 @@ import com.discordsrv.common.channel.ChannelConfigHelper;
|
||||
import com.discordsrv.common.channel.ChannelLockingModule;
|
||||
import com.discordsrv.common.channel.ChannelUpdaterModule;
|
||||
import com.discordsrv.common.channel.GlobalChannelLookupModule;
|
||||
import com.discordsrv.common.command.discord.DiscordCommandModule;
|
||||
import com.discordsrv.common.command.game.GameCommandModule;
|
||||
import com.discordsrv.common.command.game.command.subcommand.reload.ReloadResults;
|
||||
import com.discordsrv.common.command.game.commands.subcommand.reload.ReloadResults;
|
||||
import com.discordsrv.common.component.ComponentFactory;
|
||||
import com.discordsrv.common.config.connection.ConnectionConfig;
|
||||
import com.discordsrv.common.config.connection.UpdateConfig;
|
||||
@ -562,6 +563,7 @@ public abstract class AbstractDiscordSRV<B extends IBootstrap, C extends MainCon
|
||||
// Modules
|
||||
registerModule(ChannelLockingModule::new);
|
||||
registerModule(ChannelUpdaterModule::new);
|
||||
registerModule(DiscordCommandModule::new);
|
||||
registerModule(GameCommandModule::new);
|
||||
registerModule(GlobalChannelLookupModule::new);
|
||||
registerModule(DiscordAPIEventModule::new);
|
||||
@ -755,6 +757,11 @@ public abstract class AbstractDiscordSRV<B extends IBootstrap, C extends MainCon
|
||||
results.addAll(moduleManager.reload());
|
||||
}
|
||||
|
||||
if (1 == 1) {
|
||||
discordAPI().commandRegistry().registerCommandsFromEvent();
|
||||
discordAPI().commandRegistry().registerCommandsToDiscord();
|
||||
}
|
||||
|
||||
if (!initial) {
|
||||
eventBus().publish(new DiscordSRVReloadedEvent(flags));
|
||||
logger().info("Reload complete.");
|
||||
|
@ -0,0 +1,31 @@
|
||||
package com.discordsrv.common.command.combined.abstraction;
|
||||
|
||||
import com.discordsrv.api.discord.events.interaction.command.DiscordChatInputInteractionEvent;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandArguments;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandExecutor;
|
||||
import com.discordsrv.common.command.game.sender.ICommandSender;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public abstract class CombinedCommand implements GameCommandExecutor, Consumer<DiscordChatInputInteractionEvent> {
|
||||
|
||||
protected final DiscordSRV discordSRV;
|
||||
|
||||
public CombinedCommand(DiscordSRV discordSRV) {
|
||||
this.discordSRV = discordSRV;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ICommandSender sender, GameCommandArguments arguments) {
|
||||
execute(new GameCommandExecution(discordSRV, sender, arguments));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DiscordChatInputInteractionEvent event) {
|
||||
execute(new DiscordCommandExecution(discordSRV, event));
|
||||
}
|
||||
|
||||
public abstract void execute(CommandExecution execution);
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.discordsrv.common.command.combined.abstraction;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
public interface CommandExecution {
|
||||
|
||||
void setEphemeral(boolean ephemeral);
|
||||
|
||||
String getArgument(String label);
|
||||
|
||||
default void send(Text... texts) {
|
||||
send(Arrays.asList(texts));
|
||||
}
|
||||
void send(Collection<Text> texts);
|
||||
|
||||
void runAsync(Runnable runnable);
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package com.discordsrv.common.command.combined.abstraction;
|
||||
|
||||
import com.discordsrv.api.discord.events.interaction.command.DiscordChatInputInteractionEvent;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import net.dv8tion.jda.api.interactions.InteractionHook;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class DiscordCommandExecution implements CommandExecution {
|
||||
|
||||
private final DiscordSRV discordSRV;
|
||||
private final DiscordChatInputInteractionEvent event;
|
||||
private final AtomicBoolean isEphemeral = new AtomicBoolean(true);
|
||||
private final AtomicReference<InteractionHook> hook = new AtomicReference<>();
|
||||
|
||||
public DiscordCommandExecution(DiscordSRV discordSRV, DiscordChatInputInteractionEvent event) {
|
||||
this.discordSRV = discordSRV;
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEphemeral(boolean ephemeral) {
|
||||
isEphemeral.set(ephemeral);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgument(String label) {
|
||||
OptionMapping mapping = event.asJDA().getOption(label);
|
||||
return mapping != null ? mapping.getAsString() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Collection<Text> texts) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
EnumMap<Text.Formatting, Boolean> formats = new EnumMap<>(Text.Formatting.class);
|
||||
|
||||
for (Text text : texts) {
|
||||
if (StringUtils.isEmpty(text.content())) continue;
|
||||
|
||||
verifyStyle(builder, formats, text);
|
||||
builder.append(text.content());
|
||||
}
|
||||
|
||||
verifyStyle(builder, formats, null);
|
||||
|
||||
InteractionHook interactionHook = hook.get();
|
||||
boolean ephemeral = isEphemeral.get();
|
||||
if (interactionHook != null) {
|
||||
interactionHook.sendMessage(builder.toString()).setEphemeral(ephemeral).queue();
|
||||
} else {
|
||||
event.asJDA().reply(builder.toString()).setEphemeral(ephemeral).queue();
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyStyle(StringBuilder builder, EnumMap<Text.Formatting, Boolean> formats, Text text) {
|
||||
for (Text.Formatting format : Text.Formatting.values()) {
|
||||
boolean is = formats.computeIfAbsent(format, key -> false);
|
||||
boolean thisIs = text != null && text.discordFormatting().contains(format);
|
||||
|
||||
if (is != thisIs) {
|
||||
// should end or start
|
||||
builder.append(format.discord());
|
||||
formats.put(format, thisIs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runAsync(Runnable runnable) {
|
||||
event.asJDA().deferReply(isEphemeral.get()).queue(ih -> {
|
||||
hook.set(ih);
|
||||
discordSRV.scheduler().run(runnable);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.discordsrv.common.command.combined.abstraction;
|
||||
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandArguments;
|
||||
import com.discordsrv.common.command.game.sender.ICommandSender;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class GameCommandExecution implements CommandExecution {
|
||||
|
||||
private final DiscordSRV discordSRV;
|
||||
private final ICommandSender sender;
|
||||
private final GameCommandArguments arguments;
|
||||
|
||||
public GameCommandExecution(DiscordSRV discordSRV, ICommandSender sender, GameCommandArguments arguments) {
|
||||
this.discordSRV = discordSRV;
|
||||
this.sender = sender;
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEphemeral(boolean ephemeral) {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgument(String label) {
|
||||
return arguments.getString(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Collection<Text> texts) {
|
||||
TextComponent.Builder builder = Component.text();
|
||||
for (Text text : texts) {
|
||||
builder.append(
|
||||
Component.text(text.content())
|
||||
.color(text.gameColor())
|
||||
.decorations(text.gameFormatting(), true)
|
||||
);
|
||||
}
|
||||
sender.sendMessage(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runAsync(Runnable runnable) {
|
||||
discordSRV.scheduler().run(runnable);
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package com.discordsrv.common.command.combined.abstraction;
|
||||
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
||||
public class Text {
|
||||
|
||||
private final String content;
|
||||
private TextColor gameColor;
|
||||
private EnumSet<TextDecoration> gameFormatting;
|
||||
private EnumSet<Formatting> discordFormatting;
|
||||
|
||||
public Text(String content) {
|
||||
this.content = content;
|
||||
this.gameFormatting = EnumSet.noneOf(TextDecoration.class);
|
||||
this.discordFormatting = EnumSet.noneOf(Formatting.class);
|
||||
}
|
||||
|
||||
public String content() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public Text withGameColor(TextColor color) {
|
||||
this.gameColor = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextColor gameColor() {
|
||||
return gameColor;
|
||||
}
|
||||
|
||||
public Text withFormatting(Formatting... formatting) {
|
||||
EnumSet<TextDecoration> game = EnumSet.noneOf(TextDecoration.class);
|
||||
for (Formatting format : formatting) {
|
||||
game.add(format.game);
|
||||
}
|
||||
|
||||
this.gameFormatting = game;
|
||||
this.discordFormatting = EnumSet.copyOf(Arrays.asList(formatting));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Text withGameFormatting(Formatting... formatting) {
|
||||
EnumSet<TextDecoration> game = EnumSet.noneOf(TextDecoration.class);
|
||||
for (Formatting format : formatting) {
|
||||
game.add(format.game);
|
||||
}
|
||||
|
||||
this.gameFormatting = game;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EnumSet<TextDecoration> gameFormatting() {
|
||||
return gameFormatting;
|
||||
}
|
||||
|
||||
public Text withDiscordFormatting(Formatting... formatting) {
|
||||
this.discordFormatting = EnumSet.copyOf(Arrays.asList(formatting));
|
||||
return this;
|
||||
}
|
||||
|
||||
public EnumSet<Formatting> discordFormatting() {
|
||||
return discordFormatting;
|
||||
}
|
||||
|
||||
public enum Formatting {
|
||||
BOLD(TextDecoration.BOLD, "**"),
|
||||
ITALICS(TextDecoration.ITALIC, "*"),
|
||||
UNDERLINED(TextDecoration.UNDERLINED, "__"),
|
||||
STRIKETHROUGH(TextDecoration.STRIKETHROUGH, "~~");
|
||||
|
||||
private final TextDecoration game;
|
||||
private final String discord;
|
||||
|
||||
Formatting(TextDecoration game, String discord) {
|
||||
this.game = game;
|
||||
this.discord = discord;
|
||||
}
|
||||
|
||||
public String discord() {
|
||||
return discord;
|
||||
}
|
||||
}
|
||||
}
|
@ -16,20 +16,21 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.command.game.command.subcommand;
|
||||
package com.discordsrv.common.command.combined.commands;
|
||||
|
||||
import com.discordsrv.api.discord.entity.interaction.command.Command;
|
||||
import com.discordsrv.api.discord.entity.interaction.command.CommandOption;
|
||||
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.combined.abstraction.CombinedCommand;
|
||||
import com.discordsrv.common.command.combined.abstraction.CommandExecution;
|
||||
import com.discordsrv.common.command.combined.abstraction.Text;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommand;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandArguments;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandExecutor;
|
||||
import com.discordsrv.common.command.game.sender.ICommandSender;
|
||||
import com.discordsrv.common.debug.DebugReport;
|
||||
import com.discordsrv.common.paste.Paste;
|
||||
import com.discordsrv.common.paste.PasteService;
|
||||
import com.discordsrv.common.paste.service.AESEncryptedPasteService;
|
||||
import com.discordsrv.common.paste.service.BytebinPasteService;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -38,54 +39,76 @@ import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
|
||||
public class DebugCommand implements GameCommandExecutor {
|
||||
public class DebugCommand extends CombinedCommand {
|
||||
|
||||
private static GameCommand INSTANCE;
|
||||
private static DebugCommand INSTANCE;
|
||||
private static GameCommand GAME;
|
||||
private static Command DISCORD;
|
||||
|
||||
public static GameCommand get(DiscordSRV discordSRV) {
|
||||
if (INSTANCE == null) {
|
||||
DebugCommand debugCommand = new DebugCommand(discordSRV);
|
||||
INSTANCE = GameCommand.literal("debug")
|
||||
private static DebugCommand getInstance(DiscordSRV discordSRV) {
|
||||
return INSTANCE != null ? INSTANCE : (INSTANCE = new DebugCommand(discordSRV));
|
||||
}
|
||||
|
||||
public static GameCommand getGame(DiscordSRV discordSRV) {
|
||||
if (GAME == null) {
|
||||
DebugCommand command = getInstance(discordSRV);
|
||||
GAME = GameCommand.literal("debug")
|
||||
.requiredPermission("discordsrv.admin.debug")
|
||||
.executor(debugCommand)
|
||||
.executor(command)
|
||||
.then(
|
||||
GameCommand.stringWord("zip")
|
||||
GameCommand.stringWord("format")
|
||||
.suggester((sender, previousArguments, currentInput) ->
|
||||
"zip".startsWith(currentInput.toLowerCase(Locale.ROOT))
|
||||
? Collections.singletonList("zip") : Collections.emptyList())
|
||||
.executor(debugCommand)
|
||||
.executor(command)
|
||||
);
|
||||
}
|
||||
|
||||
return INSTANCE;
|
||||
return GAME;
|
||||
}
|
||||
|
||||
public static Command getDiscord(DiscordSRV discordSRV) {
|
||||
if (DISCORD == null) {
|
||||
DebugCommand command = getInstance(discordSRV);
|
||||
DISCORD = Command.chatInput(ComponentIdentifier.of("DiscordSRV", "debug"), "debug", "Create a debug report")
|
||||
.addOption(
|
||||
CommandOption.builder(CommandOption.Type.STRING, "format", "The format to generate the debug report")
|
||||
.addChoice(".zip", "zip")
|
||||
.setRequired(false)
|
||||
.build()
|
||||
)
|
||||
.setEventHandler(command)
|
||||
.build();
|
||||
}
|
||||
|
||||
return DISCORD;
|
||||
}
|
||||
|
||||
private static final String URL_FORMAT = "https://discordsrv.vankka.dev/debug/%s#%s";
|
||||
private static final Base64.Encoder KEY_ENCODER = Base64.getUrlEncoder().withoutPadding();
|
||||
|
||||
private final DiscordSRV discordSRV;
|
||||
private final PasteService pasteService;
|
||||
|
||||
public DebugCommand(DiscordSRV discordSRV) {
|
||||
this.discordSRV = discordSRV;
|
||||
super(discordSRV);
|
||||
this.pasteService = new AESEncryptedPasteService(new BytebinPasteService(discordSRV, "https://bytebin.lucko.me") /* TODO: final store tbd */, 128);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ICommandSender sender, GameCommandArguments arguments) {
|
||||
boolean usePaste = !"zip".equals(arguments.getString("zip"));
|
||||
public void execute(CommandExecution execution) {
|
||||
boolean usePaste = !"zip".equals(execution.getArgument("format"));
|
||||
|
||||
discordSRV.scheduler().run(() -> {
|
||||
execution.runAsync(() -> {
|
||||
DebugReport report = new DebugReport(discordSRV);
|
||||
report.generate();
|
||||
|
||||
Throwable pasteError = usePaste ? paste(sender, report) : null;
|
||||
Throwable pasteError = usePaste ? paste(execution, report) : null;
|
||||
if (usePaste && pasteError == null) {
|
||||
// Success
|
||||
return;
|
||||
}
|
||||
|
||||
Throwable zipError = zip(sender, report);
|
||||
Throwable zipError = zip(execution, report);
|
||||
if (zipError == null) {
|
||||
// Success
|
||||
if (usePaste) {
|
||||
@ -98,35 +121,38 @@ public class DebugCommand implements GameCommandExecutor {
|
||||
zipError.addSuppressed(pasteError);
|
||||
}
|
||||
discordSRV.logger().error(usePaste ? "Failed to upload & zip debug" : "Failed to zip debug", zipError);
|
||||
sender.sendMessage(Component.text(
|
||||
usePaste
|
||||
? "Failed to upload debug report to paste & failed to generate zip"
|
||||
: "Failed to create debug zip",
|
||||
NamedTextColor.DARK_RED
|
||||
));
|
||||
execution.send(
|
||||
new Text(usePaste
|
||||
? "Failed to upload debug report to paste & failed to generate zip"
|
||||
: "Failed to create debug zip"
|
||||
).withGameColor(NamedTextColor.DARK_RED)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private Throwable paste(ICommandSender sender, DebugReport report) {
|
||||
private Throwable paste(CommandExecution execution, DebugReport report) {
|
||||
try {
|
||||
Paste paste = report.upload(pasteService);
|
||||
String key = new String(KEY_ENCODER.encode(paste.decryptionKey()), StandardCharsets.UTF_8);
|
||||
String url = String.format(URL_FORMAT, paste.id(), key);
|
||||
|
||||
sender.sendMessage(Component.text(url).clickEvent(ClickEvent.openUrl(url)));
|
||||
execution.send(new Text(url));
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
private Throwable zip(ICommandSender sender, DebugReport report) {
|
||||
private Throwable zip(CommandExecution execution, DebugReport report) {
|
||||
try {
|
||||
Path zip = report.zip();
|
||||
Path relative = discordSRV.dataDirectory().resolve("../..").relativize(zip);
|
||||
sender.sendMessage(
|
||||
Component.text("Debug generated to zip: ", NamedTextColor.GRAY)
|
||||
.append(Component.text(relative.toString(), NamedTextColor.GREEN))
|
||||
execution.send(
|
||||
new Text("Debug generated to zip ")
|
||||
.withGameColor(NamedTextColor.GRAY),
|
||||
new Text(relative.toString())
|
||||
.withGameColor(NamedTextColor.GREEN)
|
||||
.withDiscordFormatting(Text.Formatting.BOLD)
|
||||
);
|
||||
return null;
|
||||
} catch (Throwable e) {
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2023 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.command.combined.commands;
|
||||
|
||||
import com.discordsrv.api.color.Color;
|
||||
import com.discordsrv.api.discord.entity.interaction.command.Command;
|
||||
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.combined.abstraction.CombinedCommand;
|
||||
import com.discordsrv.common.command.combined.abstraction.CommandExecution;
|
||||
import com.discordsrv.common.command.combined.abstraction.Text;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommand;
|
||||
import com.discordsrv.common.debug.data.VersionInfo;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class VersionCommand extends CombinedCommand {
|
||||
|
||||
private static VersionCommand INSTANCE;
|
||||
private static GameCommand GAME;
|
||||
private static Command DISCORD;
|
||||
|
||||
private static VersionCommand getInstance(DiscordSRV discordSRV) {
|
||||
return INSTANCE != null ? INSTANCE : (INSTANCE = new VersionCommand(discordSRV));
|
||||
}
|
||||
|
||||
public static GameCommand getGame(DiscordSRV discordSRV) {
|
||||
if (GAME == null) {
|
||||
VersionCommand command = getInstance(discordSRV);
|
||||
GAME = GameCommand.literal("version")
|
||||
.requiredPermission("discordsrv.admin.version")
|
||||
.executor(command);
|
||||
}
|
||||
|
||||
return GAME;
|
||||
}
|
||||
|
||||
public static Command getDiscord(DiscordSRV discordSRV) {
|
||||
if (DISCORD == null) {
|
||||
VersionCommand command = getInstance(discordSRV);
|
||||
DISCORD = Command.chatInput(ComponentIdentifier.of("DiscordSRV", "version"), "version", "Get the DiscordSRV version")
|
||||
.setEventHandler(command)
|
||||
.build();
|
||||
}
|
||||
|
||||
return DISCORD;
|
||||
}
|
||||
|
||||
public VersionCommand(DiscordSRV discordSRV) {
|
||||
super(discordSRV);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandExecution execution) {
|
||||
VersionInfo versionInfo = discordSRV.versionInfo();
|
||||
|
||||
List<Text> text = new ArrayList<>();
|
||||
text.add(
|
||||
new Text("Running DiscordSRV ")
|
||||
.withGameColor(TextColor.color(Color.BLURPLE.rgb()))
|
||||
);
|
||||
text.add(
|
||||
new Text("v" + versionInfo.version())
|
||||
.withGameColor(NamedTextColor.GRAY)
|
||||
.withDiscordFormatting(Text.Formatting.BOLD)
|
||||
);
|
||||
|
||||
if (versionInfo.isSnapshot()) {
|
||||
String rev = StringUtils.substring(versionInfo.gitRevision(), 0, 6);
|
||||
text.add(new Text(" (" + rev + "/" + versionInfo.gitBranch() + ")").withGameColor(NamedTextColor.AQUA));
|
||||
}
|
||||
|
||||
execution.send(text);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.discordsrv.common.command.discord;
|
||||
|
||||
import com.discordsrv.api.discord.events.interaction.command.CommandRegisterEvent;
|
||||
import com.discordsrv.api.event.bus.Subscribe;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.discord.commands.DiscordSRVDiscordCommand;
|
||||
import com.discordsrv.common.module.type.AbstractModule;
|
||||
|
||||
public class DiscordCommandModule extends AbstractModule<DiscordSRV> {
|
||||
|
||||
public DiscordCommandModule(DiscordSRV discordSRV) {
|
||||
super(discordSRV);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onCommandRegister(CommandRegisterEvent event) {
|
||||
event.registerCommands(DiscordSRVDiscordCommand.get(discordSRV));
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.discordsrv.common.command.discord.commands;
|
||||
|
||||
import com.discordsrv.api.discord.entity.interaction.command.Command;
|
||||
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.combined.commands.DebugCommand;
|
||||
import com.discordsrv.common.command.combined.commands.VersionCommand;
|
||||
|
||||
public class DiscordSRVDiscordCommand {
|
||||
|
||||
private static final ComponentIdentifier IDENTIFIER = ComponentIdentifier.of("DiscordSRV", "discordsrv");
|
||||
|
||||
private static Command INSTANCE;
|
||||
|
||||
public static Command get(DiscordSRV discordSRV) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = Command.chatInput(IDENTIFIER, "discordsrv", "DiscordSRV related commands")
|
||||
.addSubCommand(DebugCommand.getDiscord(discordSRV))
|
||||
.addSubCommand(VersionCommand.getDiscord(discordSRV))
|
||||
.setGuildOnly(false)
|
||||
.setDefaultPermission(Command.DefaultPermission.ADMINISTRATOR)
|
||||
.build();
|
||||
}
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
@ -20,8 +20,8 @@ package com.discordsrv.common.command.game;
|
||||
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommand;
|
||||
import com.discordsrv.common.command.game.command.DiscordSRVCommand;
|
||||
import com.discordsrv.common.command.game.command.subcommand.LinkCommand;
|
||||
import com.discordsrv.common.command.game.commands.DiscordSRVGameCommand;
|
||||
import com.discordsrv.common.command.game.commands.subcommand.LinkCommand;
|
||||
import com.discordsrv.common.command.game.handler.ICommandHandler;
|
||||
import com.discordsrv.common.config.main.CommandConfig;
|
||||
import com.discordsrv.common.module.type.AbstractModule;
|
||||
@ -39,8 +39,8 @@ public class GameCommandModule extends AbstractModule<DiscordSRV> {
|
||||
|
||||
public GameCommandModule(DiscordSRV discordSRV) {
|
||||
super(discordSRV);
|
||||
this.primaryCommand = DiscordSRVCommand.get(discordSRV, "discordsrv");
|
||||
this.discordAlias = DiscordSRVCommand.get(discordSRV, "discord");
|
||||
this.primaryCommand = DiscordSRVGameCommand.get(discordSRV, "discordsrv");
|
||||
this.discordAlias = DiscordSRVGameCommand.get(discordSRV, "discord");
|
||||
this.linkCommand = LinkCommand.get(discordSRV);
|
||||
|
||||
registerCommand(primaryCommand);
|
||||
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2023 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.command.game.command.subcommand;
|
||||
|
||||
import com.discordsrv.api.color.Color;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommand;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandArguments;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandExecutor;
|
||||
import com.discordsrv.common.command.game.sender.ICommandSender;
|
||||
import com.discordsrv.common.debug.data.VersionInfo;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class VersionCommand implements GameCommandExecutor {
|
||||
|
||||
private static GameCommand INSTANCE;
|
||||
|
||||
public static GameCommand get(DiscordSRV discordSRV) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = GameCommand.literal("version")
|
||||
.requiredPermission("discordsrv.admin.version")
|
||||
.executor(new VersionCommand(discordSRV));
|
||||
}
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private final DiscordSRV discordSRV;
|
||||
|
||||
public VersionCommand(DiscordSRV discordSRV) {
|
||||
this.discordSRV = discordSRV;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ICommandSender sender, GameCommandArguments arguments) {
|
||||
VersionInfo versionInfo = discordSRV.versionInfo();
|
||||
|
||||
TextComponent.Builder builder =
|
||||
Component.text()
|
||||
.content("Running DiscordSRV ")
|
||||
.color(TextColor.color(Color.BLURPLE.rgb()))
|
||||
.append(Component.text("v" + versionInfo.version(), NamedTextColor.GRAY));
|
||||
if (versionInfo.isSnapshot()) {
|
||||
String rev = StringUtils.substring(versionInfo.gitRevision(), 0, 6);
|
||||
builder.append(
|
||||
Component.text()
|
||||
.content(" (" + rev + "/" + versionInfo.gitBranch() + ")")
|
||||
.color(NamedTextColor.AQUA)
|
||||
);
|
||||
}
|
||||
|
||||
sender.sendMessage(builder);
|
||||
}
|
||||
}
|
@ -16,29 +16,31 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.command.game.command;
|
||||
package com.discordsrv.common.command.game.commands;
|
||||
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.combined.commands.DebugCommand;
|
||||
import com.discordsrv.common.command.combined.commands.VersionCommand;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommand;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandArguments;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandExecutor;
|
||||
import com.discordsrv.common.command.game.command.subcommand.*;
|
||||
import com.discordsrv.common.command.game.command.subcommand.reload.ReloadCommand;
|
||||
import com.discordsrv.common.command.game.commands.subcommand.*;
|
||||
import com.discordsrv.common.command.game.commands.subcommand.reload.ReloadCommand;
|
||||
import com.discordsrv.common.command.game.sender.ICommandSender;
|
||||
import com.discordsrv.common.component.util.ComponentUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class DiscordSRVCommand implements GameCommandExecutor {
|
||||
public class DiscordSRVGameCommand implements GameCommandExecutor {
|
||||
|
||||
private static final Map<String, GameCommand> INSTANCES = new ConcurrentHashMap<>();
|
||||
private static DiscordSRVCommand COMMAND;
|
||||
private static DiscordSRVGameCommand COMMAND;
|
||||
|
||||
public static GameCommand get(DiscordSRV discordSRV, String alias) {
|
||||
if (COMMAND == null) {
|
||||
COMMAND = new DiscordSRVCommand(discordSRV);
|
||||
COMMAND = new DiscordSRVGameCommand(discordSRV);
|
||||
}
|
||||
return INSTANCES.computeIfAbsent(alias, key ->
|
||||
GameCommand.literal(alias)
|
||||
@ -47,17 +49,17 @@ public class DiscordSRVCommand implements GameCommandExecutor {
|
||||
.then(BroadcastCommand.discord(discordSRV))
|
||||
.then(BroadcastCommand.minecraft(discordSRV))
|
||||
.then(BroadcastCommand.json(discordSRV))
|
||||
.then(DebugCommand.get(discordSRV))
|
||||
.then(DebugCommand.getGame(discordSRV))
|
||||
.then(LinkCommand.get(discordSRV))
|
||||
.then(ReloadCommand.get(discordSRV))
|
||||
.then(ResyncCommand.get(discordSRV))
|
||||
.then(VersionCommand.get(discordSRV))
|
||||
.then(VersionCommand.getGame(discordSRV))
|
||||
);
|
||||
}
|
||||
|
||||
private final DiscordSRV discordSRV;
|
||||
|
||||
public DiscordSRVCommand(DiscordSRV discordSRV) {
|
||||
public DiscordSRVGameCommand(DiscordSRV discordSRV) {
|
||||
this.discordSRV = discordSRV;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.command.game.command.subcommand;
|
||||
package com.discordsrv.common.command.game.commands.subcommand;
|
||||
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.discord.entity.channel.DiscordMessageChannel;
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.command.game.command.subcommand;
|
||||
package com.discordsrv.common.command.game.commands.subcommand;
|
||||
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommand;
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.command.game.command.subcommand;
|
||||
package com.discordsrv.common.command.game.commands.subcommand;
|
||||
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommand;
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.command.game.command.subcommand.reload;
|
||||
package com.discordsrv.common.command.game.commands.subcommand.reload;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.common.DiscordSRV;
|
@ -1,4 +1,4 @@
|
||||
package com.discordsrv.common.command.game.command.subcommand.reload;
|
||||
package com.discordsrv.common.command.game.commands.subcommand.reload;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
|
@ -23,6 +23,7 @@ import com.discordsrv.api.discord.entity.channel.DiscordMessageChannel;
|
||||
import com.discordsrv.api.discord.entity.guild.DiscordGuildMember;
|
||||
import com.discordsrv.api.discord.entity.interaction.DiscordInteractionHook;
|
||||
import com.discordsrv.api.discord.entity.interaction.command.CommandType;
|
||||
import com.discordsrv.api.discord.entity.interaction.command.SubCommandGroup;
|
||||
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
|
||||
import com.discordsrv.api.discord.events.interaction.DiscordModalInteractionEvent;
|
||||
import com.discordsrv.api.discord.events.interaction.command.*;
|
||||
@ -169,7 +170,7 @@ public class DiscordAPIEventModule extends AbstractModule<DiscordSRV> {
|
||||
String name = ((GenericCommandInteractionEvent) event).getName();
|
||||
if (event instanceof MessageContextInteractionEvent) {
|
||||
com.discordsrv.api.discord.entity.interaction.command.Command command = discordSRV.discordAPI()
|
||||
.getActiveCommand(guild, CommandType.CHAT_INPUT, name).orElse(null);
|
||||
.getActiveCommand(guild, CommandType.MESSAGE, name).orElse(null);
|
||||
if (command == null) {
|
||||
return;
|
||||
}
|
||||
@ -190,7 +191,7 @@ public class DiscordAPIEventModule extends AbstractModule<DiscordSRV> {
|
||||
}
|
||||
} else if (event instanceof UserContextInteractionEvent) {
|
||||
com.discordsrv.api.discord.entity.interaction.command.Command command = discordSRV.discordAPI()
|
||||
.getActiveCommand(guild, CommandType.MESSAGE, name).orElse(null);
|
||||
.getActiveCommand(guild, CommandType.USER, name).orElse(null);
|
||||
if (command == null) {
|
||||
return;
|
||||
}
|
||||
@ -211,11 +212,35 @@ public class DiscordAPIEventModule extends AbstractModule<DiscordSRV> {
|
||||
}
|
||||
} else if (event instanceof SlashCommandInteractionEvent) {
|
||||
com.discordsrv.api.discord.entity.interaction.command.Command command = discordSRV.discordAPI()
|
||||
.getActiveCommand(guild, CommandType.USER, name).orElse(null);
|
||||
.getActiveCommand(guild, CommandType.CHAT_INPUT, name).orElse(null);
|
||||
if (command == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String subCommandGroupName = ((SlashCommandInteractionEvent) event).getSubcommandGroup();
|
||||
String subCommandName = ((SlashCommandInteractionEvent) event).getSubcommandName();
|
||||
|
||||
if (subCommandGroupName != null) {
|
||||
for (SubCommandGroup group : command.getSubCommandGroups()) {
|
||||
if (group.getName().equals(subCommandGroupName)) {
|
||||
for (com.discordsrv.api.discord.entity.interaction.command.Command subCommand : group.getCommands()) {
|
||||
if (subCommand.getName().equals(subCommandName)) {
|
||||
command = subCommand;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (subCommandName != null) {
|
||||
for (com.discordsrv.api.discord.entity.interaction.command.Command subCommand : command.getSubCommands()) {
|
||||
if (subCommandName.equals(subCommand.getName())) {
|
||||
command = subCommand;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DiscordChatInputInteractionEvent interactionEvent = new DiscordChatInputInteractionEvent(
|
||||
(SlashCommandInteractionEvent) event,
|
||||
command.getId(),
|
||||
|
@ -485,6 +485,10 @@ public class DiscordAPIImpl implements DiscordAPI {
|
||||
return Optional.ofNullable(commandRegistry.getActive(guild != null ? guild.getIdLong() : null, type, name));
|
||||
}
|
||||
|
||||
public DiscordCommandRegistry commandRegistry() {
|
||||
return commandRegistry;
|
||||
}
|
||||
|
||||
private class WebhookCacheLoader implements AsyncCacheLoader<Long, WebhookClient> {
|
||||
|
||||
@Override
|
||||
|
@ -91,9 +91,13 @@ public class DiscordCommandRegistry {
|
||||
|
||||
@Nullable
|
||||
public Command getActive(Long guildId, CommandType type, String name) {
|
||||
return registries
|
||||
Registry registry = registries
|
||||
.computeIfAbsent(guildId != null ? guildId : GLOBAL_ID, key -> Collections.emptyMap())
|
||||
.get(type).getActive(name);
|
||||
.get(type);
|
||||
if (registry == null) {
|
||||
return null;
|
||||
}
|
||||
return registry.getActive(name);
|
||||
}
|
||||
|
||||
public void registerCommandsToDiscord() {
|
||||
@ -149,7 +153,10 @@ public class DiscordCommandRegistry {
|
||||
action.addCommands(allCommands.stream().map(JDAEntity::asJDA).collect(Collectors.toList()))
|
||||
.queue(v -> {
|
||||
for (CommandType value : CommandType.values()) {
|
||||
commandsByType.get(value).putActiveCommands(commandsToRegister.get(value));
|
||||
Registry registry = commandsByType.get(value);
|
||||
if (registry != null) {
|
||||
registry.putActiveCommands(commandsToRegister.get(value));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import com.discordsrv.api.event.bus.Subscribe;
|
||||
import com.discordsrv.api.event.events.lifecycle.DiscordSRVShuttingDownEvent;
|
||||
import com.discordsrv.api.module.type.Module;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.game.command.subcommand.reload.ReloadResults;
|
||||
import com.discordsrv.common.command.game.commands.subcommand.reload.ReloadResults;
|
||||
import com.discordsrv.common.debug.DebugGenerateEvent;
|
||||
import com.discordsrv.common.debug.file.TextDebugFile;
|
||||
import com.discordsrv.common.discord.connection.jda.JDAConnectionManager;
|
||||
|
Loading…
Reference in New Issue
Block a user