Prevent concurrent modification exception when moving token to a zone besides the graveyard

This commit is contained in:
drdev
2014-10-15 16:07:54 +00:00
parent ab7fb0788e
commit 99e2b67e04
3 changed files with 32 additions and 9 deletions

View File

@@ -251,4 +251,10 @@ public class FCollection<T> implements List<T>, Set<T>, FCollectionView<T>, Clon
} }
return subList; return subList;
} }
@Override
public Iterable<T> threadSafeIterator() {
//create a new linked list for iterating to make it thread safe and avoid concurrent modification exceptions
return new LinkedList<T>(list);
}
} }

View File

@@ -13,4 +13,5 @@ public interface FCollectionView<T> extends Iterable<T> {
int lastIndexOf(Object o); int lastIndexOf(Object o);
boolean contains(Object o); boolean contains(Object o);
List<T> subList(int fromIndex, int toIndex); List<T> subList(int fromIndex, int toIndex);
Iterable<T> threadSafeIterator();
} }

View File

@@ -675,23 +675,32 @@ public class GameAction {
if (zt == ZoneType.Battlefield) { if (zt == ZoneType.Battlefield) {
continue; continue;
} }
for (Card c : p.getCardsIn(zt)) { Iterable<Card> cards = p.getCardsIn(zt).threadSafeIterator();
for (Card c : cards) {
// If a token is in a zone other than the battlefield, it ceases to exist. // If a token is in a zone other than the battlefield, it ceases to exist.
checkAgain |= stateBasedAction704_5d(c); checkAgain |= stateBasedAction704_5d(c);
} }
} }
} }
List<Card> noRegCreats = new ArrayList<Card>(); Iterable<Card> cards = game.getCardsIn(ZoneType.Battlefield).threadSafeIterator();
List<Card> desCreats = new ArrayList<Card>(); List<Card> noRegCreats = null;
for (Card c : game.getCardsIn(ZoneType.Battlefield)) { List<Card> desCreats = null;
for (Card c : cards) {
if (c.isCreature()) { if (c.isCreature()) {
// Rule 704.5f - Put into grave (no regeneration) for toughness <= 0 // Rule 704.5f - Put into grave (no regeneration) for toughness <= 0
if (c.getNetToughness() <= 0) { if (c.getNetToughness() <= 0) {
if (noRegCreats == null) {
noRegCreats = new LinkedList<Card>();
}
noRegCreats.add(c); noRegCreats.add(c);
checkAgain = true; checkAgain = true;
} else if (c.hasKeyword("CARDNAME can't be destroyed by lethal damage unless lethal damage dealt by a single source is marked on it.")) { }
else if (c.hasKeyword("CARDNAME can't be destroyed by lethal damage unless lethal damage dealt by a single source is marked on it.")) {
for (final Integer dmg : c.getReceivedDamageFromThisTurn().values()) { for (final Integer dmg : c.getReceivedDamageFromThisTurn().values()) {
if (c.getNetToughness() <= dmg.intValue()) { if (c.getNetToughness() <= dmg.intValue()) {
if (desCreats == null) {
desCreats = new LinkedList<Card>();
}
desCreats.add(c); desCreats.add(c);
checkAgain = true; checkAgain = true;
break; break;
@@ -700,6 +709,9 @@ public class GameAction {
} }
// Rule 704.5g - Destroy due to lethal damage // Rule 704.5g - Destroy due to lethal damage
else if (c.getNetToughness() <= c.getDamage()) { else if (c.getNetToughness() <= c.getDamage()) {
if (desCreats == null) {
desCreats = new LinkedList<Card>();
}
desCreats.add(c); desCreats.add(c);
checkAgain = true; checkAgain = true;
} }
@@ -721,11 +733,15 @@ public class GameAction {
} }
} }
for (Card c : noRegCreats) { if (noRegCreats != null) {
sacrificeDestroy(c); for (Card c : noRegCreats) {
sacrificeDestroy(c);
}
} }
for (Card c : desCreats) { if (desCreats != null) {
destroy(c, null); for (Card c : desCreats) {
destroy(c, null);
}
} }
if (game.getTriggerHandler().runWaitingTriggers()) { if (game.getTriggerHandler().runWaitingTriggers()) {