From 62aa310a4f318be03b7492a10c2508dccdf2e86e Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Wed, 7 May 2025 17:27:26 +0400 Subject: [PATCH] server: fixed game freeze on leaving player before finish target selection (example: Nethergoyf, close #13567, related to #11285) --- Mage.Sets/src/mage/cards/n/Nethergoyf.java | 7 +++-- Mage/src/main/java/mage/target/Targets.java | 32 ++++++++++++++------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Mage.Sets/src/mage/cards/n/Nethergoyf.java b/Mage.Sets/src/mage/cards/n/Nethergoyf.java index bc8d5c71602..858e2718695 100644 --- a/Mage.Sets/src/mage/cards/n/Nethergoyf.java +++ b/Mage.Sets/src/mage/cards/n/Nethergoyf.java @@ -6,7 +6,6 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.CostsImpl; import mage.abilities.costs.common.ExileFromGraveCost; -import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.continuous.SetBasePowerToughnessPlusOneSourceEffect; import mage.abilities.hint.HintUtils; @@ -100,7 +99,11 @@ class NethergoyfTarget extends TargetCardInYourGraveyard { types.size() + " of 4", types.size() >= 4 ? Color.GREEN : Color.RED ); - text += " [" + types.stream().map(CardType::toString).collect(Collectors.joining(", ")) + "])"; + String info = types.stream().map(CardType::toString).collect(Collectors.joining(", ")); + if (!info.isEmpty()) { + text += " [" + info + "]"; + } + text += ")"; return text; } diff --git a/Mage/src/main/java/mage/target/Targets.java b/Mage/src/main/java/mage/target/Targets.java index 7499467e02c..2d337ffbabd 100644 --- a/Mage/src/main/java/mage/target/Targets.java +++ b/Mage/src/main/java/mage/target/Targets.java @@ -52,11 +52,17 @@ public class Targets extends ArrayList implements Copyable { } public boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Ability source, Game game) { - if (this.size() > 0) { - if (!canChoose(playerId, source, game)) { - return false; - } - while (!isChosen(game)) { + Player player = game.getPlayer(playerId); + if (player == null) { + return false; + } + + if (this.size() > 0 && !this.doneChoosing(game)) { + do { + if (!player.canRespond() || !canChoose(playerId, source, game)) { + return false; + } + Target target = this.getUnchosen(game).get(0); if (!target.choose(outcome, playerId, sourceId, source, game)) { return false; @@ -67,13 +73,17 @@ public class Targets extends ArrayList implements Copyable { } public boolean chooseTargets(Outcome outcome, UUID playerId, Ability source, boolean noMana, Game game, boolean canCancel) { - if (this.size() > 0) { - if (!canChoose(playerId, source, game)) { - return false; - } + Player player = game.getPlayer(playerId); + if (player == null) { + return false; + } + + if (this.size() > 0 && !this.doneChoosing(game)) { + do { + if (!player.canRespond() || !canChoose(playerId, source, game)) { + return false; + } - //int state = game.bookmarkState(); - while (!isChosen(game)) { Target target = this.getUnchosen(game).get(0); UUID targetController = playerId;