GUI: added more error checks while import/load deck file;

This commit is contained in:
Oleg Agafonov 2020-08-08 23:12:06 +04:00
parent c5d7a3e9f9
commit ad6797d3c0
4 changed files with 58 additions and 23 deletions

View file

@ -71,6 +71,7 @@ public class VerifyCardDataTest {
private static final String SKIP_LIST_DOUBLE_RARE = "DOUBLE_RARE"; private static final String SKIP_LIST_DOUBLE_RARE = "DOUBLE_RARE";
private static final String SKIP_LIST_UNSUPPORTED_SETS = "UNSUPPORTED_SETS"; private static final String SKIP_LIST_UNSUPPORTED_SETS = "UNSUPPORTED_SETS";
private static final String SKIP_LIST_SCRYFALL_DOWNLOAD_SETS = "SCRYFALL_DOWNLOAD_SETS"; private static final String SKIP_LIST_SCRYFALL_DOWNLOAD_SETS = "SCRYFALL_DOWNLOAD_SETS";
private static final String SKIP_LIST_SAMPLE_DECKS = "SAMPLE_DECKS";
private static final Pattern SHORT_JAVA_STRING = Pattern.compile("(?<=\")[A-Z][a-z]+(?=\")"); private static final Pattern SHORT_JAVA_STRING = Pattern.compile("(?<=\")[A-Z][a-z]+(?=\")");
static { static {
@ -190,6 +191,10 @@ public class VerifyCardDataTest {
// scryfall download sets (missing from scryfall website) // scryfall download sets (missing from scryfall website)
skipListCreate(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS); skipListCreate(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS);
skipListAddName(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS, "SWS"); // Star Wars skipListAddName(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS, "SWS"); // Star Wars
// sample decks checking - some decks can contains unimplemented cards, so ignore it
skipListCreate(SKIP_LIST_SAMPLE_DECKS);
skipListAddName(SKIP_LIST_SAMPLE_DECKS, "\\Commander\\Commander 2019\\Merciless Rage.dck"); // TODO: delete after Aeon Engine implemented
} }
private final ArrayList<String> outputMessages = new ArrayList<>(); private final ArrayList<String> outputMessages = new ArrayList<>();
@ -472,7 +477,6 @@ public class VerifyCardDataTest {
} }
@Test @Test
//@Ignore // TODO: enable and fix broken decks after promo sets merge https://github.com/magefree/mage/pull/6190
public void test_checkSampleDecks() { public void test_checkSampleDecks() {
Collection<String> errorsList = new ArrayList<>(); Collection<String> errorsList = new ArrayList<>();
@ -496,7 +500,11 @@ public class VerifyCardDataTest {
// try to open deck files // try to open deck files
int totalErrorFiles = 0; int totalErrorFiles = 0;
for (Path deckFile : filesList) { for (Path deckFile : filesList) {
String deckName = deckFile.toString().replace(rootPath, ""); String deckName = "\\" + deckFile.toString().replace(rootPath, "");
if (skipListHaveName(SKIP_LIST_SAMPLE_DECKS, deckName)) {
continue;
}
StringBuilder deckErrors = new StringBuilder(); StringBuilder deckErrors = new StringBuilder();
DeckCardLists deckCards = DeckImporter.importDeckFromFile(deckFile.toString(), deckErrors, AUTO_FIX_SAMPLE_DECKS); DeckCardLists deckCards = DeckImporter.importDeckFromFile(deckFile.toString(), deckErrors, AUTO_FIX_SAMPLE_DECKS);
@ -508,7 +516,7 @@ public class VerifyCardDataTest {
} }
if ((deckCards.getCards().size() + deckCards.getSideboard().size()) < 10) { if ((deckCards.getCards().size() + deckCards.getSideboard().size()) < 10) {
errorsList.add("Error: sample deck contains too little cards " + deckName); errorsList.add("Error: sample deck contains too little cards (" + deckCards.getSideboard().size() + ") " + deckName);
totalErrorFiles++; totalErrorFiles++;
continue; continue;
} }

View file

@ -7,7 +7,7 @@ import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository; import mage.cards.repository.CardRepository;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -28,7 +28,9 @@ public class DckDeckImporter extends PlainTextDeckImporter {
private static final Pattern layoutStackEntryPattern = Pattern.compile("\\[(\\w+[^:]*\\w*):(\\w+\\w*)]"); // test cases: [JR:64ab],[JR:64],[MPSAK1321:43],[MPSAKH:9],[MPS123-AKH:32],[MPS-13AKH:30],[MPS-AKH:49],[MPS-AKH:11], [PUMA:U16] private static final Pattern layoutStackEntryPattern = Pattern.compile("\\[(\\w+[^:]*\\w*):(\\w+\\w*)]"); // test cases: [JR:64ab],[JR:64],[MPSAK1321:43],[MPSAKH:9],[MPS123-AKH:32],[MPS-13AKH:30],[MPS-AKH:49],[MPS-AKH:11], [PUMA:U16]
private final Map<String, String> possibleFixes = new HashMap<>(); // possible fixes for card codes and numbers [code:123] -> [code:456] // possible fixes for card numbers: [code:123] -> [code:456]
// possible fixes for card numbers with name: [code:123] card1 -> [code:456] card2
private final Map<String, String> possibleFixes = new LinkedHashMap<>();
@Override @Override
protected void readLine(String line, DeckCardLists deckList, FixedInfo fixedInfo) { protected void readLine(String line, DeckCardLists deckList, FixedInfo fixedInfo) {
@ -60,13 +62,14 @@ public class DckDeckImporter extends PlainTextDeckImporter {
setCode = setCode == null ? "" : setCode.trim(); setCode = setCode == null ? "" : setCode.trim();
cardName = cardName == null ? "" : cardName.trim(); cardName = cardName == null ? "" : cardName.trim();
// text for auto-fix // text for auto-fix (don't work on extra spaces between numbers and name -- it's ok)
String originalText = ""; String originalNumbers = "";
String originalNumbersWithName = "";
if (!setCode.isEmpty() && !cardNum.isEmpty()) { if (!setCode.isEmpty() && !cardNum.isEmpty()) {
// [ISD:144] // [ISD:144] card_name
originalText = "[" + setCode + ":" + cardNum + "]"; originalNumbers = "[" + setCode + ":" + cardNum + "]";
originalNumbersWithName = originalNumbers + " " + cardName;
} }
String fixedText = originalText;
// search priority: set/number -> name // search priority: set/number -> name
// with bulletproof on card number or name changes // with bulletproof on card number or name changes
@ -74,7 +77,7 @@ public class DckDeckImporter extends PlainTextDeckImporter {
DeckCardInfo deckCardInfo = null; DeckCardInfo deckCardInfo = null;
// search by set/number // search by set/number
CardInfo foundedCard = CardRepository.instance.findCard(setCode, cardNum); CardInfo foundedCard = CardRepository.instance.findCard(setCode, cardNum, true);
boolean wasOutdated = false; boolean wasOutdated = false;
if ((foundedCard != null) && !foundedCard.getName().equals(cardName)) { if ((foundedCard != null) && !foundedCard.getName().equals(cardName)) {
sbMessage.append("Line ").append(lineCount).append(": ").append("found outdated card number or name, will try to replace: ").append(line).append('\n'); sbMessage.append("Line ").append(lineCount).append(": ").append("found outdated card number or name, will try to replace: ").append(line).append('\n');
@ -93,15 +96,24 @@ public class DckDeckImporter extends PlainTextDeckImporter {
} }
if (foundedCard != null) { if (foundedCard != null) {
if (foundedCard.isNightCard()) {
sbMessage.append("Line ").append(lineCount).append(": ").append("ERROR, you can't use night card in deck [").append(foundedCard.getName()).append("]").append('\n');
} else {
sbMessage.append("Line ").append(lineCount).append(": ") sbMessage.append("Line ").append(lineCount).append(": ")
.append("replaced to [").append(foundedCard.getSetCode()).append(":").append(foundedCard.getCardNumberAsInt()).append("] ") .append("replaced to [").append(foundedCard.getSetCode()).append(":").append(foundedCard.getCardNumberAsInt()).append("] ")
.append(foundedCard.getName()).append('\n'); .append(foundedCard.getName()).append('\n');
// AUTO-FIX POSSIBLE (apply and save it for another lines like layout) // AUTO-FIX POSSIBLE (apply and save it for another lines like layout)
// [ISD:144] // [ISD:144] card
fixedText = "[" + foundedCard.getSetCode() + ":" + foundedCard.getCardNumber() + "]"; String fixNumbers = "[" + foundedCard.getSetCode() + ":" + foundedCard.getCardNumber() + "]";
fixedInfo.setFixedLine(fixedInfo.getOriginalLine().replace(originalText, fixedText)); String fixNumbersWithName = fixNumbers + " " + foundedCard.getName();
this.possibleFixes.put(originalText, fixedText); this.possibleFixes.put(originalNumbersWithName, fixNumbersWithName); // name fix must goes first
this.possibleFixes.put(originalNumbers, fixNumbers);
String fixedLine = fixedInfo.getOriginalLine()
.replace(originalNumbersWithName, fixNumbersWithName)
.replace(originalNumbers, fixNumbers);
fixedInfo.setFixedLine(fixedLine);
}
} else { } else {
sbMessage.append("Line ").append(lineCount).append(": ").append("ERROR, can't find card [").append(cardName).append("]").append('\n'); sbMessage.append("Line ").append(lineCount).append(": ").append("ERROR, can't find card [").append(cardName).append("]").append('\n');
} }

View file

@ -58,6 +58,10 @@ public abstract class PlainTextDeckImporter extends DeckImporter {
saveFixedDeckFile(fixedFile, f); saveFixedDeckFile(fixedFile, f);
} }
if (deckList.getCards().isEmpty() && deckList.getSideboard().isEmpty()) {
sbMessage.append("ERROR, unknown deck format, can't find any cards").append("\n");
}
if (sbMessage.length() > 0) { if (sbMessage.length() > 0) {
if (errorMessages != null) { if (errorMessages != null) {
// normal output for user // normal output for user

View file

@ -39,7 +39,7 @@ public enum CardRepository {
private static final long CARD_CONTENT_VERSION = 231; private static final long CARD_CONTENT_VERSION = 231;
private Dao<CardInfo, Object> cardDao; private Dao<CardInfo, Object> cardDao;
private Set<String> classNames; private Set<String> classNames;
private RepositoryEventSource eventSource = new RepositoryEventSource(); private final RepositoryEventSource eventSource = new RepositoryEventSource();
CardRepository() { CardRepository() {
File file = new File("db"); File file = new File("db");
@ -335,11 +335,22 @@ public enum CardRepository {
} }
public CardInfo findCard(String setCode, String cardNumber) { public CardInfo findCard(String setCode, String cardNumber) {
return findCard(setCode, cardNumber, true);
}
public CardInfo findCard(String setCode, String cardNumber, boolean ignoreNightCards) {
try { try {
QueryBuilder<CardInfo, Object> queryBuilder = cardDao.queryBuilder(); QueryBuilder<CardInfo, Object> queryBuilder = cardDao.queryBuilder();
queryBuilder.limit(1L).where().eq("setCode", new SelectArg(setCode)) if (ignoreNightCards) {
queryBuilder.limit(1L).where()
.eq("setCode", new SelectArg(setCode))
.and().eq("cardNumber", new SelectArg(cardNumber)) .and().eq("cardNumber", new SelectArg(cardNumber))
.and().eq("nightCard", new SelectArg(false)); .and().eq("nightCard", new SelectArg(false));
} else {
queryBuilder.limit(1L).where()
.eq("setCode", new SelectArg(setCode))
.and().eq("cardNumber", new SelectArg(cardNumber));
}
List<CardInfo> result = cardDao.query(queryBuilder.prepare()); List<CardInfo> result = cardDao.query(queryBuilder.prepare());
if (!result.isEmpty()) { if (!result.isEmpty()) {
return result.get(0); return result.get(0);