From c8016b4fc675ff1cbc87a29084b56785f7a8beaa Mon Sep 17 00:00:00 2001 From: barelyprofessional <150058423+barelyprofessional@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:34:36 -0600 Subject: [PATCH] Update for new chyat --- KfChatDotNetBot/ChatBot.cs | 18 ++--- KfChatDotNetBot/Commands/AdminCommands.cs | 4 +- .../Commands/Kasino/KasinoEventCommands.cs | 2 +- .../Commands/Kasino/KenoCommand.cs | 6 +- .../Commands/Kasino/LambchopCommand.cs | 4 +- .../Commands/Kasino/MinesCommand.cs | 4 +- .../Commands/Kasino/PlanesCommand.cs | 12 ++-- .../Commands/Kasino/PlinkoCommand.cs | 6 +- .../Commands/Kasino/RainCommand.cs | 6 +- .../Commands/Kasino/RouletteCommand.cs | 18 ++--- .../Commands/Kasino/WheelCommand.cs | 2 +- KfChatDotNetBot/Commands/MemeCommands.cs | 16 ++--- KfChatDotNetBot/Commands/TestCommands.cs | 24 +++---- .../Models/SeenMessageMetadataModel.cs | 2 +- .../Models/SentMessageTrackerModel.cs | 2 +- KfChatDotNetBot/Services/BotServices.cs | 12 ++-- KfChatDotNetBot/Services/KasinoMines.cs | 38 +++++------ KfChatDotNetWsClient/ChatClient.cs | 65 ++++++++++++++++--- .../Models/Events/EventHandlers.cs | 4 ++ .../Models/Events/MessageModel.cs | 2 +- .../Models/Json/EditMessageJsonModel.cs | 4 +- .../Models/Json/MessagesJsonModel.cs | 4 +- .../Models/Json/PermissionsJsonModel.cs | 27 ++++++++ 23 files changed, 178 insertions(+), 104 deletions(-) create mode 100644 KfChatDotNetWsClient/Models/Json/PermissionsJsonModel.cs diff --git a/KfChatDotNetBot/ChatBot.cs b/KfChatDotNetBot/ChatBot.cs index 5ed63c5..bcd7eef 100644 --- a/KfChatDotNetBot/ChatBot.cs +++ b/KfChatDotNetBot/ChatBot.cs @@ -193,7 +193,7 @@ public class ChatBot foreach (var deletion in _scheduledDeletions) { if (deletion.DeleteAt > now) continue; - if (deletion.Message.ChatMessageId == null) + if (deletion.Message.ChatMessageUuid == null) { _logger.Error($"Can't clean up {deletion.Message.Reference} as it doesn't have a chat message ID"); if (failures.TryGetValue(deletion.Message.Reference, out var failure)) @@ -213,7 +213,7 @@ public class ChatBot } continue; } - await KfClient.DeleteMessageAsync(deletion.Message.ChatMessageId.Value); + await KfClient.DeleteMessageAsync(deletion.Message.ChatMessageUuid); removals.Add(deletion); } foreach (var removal in removals) @@ -295,7 +295,7 @@ public class ChatBot // Update last edit timestamp if (message.Author.Username == settings[BuiltIn.Keys.KiwiFarmsUsername].Value && message.MessageEditDate != null) { - var sentMessage = SentMessages.FirstOrDefault(x => x.ChatMessageId == message.MessageId); + var sentMessage = SentMessages.FirstOrDefault(x => x.ChatMessageUuid == message.MessageUuid); if (sentMessage != null) { sentMessage.LastEdited = message.MessageEditDate.Value; @@ -321,14 +321,14 @@ public class ChatBot // back to you. So this fallback should be generally correct and will account for the occasional // mismatch due to messages not being 1:1 with what we thought we sent _logger.Info("Just going to lazily associate it with the latest message"); - latest.ChatMessageId = message.MessageId; + latest.ChatMessageUuid = message.MessageUuid; latest.Delay = DateTimeOffset.UtcNow - latest.SentAt; latest.Status = SentMessageTrackerStatus.ResponseReceived; } } else { - sentMessage.ChatMessageId = message.MessageId; + sentMessage.ChatMessageUuid = message.MessageUuid; sentMessage.Delay = DateTimeOffset.UtcNow - sentMessage.SentAt; sentMessage.Status = SentMessageTrackerStatus.ResponseReceived; } @@ -350,7 +350,7 @@ public class ChatBot // So this avoids reprocessing messages on reconnect while being able to handle edits, even if the edit came // during a disconnect / reconnect event if (!_seenMessages.Any(msg => - msg.MessageId == message.MessageId && msg.LastEdited == message.MessageEditDate) && + msg.MessageUuid == message.MessageUuid && msg.LastEdited == message.MessageEditDate) && !InitialStartCooldown) { _logger.Debug("Passing message to command interface"); @@ -366,14 +366,14 @@ public class ChatBot } // Update or add the element to keep it in sync - var existingMsg = _seenMessages.FirstOrDefault(msg => msg.MessageId == message.MessageId); + var existingMsg = _seenMessages.FirstOrDefault(msg => msg.MessageUuid == message.MessageUuid); if (existingMsg != null) { existingMsg.LastEdited = message.MessageEditDate; } else { - _seenMessages.Add(new SeenMessageMetadataModel {MessageId = message.MessageId, LastEdited = message.MessageEditDate}); + _seenMessages.Add(new SeenMessageMetadataModel {MessageUuid = message.MessageUuid, LastEdited = message.MessageEditDate}); } UpdateUserLastActivityAsync(message.Author.Id, WhoWasActivityType.Message).Wait(_cancellationToken); // Strip weird control characters and just allow basic punctuation + whitespace @@ -546,7 +546,7 @@ public class ChatBot } var patienceEnds = DateTimeOffset.UtcNow.Add(patience.Value); - while (message.ChatMessageId == null) + while (message.ChatMessageUuid == null) { if (DateTimeOffset.UtcNow > patienceEnds) return false; if (message.Status is SentMessageTrackerStatus.Lost or SentMessageTrackerStatus.NotSending) return false; diff --git a/KfChatDotNetBot/Commands/AdminCommands.cs b/KfChatDotNetBot/Commands/AdminCommands.cs index 462cefa..b11faa5 100644 --- a/KfChatDotNetBot/Commands/AdminCommands.cs +++ b/KfChatDotNetBot/Commands/AdminCommands.cs @@ -337,12 +337,12 @@ public class DeleteMessagesCommand : ICommand .TakeLast(amount); foreach (var msg in messages) { - if (msg.ChatMessageId == null) + if (msg.ChatMessageUuid == null) { continue; } - await botInstance.KfClient.DeleteMessageAsync(msg.ChatMessageId.Value); + await botInstance.KfClient.DeleteMessageAsync(msg.ChatMessageUuid); } } } diff --git a/KfChatDotNetBot/Commands/Kasino/KasinoEventCommands.cs b/KfChatDotNetBot/Commands/Kasino/KasinoEventCommands.cs index 9db968f..848536c 100644 --- a/KfChatDotNetBot/Commands/Kasino/KasinoEventCommands.cs +++ b/KfChatDotNetBot/Commands/Kasino/KasinoEventCommands.cs @@ -153,7 +153,7 @@ public class KasinoEventStart : ICommand var msg = $":!: :!: A Keno Kasino event has started! :!: :!:[br]{targetEvent.EventText}[br]{guide}"; var msgIds = await botInstance.SendChatMessagesAsync(msg.FancySplitMessage(partSeparator: "[br]"), true); var i = 0; - while (msgIds[0].ChatMessageId != null) + while (msgIds[0].ChatMessageUuid != null) { i++; await Task.Delay(TimeSpan.FromMilliseconds(100), ctx); diff --git a/KfChatDotNetBot/Commands/Kasino/KenoCommand.cs b/KfChatDotNetBot/Commands/Kasino/KenoCommand.cs index a948a10..baae428 100644 --- a/KfChatDotNetBot/Commands/Kasino/KenoCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/KenoCommand.cs @@ -227,7 +227,7 @@ public class KenoCommand : ICommand _kenoTable = await botInstance.SendChatMessageAsync(displayMessage, true); var i = 0; - while (_kenoTable.ChatMessageId == null) + while (_kenoTable.ChatMessageUuid == null) { i++; if (_kenoTable.Status is SentMessageTrackerStatus.NotSending or SentMessageTrackerStatus.Lost) return; @@ -235,7 +235,7 @@ public class KenoCommand : ICommand await Task.Delay(100); } - if (_kenoTable.ChatMessageId == null) + if (_kenoTable.ChatMessageUuid == null) { throw new Exception($"_kenoTable chat message ID never got populated. Tracker status is: {_kenoTable?.Status}"); } @@ -269,7 +269,7 @@ public class KenoCommand : ICommand } displayMessage += "[br]"; } - await botInstance.KfClient.EditMessageAsync(_kenoTable.ChatMessageId!.Value, displayMessage); + await botInstance.KfClient.EditMessageAsync(_kenoTable.ChatMessageUuid, displayMessage); await Task.Delay(frameDelay); if (displayMessage.Length <= 79 && displayMessage.Contains(BlankSpaceDisplay) && (displayMessage.Contains(CasinoNumberDisplay) || displayMessage.Contains(MatchRevealDisplay) || diff --git a/KfChatDotNetBot/Commands/Kasino/LambchopCommand.cs b/KfChatDotNetBot/Commands/Kasino/LambchopCommand.cs index e7a8a2c..05ca5a5 100644 --- a/KfChatDotNetBot/Commands/Kasino/LambchopCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/LambchopCommand.cs @@ -145,7 +145,7 @@ public class LambchopCommand : ICommand var lambChopDisplayMessage = await botInstance.SendChatMessageAsync(ConvertLambchopFieldToString(tiles, hazards, true), true, autoDeleteAfter: cleanupDelay); - while (lambChopDisplayMessage.ChatMessageId == null) + while (lambChopDisplayMessage.ChatMessageUuid == null) { await Task.Delay(50, ctx); // wait until first message is fully sent if (lambChopDisplayMessage.Status is SentMessageTrackerStatus.Lost or SentMessageTrackerStatus.NotSending) @@ -307,7 +307,7 @@ public class LambchopCommand : ICommand async Task UpdateGameAsync(string? updateText = null) { updateText ??= ConvertLambchopFieldToString(tiles, hazards, false); - await botInstance.KfClient.EditMessageAsync(lambChopDisplayMessage.ChatMessageId!.Value, updateText); + await botInstance.KfClient.EditMessageAsync(lambChopDisplayMessage.ChatMessageUuid, updateText); await Task.Delay(TimeSpan.FromMilliseconds(FRAME_DELAY), ctx); } } diff --git a/KfChatDotNetBot/Commands/Kasino/MinesCommand.cs b/KfChatDotNetBot/Commands/Kasino/MinesCommand.cs index 07d1be5..6b85a75 100644 --- a/KfChatDotNetBot/Commands/Kasino/MinesCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/MinesCommand.cs @@ -269,11 +269,11 @@ public class MinesCommand : ICommand var lastmsg = KasinoMines.ActiveGames[gambler.Id].LastMessageId; SentMessageTrackerModel msg; - if (lastmsg == 0) + if (lastmsg == null) { msg = (await botInstance.SendChatMessageAsync($"{KasinoMines.ActiveGames[gambler.Id].ToString()}", true)); await botInstance.WaitForChatMessageAsync(msg, ct: ctx); - if (msg.ChatMessageId == null) throw new InvalidOperationException("Timed out waiting for the message"); + if (msg.ChatMessageUuid == null) throw new InvalidOperationException("Timed out waiting for the message"); } else { diff --git a/KfChatDotNetBot/Commands/Kasino/PlanesCommand.cs b/KfChatDotNetBot/Commands/Kasino/PlanesCommand.cs index 18ed19c..1c5575e 100644 --- a/KfChatDotNetBot/Commands/Kasino/PlanesCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/PlanesCommand.cs @@ -119,7 +119,7 @@ public class Planes : ICommand var planesDisplay = GetPreGameBoard(-3, planesBoard2, plane, CarrierCount, noseUp); var msgId = await botInstance.SendChatMessageAsync(planesDisplay, true); var num = 0; - while (msgId.ChatMessageId == null) + while (msgId.ChatMessageUuid == null) { num++; if (msgId.Status is SentMessageTrackerStatus.NotSending or SentMessageTrackerStatus.Lost) return; @@ -148,7 +148,7 @@ public class Planes : ICommand } var winnings = plane.MultiTracker * wager; planesDisplay += $"Winnings: {await winnings.FormatKasinoCurrencyAsync()}"; - await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageId!.Value, planesDisplay); + await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, planesDisplay); } var neutral = false; @@ -159,7 +159,7 @@ public class Planes : ICommand { counter = (fullCounter - 3) % 24; planesDisplay = GetPreGameBoard(fullCounter, planesBoard2, plane, CarrierCount, noseUp); - await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageId!.Value, planesDisplay); + await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, planesDisplay); await Task.Delay(TimeSpan.FromMilliseconds(frameLength), ctx); fullCounter++; } @@ -236,7 +236,7 @@ public class Planes : ICommand var winnings = plane.MultiTracker * wager; planesDisplay += $"Winnings: {await winnings.FormatKasinoCurrencyAsync()}"; - await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageId!.Value, planesDisplay); + await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, planesDisplay); if (plane.Height > 5) { break; @@ -264,7 +264,7 @@ public class Planes : ICommand var win = plane.MultiTracker * wager; newBalance = await Money.NewWagerAsync(gambler.Id, wager, win, WagerGame.Planes, ct: ctx); planesDisplay = GetGameBoard(fullCounter, planesBoards, plane, CarrierCount, noseUp); - await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageId!.Value, planesDisplay); + await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, planesDisplay); await botInstance.SendChatMessageAsync( $"{user.FormatUsername()}, you [color={colors[BuiltIn.Keys.KiwiFarmsGreenColor].Value}]successfully landed with {await win.FormatKasinoCurrencyAsync()} from a total {plane.MultiTracker:N2}x multi![/color]. Your balance is now: {await newBalance.FormatKasinoCurrencyAsync()}", true, autoDeleteAfter: cleanupDelay); @@ -275,7 +275,7 @@ public class Planes : ICommand newBalance = await Money.NewWagerAsync(gambler.Id, wager, -wager, WagerGame.Planes, ct: ctx); planesDisplay = GetGameBoard(fullCounter, planesBoards, plane, CarrierCount, noseUp); await Task.Delay(TimeSpan.FromMilliseconds(frameLength), ctx); - await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageId!.Value, planesDisplay); + await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, planesDisplay); await botInstance.SendChatMessageAsync( $"{user.FormatUsername()}, you [color={colors[BuiltIn.Keys.KiwiFarmsRedColor].Value}]crashed![/color] Your balance is now: {await newBalance.FormatKasinoCurrencyAsync()}", true, autoDeleteAfter: cleanupDelay); diff --git a/KfChatDotNetBot/Commands/Kasino/PlinkoCommand.cs b/KfChatDotNetBot/Commands/Kasino/PlinkoCommand.cs index 6615655..2dc0aa3 100644 --- a/KfChatDotNetBot/Commands/Kasino/PlinkoCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/PlinkoCommand.cs @@ -173,7 +173,7 @@ public class PlinkoCommand : ICommand //game starts here int breakCounter = 0; var plinkoMessageID = await botInstance.SendChatMessageAsync(PlinkoBoardDisplay(ballsInPlay), true, autoDeleteAfter: cleanupDelay); - while (plinkoMessageID.ChatMessageId == null && breakCounter < 1000) { + while (plinkoMessageID.ChatMessageUuid == null && breakCounter < 1000) { await Task.Delay(100, ctx); breakCounter++; } @@ -195,7 +195,7 @@ public class PlinkoCommand : ICommand ballsNotInPlay.RemoveAt(0); } PlinkoMessage = PlinkoBoardDisplay(ballsInPlay) + "[br]" + lastPayoutMessage; - await botInstance.KfClient.EditMessageAsync(plinkoMessageID.ChatMessageId!.Value,PlinkoMessage); + await botInstance.KfClient.EditMessageAsync(plinkoMessageID.ChatMessageUuid!, PlinkoMessage); if (ballsInPlay[0].POSITION.row == DIFFICULTY - 1) //once your ball has reached the bottom calculate the payout { currentPayout = wager * PlinkoPayoutBoard[ballsInPlay[0].POSITION.col]; @@ -219,7 +219,7 @@ public class PlinkoCommand : ICommand await Task.Delay(300, ctx); PlinkoMessage = PlinkoBoardDisplay(ballsInPlay) + "[br]" + lastPayoutMessage; - await botInstance.KfClient.EditMessageAsync(plinkoMessageID.ChatMessageId!.Value, PlinkoMessage); + await botInstance.KfClient.EditMessageAsync(plinkoMessageID.ChatMessageUuid!, PlinkoMessage); await Task.Delay(300, ctx); } diff --git a/KfChatDotNetBot/Commands/Kasino/RainCommand.cs b/KfChatDotNetBot/Commands/Kasino/RainCommand.cs index c5510ec..3602c63 100644 --- a/KfChatDotNetBot/Commands/Kasino/RainCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/RainCommand.cs @@ -128,10 +128,12 @@ public class RainCommand : ICommand { timer--; await Task.Delay(1000, ctx); - await botInstance.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, + await botInstance.KfClient.EditMessageAsync(msg.ChatMessageUuid!, $"{user.FormatUsername()} is making it rain with {await decAmount.FormatKasinoCurrencyAsync()}! Type !rain in the next {timer} seconds to join."); } - await botInstance.KfClient.DeleteMessageAsync(msg.ChatMessageId!.Value); + + await Task.Delay(100, ctx); + await botInstance.KfClient.DeleteMessageAsync(msg.ChatMessageUuid!); // At this point the timer should take care of things but truthfully it's a disaster and probably won't work } } \ No newline at end of file diff --git a/KfChatDotNetBot/Commands/Kasino/RouletteCommand.cs b/KfChatDotNetBot/Commands/Kasino/RouletteCommand.cs index f102f26..4318bc8 100644 --- a/KfChatDotNetBot/Commands/Kasino/RouletteCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/RouletteCommand.cs @@ -262,7 +262,7 @@ public class RouletteCommand : ICommand if (activeRound != null) { - activeRound.CountdownMessageId = countdownMessage.ChatMessageId; + activeRound.CountdownMessageId = countdownMessage.ChatMessageUuid; await SaveRound(activeRound); } @@ -291,7 +291,7 @@ public class RouletteCommand : ICommand try { var updatedMessage = await FormatCountdownMessage(endTime); - await botInstance.KfClient.EditMessageAsync(countdownMessage.ChatMessageId!.Value, updatedMessage); + await botInstance.KfClient.EditMessageAsync(countdownMessage.ChatMessageUuid!, updatedMessage); var timeSinceLastUpdate = DateTimeOffset.UtcNow - lastUpdate; logger.Debug($"Countdown updated (elapsed: {timeSinceLastUpdate.TotalSeconds:F1}s, remaining: {remaining.TotalSeconds:F0}s)"); @@ -414,12 +414,12 @@ public class RouletteCommand : ICommand logger.Info($"Animation uploaded: {animationUrl}"); // Update countdown message to show it's spinning - if (round.CountdownMessageId.HasValue) + if (round.CountdownMessageId != null) { var spinningMessage = $"🎰 [B]SPINNING THE WHEEL...[/B] 🎰[br][br]" + "Watch the animation below!"; await botInstance.KfClient.EditMessageAsync( - round.CountdownMessageId.Value, + round.CountdownMessageId, spinningMessage); } @@ -486,10 +486,10 @@ public class RouletteCommand : ICommand $"All {round.Bets.Count} bet(s) have been refunded (total: {await totalRefunded.FormatKasinoCurrencyAsync()}).[br]" + $"Please try again."; - if (round.CountdownMessageId.HasValue) + if (round.CountdownMessageId != null) { await botInstance.KfClient.EditMessageAsync( - round.CountdownMessageId.Value, + round.CountdownMessageId, cancelMessage); } else @@ -707,10 +707,10 @@ public class RouletteCommand : ICommand $"Cancelled by {user.FormatUsername()}[br]" + $"Refunded {round.Bets.Count} bet(s) totaling {await totalRefunded.FormatKasinoCurrencyAsync()}"; - if (round.CountdownMessageId.HasValue) + if (round.CountdownMessageId != null) { await botInstance.KfClient.EditMessageAsync( - round.CountdownMessageId.Value, + round.CountdownMessageId, cancelMessage); } else @@ -884,7 +884,7 @@ public class RouletteCommand : ICommand { public required int RoundId { get; init; } public required DateTimeOffset StartTime { get; init; } - public int? CountdownMessageId { get; set; } + public string? CountdownMessageId { get; set; } public required List Bets { get; init; } } diff --git a/KfChatDotNetBot/Commands/Kasino/WheelCommand.cs b/KfChatDotNetBot/Commands/Kasino/WheelCommand.cs index 9a03eae..0a5acd7 100644 --- a/KfChatDotNetBot/Commands/Kasino/WheelCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/WheelCommand.cs @@ -156,7 +156,7 @@ public class WheelCommand : ICommand int delay = (int)(MIN_WHEELSPIN_DELAY + easeOut * (MAX_WHEELSPIN_DELAY - MIN_WHEELSPIN_DELAY)); await Task.Delay(delay, ctx); wheel.RotateWheelOnce(); - await botInstance.KfClient.EditMessageAsync(wheelDisplayMessage.ChatMessageId!.Value, + await botInstance.KfClient.EditMessageAsync(wheelDisplayMessage.ChatMessageUuid!, wheel.ConvertWheelToOvalString()); } diff --git a/KfChatDotNetBot/Commands/MemeCommands.cs b/KfChatDotNetBot/Commands/MemeCommands.cs index 821242d..a75e899 100644 --- a/KfChatDotNetBot/Commands/MemeCommands.cs +++ b/KfChatDotNetBot/Commands/MemeCommands.cs @@ -156,16 +156,14 @@ public class NextPoVisitCommand : ICommand return; } var sent = await botInstance.SendChatMessageAsync($"Austin's next PO visit will be in roughly {timespan.Humanize(precision: 10, minUnit: TimeUnit.Millisecond)}", true); - while (sent.Status != SentMessageTrackerStatus.ResponseReceived) - { - await Task.Delay(250, ctx); - } + var success = await botInstance.WaitForChatMessageAsync(sent, TimeSpan.FromSeconds(30), ctx); + if (!success) throw new InvalidOperationException(); var i = 0; while (i < 60) { await Task.Delay(1000, ctx); timespan = DateTimeOffset.Parse(time.Value) - DateTimeOffset.UtcNow; - await botInstance.KfClient.EditMessageAsync(sent.ChatMessageId!.Value, + await botInstance.KfClient.EditMessageAsync(sent.ChatMessageUuid!, $"Austin's next PO visit will be in roughly {timespan.Humanize(precision: 10, minUnit: TimeUnit.Millisecond)}"); i++; } @@ -197,15 +195,13 @@ public class NextCourtHearingCommand : ICommand } var sent = await botInstance.SendChatMessageAsync(RenderHearings(hearings),true); - while (sent.Status != SentMessageTrackerStatus.ResponseReceived) - { - await Task.Delay(250, ctx); - } + var success = await botInstance.WaitForChatMessageAsync(sent, TimeSpan.FromSeconds(15), ctx); + if (!success) throw new InvalidOperationException(); var i = 0; while (i < 60) { await Task.Delay(1000, ctx); - await botInstance.KfClient.EditMessageAsync(sent.ChatMessageId!.Value, RenderHearings(hearings)); + await botInstance.KfClient.EditMessageAsync(sent.ChatMessageUuid!, RenderHearings(hearings)); i++; } } diff --git a/KfChatDotNetBot/Commands/TestCommands.cs b/KfChatDotNetBot/Commands/TestCommands.cs index 28ca67b..096bfae 100644 --- a/KfChatDotNetBot/Commands/TestCommands.cs +++ b/KfChatDotNetBot/Commands/TestCommands.cs @@ -35,7 +35,7 @@ public class EditTestCommand : ICommand reference.Status == SentMessageTrackerStatus.Unknown || reference.Status == SentMessageTrackerStatus.ChatDisconnected || reference.Status == SentMessageTrackerStatus.Lost || - reference.ChatMessageId == null) + reference.ChatMessageUuid == null) { logger.Error("Either message refused to send due to bot settings or something fucked up getting the message ID"); return; @@ -44,13 +44,13 @@ public class EditTestCommand : ICommand { i++; await Task.Delay(delay, ctx); - await botInstance.KfClient.EditMessageAsync(reference.ChatMessageId!.Value, $"{msg} {i}"); + await botInstance.KfClient.EditMessageAsync(reference.ChatMessageUuid, $"{msg} {i}"); } await Task.Delay(delay, ctx); - await botInstance.KfClient.EditMessageAsync(reference.ChatMessageId!.Value, "This message will self destruct in 1 second"); + await botInstance.KfClient.EditMessageAsync(reference.ChatMessageUuid, "This message will self destruct in 1 second"); await Task.Delay(delay, ctx); - await botInstance.KfClient.DeleteMessageAsync(reference.ChatMessageId!.Value); + await botInstance.KfClient.DeleteMessageAsync(reference.ChatMessageUuid); } } @@ -113,15 +113,15 @@ public class LengthLimitTestCommand : ICommand true, ChatBot.LengthLimitBehavior.RefuseToSend, 20); await Task.Delay(TimeSpan.FromSeconds(5), ctx); logger.Info($"niceTruncation => {niceTruncation.Status}; exactTruncation => {exactTruncation.Status}; doNothing => {doNothing.Status}; refuseToSend => {refuseToSend.Status}"); - if (niceTruncation.ChatMessageId != null) - await botInstance.KfClient.DeleteMessageAsync(niceTruncation.ChatMessageId.Value); - if (exactTruncation.ChatMessageId != null) - await botInstance.KfClient.DeleteMessageAsync(exactTruncation.ChatMessageId.Value); - if (doNothing.ChatMessageId != null) - await botInstance.KfClient.DeleteMessageAsync(doNothing.ChatMessageId.Value); + if (niceTruncation.ChatMessageUuid != null) + await botInstance.KfClient.DeleteMessageAsync(niceTruncation.ChatMessageUuid); + if (exactTruncation.ChatMessageUuid != null) + await botInstance.KfClient.DeleteMessageAsync(exactTruncation.ChatMessageUuid); + if (doNothing.ChatMessageUuid != null) + await botInstance.KfClient.DeleteMessageAsync(doNothing.ChatMessageUuid); // Should never happen - if (refuseToSend.ChatMessageId != null) - await botInstance.KfClient.DeleteMessageAsync(refuseToSend.ChatMessageId.Value); + if (refuseToSend.ChatMessageUuid != null) + await botInstance.KfClient.DeleteMessageAsync(refuseToSend.ChatMessageUuid); } } diff --git a/KfChatDotNetBot/Models/SeenMessageMetadataModel.cs b/KfChatDotNetBot/Models/SeenMessageMetadataModel.cs index aa35891..19dea50 100644 --- a/KfChatDotNetBot/Models/SeenMessageMetadataModel.cs +++ b/KfChatDotNetBot/Models/SeenMessageMetadataModel.cs @@ -2,6 +2,6 @@ public class SeenMessageMetadataModel { - public int MessageId { get; set; } + public string MessageUuid { get; set; } public DateTimeOffset? LastEdited { get; set; } } \ No newline at end of file diff --git a/KfChatDotNetBot/Models/SentMessageTrackerModel.cs b/KfChatDotNetBot/Models/SentMessageTrackerModel.cs index 71be709..fa4aa93 100644 --- a/KfChatDotNetBot/Models/SentMessageTrackerModel.cs +++ b/KfChatDotNetBot/Models/SentMessageTrackerModel.cs @@ -6,7 +6,7 @@ public class SentMessageTrackerModel public required string Reference { get; set; } public required string Message { get; set; } public required SentMessageTrackerStatus Status { get; set; } - public int? ChatMessageId { get; set; } + public string? ChatMessageUuid { get; set; } // Timespan from when the message was sent until we saw it come back public TimeSpan? Delay { get; set; } public DateTimeOffset? SentAt { get; set; } diff --git a/KfChatDotNetBot/Services/BotServices.cs b/KfChatDotNetBot/Services/BotServices.cs index 0636164..dba4b13 100644 --- a/KfChatDotNetBot/Services/BotServices.cs +++ b/KfChatDotNetBot/Services/BotServices.cs @@ -736,19 +736,19 @@ public class BotServices private async Task OnYeetWinEditTaskAsync(SentMessageTrackerModel oldMsg, string newMsg) { var i = 0; - while (oldMsg.ChatMessageId == null && i < 50) + while (oldMsg.ChatMessageUuid == null && i < 50) { await Task.Delay(100, _cancellationToken); i++; } - if (oldMsg.ChatMessageId == null) + if (oldMsg.ChatMessageUuid == null) { _logger.Error($"Timed out waiting to figure out our message ID"); return; } - await _chatBot.KfClient.EditMessageAsync(oldMsg.ChatMessageId.Value, newMsg); + await _chatBot.KfClient.EditMessageAsync(oldMsg.ChatMessageUuid, newMsg); } private void OnHowlggBetHistory(object sender, HowlggBetHistoryResponseModel data) @@ -918,7 +918,7 @@ public class BotServices BuiltIn.Keys.KiwiFarmsRedColor, BuiltIn.Keys.KiwiFarmsGreenColor ]); var patience = 0; - while (msg.ChatMessageId == null) + while (msg.ChatMessageUuid == null) { patience++; if (msg.Status is SentMessageTrackerStatus.Lost or SentMessageTrackerStatus.NotSending || patience > 50) @@ -935,11 +935,11 @@ public class BotServices { if (seconds % 2 == 0) { - await _chatBot.KfClient.EditMessageAsync(msg.ChatMessageId.Value, $"[color={settings[BuiltIn.Keys.KiwiFarmsGreenColor].Value}]{msg.Message}[/color]"); + await _chatBot.KfClient.EditMessageAsync(msg.ChatMessageUuid, $"[color={settings[BuiltIn.Keys.KiwiFarmsGreenColor].Value}]{msg.Message}[/color]"); } else { - await _chatBot.KfClient.EditMessageAsync(msg.ChatMessageId.Value, $"[color={settings[BuiltIn.Keys.KiwiFarmsRedColor].Value}]{msg.Message}[/color]"); + await _chatBot.KfClient.EditMessageAsync(msg.ChatMessageUuid, $"[color={settings[BuiltIn.Keys.KiwiFarmsRedColor].Value}]{msg.Message}[/color]"); } await Task.Delay(1000, _cancellationToken); diff --git a/KfChatDotNetBot/Services/KasinoMines.cs b/KfChatDotNetBot/Services/KasinoMines.cs index 4057f51..c70f060 100644 --- a/KfChatDotNetBot/Services/KasinoMines.cs +++ b/KfChatDotNetBot/Services/KasinoMines.cs @@ -26,7 +26,7 @@ public class KasinoMines public int Size { get; set; } public int Mines { get; set; } public List<(int r, int c)> BetsPlaced; - public int LastMessageId = 0; + public string? LastMessageId; public string LastMessageReference = ""; @@ -44,12 +44,12 @@ public class KasinoMines { _logger.Info("Resetting message"); // 0 is the default for int - if (LastMessageId != 0) + if (LastMessageId != null) { await _kfChatBot.KfClient.DeleteMessageAsync(LastMessageId); } - if (msg.ChatMessageId == null) throw new InvalidOperationException($"ChatMessageId was null for {msg.Reference}"); - LastMessageId = msg.ChatMessageId.Value; + + LastMessageId = msg.ChatMessageUuid ?? throw new InvalidOperationException($"ChatMessageId was null for {msg.Reference}"); LastMessageReference = msg.Reference; } @@ -83,7 +83,7 @@ public class KasinoMines } public async Task Explode((int r, int c) mineLocation, SentMessageTrackerModel msg) { - if (LastMessageId == 0 || LastMessageId != msg.ChatMessageId) + if (LastMessageId == null || LastMessageId != msg.ChatMessageUuid) { await ResetMessage(msg); } @@ -154,8 +154,8 @@ public class KasinoMines } await Task.Delay(TimeSpan.FromSeconds(10)); - await _kfChatBot.KfClient.DeleteMessageAsync(msg.ChatMessageId!.Value); - LastMessageId = 0; + await _kfChatBot.KfClient.DeleteMessageAsync(msg.ChatMessageUuid); + LastMessageId = null; (int vertical, int horizontal) DistanceFromMine((int r, int c) coord) { @@ -298,8 +298,8 @@ public class KasinoMines { await GetSavedGames(gamblerId); //attempt to delete the message if its there - if (ActiveGames[gamblerId].LastMessageId != 0) await _kfChatBot.KfClient.DeleteMessageAsync(ActiveGames[gamblerId].LastMessageId); - ActiveGames?.Remove(gamblerId); + if (ActiveGames[gamblerId].LastMessageId != null) await _kfChatBot.KfClient.DeleteMessageAsync(ActiveGames[gamblerId].LastMessageId!); + ActiveGames.Remove(gamblerId); await SaveActiveGames(gamblerId); } @@ -345,7 +345,7 @@ public class KasinoMines await GetSavedGames(gamblerId); var game = ActiveGames[gamblerId]; game.LastInteracted = DateTimeOffset.UtcNow; - if (game.LastMessageId == 0 || game.LastMessageId != msg.ChatMessageId) + if (game.LastMessageId == null || game.LastMessageId != msg.ChatMessageUuid) { await game.ResetMessage(msg); @@ -405,7 +405,7 @@ public class KasinoMines await GetSavedGames(gamblerId); var game = ActiveGames[gamblerId]; game.LastInteracted = DateTimeOffset.UtcNow; - if (game.LastMessageId == 0 || game.LastMessageId != msg.ChatMessageId) + if (game.LastMessageId == null || game.LastMessageId != msg.ChatMessageUuid) { await game.ResetMessage(msg); } @@ -435,7 +435,7 @@ public class KasinoMines { if (!validBets.Contains(bet) || game.BetsPlaced.Contains(bet) || bets.Contains(bet)) { - await _kfChatBot.KfClient.EditMessageAsync(invalidBetMsg.ChatMessageId!.Value, + await _kfChatBot.KfClient.EditMessageAsync(invalidBetMsg.ChatMessageUuid!, $"{game.Creator.User.FormatUsername()}, invalid bet of {bet.r},{bet.c} removed (already placed, duplicate, or invalid coordinate)"); await Task.Delay(5); } @@ -446,20 +446,20 @@ public class KasinoMines if (bets.Count > numGems) { - await _kfChatBot.KfClient.EditMessageAsync(invalidBetMsg.ChatMessageId!.Value, + await _kfChatBot.KfClient.EditMessageAsync(invalidBetMsg.ChatMessageUuid!, $"{game.Creator.User.FormatUsername()}, you bet on {bets.Count} gems, but there are only {numGems} left. Your list of bets was automatically truncated, and the game will automatically cash out if you win."); bets.RemoveRange(numGems, bets.Count - numGems); cashOut = true; } else if (bets.Count == numGems) { - await _kfChatBot.KfClient.EditMessageAsync(invalidBetMsg.ChatMessageId!.Value, + await _kfChatBot.KfClient.EditMessageAsync(invalidBetMsg.ChatMessageUuid!, $"{game.Creator.User.FormatUsername()}, you bet on all gems, so you will automatically cash out if you win."); cashOut = true; } await Task.Delay(50); - _ = _kfChatBot.KfClient.DeleteMessageAsync(invalidBetMsg.ChatMessageId!.Value); + _ = _kfChatBot.KfClient.DeleteMessageAsync(invalidBetMsg.ChatMessageUuid!); } else bets = coords; @@ -469,7 +469,7 @@ public class KasinoMines if (game.MinesBoard[coord.r][ coord.c] == 'M') { game.BetsPlaced.Add(coord); - await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, game.ToString()); + await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageUuid!, game.ToString()); _ = game.Explode((coord.r, coord.c), msg); var newBalance = await Money.NewWagerAsync(game.Creator.Id, game.Wager, -game.Wager, WagerGame.Mines); var net = -game.Wager; @@ -483,10 +483,10 @@ public class KasinoMines if (Money.GetRandomNumber(game.Creator, 0, 100) > 100 * HOUSE_EDGE)//if you didn't lose, check to see if the switch was flipped { game.BetsPlaced.Add(coord); - await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, game.ToString()); + await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageUuid!, game.ToString()); await game.RigBoard(coord); await Task.Delay(50); - await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, game.ToString()); + await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageUuid!, game.ToString()); _ = game.Explode(coord, msg); var newBalance = await Money.NewWagerAsync(game.Creator.Id, game.Wager, -game.Wager, WagerGame.Mines); var net = -game.Wager; @@ -500,7 +500,7 @@ public class KasinoMines { game.BetsPlaced.Add(coord); } - await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, game.ToString()); + await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageUuid!, game.ToString()); } diff --git a/KfChatDotNetWsClient/ChatClient.cs b/KfChatDotNetWsClient/ChatClient.cs index e3f78ea..a8feaab 100644 --- a/KfChatDotNetWsClient/ChatClient.cs +++ b/KfChatDotNetWsClient/ChatClient.cs @@ -24,6 +24,8 @@ public class ChatClient public event EventHandlers.OnWsDisconnectionEventHandler? OnWsDisconnection; public event EventHandlers.OnFailedToJoinRoom? OnFailedToJoinRoom; public event EventHandlers.OnUnknownCommand? OnUnknownCommand; + public event EventHandlers.OnPermissionsEventHandler? OnPermissions; + public event EventHandlers.OnSystemMessage? OnSystemMessage; private WebsocketClient? _wsClient; private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private ChatClientConfigModel _config; @@ -188,6 +190,20 @@ public class ChatClient return; } + if (packetType.ContainsKey("permissions")) + { + _logger.Debug("Looks like we got permissions"); + WsPermissions(message); + return; + } + + if (packetType.ContainsKey("system")) + { + _logger.Debug("Looks like a system message"); + WsSystemMessage(message); + return; + } + if (packetType.ContainsKey("delete")) { _logger.Debug($"Looks like this is a message deletion packet"); @@ -226,22 +242,22 @@ public class ChatClient _wsClient.Send($"/delete {messageId}"); } - public async Task DeleteMessageAsync(int messageId) + public async Task DeleteMessageAsync(string messageUuid) { - _logger.Debug($"Deleting {messageId}"); + _logger.Debug($"Deleting {messageUuid}"); if (_wsClient == null) throw new WebSocketNotInitializedException(); - await _wsClient.SendInstant($"/delete {messageId}"); + await _wsClient.SendInstant($"/delete {messageUuid}"); } - public void EditMessage(int messageId, string newMessage) + public void EditMessage(string messageUuid, string newMessage) { - var payload = JsonSerializer.Serialize(new EditMessageJsonModel {Id = messageId, Message = newMessage}); - _logger.Debug($"Editing {messageId} with '{newMessage}'"); + var payload = JsonSerializer.Serialize(new EditMessageJsonModel {Uuid = messageUuid, Message = newMessage}); + _logger.Debug($"Editing {messageUuid} with '{newMessage}'"); if (_wsClient == null) throw new WebSocketNotInitializedException(); _wsClient.Send($"/edit {payload}"); } - public async Task EditMessageAsync(int messageId, string newMessage) + public async Task EditMessageAsync(string messageUuid, string newMessage) { var settings = new TextEncoderSettings(); settings.AllowRange(UnicodeRanges.All); @@ -249,8 +265,8 @@ public class ChatClient { Encoder = JavaScriptEncoder.Create(settings) }; - var payload = JsonSerializer.Serialize(new EditMessageJsonModel {Id = messageId, Message = newMessage}, options); - _logger.Debug($"Editing {messageId} with '{newMessage}'"); + var payload = JsonSerializer.Serialize(new EditMessageJsonModel {Uuid = messageUuid, Message = newMessage}, options); + _logger.Debug($"Editing {messageUuid} with '{newMessage}'"); if (_wsClient == null) throw new WebSocketNotInitializedException(); var msg = $"/edit {payload}"; var length = Encoding.UTF8.GetByteCount(msg); @@ -285,7 +301,7 @@ public class ChatClient LastActivity = null }, Message = chatMessage.Message, - MessageId = chatMessage.MessageId, + MessageUuid = chatMessage.MessageUuid, MessageRaw = chatMessage.MessageRaw, RoomId = chatMessage.RoomId, MessageRawHtmlDecoded = WebUtility.HtmlDecode(chatMessage.MessageRaw), @@ -347,6 +363,35 @@ public class ChatClient _logger.Debug($"Following users have parted: {string.Join(',', usersParted)}"); OnUsersParted?.Invoke(this, usersParted); } + + private void WsPermissions(ResponseMessage message) + { + var data = JsonSerializer.Deserialize(message.Text); + var permissions = data.GetProperty("permissions").Deserialize(); + try + { + OnPermissions?.Invoke(this, permissions); + } + catch (Exception e) + { + _logger.Error("Caught error when invoking OnPermissions"); + _logger.Error(e); + } + } + + private void WsSystemMessage(ResponseMessage message) + { + var msg = JsonSerializer.Deserialize(message.Text).GetProperty("system").GetString(); + try + { + OnSystemMessage?.Invoke(this, msg); + } + catch (Exception e) + { + _logger.Error("Caught error when invoking OnSystemMessage"); + _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 98c938b..d2b4bf5 100644 --- a/KfChatDotNetWsClient/Models/Events/EventHandlers.cs +++ b/KfChatDotNetWsClient/Models/Events/EventHandlers.cs @@ -25,4 +25,8 @@ public class EventHandlers public delegate void OnFailedToJoinRoom(object sender, string message); public delegate void OnUnknownCommand(object sender, string message); + + public delegate void OnPermissionsEventHandler(object sender, PermissionsJsonModel permissions); + + public delegate void OnSystemMessage(object sender, string message); } \ No newline at end of file diff --git a/KfChatDotNetWsClient/Models/Events/MessageModel.cs b/KfChatDotNetWsClient/Models/Events/MessageModel.cs index 5555c09..70bc557 100644 --- a/KfChatDotNetWsClient/Models/Events/MessageModel.cs +++ b/KfChatDotNetWsClient/Models/Events/MessageModel.cs @@ -7,7 +7,7 @@ public class MessageModel /// HTML formatted message /// public required string Message { get; set; } - public required int MessageId { get; set; } + public required string MessageUuid { get; set; } public DateTimeOffset? MessageEditDate { get; set; } public required DateTimeOffset MessageDate { get; set; } /// diff --git a/KfChatDotNetWsClient/Models/Json/EditMessageJsonModel.cs b/KfChatDotNetWsClient/Models/Json/EditMessageJsonModel.cs index 0d7aa57..73936e2 100644 --- a/KfChatDotNetWsClient/Models/Json/EditMessageJsonModel.cs +++ b/KfChatDotNetWsClient/Models/Json/EditMessageJsonModel.cs @@ -4,8 +4,8 @@ namespace KfChatDotNetWsClient.Models.Json; public class EditMessageJsonModel { - [JsonPropertyName("id")] - public required int Id { get; set; } + [JsonPropertyName("uuid")] + public required string Uuid { get; set; } [JsonPropertyName("message")] public required string Message { get; set; } diff --git a/KfChatDotNetWsClient/Models/Json/MessagesJsonModel.cs b/KfChatDotNetWsClient/Models/Json/MessagesJsonModel.cs index 3ca6957..66579eb 100644 --- a/KfChatDotNetWsClient/Models/Json/MessagesJsonModel.cs +++ b/KfChatDotNetWsClient/Models/Json/MessagesJsonModel.cs @@ -41,8 +41,8 @@ public class MessagesJsonModel public required AuthorModel Author { get; set; } [JsonPropertyName("message")] public required string Message { get; set; } - [JsonPropertyName("message_id")] - public int MessageId { get; set; } + [JsonPropertyName("message_uuid")] + public required string MessageUuid { get; set; } [JsonPropertyName("message_edit_date")] public int MessageEditDate { get; set; } [JsonPropertyName("message_date")] diff --git a/KfChatDotNetWsClient/Models/Json/PermissionsJsonModel.cs b/KfChatDotNetWsClient/Models/Json/PermissionsJsonModel.cs new file mode 100644 index 0000000..e0a6cd5 --- /dev/null +++ b/KfChatDotNetWsClient/Models/Json/PermissionsJsonModel.cs @@ -0,0 +1,27 @@ +using System.Text.Json.Serialization; + +namespace KfChatDotNetWsClient.Models.Json; + +public class PermissionsJsonModel +{ + [JsonPropertyName("can_view")] + public required bool CanView { get; set; } + [JsonPropertyName("can_send")] + public required bool CanSend { get; set; } + [JsonPropertyName("can_edit_own")] + public required bool CanEditOwn { get; set; } + [JsonPropertyName("can_edit_other")] + public required bool CanEditOther { get; set; } + [JsonPropertyName("can_delete_own")] + public required bool CanDeleteOwn { get; set; } + [JsonPropertyName("can_delete_other")] + public required bool CanDeleteOther { get; set; } + [JsonPropertyName("can_report")] + public required bool CanReport { get; set; } + [JsonPropertyName("can_view_deleted")] + public required bool CanViewDeleted { get; set; } + [JsonPropertyName("can_undelete")] + public required bool CanUndelete { get; set; } + [JsonPropertyName("can_motd")] + public required bool CanMotd { get; set; } +} \ No newline at end of file