diff --git a/SysBot.Pokemon/BDSP/BotTrade/PokeTradeBotBS.cs b/SysBot.Pokemon/BDSP/BotTrade/PokeTradeBotBS.cs index fce749c86..2155615a3 100644 --- a/SysBot.Pokemon/BDSP/BotTrade/PokeTradeBotBS.cs +++ b/SysBot.Pokemon/BDSP/BotTrade/PokeTradeBotBS.cs @@ -342,26 +342,6 @@ private void CleanupAllBatchTradesFromQueue(PokeTradeDetail detail) Log($"Cleaned up batch trades for TrainerID: {detail.Trainer.ID}, UniqueTradeID: {detail.UniqueTradeID}"); } - private async Task HandleAbortedBatchTrade(PokeTradeDetail detail, PokeRoutineType type, uint priority, PokeTradeResult result, CancellationToken token) - { - if (detail.TotalBatchTrades > 1) - { - // Send notification once before cleanup - detail.SendNotification(this, $"Trade {detail.BatchTradeNumber}/{detail.TotalBatchTrades} failed. Canceling remaining batch trades."); - - CleanupAllBatchTradesFromQueue(detail); - - // Mark this specific trade as canceled - detail.TradeCanceled(this, result); - - await EnsureOutsideOfUnionRoom(token).ConfigureAwait(false); - } - else - { - HandleAbortedTrade(detail, type, priority, result); - } - } - private async Task DoTrades(SAV8BS sav, CancellationToken token) { var type = Config.CurrentRoutineType; @@ -1205,7 +1185,6 @@ private async Task PerformBatchTrade(SAV8BS sav, PokeTradeDetai // Finally do cleanup Hub.Queues.CompleteTrade(this, poke); - CleanupAllBatchTradesFromQueue(poke); _batchTracker.ClearReceivedPokemon(poke.Trainer.ID); break; } @@ -1249,18 +1228,11 @@ private async Task PerformTrade(SAV8BS sav, PokeTradeDetail detail, PokeRou else result = await PerformLinkCodeTrade(sav, detail, token).ConfigureAwait(false); - if (result == PokeTradeResult.Success) - { - PB8? receivedPokemon = await ReadPokemon(BoxStartOffset, BoxFormatSlotSize, token).ConfigureAwait(false); - return; - } - - // Handle failed trades - if (detail.TotalBatchTrades > 1) + if (detail.Type == PokeTradeType.Batch) { await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); } - else + else if (result != PokeTradeResult.Success) { HandleAbortedTrade(detail, type, priority, result); } @@ -1269,14 +1241,53 @@ private async Task PerformTrade(SAV8BS sav, PokeTradeDetail detail, PokeRou { Log(socket.Message); result = PokeTradeResult.ExceptionConnection; - await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + if (detail.Type == PokeTradeType.Batch) + await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + else + HandleAbortedTrade(detail, type, priority, result); throw; } catch (Exception e) { Log(e.Message); result = PokeTradeResult.ExceptionInternal; - await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + if (detail.Type == PokeTradeType.Batch) + await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + else + HandleAbortedTrade(detail, type, priority, result); + } + } + + private async Task HandleAbortedBatchTrade(PokeTradeDetail detail, PokeRoutineType type, uint priority, PokeTradeResult result, CancellationToken token) + { + detail.IsProcessing = false; + + if (detail.TotalBatchTrades > 1) + { + if (result != PokeTradeResult.Success) + { + if (result.ShouldAttemptRetry() && detail.Type != PokeTradeType.Random && !detail.IsRetry) + { + detail.IsRetry = true; + Hub.Queues.Enqueue(type, detail, Math.Min(priority, PokeTradePriorities.Tier2)); + detail.SendNotification(this, $"Oops! Something happened during batch trade {detail.BatchTradeNumber}/{detail.TotalBatchTrades}. I'll requeue you for another attempt."); + } + else + { + detail.SendNotification(this, $"Trade {detail.BatchTradeNumber}/{detail.TotalBatchTrades} failed. Canceling remaining batch trades: {result}"); + CleanupAllBatchTradesFromQueue(detail); + detail.TradeCanceled(this, result); + await EnsureOutsideOfUnionRoom(token).ConfigureAwait(false); + } + } + else + { + CleanupAllBatchTradesFromQueue(detail); + } + } + else + { + HandleAbortedTrade(detail, type, priority, result); } } diff --git a/SysBot.Pokemon/LA/BotTrade/PokeTradeBotLA.cs b/SysBot.Pokemon/LA/BotTrade/PokeTradeBotLA.cs index f3a55b675..20f01dbc6 100644 --- a/SysBot.Pokemon/LA/BotTrade/PokeTradeBotLA.cs +++ b/SysBot.Pokemon/LA/BotTrade/PokeTradeBotLA.cs @@ -266,26 +266,6 @@ private void CleanupAllBatchTradesFromQueue(PokeTradeDetail detail) Log($"Cleaned up batch trades for TrainerID: {detail.Trainer.ID}, UniqueTradeID: {detail.UniqueTradeID}"); } - private async Task HandleAbortedBatchTrade(PokeTradeDetail detail, PokeRoutineType type, uint priority, PokeTradeResult result, CancellationToken token) - { - if (detail.TotalBatchTrades > 1) - { - // Send notification once before cleanup - detail.SendNotification(this, $"Trade {detail.BatchTradeNumber}/{detail.TotalBatchTrades} failed. Canceling remaining batch trades."); - - CleanupAllBatchTradesFromQueue(detail); - - // Mark this specific trade as canceled - detail.TradeCanceled(this, result); - - await ExitTrade(false, token).ConfigureAwait(false); - } - else - { - HandleAbortedTrade(detail, type, priority, result); - } - } - private async Task PerformTrade(SAV8LA sav, PokeTradeDetail detail, PokeRoutineType type, uint priority, CancellationToken token) { PokeTradeResult result; @@ -296,18 +276,11 @@ private async Task PerformTrade(SAV8LA sav, PokeTradeDetail detail, PokeRou else result = await PerformLinkCodeTrade(sav, detail, token).ConfigureAwait(false); - if (result == PokeTradeResult.Success) - { - PA8? receivedPokemon = await ReadPokemon(BoxStartOffset, BoxFormatSlotSize, token).ConfigureAwait(false); - return; - } - - // Handle failed trades - if (detail.TotalBatchTrades > 1) + if (detail.Type == PokeTradeType.Batch) { await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); } - else + else if (result != PokeTradeResult.Success) { HandleAbortedTrade(detail, type, priority, result); } @@ -316,14 +289,53 @@ private async Task PerformTrade(SAV8LA sav, PokeTradeDetail detail, PokeRou { Log(socket.Message); result = PokeTradeResult.ExceptionConnection; - await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + if (detail.Type == PokeTradeType.Batch) + await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + else + HandleAbortedTrade(detail, type, priority, result); throw; } catch (Exception e) { Log(e.Message); result = PokeTradeResult.ExceptionInternal; - await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + if (detail.Type == PokeTradeType.Batch) + await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + else + HandleAbortedTrade(detail, type, priority, result); + } + } + + private async Task HandleAbortedBatchTrade(PokeTradeDetail detail, PokeRoutineType type, uint priority, PokeTradeResult result, CancellationToken token) + { + detail.IsProcessing = false; + + if (detail.TotalBatchTrades > 1) + { + if (result != PokeTradeResult.Success) + { + if (result.ShouldAttemptRetry() && detail.Type != PokeTradeType.Random && !detail.IsRetry) + { + detail.IsRetry = true; + Hub.Queues.Enqueue(type, detail, Math.Min(priority, PokeTradePriorities.Tier2)); + detail.SendNotification(this, $"Oops! Something happened during batch trade {detail.BatchTradeNumber}/{detail.TotalBatchTrades}. I'll requeue you for another attempt."); + } + else + { + detail.SendNotification(this, $"Trade {detail.BatchTradeNumber}/{detail.TotalBatchTrades} failed. Canceling remaining batch trades: {result}"); + CleanupAllBatchTradesFromQueue(detail); + detail.TradeCanceled(this, result); + await ExitTrade(false, token).ConfigureAwait(false); + } + } + else + { + CleanupAllBatchTradesFromQueue(detail); + } + } + else + { + HandleAbortedTrade(detail, type, priority, result); } } @@ -560,7 +572,6 @@ private async Task PerformBatchTrade(SAV8LA sav, PokeTradeDetai // cleanup Hub.Queues.CompleteTrade(this, poke); - CleanupAllBatchTradesFromQueue(poke); _batchTracker.ClearReceivedPokemon(poke.Trainer.ID); await ExitTrade(false, token).ConfigureAwait(false); break; diff --git a/SysBot.Pokemon/SV/BotTrade/PokeTradeBotSV.cs b/SysBot.Pokemon/SV/BotTrade/PokeTradeBotSV.cs index a73118d21..7d55f3143 100644 --- a/SysBot.Pokemon/SV/BotTrade/PokeTradeBotSV.cs +++ b/SysBot.Pokemon/SV/BotTrade/PokeTradeBotSV.cs @@ -1009,7 +1009,6 @@ private async Task PerformBatchTrade(SAV9SV sav, PokeTradeDetai // Finally do cleanup Hub.Queues.CompleteTrade(this, poke); - CleanupAllBatchTradesFromQueue(poke); _batchTracker.ClearReceivedPokemon(poke.Trainer.ID); break; } @@ -1328,56 +1327,21 @@ private void CleanupAllBatchTradesFromQueue(PokeTradeDetail detail) Log($"Cleaned up batch trades for TrainerID: {detail.Trainer.ID}, UniqueTradeID: {detail.UniqueTradeID}"); } - private async Task HandleAbortedBatchTrade(PokeTradeDetail detail, PokeRoutineType type, uint priority, PokeTradeResult result, CancellationToken token) - { - if (detail.TotalBatchTrades > 1) - { - // Send notification once before cleanup - detail.SendNotification(this, $"Trade {detail.BatchTradeNumber}/{detail.TotalBatchTrades} failed. Canceling remaining batch trades."); - - CleanupAllBatchTradesFromQueue(detail); - - // Mark this specific trade as canceled - detail.TradeCanceled(this, result); - - // Attempt to recover - if (await RecoverToPortal(token).ConfigureAwait(false)) - { - Log("Recovered to portal after batch trade failure."); - } - else - { - Log("Failed to recover to portal after batch trade failure."); - await RecoverToOverworld(token).ConfigureAwait(false); - } - } - else - { - HandleAbortedTrade(detail, type, priority, result); - } - } - private async Task PerformTrade(SAV9SV sav, PokeTradeDetail detail, PokeRoutineType type, uint priority, CancellationToken token) { PokeTradeResult result; try { - // Keep track of the first trade in batch for cleanup purposes - bool isFirstInBatch = detail.BatchTradeNumber == 1; - result = await PerformLinkCodeTrade(sav, detail, token).ConfigureAwait(false); - - if (result == PokeTradeResult.Success) - { - PK9? receivedPokemon = await ReadPokemon(BoxStartOffset, BoxFormatSlotSize, token).ConfigureAwait(false); - return; - } + if (detail.Type == PokeTradeType.Batch) + result = await PerformBatchTrade(sav, detail, token).ConfigureAwait(false); + else + result = await PerformLinkCodeTrade(sav, detail, token).ConfigureAwait(false); - // Handle failed trades - if (detail.TotalBatchTrades > 1) + if (detail.Type == PokeTradeType.Batch) { await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); } - else + else if (result != PokeTradeResult.Success) { HandleAbortedTrade(detail, type, priority, result); } @@ -1386,14 +1350,53 @@ private async Task PerformTrade(SAV9SV sav, PokeTradeDetail detail, PokeRou { Log(socket.Message); result = PokeTradeResult.ExceptionConnection; - await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + if (detail.Type == PokeTradeType.Batch) + await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + else + HandleAbortedTrade(detail, type, priority, result); throw; } catch (Exception e) { Log(e.Message); result = PokeTradeResult.ExceptionInternal; - await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + if (detail.Type == PokeTradeType.Batch) + await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + else + HandleAbortedTrade(detail, type, priority, result); + } + } + + private async Task HandleAbortedBatchTrade(PokeTradeDetail detail, PokeRoutineType type, uint priority, PokeTradeResult result, CancellationToken token) + { + detail.IsProcessing = false; + + if (detail.TotalBatchTrades > 1) + { + if (result != PokeTradeResult.Success) + { + if (result.ShouldAttemptRetry() && detail.Type != PokeTradeType.Random && !detail.IsRetry) + { + detail.IsRetry = true; + Hub.Queues.Enqueue(type, detail, Math.Min(priority, PokeTradePriorities.Tier2)); + detail.SendNotification(this, $"Oops! Something happened during batch trade {detail.BatchTradeNumber}/{detail.TotalBatchTrades}. I'll requeue you for another attempt."); + } + else + { + detail.SendNotification(this, $"Trade {detail.BatchTradeNumber}/{detail.TotalBatchTrades} failed. Canceling remaining batch trades: {result}"); + CleanupAllBatchTradesFromQueue(detail); + detail.TradeCanceled(this, result); + await ExitTradeToPortal(false, token).ConfigureAwait(false); + } + } + else + { + CleanupAllBatchTradesFromQueue(detail); + } + } + else + { + HandleAbortedTrade(detail, type, priority, result); } } diff --git a/SysBot.Pokemon/SWSH/BotTrade/PokeTradeBotSWSH.cs b/SysBot.Pokemon/SWSH/BotTrade/PokeTradeBotSWSH.cs index 9e566ba30..b8e19e6ab 100644 --- a/SysBot.Pokemon/SWSH/BotTrade/PokeTradeBotSWSH.cs +++ b/SysBot.Pokemon/SWSH/BotTrade/PokeTradeBotSWSH.cs @@ -470,7 +470,6 @@ private async Task PerformBatchTrade(SAV8SWSH sav, PokeTradeDet // cleanup Hub.Queues.CompleteTrade(this, poke); - CleanupAllBatchTradesFromQueue(poke); _batchTracker.ClearReceivedPokemon(poke.Trainer.ID); break; } @@ -514,23 +513,67 @@ private async Task PerformTrade(SAV8SWSH sav, PokeTradeDetail detail, PokeR else result = await PerformLinkCodeTrade(sav, detail, token).ConfigureAwait(false); - if (result == PokeTradeResult.Success) - return; + if (detail.Type == PokeTradeType.Batch) + { + await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + } + else if (result != PokeTradeResult.Success) + { + HandleAbortedTrade(detail, type, priority, result); + } } catch (SocketException socket) { Log(socket.Message); result = PokeTradeResult.ExceptionConnection; - HandleAbortedTrade(detail, type, priority, result); + if (detail.Type == PokeTradeType.Batch) + await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + else + HandleAbortedTrade(detail, type, priority, result); throw; } catch (Exception e) { Log(e.Message); result = PokeTradeResult.ExceptionInternal; + if (detail.Type == PokeTradeType.Batch) + await HandleAbortedBatchTrade(detail, type, priority, result, token).ConfigureAwait(false); + else + HandleAbortedTrade(detail, type, priority, result); } + } - HandleAbortedTrade(detail, type, priority, result); + private async Task HandleAbortedBatchTrade(PokeTradeDetail detail, PokeRoutineType type, uint priority, PokeTradeResult result, CancellationToken token) + { + detail.IsProcessing = false; + + if (detail.TotalBatchTrades > 1) + { + if (result != PokeTradeResult.Success) + { + if (result.ShouldAttemptRetry() && detail.Type != PokeTradeType.Random && !detail.IsRetry) + { + detail.IsRetry = true; + hub.Queues.Enqueue(type, detail, Math.Min(priority, PokeTradePriorities.Tier2)); + detail.SendNotification(this, $"Oops! Something happened during batch trade {detail.BatchTradeNumber}/{detail.TotalBatchTrades}. I'll requeue you for another attempt."); + } + else + { + detail.SendNotification(this, $"Trade {detail.BatchTradeNumber}/{detail.TotalBatchTrades} failed. Canceling remaining batch trades: {result}"); + CleanupAllBatchTradesFromQueue(detail); + detail.TradeCanceled(this, result); + await ExitTrade(false, token).ConfigureAwait(false); + } + } + else + { + CleanupAllBatchTradesFromQueue(detail); + } + } + else + { + HandleAbortedTrade(detail, type, priority, result); + } } private void HandleAbortedTrade(PokeTradeDetail detail, PokeRoutineType type, uint priority, PokeTradeResult result)