diff --git a/DisCatSharp.ApplicationCommands/ApplicationCommandsExtension.cs b/DisCatSharp.ApplicationCommands/ApplicationCommandsExtension.cs
index 7405e924a7..c55d67a486 100644
--- a/DisCatSharp.ApplicationCommands/ApplicationCommandsExtension.cs
+++ b/DisCatSharp.ApplicationCommands/ApplicationCommandsExtension.cs
@@ -18,6 +18,7 @@
using DisCatSharp.Common.Utilities;
using DisCatSharp.Entities;
using DisCatSharp.Enums;
+using DisCatSharp.Enums.Core;
using DisCatSharp.EventArgs;
using DisCatSharp.Exceptions;
@@ -85,16 +86,6 @@ public sealed class ApplicationCommandsExtension : BaseExtension
///
private static bool s_errored { get; set; }
- ///
- /// Gets the cooldown buckets for slash commands.
- ///
- public static ConcurrentDictionary SlashCommandBuckets { get; } = [];
-
- ///
- /// Gets the cooldown buckets for context menu commands.
- ///
- public static ConcurrentDictionary ContextMenuCommandBuckets { get; } = [];
-
///
/// Gets a list of registered commands. The key is the guild id (null if global).
///
@@ -1091,7 +1082,11 @@ private Task InteractionHandler(DiscordClient client, InteractionCreateEventArgs
GuildLocale = e.Interaction.GuildLocale,
AppPermissions = e.Interaction.AppPermissions,
Entitlements = e.Interaction.Entitlements,
- EntitlementSkuIds = e.Interaction.EntitlementSkuIds
+ EntitlementSkuIds = e.Interaction.EntitlementSkuIds,
+ UserId = e.Interaction.User.Id,
+ GuildId = e.Interaction.GuildId,
+ MemberId = e.Interaction.GuildId is not null ? e.Interaction.User.Id : null,
+ ChannelId = e.Interaction.ChannelId
};
try
@@ -1118,6 +1113,7 @@ private Task InteractionHandler(DiscordClient client, InteractionCreateEventArgs
var method = methods.First().Method;
context.SubCommandName = null;
context.SubSubCommandName = null;
+ context.CommandGroupingType = DisCatSharpCommandGroupingType.Command;
if (DebugEnabled)
this.Client.Logger.LogDebug("Executing {cmd}", method.Name);
var args = await this.ResolveInteractionCommandParameters(e, context, method, e.Interaction.Data.Options).ConfigureAwait(false);
@@ -1131,6 +1127,7 @@ private Task InteractionHandler(DiscordClient client, InteractionCreateEventArgs
var method = groups.First().Methods.First(x => x.Key == command.Name).Value;
context.SubCommandName = command.Name;
context.SubSubCommandName = null;
+ context.CommandGroupingType = DisCatSharpCommandGroupingType.SubCommand;
if (DebugEnabled)
this.Client.Logger.LogDebug("Executing {cmd}", method.Name);
var args = await this.ResolveInteractionCommandParameters(e, context, method, e.Interaction.Data.Options[0].Options).ConfigureAwait(false);
@@ -1146,6 +1143,7 @@ private Task InteractionHandler(DiscordClient client, InteractionCreateEventArgs
var method = group.Methods.First(x => x.Key == command.Options[0].Name).Value;
context.SubCommandName = command.Name;
context.SubSubCommandName = command.Options[0].Name;
+ context.CommandGroupingType = DisCatSharpCommandGroupingType.SubGroupCommand;
if (DebugEnabled)
this.Client.Logger.LogDebug("Executing {cmd}", method.Name);
@@ -1350,7 +1348,12 @@ private Task ContextMenuHandler(DiscordClient client, ContextMenuInteractionCrea
_ = Task.Run(async () =>
{
//Creates the context
- var context = new ContextMenuContext
+ var context = new ContextMenuContext(e.Type switch
+ {
+ ApplicationCommandType.User => DisCatSharpCommandType.UserCommand,
+ ApplicationCommandType.Message => DisCatSharpCommandType.MessageCommand,
+ _ => throw new ArgumentOutOfRangeException(nameof(e.Type), "Unknown context menu type")
+ })
{
Interaction = e.Interaction,
Channel = e.Interaction.Channel,
@@ -1369,7 +1372,12 @@ private Task ContextMenuHandler(DiscordClient client, ContextMenuInteractionCrea
GuildLocale = e.Interaction.GuildLocale,
AppPermissions = e.Interaction.AppPermissions,
Entitlements = e.Interaction.Entitlements,
- EntitlementSkuIds = e.Interaction.EntitlementSkuIds
+ EntitlementSkuIds = e.Interaction.EntitlementSkuIds,
+ CommandGroupingType = DisCatSharpCommandGroupingType.Command,
+ UserId = e.Interaction.User.Id,
+ GuildId = e.Interaction.GuildId,
+ MemberId = e.Interaction.GuildId is not null ? e.Interaction.User.Id : null,
+ ChannelId = e.Interaction.ChannelId
};
try
diff --git a/DisCatSharp.ApplicationCommands/Attributes/ContextMenu/ContextMenuCooldownAttribute.cs b/DisCatSharp.ApplicationCommands/Attributes/ContextMenu/ContextMenuCooldownAttribute.cs
index b52a4676e8..9ba4b58b42 100644
--- a/DisCatSharp.ApplicationCommands/Attributes/ContextMenu/ContextMenuCooldownAttribute.cs
+++ b/DisCatSharp.ApplicationCommands/Attributes/ContextMenu/ContextMenuCooldownAttribute.cs
@@ -1,11 +1,12 @@
using System;
-using System.Collections.Concurrent;
-using System.ComponentModel.Design;
+using System.Globalization;
using System.Threading.Tasks;
using DisCatSharp.ApplicationCommands.Context;
-using DisCatSharp.ApplicationCommands.Entities;
-using DisCatSharp.ApplicationCommands.Enums;
+using DisCatSharp.Entities;
+using DisCatSharp.Entities.Core;
+using DisCatSharp.Enums;
+using DisCatSharp.Enums.Core;
namespace DisCatSharp.ApplicationCommands.Attributes;
@@ -13,7 +14,7 @@ namespace DisCatSharp.ApplicationCommands.Attributes;
/// Defines a cooldown for this command. This allows you to define how many times can users execute a specific command
///
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
-public sealed class ContextMenuCooldownAttribute : ApplicationCommandCheckBaseAttribute, ICooldown
+public sealed class ContextMenuCooldownAttribute : ApplicationCommandCheckBaseAttribute, ICooldown
{
///
/// Gets the maximum number of uses before this command triggers a cooldown for its bucket.
@@ -48,10 +49,10 @@ public ContextMenuCooldownAttribute(int maxUses, double resetAfter, CooldownBuck
///
/// Command context to get cooldown bucket for.
/// Requested cooldown bucket, or null if one wasn't present.
- public ContextMenuCooldownBucket GetBucket(BaseContext ctx)
+ public CooldownBucket GetBucket(BaseContext ctx)
{
var bid = this.GetBucketId(ctx, out _, out _, out _, out _);
- ApplicationCommandsExtension.ContextMenuCommandBuckets.TryGetValue(bid, out var bucket);
+ ctx.Client.CommandCooldownBuckets.TryGetValue(bid, out var bucket);
return bucket!;
}
@@ -97,7 +98,7 @@ private string GetBucketId(BaseContext ctx, out ulong userId, out ulong channelI
if (ctx.Guild is not null && ctx.Member is not null && (this.BucketType & CooldownBucketType.Member) != 0)
memberId = ctx.Member.Id;
- var bid = CooldownBucket.MakeId(ctx.Interaction.Data.Id, ctx.FullCommandName, userId, channelId, guildId, memberId);
+ var bid = CooldownBucket.MakeId(ctx.FullCommandName, ctx.Interaction.Data.Id.ToString(CultureInfo.InvariantCulture), userId, channelId, guildId, memberId);
return bid;
}
@@ -108,40 +109,26 @@ private string GetBucketId(BaseContext ctx, out ulong userId, out ulong channelI
public override async Task ExecuteChecksAsync(BaseContext ctx)
{
var bid = this.GetBucketId(ctx, out var usr, out var chn, out var gld, out var mem);
- if (ApplicationCommandsExtension.ContextMenuCommandBuckets.TryGetValue(bid, out var bucket))
- return await bucket.DecrementUseAsync(ctx).ConfigureAwait(false);
+ if (ctx.Client.CommandCooldownBuckets.TryGetValue(bid, out var bucket))
+ return await this.RespondRatelimitHitAsync(ctx, await bucket.DecrementUseAsync(ctx), bucket);
- bucket = new(this.MaxUses, this.Reset, ctx.Interaction.Data.Id, ctx.FullCommandName, usr, chn, gld, mem);
- ApplicationCommandsExtension.ContextMenuCommandBuckets.AddOrUpdate(bid, bucket, (k, v) => bucket);
+ bucket = new(this.MaxUses, this.Reset, ctx.FullCommandName, ctx.Interaction.Data.Id.ToString(CultureInfo.InvariantCulture), usr, chn, gld, mem);
+ ctx.Client.CommandCooldownBuckets.AddOrUpdate(bid, bucket, (k, v) => bucket);
- return await bucket.DecrementUseAsync(ctx).ConfigureAwait(false);
+ return await this.RespondRatelimitHitAsync(ctx, await bucket.DecrementUseAsync(ctx), bucket);
}
-}
-///
-/// Represents a cooldown bucket for context menu commands.
-///
-public sealed class ContextMenuCooldownBucket : CooldownBucket
-{
- ///
- /// Creates a new context menu command cooldown bucket.
- ///
- /// Maximum number of uses for this bucket.
- /// Time after which this bucket resets.
- /// ID of the command
- /// Name of the command.
- /// ID of the user with which this cooldown is associated.
- /// ID of the channel with which this cooldown is associated.
- /// ID of the guild with which this cooldown is associated.
- /// ID of the member with which this cooldown is associated.
- internal ContextMenuCooldownBucket(int maxUses, TimeSpan resetAfter, ulong commandId, string commandName, ulong userId = 0, ulong channelId = 0, ulong guildId = 0, ulong memberId = 0)
- : base(maxUses, resetAfter, commandId, commandName, userId, channelId, guildId, memberId)
- { }
+ ///
+ public async Task RespondRatelimitHitAsync(BaseContext ctx, bool noHit, CooldownBucket bucket)
+ {
+ if (noHit)
+ return true;
- ///
- /// Returns a string representation of this command cooldown bucket.
- ///
- /// String representation of this command cooldown bucket.
- public override string ToString()
- => $"Context Menu Command bucket {this.BucketId}";
+ if (ApplicationCommandsExtension.Configuration.AutoDefer)
+ await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent($"Error: Ratelimit hit\nTry again in {bucket.ResetsAt.Timestamp()}"));
+ else
+ await ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().WithContent($"Error: Ratelimit hit\nTry again in {bucket.ResetsAt.Timestamp()}").AsEphemeral());
+
+ return false;
+ }
}
diff --git a/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/SlashCommandCooldownAttribute.cs b/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/SlashCommandCooldownAttribute.cs
index 929f08db3c..b6762e1434 100644
--- a/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/SlashCommandCooldownAttribute.cs
+++ b/DisCatSharp.ApplicationCommands/Attributes/SlashCommand/SlashCommandCooldownAttribute.cs
@@ -1,10 +1,12 @@
using System;
-using System.Collections.Concurrent;
+using System.Globalization;
using System.Threading.Tasks;
using DisCatSharp.ApplicationCommands.Context;
-using DisCatSharp.ApplicationCommands.Entities;
-using DisCatSharp.ApplicationCommands.Enums;
+using DisCatSharp.Entities;
+using DisCatSharp.Entities.Core;
+using DisCatSharp.Enums;
+using DisCatSharp.Enums.Core;
namespace DisCatSharp.ApplicationCommands.Attributes;
@@ -12,7 +14,7 @@ namespace DisCatSharp.ApplicationCommands.Attributes;
/// Defines a cooldown for this command. This allows you to define how many times can users execute a specific command.
///
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
-public sealed class SlashCommandCooldownAttribute : ApplicationCommandCheckBaseAttribute, ICooldown
+public sealed class SlashCommandCooldownAttribute : ApplicationCommandCheckBaseAttribute, ICooldown
{
///
/// Gets the maximum number of uses before this command triggers a cooldown for its bucket.
@@ -47,10 +49,10 @@ public SlashCommandCooldownAttribute(int maxUses, double resetAfter, CooldownBuc
///
/// Command context to get cooldown bucket for.
/// Requested cooldown bucket, or null if one wasn't present.
- public SlashCommandCooldownBucket GetBucket(BaseContext ctx)
+ public CooldownBucket GetBucket(BaseContext ctx)
{
var bid = this.GetBucketId(ctx, out _, out _, out _, out _);
- ApplicationCommandsExtension.SlashCommandBuckets.TryGetValue(bid, out var bucket);
+ ctx.Client.CommandCooldownBuckets.TryGetValue(bid, out var bucket);
return bucket!;
}
@@ -96,7 +98,7 @@ private string GetBucketId(BaseContext ctx, out ulong userId, out ulong channelI
if (ctx.Guild is not null && ctx.Member is not null && this.BucketType.HasFlag(CooldownBucketType.Member))
memberId = ctx.Member.Id;
- var bid = CooldownBucket.MakeId(ctx.Interaction.Data.Id, ctx.FullCommandName, userId, channelId, guildId, memberId);
+ var bid = CooldownBucket.MakeId(ctx.FullCommandName, ctx.Interaction.Data.Id.ToString(CultureInfo.InvariantCulture), userId, channelId, guildId, memberId);
return bid;
}
@@ -107,40 +109,26 @@ private string GetBucketId(BaseContext ctx, out ulong userId, out ulong channelI
public override async Task ExecuteChecksAsync(BaseContext ctx)
{
var bid = this.GetBucketId(ctx, out var usr, out var chn, out var gld, out var mem);
- if (ApplicationCommandsExtension.SlashCommandBuckets.TryGetValue(bid, out var bucket))
- return await bucket.DecrementUseAsync(ctx).ConfigureAwait(false);
+ if (ctx.Client.CommandCooldownBuckets.TryGetValue(bid, out var bucket))
+ return await this.RespondRatelimitHitAsync(ctx, await bucket.DecrementUseAsync(ctx), bucket);
- bucket = new(this.MaxUses, this.Reset, ctx.Interaction.Data.Id, ctx.FullCommandName, usr, chn, gld, mem);
- ApplicationCommandsExtension.SlashCommandBuckets.AddOrUpdate(bid, bucket, (k, v) => bucket);
+ bucket = new(this.MaxUses, this.Reset, ctx.FullCommandName, ctx.Interaction.Data.Id.ToString(CultureInfo.InvariantCulture), usr, chn, gld, mem);
+ ctx.Client.CommandCooldownBuckets.AddOrUpdate(bid, bucket, (k, v) => bucket);
- return await bucket.DecrementUseAsync(ctx).ConfigureAwait(false);
+ return await this.RespondRatelimitHitAsync(ctx, await bucket.DecrementUseAsync(ctx), bucket);
}
-}
-///
-/// Represents a cooldown bucket for slash commands.
-///
-public sealed class SlashCommandCooldownBucket : CooldownBucket
-{
- ///
- /// Creates a new slash command cooldown bucket.
- ///
- /// Maximum number of uses for this bucket.
- /// Time after which this bucket resets.
- /// ID of the command
- /// Name of the command.
- /// ID of the user with which this cooldown is associated.
- /// ID of the channel with which this cooldown is associated.
- /// ID of the guild with which this cooldown is associated.
- /// ID of the member with which this cooldown is associated.
- internal SlashCommandCooldownBucket(int maxUses, TimeSpan resetAfter, ulong commandId, string commandName, ulong userId = 0, ulong channelId = 0, ulong guildId = 0, ulong memberId = 0)
- : base(maxUses, resetAfter, commandId, commandName, userId, channelId, guildId, memberId)
- { }
+ ///
+ public async Task RespondRatelimitHitAsync(BaseContext ctx, bool noHit, CooldownBucket bucket)
+ {
+ if (noHit)
+ return true;
- ///
- /// Returns a string representation of this command cooldown bucket.
- ///
- /// String representation of this command cooldown bucket.
- public override string ToString()
- => $"Slash Command bucket {this.BucketId}";
+ if (ApplicationCommandsExtension.Configuration.AutoDefer)
+ await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent($"Error: Ratelimit hit\nTry again in {bucket.ResetsAt.Timestamp()}"));
+ else
+ await ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().WithContent($"Error: Ratelimit hit\nTry again in {bucket.ResetsAt.Timestamp()}").AsEphemeral());
+
+ return false;
+ }
}
diff --git a/DisCatSharp.ApplicationCommands/Context/BaseContext.cs b/DisCatSharp.ApplicationCommands/Context/BaseContext.cs
index cf173a171a..1c60ddd27e 100644
--- a/DisCatSharp.ApplicationCommands/Context/BaseContext.cs
+++ b/DisCatSharp.ApplicationCommands/Context/BaseContext.cs
@@ -4,7 +4,9 @@
using DisCatSharp.Attributes;
using DisCatSharp.Entities;
+using DisCatSharp.Entities.Core;
using DisCatSharp.Enums;
+using DisCatSharp.Enums.Core;
using Microsoft.Extensions.DependencyInjection;
@@ -13,18 +15,13 @@ namespace DisCatSharp.ApplicationCommands.Context;
///
/// Represents a base context for application command contexts.
///
-public class BaseContext
+public class BaseContext : DisCatSharpCommandContext
{
///
/// Gets the interaction that was created.
///
public DiscordInteraction Interaction { get; internal init; }
- ///
- /// Gets the client for this interaction.
- ///
- public DiscordClient Client { get; internal init; }
-
///
/// Gets the guild this interaction was executed in.
///
@@ -61,25 +58,10 @@ public DiscordMember? Member
///
public ulong InteractionId { get; internal set; }
- ///
- /// Gets the name of the command.
- ///
- public string CommandName { get; internal init; }
-
- ///
- /// Gets the name of the sub command.
- ///
- public string? SubCommandName { get; internal set; }
-
- ///
- /// Gets the name of the sub command.
- ///
- public string? SubSubCommandName { get; internal set; }
-
///
/// Gets the full command string, including the subcommand.
///
- public string FullCommandName
+ public override string FullCommandName
=> $"{this.CommandName}{(string.IsNullOrWhiteSpace(this.SubCommandName) ? "" : $" {this.SubCommandName}")}{(string.IsNullOrWhiteSpace(this.SubSubCommandName) ? "" : $" {this.SubSubCommandName}")}";
///
@@ -125,6 +107,15 @@ public string FullCommandName
///
public IServiceProvider Services { get; internal set; } = new ServiceCollection().BuildServiceProvider(true);
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The command type.
+ /// The command grouping type.
+ internal BaseContext(DisCatSharpCommandType type, DisCatSharpCommandGroupingType groupingType = DisCatSharpCommandGroupingType.Command)
+ : base(type, groupingType)
+ { }
+
///
/// Creates a response to this interaction.
/// You must create a response within 3 seconds of this interaction being executed; if the command has the potential to take more than 3 seconds, create a at the start, and edit the response later.
diff --git a/DisCatSharp.ApplicationCommands/Context/ContextMenuContext.cs b/DisCatSharp.ApplicationCommands/Context/ContextMenuContext.cs
index 7b03989840..fb405d7294 100644
--- a/DisCatSharp.ApplicationCommands/Context/ContextMenuContext.cs
+++ b/DisCatSharp.ApplicationCommands/Context/ContextMenuContext.cs
@@ -1,11 +1,12 @@
using DisCatSharp.Entities;
+using DisCatSharp.Enums.Core;
namespace DisCatSharp.ApplicationCommands.Context;
///
/// Represents a context for a context menu.
///
-public sealed class ContextMenuContext : BaseContext
+public sealed class ContextMenuContext(DisCatSharpCommandType type) : BaseContext(type)
{
///
/// The user this command targets, if applicable.
@@ -15,7 +16,7 @@ public sealed class ContextMenuContext : BaseContext
///
/// The member this command targets, if applicable.
///
- public DiscordMember TargetMember
+ public DiscordMember? TargetMember
=> this.TargetUser is DiscordMember member ? member : null;
///
diff --git a/DisCatSharp.ApplicationCommands/Context/InteractionContext.cs b/DisCatSharp.ApplicationCommands/Context/InteractionContext.cs
index 1000b43014..c425cb79e6 100644
--- a/DisCatSharp.ApplicationCommands/Context/InteractionContext.cs
+++ b/DisCatSharp.ApplicationCommands/Context/InteractionContext.cs
@@ -1,13 +1,14 @@
using System.Collections.Generic;
using DisCatSharp.Entities;
+using DisCatSharp.Enums.Core;
namespace DisCatSharp.ApplicationCommands.Context;
///
/// Represents a context for an interaction.
///
-public sealed class InteractionContext : BaseContext
+public sealed class InteractionContext() : BaseContext(DisCatSharpCommandType.SlashCommand)
{
///
/// Gets the users mentioned in the command parameters.
diff --git a/DisCatSharp.CommandsNext/Attributes/CooldownAttribute.cs b/DisCatSharp.CommandsNext/Attributes/CooldownAttribute.cs
index a6745c1928..ddb6c4d21d 100644
--- a/DisCatSharp.CommandsNext/Attributes/CooldownAttribute.cs
+++ b/DisCatSharp.CommandsNext/Attributes/CooldownAttribute.cs
@@ -1,16 +1,17 @@
using System;
-using System.Collections.Concurrent;
-using System.Globalization;
-using System.Threading;
using System.Threading.Tasks;
+using DisCatSharp.Entities;
+using DisCatSharp.Entities.Core;
+using DisCatSharp.Enums.Core;
+
namespace DisCatSharp.CommandsNext.Attributes;
///
/// Defines a cooldown for this command. This allows you to define how many times can users execute a specific command
///
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
-public sealed class CooldownAttribute : CheckBaseAttribute
+public sealed class CooldownAttribute : CheckBaseAttribute, ICooldown
{
///
/// Gets the maximum number of uses before this command triggers a cooldown for its bucket.
@@ -45,10 +46,10 @@ public CooldownAttribute(int maxUses, double resetAfter, CooldownBucketType buck
///
/// Command context to get cooldown bucket for.
/// Requested cooldown bucket, or null if one wasn't present.
- public CommandCooldownBucket GetBucket(CommandContext ctx)
+ public CooldownBucket GetBucket(CommandContext ctx)
{
var bid = this.GetBucketId(ctx, out _, out _, out _);
- CommandsNextExtension.CommandCooldownBuckets.TryGetValue(bid, out var bucket);
+ ctx.Client.CommandCooldownBuckets.TryGetValue(bid, out var bucket);
return bucket!;
}
@@ -91,7 +92,7 @@ private string GetBucketId(CommandContext ctx, out ulong userId, out ulong chann
if (ctx.Guild is not null && this.BucketType.HasFlag(CooldownBucketType.Guild))
guildId = ctx.Guild.Id;
- var bid = CommandCooldownBucket.MakeId(ctx.Command.QualifiedName, userId, channelId, guildId);
+ var bid = CooldownBucket.MakeId(ctx.Command.QualifiedName, "text", userId, channelId, guildId);
return bid;
}
@@ -106,213 +107,23 @@ public override async Task ExecuteCheckAsync(CommandContext ctx, bool help
return true;
var bid = this.GetBucketId(ctx, out var usr, out var chn, out var gld);
- if (CommandsNextExtension.CommandCooldownBuckets.TryGetValue(bid, out var bucket))
- return await bucket.DecrementUseAsync().ConfigureAwait(false);
-
- bucket = new(this.MaxUses, this.Reset, ctx.Command.QualifiedName, usr, chn, gld);
- CommandsNextExtension.CommandCooldownBuckets.AddOrUpdate(bid, bucket, (k, v) => bucket);
-
- return await bucket.DecrementUseAsync().ConfigureAwait(false);
- }
-}
-
-///
-/// Defines how are command cooldowns applied.
-///
-[Flags]
-public enum CooldownBucketType
-{
- ///
- /// Denotes that the command will have its cooldown applied per-user.
- ///
- User = 1,
-
- ///
- /// Denotes that the command will have its cooldown applied per-channel.
- ///
- Channel = 2,
-
- ///
- /// Denotes that the command will have its cooldown applied per-guild. In DMs, this applies the cooldown per-channel.
- ///
- Guild = 4,
-
- ///
- /// Denotes that the command will have its cooldown applied globally.
- ///
- Global = 0
-}
-
-///
-/// Represents a cooldown bucket for commands.
-///
-public sealed class CommandCooldownBucket : IEquatable
-{
- ///
- /// Gets the ID of the user with whom this cooldown is associated.
- ///
- public ulong UserId { get; }
-
- ///
- /// Gets the ID of the channel with which this cooldown is associated.
- ///
- public ulong ChannelId { get; }
-
- ///
- /// Gets the ID of the guild with which this cooldown is associated.
- ///
- public ulong GuildId { get; }
-
- ///
- /// Gets the ID of the bucket. This is used to distinguish between cooldown buckets.
- ///
- public string BucketId { get; }
-
- ///
- /// Gets the remaining number of uses before the cooldown is triggered.
- ///
- public int RemainingUses
- => Volatile.Read(ref this._remainingUses);
-
- ///
- /// Gets the remaining number of uses before the cooldown is triggered.
- ///
- private int _remainingUses;
-
- ///
- /// Gets the maximum number of times this command can be used in given timespan.
- ///
- public int MaxUses { get; }
-
- ///
- /// Gets the date and time at which the cooldown resets.
- ///
- public DateTimeOffset ResetsAt { get; internal set; }
+ if (ctx.Client.CommandCooldownBuckets.TryGetValue(bid, out var bucket))
+ return await bucket.DecrementUseAsync(ctx).ConfigureAwait(false);
- ///
- /// Gets the time after which this cooldown resets.
- ///
- public TimeSpan Reset { get; internal set; }
-
- ///
- /// Gets the semaphore used to lock the use value.
- ///
- private readonly SemaphoreSlim _usageSemaphore;
+ bucket = new(this.MaxUses, this.Reset, ctx.Command.QualifiedName, "text", usr, chn, gld);
+ ctx.Client.CommandCooldownBuckets.AddOrUpdate(bid, bucket, (k, v) => bucket);
- ///
- /// Creates a new command cooldown bucket.
- ///
- /// Name of the command.
- /// Maximum number of uses for this bucket.
- /// Time after which this bucket resets.
- /// ID of the user with which this cooldown is associated.
- /// ID of the channel with which this cooldown is associated.
- /// ID of the guild with which this cooldown is associated.
- internal CommandCooldownBucket(int maxUses, TimeSpan resetAfter, string commandName, ulong userId = 0, ulong channelId = 0, ulong guildId = 0)
- {
- this._remainingUses = maxUses;
- this.MaxUses = maxUses;
- this.ResetsAt = DateTimeOffset.UtcNow + resetAfter;
- this.Reset = resetAfter;
- this.UserId = userId;
- this.ChannelId = channelId;
- this.GuildId = guildId;
- this.BucketId = MakeId(commandName, userId, channelId, guildId);
- this._usageSemaphore = new(1, 1);
+ return await bucket.DecrementUseAsync(ctx).ConfigureAwait(false);
}
- ///
- /// Decrements the remaining use counter.
- ///
- /// Whether decrement succeeded or not.
- internal async Task DecrementUseAsync()
+ ///
+ public async Task RespondRatelimitHitAsync(CommandContext ctx, bool noHit, CooldownBucket bucket)
{
- await this._usageSemaphore.WaitAsync().ConfigureAwait(false);
-
- // if we're past reset time...
- var now = DateTimeOffset.UtcNow;
- if (now >= this.ResetsAt)
- {
- // ...do the reset and set a new reset time
- Interlocked.Exchange(ref this._remainingUses, this.MaxUses);
- this.ResetsAt = now + this.Reset;
- }
-
- // check if we have any uses left, if we do...
- var success = false;
- if (this.RemainingUses > 0)
- {
- // ...decrement, and return success...
- Interlocked.Decrement(ref this._remainingUses);
- success = true;
- }
-
- // ...otherwise just fail
- this._usageSemaphore.Release();
- return success;
- }
-
- ///
- /// Returns a string representation of this command cooldown bucket.
- ///
- /// String representation of this command cooldown bucket.
- public override string ToString()
- => $"Command bucket {this.BucketId}";
-
- ///
- /// Checks whether this is equal to another object.
- ///
- /// Object to compare to.
- /// Whether the object is equal to this .
- public override bool Equals(object? obj)
- => this.Equals(obj as CommandCooldownBucket);
-
- ///
- /// Checks whether this is equal to another .
- ///
- /// to compare to.
- /// Whether the is equal to this .
- public bool Equals(CommandCooldownBucket? other)
- => other is not null && (ReferenceEquals(this, other) || (this.UserId == other.UserId && this.ChannelId == other.ChannelId && this.GuildId == other.GuildId));
-
- ///
- /// Gets the hash code for this .
- ///
- /// The hash code for this .
- public override int GetHashCode()
- => HashCode.Combine(this.UserId, this.ChannelId, this.GuildId);
+ if (noHit)
+ return true;
- ///
- /// Gets whether the two objects are equal.
- ///
- /// First bucket to compare.
- /// Second bucket to compare.
- /// Whether the two buckets are equal.
- public static bool operator ==(CommandCooldownBucket? bucket1, CommandCooldownBucket? bucket2)
- {
- var null1 = bucket1 is null;
- var null2 = bucket2 is null;
+ await ctx.Message.CreateReactionAsync(DiscordEmoji.FromName(ctx.Client, ":x:", false));
- return (null1 && null2) || (null1 == null2 && null1.Equals(null2));
+ return false;
}
-
- ///
- /// Gets whether the two objects are not equal.
- ///
- /// First bucket to compare.
- /// Second bucket to compare.
- /// Whether the two buckets are not equal.
- public static bool operator !=(CommandCooldownBucket? bucket1, CommandCooldownBucket? bucket2)
- => !(bucket1 == bucket2);
-
- ///
- /// Creates a bucket ID from given bucket parameters.
- ///
- /// Name of the command.
- /// ID of the user with which this cooldown is associated.
- /// ID of the channel with which this cooldown is associated.
- /// ID of the guild with which this cooldown is associated.
- /// Generated bucket ID.
- public static string MakeId(string commandName, ulong userId = 0, ulong channelId = 0, ulong guildId = 0)
- => $"{commandName}::{userId.ToString(CultureInfo.InvariantCulture)}:{channelId.ToString(CultureInfo.InvariantCulture)}:{guildId.ToString(CultureInfo.InvariantCulture)}";
}
diff --git a/DisCatSharp.CommandsNext/CommandsNextExtension.cs b/DisCatSharp.CommandsNext/CommandsNextExtension.cs
index aa4f26bcf3..f052de5bc7 100644
--- a/DisCatSharp.CommandsNext/CommandsNextExtension.cs
+++ b/DisCatSharp.CommandsNext/CommandsNextExtension.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
@@ -50,11 +49,6 @@ public class CommandsNextExtension : BaseExtension
///
internal Dictionary ArgumentConverters { get; }
- ///
- /// Gets the cooldown buckets for this command.
- ///
- public static ConcurrentDictionary CommandCooldownBuckets { get; } = [];
-
///
/// Gets the service provider this CommandsNext module was configured with.
///
@@ -264,7 +258,7 @@ private async Task HandleCommandsAsync(DiscordClient sender, MessageCreateEventA
/// Qualified name of the command, optionally with arguments.
/// Separated arguments.
/// Found command or null if none was found.
- public Command FindCommand(string commandString, out string rawArguments)
+ public Command FindCommand(string commandString, out string? rawArguments)
{
rawArguments = null;
@@ -329,7 +323,7 @@ public Command FindCommand(string commandString, out string rawArguments)
/// Command to execute.
/// Raw arguments to pass to command.
/// Created command execution context.
- public CommandContext CreateContext(DiscordMessage msg, string prefix, Command cmd, string rawArguments = null)
+ public CommandContext CreateContext(DiscordMessage msg, string prefix, Command cmd, string? rawArguments = null)
{
var ctx = new CommandContext
{
@@ -340,7 +334,11 @@ public CommandContext CreateContext(DiscordMessage msg, string prefix, Command c
RawArgumentString = rawArguments ?? "",
Prefix = prefix,
CommandsNext = this,
- Services = this.Services
+ Services = this.Services,
+ UserId = msg.Author.Id,
+ GuildId = msg.GuildId,
+ MemberId = msg.GuildId is not null ? msg.Author.Id : null,
+ ChannelId = msg.ChannelId
};
if (cmd != null && (cmd.Module is TransientCommandModule || cmd.Module == null))
@@ -845,7 +843,8 @@ public CommandContext CreateFakeContext(DiscordUser actor, DiscordChannel channe
AttachmentsInternal = [],
EmbedsInternal = [],
TimestampRaw = now.ToString("yyyy-MM-ddTHH:mm:sszzz"),
- ReactionsInternal = []
+ ReactionsInternal = [],
+ GuildId = channel.GuildId
};
var mentionedUsers = new List();
@@ -877,10 +876,14 @@ public CommandContext CreateFakeContext(DiscordUser actor, DiscordChannel channe
RawArgumentString = rawArguments ?? "",
Prefix = prefix,
CommandsNext = this,
- Services = this.Services
+ Services = this.Services,
+ UserId = msg.Author.Id,
+ GuildId = msg.GuildId,
+ MemberId = msg.GuildId is not null ? msg.Author.Id : null,
+ ChannelId = msg.ChannelId
};
- if (cmd != null && (cmd.Module is TransientCommandModule || cmd.Module == null))
+ if (cmd != null && cmd.Module is TransientCommandModule or null)
{
var scope = ctx.Services.CreateScope();
ctx.ServiceScopeContext = new(ctx.Services, scope);
diff --git a/DisCatSharp.CommandsNext/Entities/CommandGroup.cs b/DisCatSharp.CommandsNext/Entities/CommandGroup.cs
index 5930de264f..063fc1039c 100644
--- a/DisCatSharp.CommandsNext/Entities/CommandGroup.cs
+++ b/DisCatSharp.CommandsNext/Entities/CommandGroup.cs
@@ -56,7 +56,11 @@ public override async Task ExecuteAsync(CommandContext ctx)
RawArgumentString = ctx.RawArgumentString[findPos..],
Prefix = ctx.Prefix,
CommandsNext = ctx.CommandsNext,
- Services = ctx.Services
+ Services = ctx.Services,
+ UserId = ctx.Message.Author.Id,
+ GuildId = ctx.Message.GuildId,
+ MemberId = ctx.Message.GuildId is not null ? ctx.Message.Author.Id : null,
+ ChannelId = ctx.Message.ChannelId
};
var fchecks = await cmd.RunChecksAsync(xctx, false).ConfigureAwait(false);
diff --git a/DisCatSharp.CommandsNext/EventArgs/CommandContext.cs b/DisCatSharp.CommandsNext/EventArgs/CommandContext.cs
index 7a71858143..64a64c512f 100644
--- a/DisCatSharp.CommandsNext/EventArgs/CommandContext.cs
+++ b/DisCatSharp.CommandsNext/EventArgs/CommandContext.cs
@@ -3,6 +3,8 @@
using System.Threading.Tasks;
using DisCatSharp.Entities;
+using DisCatSharp.Entities.Core;
+using DisCatSharp.Enums.Core;
using Microsoft.Extensions.DependencyInjection;
@@ -11,7 +13,7 @@ namespace DisCatSharp.CommandsNext;
///
/// Represents a context in which a command is executed.
///
-public sealed class CommandContext
+public sealed class CommandContext : DisCatSharpCommandContext
{
///
/// Gets the client which received the message.
@@ -98,6 +100,7 @@ public DiscordMember Member
/// Initializes a new instance of the class.
///
internal CommandContext()
+ : base(DisCatSharpCommandType.TextCommand)
{
this._lazyMember = new(() => this.Guild is not null && this.Guild.Members.TryGetValue(this.User.Id, out var member) ? member : this.Guild?.GetMemberAsync(this.User.Id).ConfigureAwait(false).GetAwaiter().GetResult());
}
diff --git a/DisCatSharp/Clients/DiscordClient.cs b/DisCatSharp/Clients/DiscordClient.cs
index f42f01344c..b531722c6c 100644
--- a/DisCatSharp/Clients/DiscordClient.cs
+++ b/DisCatSharp/Clients/DiscordClient.cs
@@ -11,6 +11,7 @@
using DisCatSharp.Attributes;
using DisCatSharp.Entities;
+using DisCatSharp.Entities.Core;
using DisCatSharp.Enums;
using DisCatSharp.Exceptions;
using DisCatSharp.Net;
@@ -135,6 +136,11 @@ public IReadOnlyDictionary EmbeddedActivities
internal Dictionary EmbeddedActivitiesInternal = [];
private Lazy> _embeddedActivitiesLazy;
+ ///
+ /// Gets the cooldown buckets for commands.
+ ///
+ public ConcurrentDictionary CommandCooldownBuckets { get; } = [];
+
#endregion
#region Constructor/Internal Setup
@@ -1697,6 +1703,8 @@ public override void Dispose()
this.ApiClient.Rest.Dispose();
this.CurrentUser = null;
+ this.CommandCooldownBuckets.Clear();
+
var extensions = this._extensions; // prevent _extensions being modified during dispose
this._extensions.Clear();
foreach (var extension in extensions)
diff --git a/DisCatSharp.ApplicationCommands/Entities/CooldownBucket.cs b/DisCatSharp/Entities/Core/CooldownBucket.cs
similarity index 81%
rename from DisCatSharp.ApplicationCommands/Entities/CooldownBucket.cs
rename to DisCatSharp/Entities/Core/CooldownBucket.cs
index 2def3891ab..de21ef767b 100644
--- a/DisCatSharp.ApplicationCommands/Entities/CooldownBucket.cs
+++ b/DisCatSharp/Entities/Core/CooldownBucket.cs
@@ -3,13 +3,9 @@
using System.Threading;
using System.Threading.Tasks;
-using DisCatSharp.ApplicationCommands.Context;
-using DisCatSharp.Entities;
-using DisCatSharp.Enums;
-
using Microsoft.Extensions.Logging;
-namespace DisCatSharp.ApplicationCommands.Entities;
+namespace DisCatSharp.Entities.Core;
///
/// Represents a cooldown bucket.
@@ -83,7 +79,7 @@ public int RemainingUses
/// ID of the channel with which this cooldown is associated.
/// ID of the guild with which this cooldown is associated.
/// ID of the member with which this cooldown is associated.
- internal CooldownBucket(int maxUses, TimeSpan resetAfter, ulong commandId, string commandName, ulong userId = 0, ulong channelId = 0, ulong guildId = 0, ulong memberId = 0)
+ internal CooldownBucket(int maxUses, TimeSpan resetAfter, string commandName, string commandId, ulong userId = 0, ulong channelId = 0, ulong guildId = 0, ulong memberId = 0)
{
this.RemainingUsesInternal = maxUses;
this.MaxUses = maxUses;
@@ -100,42 +96,35 @@ internal CooldownBucket(int maxUses, TimeSpan resetAfter, ulong commandId, strin
///
/// Decrements the remaining use counter.
///
+ /// The context.
/// Whether decrement succeeded or not.
- internal async Task DecrementUseAsync(BaseContext ctx)
+ internal async Task DecrementUseAsync(DisCatSharpCommandContext ctx)
{
await this.UsageSemaphore.WaitAsync().ConfigureAwait(false);
- ctx.Client.Logger.LogDebug($"[Cooldown::check({ctx.FullCommandName})]:\n\tRemaining: {this.RemainingUses}/{this.MaxUses}\n\tResets: {this.ResetsAt}\n\tNow: {DateTimeOffset.UtcNow}\n\tVars[u,c,g,m]: {this.UserId} {this.ChannelId} {this.GuildId} {this.MemberId}\n\tId: {this.BucketId}");
+ ctx.Client.Logger.LogDebug($"[Cooldown::prev_check({ctx.FullCommandName})]:\n\tRemaining: {this.RemainingUses}/{this.MaxUses}\n\tResets: {this.ResetsAt}\n\tNow: {DateTimeOffset.UtcNow}\n\tVars[u,c,g,m]: {this.UserId} {this.ChannelId} {this.GuildId} {this.MemberId}\n\tId: {this.BucketId}");
- // if we're past reset time...
var now = DateTimeOffset.UtcNow;
if (now >= this.ResetsAt)
{
- // ...do the reset and set a new reset time
Interlocked.Exchange(ref this.RemainingUsesInternal, this.MaxUses);
this.ResetsAt = now + this.Reset;
}
- // check if we have any uses left, if we do...
+ ctx.Client.Logger.LogDebug($"[Cooldown::check({ctx.FullCommandName})]:\n\tRemaining: {this.RemainingUses}/{this.MaxUses}\n\tResets: {this.ResetsAt}\n\tNow: {DateTimeOffset.UtcNow}\n\tVars[u,c,g,m]: {this.UserId} {this.ChannelId} {this.GuildId} {this.MemberId}\n\tId: {this.BucketId}");
+
var success = false;
if (this.RemainingUses > 0)
{
- // ...decrement, and return success...
Interlocked.Decrement(ref this.RemainingUsesInternal);
success = true;
}
- // ...otherwise just fail
this.UsageSemaphore.Release();
if (success)
return success;
ctx.Client.Logger.LogWarning($"[Cooldown::hit({ctx.FullCommandName})]:\n\tRemaining: {this.RemainingUses}/{this.MaxUses}\n\tResets: {this.ResetsAt}\n\tNow: {DateTimeOffset.UtcNow}\n\tVars[u,c,g,m]: {this.UserId} {this.ChannelId} {this.GuildId} {this.MemberId}\n\tId: {this.BucketId}");
- if (ApplicationCommandsExtension.Configuration.AutoDefer)
- await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent($"Error: Ratelimit hit. Try again in {this.ResetsAt.Timestamp()}"));
- else
- await ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().AsEphemeral().WithContent($"Error: Ratelimit hit. Try again in {this.ResetsAt.Timestamp()}"));
-
return success;
}
@@ -195,6 +184,6 @@ public override int GetHashCode()
/// ID of the guild with which this cooldown is associated.
/// ID of the member with which this cooldown is associated.
/// Generated bucket ID.
- public static string MakeId(ulong commandId, string commandName, ulong userId = 0, ulong channelId = 0, ulong guildId = 0, ulong memberId = 0)
- => $"{commandId.ToString(CultureInfo.InvariantCulture)}:{commandName}::{userId.ToString(CultureInfo.InvariantCulture)}:{channelId.ToString(CultureInfo.InvariantCulture)}:{guildId.ToString(CultureInfo.InvariantCulture)}:{memberId.ToString(CultureInfo.InvariantCulture)}";
+ public static string MakeId(string commandId, string commandName, ulong userId = 0, ulong channelId = 0, ulong guildId = 0, ulong memberId = 0)
+ => $"{commandId}:{commandName}::{userId.ToString(CultureInfo.InvariantCulture)}:{channelId.ToString(CultureInfo.InvariantCulture)}:{guildId.ToString(CultureInfo.InvariantCulture)}:{memberId.ToString(CultureInfo.InvariantCulture)}";
}
diff --git a/DisCatSharp/Entities/Core/DisCatSharpCommandContext.cs b/DisCatSharp/Entities/Core/DisCatSharpCommandContext.cs
new file mode 100644
index 0000000000..cc5300e6b7
--- /dev/null
+++ b/DisCatSharp/Entities/Core/DisCatSharpCommandContext.cs
@@ -0,0 +1,80 @@
+using DisCatSharp.Enums.Core;
+
+namespace DisCatSharp.Entities.Core;
+
+///
+/// Interface for various command types like slash commands, user commands, message commands, text commands, etc.
+///
+public class DisCatSharpCommandContext
+{
+ ///
+ /// Gets the client.
+ ///
+ public DiscordClient Client { get; internal init; }
+
+ ///
+ /// Gets the id of the user who executes this command.
+ ///
+ public ulong UserId { get; internal set; }
+
+ ///
+ /// Gets the id of the channel this command gets executed in.
+ ///
+ public ulong ChannelId { get; internal set; }
+
+ ///
+ /// Gets the id of the guild this command gets executed in.
+ ///
+ public ulong? GuildId { get; internal set; }
+
+ ///
+ /// Gets the id of the member who executes this command.
+ ///
+ public ulong? MemberId { get; internal set; }
+
+ ///
+ /// Gets the id of the command.
+ ///
+ public ulong? CommandId { get; internal set; }
+
+ ///
+ /// Gets the name of the command.
+ ///
+ public string CommandName { get; internal set; } = string.Empty;
+
+ ///
+ /// Gets the name of the sub command.
+ ///
+ public string? SubCommandName { get; internal set; }
+
+ ///
+ /// Gets the name of the sub command within a sub group.
+ ///
+ public string? SubSubCommandName { get; internal set; }
+
+ ///
+ /// Gets the fully qualified name of the command.
+ ///
+ public virtual string FullCommandName { get; internal set; } = string.Empty;
+
+ ///
+ /// Gets the type of the command.
+ ///
+ public DisCatSharpCommandType CommandType { get; internal set; }
+
+ ///
+ /// Gets the command grouping type of the command.
+ ///
+ public DisCatSharpCommandGroupingType CommandGroupingType { get; internal set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The command type.
+ /// The command grouping type.
+ internal DisCatSharpCommandContext(DisCatSharpCommandType type, DisCatSharpCommandGroupingType groupingType = DisCatSharpCommandGroupingType.None)
+ {
+ this.CommandType = type;
+ this.CommandGroupingType = groupingType;
+ }
+}
diff --git a/DisCatSharp.ApplicationCommands/Entities/IBucket.cs b/DisCatSharp/Entities/Core/IBucket.cs
similarity index 94%
rename from DisCatSharp.ApplicationCommands/Entities/IBucket.cs
rename to DisCatSharp/Entities/Core/IBucket.cs
index fa10df5bb7..3ff9bd923c 100644
--- a/DisCatSharp.ApplicationCommands/Entities/IBucket.cs
+++ b/DisCatSharp/Entities/Core/IBucket.cs
@@ -1,6 +1,7 @@
using System;
+using System.Threading.Tasks;
-namespace DisCatSharp.ApplicationCommands.Entities;
+namespace DisCatSharp.Entities.Core;
///
/// Defines the standard contract for bucket feature
diff --git a/DisCatSharp.ApplicationCommands/Entities/ICooldown.cs b/DisCatSharp/Entities/Core/ICooldown.cs
similarity index 69%
rename from DisCatSharp.ApplicationCommands/Entities/ICooldown.cs
rename to DisCatSharp/Entities/Core/ICooldown.cs
index ae3747f725..0b9c7dde88 100644
--- a/DisCatSharp.ApplicationCommands/Entities/ICooldown.cs
+++ b/DisCatSharp/Entities/Core/ICooldown.cs
@@ -1,17 +1,17 @@
using System;
+using System.Threading.Tasks;
-using DisCatSharp.ApplicationCommands.Context;
-using DisCatSharp.ApplicationCommands.Enums;
+using DisCatSharp.Enums.Core;
-namespace DisCatSharp.ApplicationCommands.Entities;
+namespace DisCatSharp.Entities.Core;
///
/// Cooldown feature contract
///
-/// Type of in which this cooldown handles
+/// Type of in which this cooldown handles
/// Type of Cooldown bucket
public interface ICooldown
- where TContextType : BaseContext
+ where TContextType : DisCatSharpCommandContext
where TBucketType : CooldownBucket
{
///
@@ -42,4 +42,11 @@ public interface ICooldown
/// Command context to get cooldown bucket for.
/// Requested cooldown bucket, or null if one wasn't present
TBucketType GetBucket(TContextType ctx);
+
+ ///
+ /// Responds to a ratelimit hit.
+ ///
+ /// The command context.
+ /// Whether the ratelimit wasn't it.
+ Task RespondRatelimitHitAsync(TContextType ctx, bool noHit, CooldownBucket bucket);
}
diff --git a/DisCatSharp/Entities/Core/IDisCatSharpCommand.cs b/DisCatSharp/Entities/Core/IDisCatSharpCommand.cs
deleted file mode 100644
index a7c6f01d54..0000000000
--- a/DisCatSharp/Entities/Core/IDisCatSharpCommand.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using DisCatSharp.Enums.Core;
-
-namespace DisCatSharp.Entities.Core;
-
-///
-/// Interface for various command types like slash commands, user commands, message commands, text commands, etc.
-///
-internal interface IDisCatSharpCommand
-{
- ///
- /// Gets the id of the user who executes this command.
- ///
- ulong UserId { get; internal set; }
-
- ///
- /// Gets the id of the channel this command gets executed in.
- ///
- ulong ChannelId { get; internal set; }
-
- ///
- /// Gets the id of the guild this command gets executed in.
- ///
- ulong? GuildId { get; internal set; }
-
- ///
- /// Gets the id of the member who executes this command.
- ///
- ulong? MemberId { get; internal set; }
-
- ///
- /// Gets the id of the command.
- ///
- ulong? CommandId { get; internal set; }
-
- ///
- /// Gets the name of the command if is not available.
- ///
- string? CommandName { get; internal set; }
-
- ///
- /// Gets the type of the command.
- ///
- DisCatSharpCommandType CommandType { get; internal set; }
-
- ///
- /// Gets the command grouping type of the command.
- ///
- DisCatSharpCommandGroupingType CommandGroupingType { get; internal set; }
-}
diff --git a/DisCatSharp.ApplicationCommands/Enums/CooldownBucketType.cs b/DisCatSharp/Enums/Core/CooldownBucketType.cs
similarity index 94%
rename from DisCatSharp.ApplicationCommands/Enums/CooldownBucketType.cs
rename to DisCatSharp/Enums/Core/CooldownBucketType.cs
index dad7acc93c..f50fecab0d 100644
--- a/DisCatSharp.ApplicationCommands/Enums/CooldownBucketType.cs
+++ b/DisCatSharp/Enums/Core/CooldownBucketType.cs
@@ -1,6 +1,6 @@
using System;
-namespace DisCatSharp.ApplicationCommands.Enums;
+namespace DisCatSharp.Enums.Core;
///
/// Defines how are command cooldowns applied.
diff --git a/DisCatSharp/Enums/Core/DisCatSharpCommandGroupingType.cs b/DisCatSharp/Enums/Core/DisCatSharpCommandGroupingType.cs
index e48e2e2d86..6debe497b4 100644
--- a/DisCatSharp/Enums/Core/DisCatSharpCommandGroupingType.cs
+++ b/DisCatSharp/Enums/Core/DisCatSharpCommandGroupingType.cs
@@ -3,25 +3,25 @@ namespace DisCatSharp.Enums.Core;
///
/// Represents the grouping type of a command.
///
-internal enum DisCatSharpCommandGroupingType
+public enum DisCatSharpCommandGroupingType
{
///
- /// The command is not part of a group.
+ /// This is a special type and not a command.
///
None,
///
- /// The command is a group.
+ /// The command is not part of a group.
///
- Group,
+ Command,
///
- /// The command is a subgroup.
+ /// The command is a sub command.
///
- SubGroup,
+ SubCommand,
///
- /// The command is a subcommand.
+ /// The command is a sub group command.
///
- SubCommand
+ SubGroupCommand
}
diff --git a/DisCatSharp/Enums/Core/DisCatSharpCommandType.cs b/DisCatSharp/Enums/Core/DisCatSharpCommandType.cs
index b7394f1eca..22619fd78f 100644
--- a/DisCatSharp/Enums/Core/DisCatSharpCommandType.cs
+++ b/DisCatSharp/Enums/Core/DisCatSharpCommandType.cs
@@ -3,7 +3,7 @@ namespace DisCatSharp.Enums.Core;
///
/// Represents the type of a command.
///
-internal enum DisCatSharpCommandType
+public enum DisCatSharpCommandType
{
///
/// A text command.
@@ -26,7 +26,7 @@ internal enum DisCatSharpCommandType
MessageCommand,
///
- /// A special component command.
+ /// A special type.
///
- ComponentCommand
+ Special
}