mirror of
https://github.com/correl/mage.git
synced 2024-11-15 03:00:16 +00:00
Merge pull request #5501 from hitch17/add-cockatrice-deck-format-5493
UI: add cockatrice deck format support for import (*.cod)
This commit is contained in:
commit
11f93cf762
24 changed files with 584 additions and 162 deletions
|
@ -14,7 +14,6 @@ import mage.cards.Sets;
|
|||
import mage.cards.decks.Deck;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.decks.importer.DeckImporter;
|
||||
import mage.cards.decks.importer.DeckImporterUtil;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.client.MageFrame;
|
||||
|
@ -798,7 +797,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
|
||||
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
try {
|
||||
newDeck = Deck.load(DeckImporterUtil.importDeck(dialog.getTmpPath(), errorMessages), true, true);
|
||||
newDeck = Deck.load(DeckImporter.importDeckFromFile(dialog.getTmpPath(), errorMessages), true, true);
|
||||
processAndShowImportErrors(errorMessages);
|
||||
|
||||
if (newDeck != null) {
|
||||
|
@ -831,7 +830,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
|
||||
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
try {
|
||||
deckToAppend = Deck.load(DeckImporterUtil.importDeck(dialog.getTmpPath(), errorMessages), true, true);
|
||||
deckToAppend = Deck.load(DeckImporter.importDeckFromFile(dialog.getTmpPath(), errorMessages), true, true);
|
||||
processAndShowImportErrors(errorMessages);
|
||||
|
||||
if (deckToAppend != null) {
|
||||
|
@ -878,7 +877,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
Deck newDeck = null;
|
||||
StringBuilder errorMessages = new StringBuilder();
|
||||
|
||||
newDeck = Deck.load(DeckImporterUtil.importDeck(file.getPath(), errorMessages), true, true);
|
||||
newDeck = Deck.load(DeckImporter.importDeckFromFile(file.getPath(), errorMessages), true, true);
|
||||
processAndShowImportErrors(errorMessages);
|
||||
|
||||
if (newDeck != null) {
|
||||
|
@ -977,7 +976,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
File file = fcImportDeck.getSelectedFile();
|
||||
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
try {
|
||||
DeckImporter importer = DeckImporterUtil.getDeckImporter(file.getPath());
|
||||
DeckImporter importer = DeckImporter.getDeckImporter(file.getPath());
|
||||
|
||||
if (importer != null) {
|
||||
StringBuilder errorMessages = new StringBuilder();
|
||||
|
@ -1048,7 +1047,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
try {
|
||||
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
String path = DeckGenerator.generateDeck();
|
||||
deck = Deck.load(DeckImporterUtil.importDeck(path), true, true);
|
||||
deck = Deck.load(DeckImporter.importDeckFromFile(path), true, true);
|
||||
} catch (GameException ex) {
|
||||
JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage(), "Error loading generated deck", JOptionPane.ERROR_MESSAGE);
|
||||
} catch (DeckGeneratorException ex) {
|
||||
|
@ -1120,7 +1119,11 @@ class ImportFilter extends FileFilter {
|
|||
ext = s.substring(i + 1).toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
if (ext != null) {
|
||||
if (ext.toLowerCase(Locale.ENGLISH).equals("dec") || ext.toLowerCase(Locale.ENGLISH).equals("mwdeck") || ext.toLowerCase(Locale.ENGLISH).equals("txt") || ext.toLowerCase(Locale.ENGLISH).equals("dek")) {
|
||||
if (ext.toLowerCase(Locale.ENGLISH).equals("dec")
|
||||
|| ext.toLowerCase(Locale.ENGLISH).equals("mwdeck")
|
||||
|| ext.toLowerCase(Locale.ENGLISH).equals("txt")
|
||||
|| ext.toLowerCase(Locale.ENGLISH).equals("dek")
|
||||
|| ext.toLowerCase(Locale.ENGLISH).equals("cod")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1129,7 +1132,7 @@ class ImportFilter extends FileFilter {
|
|||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "*.dec | *.mwDeck | *.txt | *.dek";
|
||||
return "*.dec | *.mwDeck | *.txt | *.dek | *.cod";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
package mage.client.dialog;
|
||||
|
||||
import mage.cards.decks.importer.DeckImporterUtil;
|
||||
import mage.cards.decks.importer.DeckImporter;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.SessionHandler;
|
||||
import mage.players.PlayerType;
|
||||
|
@ -119,9 +119,9 @@ public class JoinTableDialog extends MageDialog {
|
|||
try {
|
||||
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD_JOIN, txtPassword.getText());
|
||||
if (isTournament) {
|
||||
joined = session.joinTournamentTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporterUtil.importDeck(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText());
|
||||
joined = session.joinTournamentTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporter.importDeckFromFile(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText());
|
||||
} else {
|
||||
joined = session.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporterUtil.importDeck(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText());
|
||||
joined = session.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporter.importDeckFromFile(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText());
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
|
|
|
@ -7,7 +7,8 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.swing.*;
|
||||
import mage.cards.decks.importer.DeckImporterUtil;
|
||||
|
||||
import mage.cards.decks.importer.DeckImporter;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.SessionHandler;
|
||||
import mage.client.components.MageComponents;
|
||||
|
@ -425,7 +426,7 @@ public class NewTableDialog extends MageDialog {
|
|||
table.getTableId(),
|
||||
this.player1Panel.getPlayerName(),
|
||||
PlayerType.HUMAN, 1,
|
||||
DeckImporterUtil.importDeck(this.player1Panel.getDeckFile()),
|
||||
DeckImporter.importDeckFromFile(this.player1Panel.getDeckFile()),
|
||||
this.txtPassword.getText())) {
|
||||
for (TablePlayerPanel player : players) {
|
||||
if (player.getPlayerType() != PlayerType.HUMAN) {
|
||||
|
|
|
@ -18,7 +18,7 @@ import java.util.UUID;
|
|||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.cards.decks.importer.DeckImporterUtil;
|
||||
import mage.cards.decks.importer.DeckImporter;
|
||||
import mage.cards.repository.ExpansionInfo;
|
||||
import mage.cards.repository.ExpansionRepository;
|
||||
import mage.client.MageFrame;
|
||||
|
@ -557,7 +557,7 @@ public class NewTournamentDialog extends MageDialog {
|
|||
if (!(cubeFromDeckFilename.isEmpty())) {
|
||||
Deck cubeFromDeck = new Deck();
|
||||
try {
|
||||
cubeFromDeck = Deck.load(DeckImporterUtil.importDeck(cubeFromDeckFilename), true, true);
|
||||
cubeFromDeck = Deck.load(DeckImporter.importDeckFromFile(cubeFromDeckFilename), true, true);
|
||||
} catch (GameException e1) {
|
||||
JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
|
@ -631,11 +631,11 @@ public class NewTournamentDialog extends MageDialog {
|
|||
table.getTableId(),
|
||||
this.player1Panel.getPlayerName(),
|
||||
PlayerType.HUMAN, 1,
|
||||
DeckImporterUtil.importDeck(this.player1Panel.getDeckFile()),
|
||||
DeckImporter.importDeckFromFile(this.player1Panel.getDeckFile()),
|
||||
tOptions.getPassword())) {
|
||||
for (TournamentPlayerPanel player : players) {
|
||||
if (player.getPlayerType().getSelectedItem() != PlayerType.HUMAN) {
|
||||
if (!player.joinTournamentTable(roomId, table.getTableId(), DeckImporterUtil.importDeck(this.player1Panel.getDeckFile()))) {
|
||||
if (!player.joinTournamentTable(roomId, table.getTableId(), DeckImporter.importDeckFromFile(this.player1Panel.getDeckFile()))) {
|
||||
// error message must be send by sever
|
||||
SessionHandler.removeTable(roomId, table.getTableId());
|
||||
table = null;
|
||||
|
|
|
@ -20,7 +20,8 @@ import javax.swing.JPopupMenu;
|
|||
import javax.swing.LayoutStyle.ComponentPlacement;
|
||||
import javax.swing.MenuSelectionManager;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import mage.cards.decks.importer.DeckImporterUtil;
|
||||
|
||||
import mage.cards.decks.importer.DeckImporter;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.SessionHandler;
|
||||
import mage.client.cards.BigCard;
|
||||
|
@ -569,7 +570,7 @@ public class PlayAreaPanel extends javax.swing.JPanel {
|
|||
}
|
||||
|
||||
private void btnCheatActionPerformed(java.awt.event.ActionEvent evt) {
|
||||
SessionHandler.cheat(gameId, playerId, DeckImporterUtil.importDeck("cheat.dck"));
|
||||
SessionHandler.cheat(gameId, playerId, DeckImporter.importDeckFromFile("cheat.dck"));
|
||||
}
|
||||
|
||||
public boolean isSmallMode() {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
package mage.client.table;
|
||||
|
||||
import mage.cards.decks.importer.DeckImporterUtil;
|
||||
import mage.cards.decks.importer.DeckImporter;
|
||||
import mage.client.SessionHandler;
|
||||
import mage.client.util.Config;
|
||||
import mage.client.util.Event;
|
||||
|
@ -53,7 +53,7 @@ public class TablePlayerPanel extends javax.swing.JPanel {
|
|||
|
||||
public boolean joinTable(UUID roomId, UUID tableId) throws IOException, ClassNotFoundException {
|
||||
if (this.cbPlayerType.getSelectedItem() != PlayerType.HUMAN) {
|
||||
return SessionHandler.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), (PlayerType) this.cbPlayerType.getSelectedItem(), this.newPlayerPanel.getLevel(), DeckImporterUtil.importDeck(this.newPlayerPanel.getDeckFile()), "");
|
||||
return SessionHandler.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), (PlayerType) this.cbPlayerType.getSelectedItem(), this.newPlayerPanel.getLevel(), DeckImporter.importDeckFromFile(this.newPlayerPanel.getDeckFile()), "");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package mage.client.table;
|
||||
|
||||
import mage.cards.decks.importer.DeckImporterUtil;
|
||||
import mage.cards.decks.importer.DeckImporter;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.SessionHandler;
|
||||
import mage.client.chat.ChatPanelBasic;
|
||||
|
@ -1263,8 +1263,8 @@ public class TablesPanel extends javax.swing.JPanel {
|
|||
options.setBannedUsers(IgnoreList.ignoreList(serverAddress));
|
||||
table = SessionHandler.createTable(roomId, options);
|
||||
|
||||
SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, DeckImporterUtil.importDeck("test.dck"), "");
|
||||
SessionHandler.joinTable(roomId, table.getTableId(), "Computer", PlayerType.COMPUTER_MAD, 5, DeckImporterUtil.importDeck("test.dck"), "");
|
||||
SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, DeckImporter.importDeckFromFile("test.dck"), "");
|
||||
SessionHandler.joinTable(roomId, table.getTableId(), "Computer", PlayerType.COMPUTER_MAD, 5, DeckImporter.importDeckFromFile("test.dck"), "");
|
||||
SessionHandler.startMatch(roomId, table.getTableId());
|
||||
} catch (HeadlessException ex) {
|
||||
handleError(ex);
|
||||
|
|
|
@ -6,7 +6,7 @@ import mage.abilities.Ability;
|
|||
import mage.cards.Card;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.decks.importer.DeckImporterUtil;
|
||||
import mage.cards.decks.importer.DeckImporter;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.cards.repository.CardScanner;
|
||||
|
@ -189,7 +189,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
if (loadedDeckCardLists.containsKey(deckName)) {
|
||||
list = loadedDeckCardLists.get(deckName);
|
||||
} else {
|
||||
list = DeckImporterUtil.importDeck(deckName);
|
||||
list = DeckImporter.importDeckFromFile(deckName);
|
||||
loadedDeckCardLists.put(deckName, list);
|
||||
}
|
||||
Deck deck = Deck.load(list, false, false);
|
||||
|
|
16
Mage/src/main/java/mage/cards/decks/importer/CardLookup.java
Normal file
16
Mage/src/main/java/mage/cards/decks/importer/CardLookup.java
Normal file
|
@ -0,0 +1,16 @@
|
|||
package mage.cards.decks.importer;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
|
||||
public class CardLookup {
|
||||
|
||||
public static final CardLookup instance = new CardLookup();
|
||||
|
||||
public Optional<CardInfo> lookupCardInfo(String name) {
|
||||
return Optional.ofNullable(CardRepository.instance.findPreferedCoreExpansionCard(name, true));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package mage.cards.decks.importer;
|
||||
|
||||
import static javax.xml.xpath.XPathConstants.NODESET;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import mage.cards.decks.DeckCardInfo;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
|
||||
public class CodDeckImporter extends DeckImporter {
|
||||
|
||||
private XPathFactory xpathFactory = XPathFactory.newInstance();
|
||||
private DocumentBuilder builder = getDocumentBuilder();
|
||||
|
||||
@Override
|
||||
public DeckCardLists importDeck(String filename, StringBuilder errorMessages) {
|
||||
try {
|
||||
Document doc = getXmlDocument(filename);
|
||||
DeckCardLists decklist = new DeckCardLists();
|
||||
|
||||
List<Node> mainCards = getNodes(doc, "/cockatrice_deck/zone[@name='main']/card");
|
||||
decklist.setCards(mainCards.stream()
|
||||
.flatMap(toDeckCardInfo(getCardLookup(), errorMessages))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
List<Node> sideboardCards = getNodes(doc, "/cockatrice_deck/zone[@name='side']/card");
|
||||
decklist.setSideboard(sideboardCards.stream()
|
||||
.flatMap(toDeckCardInfo(getCardLookup(), errorMessages))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
getNodes(doc, "/cockatrice_deck/deckname")
|
||||
.forEach(n -> decklist.setName(n.getTextContent().trim()));
|
||||
|
||||
return decklist;
|
||||
} catch (Exception e) {
|
||||
logger.error("Error loading deck", e);
|
||||
errorMessages.append("There was an error loading the deck.");
|
||||
return new DeckCardLists();
|
||||
}
|
||||
}
|
||||
|
||||
private static int getQuantityFromNode(Node node) {
|
||||
Node numberNode = node.getAttributes().getNamedItem("number");
|
||||
if (numberNode == null) {
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
return Math.min(100, Math.max(1, Integer.parseInt(numberNode.getNodeValue())));
|
||||
} catch (NumberFormatException e) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static Function<Node, Stream<DeckCardInfo>> toDeckCardInfo(CardLookup lookup, StringBuilder errors) {
|
||||
return node -> {
|
||||
String name = node.getAttributes().getNamedItem("name").getNodeValue().trim();
|
||||
Optional<CardInfo> cardInfo = lookup.lookupCardInfo(name);
|
||||
if (cardInfo.isPresent()) {
|
||||
CardInfo info = cardInfo.get();
|
||||
return Collections.nCopies(
|
||||
getQuantityFromNode(node),
|
||||
new DeckCardInfo(info.getName(), info.getCardNumber(), info.getSetCode())).stream();
|
||||
} else {
|
||||
errors.append("Could not find card: '").append(name).append("'\n");
|
||||
return Stream.empty();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private List<Node> getNodes(Document doc, String xpathExpression) throws XPathExpressionException {
|
||||
NodeList nodes = (NodeList) xpathFactory.newXPath().evaluate(xpathExpression, doc, NODESET);
|
||||
ArrayList<Node> list = new ArrayList<>();
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
list.add(nodes.item(i));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private DocumentBuilder getDocumentBuilder() {
|
||||
try {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
return factory.newDocumentBuilder();
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
protected Document getXmlDocument(String filename) throws IOException {
|
||||
try {
|
||||
return builder.parse(new File(filename));
|
||||
} catch (SAXException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -15,7 +15,7 @@ import mage.cards.repository.CardRepository;
|
|||
*
|
||||
* @author North
|
||||
*/
|
||||
public class DckDeckImporter extends DeckImporter {
|
||||
public class DckDeckImporter extends PlainTextDeckImporter {
|
||||
|
||||
private static final Pattern pattern = Pattern.compile("(SB:)?\\s*(\\d*)\\s*\\[([^]:]+):([^]:]+)\\]\\s*(.*)\\s*$");
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
|
||||
package mage.cards.decks.importer;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import mage.cards.decks.DeckCardInfo;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.repository.CardInfo;
|
||||
|
@ -10,7 +12,7 @@ import mage.cards.repository.CardRepository;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class DecDeckImporter extends DeckImporter {
|
||||
public class DecDeckImporter extends PlainTextDeckImporter {
|
||||
|
||||
@Override
|
||||
protected void readLine(String line, DeckCardLists deckList) {
|
||||
|
@ -29,10 +31,11 @@ public class DecDeckImporter extends DeckImporter {
|
|||
String lineName = line.substring(delim).trim();
|
||||
try {
|
||||
int num = Integer.parseInt(lineNum);
|
||||
CardInfo cardInfo = CardRepository.instance.findPreferedCoreExpansionCard(lineName, true);
|
||||
if (cardInfo == null) {
|
||||
Optional<CardInfo> cardLookup = getCardLookup().lookupCardInfo(lineName);
|
||||
if (!cardLookup.isPresent()) {
|
||||
sbMessage.append("Could not find card: '").append(lineName).append("' at line ").append(lineCount).append('\n');
|
||||
} else {
|
||||
CardInfo cardInfo = cardLookup.get();
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (!sideboard) {
|
||||
deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode()));
|
||||
|
|
|
@ -1,74 +1,87 @@
|
|||
|
||||
|
||||
package mage.cards.decks.importer;
|
||||
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
|
||||
public abstract class DeckImporter {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DeckImporter.class);
|
||||
protected static final Logger logger = Logger.getLogger(DeckImporter.class);
|
||||
|
||||
protected StringBuilder sbMessage = new StringBuilder(); //TODO we should stop using this not garbage collectable StringBuilder. It just bloats
|
||||
protected int lineCount;
|
||||
private static final String[] SIDEBOARD_MARKS = new String[]{"//sideboard", "sb: "};
|
||||
|
||||
public static DeckImporter getDeckImporter(String file) {
|
||||
if (file == null) {
|
||||
return null;
|
||||
} if (file.toLowerCase(Locale.ENGLISH).endsWith("dec")) {
|
||||
return new DecDeckImporter();
|
||||
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("mwdeck")) {
|
||||
return new MWSDeckImporter();
|
||||
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("txt")) {
|
||||
return new TxtDeckImporter(haveSideboardSection(file));
|
||||
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("dck")) {
|
||||
return new DckDeckImporter();
|
||||
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("dek")) {
|
||||
return new DekDeckImporter();
|
||||
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("cod")) {
|
||||
return new CodDeckImporter();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param file file to import
|
||||
* @param errorMessages you can setup output messages to showup to user (set null for fatal exception on messages.count > 0)
|
||||
* @return decks list
|
||||
*/
|
||||
public DeckCardLists importDeck(String file, StringBuilder errorMessages) {
|
||||
File f = new File(file);
|
||||
DeckCardLists deckList = new DeckCardLists();
|
||||
if (!f.exists()) {
|
||||
logger.warn("Deckfile " + file + " not found.");
|
||||
return deckList;
|
||||
public static DeckCardLists importDeckFromFile(String file) {
|
||||
return importDeckFromFile(file, new StringBuilder());
|
||||
}
|
||||
|
||||
public static DeckCardLists importDeckFromFile(String file, StringBuilder errorMessages) {
|
||||
DeckImporter deckImporter = getDeckImporter(file);
|
||||
if (deckImporter != null) {
|
||||
return deckImporter.importDeck(file, errorMessages);
|
||||
} else {
|
||||
return new DeckCardLists();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract DeckCardLists importDeck(String file, StringBuilder errorMessages);
|
||||
|
||||
public DeckCardLists importDeck(String file) {
|
||||
return importDeck(file, new StringBuilder());
|
||||
}
|
||||
|
||||
public CardLookup getCardLookup() {
|
||||
return CardLookup.instance;
|
||||
}
|
||||
|
||||
private static boolean haveSideboardSection(String file) {
|
||||
// search for sideboard section:
|
||||
// or //sideboard
|
||||
// or SB: 1 card name -- special deckstats.net
|
||||
|
||||
File f = new File(file);
|
||||
try (Scanner scanner = new Scanner(f)) {
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine().trim().toLowerCase(Locale.ENGLISH);
|
||||
|
||||
for (String mark : SIDEBOARD_MARKS) {
|
||||
if (line.startsWith(mark)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
lineCount = 0;
|
||||
|
||||
sbMessage.setLength(0);
|
||||
try {
|
||||
try (Scanner scanner = new Scanner(f)) {
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine().trim();
|
||||
lineCount++;
|
||||
readLine(line, deckList);
|
||||
}
|
||||
|
||||
if (sbMessage.length() > 0) {
|
||||
if(errorMessages != null) {
|
||||
// normal output for user
|
||||
errorMessages.append(sbMessage);
|
||||
}else{
|
||||
// fatal error
|
||||
logger.fatal(sbMessage);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.fatal(null, ex);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.fatal(null, ex);
|
||||
}
|
||||
return deckList;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore error, deckimporter will process it
|
||||
}
|
||||
|
||||
public DeckCardLists importDeck(String file) {
|
||||
return importDeck(file, null);
|
||||
}
|
||||
// not found
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getErrors(){
|
||||
return sbMessage.toString();
|
||||
}
|
||||
|
||||
protected abstract void readLine(String line, DeckCardLists deckList);
|
||||
}
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
|
||||
package mage.cards.decks.importer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Locale;
|
||||
import java.util.Scanner;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author North
|
||||
*/
|
||||
public final class DeckImporterUtil {
|
||||
|
||||
private static final String[] SIDEBOARD_MARKS = new String[]{"//sideboard", "sb: "};
|
||||
|
||||
public static boolean haveSideboardSection(String file) {
|
||||
// search for sideboard section:
|
||||
// or //sideboard
|
||||
// or SB: 1 card name -- special deckstats.net
|
||||
|
||||
File f = new File(file);
|
||||
try (Scanner scanner = new Scanner(f)) {
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine().trim().toLowerCase(Locale.ENGLISH);
|
||||
|
||||
for (String mark : SIDEBOARD_MARKS) {
|
||||
if (line.startsWith(mark)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore error, deckimporter will process it
|
||||
}
|
||||
|
||||
// not found
|
||||
return false;
|
||||
}
|
||||
|
||||
public static DeckImporter getDeckImporter(String file) {
|
||||
if (file == null) {
|
||||
return null;
|
||||
} if (file.toLowerCase(Locale.ENGLISH).endsWith("dec")) {
|
||||
return new DecDeckImporter();
|
||||
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("mwdeck")) {
|
||||
return new MWSDeckImporter();
|
||||
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("txt")) {
|
||||
return new TxtDeckImporter(haveSideboardSection(file));
|
||||
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("dck")) {
|
||||
return new DckDeckImporter();
|
||||
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("dek")) {
|
||||
return new DekDeckImporter();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static DeckCardLists importDeck(String file, StringBuilder errorMessages) {
|
||||
DeckImporter deckImporter = getDeckImporter(file);
|
||||
if (deckImporter != null) {
|
||||
return deckImporter.importDeck(file, errorMessages);
|
||||
} else {
|
||||
return new DeckCardLists();
|
||||
}
|
||||
}
|
||||
|
||||
public static DeckCardLists importDeck(String file) {
|
||||
return importDeck(file, null);
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ import mage.cards.repository.CardRepository;
|
|||
/**
|
||||
* Created by royk on 11-Sep-16.
|
||||
*/
|
||||
public class DekDeckImporter extends DeckImporter {
|
||||
public class DekDeckImporter extends PlainTextDeckImporter {
|
||||
|
||||
@Override
|
||||
protected void readLine(String line, DeckCardLists deckList) {
|
||||
|
|
|
@ -14,7 +14,7 @@ import mage.util.RandomUtil;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class MWSDeckImporter extends DeckImporter {
|
||||
public class MWSDeckImporter extends PlainTextDeckImporter {
|
||||
|
||||
@Override
|
||||
protected void readLine(String line, DeckCardLists deckList) {
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
|
||||
package mage.cards.decks.importer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Scanner;
|
||||
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public abstract class PlainTextDeckImporter extends DeckImporter {
|
||||
|
||||
protected StringBuilder sbMessage = new StringBuilder(); //TODO we should stop using this not garbage collectable StringBuilder. It just bloats
|
||||
protected int lineCount;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param file file to import
|
||||
* @param errorMessages you can setup output messages to showup to user (set null for fatal exception on messages.count > 0)
|
||||
* @return decks list
|
||||
*/
|
||||
public DeckCardLists importDeck(String file, StringBuilder errorMessages) {
|
||||
File f = new File(file);
|
||||
DeckCardLists deckList = new DeckCardLists();
|
||||
if (!f.exists()) {
|
||||
logger.warn("Deckfile " + file + " not found.");
|
||||
return deckList;
|
||||
}
|
||||
lineCount = 0;
|
||||
|
||||
sbMessage.setLength(0);
|
||||
try {
|
||||
try (Scanner scanner = new Scanner(f)) {
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine().trim();
|
||||
lineCount++;
|
||||
readLine(line, deckList);
|
||||
}
|
||||
|
||||
if (sbMessage.length() > 0) {
|
||||
if(errorMessages != null) {
|
||||
// normal output for user
|
||||
errorMessages.append(sbMessage);
|
||||
}else{
|
||||
// fatal error
|
||||
logger.fatal(sbMessage);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.fatal(null, ex);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.fatal(null, ex);
|
||||
}
|
||||
return deckList;
|
||||
}
|
||||
|
||||
public DeckCardLists importDeck(String file) {
|
||||
return importDeck(file, null);
|
||||
}
|
||||
|
||||
protected abstract void readLine(String line, DeckCardLists deckList);
|
||||
}
|
|
@ -14,7 +14,7 @@ import mage.cards.repository.CardRepository;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class TxtDeckImporter extends DeckImporter {
|
||||
public class TxtDeckImporter extends PlainTextDeckImporter {
|
||||
|
||||
private static final String[] SET_VALUES = new String[]{"lands", "creatures", "planeswalkers", "other spells", "sideboard cards",
|
||||
"Instant", "Land", "Enchantment", "Artifact", "Sorcery", "Planeswalker", "Creature"};
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package mage.cards.decks.importer;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.decks.DeckCardInfo;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.repository.CardInfo;
|
||||
|
||||
public class CodDeckImportTest {
|
||||
|
||||
private static final FakeCardLookup LOOKUP = new FakeCardLookup()
|
||||
.addCard("Forest")
|
||||
.addCard("Razorverge Thicket")
|
||||
.addCard("Avacyn's Pilgrim")
|
||||
.addCard("War Priest of Thune");
|
||||
|
||||
@Test
|
||||
public void testImportCod() {
|
||||
CodDeckImporter importer = new CodDeckImporter() {
|
||||
@Override
|
||||
public CardLookup getCardLookup() {
|
||||
return LOOKUP;
|
||||
}
|
||||
};
|
||||
StringBuilder errors = new StringBuilder();
|
||||
DeckCardLists deck = importer.importDeck(
|
||||
"src/test/java/mage/cards/decks/importer/testdeck.cod", errors);
|
||||
assertEquals("Deck Name", deck.getName());
|
||||
|
||||
TestDeckChecker.checker()
|
||||
.addMain("Forest", 12)
|
||||
.addMain("Razorverge Thicket", 100)
|
||||
.addMain("Avacyn's Pilgrim", 1)
|
||||
.addSide("War Priest of Thune", 3)
|
||||
.verify(deck, 113, 3);
|
||||
|
||||
assertEquals("Could not find card: '@#$NOT A REAL CARD NAME@#$'\n", errors.toString());
|
||||
}
|
||||
|
||||
private static void assertCardSame(String name, DeckCardInfo card) {
|
||||
assertEquals(name, card.getCardName());
|
||||
assertEquals(1, card.getQuantity());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package mage.cards.decks.importer;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import mage.cards.decks.DeckCardInfo;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.repository.CardInfo;
|
||||
|
||||
public class DecDeckImportTest {
|
||||
|
||||
private static final FakeCardLookup LOOKUP = new FakeCardLookup()
|
||||
.addCard("Masticore")
|
||||
.addCard("Metalworker")
|
||||
.addCard("Phyrexian Colossus")
|
||||
.addCard("Crumbling Sanctuary")
|
||||
.addCard("Grim Monolith")
|
||||
.addCard("Mishra's Helix")
|
||||
.addCard("Phyrexian Processor")
|
||||
.addCard("Tangle Wire")
|
||||
.addCard("Thran Dynamo")
|
||||
.addCard("Voltaic Key")
|
||||
.addCard("Tinker")
|
||||
.addCard("Brainstorm")
|
||||
.addCard("Crystal Vein")
|
||||
.addCard("Island")
|
||||
.addCard("Rishadan Port")
|
||||
.addCard("Saprazzan Skerry")
|
||||
.addCard("Annul")
|
||||
.addCard("Chill")
|
||||
.addCard("Miscalculation")
|
||||
.addCard("Mishra's Helix")
|
||||
.addCard("Rising Waters");
|
||||
|
||||
@Test
|
||||
public void testImport() {
|
||||
StringBuilder errors = new StringBuilder();
|
||||
DecDeckImporter importer = new DecDeckImporter() {
|
||||
@Override
|
||||
public CardLookup getCardLookup() {
|
||||
return LOOKUP;
|
||||
}
|
||||
};
|
||||
DeckCardLists deck = importer.importDeck(
|
||||
"src/test/java/mage/cards/decks/importer/testdeck.dec", errors);
|
||||
|
||||
TestDeckChecker.checker()
|
||||
.addMain("Masticore", 4)
|
||||
.addMain("Metalworker", 4)
|
||||
.addMain("Phyrexian Colossus", 1)
|
||||
.addMain("Crumbling Sanctuary", 1)
|
||||
.addMain("Grim Monolith", 4)
|
||||
.addMain("Mishra's Helix", 1)
|
||||
.addMain("Phyrexian Processor", 4)
|
||||
.addMain("Tangle Wire", 4)
|
||||
.addMain("Thran Dynamo", 4)
|
||||
.addMain("Voltaic Key", 4)
|
||||
.addMain("Tinker", 4)
|
||||
.addMain("Brainstorm", 4)
|
||||
.addMain("Crystal Vein", 4)
|
||||
.addMain("Island", 9)
|
||||
.addMain("Rishadan Port", 4)
|
||||
.addMain("Saprazzan Skerry", 4)
|
||||
.addSide("Annul", 4)
|
||||
.addSide("Chill", 4)
|
||||
.addSide("Miscalculation", 4)
|
||||
.addSide("Mishra's Helix", 1)
|
||||
.addSide("Rising Waters", 2)
|
||||
.verify(deck, 60, 15);
|
||||
|
||||
assertEquals("", errors.toString());
|
||||
}
|
||||
|
||||
private static FakeCardLookup getFakeCardLookup() {
|
||||
FakeCardLookup lookup = new FakeCardLookup() {
|
||||
@Override
|
||||
public Optional<CardInfo> lookupCardInfo(String name) {
|
||||
System.out.println(name);
|
||||
return super.lookupCardInfo(name);
|
||||
}
|
||||
};
|
||||
return lookup;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package mage.cards.decks.importer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import mage.cards.repository.CardInfo;
|
||||
|
||||
public class FakeCardLookup extends CardLookup {
|
||||
|
||||
private final Map<String, CardInfo> lookup = new HashMap<>();
|
||||
|
||||
public FakeCardLookup addCard(String cardName) {
|
||||
lookup.put(cardName, new CardInfo() {{
|
||||
name = cardName;
|
||||
}});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CardInfo> lookupCardInfo(String name) {
|
||||
CardInfo card = lookup.get(name);
|
||||
if (card == null) {
|
||||
System.out.println("Couldn't find: " + name);
|
||||
}
|
||||
return Optional.ofNullable(card);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package mage.cards.decks.importer;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
|
||||
public class TestDeckChecker {
|
||||
|
||||
private final List<String> main = new ArrayList<>();
|
||||
private final List<String> side = new ArrayList<>();
|
||||
|
||||
public TestDeckChecker addMain(String name) {
|
||||
return addMain(name, 1);
|
||||
}
|
||||
|
||||
public TestDeckChecker addMain(String name, int quantity) {
|
||||
main.addAll(Collections.nCopies(quantity, name));
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestDeckChecker addSide(String name) {
|
||||
return addSide(name, 1);
|
||||
}
|
||||
|
||||
public TestDeckChecker addSide(String name, int quantity) {
|
||||
side.addAll(Collections.nCopies(quantity, name));
|
||||
return this;
|
||||
}
|
||||
|
||||
public void verify(DeckCardLists deck, int nMain, int nSide) {
|
||||
assertEquals(nMain, main.size());
|
||||
assertEquals(nSide, side.size());
|
||||
assertEquals(nMain, deck.getCards().size());
|
||||
assertEquals(nSide, deck.getSideboard().size());
|
||||
|
||||
for (int i = 0; i < main.size(); i++) {
|
||||
String expected = main.get(i);
|
||||
String actual = deck.getCards().get(i).getCardName();
|
||||
assertEquals(String.format("Expected: '%s' Actual: '%s' at index: %s",
|
||||
expected, actual, i), expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
public static TestDeckChecker checker() {
|
||||
return new TestDeckChecker();
|
||||
}
|
||||
|
||||
}
|
14
Mage/src/test/java/mage/cards/decks/importer/testdeck.cod
Normal file
14
Mage/src/test/java/mage/cards/decks/importer/testdeck.cod
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<cockatrice_deck version="1">
|
||||
<deckname>Deck Name </deckname>
|
||||
<comments>Some comments in here.</comments>
|
||||
<zone name="main">
|
||||
<card number="12" name="Forest"/>
|
||||
<card number="101" price="0" name="Razorverge Thicket"/>
|
||||
<card price="0" name="Avacyn's Pilgrim"/>
|
||||
<card number="1" price="0" name="@#$NOT A REAL CARD NAME@#$"/>
|
||||
</zone>
|
||||
<zone name="side">
|
||||
<card number="3" price="0" name="War Priest of Thune"/>
|
||||
</zone>
|
||||
</cockatrice_deck>
|
28
Mage/src/test/java/mage/cards/decks/importer/testdeck.dec
Normal file
28
Mage/src/test/java/mage/cards/decks/importer/testdeck.dec
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Name: Mono-Blue Tinker from MTGSalvation.com via mtgtrice mtg-decks
|
||||
// Creatures
|
||||
4 Masticore
|
||||
4 Metalworker
|
||||
1 Phyrexian Colossus
|
||||
// Artifacts
|
||||
1 Crumbling Sanctuary
|
||||
4 Grim Monolith
|
||||
1 Mishra's Helix
|
||||
4 Phyrexian Processor
|
||||
4 Tangle Wire
|
||||
4 Thran Dynamo
|
||||
4 Voltaic Key
|
||||
// Sorceries
|
||||
4 Tinker
|
||||
// Instants
|
||||
4 Brainstorm
|
||||
// Lands
|
||||
4 Crystal Vein
|
||||
9 Island
|
||||
4 Rishadan Port
|
||||
4 Saprazzan Skerry
|
||||
// Sideboard
|
||||
SB: 4 Annul
|
||||
SB: 4 Chill
|
||||
SB: 4 Miscalculation
|
||||
SB: 1 Mishra's Helix
|
||||
SB: 2 Rising Waters
|
Loading…
Reference in a new issue