* Performance: memory usage optimization for deck editor (part 2 of removed bloated usage of ManaCosts -> ManaColor objects, see #7515);

This commit is contained in:
Oleg Agafonov 2021-02-12 22:12:18 +04:00
parent c1dea5b21e
commit 10e557b873
25 changed files with 164 additions and 113 deletions

View file

@ -88,6 +88,14 @@ public interface MageObject extends MageItem, Serializable {
ManaCosts<ManaCost> getManaCost();
default List<String> getManaCostSymbols() {
List<String> symbols = new ArrayList<>();
for (ManaCost cost : getManaCost()) {
symbols.add(cost.getText());
}
return symbols;
}
int getConvertedManaCost();
MageInt getPower();

View file

@ -22,6 +22,7 @@ import mage.target.targetadjustment.TargetAdjuster;
import mage.watchers.Watcher;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageIdentifier;
@ -123,6 +124,14 @@ public interface Ability extends Controllable, Serializable {
*/
ManaCosts<ManaCost> getManaCosts();
default List<String> getManaCostSymbols() {
List<String> symbols = new ArrayList<>();
for (ManaCost cost : getManaCosts()) {
symbols.add(cost.getText());
}
return symbols;
}
/**
* Gets all the {@link ManaCosts} that must be paid before activating this
* ability. These costs should be modified by any modification effects

View file

@ -39,8 +39,6 @@ public interface ManaCosts<T extends ManaCost> extends List<T>, ManaCost {
*/
void load(String mana, boolean extractMonoHybridGenericValue);
List<String> getSymbols();
boolean payOrRollback(Ability ability, Game game, Ability source, UUID payingPlayerId);
@Override

View file

@ -505,15 +505,6 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
}
}
@Override
public List<String> getSymbols() {
List<String> symbols = new ArrayList<>();
for (ManaCost cost : this) {
symbols.add(cost.getText());
}
return symbols;
}
@Override
public UUID getId() {
return this.id;

View file

@ -43,9 +43,7 @@ public class SpellCostReductionForEachSourceEffect extends CostModificationEffec
StringBuilder sb = new StringBuilder();
sb.append("this spell costs ");
for (String manaSymbol : reduceManaCosts.getSymbols()) {
sb.append(manaSymbol);
}
sb.append(reduceManaCosts.getText());
sb.append(" less to cast for each ").append(this.eachAmount.getMessage());
this.staticText = sb.toString();
}

View file

@ -34,9 +34,7 @@ public class SpellCostReductionSourceEffect extends CostModificationEffectImpl {
StringBuilder sb = new StringBuilder();
sb.append("this spell costs ");
for (String manaSymbol : manaCostsToReduce.getSymbols()) {
sb.append(manaSymbol);
}
sb.append(manaCostsToReduce.getText());
sb.append(" less to cast");
if (this.condition != null) {
sb.append(" if ").append(this.condition.toString());

View file

@ -63,9 +63,7 @@ public class SpellsCostIncreasingAllEffect extends CostModificationEffectImpl {
sb.append(" cost ");
if (this.increaseManaCosts != null) {
for (String manaSymbol : this.increaseManaCosts.getSymbols()) {
sb.append(manaSymbol);
}
sb.append(this.increaseManaCosts.getText());
} else {
sb.append("{").append(increaseGenericCost).append("}");
}

View file

@ -37,9 +37,7 @@ public class SpellsCostReductionControllerEffect extends CostModificationEffectI
StringBuilder sb = new StringBuilder();
sb.append(filter.getMessage()).append(" you cast cost ");
for (String manaSymbol : manaCostsToReduce.getSymbols()) {
sb.append(manaSymbol);
}
sb.append(manaCostsToReduce.getText());
sb.append(" less to cast. This effect reduces only the amount of colored mana you pay.");
this.staticText = sb.toString();
}

View file

@ -4,7 +4,6 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.cards.CardImpl;
import mage.cards.ModalDoubleFacesCard;
import mage.cards.repository.CardInfo;
@ -35,6 +34,7 @@ public class MockCard extends CardImpl {
protected List<String> manaCostStr;
protected String adventureSpellName;
protected boolean isModalDoubleFacesCard;
protected int convertedManaCost;
public MockCard(CardInfo card) {
super(null, card.getName());
@ -49,10 +49,11 @@ public class MockCard extends CardImpl {
this.usesVariousArt = card.usesVariousArt();
this.manaCost = new ManaCostsImpl(join(card.getManaCosts(CardInfo.ManaCostSide.ALL)));
//this.manaCost = new ManaCostsImpl(join(card.getManaCosts(CardInfo.ManaCostSide.ALL)));
this.manaCostLeftStr = card.getManaCosts(CardInfo.ManaCostSide.LEFT);
this.manaCostRightStr = card.getManaCosts(CardInfo.ManaCostSide.RIGHT);
this.manaCostStr = card.getManaCosts(CardInfo.ManaCostSide.ALL);
this.convertedManaCost = card.getConvertedManaCost();
this.color = card.getColor();
@ -112,21 +113,20 @@ public class MockCard extends CardImpl {
@Override
public ManaCosts<ManaCost> getManaCost() {
return manaCost;
// only split half cards can store mana cost in objects list instead strings (memory optimization)
// see https://github.com/magefree/mage/issues/7515
throw new IllegalArgumentException("Unsupport method call: getManaCost in " + this.getClass().getCanonicalName());
}
/*
private ManaCosts<ManaCost> getManaCost(CardInfo.ManaCostSide manaCostSide) {
switch (manaCostSide) {
case LEFT:
return manaCostLeft;
case RIGHT:
return manaCostRight;
default:
case ALL:
return manaCost;
}
}*/
@Override
public List<String> getManaCostSymbols() {
return getManaCostStr(CardInfo.ManaCostSide.ALL);
}
@Override
public int getConvertedManaCost() {
return this.convertedManaCost;
}
public List<String> getManaCostStr(CardInfo.ManaCostSide manaCostSide) {
switch (manaCostSide) {
@ -164,14 +164,6 @@ public class MockCard extends CardImpl {
}
}
private String join(List<String> strings) {
StringBuilder sb = new StringBuilder();
for (String string : strings) {
sb.append(string);
}
return sb.toString();
}
private Ability textAbilityFromString(final String text) {
return new MockAbility(text);
}

View file

@ -1,10 +1,16 @@
package mage.cards.mock;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.cards.Card;
import mage.cards.SplitCard;
import mage.cards.SplitCardHalf;
import mage.cards.repository.CardInfo;
import java.util.List;
/**
*
* @author LevelX2
@ -12,9 +18,13 @@ import mage.cards.repository.CardInfo;
public class MockSplitCardHalf extends MockCard implements SplitCardHalf {
private SplitCard splitCardParent;
private ManaCosts<ManaCost> manaCosts;
private List<String> manaCostsSymbols;
public MockSplitCardHalf(CardInfo card) {
super(card);
this.manaCostsSymbols = card.getManaCosts(CardInfo.ManaCostSide.ALL);
this.manaCosts = new ManaCostsImpl<>(String.join("", this.manaCostsSymbols));
}
public MockSplitCardHalf(final MockSplitCardHalf card) {
@ -36,4 +46,15 @@ public class MockSplitCardHalf extends MockCard implements SplitCardHalf {
return splitCardParent;
}
@Override
public ManaCosts<ManaCost> getManaCost() {
// only split half cards can store mana cost in objects list instead strings (memory optimization)
return manaCosts;
}
@Override
public List<String> getManaCostSymbols() {
// only split half cards can store mana cost in objects list instead strings (memory optimization)
return manaCostsSymbols;
}
}

View file

@ -167,19 +167,19 @@ public class CardInfo {
// mana cost can contains multiple cards (split left/right, modal double faces, card/adventure)
if (card instanceof SplitCard) {
List<String> manaCostLeft = ((SplitCard) card).getLeftHalfCard().getManaCost().getSymbols();
List<String> manaCostRight = ((SplitCard) card).getRightHalfCard().getManaCost().getSymbols();
List<String> manaCostLeft = ((SplitCard) card).getLeftHalfCard().getManaCostSymbols();
List<String> manaCostRight = ((SplitCard) card).getRightHalfCard().getManaCostSymbols();
this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight));
} else if (card instanceof ModalDoubleFacesCard) {
List<String> manaCostLeft = ((ModalDoubleFacesCard) card).getLeftHalfCard().getManaCost().getSymbols();
List<String> manaCostRight = ((ModalDoubleFacesCard) card).getRightHalfCard().getManaCost().getSymbols();
List<String> manaCostLeft = ((ModalDoubleFacesCard) card).getLeftHalfCard().getManaCostSymbols();
List<String> manaCostRight = ((ModalDoubleFacesCard) card).getRightHalfCard().getManaCostSymbols();
this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight));
} else if (card instanceof AdventureCard) {
List<String> manaCostLeft = ((AdventureCard) card).getSpellCard().getManaCost().getSymbols();
List<String> manaCostRight = card.getManaCost().getSymbols();
List<String> manaCostLeft = ((AdventureCard) card).getSpellCard().getManaCostSymbols();
List<String> manaCostRight = card.getManaCostSymbols();
this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight));
} else {
this.setManaCosts(card.getManaCost().getSymbols());
this.setManaCosts(card.getManaCostSymbols());
}
int length = 0;

View file

@ -317,10 +317,10 @@ public final class RateCard {
* @return
*/
private static int getManaCostScore(Card card, List<ColoredManaSymbol> allowedColors) {
int converted = card.getManaCost().convertedManaCost();
int converted = card.getConvertedManaCost();
if (allowedColors == null) {
int colorPenalty = 0;
for (String symbol : card.getManaCost().getSymbols()) {
for (String symbol : card.getManaCostSymbols()) {
if (isColoredMana(symbol)) {
colorPenalty++;
}
@ -329,7 +329,7 @@ public final class RateCard {
}
final Map<String, Integer> singleCount = new HashMap<>();
int maxSingleCount = 0;
for (String symbol : card.getManaCost().getSymbols()) {
for (String symbol : card.getManaCostSymbols()) {
int count = 0;
symbol = symbol.replace("{", "").replace("}", "");
if (isColoredMana(symbol)) {
@ -385,7 +385,7 @@ public final class RateCard {
*/
public static int getColorManaCount(Card card) {
int count = 0;
for (String symbol : card.getManaCost().getSymbols()) {
for (String symbol : card.getManaCostSymbols()) {
if (isColoredMana(symbol)) {
count++;
}
@ -401,7 +401,7 @@ public final class RateCard {
*/
public static int getDifferentColorManaCount(Card card) {
Set<String> symbols = new HashSet<>();
for (String symbol : card.getManaCost().getSymbols()) {
for (String symbol : card.getManaCostSymbols()) {
if (isColoredMana(symbol)) {
symbols.add(symbol);
}

View file

@ -1,9 +1,6 @@
package mage.game.stack;
import mage.MageIdentifier;
import mage.MageInt;
import mage.MageObject;
import mage.ObjectColor;
import mage.*;
import mage.abilities.*;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostAdjuster;
@ -222,6 +219,11 @@ public class StackAbility extends StackObjImpl implements Ability {
return emptyCost;
}
@Override
public List<String> getManaCostSymbols() {
return super.getManaCostSymbols();
}
@Override
public MageInt getPower() {
return MageInt.EmptyMageInt;

View file

@ -133,29 +133,37 @@ public final class CardUtil {
}
private static ManaCosts<ManaCost> adjustCost(ManaCosts<ManaCost> manaCosts, int reduceCount) {
ManaCosts<ManaCost> adjustedCost = new ManaCostsImpl<>();
ManaCosts<ManaCost> newCost = new ManaCostsImpl<>();
// nothing to change
if (reduceCount == 0) {
for (ManaCost manaCost : manaCosts) {
adjustedCost.add(manaCost.copy());
newCost.add(manaCost.copy());
}
return adjustedCost;
return newCost;
}
// keep same order for costs
Map<ManaCost, ManaCost> changedCost = new LinkedHashMap<>(); // must be ordered
List<ManaCost> addedCost = new ArrayList<>();
manaCosts.forEach(manaCost -> {
changedCost.put(manaCost, manaCost);
});
// remove or save cost
if (reduceCount > 0) {
int restToReduce = reduceCount;
// first run - priority for single option costs (generic)
for (ManaCost manaCost : manaCosts) {
// ignore snow mana
if (manaCost instanceof SnowManaCost) {
adjustedCost.add(manaCost);
continue;
}
// ignore unknown mana
if (manaCost.getOptions().size() == 0) {
adjustedCost.add(manaCost);
continue;
}
@ -171,15 +179,15 @@ public final class CardUtil {
if ((colorless - restToReduce) > 0) {
// partly reduce
int newColorless = colorless - restToReduce;
adjustedCost.add(new GenericManaCost(newColorless));
changedCost.put(manaCost, new GenericManaCost(newColorless));
restToReduce = 0;
} else {
// full reduce - ignore cost
changedCost.put(manaCost, null);
restToReduce -= colorless;
}
} else {
// nothing to reduce
adjustedCost.add(manaCost.copy());
}
}
@ -203,22 +211,21 @@ public final class CardUtil {
if ((colorless - restToReduce) > 0) {
// partly reduce
int newColorless = colorless - restToReduce;
adjustedCost.add(new MonoHybridManaCost(mono.getManaColor(), newColorless));
changedCost.put(manaCost, new MonoHybridManaCost(mono.getManaColor(), newColorless));
restToReduce = 0;
} else {
// full reduce
adjustedCost.add(new MonoHybridManaCost(mono.getManaColor(), 0));
changedCost.put(manaCost, new MonoHybridManaCost(mono.getManaColor(), 0));
restToReduce -= colorless;
}
} else {
// nothing to reduce
adjustedCost.add(mono.copy());
}
continue;
}
// unsupported multi-option mana types for reduce (like HybridManaCost)
adjustedCost.add(manaCost.copy());
// nothing to do
}
}
@ -226,23 +233,39 @@ public final class CardUtil {
if (reduceCount < 0) {
boolean added = false;
for (ManaCost manaCost : manaCosts) {
// ignore already reduced cost (add new cost to the start)
if (changedCost.get(manaCost) == null) {
continue;
}
// add to existing cost
if (reduceCount != 0 && manaCost instanceof GenericManaCost) {
// add increase cost to existing generic
GenericManaCost gen = (GenericManaCost) manaCost;
adjustedCost.add(new GenericManaCost(gen.getOptions().get(0).getGeneric() + -reduceCount));
changedCost.put(manaCost, new GenericManaCost(gen.getOptions().get(0).getGeneric() + -reduceCount));
reduceCount = 0;
added = true;
} else {
// non-generic mana
adjustedCost.add(manaCost.copy());
}
}
// add as new cost
if (!added) {
// add increase cost as new
adjustedCost.add(new GenericManaCost(-reduceCount));
addedCost.add(new GenericManaCost(-reduceCount));
}
}
// collect final result
addedCost.forEach(cost -> {
newCost.add(cost.copy());
});
changedCost.forEach((key, value) -> {
// ignore fully reduced and add changed
if (value != null) {
newCost.add(value.copy());
}
});
// cost modifying effects requiring snow mana unnecessarily (fixes #6000)
Filter filter = manaCosts.stream()
.filter(manaCost -> !(manaCost instanceof SnowManaCost))
@ -251,9 +274,10 @@ public final class CardUtil {
.findFirst()
.orElse(null);
if (filter != null) {
adjustedCost.setSourceFilter(filter);
newCost.setSourceFilter(filter);
}
return adjustedCost;
return newCost;
}
public static void reduceCost(SpellAbility spellAbility, ManaCosts<ManaCost> manaCostsToReduce) {

View file

@ -576,7 +576,7 @@ public final class ManaUtil {
res.setWhite(res.isWhite() || secondColor.isWhite());
// from mana
List<String> secondManaSymbols = secondSideCard.getManaCost().getSymbols();
List<String> secondManaSymbols = secondSideCard.getManaCostSymbols();
res.setWhite(res.isWhite() || containsManaSymbol(secondManaSymbols, "W"));
res.setBlue(res.isBlue() || containsManaSymbol(secondManaSymbols, "U"));
res.setBlack(res.isBlack() || containsManaSymbol(secondManaSymbols, "B"));
@ -628,7 +628,7 @@ public final class ManaUtil {
} else {
secondSide = card.getSecondCardFace();
}
return getColorIdentity(card.getColor(), String.join("", card.getManaCost().getSymbols()), card.getRules(), secondSide);
return getColorIdentity(card.getColor(), String.join("", card.getManaCostSymbols()), card.getRules(), secondSide);
}
public static int getColorIdentityHash(FilterMana colorIdentity) {