Skip to content

Commit

Permalink
✨ Better args description + slash command cooldowns
Browse files Browse the repository at this point in the history
  • Loading branch information
ItsTheSky committed May 7, 2024
1 parent 6099aff commit f39ce98
Show file tree
Hide file tree
Showing 8 changed files with 283 additions and 79 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ shadowJar {
archiveName = 'DiSky ' + version + '.jar'
}

def targetJavaVersion = 8
def targetJavaVersion = 11
java {
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
sourceCompatibility = javaVersion
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package info.itsthesky.disky.elements.structures.slash;

import ch.njol.skript.lang.Trigger;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import info.itsthesky.disky.DiSky;
import info.itsthesky.disky.core.Bot;
import info.itsthesky.disky.elements.effects.SendTyping;
import info.itsthesky.disky.elements.events.interactions.SlashCommandReceiveEvent;
import info.itsthesky.disky.elements.events.interactions.SlashCompletionEvent;
import info.itsthesky.disky.elements.structures.slash.elements.OnCooldownEvent;
import info.itsthesky.disky.elements.structures.slash.models.ParsedArgument;
import info.itsthesky.disky.elements.structures.slash.models.ParsedCommand;
import info.itsthesky.disky.elements.structures.slash.models.RegisteredCommand;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.events.guild.GuildReadyEvent;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
Expand All @@ -22,6 +22,7 @@
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData;
import net.dv8tion.jda.api.requests.RestAction;
import org.jetbrains.annotations.Nullable;

import java.util.*;

Expand Down Expand Up @@ -82,8 +83,13 @@ public void registerCommand(ParsedCommand command) {
if (readyGlobal) {
runnable.run();
} else {
waitingGlobalCommands.add(runnable);
DiSky.debug("Bot " + bot.getName() + " is not ready yet, waiting for ready event to register command (now " + waitingGlobalCommands.size() + " waiting)");
if (!bot.getInstance().getStatus().equals(JDA.Status.CONNECTED)) {
waitingGlobalCommands.add(runnable);
DiSky.debug("Bot " + bot.getName() + " is not ready yet, waiting for ready event to register command (now " + waitingGlobalCommands.size() + " waiting)");
return;
}

runnable.run();
}

} else {
Expand All @@ -110,8 +116,14 @@ public void registerCommand(ParsedCommand command) {
if (readyGuilds.contains(guildId)) {
runnable.run();
} else {
waitingGuildCommands.computeIfAbsent(guildId, k -> new ArrayList<>()).add(runnable);
DiSky.debug("Guild " + guildId + " is not ready yet, waiting for ready event to register command (now " + waitingGuildCommands.get(guildId).size() + " waiting)");
final @Nullable Guild guild = bot.getInstance().getGuildById(guildId);
if (guild == null) {
waitingGuildCommands.computeIfAbsent(guildId, k -> new ArrayList<>()).add(runnable);
DiSky.debug("Guild " + guildId + " is not ready yet, waiting for ready event to register command (now " + waitingGuildCommands.get(guildId).size() + " waiting)");
return;
}

runnable.run();
}
}
}
Expand Down Expand Up @@ -173,6 +185,8 @@ public void updateCommand(ParsedCommand command,

registeredCommand.setTrigger(command.getTrigger()); // we update the trigger anyway & the args
registeredCommand.setArguments(command.getArguments());
registeredCommand.setOnCooldown(command.getOnCooldown());
registeredCommand.setCooldown(command.getCooldown());

if (!registeredCommand.shouldUpdate(command))
{
Expand Down Expand Up @@ -223,6 +237,8 @@ public void updateGlobalCommand(ParsedCommand command,

registeredCommand.setTrigger(command.getTrigger()); // we update the trigger anyway & the args
registeredCommand.setArguments(command.getArguments());
registeredCommand.setOnCooldown(command.getOnCooldown());
registeredCommand.setCooldown(command.getCooldown());

if (!registeredCommand.shouldUpdate(command))
{
Expand Down Expand Up @@ -264,9 +280,6 @@ public void shutdown() {
}





private SlashCommandData buildCommand(ParsedCommand parsedCommand) {
final SlashCommandData slashCommandData = Commands.slash(parsedCommand.getName(), parsedCommand.getDescription());

Expand Down Expand Up @@ -306,6 +319,8 @@ else if (value instanceof Number)
return slashCommandData;
}

// ---------------------------------------------------------------------------------------------

@Override
public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
if (!event.isGlobalCommand()) {
Expand All @@ -315,26 +330,46 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
return;
}

registeredCommand.prepareArguments(event.getOptions());
final Trigger trigger = registeredCommand.getTrigger();
final SlashCommandReceiveEvent.BukkitSlashCommandReceiveEvent bukkitEvent = new SlashCommandReceiveEvent.BukkitSlashCommandReceiveEvent(new SlashCommandReceiveEvent());
bukkitEvent.setJDAEvent(event);

trigger.execute(bukkitEvent);
tryExecute(registeredCommand, event);
} else {
final RegisteredCommand registeredCommand = findCommand(event.getName());
if (registeredCommand == null) {
DiSky.debug("Received command " + event.getName() + " but it's not registered on all guilds for bot " + event.getJDA().getSelfUser().getGlobalName());
return;
}

registeredCommand.prepareArguments(event.getOptions());
final Trigger trigger = registeredCommand.getTrigger();
final SlashCommandReceiveEvent.BukkitSlashCommandReceiveEvent bukkitEvent = new SlashCommandReceiveEvent.BukkitSlashCommandReceiveEvent(new SlashCommandReceiveEvent());
bukkitEvent.setJDAEvent(event);
tryExecute(registeredCommand, event);
}
}

trigger.execute(bukkitEvent);
private void tryExecute(RegisteredCommand command, SlashCommandInteractionEvent event) {

// cooldown
if (command.hasCooldown()) {
if (command.isInCooldown(event.getUser())) {
if (command.getOnCooldown() != null) {
final OnCooldownEvent.BukkitCooldownEvent bukkitEvent =
new OnCooldownEvent.BukkitCooldownEvent(new OnCooldownEvent(),
command.getCooldown(event.getUser()) - System.currentTimeMillis());
bukkitEvent.setJDAEvent(event);
command.prepareArguments(event.getOptions());
command.getOnCooldown().execute(bukkitEvent);

if (!bukkitEvent.isCancelled())
return;
}
}

command.setCooldown(event.getUser());
}

// "real" execution
command.prepareArguments(event.getOptions());
final Trigger trigger = command.getTrigger();
final SlashCommandReceiveEvent.BukkitSlashCommandReceiveEvent bukkitEvent = new SlashCommandReceiveEvent.BukkitSlashCommandReceiveEvent(new SlashCommandReceiveEvent());
bukkitEvent.setJDAEvent(event);

trigger.execute(bukkitEvent);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import ch.njol.skript.lang.Trigger;
import ch.njol.skript.lang.parser.ParserInstance;
import ch.njol.skript.lang.util.SimpleEvent;
import ch.njol.skript.util.Timespan;
import info.itsthesky.disky.DiSky;
import info.itsthesky.disky.api.events.SimpleDiSkyEvent;
import info.itsthesky.disky.api.skript.entries.MutexEntryData;
Expand All @@ -17,6 +18,7 @@
import info.itsthesky.disky.elements.events.bots.ReadyEvent;
import info.itsthesky.disky.elements.events.interactions.SlashCommandReceiveEvent;
import info.itsthesky.disky.elements.events.interactions.SlashCompletionEvent;
import info.itsthesky.disky.elements.structures.slash.elements.OnCooldownEvent;
import info.itsthesky.disky.elements.structures.slash.models.ParsedArgument;
import info.itsthesky.disky.elements.structures.slash.models.ParsedCommand;
import net.dv8tion.jda.api.Permission;
Expand All @@ -27,6 +29,7 @@
import org.jetbrains.annotations.Nullable;
import org.skriptlang.skript.lang.entry.EntryContainer;
import org.skriptlang.skript.lang.entry.EntryValidator;
import org.skriptlang.skript.lang.entry.KeyValueEntryData;
import org.skriptlang.skript.lang.structure.Structure;

import java.util.*;
Expand Down Expand Up @@ -59,6 +62,14 @@ public class StructSlashCommand extends Structure {
.addSection("arguments", true)
.addSection("name", true)

.addEntryData(new KeyValueEntryData<Timespan>("cooldown", null, true) {
@Override
protected @Nullable Timespan getValue(@NotNull String value) {
return Timespan.parse(value);
}
})
.addSection("on cooldown", true)

.addSection("trigger", false)

.build();
Expand Down Expand Up @@ -137,6 +148,12 @@ public boolean load() {
if (!trigger)
return false;


// Cooldown
final boolean cooldown = parseCooldown(parsedCommand);
if (!cooldown)
return false;

//region Debug
DiSky.debug("------------------- Name -------------------");
DiSky.debug("Default: " + parsedCommand.getName());
Expand Down Expand Up @@ -181,6 +198,19 @@ public boolean load() {
else
DiSky.debug("No trigger found.");

DiSky.debug("------------------- Cooldown -------------------");
if (parsedCommand.hasCooldown()) {
DiSky.debug("Cooldown: " + parsedCommand.getCooldown() + "ms (" + parsedCommand.getCooldown() / 1000 + "s)");
if (parsedCommand.getOnCooldown() != null) {
DiSky.debug(" - On Cooldown trigger found.");
DiSky.debug(" - Label: " + parsedCommand.getOnCooldown().getDebugLabel());
}
else
DiSky.debug(" - No on cooldown trigger found.");
}
else
DiSky.debug("No cooldown found.");

DiSky.debug("------------------- End -------------------");
//endregion

Expand Down Expand Up @@ -260,69 +290,70 @@ private List<ParsedArgument> parseArguments() {
if (argNode == null)
continue;

if (!(argNode instanceof SectionNode)) {
Skript.error("Invalid argument node (Not a section! Check the wiki for information's): " + argNode);
return null;
}

final SectionNode argSection = (SectionNode) argNode;
final EntryContainer container = ARGUMENT_VALIDATOR.validate(argSection);
if (container == null)
return null;

final String description = container.get("description", String.class, true);

// Choices, if applicable
final SectionNode choiceNode = container.getOptional("choices", SectionNode.class, true);
if (choiceNode != null) {
final OptionType type = argument.getType();
if (!type.canSupportChoices()) {
Skript.error("Choices are not supported for the argument type: " + type);
if (argNode instanceof SectionNode) {
final SectionNode argSection = (SectionNode) argNode;
final EntryContainer container = ARGUMENT_VALIDATOR.validate(argSection);
if (container == null)
return null;
}

choiceNode.convertToEntries(0);
for (Node choice : choiceNode) {
final String name = choice.getKey();
final String value = choiceNode.get(name, "");
if (value.isEmpty()) {
Skript.error("Empty value for choice: " + name);
final String description = container.get("description", String.class, true);

// Choices, if applicable
final SectionNode choiceNode = container.getOptional("choices", SectionNode.class, true);
if (choiceNode != null) {
final OptionType type = argument.getType();
if (!type.canSupportChoices()) {
Skript.error("Choices are not supported for the argument type: " + type);
return null;
}

final Object arg;
if (type.equals(OptionType.NUMBER) || type.equals(OptionType.INTEGER)) {
try {
arg = Integer.parseInt(value);
} catch (NumberFormatException ex) {
Skript.error("Invalid number value for choice: " + name);
choiceNode.convertToEntries(0);
for (Node choice : choiceNode) {
final String name = choice.getKey();
final String value = choiceNode.get(name, "");
if (value.isEmpty()) {
Skript.error("Empty value for choice: " + name);
return null;
}
} else if (type.equals(OptionType.STRING)) {
arg = value;
} else {
Skript.error("Invalid choice type: " + type);
return null;

final Object arg;
if (type.equals(OptionType.NUMBER) || type.equals(OptionType.INTEGER)) {
try {
arg = Integer.parseInt(value);
} catch (NumberFormatException ex) {
Skript.error("Invalid number value for choice: " + name);
return null;
}
} else if (type.equals(OptionType.STRING)) {
arg = value;
} else {
Skript.error("Invalid choice type: " + type);
return null;
}

argument.addChoice(name, arg);
}
}

argument.addChoice(name, arg);
// auto completion
final SectionNode completionNode = container.getOptional("on completion request", SectionNode.class, true);
if (completionNode != null) {
final Trigger trigger = new Trigger(getParser().getCurrentScript(), "completion for argument " + argument.getName(), new SimpleEvent(),
SkriptUtils.loadCode(completionNode, SlashCompletionEvent.BukkitSlashCompletionEvent.class));
argument.setOnCompletionRequest(trigger);
}
}

// auto completion
final SectionNode completionNode = container.getOptional("on completion request", SectionNode.class, true);
if (completionNode != null) {
final Trigger trigger = new Trigger(getParser().getCurrentScript(), "completion for argument " + argument.getName(), new SimpleEvent(),
SkriptUtils.loadCode(completionNode, SlashCompletionEvent.BukkitSlashCompletionEvent.class));
argument.setOnCompletionRequest(trigger);
}
if (argument.hasChoices() && argument.isAutoCompletion()) {
Skript.error("You can't have both auto completion and choices for the same argument.");
return null;
}

if (argument.hasChoices() && argument.isAutoCompletion()) {
Skript.error("You can't have both auto completion and choices for the same argument.");
return null;
argument.setDescription(description);
} else {
final String description = node.getValue(argument.getName());
argument.setDescription(description);
}

argument.setDescription(description);
}

return arguments;
Expand Down Expand Up @@ -472,6 +503,29 @@ public boolean parseTrigger(ParsedCommand parsedCommand) {

//endregion

//region Cooldown

public boolean parseCooldown(ParsedCommand parsedCommand) {
final Timespan cooldown = entryContainer.getOptional("cooldown", Timespan.class, true);
if (cooldown == null)
return true;

final SectionNode sectionNode = entryContainer.getOptional("on cooldown", SectionNode.class, true);
if (sectionNode == null) {
Skript.error("You must specify a section for the cooldown. ('on cooldown' section, to be ran when the command is on cooldown)");
return false;
}


final Trigger trigger = new Trigger(getParser().getCurrentScript(), "on cooldown for " + parsedCommand.getName(),
new OnCooldownEvent(),
SkriptUtils.loadCode(sectionNode, OnCooldownEvent.BukkitCooldownEvent.class));

parsedCommand.setCooldown(cooldown.getMilliSeconds());
parsedCommand.setOnCooldown(trigger);
return true;
}

@Override
public @NotNull Priority getPriority() {
return PRIORITY;
Expand Down
Loading

0 comments on commit f39ce98

Please sign in to comment.