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

This commit is contained in:
Oleg Agafonov 2021-02-12 14:08:17 +04:00
parent c3d55ea12a
commit 275e996c08
23 changed files with 170 additions and 143 deletions

View file

@ -1398,11 +1398,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
}
// Casting cost
if (!s) {
String mc = "";
for (String m : card.getManaCost()) {
mc += m;
}
s |= mc.toLowerCase(Locale.ENGLISH).contains(searchStr);
s |= card.getManaCostStr().toLowerCase(Locale.ENGLISH).contains(searchStr);
}
// Rules
if (!s) {
@ -1473,10 +1469,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
}
// Mana Cost
String mc = "";
for (String m : card.getManaCost()) {
mc += m;
}
String mc = card.getManaCostStr();
mc = mc.replaceAll("\\{([WUBRG]).([WUBRG])\\}", "{$1}{$2}");
mc = mc.replaceAll("\\{", "#");
mc = mc.replaceAll("#2\\/", "#");

View file

@ -215,7 +215,7 @@ public class TableModel extends AbstractTableModel implements ICardGrid {
return c.getDisplayFullName(); // show full name in deck editor table, e.g. adventure with spell name
case 2:
// new svg images version
return ManaSymbols.getStringManaCost(c.getManaCost());
return ManaSymbols.getClearManaCost(c.getManaCostStr());
/*
// old html images version
String manaCost = "";

View file

@ -24,7 +24,7 @@ public class CardViewColorIdentityComparator implements CardViewComparator {
}
public static FilterMana calcIdentity(CardView cardView) {
return ManaUtil.getColorIdentity(cardView.getColor(), cardView.getManaCost(), cardView.getRules(), null);
return ManaUtil.getColorIdentity(cardView.getColor(), cardView.getManaCostStr(), cardView.getRules(), null);
}
public static int calcHash(CardView cardView) {

View file

@ -97,7 +97,7 @@ public final class GuiDisplayUtil {
j.add(cardText);
TextLines textLines = GuiDisplayUtil.getTextLinesfromCardView(card);
cardText.setText(getRulefromCardView(card, textLines).toString());
cardText.setText(getRulesFromCardView(card, textLines).toString());
descriptionPanel.add(j);
@ -227,11 +227,8 @@ public final class GuiDisplayUtil {
return "<img src='" + getResourcePath("hint/" + iconName + ".png") + "' alt='" + iconName + "' width=" + symbolSize + " height=" + symbolSize + ">";
}
public static StringBuilder getRulefromCardView(CardView card, TextLines textLines) {
String manaCost = "";
for (String m : card.getManaCost()) {
manaCost += m;
}
public static StringBuilder getRulesFromCardView(CardView card, TextLines textLines) {
String manaCost = card.getManaCostStr();
String castingCost = UI.getDisplayManaCost(manaCost);
castingCost = ManaSymbols.replaceSymbolsWithHTML(castingCost, ManaSymbols.Type.TOOLTIP);
@ -347,9 +344,9 @@ public final class GuiDisplayUtil {
rule.append("<tr><td valign='top'><b>");
rule.append(card.getLeftSplitName());
rule.append("</b></td><td align='right' valign='top' style='width:");
rule.append(card.getLeftSplitCosts().getSymbols().size() * GUISizeHelper.symbolTooltipSize + 1);
rule.append(ManaSymbols.getClearManaSymbolsCount(card.getLeftSplitCostsStr()) * GUISizeHelper.symbolTooltipSize + 1);
rule.append("px'>");
rule.append(card.getLeftSplitCosts().getText());
rule.append(card.getLeftSplitCostsStr());
rule.append("</td></tr></table>");
for (String ruling : card.getLeftSplitRules()) {
if (ruling != null && !ruling.replace(".", "").trim().isEmpty()) {
@ -362,9 +359,9 @@ public final class GuiDisplayUtil {
rule.append("<tr><td valign='top'><b>");
rule.append(card.getRightSplitName());
rule.append("</b></td><td align='right' valign='top' style='width:");
rule.append(card.getRightSplitCosts().getSymbols().size() * GUISizeHelper.symbolTooltipSize + 1);
rule.append(ManaSymbols.getClearManaSymbolsCount(card.getRightSplitCostsStr()) * GUISizeHelper.symbolTooltipSize + 1);
rule.append("px'>");
rule.append(card.getRightSplitCosts().getText());
rule.append(card.getRightSplitCostsStr());
rule.append("</td></tr></table>");
for (String ruling : card.getRightSplitRules()) {
if (ruling != null && !ruling.replace(".", "").trim().isEmpty()) {

View file

@ -789,8 +789,8 @@ public abstract class CardPanel extends MagePermanent implements ComponentListen
}
} else {
sb.append(card.getName());
if (!card.getManaCost().isEmpty()) {
sb.append('\n').append(card.getManaCost());
if (!card.getManaCostStr().isEmpty()) {
sb.append('\n').append(card.getManaCostStr());
}
sb.append('\n').append(cardType);
if (card.getColor().hasColor()) {

View file

@ -529,7 +529,7 @@ public class CardPanelRenderModeImage extends CardPanel {
int symbolMarginX = 2; // 2 px between icons
String manaCost = ManaSymbols.getStringManaCost(getGameCard().getManaCost());
String manaCost = ManaSymbols.getClearManaCost(getGameCard().getManaCostStr());
int manaWidth = getManaWidth(manaCost, symbolMarginX);
// right top corner with margin (sizes from any sample card, length from black border to mana icon)

View file

@ -56,7 +56,7 @@ public class CardPanelRenderModeMTGO extends CardPanel {
if (!a.getSuperTypes().equals(b.getSuperTypes())) {
return false;
}
if (!a.getManaCost().equals(b.getManaCost())) {
if (!a.getManaCostStr().equals(b.getManaCostStr())) {
return false;
}
if (!a.getRules().equals(b.getRules())) {
@ -166,9 +166,7 @@ public class CardPanelRenderModeMTGO extends CardPanel {
for (SubType s : this.view.getSubTypes()) {
sb.append(s);
}
for (String s : this.view.getManaCost()) {
sb.append(s);
}
sb.append(this.view.getManaCostStr());
for (String s : this.view.getRules()) {
sb.append(s);
}

View file

@ -550,18 +550,35 @@ public final class ManaSymbols {
}
public static String getStringManaCost(java.util.List<String> manaCost) {
public static String getClearManaCost(java.util.List<String> manaCost) {
StringBuilder sb = new StringBuilder();
for (String s : manaCost) {
sb.append(s);
}
return sb.toString()
return getClearManaCost(sb.toString());
}
public static String getClearManaCost(String manaCost) {
return manaCost
.replace("/", "")
.replace("{", "")
.replace("}", " ")
.replace("}", " ") // each mana symbol splits by space
.trim();
}
public static int getClearManaSymbolsCount(String manaCost) {
// find mana symbols amount in the cost
if (manaCost.isEmpty()) {
return 0;
} else {
String clearManaCost = getClearManaCost(manaCost);
String checkManaCost = clearManaCost.replace(" ", "");
return clearManaCost.length() - checkManaCost.length() + 1;
}
}
public enum Type {
TABLE,
CHAT,

View file

@ -221,7 +221,7 @@ public class ModernCardRenderer extends CardRenderer {
super(card);
// Mana cost string
manaCostString = ManaSymbols.getStringManaCost(cardView.getManaCost());
manaCostString = ManaSymbols.getClearManaCost(cardView.getManaCostStr());
}
@Override

View file

@ -1,7 +1,6 @@
package org.mage.card.arcane;
import mage.ObjectColor;
import mage.abilities.costs.mana.ManaCosts;
import mage.cards.ArtRect;
import mage.constants.CardType;
import mage.view.CardView;
@ -50,11 +49,11 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
public ModernSplitCardRenderer(CardView view) {
super(view);
rightHalf.manaCostString = ManaSymbols.getStringManaCost(cardView.getRightSplitCosts().getSymbols());
leftHalf.manaCostString = ManaSymbols.getStringManaCost(cardView.getLeftSplitCosts().getSymbols());
rightHalf.manaCostString = ManaSymbols.getClearManaCost(cardView.getRightSplitCostsStr());
leftHalf.manaCostString = ManaSymbols.getClearManaCost(cardView.getLeftSplitCostsStr());
rightHalf.color = getColorFromManaCostHack(cardView.getRightSplitCosts());
leftHalf.color = getColorFromManaCostHack(cardView.getLeftSplitCosts());
rightHalf.color = getColorFromManaCostHack(cardView.getRightSplitCostsStr());
leftHalf.color = getColorFromManaCostHack(cardView.getLeftSplitCostsStr());
parseRules(view.getRightSplitRules(), rightHalf.keywords, rightHalf.rules);
parseRules(view.getLeftSplitRules(), leftHalf.keywords, leftHalf.rules);
@ -129,21 +128,18 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
// Ugly hack used here because the card database doesn't actually store color
// for each half of split cards separately.
private ObjectColor getColorFromManaCostHack(ManaCosts costs) {
private ObjectColor getColorFromManaCostHack(String costs) {
ObjectColor c = new ObjectColor();
List<String> symbols = costs.getSymbols();
for (String symbol : symbols) {
if (symbol.contains("W")) {
c.setWhite(true);
} else if (symbol.contains("U")) {
c.setBlue(true);
} else if (symbol.contains("B")) {
c.setBlack(true);
} else if (symbol.contains("R")) {
c.setRed(true);
} else if (symbol.contains("G")) {
c.setGreen(true);
}
if (costs.contains("W")) {
c.setWhite(true);
} else if (costs.contains("U")) {
c.setBlue(true);
} else if (costs.contains("B")) {
c.setBlack(true);
} else if (costs.contains("R")) {
c.setRed(true);
} else if (costs.contains("G")) {
c.setGreen(true);
}
return c;
}

View file

@ -56,7 +56,7 @@ public class CardInfoPaneImpl extends JEditorPane implements CardInfoPane {
try {
SwingUtilities.invokeLater(() -> {
TextLines textLines = GuiDisplayUtil.getTextLinesfromCardView(card);
StringBuilder buffer = GuiDisplayUtil.getRulefromCardView(card, textLines);
StringBuilder buffer = GuiDisplayUtil.getRulesFromCardView(card, textLines);
resizeTooltipIfNeeded(container, textLines.getBasicTextLength(), textLines.getLines().size());
setText(buffer.toString());
setCaretPosition(0);

View file

@ -308,6 +308,10 @@ public final class CardImageUtils {
// search broken files and delete it (zero size files)
// search temp files and delete it (.tmp files from zip library)
Path rootPath = new File(CardImageUtils.getImagesDir()).toPath();
if (!Files.exists(rootPath)) {
return;
}
Collection<Path> brokenFilesList = new ArrayList<>();
Collection<Path> tempFilesList = new ArrayList<>();
try {

View file

@ -31,8 +31,8 @@ public class AbilityView extends CardView {
this.subTypes = new SubTypes();
this.superTypes = EnumSet.noneOf(SuperType.class);
this.color = new ObjectColor();
this.manaCostLeft = ability.getManaCosts().getSymbols();
this.manaCostRight = new ArrayList<>();
this.manaCostLeftStr = String.join("", ability.getManaCosts().getSymbols());
this.manaCostRightStr = "";
}
public CardView getSourceCard() {

View file

@ -7,7 +7,6 @@ import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.SpellAbility;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.effects.Effect;
import mage.abilities.effects.Effects;
import mage.abilities.icon.CardIcon;
@ -65,8 +64,8 @@ public class CardView extends SimpleCardView {
protected ObjectColor frameColor;
protected FrameStyle frameStyle;
// can combine multiple costs for MockCard from deck editor or db (left/right, card/adventure)
protected List<String> manaCostLeft;
protected List<String> manaCostRight;
protected String manaCostLeftStr;
protected String manaCostRightStr;
protected int convertedManaCost;
protected Rarity rarity;
@ -91,11 +90,11 @@ public class CardView extends SimpleCardView {
protected boolean isSplitCard;
protected String leftSplitName;
protected ManaCosts leftSplitCosts;
protected String leftSplitCostsStr;
protected List<String> leftSplitRules;
protected String leftSplitTypeLine;
protected String rightSplitName;
protected ManaCosts rightSplitCosts;
protected String rightSplitCostsStr;
protected List<String> rightSplitRules;
protected String rightSplitTypeLine;
@ -173,8 +172,8 @@ public class CardView extends SimpleCardView {
this.color = cardView.color;
this.frameColor = cardView.frameColor;
this.frameStyle = cardView.frameStyle;
this.manaCostLeft = new ArrayList<>(cardView.manaCostLeft);
this.manaCostRight = new ArrayList<>(cardView.manaCostRight);
this.manaCostLeftStr = cardView.manaCostLeftStr;
this.manaCostRightStr = cardView.manaCostRightStr;
this.convertedManaCost = cardView.convertedManaCost;
this.rarity = cardView.rarity;
@ -195,11 +194,11 @@ public class CardView extends SimpleCardView {
this.isSplitCard = cardView.isSplitCard;
this.leftSplitName = cardView.leftSplitName;
this.leftSplitCosts = cardView.leftSplitCosts == null ? null : cardView.leftSplitCosts.copy();
this.leftSplitCostsStr = cardView.leftSplitCostsStr;
this.leftSplitRules = cardView.leftSplitRules == null ? null : new ArrayList<>(cardView.leftSplitRules);
this.leftSplitTypeLine = cardView.leftSplitTypeLine;
this.rightSplitName = cardView.rightSplitName;
this.rightSplitCosts = cardView.rightSplitCosts == null ? null : cardView.rightSplitCosts.copy();
this.rightSplitCostsStr = cardView.rightSplitCostsStr;
this.rightSplitRules = cardView.rightSplitRules == null ? null : new ArrayList<>(cardView.rightSplitRules);
this.rightSplitTypeLine = cardView.rightSplitTypeLine;
@ -348,40 +347,39 @@ public class CardView extends SimpleCardView {
if (splitCard != null) {
this.isSplitCard = true;
leftSplitName = splitCard.getLeftHalfCard().getName();
leftSplitCosts = splitCard.getLeftHalfCard().getManaCost();
leftSplitCostsStr = String.join("", splitCard.getLeftHalfCard().getManaCost().getSymbols());
leftSplitRules = splitCard.getLeftHalfCard().getRules(game);
leftSplitTypeLine = getCardTypeLine(game, splitCard.getLeftHalfCard());
rightSplitName = splitCard.getRightHalfCard().getName();
rightSplitCosts = splitCard.getRightHalfCard().getManaCost();
rightSplitCostsStr = String.join("", splitCard.getRightHalfCard().getManaCost().getSymbols());
rightSplitRules = splitCard.getRightHalfCard().getRules(game);
rightSplitTypeLine = getCardTypeLine(game, splitCard.getRightHalfCard());
fullCardName = card.getName(); // split card contains full name as normal
this.manaCostLeft = splitCard.getLeftHalfCard().getManaCost().getSymbols();
this.manaCostRight = splitCard.getRightHalfCard().getManaCost().getSymbols();
this.manaCostLeftStr = String.join("", splitCard.getLeftHalfCard().getManaCost().getSymbols());
this.manaCostRightStr = String.join("", splitCard.getRightHalfCard().getManaCost().getSymbols());
} else if (card instanceof ModalDoubleFacesCard) {
this.isModalDoubleFacesCard = true;
ModalDoubleFacesCard mainCard = ((ModalDoubleFacesCard) card);
fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName();
this.manaCostLeft = mainCard.getLeftHalfCard().getManaCost().getSymbols();
this.manaCostRight = mainCard.getRightHalfCard().getManaCost().getSymbols();
this.manaCostLeftStr = String.join("", mainCard.getLeftHalfCard().getManaCost().getSymbols());
this.manaCostRightStr = String.join("", mainCard.getRightHalfCard().getManaCost().getSymbols());
} else if (card instanceof AdventureCard) {
AdventureCard adventureCard = ((AdventureCard) card);
AdventureCardSpell adventureCardSpell = ((AdventureCardSpell) adventureCard.getSpellCard());
fullCardName = adventureCard.getName() + MockCard.ADVENTURE_NAME_SEPARATOR + adventureCardSpell.getName();
this.manaCostLeft = adventureCardSpell.getManaCost().getSymbols();
this.manaCostRight = adventureCard.getManaCost().getSymbols();
this.manaCostLeftStr = String.join("", adventureCardSpell.getManaCost().getSymbols());
this.manaCostRightStr = String.join("", adventureCard.getManaCost().getSymbols());
} else if (card instanceof MockCard) {
// deck editor cards
fullCardName = ((MockCard) card).getFullName(true);
this.manaCostLeft = ((MockCard) card).getManaCost(CardInfo.ManaCostSide.LEFT).getSymbols();
this.manaCostRight = ((MockCard) card).getManaCost(CardInfo.ManaCostSide.RIGHT).getSymbols();
this.manaCostLeftStr = String.join("", ((MockCard) card).getManaCostStr(CardInfo.ManaCostSide.LEFT));
this.manaCostRightStr = String.join("", ((MockCard) card).getManaCostStr(CardInfo.ManaCostSide.RIGHT));
} else {
fullCardName = card.getName();
this.manaCostLeft = card.getManaCost().getSymbols();
this.manaCostRight = new ArrayList<>();
this.manaCostLeftStr = String.join("", card.getManaCost().getSymbols());
this.manaCostRightStr = "";
}
//this.manaCost = card.getManaCost().getSymbols();
this.name = card.getImageName();
this.displayName = card.getName();
@ -565,8 +563,8 @@ public class CardView extends SimpleCardView {
this.subTypes = object.getSubtype(game);
this.superTypes = object.getSuperType();
this.color = object.getColor(game);
this.manaCostLeft = object.getManaCost().getSymbols();
this.manaCostRight = new ArrayList<>();
this.manaCostLeftStr = String.join("", object.getManaCost().getSymbols());
this.manaCostRightStr = "";
this.convertedManaCost = object.getManaCost().convertedManaCost();
if (object instanceof PermanentToken) {
this.mageObjectType = MageObjectType.TOKEN;
@ -686,8 +684,8 @@ public class CardView extends SimpleCardView {
this.color = new ObjectColor();
this.frameColor = new ObjectColor();
this.frameStyle = FrameStyle.M15_NORMAL;
this.manaCostLeft = new ArrayList<>();
this.manaCostRight = new ArrayList<>();
this.manaCostLeftStr = "";
this.manaCostRightStr = "";
this.convertedManaCost = 0;
// the controller can see more information (e.g. enlarged image) than other players for face down cards (e.g. Morph played face down)
@ -735,8 +733,8 @@ public class CardView extends SimpleCardView {
this.color = token.getColor(game);
this.frameColor = token.getFrameColor(game);
this.frameStyle = token.getFrameStyle();
this.manaCostLeft = token.getManaCost().getSymbols();
this.manaCostRight = new ArrayList<>();
this.manaCostLeftStr = String.join("", token.getManaCost().getSymbols());
this.manaCostRightStr = "";
this.rarity = Rarity.SPECIAL;
this.type = token.getTokenType();
this.tokenDescriptor = token.getTokenDescriptor();
@ -846,8 +844,8 @@ public class CardView extends SimpleCardView {
return frameStyle;
}
public List<String> getManaCost() {
return CardUtil.concatManaSymbols(CardInfo.SPLIT_MANA_SEPARATOR_FULL, this.manaCostLeft, this.manaCostRight);
public String getManaCostStr() {
return CardUtil.concatManaSymbols(CardInfo.SPLIT_MANA_SEPARATOR_FULL, this.manaCostLeftStr, this.manaCostRightStr);
}
public int getConvertedManaCost() {
@ -963,8 +961,8 @@ public class CardView extends SimpleCardView {
return leftSplitName;
}
public ManaCosts getLeftSplitCosts() {
return leftSplitCosts;
public String getLeftSplitCostsStr() {
return leftSplitCostsStr;
}
public List<String> getLeftSplitRules() {
@ -979,8 +977,8 @@ public class CardView extends SimpleCardView {
return rightSplitName;
}
public ManaCosts getRightSplitCosts() {
return rightSplitCosts;
public String getRightSplitCostsStr() {
return rightSplitCostsStr;
}
public List<String> getRightSplitRules() {

View file

@ -44,8 +44,8 @@ public class StackAbilityView extends CardView {
this.subTypes = ability.getSubtype(game);
this.superTypes = ability.getSuperType();
this.color = ability.getColor(game);
this.manaCostLeft = ability.getManaCost().getSymbols();
this.manaCostRight = new ArrayList<>();
this.manaCostLeftStr = String.join("", ability.getManaCost().getSymbols());
this.manaCostRightStr = "";
this.cardTypes = ability.getCardType();
this.subTypes = ability.getSubtype(game);
this.superTypes = ability.getSuperType();
@ -60,8 +60,8 @@ public class StackAbilityView extends CardView {
tmpSourceCard.subTypes.clear();
tmpSourceCard.cardTypes.clear();
tmpSourceCard.cardTypes.add(CardType.CREATURE);
tmpSourceCard.manaCostLeft.clear();
tmpSourceCard.manaCostRight.clear();
tmpSourceCard.manaCostLeftStr = "";
tmpSourceCard.manaCostRightStr = "";
tmpSourceCard.power = "2";
tmpSourceCard.toughness = "2";
nameToShow = "creature without name";

View file

@ -1621,7 +1621,7 @@ public class VerifyCardDataTest {
}
String expected = ref.manaCost;
String cost = join(card.getManaCost().getSymbols());
String cost = String.join("", card.getManaCost().getSymbols());
if (cost.isEmpty()) {
cost = null;
}
@ -1674,14 +1674,6 @@ public class VerifyCardDataTest {
}
}
private String join(Iterable<?> items) {
StringBuilder result = new StringBuilder();
for (Object item : items) {
result.append(item);
}
return result.toString();
}
@Test
public void test_checkCardRatingConsistency() {
// all cards with same name must have same rating (see RateCard.rateCard)

View file

@ -57,7 +57,7 @@ public abstract class MageObjectImpl implements MageObject {
color = new ObjectColor();
frameColor = new ObjectColor();
frameStyle = FrameStyle.M15_NORMAL;
manaCost = new ManaCostsImpl<>("");
manaCost = new ManaCostsImpl<>();
abilities = new AbilitiesImpl<>();
textParts = new ArrayList<>();
}

View file

@ -24,6 +24,10 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
private ManaColor() {
}
protected ManaColor(final ManaColor manaColor) {
this.copyFrom(manaColor);
}
private ManaColor(int amount) {
this.amount = amount;
}
@ -76,9 +80,12 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
}
protected ManaColor copy() {
ManaColor copy = new ManaColor();
copy.incrementAmount(this);
return copy;
return new ManaColor(this);
}
protected void copyFrom(final ManaColor manaColor) {
this.amount = manaColor.amount;
this.snowAmount = manaColor.snowAmount;
}
@Override
@ -1202,14 +1209,15 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
* @param mana the mana to set this object to.
*/
public void setToMana(final Mana mana) {
this.any = mana.any.copy();
this.white = mana.white.copy();
this.blue = mana.blue.copy();
this.black = mana.black.copy();
this.red = mana.red.copy();
this.green = mana.green.copy();
this.colorless = mana.colorless.copy();
this.generic = mana.generic.copy();
this.any.copyFrom(mana.any);
this.white.copyFrom(mana.white);
this.blue.copyFrom(mana.blue.copy());
this.black.copyFrom(mana.black.copy());
this.red.copyFrom(mana.red.copy());
this.green.copyFrom(mana.green.copy());
this.colorless.copyFrom(mana.colorless.copy());
this.generic.copyFrom(mana.generic.copy());
//this.flag = mana.flag;
}
/**

View file

@ -194,11 +194,11 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
private void handleLikePhyrexianManaCosts(Player player, Ability source, Game game) {
if (this.isEmpty()) {
return; // nothing to be done without any mana costs. prevents NRE from occurring here
}
}
FilterMana phyrexianColors = player.getPhyrexianColors();
if (player.getPhyrexianColors() != null) {
Costs<PayLifeCost> tempCosts = new CostsImpl<>();
Iterator<T> manaCostIterator = this.iterator();
while (manaCostIterator.hasNext()) {
ManaCost manaCost = manaCostIterator.next();
@ -440,15 +440,16 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
@Override
public final void load(String mana, boolean extractMonoHybridGenericValue) {
this.clear();
if (!extractMonoHybridGenericValue && mana != null && costsCache.containsKey(mana)) {
if (mana == null || mana.isEmpty()) {
return;
}
if (!extractMonoHybridGenericValue && costsCache.containsKey(mana)) {
ManaCosts<ManaCost> savedCosts = costsCache.get(mana);
for (ManaCost cost : savedCosts) {
this.add(cost.copy());
}
} else {
if (mana == null || mana.isEmpty()) {
return;
}
String[] symbols = mana.split("^\\{|}\\{|}$");
int modifierForX = 0;
for (String symbol : symbols) {
@ -463,15 +464,15 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
} else if (!symbol.equals("X")) {
this.add(new ColoredManaCost(ColoredManaSymbol.lookup(symbol.charAt(0))));
} else // check X wasn't added before
if (modifierForX == 0) {
// count X occurence
for (String s : symbols) {
if (s.equals("X")) {
modifierForX++;
if (modifierForX == 0) {
// count X occurence
for (String s : symbols) {
if (s.equals("X")) {
modifierForX++;
}
}
}
this.add(new VariableManaCost(modifierForX));
} //TODO: handle multiple {X} and/or {Y} symbols
this.add(new VariableManaCost(modifierForX));
} //TODO: handle multiple {X} and/or {Y} symbols
} else if (Character.isDigit(symbol.charAt(0))) {
MonoHybridManaCost cost;
if (extractMonoHybridGenericValue) {
@ -534,14 +535,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
StringBuilder sbText = new StringBuilder();
for (ManaCost cost : this) {
if (cost instanceof GenericManaCost) {
sbText.append(cost.getText());
}
}
for (ManaCost cost : this) {
if (!(cost instanceof GenericManaCost)) {
sbText.append(cost.getText());
}
sbText.append(cost.getText());
}
return sbText.toString();
}

View file

@ -29,8 +29,10 @@ public class MockCard extends CardImpl {
private int startingLoyalty;
// mana cost extra info for multiple mana drawing
protected ManaCosts<ManaCost> manaCostLeft;
protected ManaCosts<ManaCost> manaCostRight;
// warning, don't use ManaCost objects here due too much memory consumptions
protected List<String> manaCostLeftStr;
protected List<String> manaCostRightStr;
protected List<String> manaCostStr;
protected String adventureSpellName;
protected boolean isModalDoubleFacesCard;
@ -47,9 +49,10 @@ public class MockCard extends CardImpl {
this.usesVariousArt = card.usesVariousArt();
this.manaCostLeft = new ManaCostsImpl(join(card.getManaCosts(CardInfo.ManaCostSide.LEFT)));
this.manaCostRight = new ManaCostsImpl(join(card.getManaCosts(CardInfo.ManaCostSide.RIGHT)));
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.color = card.getColor();
@ -112,7 +115,8 @@ public class MockCard extends CardImpl {
return manaCost;
}
public ManaCosts<ManaCost> getManaCost(CardInfo.ManaCostSide manaCostSide) {
/*
private ManaCosts<ManaCost> getManaCost(CardInfo.ManaCostSide manaCostSide) {
switch (manaCostSide) {
case LEFT:
return manaCostLeft;
@ -122,6 +126,18 @@ public class MockCard extends CardImpl {
case ALL:
return manaCost;
}
}*/
public List<String> getManaCostStr(CardInfo.ManaCostSide manaCostSide) {
switch (manaCostSide) {
case LEFT:
return manaCostLeftStr;
case RIGHT:
return manaCostRightStr;
default:
case ALL:
return manaCostStr;
}
}
public String getFullName(boolean showSecondName) {

View file

@ -293,7 +293,7 @@ public class CardInfo {
return sb.toString();
}
private List<String> parseList(String list, ManaCostSide manaCostSide) {
public static List<String> parseList(String list, ManaCostSide manaCostSide) {
if (list.isEmpty()) {
return Collections.emptyList();
}

View file

@ -791,6 +791,15 @@ public final class CardUtil {
return res;
}
public static String concatManaSymbols(String delimeter, String mana1, String mana2) {
String res = mana1;
if (!res.isEmpty() && !mana2.isEmpty() && delimeter != null && !delimeter.isEmpty()) {
res += delimeter;
}
res += mana2;
return res;
}
public static ColoredManaSymbol manaTypeToColoredManaSymbol(ManaType manaType) {
switch (manaType) {
case BLACK:

View file

@ -523,7 +523,7 @@ public final class ManaUtil {
* @param secondSideCard second side of double faces card
* @return
*/
public static FilterMana getColorIdentity(ObjectColor cardColor, List<String> cardManaSymbols, List<String> cardRules, Card secondSideCard) {
public static FilterMana getColorIdentity(ObjectColor cardColor, String cardManaSymbols, List<String> cardRules, Card secondSideCard) {
// 20210121
// 903.4
// The Commander variant uses color identity to determine what cards can be in a deck with a certain
@ -612,6 +612,11 @@ public final class ManaUtil {
return cardManaSymbols.stream().anyMatch(s -> s.contains(needSymbol));
}
private static boolean containsManaSymbol(String cardManaSymbols, String needSymbol) {
// search R in {R/B}
return cardManaSymbols.contains(needSymbol);
}
public static FilterMana getColorIdentity(Card card) {
Card secondSide;
if (card instanceof SplitCard) {
@ -623,7 +628,7 @@ public final class ManaUtil {
} else {
secondSide = card.getSecondCardFace();
}
return getColorIdentity(card.getColor(), card.getManaCost().getSymbols(), card.getRules(), secondSide);
return getColorIdentity(card.getColor(), String.join("", card.getManaCost().getSymbols()), card.getRules(), secondSide);
}
public static int getColorIdentityHash(FilterMana colorIdentity) {