From 01a4b2632692cbd1dbaf3aff2a014c6fc07deab2 Mon Sep 17 00:00:00 2001 From: barelyprofessional <150058423+barelyprofessional@users.noreply.github.com> Date: Wed, 18 Mar 2026 23:50:32 -0500 Subject: [PATCH] Added support for MOTD and whispers. Commands can opt into responding to whispers and there's a helper method to handle replying through the correct channel. --- KfChatDotNetBot/ChatBot.cs | 163 +++++++++++++++++- KfChatDotNetBot/Commands/AdminCommands.cs | 73 ++++++-- KfChatDotNetBot/Commands/EightballCommand.cs | 3 +- KfChatDotNetBot/Commands/HowlggCommands.cs | 6 +- KfChatDotNetBot/Commands/ICommand.cs | 3 +- KfChatDotNetBot/Commands/ImageCommands.cs | 13 +- KfChatDotNetBot/Commands/JuiceCommand.cs | 3 +- .../Commands/Kasino/BlackjackCommand.cs | 4 +- .../Commands/Kasino/CoinflipCommand.cs | 4 +- .../Commands/Kasino/DiceCommand.cs | 4 +- .../Commands/Kasino/GuessWhatNumberCommand.cs | 25 ++- .../Commands/Kasino/KasinoAdminCommands.cs | 14 +- .../Commands/Kasino/KasinoEventCommands.cs | 18 +- .../Commands/Kasino/KasinoUserCommands.cs | 29 ++-- .../Commands/Kasino/KenoCommand.cs | 3 +- .../Commands/Kasino/LambchopCommand.cs | 3 +- .../Commands/Kasino/LegitCheckCommand.cs | 3 +- .../Commands/Kasino/LimboCommand.cs | 3 +- .../Commands/Kasino/MinesCommand.cs | 3 +- .../Commands/Kasino/PlanesCommand.cs | 3 +- .../Commands/Kasino/PlinkoCommand.cs | 3 +- .../Commands/Kasino/RainCommand.cs | 3 +- .../Commands/Kasino/RouletteCommand.cs | 3 +- .../Commands/Kasino/SlotsCommand.cs | 3 +- .../Commands/Kasino/WheelCommand.cs | 3 +- KfChatDotNetBot/Commands/MemeCommands.cs | 36 ++-- KfChatDotNetBot/Commands/MomCommands.cs | 3 +- KfChatDotNetBot/Commands/NoraCommand.cs | 7 +- KfChatDotNetBot/Commands/RainbetCommands.cs | 6 +- KfChatDotNetBot/Commands/RestreamCommands.cs | 12 +- KfChatDotNetBot/Commands/ShopCommands.cs | 93 ++++++---- KfChatDotNetBot/Commands/TestCommands.cs | 15 +- KfChatDotNetBot/Commands/TimeCommand.cs | 5 +- KfChatDotNetBot/Commands/UtilityCommands.cs | 12 +- KfChatDotNetBot/Commands/WhoisCommand.cs | 6 +- KfChatDotNetBot/Commands/XeetEmbedCommand.cs | 3 +- .../Models/BotCommandMessageModel.cs | 44 +++++ .../Models/SentMessageTrackerModel.cs | 14 ++ KfChatDotNetBot/Services/BotCommands.cs | 28 ++- KfChatDotNetBot/Settings/BuiltIn.cs | 2 + KfChatDotNetWsClient/ChatClient.cs | 100 +++++++++++ .../Models/Events/EventHandlers.cs | 4 + .../Models/Events/WhisperModel.cs | 12 ++ .../Models/Json/WhisperJsonModel.cs | 34 ++++ 44 files changed, 683 insertions(+), 148 deletions(-) create mode 100644 KfChatDotNetBot/Models/BotCommandMessageModel.cs create mode 100644 KfChatDotNetWsClient/Models/Events/WhisperModel.cs create mode 100644 KfChatDotNetWsClient/Models/Json/WhisperJsonModel.cs diff --git a/KfChatDotNetBot/ChatBot.cs b/KfChatDotNetBot/ChatBot.cs index 8f3a136..b6ab58f 100644 --- a/KfChatDotNetBot/ChatBot.cs +++ b/KfChatDotNetBot/ChatBot.cs @@ -85,6 +85,8 @@ public class ChatBot KfClient.OnWsDisconnection += OnKfWsDisconnected; KfClient.OnWsReconnect += OnKfWsReconnected; KfClient.OnFailedToJoinRoom += OnFailedToJoinRoom; + KfClient.OnMotd += OnMotd; + KfClient.OnWhisper += OnWhisper; KfClient.StartWsClient().Wait(_cancellationToken); @@ -98,6 +100,11 @@ public class ChatBot exitEvent.WaitOne(); } + private void OnMotd(object sender, MessageModel message) + { + SettingsProvider.SetValueAsync(BuiltIn.Keys.KiwiFarmsMotdUuid, message.MessageUuid).Wait(_cancellationToken); + } + private void OnFailedToJoinRoom(object sender, string message) { var failureLimit = SettingsProvider.GetValueAsync(BuiltIn.Keys.KiwiFarmsJoinFailLimit).Result.ToType(); @@ -263,6 +270,45 @@ public class ChatBot await _kfTokenService.SaveCookies(); KfClient.UpdateCookies(_kfTokenService.GetCookies()); } + + private void OnWhisper(object sender, WhisperModel whisper) + { + var settings = SettingsProvider.GetMultipleValuesAsync([ + BuiltIn.Keys.KiwiFarmsUsername, BuiltIn.Keys.BotDisconnectReplayLimit + ]).Result; + if (whisper.Author.Username == settings[BuiltIn.Keys.KiwiFarmsUsername].Value) + { + _logger.Debug("Ignoring my own whisper"); + return; + } + + var sentMsgMaybe = SentMessages.FirstOrDefault(msg => + msg.Type == SentMessageType.Whisper && msg.WhisperMessage == whisper.MessageRawHtmlDecoded); + sentMsgMaybe?.Status = SentMessageTrackerStatus.ResponseReceived; + _logger.Debug("Passing message to command interface"); + var botCommandsMsg = new BotCommandMessageModel + { + Author = whisper.Author, + Recipient = whisper.Recipient, + Message = whisper.Message, + MessageDate = whisper.MessageDate, + MessageEditDate = null, + MessageRaw = whisper.MessageRaw, + MessageRawHtmlDecoded = whisper.MessageRawHtmlDecoded, + MessageUuid = null, + RoomId = null, + IsWhisper = true + }; + try + { + _botCommands.ProcessMessage(botCommandsMsg); + } + catch (Exception e) + { + _logger.Error("ProcessMessage threw an exception"); + _logger.Error(e); + } + } private void OnKfChatMessage(object sender, List messages, MessagesJsonModel jsonPayload) { @@ -307,14 +353,14 @@ public class ChatBot // MessageRaw is not actually REAL and RAW. The messages are still HTML encoded var decodedMessage = WebUtility.HtmlDecode(message.MessageRaw); var sentMessage = SentMessages.FirstOrDefault(sent => - sent.Message == decodedMessage && sent.Status == SentMessageTrackerStatus.WaitingForResponse); + sent.Message == decodedMessage && sent is { Status: SentMessageTrackerStatus.WaitingForResponse, Type: SentMessageType.ChatMessage }); if (sentMessage == null) { _logger.Error("Received message from Sneedchat that I sent but have no idea about. Message Data Follows:"); _logger.Error(JsonSerializer.Serialize(message)); _logger.Error("Last item inserted into the sent messages collection waiting for response:"); var latest = - SentMessages.LastOrDefault(msg => msg.Status == SentMessageTrackerStatus.WaitingForResponse); + SentMessages.LastOrDefault(msg => msg is { Status: SentMessageTrackerStatus.WaitingForResponse, Type: SentMessageType.ChatMessage }); _logger.Error(JsonSerializer.Serialize(latest)); if (latest != null) { @@ -355,9 +401,22 @@ public class ChatBot !InitialStartCooldown) { _logger.Debug("Passing message to command interface"); + var botCommandsMsg = new BotCommandMessageModel + { + Author = message.Author, + MessageRaw = message.MessageRaw, + Message = message.Message, + MessageDate = message.MessageDate, + MessageEditDate = message.MessageEditDate, + MessageRawHtmlDecoded = message.MessageRawHtmlDecoded, + MessageUuid = message.MessageUuid, + Recipient = null, + RoomId = message.RoomId, + IsWhisper = false + }; try { - _botCommands.ProcessMessage(message); + _botCommands.ProcessMessage(botCommandsMsg); } catch (Exception e) { @@ -418,6 +477,8 @@ public class ChatBot Reference = reference, Message = message.TrimEnd(), // Sneedchat trims trailing spaces Status = SentMessageTrackerStatus.Unknown, + Type = SentMessageType.ChatMessage, + WhisperMessage = null }; if (settings[BuiltIn.Keys.KiwiFarmsSuppressChatMessages].ToBoolean()) { @@ -476,6 +537,80 @@ public class ChatBot } return messageTracker; } + + // Reference for Sneedchat hardcoded length limit + // https://github.com/jaw-sh/ruforo/blob/master/src/web/chat/connection.rs#L226 + /// + /// Async method for sending a whisper + /// + /// Kiwi Farms user ID of the recipient for this whisper + /// The message you wish to whisper + /// What behavior to use when encountering a message that exceeds the length limit + /// Length limit to enforce in bytes + /// An object you can use to check the status of the message + public async Task SendWhisperAsync(int recipient, string message, LengthLimitBehavior lengthLimitBehavior = LengthLimitBehavior.TruncateNicely, int lengthLimit = 2048) + { + var settings = await SettingsProvider + .GetMultipleValuesAsync([ + BuiltIn.Keys.KiwiFarmsSuppressChatMessages + ]); + var originalMessage = message; + message = $"/w {recipient} {message}"; + var reference = Guid.NewGuid().ToString(); + var messageTracker = new SentMessageTrackerModel + { + Reference = reference, + Message = message.TrimEnd(), // Sneedchat trims trailing spaces + Status = SentMessageTrackerStatus.Unknown, + Type = SentMessageType.Whisper, + WhisperMessage = originalMessage.TrimEnd() + }; + if (settings[BuiltIn.Keys.KiwiFarmsSuppressChatMessages].ToBoolean()) + { + _logger.Info("Not sending message as SuppressChatMessages is enabled"); + _logger.Info($"Message was: {message}"); + messageTracker.Status = SentMessageTrackerStatus.NotSending; + SentMessages.Add(messageTracker); + return messageTracker; + } + + if (!KfClient.IsConnected()) + { + _logger.Info($"Not sending message '{message}' as Sneedchat is not connected"); + messageTracker.Status = SentMessageTrackerStatus.ChatDisconnected; + SentMessages.Add(messageTracker); + return messageTracker; + } + + if (messageTracker.Message.Utf8LengthBytes() > lengthLimit && lengthLimitBehavior != LengthLimitBehavior.DoNothing) + { + if (lengthLimitBehavior == LengthLimitBehavior.RefuseToSend) + { + _logger.Info("Refusing to send message as it exceeds the length limit and LengthLimitBehavior is RefuseToSend"); + messageTracker.Status = SentMessageTrackerStatus.NotSending; + SentMessages.Add(messageTracker); + return messageTracker; + } + if (lengthLimitBehavior == LengthLimitBehavior.TruncateNicely) + { + // '…' is 3 bytes so we have to make room for it + messageTracker.Message = messageTracker.Message.TruncateBytes(lengthLimit - 3).TrimEnd() + "…"; + } + + if (lengthLimitBehavior == LengthLimitBehavior.TruncateExactly) + { + // TrimEnd in case you end up truncating on a space (happened during testing) as Sneedchat will trim it + messageTracker.Message = messageTracker.Message.TruncateBytes(lengthLimit).TrimEnd(); + } + } + + messageTracker.Status = SentMessageTrackerStatus.WaitingForResponse; + messageTracker.SentAt = DateTimeOffset.UtcNow; + _logger.Debug($"Message is {messageTracker.Message.Utf8LengthBytes()} bytes"); + SentMessages.Add(messageTracker); + await KfClient.SendMessageInstantAsync(messageTracker.Message); + return messageTracker; + } /// /// Exposes the private task used to delete messages based on a TimeSpan in case you want to use it on-demand @@ -699,4 +834,26 @@ public class ChatBot public required SentMessageTrackerModel Message { get; set; } public required DateTimeOffset DeleteAt { get; set; } } + + /// + /// Thin wrapper to decide whether to whisper or chat message respond + /// + /// The original message you received (so I know if it was a whisper) + /// Message you want to send + /// Whether to bypass gambasesh (not applicable for whispers) + /// Whether to auto delete after a period of time (not applicable to whispers) + /// What behavior to use for messages which exceed the length limit + /// + public async Task ReplyToUser(BotCommandMessageModel origMsg, string response, + bool bypassGambaSesh = false, TimeSpan? autoDeleteAfter = null, LengthLimitBehavior lengthLimitBehavior = ChatBot.LengthLimitBehavior.TruncateNicely) + { + if (origMsg.IsWhisper) + { + return await SendWhisperAsync(origMsg.Author.Id, response, + lengthLimitBehavior: lengthLimitBehavior); + } + + return await SendChatMessageAsync(response, bypassGambaSesh, lengthLimitBehavior, + autoDeleteAfter: autoDeleteAfter); + } } \ No newline at end of file diff --git a/KfChatDotNetBot/Commands/AdminCommands.cs b/KfChatDotNetBot/Commands/AdminCommands.cs index b11faa5..c65827e 100644 --- a/KfChatDotNetBot/Commands/AdminCommands.cs +++ b/KfChatDotNetBot/Commands/AdminCommands.cs @@ -22,8 +22,9 @@ public class SetRoleCommand : ICommand public UserRight RequiredRight => UserRight.Admin; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); var targetUserId = Convert.ToInt32(arguments["user"].Value); @@ -51,8 +52,9 @@ public class CacheClearAdminCommand : ICommand public UserRight RequiredRight => UserRight.Admin; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList(); foreach (var cacheKey in cacheKeys) @@ -74,7 +76,8 @@ public class NewKickChannelCommand : ICommand public UserRight RequiredRight => UserRight.Admin; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var autoCapture = false; if (arguments.TryGetValue("auto_capture", out var argument)) @@ -121,7 +124,8 @@ public class RemoveStreamChannelCommand : ICommand public UserRight RequiredRight => UserRight.Admin; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); var rowId = Convert.ToInt32(arguments["id"].Value); @@ -147,7 +151,8 @@ public class ReconnectKickCommand : ICommand public UserRight RequiredRight => UserRight.Admin; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { if (botInstance.BotServices.KickClient == null) { @@ -171,7 +176,8 @@ public class NewPartiChannelCommand : ICommand public UserRight RequiredRight => UserRight.Admin; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var autoCapture = false; if (arguments.TryGetValue("auto_capture", out var argument)) @@ -219,7 +225,8 @@ public class NewDLiveChannelCommand : ICommand public UserRight RequiredRight => UserRight.Admin; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var autoCapture = false; if (arguments.TryGetValue("auto_capture", out var argument)) @@ -261,7 +268,8 @@ public class AddCourtHearingCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var hearings = (await SettingsProvider.GetValueAsync(BuiltIn.Keys.BotCourtCalendar)).JsonDeserialize>(); if (hearings == null) @@ -292,7 +300,8 @@ public class RemoveCourtHearingCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var hearings = (await SettingsProvider.GetValueAsync(BuiltIn.Keys.BotCourtCalendar)).JsonDeserialize>(); if (hearings == null) @@ -324,7 +333,8 @@ public class DeleteMessagesCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var amount = int.Parse(arguments["msg_count"].Value); @@ -357,7 +367,8 @@ public class IgnoreCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); @@ -398,7 +409,8 @@ public class UnignoreCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); @@ -432,7 +444,8 @@ public class SetAlmanacTextCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await SettingsProvider.SetValueAsync(BuiltIn.Keys.BotAlmanacText, arguments["text"].Value); @@ -450,7 +463,8 @@ public class SetAlmanacIntervalCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var interval = Convert.ToInt32(arguments["interval"].Value); @@ -480,7 +494,8 @@ public class StopAlmanacCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { if (botInstance.BotServices.AlmanacShill == null) @@ -509,7 +524,8 @@ public class StartAlmanacCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { if (botInstance.BotServices.AlmanacShill == null) @@ -538,7 +554,8 @@ public class ToggleForcedGambaMessagesCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { botInstance.BotServices.TemporarilyForceGambaMessages = !botInstance.BotServices.TemporarilyForceGambaMessages; @@ -557,9 +574,29 @@ public class ToggleDiscordRelayingCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { botInstance.BotServices.TemporarilyBypassGambaSeshForDiscord = !botInstance.BotServices.TemporarilyBypassGambaSeshForDiscord; await botInstance.SendChatMessageAsync($"TemporarilyBypassGambaSeshForDiscord is now {botInstance.BotServices.TemporarilyBypassGambaSeshForDiscord}", true); } +} + +public class SetMotd : ICommand +{ + public List Patterns => [ + new Regex(@"^admin motd (?\S+)$", RegexOptions.IgnoreCase) + ]; + + public string? HelpText => null; + public UserRight RequiredRight => UserRight.TrueAndHonest; + public TimeSpan Timeout => TimeSpan.FromSeconds(10); + public RateLimitOptionsModel? RateLimitOptions => null; + public bool WhisperCanInvoke => true; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + { + var uuid = arguments["uuid"].Value; + await botInstance.SendChatMessageAsync($"/motd {uuid}", true); + await botInstance.ReplyToUser(message, $"{user.FormatUsername()}, set MOTD to {uuid}", true); + } } \ No newline at end of file diff --git a/KfChatDotNetBot/Commands/EightballCommand.cs b/KfChatDotNetBot/Commands/EightballCommand.cs index e931de1..8543aa7 100644 --- a/KfChatDotNetBot/Commands/EightballCommand.cs +++ b/KfChatDotNetBot/Commands/EightballCommand.cs @@ -21,6 +21,7 @@ public class EightBallCommand : ICommand MaxInvocations = 3, Window = TimeSpan.FromSeconds(15) }; + public bool WhisperCanInvoke => false; private static readonly string[] AnswersYes = [ "Yes, definitely.", @@ -103,7 +104,7 @@ public class EightBallCommand : ICommand "The outlook is bleak." ]; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var random = RandomShim.Create(StandardRng.Create()); diff --git a/KfChatDotNetBot/Commands/HowlggCommands.cs b/KfChatDotNetBot/Commands/HowlggCommands.cs index 66bf937..96767ca 100644 --- a/KfChatDotNetBot/Commands/HowlggCommands.cs +++ b/KfChatDotNetBot/Commands/HowlggCommands.cs @@ -17,7 +17,8 @@ public class HowlggStatsCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var window = Convert.ToInt32(arguments["window"].Value); var start = DateTimeOffset.UtcNow.AddHours(-window); @@ -45,7 +46,8 @@ public class HowlggRecentBetCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ BuiltIn.Keys.KiwiFarmsGreenColor, BuiltIn.Keys.KiwiFarmsRedColor, BuiltIn.Keys.HowlggDivisionAmount diff --git a/KfChatDotNetBot/Commands/ICommand.cs b/KfChatDotNetBot/Commands/ICommand.cs index 1a01f76..4ac8630 100644 --- a/KfChatDotNetBot/Commands/ICommand.cs +++ b/KfChatDotNetBot/Commands/ICommand.cs @@ -13,6 +13,7 @@ public interface ICommand UserRight RequiredRight { get; } TimeSpan Timeout { get; } RateLimitOptionsModel? RateLimitOptions { get; } + bool WhisperCanInvoke { get; } - Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx); + Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx); } \ No newline at end of file diff --git a/KfChatDotNetBot/Commands/ImageCommands.cs b/KfChatDotNetBot/Commands/ImageCommands.cs index 91dbc2c..30ef22d 100644 --- a/KfChatDotNetBot/Commands/ImageCommands.cs +++ b/KfChatDotNetBot/Commands/ImageCommands.cs @@ -23,7 +23,8 @@ public class AddImageCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); @@ -65,7 +66,8 @@ public class RemoveImageCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); @@ -105,8 +107,8 @@ public class ListImageCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); @@ -164,7 +166,8 @@ public class GetRandomImage : ICommand MaxInvocations = 7, Flags = RateLimitFlags.UseEntireMessage | RateLimitFlags.NoResponse }; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); diff --git a/KfChatDotNetBot/Commands/JuiceCommand.cs b/KfChatDotNetBot/Commands/JuiceCommand.cs index 5057414..11587ea 100644 --- a/KfChatDotNetBot/Commands/JuiceCommand.cs +++ b/KfChatDotNetBot/Commands/JuiceCommand.cs @@ -17,7 +17,8 @@ public class JuiceStatsCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { int top; if (arguments.TryGetValue("top", out var argument)) diff --git a/KfChatDotNetBot/Commands/Kasino/BlackjackCommand.cs b/KfChatDotNetBot/Commands/Kasino/BlackjackCommand.cs index e5ea5b0..8e38c8b 100644 --- a/KfChatDotNetBot/Commands/Kasino/BlackjackCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/BlackjackCommand.cs @@ -40,9 +40,11 @@ public class BlackjackCommand : ICommand Flags = RateLimitFlags.NoAutoDeleteCooldownResponse }; + public bool WhisperCanInvoke => false; + private ApplicationDbContext _dbContext = new(); - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ diff --git a/KfChatDotNetBot/Commands/Kasino/CoinflipCommand.cs b/KfChatDotNetBot/Commands/Kasino/CoinflipCommand.cs index 8e15c91..aaf5773 100644 --- a/KfChatDotNetBot/Commands/Kasino/CoinflipCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/CoinflipCommand.cs @@ -30,9 +30,11 @@ public class CoinflipCommand : ICommand MaxInvocations = 3, Window = TimeSpan.FromSeconds(15) }; + + public bool WhisperCanInvoke => false; private static double _houseEdge = 0.015; // house edge hack? - public async Task RunCommand(ChatBot botInstance, MessageModel messagen, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ diff --git a/KfChatDotNetBot/Commands/Kasino/DiceCommand.cs b/KfChatDotNetBot/Commands/Kasino/DiceCommand.cs index 724b6aa..713f89f 100644 --- a/KfChatDotNetBot/Commands/Kasino/DiceCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/DiceCommand.cs @@ -25,9 +25,11 @@ public class DiceCommand : ICommand MaxInvocations = 3, Window = TimeSpan.FromSeconds(15) }; + + public bool WhisperCanInvoke => false; private static double _houseEdge = 0.015; // house edge hack? - public async Task RunCommand(ChatBot botInstance, MessageModel messagen, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ diff --git a/KfChatDotNetBot/Commands/Kasino/GuessWhatNumberCommand.cs b/KfChatDotNetBot/Commands/Kasino/GuessWhatNumberCommand.cs index ec2620a..c527e96 100644 --- a/KfChatDotNetBot/Commands/Kasino/GuessWhatNumberCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/GuessWhatNumberCommand.cs @@ -21,20 +21,27 @@ public class GuessWhatNumberCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ BuiltIn.Keys.KasinoGameDisabledMessageCleanupDelay, BuiltIn.Keys.KasinoGuessWhatNumberCleanupDelay, BuiltIn.Keys.KasinoGuessWhatNumberEnabled ]); + + if (message is { IsWhisper: false, MessageUuid: not null }) + { + await botInstance.KfClient.DeleteMessageAsync(message.MessageUuid); + } // Check if guesswhatnumber is enabled - var guessWhatNumberEnabled = (settings[BuiltIn.Keys.KasinoGuessWhatNumberEnabled]).ToBoolean(); + var guessWhatNumberEnabled = settings[BuiltIn.Keys.KasinoGuessWhatNumberEnabled].ToBoolean(); if (!guessWhatNumberEnabled) { var gameDisabledCleanupDelay= TimeSpan.FromMilliseconds(settings[BuiltIn.Keys.KasinoGameDisabledMessageCleanupDelay].ToType()); - await botInstance.SendChatMessageAsync( + await botInstance.ReplyToUser(message, $"{user.FormatUsername()}, guess what number is currently disabled.", true, autoDeleteAfter: gameDisabledCleanupDelay); return; @@ -44,7 +51,7 @@ public class GuessWhatNumberCommand : ICommand if (!arguments.TryGetValue("amount", out var amount)) { - await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, not enough arguments. !guess ", true, autoDeleteAfter: cleanupDelay); + await botInstance.ReplyToUser(message, $"{user.FormatUsername()}, not enough arguments. !guess ", true, autoDeleteAfter: cleanupDelay); RateLimitService.RemoveMostRecentEntry(user, this); return; } @@ -53,7 +60,7 @@ public class GuessWhatNumberCommand : ICommand var guess = Convert.ToInt32(arguments["number"].Value); if (guess is < 1 or > 10) { - await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, your guess must be between 1 and 10", true, autoDeleteAfter: cleanupDelay); + await botInstance.ReplyToUser(message, $"{user.FormatUsername()}, your guess must be between 1 and 10", true, autoDeleteAfter: cleanupDelay); RateLimitService.RemoveMostRecentEntry(user, this); return; } @@ -62,7 +69,7 @@ public class GuessWhatNumberCommand : ICommand throw new InvalidOperationException($"Caught a null when retrieving gambler for {user.KfUsername}"); if (gambler.Balance < wager) { - await botInstance.SendChatMessageAsync( + await botInstance.ReplyToUser(message, $"{user.FormatUsername()}, your balance of {await gambler.Balance.FormatKasinoCurrencyAsync()} isn't enough for this wager.", true, autoDeleteAfter: cleanupDelay); return; @@ -70,7 +77,7 @@ public class GuessWhatNumberCommand : ICommand if (wager == 0) { - await botInstance.SendChatMessageAsync( + await botInstance.ReplyToUser(message, $"{user.FormatUsername()}, you have to wager more than {await wager.FormatKasinoCurrencyAsync()}", true, autoDeleteAfter: cleanupDelay); RateLimitService.RemoveMostRecentEntry(user, this); @@ -87,14 +94,14 @@ public class GuessWhatNumberCommand : ICommand { var effect = wager * 9; newBalance = await Money.NewWagerAsync(gambler.Id, wager, effect, WagerGame.GuessWhatNumber, ct: ctx); - await botInstance.SendChatMessageAsync( + await botInstance.ReplyToUser(message, $"{user.FormatUsername()}, [color={colors[BuiltIn.Keys.KiwiFarmsGreenColor].Value}]correct![/color] You won {await effect.FormatKasinoCurrencyAsync()} and your balance is now {await newBalance.FormatKasinoCurrencyAsync()}", true, autoDeleteAfter: cleanupDelay); return; } newBalance = await Money.NewWagerAsync(gambler.Id, wager, -wager, WagerGame.GuessWhatNumber, ct: ctx); - await botInstance.SendChatMessageAsync( + await botInstance.ReplyToUser(message, $"{user.FormatUsername()}, [color={colors[BuiltIn.Keys.KiwiFarmsRedColor].Value}]wrong![/color] I was thinking of {answer}. Your balance is now {await newBalance.FormatKasinoCurrencyAsync()}", true, autoDeleteAfter: cleanupDelay); } diff --git a/KfChatDotNetBot/Commands/Kasino/KasinoAdminCommands.cs b/KfChatDotNetBot/Commands/Kasino/KasinoAdminCommands.cs index 58a0b3e..3ce6dfb 100644 --- a/KfChatDotNetBot/Commands/Kasino/KasinoAdminCommands.cs +++ b/KfChatDotNetBot/Commands/Kasino/KasinoAdminCommands.cs @@ -21,7 +21,9 @@ public class TempExcludeCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); @@ -87,8 +89,9 @@ public class KasinoGameToggleCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { if (!arguments.TryGetValue("action", out var actionArg)) @@ -168,8 +171,9 @@ public class KasinoGameListCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var response = $"{user.FormatUsername()}, Kasino games:[br]"; diff --git a/KfChatDotNetBot/Commands/Kasino/KasinoEventCommands.cs b/KfChatDotNetBot/Commands/Kasino/KasinoEventCommands.cs index 848536c..75e30bb 100644 --- a/KfChatDotNetBot/Commands/Kasino/KasinoEventCommands.cs +++ b/KfChatDotNetBot/Commands/Kasino/KasinoEventCommands.cs @@ -22,8 +22,9 @@ public class KasinoNewEventCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ @@ -109,8 +110,9 @@ public class KasinoEventStart : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(300); public RateLimitOptionsModel? RateLimitOptions => null; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ @@ -178,8 +180,9 @@ public class KasinoNewEventOption : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ @@ -243,8 +246,9 @@ public class KasinoRemoveEventOption : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ @@ -300,8 +304,9 @@ public class KasinoGetEventInfo : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ @@ -347,8 +352,9 @@ public class KasinoGetEvents : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ diff --git a/KfChatDotNetBot/Commands/Kasino/KasinoUserCommands.cs b/KfChatDotNetBot/Commands/Kasino/KasinoUserCommands.cs index a5d7aac..800b4fe 100644 --- a/KfChatDotNetBot/Commands/Kasino/KasinoUserCommands.cs +++ b/KfChatDotNetBot/Commands/Kasino/KasinoUserCommands.cs @@ -24,7 +24,9 @@ public class GetBalanceCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var gambler = await Money.GetGamblerEntityAsync(user.Id, ct: ctx); @@ -51,7 +53,8 @@ public class GetExclusionCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var gambler = await Money.GetGamblerEntityAsync(user.Id, ct: ctx); @@ -88,7 +91,8 @@ public class SendJuiceCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var logger = LogManager.GetCurrentClassLogger(); @@ -151,7 +155,8 @@ public class RakebackCommand : ICommand MaxInvocations = 1, Window = TimeSpan.FromSeconds(30) }; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); @@ -207,7 +212,8 @@ public class LossbackCommand : ICommand Window = TimeSpan.FromSeconds(30), MaxInvocations = 1 }; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var logger = LogManager.GetCurrentClassLogger(); @@ -267,8 +273,8 @@ public class AbandonKasinoCommand : ICommand Window = TimeSpan.FromSeconds(60), MaxInvocations = 1 }; - - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { if (!message.MessageRawHtmlDecoded.EndsWith("abandon confirm")) @@ -303,7 +309,8 @@ public class PocketWatchCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); @@ -356,6 +363,7 @@ public class HostessCommand : ICommand MaxInvocations = 1, Window = TimeSpan.FromSeconds(30) }; + public bool WhisperCanInvoke => false; private static readonly string[] StaticResponses = [ "For questions regarding your current contract please contact us at contact@bossmanjack.com", @@ -380,7 +388,7 @@ public class HostessCommand : ICommand "You are an overworked fastfood worker at a drive-thru. A confused gambling addict just arrived. Respond with at most two sentences." ]; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var random = RandomShim.Create(StandardRng.Create()); @@ -433,7 +441,8 @@ public class GetDailyDollarCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ diff --git a/KfChatDotNetBot/Commands/Kasino/KenoCommand.cs b/KfChatDotNetBot/Commands/Kasino/KenoCommand.cs index b957262..5b25a1a 100644 --- a/KfChatDotNetBot/Commands/Kasino/KenoCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/KenoCommand.cs @@ -28,6 +28,7 @@ public class KenoCommand : ICommand MaxInvocations = 3, Window = TimeSpan.FromSeconds(10) }; + public bool WhisperCanInvoke => false; private List _playerNumbers = []; private List _casinoNumbers = []; @@ -39,7 +40,7 @@ public class KenoCommand : ICommand private SentMessageTrackerModel? _kenoTable; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ diff --git a/KfChatDotNetBot/Commands/Kasino/LambchopCommand.cs b/KfChatDotNetBot/Commands/Kasino/LambchopCommand.cs index 05ca5a5..1c7830b 100644 --- a/KfChatDotNetBot/Commands/Kasino/LambchopCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/LambchopCommand.cs @@ -29,6 +29,7 @@ public class LambchopCommand : ICommand MaxInvocations = 3, Window = TimeSpan.FromSeconds(15) }; + public bool WhisperCanInvoke => false; private static double _houseEdge = 0.015; // house edge hack? // game assets @@ -58,7 +59,7 @@ public class LambchopCommand : ICommand private const int FIELD_LENGTH = 16; // indicates how many tiles the lamb can cross. default is 16 // WARNING: do NOT change without first implementing dynamic payout logic in LambchopPayoutMultiplier() // has to be an EVEN number > 1 - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ diff --git a/KfChatDotNetBot/Commands/Kasino/LegitCheckCommand.cs b/KfChatDotNetBot/Commands/Kasino/LegitCheckCommand.cs index 9ff595b..a098a2c 100644 --- a/KfChatDotNetBot/Commands/Kasino/LegitCheckCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/LegitCheckCommand.cs @@ -38,12 +38,13 @@ public class LegitCheckCommand : ICommand MaxInvocations = 3, Window = TimeSpan.FromSeconds(30) }; + public bool WhisperCanInvoke => false; // Minimum wagers required for a game to be considered for "luckiest game" // This prevents small sample sizes from skewing results (e.g., 1 win on 1 bet = 200% RTP) private const int MinWagersForLuckiestGame = 10; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); diff --git a/KfChatDotNetBot/Commands/Kasino/LimboCommand.cs b/KfChatDotNetBot/Commands/Kasino/LimboCommand.cs index 639bf33..1b98032 100644 --- a/KfChatDotNetBot/Commands/Kasino/LimboCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/LimboCommand.cs @@ -27,12 +27,13 @@ public class LimboCommand : ICommand MaxInvocations = 10, Window = TimeSpan.FromSeconds(30) }; + public bool WhisperCanInvoke => false; private const double Min = 1; private const double Max = 10000; private decimal HOUSE_EDGE = (decimal)0.98; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { decimal limboNumber; //user number diff --git a/KfChatDotNetBot/Commands/Kasino/MinesCommand.cs b/KfChatDotNetBot/Commands/Kasino/MinesCommand.cs index 8d20f84..c20e7e5 100644 --- a/KfChatDotNetBot/Commands/Kasino/MinesCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/MinesCommand.cs @@ -42,10 +42,11 @@ public class MinesCommand : ICommand MaxInvocations = 3, Window = TimeSpan.FromSeconds(10) }; + public bool WhisperCanInvoke => false; private KasinoMines? KasinoMines; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { diff --git a/KfChatDotNetBot/Commands/Kasino/PlanesCommand.cs b/KfChatDotNetBot/Commands/Kasino/PlanesCommand.cs index fd82f5a..3687351 100644 --- a/KfChatDotNetBot/Commands/Kasino/PlanesCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/PlanesCommand.cs @@ -27,6 +27,7 @@ public class Planes : ICommand MaxInvocations = 3, Window = TimeSpan.FromSeconds(30) }; + public bool WhisperCanInvoke => false; private const string Boost = "πŸ’¨"; private const string PlaneUp = "πŸ›«"; @@ -42,7 +43,7 @@ public class Planes : ICommand private bool _riggedWin = false; private const int CarrierCount = 6; private decimal HOUSE_EDGE = (decimal)0.98; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ diff --git a/KfChatDotNetBot/Commands/Kasino/PlinkoCommand.cs b/KfChatDotNetBot/Commands/Kasino/PlinkoCommand.cs index bc20d99..2cef255 100644 --- a/KfChatDotNetBot/Commands/Kasino/PlinkoCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/PlinkoCommand.cs @@ -27,6 +27,7 @@ public class PlinkoCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(10) }; + public bool WhisperCanInvoke => false; private const string NULLSPACE = "⚫"; private const string EMPTYSPACE = "βšͺ"; @@ -65,7 +66,7 @@ public class PlinkoCommand : ICommand private static Dictionary> validColumnsForRow = new(); - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { VACUUM += 1 - (double)HOUSE_EDGE; diff --git a/KfChatDotNetBot/Commands/Kasino/RainCommand.cs b/KfChatDotNetBot/Commands/Kasino/RainCommand.cs index a5d68b4..510ef88 100644 --- a/KfChatDotNetBot/Commands/Kasino/RainCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/RainCommand.cs @@ -20,8 +20,9 @@ public class RainCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(90); public RateLimitOptionsModel? RateLimitOptions => null; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ diff --git a/KfChatDotNetBot/Commands/Kasino/RouletteCommand.cs b/KfChatDotNetBot/Commands/Kasino/RouletteCommand.cs index a63a520..008e434 100644 --- a/KfChatDotNetBot/Commands/Kasino/RouletteCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/RouletteCommand.cs @@ -42,6 +42,7 @@ public class RouletteCommand : ICommand Window = TimeSpan.FromSeconds(30), Flags = RateLimitFlags.NoAutoDeleteCooldownResponse }; + public bool WhisperCanInvoke => false; private IDatabase? _redisDb; @@ -54,7 +55,7 @@ public class RouletteCommand : ICommand private static readonly HashSet RedNumbers = new() { 2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35 }; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ diff --git a/KfChatDotNetBot/Commands/Kasino/SlotsCommand.cs b/KfChatDotNetBot/Commands/Kasino/SlotsCommand.cs index cd9748e..af37142 100644 --- a/KfChatDotNetBot/Commands/Kasino/SlotsCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/SlotsCommand.cs @@ -39,9 +39,10 @@ public class SlotsCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(15) }; + public bool WhisperCanInvoke => false; private decimal HOUSE_EDGE = (decimal)0.98; - public async Task RunCommand(ChatBot botInstance, MessageModel messagen, UserDbModel user, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { diff --git a/KfChatDotNetBot/Commands/Kasino/WheelCommand.cs b/KfChatDotNetBot/Commands/Kasino/WheelCommand.cs index 0a5acd7..6f732c4 100644 --- a/KfChatDotNetBot/Commands/Kasino/WheelCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/WheelCommand.cs @@ -30,6 +30,7 @@ public class WheelCommand : ICommand MaxInvocations = 3, Window = TimeSpan.FromSeconds(15) }; + public bool WhisperCanInvoke => false; //private static double _houseEdge = 0.015; // house edge hack? // game assets @@ -61,7 +62,7 @@ public class WheelCommand : ICommand }; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ diff --git a/KfChatDotNetBot/Commands/MemeCommands.cs b/KfChatDotNetBot/Commands/MemeCommands.cs index a75e899..98d54ba 100644 --- a/KfChatDotNetBot/Commands/MemeCommands.cs +++ b/KfChatDotNetBot/Commands/MemeCommands.cs @@ -17,7 +17,8 @@ public class InsanityCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { // ReSharper disable once StringLiteralTypo await botInstance.SendChatMessageAsync("definition of insanity = doing the same thing over and over and over excecting a different result, and heres my dumbass trying to get rich every day and losing everythign i fucking touch every fucking time FUCK this bullshit FUCK MY LIEFdefinition of insanity = doing the same thing over and over and over excecting a different result, and heres my dumbass trying to get rich every day and losing everythign i fucking touch every fucking time FUCK this bullshit FUCK MY LIEF"); @@ -31,7 +32,8 @@ public class TwistedCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { // ReSharper disable once StringLiteralTypo await botInstance.SendChatMessageAsync("🦍 πŸ—£ GET IT TWISTED πŸŒͺ , GAMBLE βœ… . PLEASE START GAMBLING πŸ‘ . GAMBLING IS AN INVESTMENT 🎰 AND AN INVESTMENT ONLY πŸ‘ . YOU WILL PROFIT πŸ’° , YOU WILL WIN ❗ ️. YOU WILL DO ALL OF THAT πŸ’― , YOU UNDERSTAND ⁉ ️ YOU WILL BECOME A BILLIONAIRE πŸ’΅ πŸ“ˆ AND REBUILD YOUR FUCKING LIFE 🀯"); @@ -45,7 +47,8 @@ public class ScratchCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { // ReSharper disable once StringLiteralTypo await botInstance.SendChatMessageAsync("πŸ€ πŸ—£ GET IT TWISTED πŸŒͺ, SCRATCH βœ…. PLEASE START SCRATCHING πŸ‘. SCRATCHING YOUR SCABIES SORES IS RELIEF 😌 AND RELIEF ONLY πŸ‘. YOU WILL FEEL BETTER πŸ’ͺ, YOU WILL FIND COMFORT ❗️. YOU WILL DO ALL OF THAT πŸ’―, YOU UNDERSTAND ⁉️ YOU WILL CONQUER THE ITCH 🦠 AND REBUILD YOUR SKIN’S PEACE 🀯", true); @@ -62,7 +65,8 @@ public class CrackedCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var logger = LogManager.GetCurrentClassLogger(); var msg = arguments["msg"].Value.TrimStart('/'); @@ -85,7 +89,8 @@ public class CleanCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([BuiltIn.Keys.BotCleanStartTime, BuiltIn.Keys.TwitchBossmanJackUsername]); @@ -109,7 +114,8 @@ public class RehabCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([BuiltIn.Keys.BotRehabEndTime, BuiltIn.Keys.TwitchBossmanJackUsername]); @@ -141,7 +147,8 @@ public class NextPoVisitCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(120); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var time = await SettingsProvider.GetValueAsync(BuiltIn.Keys.BotPoNextVisit); if (time.Value == null) @@ -179,7 +186,8 @@ public class NextCourtHearingCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(120); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var hearings = (await SettingsProvider.GetValueAsync(BuiltIn.Keys.BotCourtCalendar)).JsonDeserialize>(); if (hearings == null) @@ -233,7 +241,8 @@ public class JailCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([BuiltIn.Keys.BotJailStartTime, BuiltIn.Keys.TwitchBossmanJackUsername]); var start = settings[BuiltIn.Keys.BotJailStartTime]; @@ -254,7 +263,8 @@ public class LastStreamCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ BuiltIn.Keys.TwitchGraphQlPersistedCurrentlyLive, BuiltIn.Keys.TwitchBossmanJackUsername @@ -290,7 +300,8 @@ public class AlmanacCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var text = await SettingsProvider.GetValueAsync(BuiltIn.Keys.BotAlmanacText); if (message.MessageRaw.Contains("almanac plain")) @@ -311,7 +322,8 @@ public class JuiceSportsCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await botInstance.SendChatMessageAsync(":juice: [img]https://i.ddos.lgbt/u/3GJtHq.gif[/img] :juice: [br]β €β €β €β €β €β €β €" + "[img]https://i.ddos.lgbt/u/KAwWMW.webp[/img][br]β €β €β €β €β €β €β €β €β €β €β €" + diff --git a/KfChatDotNetBot/Commands/MomCommands.cs b/KfChatDotNetBot/Commands/MomCommands.cs index 1afff30..00a287a 100644 --- a/KfChatDotNetBot/Commands/MomCommands.cs +++ b/KfChatDotNetBot/Commands/MomCommands.cs @@ -16,8 +16,9 @@ public class MomCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(60); public RateLimitOptionsModel? RateLimitOptions => null; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); diff --git a/KfChatDotNetBot/Commands/NoraCommand.cs b/KfChatDotNetBot/Commands/NoraCommand.cs index 13981b8..461ce9f 100644 --- a/KfChatDotNetBot/Commands/NoraCommand.cs +++ b/KfChatDotNetBot/Commands/NoraCommand.cs @@ -53,8 +53,9 @@ public class NoraCommand : ICommand MaxInvocations = 3, Flags = RateLimitFlags.None }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var userMessage = arguments["message"].Value.Trim(); @@ -75,7 +76,7 @@ public class NoraCommand : ICommand return; } - var resetKey = ConversationContextManager.GetContextKeyAsync(mode, user.KfId, message.RoomId); + var resetKey = ConversationContextManager.GetContextKeyAsync(mode, user.KfId, message.RoomId!.Value); var cleared = await manager.ClearContextAsync(resetKey); await botInstance.SendChatMessageAsync( cleared @@ -166,7 +167,7 @@ public class NoraCommand : ICommand // Compute context key once (used for mood and later for context messages) string? contextKey = null; if (!contextDisabled) - contextKey = ConversationContextManager.GetContextKeyAsync(contextMode, user.KfId, message.RoomId); + contextKey = ConversationContextManager.GetContextKeyAsync(contextMode, user.KfId, message.RoomId!.Value); // Optionally inject user info into the system prompt var userInfoEnabled = settings[BuiltIn.Keys.GrokNoraUserInfoEnabled].Value?.Equals("true", StringComparison.OrdinalIgnoreCase) == true; diff --git a/KfChatDotNetBot/Commands/RainbetCommands.cs b/KfChatDotNetBot/Commands/RainbetCommands.cs index c777ce1..bd676d4 100644 --- a/KfChatDotNetBot/Commands/RainbetCommands.cs +++ b/KfChatDotNetBot/Commands/RainbetCommands.cs @@ -17,7 +17,8 @@ public class RainbetStatsCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var window = Convert.ToInt32(arguments["window"].Value); var start = DateTimeOffset.UtcNow.AddHours(-window); @@ -44,7 +45,8 @@ public class RainbetRecentBetCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var settings = await SettingsProvider.GetMultipleValuesAsync([ BuiltIn.Keys.KiwiFarmsGreenColor, BuiltIn.Keys.KiwiFarmsRedColor, BuiltIn.Keys.HowlggDivisionAmount diff --git a/KfChatDotNetBot/Commands/RestreamCommands.cs b/KfChatDotNetBot/Commands/RestreamCommands.cs index ffc13a1..e720e05 100644 --- a/KfChatDotNetBot/Commands/RestreamCommands.cs +++ b/KfChatDotNetBot/Commands/RestreamCommands.cs @@ -17,7 +17,8 @@ public class GetRestreamCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var url = await SettingsProvider.GetValueAsync(BuiltIn.Keys.RestreamUrl); @@ -35,7 +36,8 @@ public class SetRestreamCommand : ICommand public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await SettingsProvider.SetValueAsync(BuiltIn.Keys.RestreamUrl, arguments["url"].Value); @@ -53,7 +55,8 @@ public class SelfPromoCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); @@ -82,7 +85,8 @@ public class GetRestreamPlainCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var url = await SettingsProvider.GetValueAsync(BuiltIn.Keys.RestreamUrl); diff --git a/KfChatDotNetBot/Commands/ShopCommands.cs b/KfChatDotNetBot/Commands/ShopCommands.cs index 24c21ce..a373ab9 100644 --- a/KfChatDotNetBot/Commands/ShopCommands.cs +++ b/KfChatDotNetBot/Commands/ShopCommands.cs @@ -22,9 +22,8 @@ public class ShopGlobalResetCommand : ICommand MaxInvocations = 1, Window = TimeSpan.FromSeconds(120) }; - - - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -46,6 +45,7 @@ public class ShopGlobalLoanResetCommand : ICommand public string? HelpText => "!beg to beg for a loan"; public UserRight RequiredRight => UserRight.TrueAndHonest; public TimeSpan Timeout => TimeSpan.FromSeconds(30); + public bool WhisperCanInvoke => false; public RateLimitOptionsModel? RateLimitOptions => new RateLimitOptionsModel { MaxInvocations = 1, @@ -53,7 +53,7 @@ public class ShopGlobalLoanResetCommand : ICommand }; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -83,9 +83,10 @@ public class ShopHelpCommand : ICommand MaxInvocations = 1, Window = TimeSpan.FromSeconds(120) }; + public bool WhisperCanInvoke => false; private const string KasinoShopHelpLink = "https://i.ddos.lgbt/raw/pgTFLJ.html"; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); var gambler = await Money.GetGamblerEntityAsync(user.Id, ct: ctx); @@ -122,9 +123,10 @@ public class ShopListCommand : ICommand MaxInvocations = 1, Window = TimeSpan.FromSeconds(120) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); var gambler = await Money.GetGamblerEntityAsync(user.Id, ct: ctx); @@ -179,9 +181,10 @@ public class ShopSellCommand : ICommand MaxInvocations = 1, Window = TimeSpan.FromSeconds(120) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -219,7 +222,8 @@ public class BegCommand : ICommand MaxInvocations = 1, Window = TimeSpan.FromSeconds(120) }; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); var gambler = await Money.GetGamblerEntityAsync(user.Id, ct: ctx); @@ -252,7 +256,8 @@ public class LoanCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); if (botInstance.BotServices.KasinoShop == null) @@ -298,8 +303,8 @@ public class RepaymentCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; - - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -351,8 +356,9 @@ public class ShopSmashableCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -402,8 +408,9 @@ public class ShopInvestmentsCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -455,7 +462,8 @@ public class ShopUpdateGambler : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); if (botInstance.BotServices.KasinoShop == null) @@ -495,8 +503,9 @@ public class ShopShoeCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -547,8 +556,9 @@ public class ShopSkinCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -593,8 +603,9 @@ public class ShopStakeCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -644,8 +655,9 @@ public class ShopUnstakeCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -695,8 +707,9 @@ public class SmashCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -727,8 +740,9 @@ public class SponsorShipCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -759,8 +773,9 @@ public class SponsorShipBonusCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -791,8 +806,9 @@ public class EndSponsorShipCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -833,8 +849,9 @@ public class ShopDrugsCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -939,8 +956,9 @@ public class ShopCarCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { //civic audi bentley bmw var cleanupDelay = TimeSpan.FromSeconds(10); @@ -1014,8 +1032,9 @@ public class ShopDepositCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -1057,8 +1076,9 @@ public class ShopCarJobCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -1093,8 +1113,9 @@ public class ShopWithdrawCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -1152,8 +1173,9 @@ public class FlipSwitchCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -1182,8 +1204,9 @@ public class PushButtonCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -1212,8 +1235,9 @@ public class PullLeverCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -1241,8 +1265,9 @@ public class DialCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -1272,8 +1297,9 @@ public class KeypadCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); @@ -1305,8 +1331,9 @@ public class PanelCommand : ICommand MaxInvocations = 2, Window = TimeSpan.FromSeconds(60) }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var cleanupDelay = TimeSpan.FromSeconds(10); diff --git a/KfChatDotNetBot/Commands/TestCommands.cs b/KfChatDotNetBot/Commands/TestCommands.cs index 096bfae..aaa72b5 100644 --- a/KfChatDotNetBot/Commands/TestCommands.cs +++ b/KfChatDotNetBot/Commands/TestCommands.cs @@ -18,7 +18,8 @@ public class EditTestCommand : ICommand // Increased timeout as it has to wait for Sneedchat to echo the message and that can be slow sometimes public TimeSpan Timeout => TimeSpan.FromSeconds(60); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var logger = LogManager.GetCurrentClassLogger(); var msg = WebUtility.HtmlDecode(arguments["msg"].Value); @@ -65,7 +66,8 @@ public class TimeoutTestCommand : ICommand // Increased timeout as it has to wait for Sneedchat to echo the message and that can be slow sometimes public TimeSpan Timeout => TimeSpan.FromSeconds(15); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await Task.Delay(TimeSpan.FromMinutes(1), ctx); } @@ -82,7 +84,8 @@ public class ExceptionTestCommand : ICommand // Increased timeout as it has to wait for Sneedchat to echo the message and that can be slow sometimes public TimeSpan Timeout => TimeSpan.FromSeconds(15); public RateLimitOptionsModel? RateLimitOptions => null; - public Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { throw new Exception("Caused by the test exception command"); } @@ -99,7 +102,8 @@ public class LengthLimitTestCommand : ICommand // Increased timeout as it has to wait for Sneedchat to echo the message and that can be slow sometimes public TimeSpan Timeout => TimeSpan.FromSeconds(15); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var logger = LogManager.GetCurrentClassLogger(); var niceTruncation = await botInstance.SendChatMessageAsync("The quick brown fox jumps over the lazy dog.", @@ -140,7 +144,8 @@ public class RateLimitTestCommand : ICommand MaxInvocations = 3, Window = TimeSpan.FromSeconds(60) }; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await botInstance.SendChatMessageAsync("Nigger", true); } diff --git a/KfChatDotNetBot/Commands/TimeCommand.cs b/KfChatDotNetBot/Commands/TimeCommand.cs index 1d9d4ac..4b17afb 100644 --- a/KfChatDotNetBot/Commands/TimeCommand.cs +++ b/KfChatDotNetBot/Commands/TimeCommand.cs @@ -12,10 +12,11 @@ public class TimeCommand : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => true; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var bmt = new DateTimeOffset(TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")), TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time").BaseUtcOffset); - await botInstance.SendChatMessageAsync($"It's currently {bmt:dddd h:mm:ss tt} BMT"); + await botInstance.ReplyToUser(message, $"It's currently {bmt:dddd h:mm:ss tt} BMT"); } } \ No newline at end of file diff --git a/KfChatDotNetBot/Commands/UtilityCommands.cs b/KfChatDotNetBot/Commands/UtilityCommands.cs index e3ffeb6..6407356 100644 --- a/KfChatDotNetBot/Commands/UtilityCommands.cs +++ b/KfChatDotNetBot/Commands/UtilityCommands.cs @@ -19,7 +19,8 @@ public class TempSuppressGambaMessages : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { botInstance.BotServices.TemporarilySuppressGambaMessages = true; await botInstance.SendChatMessageAsync("No more gamba notifs", true); @@ -36,7 +37,8 @@ public class EnableGambaMessages : ICommand public UserRight RequiredRight => UserRight.Guest; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { botInstance.BotServices.TemporarilySuppressGambaMessages = false; await botInstance.SendChatMessageAsync("Gamba notifs back on the menu", true); @@ -53,7 +55,8 @@ public class GetVersionCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var version = Assembly.GetEntryAssembly()? .GetCustomAttribute()?.InformationalVersion; @@ -82,7 +85,8 @@ public class GetLastActivity : ICommand MaxInvocations = 3, Window = TimeSpan.FromSeconds(10) }; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var lastActive = await SettingsProvider.GetValueAsync(BuiltIn.Keys.BossmanLastSighting); if (lastActive.Value == null) diff --git a/KfChatDotNetBot/Commands/WhoisCommand.cs b/KfChatDotNetBot/Commands/WhoisCommand.cs index 5904ebb..e8188f1 100644 --- a/KfChatDotNetBot/Commands/WhoisCommand.cs +++ b/KfChatDotNetBot/Commands/WhoisCommand.cs @@ -18,7 +18,8 @@ public class WhoisCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await using var db = new ApplicationDbContext(); var query = arguments["user"].Value.TrimStart('@').TrimEnd(',').TrimEnd(); @@ -47,7 +48,8 @@ public class WhoamiCommand : ICommand public UserRight RequiredRight => UserRight.Loser; public TimeSpan Timeout => TimeSpan.FromSeconds(10); public RateLimitOptionsModel? RateLimitOptions => null; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) + public bool WhisperCanInvoke => false; + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, your addy is {user.KfId}", true); } diff --git a/KfChatDotNetBot/Commands/XeetEmbedCommand.cs b/KfChatDotNetBot/Commands/XeetEmbedCommand.cs index cbecdc8..15a6fbf 100644 --- a/KfChatDotNetBot/Commands/XeetEmbedCommand.cs +++ b/KfChatDotNetBot/Commands/XeetEmbedCommand.cs @@ -39,8 +39,9 @@ public class XeetEmbedCommand : ICommand // Really don't want to get rate-limited by FxTwitter hence global rate-limits Flags = RateLimitFlags.Global }; + public bool WhisperCanInvoke => false; - public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { var kiwiFarmsUsername = await SettingsProvider.GetValueAsync(BuiltIn.Keys.KiwiFarmsUsername); diff --git a/KfChatDotNetBot/Models/BotCommandMessageModel.cs b/KfChatDotNetBot/Models/BotCommandMessageModel.cs new file mode 100644 index 0000000..955ded6 --- /dev/null +++ b/KfChatDotNetBot/Models/BotCommandMessageModel.cs @@ -0,0 +1,44 @@ +using KfChatDotNetWsClient.Models.Events; + +namespace KfChatDotNetBot.Models; + +public class BotCommandMessageModel +{ + /// + /// Author of the message + /// + public required UserModel Author { get; set; } + /// + /// Recipient of the message if this is a whisper + /// + public UserModel? Recipient { get; set; } + /// + /// Message rendered into HTML + /// + public required string Message { get; set; } + /// + /// Original message with BBCode intact (but HTML-encoded) + /// + public required string MessageRaw { get; set; } + /// + /// Date and time the message was sent + /// + public required DateTimeOffset MessageDate { get; set; } + /// + /// Original message with BBCode intact and HTML decoded + /// + public required string MessageRawHtmlDecoded { get; set; } + /// + /// Chat UUID reference to the message (null for whispers) + /// + public string? MessageUuid { get; set; } + /// + /// When the message was edited (null if never edited or a whisper) + /// + public DateTimeOffset? MessageEditDate { get; set; } + /// + /// Room ID where this message was received. (null if a whisper) + /// + public int? RoomId { get; set; } + public required bool IsWhisper { get; set; } +} \ No newline at end of file diff --git a/KfChatDotNetBot/Models/SentMessageTrackerModel.cs b/KfChatDotNetBot/Models/SentMessageTrackerModel.cs index fa4aa93..372c5ec 100644 --- a/KfChatDotNetBot/Models/SentMessageTrackerModel.cs +++ b/KfChatDotNetBot/Models/SentMessageTrackerModel.cs @@ -4,6 +4,9 @@ public class SentMessageTrackerModel { // Unique GUID for each message public required string Reference { get; set; } + /// + /// The raw message. If this was a whisper, it'll include the '/w id msg' payload + /// public required string Message { get; set; } public required SentMessageTrackerStatus Status { get; set; } public string? ChatMessageUuid { get; set; } @@ -15,6 +18,11 @@ public class SentMessageTrackerModel /// When edited multiple times, it'll be the most recent edit /// public DateTimeOffset? LastEdited { get; set; } = null; + public required SentMessageType Type { get; set; } + /// + /// Contains just the whisper message + /// + public string? WhisperMessage { get; set; } } public enum SentMessageTrackerStatus @@ -29,4 +37,10 @@ public enum SentMessageTrackerStatus ChatDisconnected, // Was held in the replay buffer due to a disconnect, but there were too many messages ahead of it and so was culled Lost +} + +public enum SentMessageType +{ + ChatMessage, + Whisper } \ No newline at end of file diff --git a/KfChatDotNetBot/Services/BotCommands.cs b/KfChatDotNetBot/Services/BotCommands.cs index bd68467..c74d61d 100644 --- a/KfChatDotNetBot/Services/BotCommands.cs +++ b/KfChatDotNetBot/Services/BotCommands.cs @@ -40,7 +40,7 @@ internal class BotCommands _ = CleanupExpiredRateLimitEntriesTask(); } - internal void ProcessMessage(MessageModel message) + internal void ProcessMessage(BotCommandMessageModel message) { if (string.IsNullOrEmpty(message.MessageRaw)) { @@ -57,6 +57,7 @@ internal class BotCommands var match = regex.Match(messageTrimmed); if (!match.Success) continue; _logger.Debug($"Message matches {regex}"); + if (!command.WhisperCanInvoke && message.IsWhisper) return; using var db = new ApplicationDbContext(); var user = db.Users.AsNoTracking().FirstOrDefault(u => u.KfId == message.Author.Id); // This should never happen as brand-new users are created upon join @@ -73,6 +74,11 @@ internal class BotCommands if (kasinoCommand && Money.IsPermanentlyBannedAsync(user.Id, _cancellationToken).Result) { + if (message.IsWhisper) + { + _ = _bot.SendWhisperAsync(message.Author.Id, $"@{message.Author.Username}, you've been permanently banned from the kasino. Contact support for more information."); + return; + } _bot.SendChatMessage($"@{message.Author.Username}, you've been permanently banned from the kasino. Contact support for more information.", true); return; } @@ -87,6 +93,12 @@ internal class BotCommands var exclusion = Money.GetActiveExclusionAsync(gambler.Id, ct: _cancellationToken).Result; if (exclusion != null) { + if (message.IsWhisper) + { + _ = _bot.SendWhisperAsync(message.Author.Id, + $"@{message.Author.Username}, you're self excluded from the kasino for another {(exclusion.Expires - DateTimeOffset.UtcNow).Humanize(precision: 3)}"); + return; + } _bot.SendChatMessage( $"@{message.Author.Username}, you're self excluded from the kasino for another {(exclusion.Expires - DateTimeOffset.UtcNow).Humanize(precision: 3)}", true); return; @@ -96,7 +108,15 @@ internal class BotCommands if (user.UserRight < command.RequiredRight) { - _bot.SendChatMessage($"@{message.Author.Username}, you do not have access to use this command. Your rank: {user.UserRight.Humanize()}; Required rank: {command.RequiredRight.Humanize()}", true); + if (message.IsWhisper) + { + _ = _bot.SendWhisperAsync(message.Author.Id, + $"@{message.Author.Username}, you do not have access to use this command. Your rank: {user.UserRight.Humanize()}; Required rank: {command.RequiredRight.Humanize()}"); + } + else + { + _bot.SendChatMessage($"@{message.Author.Username}, you do not have access to use this command. Your rank: {user.UserRight.Humanize()}; Required rank: {command.RequiredRight.Humanize()}", true); + } if (continueAfterProcess) continue; break; } @@ -116,8 +136,8 @@ internal class BotCommands } } } - - private async Task ProcessMessageAsync(ICommand command, MessageModel message, UserDbModel user, GroupCollection arguments) + + private async Task ProcessMessageAsync(ICommand command, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments) { var cts = new CancellationTokenSource(command.Timeout); var task = Task.Run(() => command.RunCommand(_bot, message, user, arguments, cts.Token), cts.Token); diff --git a/KfChatDotNetBot/Settings/BuiltIn.cs b/KfChatDotNetBot/Settings/BuiltIn.cs index a4e4c24..090eb03 100644 --- a/KfChatDotNetBot/Settings/BuiltIn.cs +++ b/KfChatDotNetBot/Settings/BuiltIn.cs @@ -564,6 +564,8 @@ public static class BuiltIn public static string ShuffleDotUsBmjVipLevel = "ShuffleDotUs.BmjVipLevel"; [BuiltInSetting("Bossman's super secret user ID on .us", SettingValueType.Text, "e2faee09-8ebb-4a22-8793-59aefc8191e5")] public static string ShuffleDotUsBmjUserId = "ShuffleDotUs.BmjUserId"; + [BuiltInSetting("UUID for the current MOTD message UUID", SettingValueType.Text)] + public static string KiwiFarmsMotdUuid = "KiwiFarms.MotdUuid"; } } diff --git a/KfChatDotNetWsClient/ChatClient.cs b/KfChatDotNetWsClient/ChatClient.cs index 6e54ad5..386a5a4 100644 --- a/KfChatDotNetWsClient/ChatClient.cs +++ b/KfChatDotNetWsClient/ChatClient.cs @@ -26,6 +26,8 @@ public class ChatClient public event EventHandlers.OnUnknownCommand? OnUnknownCommand; public event EventHandlers.OnPermissionsEventHandler? OnPermissions; public event EventHandlers.OnSystemMessage? OnSystemMessage; + public event EventHandlers.OnMotdEventHandler? OnMotd; + public event EventHandlers.OnWhisperEventHandler? OnWhisper; private WebsocketClient? _wsClient; private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private ChatClientConfigModel _config; @@ -210,6 +212,20 @@ public class ChatClient WsDeleteMessagesReceived(message); return; } + + if (packetType.ContainsKey("whisper")) + { + _logger.Debug("Looks like this is a whisper packet"); + WsWhisper(message); + return; + } + + if (packetType.ContainsKey("motd")) + { + _logger.Debug("Looks like this is an MOTD packet"); + WsMotd(message); + return; + } _logger.Info($"Received packet this was not handled: {message.Text}"); } @@ -277,6 +293,13 @@ public class ChatClient await _wsClient.SendInstant($"/edit {payload}"); } + public async Task SetMotd(string messageUuid) + { + _logger.Debug($"Setting {messageUuid} as the MOTD"); + if (_wsClient == null) throw new WebSocketNotInitializedException(); + await _wsClient.SendInstant($"/motd {messageUuid}"); + } + private void WsDeleteMessagesReceived(ResponseMessage message) { var data = JsonSerializer.Deserialize(message.Text!); @@ -392,6 +415,83 @@ public class ChatClient _logger.Error(e); } } + + private void WsWhisper(ResponseMessage message) + { + var data = JsonSerializer.Deserialize(message.Text).GetProperty("whisper") + .Deserialize(); + var model = new WhisperModel + { + Author = new UserModel + { + Id = data.Author.Id, + Username = data.Author.Username, + AvatarUrl = data.Author.AvatarUrl + }, + Recipient = new UserModel + { + Id = data.Recipient.Id, + Username = data.Recipient.Username, + AvatarUrl = data.Recipient.AvatarUrl + }, + Message = data.Message, + MessageRaw = data.MessageRaw, + MessageRawHtmlDecoded = WebUtility.HtmlDecode(data.MessageRaw), + MessageDate = DateTimeOffset.FromUnixTimeSeconds(data.MessageDate) + }; + try + { + OnWhisper?.Invoke(this, model); + } + catch (Exception e) + { + _logger.Error("WS handler for whisper threw an exception when invoking OnWhisper"); + _logger.Error(e); + } + } + + private void WsMotd(ResponseMessage message) + { + var msg = JsonSerializer.Deserialize(message.Text).GetProperty("motd") + .Deserialize(); + + var model = new MessageModel + { + Author = new UserModel + { + Id = msg.Author.Id, + Username = msg.Author.Username, + AvatarUrl = msg.Author.AvatarUrl, + // It isn't sent on chat messages + LastActivity = null + }, + Message = msg.Message, + MessageUuid = msg.MessageUuid, + MessageRaw = msg.MessageRaw, + RoomId = msg.RoomId, + MessageRawHtmlDecoded = WebUtility.HtmlDecode(msg.MessageRaw), + MessageDate = DateTimeOffset.FromUnixTimeSeconds(msg.MessageDate) + }; + + if (msg.MessageEditDate == 0) + { + model.MessageEditDate = null; + } + else + { + model.MessageEditDate = DateTimeOffset.FromUnixTimeSeconds(msg.MessageEditDate); + } + + try + { + OnMotd?.Invoke(this, model); + } + catch (Exception e) + { + _logger.Error("The handler for MOTD messages threw an exception"); + _logger.Error(e); + } + } } public class WebSocketNotInitializedException : Exception; \ No newline at end of file diff --git a/KfChatDotNetWsClient/Models/Events/EventHandlers.cs b/KfChatDotNetWsClient/Models/Events/EventHandlers.cs index ce80166..aa833d0 100644 --- a/KfChatDotNetWsClient/Models/Events/EventHandlers.cs +++ b/KfChatDotNetWsClient/Models/Events/EventHandlers.cs @@ -29,4 +29,8 @@ public class EventHandlers public delegate void OnPermissionsEventHandler(object sender, PermissionsJsonModel permissions); public delegate void OnSystemMessage(object sender, string message); + + public delegate void OnMotdEventHandler(object sender, MessageModel message); + + public delegate void OnWhisperEventHandler(object sender, WhisperModel whisper); } \ No newline at end of file diff --git a/KfChatDotNetWsClient/Models/Events/WhisperModel.cs b/KfChatDotNetWsClient/Models/Events/WhisperModel.cs new file mode 100644 index 0000000..da371bb --- /dev/null +++ b/KfChatDotNetWsClient/Models/Events/WhisperModel.cs @@ -0,0 +1,12 @@ +namespace KfChatDotNetWsClient.Models.Events; + +public class WhisperModel +{ + public required UserModel Author { get; set; } + public required UserModel Recipient { get; set; } + public required string Message { get; set; } + public required string MessageRaw { get; set; } + public required DateTimeOffset MessageDate { get; set; } + public required string MessageRawHtmlDecoded { get; set; } + +} \ No newline at end of file diff --git a/KfChatDotNetWsClient/Models/Json/WhisperJsonModel.cs b/KfChatDotNetWsClient/Models/Json/WhisperJsonModel.cs new file mode 100644 index 0000000..6d29ade --- /dev/null +++ b/KfChatDotNetWsClient/Models/Json/WhisperJsonModel.cs @@ -0,0 +1,34 @@ +using System.Text.Json.Serialization; + +namespace KfChatDotNetWsClient.Models.Json; + +// { +// "whisper": { +// "author": { +// "id": 58227, +// "username": "Flaming Dumpster", +// "avatar_url": "/data/avatars/m/58/58227.jpg?1771372231" +// }, +// "recipient": { +// "id": 1, +// "username": "Null", +// "avatar_url": "/data/avatars/m/0/1.jpg?1767201853" +// }, +// "message": "nigger", +// "message_raw": "nigger", +// "message_date": 1773881876 +// } +// } +public class WhisperJsonModel +{ + [JsonPropertyName("author")] + public required MessagesJsonModel.AuthorModel Author { get; set; } + [JsonPropertyName("recipient")] + public required MessagesJsonModel.AuthorModel Recipient { get; set; } + [JsonPropertyName("message")] + public required string Message { get; set; } + [JsonPropertyName("message_raw")] + public required string MessageRaw { get; set; } + [JsonPropertyName("message_date")] + public required int MessageDate { get; set; } +} \ No newline at end of file