diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index e24067bf276..83a75251128 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -48,6 +48,7 @@ import forge.game.zone.PlayerZoneBattlefield; import forge.game.zone.Zone; import forge.game.zone.ZoneType; import forge.item.PaperCard; +import forge.trackable.TrackableObject; import forge.util.Aggregates; import forge.util.CollectionSuppliers; import forge.util.Expressions; @@ -659,6 +660,7 @@ public class GameAction { final boolean refreeze = game.getStack().isFrozen(); game.getStack().setFrozen(true); + TrackableObject.freeze(); //prevent views flickering during while updating for state-based effects // do this multiple times, sometimes creatures/permanents will survive // when they shouldn't @@ -750,14 +752,16 @@ public class GameAction { } } // for q=0;q<9 + TrackableObject.unfreeze(); + if (runEvents) { game.fireEvent(new GameEventCardStatsChanged(allAffectedCards)); } checkGameOverCondition(); - if (game.getAge() != GameStage.Play) + if (game.getAge() != GameStage.Play) { return Collections.emptySet(); - + } game.getTriggerHandler().resetActiveTriggers(); if (!refreeze) { game.getStack().unfreezeStack(); diff --git a/forge-game/src/main/java/forge/trackable/TrackableObject.java b/forge-game/src/main/java/forge/trackable/TrackableObject.java index eaa47505813..a17dcbc8759 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableObject.java +++ b/forge-game/src/main/java/forge/trackable/TrackableObject.java @@ -1,5 +1,6 @@ package forge.trackable; +import java.util.ArrayList; import java.util.EnumMap; import java.util.EnumSet; @@ -7,6 +8,32 @@ import forge.game.IIdentifiable; //base class for objects that can be tracked and synced between game server and GUI public abstract class TrackableObject implements IIdentifiable { + private static int freezeCounter = 0; + public static void freeze() { + freezeCounter++; + } + public static void unfreeze() { + if (freezeCounter == 0 || --freezeCounter > 0 || delayedPropChanges.isEmpty()) { + return; + } + //after being unfrozen, ensure all changes delayed during freeze are now applied + for (DelayedPropChange change : delayedPropChanges) { + change.object.set(change.prop, change.value); + } + delayedPropChanges.clear(); + } + private static class DelayedPropChange { + private final TrackableObject object; + private final TrackableProperty prop; + private final Object value; + private DelayedPropChange(TrackableObject object0, TrackableProperty prop0, Object value0) { + object = object0; + prop = prop0; + value = value0; + } + } + private static final ArrayList delayedPropChanges = new ArrayList(); + private final int id; private final EnumMap props; private final EnumSet changedProps; @@ -36,6 +63,10 @@ public abstract class TrackableObject implements IIdentifiable { } protected void set(TrackableProperty key, T value) { + if (freezeCounter > 0 && key.respectFreeze()) { //if trackable objects currently frozen, queue up delayed prop change + delayedPropChanges.add(new DelayedPropChange(this, key, value)); + return; + } if (value == null || value.equals(key.getDefaultValue())) { if (props.remove(key) != null) { changedProps.add(key); diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index 65419b4f151..080fa4a488c 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -52,7 +52,7 @@ public enum TrackableProperty { Haunting(TrackableTypes.CardViewType), MustBlockCards(TrackableTypes.CardViewCollectionType), PairedWith(TrackableTypes.CardViewType), - CurrentState(TrackableTypes.CardStateViewType), + CurrentState(TrackableTypes.CardStateViewType, false), //can't respect freeze, otherwise card constructor can crash AlternateState(TrackableTypes.CardStateViewType), //Card State @@ -140,9 +140,18 @@ public enum TrackableProperty { Phase(TrackableTypes.EnumType(PhaseType.class)); private final TrackableType type; + private final boolean respectFreeze; private TrackableProperty(TrackableType type0) { + this(type0, true); + } + private TrackableProperty(TrackableType type0, boolean respectFreeze0) { type = type0; + respectFreeze = respectFreeze0; + } + + public boolean respectFreeze() { + return respectFreeze; } @SuppressWarnings("unchecked")