Skip to content

Commit e305e3d

Browse files
committed
GameAction: reduce View Updates per Layer
1 parent a0c6663 commit e305e3d

File tree

6 files changed

+115
-44
lines changed

6 files changed

+115
-44
lines changed

forge-core/src/main/java/forge/util/collect/FCollectionView.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
/**
1010
* Read-only interface to an {@link FCollection}.
1111
*/
12-
public interface FCollectionView<T> extends Iterable<T> {
12+
public interface FCollectionView<T> extends Collection<T> {
1313
/**
1414
* @see Collection#isEmpty()
1515
*/

forge-game/src/main/java/forge/game/GameAction.java

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,8 +1083,10 @@ public final void checkStaticAbilities(final boolean runEvents, final Set<Card>
10831083
}
10841084
game.getTracker().freeze(); //prevent views flickering during while updating for state-based effects
10851085

1086+
final Map<StaticAbilityLayer, Set<Card>> affectedPerLayer = Maps.newHashMap();
1087+
10861088
// remove old effects
1087-
game.getStaticEffects().clearStaticEffects(affectedCards);
1089+
game.getStaticEffects().clearStaticEffects(affectedCards, affectedPerLayer);
10881090

10891091
// search for cards with static abilities
10901092
final FCollection<StaticAbility> staticAbilities = new FCollection<>();
@@ -1150,11 +1152,15 @@ public boolean visit(final Card c) {
11501152
stAb.applyContinuousAbility(layer, previouslyAffected);
11511153
}
11521154
if (affectedHere != null) {
1155+
affectedPerLayer.computeIfAbsent(layer, l -> Sets.newHashSet()).addAll(affectedHere);
11531156
for (final Card c : affectedHere) {
11541157
for (final StaticAbility st2 : c.getStaticAbilities()) {
11551158
if (!staticAbilities.contains(st2) && st2.checkMode(StaticAbilityMode.Continuous) && st2.zonesCheck()) {
11561159
toAdd.add(st2);
1157-
st2.applyContinuousAbilityBefore(layer, preList);
1160+
CardCollectionView newAffected = st2.applyContinuousAbilityBefore(layer, preList);
1161+
if (newAffected != null) {
1162+
affectedPerLayer.computeIfAbsent(layer, l -> Sets.newHashSet()).addAll(newAffected);
1163+
}
11581164
}
11591165
}
11601166
}
@@ -1223,13 +1229,37 @@ public boolean visit(final Card c) {
12231229
game.getView().setDependencies(dependencies);
12241230
}
12251231

1232+
CardCollection affectedKeywords = new CardCollection();
1233+
CardCollection affectedPT = new CardCollection();
1234+
if (affectedPerLayer.containsKey(StaticAbilityLayer.TEXT)) {
1235+
affectedPerLayer.get(StaticAbilityLayer.TEXT).forEach(Card::updateNameforView);
1236+
affectedKeywords.addAll(affectedPerLayer.get(StaticAbilityLayer.TEXT));
1237+
}
1238+
if (affectedPerLayer.containsKey(StaticAbilityLayer.TYPE)) {
1239+
affectedPerLayer.get(StaticAbilityLayer.TYPE).forEach(Card::updateTypesForView);
1240+
// setting Basic Land Type case
1241+
affectedKeywords.addAll(affectedPerLayer.get(StaticAbilityLayer.TYPE));
1242+
}
1243+
if (affectedPerLayer.containsKey(StaticAbilityLayer.ABILITIES)) {
1244+
affectedKeywords.addAll(affectedPerLayer.get(StaticAbilityLayer.ABILITIES));
1245+
}
12261246
// Update P/T and type in the view only once after all the cards have been processed, to avoid flickering
1227-
for (Card c : affectedCards) {
1228-
c.updateNameforView();
1229-
c.updatePTforView();
1230-
c.updateTypesForView();
1231-
c.updateKeywords();
1247+
if (affectedPerLayer.containsKey(StaticAbilityLayer.CHARACTERISTIC)) {
1248+
affectedPT.addAll(affectedPerLayer.get(StaticAbilityLayer.CHARACTERISTIC));
1249+
}
1250+
if (affectedPerLayer.containsKey(StaticAbilityLayer.SETPT)) {
1251+
affectedPT.addAll(affectedPerLayer.get(StaticAbilityLayer.SETPT));
1252+
}
1253+
if (affectedPerLayer.containsKey(StaticAbilityLayer.MODIFYPT)) {
1254+
affectedPT.addAll(affectedPerLayer.get(StaticAbilityLayer.MODIFYPT));
1255+
}
1256+
/*
1257+
if (affectedPerLayer.containsKey(StaticAbilityLayer.SWITCHPT)) {
1258+
affectedPT.addAll(affectedPerLayer.get(StaticAbilityLayer.SWITCHPT));
12321259
}
1260+
//*/
1261+
affectedPT.forEach(Card::updatePTforView);
1262+
affectedKeywords.forEach(Card::updateKeywords);
12331263

12341264
// TODO filter out old copies from zone change
12351265

@@ -1355,7 +1385,7 @@ private StaticAbility findStaticAbilityToApply(StaticAbilityLayer layer, List<St
13551385
}
13561386

13571387
private Iterable<Object> generateContinuousEffectChanges(StaticAbilityLayer layer, StaticAbility stAb) {
1358-
List<Object> result = Collections.EMPTY_LIST;
1388+
List<Object> result = Collections.emptyList();
13591389
if (layer == StaticAbilityLayer.CONTROL) {
13601390
result = Lists.newArrayList();
13611391
result.addAll(AbilityUtils.getDefinedPlayers(stAb.getHostCard(), stAb.getParam("GainControl"), stAb));

forge-game/src/main/java/forge/game/StaticEffect.java

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919

2020
import java.util.List;
2121
import java.util.Map;
22+
import java.util.Set;
2223

2324
import com.google.common.collect.Lists;
2425
import com.google.common.collect.Maps;
26+
import com.google.common.collect.Sets;
2527

2628
import forge.game.card.Card;
2729
import forge.game.card.CardCollection;
@@ -171,10 +173,13 @@ public String getParam(final String key) {
171173
*
172174
* @return a {@link CardCollectionView} of all affected cards.
173175
*/
174-
final CardCollectionView remove() {
175-
return remove(StaticAbilityLayer.CONTINUOUS_LAYERS);
176+
final CardCollectionView remove(Map<StaticAbilityLayer, Set<Card>> affectedByLayer) {
177+
return remove(affectedByLayer, StaticAbilityLayer.CONTINUOUS_LAYERS);
176178
}
177179
final CardCollectionView remove(List<StaticAbilityLayer> layers) {
180+
return remove(Maps.newHashMap(), layers);
181+
}
182+
final CardCollectionView remove(Map<StaticAbilityLayer, Set<Card>> affectedByLayer, List<StaticAbilityLayer> layers) {
178183
final CardCollectionView affectedCards = getAffectedCards();
179184
final List<Player> affectedPlayers = getAffectedPlayers();
180185

@@ -224,27 +229,32 @@ final CardCollectionView remove(List<StaticAbilityLayer> layers) {
224229

225230
// remove changed name
226231
if (hasParam("SetName") || hasParam("AddNames")) {
227-
affectedCard.removeChangedName(timestamp, ability.getId());
232+
if (affectedCard.removeChangedName(timestamp, ability.getId(), false)) {
233+
addCard(affectedByLayer, StaticAbilityLayer.TEXT, affectedCard);
234+
}
228235
}
229236

230237
if (hasParam("GainTextOf")) {
231-
affectedCard.removeChangedName(getTimestamp(), ability.getId());
238+
affectedCard.removeChangedName(getTimestamp(), ability.getId(), false);
232239
affectedCard.removeChangedManaCost(getTimestamp(), ability.getId());
233-
affectedCard.removeColor(getTimestamp(), ability.getId());
234-
affectedCard.removeChangedCardTypes(getTimestamp(), ability.getId());
235-
affectedCard.removeChangedCardTraits(getTimestamp(), ability.getId());
236-
affectedCard.removeChangedCardKeywords(getTimestamp(), ability.getId());
237-
affectedCard.removeNewPT(getTimestamp(), ability.getId());
240+
affectedCard.removeColorByText(getTimestamp(), ability.getId());
241+
affectedCard.removeChangedCardTypesByText(getTimestamp(), ability.getId());
242+
affectedCard.removeChangedCardTraitsByText(getTimestamp(), ability.getId());
243+
affectedCard.removeChangedCardKeywordsByText(getTimestamp(), ability.getId());
244+
affectedCard.removeNewPTbyText(getTimestamp(), ability.getId());
238245

239246
affectedCard.updateChangedText();
247+
addCard(affectedByLayer, StaticAbilityLayer.TEXT, affectedCard);
240248
}
241249
}
242250

243251
if (layers.contains(StaticAbilityLayer.TYPE)) {
244252
// remove Types
245253
if (hasParam("AddType") || hasParam("AddAllCreatureTypes") || hasParam("RemoveType") || hasParam("RemoveLandTypes")) {
246254
// the view is updated in GameAction#checkStaticAbilities to avoid flickering
247-
affectedCard.removeChangedCardTypes(getTimestamp(), ability.getId(), false);
255+
if (affectedCard.removeChangedCardTypes(getTimestamp(), ability.getId(), false)) {
256+
addCard(affectedByLayer, StaticAbilityLayer.TYPE, affectedCard);
257+
}
248258
}
249259
}
250260

@@ -257,9 +267,10 @@ final CardCollectionView remove(List<StaticAbilityLayer> layers) {
257267

258268
if (layers.contains(StaticAbilityLayer.ABILITIES)) {
259269
// remove keywords
270+
boolean abilitiesChanged = false;
260271
if (hasParam("AddKeyword") || hasParam("RemoveKeyword") || hasParam("RemoveLandTypes")
261272
|| hasParam("ShareRememberedKeywords") || hasParam("RemoveAllAbilities")) {
262-
affectedCard.removeChangedCardKeywords(getTimestamp(), ability.getId(), false);
273+
abilitiesChanged |= affectedCard.removeChangedCardKeywords(getTimestamp(), ability.getId(), false);
263274
}
264275

265276
// remove abilities
@@ -268,27 +279,34 @@ final CardCollectionView remove(List<StaticAbilityLayer> layers) {
268279
|| hasParam("AddTrigger") || hasParam("AddStaticAbility")
269280
|| hasParam("AddReplacementEffect") || hasParam("RemoveAllAbilities")
270281
|| hasParam("RemoveLandTypes")) {
271-
affectedCard.removeChangedCardTraits(getTimestamp(), ability.getId());
282+
abilitiesChanged |= affectedCard.removeChangedCardTraits(getTimestamp(), ability.getId());
272283
}
273284

274285
if (hasParam("CantHaveKeyword")) {
275-
affectedCard.removeCantHaveKeyword(getTimestamp());
286+
abilitiesChanged |= affectedCard.removeCantHaveKeyword(getTimestamp());
276287
}
277288

278289
affectedCard.removeChangedSVars(getTimestamp(), ability.getId());
279290

280291
// need update for clean reapply
281-
affectedCard.updateKeywordsCache(affectedCard.getCurrentState());
292+
if (abilitiesChanged) {
293+
affectedCard.updateKeywordsCache(affectedCard.getCurrentState());
294+
addCard(affectedByLayer, StaticAbilityLayer.ABILITIES, affectedCard);
295+
}
282296
}
283297

284298
if (layers.contains(StaticAbilityLayer.CHARACTERISTIC) || layers.contains(StaticAbilityLayer.SETPT)) {
285299
if (hasParam("SetPower") || hasParam("SetToughness")) {
286-
affectedCard.removeNewPT(getTimestamp(), ability.getId(), false);
300+
if (affectedCard.removeNewPT(getTimestamp(), ability.getId(), false)) {
301+
addCard(affectedByLayer, ability.isCharacteristicDefining() ? StaticAbilityLayer.CHARACTERISTIC : StaticAbilityLayer.SETPT, affectedCard);
302+
}
287303
}
288304
}
289305

290306
if (layers.contains(StaticAbilityLayer.MODIFYPT)) {
291-
affectedCard.removePTBoost(getTimestamp(), ability.getId());
307+
if (affectedCard.removePTBoost(getTimestamp(), ability.getId())) {
308+
addCard(affectedByLayer, StaticAbilityLayer.MODIFYPT, affectedCard);
309+
}
292310
}
293311

294312
if (layers.contains(StaticAbilityLayer.RULES)) {
@@ -319,8 +337,12 @@ final CardCollectionView remove(List<StaticAbilityLayer> layers) {
319337
return affectedCards;
320338
}
321339

340+
protected static void addCard(Map<StaticAbilityLayer, Set<Card>> affectedByLayer, StaticAbilityLayer layer, Card affectedCard) {
341+
affectedByLayer.computeIfAbsent(layer, l -> Sets.newHashSet()).add(affectedCard);
342+
}
343+
322344
public void removeMapped(IEntityMap map) {
323-
makeMappedCopy(map).remove();
345+
makeMappedCopy(map).remove(Maps.newHashMap());
324346
}
325347

326348
}

forge-game/src/main/java/forge/game/StaticEffects.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ public class StaticEffects {
4040
// **************** StaticAbility system **************************
4141
private final Map<StaticAbility, StaticEffect> staticEffects = Maps.newHashMap();
4242

43-
public final void clearStaticEffects(final Set<Card> affectedCards) {
43+
public final void clearStaticEffects(final Set<Card> affectedCards, Map<StaticAbilityLayer, Set<Card>> affectedByLayer) {
4444
// remove all static effects
4545
for (final StaticEffect se : staticEffects.values()) {
46-
se.remove().forEach(affectedCards::add);
46+
se.remove(affectedByLayer).forEach(affectedCards::add);
4747
}
4848
this.staticEffects.clear();
4949
}

forge-game/src/main/java/forge/game/ability/effects/TextBoxExchangeEffect.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,15 @@ public void run() {
7171
Card card2 = game.getCardState(c2, null);
7272

7373
if (card1 != null && c1.equalsWithGameTimestamp(card1)) {
74-
card1.removeChangedCardTraits(ts, 0);
74+
card1.removeChangedCardTraitsByText(ts, 0);
7575
card1.removeChangedCardKeywords(ts, 0, false);
7676
card1.updateChangedText();
7777
card1.updateStateForView();
7878
game.fireEvent(new GameEventCardStatsChanged(card1));
7979
}
8080

8181
if (card2 != null && c2.equalsWithGameTimestamp(card2)) {
82-
card2.removeChangedCardTraits(ts, 0);
82+
card2.removeChangedCardTraitsByText(ts, 0);
8383
card2.removeChangedCardKeywords(ts, 0, false);
8484
card2.updateChangedText();
8585
card2.updateStateForView();

forge-game/src/main/java/forge/game/card/Card.java

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,10 +1005,15 @@ public void addChangedName(final String name0, boolean addNonLegendaryCreatureNa
10051005
updateNameforView();
10061006
}
10071007

1008-
public void removeChangedName(long timestamp, long staticId) {
1009-
if (changedCardNames.remove(timestamp, staticId) != null) {
1008+
public boolean removeChangedName(long timestamp, long staticId) {
1009+
return removeChangedName(timestamp, staticId, true);
1010+
}
1011+
public boolean removeChangedName(long timestamp, long staticId, boolean updateView) {
1012+
boolean changed = changedCardNames.remove(timestamp, staticId) != null;
1013+
if (changed && updateView) {
10101014
updateNameforView();
10111015
}
1016+
return changed;
10121017
}
10131018

10141019
public boolean clearChangedName() {
@@ -4304,6 +4309,9 @@ public final void addChangedCardTypesByText(final CardType addType, final long t
43044309

43054310
this.updateChangedText();
43064311
}
4312+
public final boolean removeChangedCardTypesByText(final long timestamp, final long staticId) {
4313+
return changedCardTypesByText.remove(timestamp, staticId) != null;
4314+
}
43074315

43084316
public final void addChangedCardTypes(final CardType addType, final CardType removeType, final boolean addAllCreatureTypes,
43094317
final Set<RemoveType> remove,
@@ -4316,10 +4324,10 @@ public final void addChangedCardTypes(final CardType addType, final CardType rem
43164324
}
43174325
}
43184326

4319-
public final void removeChangedCardTypes(final long timestamp, final long staticId) {
4320-
removeChangedCardTypes(timestamp, staticId, true);
4327+
public final boolean removeChangedCardTypes(final long timestamp, final long staticId) {
4328+
return removeChangedCardTypes(timestamp, staticId, true);
43214329
}
4322-
public final void removeChangedCardTypes(final long timestamp, final long staticId, final boolean updateView) {
4330+
public final boolean removeChangedCardTypes(final long timestamp, final long staticId, final boolean updateView) {
43234331
boolean removed = false;
43244332
removed |= changedCardTypes.remove(timestamp, staticId) != null;
43254333
removed |= changedCardTypesCharacterDefining.remove(timestamp, staticId) != null;
@@ -4328,6 +4336,7 @@ public final void removeChangedCardTypes(final long timestamp, final long static
43284336
if (updateView)
43294337
updateTypesForView();
43304338
}
4339+
return removed;
43314340
}
43324341

43334342
public final void updateTypeCache() {
@@ -4342,6 +4351,11 @@ public void addColorByText(final ColorSet color, final boolean addToColors, fina
43424351
changedCardColorsByText.put(timestamp, stAb != null ? stAb.getId() : (long)0, new CardColor(color, addToColors));
43434352
updateColorForView();
43444353
}
4354+
public final void removeColorByText(final long timestampIn, final long staticId) {
4355+
if (changedCardColorsByText.remove(timestampIn, staticId) != null) {
4356+
updateColorForView();
4357+
}
4358+
}
43454359

43464360
public final void addColor(final ColorSet color, final boolean addToColors, final long timestamp, final StaticAbility stAb) {
43474361
(stAb != null && stAb.isCharacteristicDefining() ? changedCardColorsCharacterDefining : changedCardColors).put(
@@ -4352,7 +4366,6 @@ public final void addColor(final ColorSet color, final boolean addToColors, fina
43524366

43534367
public final void removeColor(final long timestampIn, final long staticId) {
43544368
boolean removed = false;
4355-
removed |= changedCardColorsByText.remove(timestampIn, staticId) != null;
43564369
removed |= changedCardColors.remove(timestampIn, staticId) != null;
43574370
removed |= changedCardColorsCharacterDefining.remove(timestampIn, staticId) != null;
43584371

@@ -4550,6 +4563,9 @@ public final void addNewPTByText(final Integer power, final Integer toughness, f
45504563
newPTText.put(timestamp, staticId, Pair.of(power, toughness));
45514564
updatePTforView();
45524565
}
4566+
public final boolean removeNewPTbyText(final long timestamp, final long staticId) {
4567+
return newPTText.remove(timestamp, staticId) != null;
4568+
}
45534569

45544570
public final void addNewPT(final Integer power, final Integer toughness, final long timestamp, final long staticId) {
45554571
addNewPT(power, toughness, timestamp, staticId, false, true);
@@ -4564,16 +4580,16 @@ public final void addNewPT(final Integer power, final Integer toughness, final l
45644580
public final void removeNewPT(final long timestamp, final long staticId) {
45654581
removeNewPT(timestamp, staticId, true);
45664582
}
4567-
public final void removeNewPT(final long timestamp, final long staticId, final boolean updateView) {
4583+
public final boolean removeNewPT(final long timestamp, final long staticId, final boolean updateView) {
45684584
boolean removed = false;
45694585

4570-
removed |= newPTText.remove(timestamp, staticId) != null;
45714586
removed |= newPT.remove(timestamp, staticId) != null;
45724587
removed |= newPTCharacterDefining.remove(timestamp, staticId) != null;
45734588

45744589
if (removed && updateView) {
45754590
updatePTforView();
45764591
}
4592+
return removed;
45774593
}
45784594

45794595
public Iterable<Pair<Integer, Integer>> getPTIterable() {
@@ -4736,8 +4752,8 @@ public void addPTBoost(final Integer power, final Integer toughness, final long
47364752
boostPT.put(timestamp, staticId, Pair.of(power, toughness));
47374753
}
47384754

4739-
public void removePTBoost(final long timestamp, final long staticId) {
4740-
boostPT.remove(timestamp, staticId);
4755+
public boolean removePTBoost(final long timestamp, final long staticId) {
4756+
return boostPT.remove(timestamp, staticId) != null;
47414757
}
47424758

47434759
public Table<Long, Long, Pair<Integer, Integer>> getPTBoostTable() {
@@ -5087,10 +5103,10 @@ public final void addChangedCardTraits(CardTraitChanges ctc, long timestamp, lon
50875103
}
50885104

50895105
public final boolean removeChangedCardTraits(long timestamp, long staticId) {
5090-
boolean changed = false;
5091-
changed |= changedCardTraitsByText.remove(timestamp, staticId) != null;
5092-
changed |= changedCardTraits.remove(timestamp, staticId) != null;
5093-
return changed;
5106+
return changedCardTraits.remove(timestamp, staticId) != null;
5107+
}
5108+
public final boolean removeChangedCardTraitsByText(long timestamp, long staticId) {
5109+
return changedCardTraitsByText.remove(timestamp, staticId) != null;
50945110
}
50955111

50965112
public Iterable<CardTraitChanges> getChangedCardTraitsList(CardState state) {
@@ -5305,6 +5321,9 @@ public final boolean removeChangedCardKeywords(final long timestamp, final long
53055321
}
53065322
return changed;
53075323
}
5324+
public final boolean removeChangedCardKeywordsByText(final long timestamp, final long staticId) {
5325+
return changedCardKeywordsByText.remove(timestamp, staticId) != null;
5326+
}
53085327

53095328
public boolean clearChangedCardKeywords() {
53105329
return clearChangedCardKeywords(false);

0 commit comments

Comments
 (0)