mirror of
https://github.com/magefree/mage.git
synced 2026-01-26 21:29:17 -08:00
* Gain abilities - fixed wrong order effects with changeling ability (all creature type effect, #6147);
This commit is contained in:
parent
1b4145e5b8
commit
b6d76a7c02
16 changed files with 220 additions and 32 deletions
|
|
@ -0,0 +1,88 @@
|
|||
package org.mage.test.cards.continuous;
|
||||
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
|
||||
import mage.abilities.keyword.ChangelingAbility;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
import mage.constants.*;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.NamePredicate;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class GainAbilityDependenciesTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void test_GenerationByFilters() {
|
||||
// auto-dependency must find subtype predicate and add dependecy on it
|
||||
FilterPermanent filterEmpty = new FilterPermanent("empty");
|
||||
FilterPermanent filterSubtype = new FilterPermanent(SubType.HUMAN, "single");
|
||||
FilterPermanent filterOr = new FilterPermanent("or");
|
||||
filterOr.add(Predicates.or(
|
||||
SubType.HUMAN.getPredicate(),
|
||||
SubType.ORC.getPredicate()));
|
||||
FilterPermanent filterTree = new FilterPermanent("tree");
|
||||
filterTree.add(Predicates.and(
|
||||
new NamePredicate("test"),
|
||||
Predicates.or(
|
||||
SubType.HUMAN.getPredicate(),
|
||||
SubType.ORC.getPredicate())
|
||||
));
|
||||
|
||||
ContinuousEffectImpl effectEmpty = new GainAbilityAllEffect(HasteAbility.getInstance(), Duration.EndOfTurn, filterEmpty);
|
||||
ContinuousEffectImpl effectSubtype = new GainAbilityAllEffect(HasteAbility.getInstance(), Duration.EndOfTurn, filterSubtype);
|
||||
ContinuousEffectImpl effectOr = new GainAbilityAllEffect(HasteAbility.getInstance(), Duration.EndOfTurn, filterOr);
|
||||
ContinuousEffectImpl effectTree = new GainAbilityAllEffect(HasteAbility.getInstance(), Duration.EndOfTurn, filterTree);
|
||||
|
||||
Assert.assertFalse("must haven't depends with empty filter", effectEmpty.getDependedToTypes().contains(DependencyType.AddingCreatureType));
|
||||
Assert.assertTrue("must have depend from subtype predicate", effectSubtype.getDependedToTypes().contains(DependencyType.AddingCreatureType));
|
||||
Assert.assertTrue("must have depend from or predicate", effectOr.getDependedToTypes().contains(DependencyType.AddingCreatureType));
|
||||
Assert.assertTrue("must have depend from tree predicate", effectTree.getDependedToTypes().contains(DependencyType.AddingCreatureType));
|
||||
}
|
||||
|
||||
/**
|
||||
* I had an elephant token equipped with Amorphous Axe attacking and a Tempered Sliver in play. The token did combat
|
||||
* damage to a player but it didnt get the +1/+1 counter it hsould be getting.
|
||||
*
|
||||
* More details: https://github.com/magefree/mage/issues/6147
|
||||
*/
|
||||
@Test
|
||||
public void test_SliverGain() {
|
||||
// Equipped creature gets +3/+0 and is every creature type.
|
||||
// Equip {3}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Amorphous Axe");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
||||
//
|
||||
// Create a 3/3 green Elephant creature token.
|
||||
addCard(Zone.HAND, playerA, "Elephant Ambush"); // {2}{G}{G}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
//
|
||||
// Sliver creatures you control have “Whenever this creature deals combat damage to a player, put a +1/+1 counter on it.”
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tempered Sliver");
|
||||
|
||||
// cast token
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Elephant Ambush");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkPermanentCount("token must exist", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Elephant", 1);
|
||||
|
||||
// equip
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {3}", "Elephant");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkAbility("must have all type ability", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Elephant", ChangelingAbility.class, true);
|
||||
|
||||
// attack with +1 token
|
||||
attack(3, playerA, "Elephant", playerB);
|
||||
checkPermanentCounters("must have counter", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Elephant", CounterType.P1P1, 1);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(3, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ import mage.cards.FrameStyle;
|
|||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.util.GameLog;
|
||||
import mage.util.SubTypeList;
|
||||
|
||||
|
|
@ -251,8 +252,14 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
if (value.getSubTypeSet() != SubTypeSet.CreatureType) {
|
||||
return false;
|
||||
}
|
||||
// as it is creature subtype, then check the existence of Changeling
|
||||
return abilities.contains(ChangelingAbility.getInstance()) || isAllCreatureTypes();
|
||||
// as it is a creature subtype, then check the existence of Changeling
|
||||
Abilities<Ability> checkList;
|
||||
if (this instanceof Permanent) {
|
||||
checkList = ((Permanent) this).getAbilities(game);
|
||||
} else {
|
||||
checkList = abilities;
|
||||
}
|
||||
return checkList.contains(ChangelingAbility.getInstance()) || isAllCreatureTypes();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -162,6 +162,14 @@ public class ConditionalContinuousEffect extends ContinuousEffectImpl {
|
|||
return super.getDependencyTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<DependencyType> getDependedToTypes() {
|
||||
if (effect != null) {
|
||||
return effect.getDependedToTypes();
|
||||
}
|
||||
return super.getDependedToTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> isDependentTo(List<ContinuousEffect> allEffectsInLayer) {
|
||||
if (effect != null) {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ public interface ContinuousEffect extends Effect {
|
|||
|
||||
void setDependedToType(DependencyType dependencyType);
|
||||
|
||||
EnumSet<DependencyType> getDependedToTypes();
|
||||
|
||||
void addDependedToType(DependencyType dependencyType);
|
||||
|
||||
void setStartingControllerAndTurnNum(Game game, UUID startingController, UUID activePlayerId);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,17 @@ package mage.abilities.effects;
|
|||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.CompoundAbility;
|
||||
import mage.abilities.MageSingleton;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.DomainValue;
|
||||
import mage.abilities.dynamicvalue.common.SignInversionDynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||
import mage.abilities.keyword.ChangelingAbility;
|
||||
import mage.constants.*;
|
||||
import mage.filter.Filter;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.TargetPointer;
|
||||
|
|
@ -319,6 +324,11 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
return dependencyTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<DependencyType> getDependedToTypes() {
|
||||
return dependendToTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDependencyType(DependencyType dependencyType) {
|
||||
dependencyTypes.add(dependencyType);
|
||||
|
|
@ -341,4 +351,48 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-generates dependencies on different effects (what's apply first and what's apply second)
|
||||
*/
|
||||
public void generateGainAbilityDependencies(Ability abilityToGain, Filter filterToSearch) {
|
||||
this.addDependencyType(DependencyType.AddingAbility);
|
||||
this.generateGainAbilityDependenciesFromAbility(abilityToGain);
|
||||
this.generateGainAbilityDependenciesFromFilter(filterToSearch);
|
||||
}
|
||||
|
||||
public void generateGainAbilityDependencies(CompoundAbility abilityToGain, Filter filterToSearch) {
|
||||
this.addDependencyType(DependencyType.AddingAbility);
|
||||
this.generateGainAbilityDependenciesFromAbility(abilityToGain);
|
||||
this.generateGainAbilityDependenciesFromFilter(filterToSearch);
|
||||
}
|
||||
|
||||
private void generateGainAbilityDependenciesFromAbility(CompoundAbility compoundAbility) {
|
||||
if (compoundAbility == null) return;
|
||||
for (Ability ability : compoundAbility) {
|
||||
generateGainAbilityDependenciesFromAbility(ability);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateGainAbilityDependenciesFromAbility(Ability ability) {
|
||||
if (ability == null) return;
|
||||
|
||||
// 1. "Is all type" ability (changeling)
|
||||
// make dependency
|
||||
if (ability instanceof ChangelingAbility) {
|
||||
this.addDependencyType(DependencyType.AddingCreatureType);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateGainAbilityDependenciesFromFilter(Filter filter) {
|
||||
if (filter == null) return;
|
||||
|
||||
// 1. "Is all type" ability (changeling)
|
||||
// wait dependency
|
||||
// extraPredicates from some filters is player related, you don't need it here
|
||||
List<Predicate> list = new ArrayList<>();
|
||||
Predicates.collectAllComponents(filter.getPredicates(), list);
|
||||
if (list.stream().anyMatch(p -> p instanceof SubType.SubTypePredicate)) {
|
||||
this.addDependedToType(DependencyType.AddingCreatureType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ public class GainAbilityAllEffect extends ContinuousEffectImpl {
|
|||
this.ability.newId();
|
||||
this.filter = filter;
|
||||
this.excludeSource = excludeSource;
|
||||
this.addDependencyType(DependencyType.AddingAbility);
|
||||
|
||||
this.generateGainAbilityDependencies(ability, filter);
|
||||
}
|
||||
|
||||
public GainAbilityAllEffect(final GainAbilityAllEffect effect) {
|
||||
|
|
|
|||
|
|
@ -3,12 +3,7 @@ package mage.abilities.effects.common.continuous;
|
|||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.DependencyType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
|
@ -50,7 +45,8 @@ public class GainAbilityAttachedEffect extends ContinuousEffectImpl {
|
|||
} else {
|
||||
this.staticText = rule;
|
||||
}
|
||||
this.addDependencyType(DependencyType.AddingAbility);
|
||||
|
||||
this.generateGainAbilityDependencies(ability, null);
|
||||
}
|
||||
|
||||
public GainAbilityAttachedEffect(final GainAbilityAttachedEffect effect) {
|
||||
|
|
|
|||
|
|
@ -53,8 +53,9 @@ public class GainAbilityControlledEffect extends ContinuousEffectImpl {
|
|||
this.ability = ability;
|
||||
this.filter = filter;
|
||||
this.excludeSource = excludeSource;
|
||||
this.addDependencyType(DependencyType.AddingAbility);
|
||||
setText();
|
||||
|
||||
this.generateGainAbilityDependencies(ability, filter);
|
||||
}
|
||||
|
||||
public GainAbilityControlledEffect(final GainAbilityControlledEffect effect) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import mage.MageObjectReference;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.DependencyType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
|
|
@ -48,7 +47,8 @@ public class GainAbilitySourceEffect extends ContinuousEffectImpl implements Sou
|
|||
if (noStaticText) {
|
||||
staticText = null;
|
||||
}
|
||||
this.addDependencyType(DependencyType.AddingAbility);
|
||||
|
||||
this.generateGainAbilityDependencies(ability, null);
|
||||
}
|
||||
|
||||
public GainAbilitySourceEffect(final GainAbilitySourceEffect effect) {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ public class GainAbilityTargetEffect extends ContinuousEffectImpl {
|
|||
this.ability = ability;
|
||||
staticText = rule;
|
||||
this.onCard = onCard;
|
||||
this.addDependencyType(DependencyType.AddingAbility);
|
||||
|
||||
this.generateGainAbilityDependencies(ability, null);
|
||||
}
|
||||
|
||||
public GainAbilityTargetEffect(final GainAbilityTargetEffect effect) {
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
|
||||
package mage.constants;
|
||||
|
||||
/**
|
||||
* Dependency types are a part of a workaround solution to handle dependencies
|
||||
* of continuous effects.
|
||||
*
|
||||
* <p>
|
||||
* All continuous effects can:
|
||||
* addDependencyType -- make dependency (effect makes some changes)
|
||||
* addDependedToType -- wait another dependency (effect must wait until all ather effects finished)
|
||||
* <p>
|
||||
* http://magiccards.info/rule/613-interaction-of-continuous-effects.html
|
||||
*
|
||||
* https://github.com/magefree/mage/issues/1259
|
||||
*
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public enum DependencyType {
|
||||
AuraAddingRemoving,
|
||||
ArtifactAddingRemoving,
|
||||
AddingAbility,
|
||||
AddingCreatureType,
|
||||
BecomeForest,
|
||||
BecomeIsland,
|
||||
BecomeMountain,
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ public class FilterCard extends FilterObject<Card> {
|
|||
|
||||
public Set<Card> filter(Set<Card> cards, Game game) {
|
||||
return cards.stream().filter(card -> match(card, game)).collect(Collectors.toSet());
|
||||
|
||||
}
|
||||
|
||||
public boolean hasPredicates() {
|
||||
|
|
|
|||
|
|
@ -71,5 +71,4 @@ public class FilterPermanent extends FilterObject<Permanent> implements FilterIn
|
|||
public FilterPermanent copy() {
|
||||
return new FilterPermanent(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,5 +56,4 @@ public class FilterPlayer extends FilterImpl<Player> {
|
|||
public FilterPlayer copy() {
|
||||
return new FilterPlayer(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
package mage.filter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.filter.predicate.ObjectPlayer;
|
||||
import mage.filter.predicate.ObjectPlayerPredicate;
|
||||
import mage.filter.predicate.ObjectSourcePlayer;
|
||||
|
|
@ -11,6 +8,10 @@ import mage.game.Game;
|
|||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author North
|
||||
|
|
@ -51,5 +52,4 @@ public class FilterStackObject extends FilterObject<StackObject> {
|
|||
public FilterStackObject copy() {
|
||||
return new FilterStackObject(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,10 @@ public final class Predicates {
|
|||
|
||||
/**
|
||||
* Returns a predicate that evaluates to {@code true} if the given predicate evaluates to {@code false}.
|
||||
*
|
||||
* @param <T>
|
||||
* @param predicate
|
||||
* @return
|
||||
* @return
|
||||
*/
|
||||
public static <T> Predicate<T> not(Predicate<T> predicate) {
|
||||
return new NotPredicate<T>(predicate);
|
||||
|
|
@ -34,9 +35,10 @@ public final class Predicates {
|
|||
* components are evaluated in order, and evaluation will be "short-circuited" as soon as a false predicate is
|
||||
* found. It defensively copies the iterable passed in, so future changes to it won't alter the behavior of this
|
||||
* predicate. If {@code components} is empty, the returned predicate will always evaluate to {@code true}.
|
||||
*
|
||||
* @param <T>
|
||||
* @param components
|
||||
* @return
|
||||
* @return
|
||||
*/
|
||||
public static <T> Predicate<T> and(Iterable<? extends Predicate<? super T>> components) {
|
||||
return new AndPredicate<T>(defensiveCopy(components));
|
||||
|
|
@ -47,9 +49,10 @@ public final class Predicates {
|
|||
* components are evaluated in order, and evaluation will be "short-circuited" as soon as a false predicate is
|
||||
* found. It defensively copies the array passed in, so future changes to it won't alter the behavior of this
|
||||
* predicate. If {@code components} is empty, the returned predicate will always evaluate to {@code true}.
|
||||
*
|
||||
* @param <T>
|
||||
* @param components
|
||||
* @return
|
||||
* @return
|
||||
*/
|
||||
public static <T> Predicate<T> and(Predicate<? super T>... components) {
|
||||
return new AndPredicate<T>(defensiveCopy(components));
|
||||
|
|
@ -59,10 +62,11 @@ public final class Predicates {
|
|||
* Returns a predicate that evaluates to {@code true} if both of its components evaluate to {@code true}. The
|
||||
* components are evaluated in order, and evaluation will be "short-circuited" as soon as a false predicate is
|
||||
* found.
|
||||
*
|
||||
* @param <T>
|
||||
* @param first
|
||||
* @param second
|
||||
* @return
|
||||
* @return
|
||||
*/
|
||||
public static <T> Predicate<T> and(Predicate<? super T> first, Predicate<? super T> second) {
|
||||
return new AndPredicate<T>(Predicates.<T>asList(checkNotNull(first), checkNotNull(second)));
|
||||
|
|
@ -73,9 +77,10 @@ public final class Predicates {
|
|||
* components are evaluated in order, and evaluation will be "short-circuited" as soon as a true predicate is found.
|
||||
* It defensively copies the iterable passed in, so future changes to it won't alter the behavior of this predicate.
|
||||
* If {@code components} is empty, the returned predicate will always evaluate to {@code true}.
|
||||
*
|
||||
* @param <T>
|
||||
* @param components
|
||||
* @return
|
||||
* @return
|
||||
*/
|
||||
public static <T> Predicate<T> or(Iterable<? extends Predicate<? super T>> components) {
|
||||
return new OrPredicate<T>(defensiveCopy(components));
|
||||
|
|
@ -86,9 +91,10 @@ public final class Predicates {
|
|||
* components are evaluated in order, and evaluation will be "short-circuited" as soon as a true predicate is found.
|
||||
* It defensively copies the array passed in, so future changes to it won't alter the behavior of this predicate. If
|
||||
* {@code components} is empty, the returned predicate will always evaluate to {@code true}.
|
||||
*
|
||||
* @param <T>
|
||||
* @param components
|
||||
* @return
|
||||
* @return
|
||||
*/
|
||||
public static <T> Predicate<T> or(Predicate<? super T>... components) {
|
||||
return new OrPredicate<T>(defensiveCopy(components));
|
||||
|
|
@ -97,10 +103,11 @@ public final class Predicates {
|
|||
/**
|
||||
* Returns a predicate that evaluates to {@code true} if either of its components evaluates to {@code true}. The
|
||||
* components are evaluated in order, and evaluation will be "short-circuited" as soon as a true predicate is found.
|
||||
*
|
||||
* @param <T>
|
||||
* @param first
|
||||
* @param second
|
||||
* @return
|
||||
* @return
|
||||
*/
|
||||
public static <T> Predicate<T> or(Predicate<? super T> first, Predicate<? super T> second) {
|
||||
return new OrPredicate<T>(Predicates.<T>asList(first, second));
|
||||
|
|
@ -126,6 +133,7 @@ public final class Predicates {
|
|||
public String toString() {
|
||||
return "Not(" + predicate.toString() + ')';
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
|
|
@ -150,6 +158,7 @@ public final class Predicates {
|
|||
public String toString() {
|
||||
return "And(" + commaJoin(components) + ')';
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
|
|
@ -173,6 +182,7 @@ public final class Predicates {
|
|||
public String toString() {
|
||||
return "Or(" + commaJoin(components) + ')';
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
|
|
@ -215,4 +225,25 @@ public final class Predicates {
|
|||
sb.deleteCharAt(sb.length() - 1);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect real predicates for searching some data (see dependency effect code)
|
||||
*/
|
||||
public static void collectAllComponents(Predicate predicate, List<Predicate> res) {
|
||||
if (predicate instanceof NotPredicate) {
|
||||
res.add(((NotPredicate) predicate).predicate);
|
||||
} else if (predicate instanceof AndPredicate) {
|
||||
collectAllComponents(((AndPredicate) predicate).components, res);
|
||||
} else if (predicate instanceof OrPredicate) {
|
||||
collectAllComponents(((OrPredicate) predicate).components, res);
|
||||
} else {
|
||||
res.add(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
public static void collectAllComponents(List<Predicate> predicates, List<Predicate> res) {
|
||||
predicates.forEach(p -> {
|
||||
collectAllComponents(p, res);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue