Make the type checking on predicates added to filters stricter to make runtime errors less likely.

This commit is contained in:
dilnu 2018-07-21 23:25:52 -04:00
parent 9705f7228c
commit a8cd19eaea
11 changed files with 50 additions and 32 deletions

View file

@ -18,6 +18,7 @@ import mage.counters.Counter;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.Filter; import mage.filter.Filter;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.predicate.permanent.CardCounterPredicate; import mage.filter.predicate.permanent.CardCounterPredicate;
import mage.filter.predicate.permanent.CounterPredicate; import mage.filter.predicate.permanent.CounterPredicate;
import mage.game.Game; import mage.game.Game;
@ -59,13 +60,13 @@ public final class DustOfMoments extends CardImpl {
public abstract static class DustOfMomentsEffect extends OneShotEffect { public abstract static class DustOfMomentsEffect extends OneShotEffect {
private final Counter counter; private final Counter counter;
private final Filter<Card> permFilter; private final Filter<Permanent> permFilter;
private final Filter<Card> exiledFilter; private final Filter<Card> exiledFilter;
public DustOfMomentsEffect() { public DustOfMomentsEffect() {
super(Outcome.Benefit); super(Outcome.Benefit);
this.counter = new Counter(CounterType.TIME.getName(), 2); this.counter = new Counter(CounterType.TIME.getName(), 2);
this.permFilter = new FilterCard("permanent and each suspended card"); this.permFilter = new FilterPermanent("permanent and each suspended card");
permFilter.add(new CounterPredicate(CounterType.TIME)); permFilter.add(new CounterPredicate(CounterType.TIME));
this.exiledFilter = new FilterCard("permanent and each suspended card"); this.exiledFilter = new FilterCard("permanent and each suspended card");

View file

@ -55,15 +55,15 @@ public final class Interdict extends CardImpl {
} }
} }
class InterdictPredicate implements Predicate<Ability> { class InterdictPredicate implements Predicate<StackObject> {
public InterdictPredicate() { public InterdictPredicate() {
} }
@Override @Override
public boolean apply(Ability input, Game game) { public boolean apply(StackObject input, Game game) {
if (input instanceof StackAbility && input.getAbilityType() == AbilityType.ACTIVATED) { if (input instanceof StackAbility && ((StackAbility) input).getAbilityType() == AbilityType.ACTIVATED) {
MageObject sourceObject = input.getSourceObject(game); MageObject sourceObject = ((StackAbility) input).getSourceObject(game);
if (sourceObject != null) { if (sourceObject != null) {
return (sourceObject.isArtifact() return (sourceObject.isArtifact()
|| sourceObject.isEnchantment() || sourceObject.isEnchantment()

View file

@ -61,15 +61,16 @@ public final class OupheVandals extends CardImpl {
} }
} }
class ArtifactSourcePredicate implements Predicate<Ability> { class ArtifactSourcePredicate implements Predicate<StackObject> {
public ArtifactSourcePredicate() { public ArtifactSourcePredicate() {
} }
@Override @Override
public boolean apply(Ability input, Game game) { public boolean apply(StackObject input, Game game) {
if (input instanceof StackAbility) { if (input instanceof StackAbility) {
return input.getSourceObject(game).isArtifact() && input.getAbilityType() == AbilityType.ACTIVATED; StackAbility ability = (StackAbility) input;
return ability.getSourceObject(game).isArtifact() && ability.getAbilityType() == AbilityType.ACTIVATED;
} }
return false; return false;
} }

View file

@ -10,7 +10,7 @@ import mage.constants.CardType;
import mage.filter.FilterSpell; import mage.filter.FilterSpell;
import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicate;
import mage.game.Game; import mage.game.Game;
import mage.game.stack.Spell; import mage.game.stack.StackObject;
import mage.target.TargetSpell; import mage.target.TargetSpell;
import mage.watchers.common.CastSpellLastTurnWatcher; import mage.watchers.common.CastSpellLastTurnWatcher;
@ -45,10 +45,10 @@ public final class SecondGuess extends CardImpl {
} }
} }
class SecondSpellPredicate implements Predicate<Spell> { class SecondSpellPredicate implements Predicate<StackObject> {
@Override @Override
public boolean apply(Spell input, Game game) { public boolean apply(StackObject input, Game game) {
CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName());
if (watcher.getSpellOrder(new MageObjectReference(input.getId(), game), game) == 2) { if (watcher.getSpellOrder(new MageObjectReference(input.getId(), game), game) == 2) {

View file

@ -12,6 +12,7 @@ import mage.filter.FilterSpell;
import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicate;
import mage.game.Game; import mage.game.Game;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackObject;
/** /**
* *
@ -43,7 +44,7 @@ public final class SecretsOfTheDead extends CardImpl {
} }
} }
class SpellZonePredicate implements Predicate<Spell> { class SpellZonePredicate implements Predicate<StackObject> {
private final Zone zone; private final Zone zone;
@ -52,8 +53,8 @@ class SpellZonePredicate implements Predicate<Spell> {
} }
@Override @Override
public boolean apply(Spell input, Game game) { public boolean apply(StackObject input, Game game) {
return input.getFromZone().match(zone); return input instanceof Spell && ((Spell) input).getFromZone().match(zone);
} }
@Override @Override

View file

@ -18,7 +18,7 @@ public interface Filter<E> extends Serializable {
boolean match(E o, Game game); boolean match(E o, Game game);
Filter<E> add(Predicate predicate); Filter<E> add(Predicate<? super E> predicate);
boolean checkObjectClass(Object object); boolean checkObjectClass(Object object);

View file

@ -14,9 +14,9 @@ import mage.game.Game;
*/ */
public abstract class FilterImpl<E> implements Filter<E> { public abstract class FilterImpl<E> implements Filter<E> {
protected List<Predicate<Object>> predicates = new ArrayList<>(); protected List<Predicate<? super E>> predicates = new ArrayList<>();
protected String message; protected String message;
protected boolean lockedFilter; // Helps to prevent to "accidently" modify the StaticFilters objects protected boolean lockedFilter; // Helps to prevent "accidentally" modifying the StaticFilters objects
@Override @Override
public abstract FilterImpl<E> copy(); public abstract FilterImpl<E> copy();
@ -41,7 +41,7 @@ public abstract class FilterImpl<E> implements Filter<E> {
} }
@Override @Override
public final Filter add(Predicate predicate) { public final Filter add(Predicate<? super E> predicate) {
if (isLockedFilter()) { if (isLockedFilter()) {
throw new UnsupportedOperationException("You may not modify a locked filter"); throw new UnsupportedOperationException("You may not modify a locked filter");
} }

View file

@ -30,6 +30,8 @@
package mage.filter.common; package mage.filter.common;
import java.util.UUID; import java.util.UUID;
import mage.MageObject;
import mage.abilities.keyword.SuspendAbility; import mage.abilities.keyword.SuspendAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.counters.CounterType; import mage.counters.CounterType;
@ -46,7 +48,7 @@ import mage.game.permanent.Permanent;
* *
* @author emerald000 * @author emerald000
*/ */
public class FilterPermanentOrSuspendedCard extends FilterImpl<Object> implements FilterInPlay<Object> { public class FilterPermanentOrSuspendedCard extends FilterImpl<MageObject> implements FilterInPlay<MageObject> {
protected FilterCard cardFilter; protected FilterCard cardFilter;
protected FilterPermanent permanentFilter; protected FilterPermanent permanentFilter;
@ -71,11 +73,11 @@ public class FilterPermanentOrSuspendedCard extends FilterImpl<Object> implement
@Override @Override
public boolean checkObjectClass(Object object) { public boolean checkObjectClass(Object object) {
return true; return object instanceof MageObject;
} }
@Override @Override
public boolean match(Object o, Game game) { public boolean match(MageObject o, Game game) {
if (o instanceof Permanent) { if (o instanceof Permanent) {
return permanentFilter.match((Permanent) o, game); return permanentFilter.match((Permanent) o, game);
} else if (o instanceof Card) { } else if (o instanceof Card) {
@ -85,7 +87,7 @@ public class FilterPermanentOrSuspendedCard extends FilterImpl<Object> implement
} }
@Override @Override
public boolean match(Object o, UUID sourceId, UUID playerId, Game game) { public boolean match(MageObject o, UUID sourceId, UUID playerId, Game game) {
if (o instanceof Permanent) { if (o instanceof Permanent) {
return permanentFilter.match((Permanent) o, sourceId, playerId, game); return permanentFilter.match((Permanent) o, sourceId, playerId, game);
} else if (o instanceof Card) { } else if (o instanceof Card) {
@ -106,7 +108,7 @@ public class FilterPermanentOrSuspendedCard extends FilterImpl<Object> implement
this.permanentFilter = permanentFilter; this.permanentFilter = permanentFilter;
} }
public void setSpellFilter(FilterCard cardFilter) { public void setCardFilter(FilterCard cardFilter) {
this.cardFilter = cardFilter; this.cardFilter = cardFilter;
} }

View file

@ -30,10 +30,14 @@
package mage.filter.common; package mage.filter.common;
import java.util.UUID; import java.util.UUID;
import mage.MageObject;
import mage.filter.FilterImpl; import mage.filter.FilterImpl;
import mage.filter.FilterInPlay; import mage.filter.FilterInPlay;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.FilterSpell; import mage.filter.FilterSpell;
import mage.filter.predicate.ObjectPlayer;
import mage.filter.predicate.ObjectPlayerPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.stack.Spell; import mage.game.stack.Spell;
@ -42,7 +46,7 @@ import mage.game.stack.Spell;
* *
* @author LevelX * @author LevelX
*/ */
public class FilterSpellOrPermanent extends FilterImpl<Object> implements FilterInPlay<Object> { public class FilterSpellOrPermanent extends FilterImpl<MageObject> implements FilterInPlay<MageObject> {
protected FilterPermanent permanentFilter; protected FilterPermanent permanentFilter;
protected FilterSpell spellFilter; protected FilterSpell spellFilter;
@ -65,11 +69,11 @@ public class FilterSpellOrPermanent extends FilterImpl<Object> implements Filter
@Override @Override
public boolean checkObjectClass(Object object) { public boolean checkObjectClass(Object object) {
return true; return object instanceof MageObject;
} }
@Override @Override
public boolean match(Object o, Game game) { public boolean match(MageObject o, Game game) {
if (o instanceof Spell) { if (o instanceof Spell) {
return spellFilter.match((Spell) o, game); return spellFilter.match((Spell) o, game);
} else if (o instanceof Permanent) { } else if (o instanceof Permanent) {
@ -79,7 +83,7 @@ public class FilterSpellOrPermanent extends FilterImpl<Object> implements Filter
} }
@Override @Override
public boolean match(Object o, UUID sourceId, UUID playerId, Game game) { public boolean match(MageObject o, UUID sourceId, UUID playerId, Game game) {
if (o instanceof Spell) { if (o instanceof Spell) {
return spellFilter.match((Spell) o, sourceId, playerId, game); return spellFilter.match((Spell) o, sourceId, playerId, game);
} else if (o instanceof Permanent) { } else if (o instanceof Permanent) {
@ -88,11 +92,19 @@ public class FilterSpellOrPermanent extends FilterImpl<Object> implements Filter
return false; return false;
} }
public final void add(ObjectPlayerPredicate<? extends ObjectPlayer> predicate) {
if (isLockedFilter()) {
throw new UnsupportedOperationException("You may not modify a locked filter");
}
spellFilter.add(predicate);
permanentFilter.add(predicate);
}
public FilterPermanent getPermanentFilter() { public FilterPermanent getPermanentFilter() {
return this.permanentFilter; return this.permanentFilter;
} }
public FilterSpell getspellFilter() { public FilterSpell getSpellFilter() {
return this.spellFilter; return this.spellFilter;
} }

View file

@ -5,6 +5,7 @@ import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicate;
import mage.game.Controllable;
import mage.game.Game; import mage.game.Game;
import mage.game.stack.StackObject; import mage.game.stack.StackObject;
import mage.target.Target; import mage.target.Target;
@ -13,7 +14,7 @@ import mage.target.Target;
* *
* @author jeffwadsworth * @author jeffwadsworth
*/ */
public class NumberOfTargetsPredicate implements Predicate<MageObject> { public class NumberOfTargetsPredicate implements Predicate<Controllable> {
private final int targets; private final int targets;
@ -22,7 +23,7 @@ public class NumberOfTargetsPredicate implements Predicate<MageObject> {
} }
@Override @Override
public boolean apply(MageObject input, Game game) { public boolean apply(Controllable input, Game game) {
StackObject stackObject = game.getState().getStack().getStackObject(input.getId()); StackObject stackObject = game.getState().getStack().getStackObject(input.getId());
if (stackObject != null) { if (stackObject != null) {
int numberOfTargets = 0; int numberOfTargets = 0;

View file

@ -69,7 +69,7 @@ public class TargetPermanentOrSuspendedCard extends TargetImpl {
} }
@Override @Override
public Filter<Object> getFilter() { public Filter<MageObject> getFilter() {
return this.filter; return this.filter;
} }