* Gain ability effect: fixed rollback error with AI games and too many cards (related to d202278ccd);

This commit is contained in:
Oleg Agafonov 2021-08-11 12:43:13 +04:00
parent 8a69ea97e7
commit 9f882824a0
5 changed files with 51 additions and 109 deletions

View file

@ -0,0 +1,51 @@
package org.mage.test.cards.continuous;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps;
public class ConcurrentModificationExceptionTest extends CardTestPlayerBaseWithAIHelps {
// see details here: https://github.com/magefree/mage/commit/d202278ccd6876f8113d26951e6bd018f6e9b792
@Ignore // debug only: too slow, only for manual run (use multi run to ensure)
@Test
public void massWarpWorld() {
removeAllCardsFromLibrary(playerA);
addCard(Zone.BATTLEFIELD, playerA, "Prosperous Innkeeper");
addCard(Zone.BATTLEFIELD, playerA, "Tireless Tracker");
addCard(Zone.BATTLEFIELD, playerA, "Gilded Goose");
addCard(Zone.BATTLEFIELD, playerA, "Galazeth Prismari");
addCard(Zone.BATTLEFIELD, playerA, "Wood Elves");
addCard(Zone.BATTLEFIELD, playerA, "Nesting Dragon");
addCard(Zone.BATTLEFIELD, playerA, "Primeval Titan");
addCard(Zone.BATTLEFIELD, playerA, "Eternal Witness");
addCard(Zone.BATTLEFIELD, playerA, "Westvale Abbey");
addCard(Zone.BATTLEFIELD, playerA, "Gaea's Cradle");
addCard(Zone.BATTLEFIELD, playerA, "Castle Garenbrig");
addCard(Zone.BATTLEFIELD, playerA, "Nyxbloom Ancient");
addCard(Zone.BATTLEFIELD, playerA, "Huntmaster of the Fells");
addCard(Zone.BATTLEFIELD, playerA, "Xenagos, the Reveler");
addCard(Zone.BATTLEFIELD, playerA, "Thromok the Insatiable");
addCard(Zone.BATTLEFIELD, playerA, "The World Tree");
addCard(Zone.BATTLEFIELD, playerA, "Nylea, Keen-Eyed");
addCard(Zone.BATTLEFIELD, playerA, "Kogla, the Titan Ape");
addCard(Zone.BATTLEFIELD, playerA, "Acidic Slime");
addCard(Zone.BATTLEFIELD, playerA, "Druid Class");
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10);
addCard(Zone.HAND, playerA, "Warp World");
// simple test
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Warp World");
aiPlayStep(1, PhaseStep.PRECOMBAT_MAIN, playerA);
//setStrictChooseMode(true); // need AI while cards adding
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertAllCommandsUsed();
}
}

View file

@ -1,71 +0,0 @@
package org.mage.test.cards.continuous;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
import java.util.ConcurrentModificationException;
// goal is to test the concurrentmodification exception related to continuous effects
public class WarpworldTest extends CardTestPlayerBase {
private final String innkeeper = "Prosperous Innkeeper";
private final String tracker = "Tireless Tracker";
private final String goose = "Gilded Goose";
private final String galazeth_prismari = "Galazeth Prismari";
private final String wood_elves = "Wood Elves";
private final String nesting_dragon = "Nesting Dragon";
private final String primeval_titan = "Primeval Titan";
private final String eternal_witness = "Eternal Witness";
private final String westvale_abbey = "Westvale Abbey";
private final String cradle = "Gaea's Cradle";
private final String castle_garenbrig = "Castle Garenbrig";
private final String nyxbloom_ancient = "Nyxbloom Ancient";
private final String huntmaster = "Huntmaster of the Fells";
private final String xenagos = "Xenagos, the Reveler";
private final String thromok = "Thromok the Insatiable";
private final String world_tree = "The World Tree";
private final String nylea = "Nylea, Keen-Eyed";
private final String kogla = "Kogla, the Titan Ape";
private final String slime = "Acidic Slime";
private final String druid = "Druid Class";
@Test
public void massWarpWorld(){
removeAllCardsFromLibrary(playerA);
addCard(Zone.BATTLEFIELD, playerA, innkeeper);
addCard(Zone.BATTLEFIELD, playerA, tracker);
addCard(Zone.BATTLEFIELD, playerA, goose);
addCard(Zone.BATTLEFIELD, playerA, galazeth_prismari);
addCard(Zone.BATTLEFIELD, playerA, wood_elves);
addCard(Zone.BATTLEFIELD, playerA, nesting_dragon);
addCard(Zone.BATTLEFIELD, playerA, primeval_titan);
addCard(Zone.BATTLEFIELD, playerA, eternal_witness);
addCard(Zone.BATTLEFIELD, playerA, westvale_abbey);
addCard(Zone.BATTLEFIELD, playerA, cradle);
addCard(Zone.BATTLEFIELD, playerA, castle_garenbrig);
addCard(Zone.BATTLEFIELD, playerA, nyxbloom_ancient);
addCard(Zone.BATTLEFIELD, playerA, huntmaster);
addCard(Zone.BATTLEFIELD, playerA, xenagos);
addCard(Zone.BATTLEFIELD, playerA, thromok);
addCard(Zone.BATTLEFIELD, playerA, world_tree);
addCard(Zone.BATTLEFIELD, playerA, nylea);
addCard(Zone.BATTLEFIELD, playerA, kogla);
addCard(Zone.BATTLEFIELD, playerA, slime);
addCard(Zone.BATTLEFIELD, playerA, druid);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10);
addCard(Zone.HAND, playerA, "Warp World");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA,"Warp World");
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
try {
execute();
}
catch (ConcurrentModificationException concurrentModificationException){
concurrentModificationException.printStackTrace();
Assert.fail("Concurrent Modification Exception raised");
}
}
}

View file

@ -102,18 +102,6 @@ public class GainAbilityAllEffect extends ContinuousEffectImpl {
perm.addAbility(ability, source.getSourceId(), game);
}
}
// still as long as the prev. permanent is known to the LKI (e.g. Mikaeus, the Unhallowed) so gained dies triggered ability will trigger
Map<UUID, MageObject> LKIBattlefield = game.getLKI().get(Zone.BATTLEFIELD);
if (LKIBattlefield != null) {
for (MageObject mageObject : LKIBattlefield.values()) {
Permanent perm = (Permanent) mageObject;
if (!(excludeSource && perm.getId().equals(source.getSourceId())) && selectedByRuntimeData(perm, source, game)) {
if (filter.match(perm, source.getSourceId(), source.getControllerId(), game)) {
perm.addAbility(ability, source.getSourceId(), game);
}
}
}
}
}
return true;
}

View file

@ -104,20 +104,6 @@ public class GainAbilityControlledEffect extends ContinuousEffectImpl {
}
}
}
// still as long as the prev. permanent is known to the LKI (e.g. Mikaeus, the Unhallowed) so gained dies triggered ability will trigger
Map<UUID, MageObject> LKIBattlefield = game.getLKI().get(Zone.BATTLEFIELD);
if (LKIBattlefield != null) {
for (MageObject mageObject : LKIBattlefield.values()) {
Permanent perm = (Permanent) mageObject;
if (!(excludeSource && perm.getId().equals(source.getSourceId()))) {
if (filter.match(perm, source.getSourceId(), source.getControllerId(), game)) {
for (Ability abilityToAdd : ability) {
perm.addAbility(abilityToAdd, source.getSourceId(), game);
}
}
}
}
}
}
return true;
}

View file

@ -99,18 +99,6 @@ public class LoseAbilityAllEffect extends ContinuousEffectImpl {
perm.removeAbilities(ability, source.getSourceId(), game);
}
}
// still as long as the prev. permanent is known to the LKI (e.g. Mikaeus, the Unhallowed) so gained dies triggered ability will trigger
Map<UUID, MageObject> LKIBattlefield = game.getLKI().get(Zone.BATTLEFIELD);
if (LKIBattlefield != null) {
for (MageObject mageObject : LKIBattlefield.values()) {
Permanent perm = (Permanent) mageObject;
if (!(excludeSource && perm.getId().equals(source.getSourceId()))) {
if (filter.match(perm, source.getSourceId(), source.getControllerId(), game)) {
perm.removeAbilities(ability, source.getSourceId(), game);
}
}
}
}
}
return true;
}