forked from External/mage
GUI, deck: improved bracket level calculations (added all infinite combos list and spellbook downloader, part of #13341)
This commit is contained in:
parent
1fb4cecd6b
commit
d465c9fb82
9 changed files with 2148 additions and 9 deletions
|
|
@ -27,9 +27,11 @@ import java.util.stream.Stream;
|
||||||
* Features:
|
* Features:
|
||||||
* - [x] find possible bracket level of the deck
|
* - [x] find possible bracket level of the deck
|
||||||
* - [x] find affected cards by checking group
|
* - [x] find affected cards by checking group
|
||||||
* - [ ] TODO: data download and generate
|
* - [x] can auto-generate infinite combos list, see verify test downloadAndPrepareCommanderBracketsData
|
||||||
* - [ ] TODO: tests
|
* - [ ] TODO: tests
|
||||||
* - [ ] TODO: table - players brackets level disclose settings
|
* - [ ] TODO: table - players brackets level disclose settings
|
||||||
|
* - [ ] TODO: deck - improve gui to show more levels
|
||||||
|
* - [ ] TODO: generate - convert card name to xmage format and assert on bad names (ascii only)
|
||||||
*
|
*
|
||||||
* @author JayDi85
|
* @author JayDi85
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -291,16 +291,25 @@ public class XmageURLConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String downloadText(String resourceUrl) {
|
||||||
|
return downloadText(resourceUrl, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fast download of text data
|
* Fast download of text data
|
||||||
*
|
*
|
||||||
|
* @param additionalHeaders set extra headers like application/json
|
||||||
|
*
|
||||||
* @return downloaded text on OK 200 response or empty on any other errors
|
* @return downloaded text on OK 200 response or empty on any other errors
|
||||||
*/
|
*/
|
||||||
public static String downloadText(String resourceUrl) {
|
public static String downloadText(String resourceUrl, Map<String, String> additionalHeaders) {
|
||||||
XmageURLConnection con = new XmageURLConnection(resourceUrl);
|
XmageURLConnection con = new XmageURLConnection(resourceUrl);
|
||||||
con.startConnection();
|
con.startConnection();
|
||||||
if (con.isConnected()) {
|
if (con.isConnected()) {
|
||||||
try {
|
try {
|
||||||
|
if (additionalHeaders != null) {
|
||||||
|
con.setRequestHeaders(additionalHeaders);
|
||||||
|
}
|
||||||
con.connect();
|
con.connect();
|
||||||
if (con.getResponseCode() == 200) {
|
if (con.getResponseCode() == 200) {
|
||||||
return con.getGoodResponseAsString();
|
return con.getGoodResponseAsString();
|
||||||
|
|
|
||||||
|
|
@ -853,7 +853,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
|
||||||
connection.startConnection();
|
connection.startConnection();
|
||||||
if (connection.isConnected()) {
|
if (connection.isConnected()) {
|
||||||
|
|
||||||
// custom headers (ues
|
// custom headers
|
||||||
connection.setRequestHeaders(selectedSource.getHttpRequestHeaders(currentUrl));
|
connection.setRequestHeaders(selectedSource.getHttpRequestHeaders(currentUrl));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package mage.verify.mtgjson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commanders Spellbook api: card class
|
||||||
|
* <p>
|
||||||
|
* API docs <a href="https://backend.commanderspellbook.com/variants">here</a>
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public final class SpellBookCard {
|
||||||
|
public int id;
|
||||||
|
public String name;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package mage.verify.mtgjson;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commanders Spellbook api: page class
|
||||||
|
* <p>
|
||||||
|
* API docs <a href="https://backend.commanderspellbook.com/variants">here</a>
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public final class SpellBookCardsPage {
|
||||||
|
public int count;
|
||||||
|
public String next; // can be null on last page
|
||||||
|
public String previous;
|
||||||
|
public List<SpellBookCombo> results; // empty on too big page
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package mage.verify.mtgjson;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commanders Spellbook api: full combo
|
||||||
|
* <p>
|
||||||
|
* API docs <a href="https://backend.commanderspellbook.com/variants">here</a>
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public final class SpellBookCombo {
|
||||||
|
public String id; // combo id
|
||||||
|
public List<SpellBookComboPart> uses; // combo parts
|
||||||
|
public String bracketTag; // can be useful
|
||||||
|
public String description;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package mage.verify.mtgjson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commanders Spellbook api: combo part (one card info)
|
||||||
|
* <p>
|
||||||
|
* API docs <a href="https://backend.commanderspellbook.com/variants">here</a>
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public final class SpellBookComboPart {
|
||||||
|
public SpellBookCard card;
|
||||||
|
public int quantity;
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package mage.verify;
|
package mage.verify;
|
||||||
|
|
||||||
import com.google.common.base.CharMatcher;
|
import com.google.common.base.CharMatcher;
|
||||||
|
import com.google.gson.Gson;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
|
|
@ -30,6 +31,7 @@ import mage.cards.decks.DeckCardLists;
|
||||||
import mage.cards.decks.importer.DeckImporter;
|
import mage.cards.decks.importer.DeckImporter;
|
||||||
import mage.cards.repository.*;
|
import mage.cards.repository.*;
|
||||||
import mage.choices.Choice;
|
import mage.choices.Choice;
|
||||||
|
import mage.client.remote.XmageURLConnection;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.filter.Filter;
|
import mage.filter.Filter;
|
||||||
import mage.filter.predicate.Predicate;
|
import mage.filter.predicate.Predicate;
|
||||||
|
|
@ -51,7 +53,9 @@ import mage.utils.SystemUtil;
|
||||||
import mage.verify.mtgjson.MtgJsonCard;
|
import mage.verify.mtgjson.MtgJsonCard;
|
||||||
import mage.verify.mtgjson.MtgJsonService;
|
import mage.verify.mtgjson.MtgJsonService;
|
||||||
import mage.verify.mtgjson.MtgJsonSet;
|
import mage.verify.mtgjson.MtgJsonSet;
|
||||||
|
import mage.verify.mtgjson.SpellBookCardsPage;
|
||||||
import mage.watchers.Watcher;
|
import mage.watchers.Watcher;
|
||||||
|
import net.java.truevfs.access.TFile;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
@ -59,10 +63,14 @@ import org.junit.Test;
|
||||||
import org.mage.plugins.card.dl.sources.ScryfallImageSupportCards;
|
import org.mage.plugins.card.dl.sources.ScryfallImageSupportCards;
|
||||||
import org.reflections.Reflections;
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
@ -3255,4 +3263,79 @@ public class VerifyCardDataTest {
|
||||||
+ "%29&order=set&as=grid&unique=cards"
|
+ "%29&order=set&as=grid&unique=cards"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Helper test to download infinite combos data and prepare it to use in Commander Brackets score system
|
||||||
|
* <p>
|
||||||
|
* How-to use: run it before each main release and upload updated files to github
|
||||||
|
*/
|
||||||
|
@Ignore
|
||||||
|
@Test
|
||||||
|
public void downloadAndPrepareCommanderBracketsData() {
|
||||||
|
// download data
|
||||||
|
// load data by pages, max limit = 100, no needs to setup it, ~2000 combos or 20 pages
|
||||||
|
String nextUrl = "https://backend.commanderspellbook.com/variants?format=json&group_by_combo=true&ordering=created&q=cards%3D2+result%3Ainfinite";
|
||||||
|
SpellBookCardsPage page;
|
||||||
|
int pageNumber = 0;
|
||||||
|
List<String> allCombos = new ArrayList<>();
|
||||||
|
while (nextUrl != null && !nextUrl.isEmpty()) {
|
||||||
|
pageNumber++;
|
||||||
|
System.out.println("downloading page " + pageNumber);
|
||||||
|
String res = XmageURLConnection.downloadText(nextUrl);
|
||||||
|
page = new Gson().fromJson(res, SpellBookCardsPage.class);
|
||||||
|
if (page == null || page.results == null) {
|
||||||
|
System.out.println("ERROR, unknown data format: " + res.substring(0, 10) + "...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
page.results.forEach(combo -> {
|
||||||
|
if (combo.uses.isEmpty()) {
|
||||||
|
System.out.println("wrong combo uses: " + combo.uses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Stella Lee, Wild Card - can generate infinite combo by itself, so allow 1 card
|
||||||
|
String card1 = combo.uses.get(0).card.name;
|
||||||
|
String card2 = combo.uses.size() == 1 ? card1 : combo.uses.get(1).card.name;
|
||||||
|
if (card1 != null && card2 != null) {
|
||||||
|
allCombos.add(String.format("%s@%s", card1, card2));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
nextUrl = page.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save results (run from Mage.Verify)
|
||||||
|
File destFile = new TFile("..\\Mage\\src\\main\\resources\\brackets\\infinite-combos.txt");
|
||||||
|
if (!destFile.exists()) {
|
||||||
|
System.out.println("Can't find dest file " + destFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> infiniteCombosRes;
|
||||||
|
try {
|
||||||
|
infiniteCombosRes = Files.readAllLines(destFile.toPath(), StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("Can't read file " + destFile + " " + e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace all cards data, but keep comments
|
||||||
|
infiniteCombosRes.removeIf(s -> !s.startsWith("#")
|
||||||
|
|| s.startsWith("# Source")
|
||||||
|
|| s.startsWith("# Updated")
|
||||||
|
|| s.startsWith("# Found")
|
||||||
|
);
|
||||||
|
infiniteCombosRes.add(String.format("# Source: %s", "https://commanderspellbook.com"));
|
||||||
|
infiniteCombosRes.add(String.format("# Updated: %s", LocalDate.now().format(DateTimeFormatter.ISO_DATE)));
|
||||||
|
infiniteCombosRes.add(String.format("# Found: %d", allCombos.size()));
|
||||||
|
infiniteCombosRes.addAll(allCombos); // do not sort, all new combos will be added to the end due spell book default order
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.write(destFile.toPath(), infiniteCombosRes, StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("Can't write file " + destFile + " " + e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(String.format("ALL DONE, found and write %d combos", allCombos.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue