* 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 // Casting cost
if (!s) { if (!s) {
String mc = ""; s |= card.getManaCostStr().toLowerCase(Locale.ENGLISH).contains(searchStr);
for (String m : card.getManaCost()) {
mc += m;
}
s |= mc.toLowerCase(Locale.ENGLISH).contains(searchStr);
} }
// Rules // Rules
if (!s) { if (!s) {
@ -1473,10 +1469,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
} }
// Mana Cost // Mana Cost
String mc = ""; String mc = card.getManaCostStr();
for (String m : card.getManaCost()) {
mc += m;
}
mc = mc.replaceAll("\\{([WUBRG]).([WUBRG])\\}", "{$1}{$2}"); mc = mc.replaceAll("\\{([WUBRG]).([WUBRG])\\}", "{$1}{$2}");
mc = mc.replaceAll("\\{", "#"); mc = mc.replaceAll("\\{", "#");
mc = mc.replaceAll("#2\\/", "#"); 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 return c.getDisplayFullName(); // show full name in deck editor table, e.g. adventure with spell name
case 2: case 2:
// new svg images version // new svg images version
return ManaSymbols.getStringManaCost(c.getManaCost()); return ManaSymbols.getClearManaCost(c.getManaCostStr());
/* /*
// old html images version // old html images version
String manaCost = ""; String manaCost = "";

View file

@ -24,7 +24,7 @@ public class CardViewColorIdentityComparator implements CardViewComparator {
} }
public static FilterMana calcIdentity(CardView cardView) { 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) { public static int calcHash(CardView cardView) {

View file

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

View file

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

View file

@ -529,7 +529,7 @@ public class CardPanelRenderModeImage extends CardPanel {
int symbolMarginX = 2; // 2 px between icons int symbolMarginX = 2; // 2 px between icons
String manaCost = ManaSymbols.getStringManaCost(getGameCard().getManaCost()); String manaCost = ManaSymbols.getClearManaCost(getGameCard().getManaCostStr());
int manaWidth = getManaWidth(manaCost, symbolMarginX); int manaWidth = getManaWidth(manaCost, symbolMarginX);
// right top corner with margin (sizes from any sample card, length from black border to mana icon) // 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())) { if (!a.getSuperTypes().equals(b.getSuperTypes())) {
return false; return false;
} }
if (!a.getManaCost().equals(b.getManaCost())) { if (!a.getManaCostStr().equals(b.getManaCostStr())) {
return false; return false;
} }
if (!a.getRules().equals(b.getRules())) { if (!a.getRules().equals(b.getRules())) {
@ -166,9 +166,7 @@ public class CardPanelRenderModeMTGO extends CardPanel {
for (SubType s : this.view.getSubTypes()) { for (SubType s : this.view.getSubTypes()) {
sb.append(s); sb.append(s);
} }
for (String s : this.view.getManaCost()) { sb.append(this.view.getManaCostStr());
sb.append(s);
}
for (String s : this.view.getRules()) { for (String s : this.view.getRules()) {
sb.append(s); 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(); StringBuilder sb = new StringBuilder();
for (String s : manaCost) { for (String s : manaCost) {
sb.append(s); sb.append(s);
} }
return sb.toString() return getClearManaCost(sb.toString());
}
public static String getClearManaCost(String manaCost) {
return manaCost
.replace("/", "") .replace("/", "")
.replace("{", "") .replace("{", "")
.replace("}", " ") .replace("}", " ") // each mana symbol splits by space
.trim(); .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 { public enum Type {
TABLE, TABLE,
CHAT, CHAT,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1621,7 +1621,7 @@ public class VerifyCardDataTest {
} }
String expected = ref.manaCost; String expected = ref.manaCost;
String cost = join(card.getManaCost().getSymbols()); String cost = String.join("", card.getManaCost().getSymbols());
if (cost.isEmpty()) { if (cost.isEmpty()) {
cost = null; 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 @Test
public void test_checkCardRatingConsistency() { public void test_checkCardRatingConsistency() {
// all cards with same name must have same rating (see RateCard.rateCard) // 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(); color = new ObjectColor();
frameColor = new ObjectColor(); frameColor = new ObjectColor();
frameStyle = FrameStyle.M15_NORMAL; frameStyle = FrameStyle.M15_NORMAL;
manaCost = new ManaCostsImpl<>(""); manaCost = new ManaCostsImpl<>();
abilities = new AbilitiesImpl<>(); abilities = new AbilitiesImpl<>();
textParts = new ArrayList<>(); textParts = new ArrayList<>();
} }

View file

@ -24,6 +24,10 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
private ManaColor() { private ManaColor() {
} }
protected ManaColor(final ManaColor manaColor) {
this.copyFrom(manaColor);
}
private ManaColor(int amount) { private ManaColor(int amount) {
this.amount = amount; this.amount = amount;
} }
@ -76,9 +80,12 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
} }
protected ManaColor copy() { protected ManaColor copy() {
ManaColor copy = new ManaColor(); return new ManaColor(this);
copy.incrementAmount(this); }
return copy;
protected void copyFrom(final ManaColor manaColor) {
this.amount = manaColor.amount;
this.snowAmount = manaColor.snowAmount;
} }
@Override @Override
@ -1202,14 +1209,15 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
* @param mana the mana to set this object to. * @param mana the mana to set this object to.
*/ */
public void setToMana(final Mana mana) { public void setToMana(final Mana mana) {
this.any = mana.any.copy(); this.any.copyFrom(mana.any);
this.white = mana.white.copy(); this.white.copyFrom(mana.white);
this.blue = mana.blue.copy(); this.blue.copyFrom(mana.blue.copy());
this.black = mana.black.copy(); this.black.copyFrom(mana.black.copy());
this.red = mana.red.copy(); this.red.copyFrom(mana.red.copy());
this.green = mana.green.copy(); this.green.copyFrom(mana.green.copy());
this.colorless = mana.colorless.copy(); this.colorless.copyFrom(mana.colorless.copy());
this.generic = mana.generic.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) { private void handleLikePhyrexianManaCosts(Player player, Ability source, Game game) {
if (this.isEmpty()) { if (this.isEmpty()) {
return; // nothing to be done without any mana costs. prevents NRE from occurring here return; // nothing to be done without any mana costs. prevents NRE from occurring here
} }
FilterMana phyrexianColors = player.getPhyrexianColors(); FilterMana phyrexianColors = player.getPhyrexianColors();
if (player.getPhyrexianColors() != null) { if (player.getPhyrexianColors() != null) {
Costs<PayLifeCost> tempCosts = new CostsImpl<>(); Costs<PayLifeCost> tempCosts = new CostsImpl<>();
Iterator<T> manaCostIterator = this.iterator(); Iterator<T> manaCostIterator = this.iterator();
while (manaCostIterator.hasNext()) { while (manaCostIterator.hasNext()) {
ManaCost manaCost = manaCostIterator.next(); ManaCost manaCost = manaCostIterator.next();
@ -440,15 +440,16 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
@Override @Override
public final void load(String mana, boolean extractMonoHybridGenericValue) { public final void load(String mana, boolean extractMonoHybridGenericValue) {
this.clear(); 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); ManaCosts<ManaCost> savedCosts = costsCache.get(mana);
for (ManaCost cost : savedCosts) { for (ManaCost cost : savedCosts) {
this.add(cost.copy()); this.add(cost.copy());
} }
} else { } else {
if (mana == null || mana.isEmpty()) {
return;
}
String[] symbols = mana.split("^\\{|}\\{|}$"); String[] symbols = mana.split("^\\{|}\\{|}$");
int modifierForX = 0; int modifierForX = 0;
for (String symbol : symbols) { for (String symbol : symbols) {
@ -463,15 +464,15 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
} else if (!symbol.equals("X")) { } else if (!symbol.equals("X")) {
this.add(new ColoredManaCost(ColoredManaSymbol.lookup(symbol.charAt(0)))); this.add(new ColoredManaCost(ColoredManaSymbol.lookup(symbol.charAt(0))));
} else // check X wasn't added before } else // check X wasn't added before
if (modifierForX == 0) { if (modifierForX == 0) {
// count X occurence // count X occurence
for (String s : symbols) { for (String s : symbols) {
if (s.equals("X")) { if (s.equals("X")) {
modifierForX++; modifierForX++;
}
} }
} this.add(new VariableManaCost(modifierForX));
this.add(new VariableManaCost(modifierForX)); } //TODO: handle multiple {X} and/or {Y} symbols
} //TODO: handle multiple {X} and/or {Y} symbols
} else if (Character.isDigit(symbol.charAt(0))) { } else if (Character.isDigit(symbol.charAt(0))) {
MonoHybridManaCost cost; MonoHybridManaCost cost;
if (extractMonoHybridGenericValue) { if (extractMonoHybridGenericValue) {
@ -534,14 +535,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
StringBuilder sbText = new StringBuilder(); StringBuilder sbText = new StringBuilder();
for (ManaCost cost : this) { for (ManaCost cost : this) {
if (cost instanceof GenericManaCost) { sbText.append(cost.getText());
sbText.append(cost.getText());
}
}
for (ManaCost cost : this) {
if (!(cost instanceof GenericManaCost)) {
sbText.append(cost.getText());
}
} }
return sbText.toString(); return sbText.toString();
} }

View file

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

View file

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

View file

@ -791,6 +791,15 @@ public final class CardUtil {
return res; 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) { public static ColoredManaSymbol manaTypeToColoredManaSymbol(ManaType manaType) {
switch (manaType) { switch (manaType) {
case BLACK: case BLACK:

View file

@ -523,7 +523,7 @@ public final class ManaUtil {
* @param secondSideCard second side of double faces card * @param secondSideCard second side of double faces card
* @return * @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 // 20210121
// 903.4 // 903.4
// The Commander variant uses color identity to determine what cards can be in a deck with a certain // 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)); 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) { public static FilterMana getColorIdentity(Card card) {
Card secondSide; Card secondSide;
if (card instanceof SplitCard) { if (card instanceof SplitCard) {
@ -623,7 +628,7 @@ public final class ManaUtil {
} else { } else {
secondSide = card.getSecondCardFace(); 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) { public static int getColorIdentityHash(FilterMana colorIdentity) {