Merge branch 'master' into feature/implement-spdr-piloted-by-peni

This commit is contained in:
theelk801 2025-09-05 18:15:31 -04:00
commit 04bc7b8b2a
1185 changed files with 32207 additions and 8890 deletions

View file

@ -18,10 +18,8 @@ import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.*;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
@ -258,7 +256,7 @@ public class CardArea extends JPanel implements CardEventProducer {
this.reloaded = false;
}
public void selectCards(List<UUID> selected) {
public void selectCards(Set<UUID> selected) {
for (Component component : cardArea.getComponents()) {
if (component instanceof MageCard) {
MageCard mageCard = (MageCard) component;
@ -269,7 +267,7 @@ public class CardArea extends JPanel implements CardEventProducer {
}
}
public void markCards(List<UUID> marked) {
public void markCards(Set<UUID> marked) {
for (Component component : cardArea.getComponents()) {
if (component instanceof MageCard) {
MageCard mageCard = (MageCard) component;

View file

@ -1,5 +1,6 @@
package mage.client.deckeditor;
import mage.cards.decks.importer.MtgaImporter;
import mage.client.MageFrame;
import mage.client.dialog.MageDialog;
import mage.util.DeckUtil;
@ -20,11 +21,18 @@ import java.util.Optional;
public class DeckImportClipboardDialog extends MageDialog {
private static final String FORMAT_TEXT =
"// Example:\n" +
"//1 Library of Congress\n" +
"//1 Cryptic Gateway\n" +
"//1 Azami, Lady of Scrolls\n" +
"// NB: This is slow as, and will lock your screen :)\n" +
"// MTGO format example:\n" +
"// 1 Library of Congress\n" +
"// 3 Cryptic Gateway\n" +
"//\n" +
"// MTGA, moxfield, archidekt format example:\n" +
"// Deck\n" +
"// 4 Accumulated Knowledge (A25) 40\n" +
"// 2 Adarkar Wastes (EOC) 147\n" +
"// Commander\n" +
"// 1 Grizzly Bears\n" +
"//\n" +
"// Importing deck can take some time to finish\n" +
"\n" +
"// Your current clipboard:\n" +
"\n";
@ -68,17 +76,19 @@ public class DeckImportClipboardDialog extends MageDialog {
}
private void onOK() {
String decklist = editData.getText();
decklist = decklist.replace(FORMAT_TEXT, "");
String importData = editData.getText();
importData = importData.replace(FORMAT_TEXT, "").trim();
// find possible data format
String tempDeckPath;
// This dialog also accepts a paste in .mtga format
if (decklist.startsWith("Deck\n")) { // An .mtga list always starts with the first line being "Deck". This kind of paste is processed as .mtga
tempDeckPath = DeckUtil.writeTextToTempFile("cbimportdeck", ".mtga", decklist);
if (MtgaImporter.isMTGA(importData)) {
// MTGA or Moxfield
tempDeckPath = DeckUtil.writeTextToTempFile("cbimportdeck", ".mtga", importData);
} else {
// If the paste is not .mtga format, it's processed as plaintext
tempDeckPath = DeckUtil.writeTextToTempFile(decklist);
// text
tempDeckPath = DeckUtil.writeTextToTempFile(importData);
}
if (this.callback != null) {
callback.onImportDone(tempDeckPath);
}

View file

@ -100,11 +100,11 @@
cardArea.loadCards(showCards, bigCard, gameId);
if (options != null) {
if (options.containsKey("chosenTargets")) {
java.util.List<UUID> chosenCards = (java.util.List<UUID>) options.get("chosenTargets");
java.util.Set<UUID> chosenCards = (java.util.Set<UUID>) options.get("chosenTargets");
cardArea.selectCards(chosenCards);
}
if (options.containsKey("possibleTargets")) {
java.util.List<UUID> choosableCards = (java.util.List<UUID>) options.get("possibleTargets");
java.util.Set<UUID> choosableCards = (java.util.Set<UUID>) options.get("possibleTargets");
cardArea.markCards(choosableCards);
}
if (options.containsKey("queryType") && options.get("queryType") == QueryType.PICK_ABILITY) {

View file

@ -216,17 +216,9 @@ public final class GamePanel extends javax.swing.JPanel {
});
}
public List<UUID> getPossibleTargets() {
if (options != null && options.containsKey("possibleTargets")) {
return (List<UUID>) options.get("possibleTargets");
} else {
return Collections.emptyList();
}
}
public Set<UUID> getChosenTargets() {
if (options != null && options.containsKey("chosenTargets")) {
return new HashSet<>((List<UUID>) options.get("chosenTargets"));
return (Set<UUID>) options.get("chosenTargets");
} else {
return Collections.emptySet();
}

View file

@ -10,10 +10,7 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
@ -93,7 +90,9 @@ public class XmageURLConnection {
initDefaultProxy();
try {
URL url = new URL(this.url);
// convert utf8 url to ascii format (e.g. url encode)
URI uri = new URI(this.url);
URL url = new URL(uri.toASCIIString());
// proxy settings
if (this.proxy != null) {
@ -107,7 +106,7 @@ public class XmageURLConnection {
this.connection.setReadTimeout(CONNECTION_READING_TIMEOUT_MS);
initDefaultHeaders();
} catch (IOException e) {
} catch (IOException | URISyntaxException e) {
this.connection = null;
}
}

View file

@ -107,7 +107,7 @@ public class GathererSets implements Iterable<DownloadJob> {
"JMP", "2XM", "ZNR", "KLR", "CMR", "KHC", "KHM", "TSR", "STX", "STA",
"C21", "MH2", "AFR", "AFC", "J21", "MID", "MIC", "VOW", "VOC", "YMID",
"NEC", "YNEO", "NEO", "SNC", "NCC", "CLB", "2X2", "DMU", "DMC", "40K", "GN3",
"UNF", "BRO", "BRC", "BOT", "J22", "DMR", "ONE", "ONC",
"UNF", "BRO", "BRC", "BOT", "J22", "DMR", "ONE", "ONC", "SCH",
"MOM", "MOC", "MUL", "MAT", "LTR", "CMM", "WOE", "WHO", "RVR", "WOT",
"WOC", "SPG", "LCI", "LCC", "REX", "PIP", "MKM", "MKC", "CLU", "OTJ",
"OTC", "OTP", "BIG", "MH3", "M3C", "ACR", "BLB", "BLC", "DSK", "DSC",

View file

@ -28,6 +28,8 @@ public class ScryfallImageSupportCards {
add("2ED"); // Unlimited Edition
//add("CEI"); // Intl. Collectors Edition
//add("CED"); // Collectors Edition
add("RIN"); // Rinascimento
add("REN"); // Renaissance
add("ARN"); // Arabian Nights
add("ATQ"); // Antiquities
//add("FBB"); // Foreign Black Border
@ -465,6 +467,7 @@ public class ScryfallImageSupportCards {
// add("MD1"); // Modern Event Deck
// add("DD3"); // Duel Decks Anthology
// add("PZ1"); // Legendary Cube
add("PLG20"); // Love Your LGS 2020
add("IKO"); // Ikoria: Lair of Behemoths
add("C20"); // Commander 2020
add("M21"); // Core Set 2021
@ -514,10 +517,13 @@ public class ScryfallImageSupportCards {
add("NCC"); // New Capenna Commander
add("SLX"); // Universes Within
add("CLB"); // Commander Legends: Battle for Baldur's Gate
add("PLG22"); // Love Your LGS 2022
add("2X2"); // Double Masters 2022
add("SCH"); // Store Championships
add("DMU"); // Dominaria United
add("DMC"); // Dominaria United Commander
add("YDMU"); // Alchemy: Dominaria
add("PRCQ"); // Regional Championship Qualifiers 2022
add("40K"); // Warhammer 40,000 Commander
add("UNF"); // Unfinity
add("GN3"); // Game Night: Free-for-All
@ -545,9 +551,11 @@ public class ScryfallImageSupportCards {
add("30A"); // 30th Anniversary Edition
add("P30A"); // 30th Anniversary Play Promos
add("P30M"); // 30th Anniversary Misc Promos
add("P30H"); // 30th Anniversary History Promos
add("PEWK"); // Eternal Weekend
add("LTR"); // The Lord of the Rings: Tales of Middle-Earth
add("LTC"); // Tales of Middle-Earth Commander
add("PF23"); // MagicFest 2023
add("CMM"); // Commander Masters
add("WHO"); // Doctor Who
add("WOE"); // Wilds of Eldraine
@ -558,10 +566,13 @@ public class ScryfallImageSupportCards {
add("REX"); // Jurassic World Collection
add("SPG"); // Special Guests
add("PW24"); // Wizards Play Network 2024
add("PF24"); // MagicFest 2024
add("RVR"); // Ravnica Remastered
add("PL24"); // Year of the Dragon 2024
add("PIP"); // Fallout
add("MKM"); // Murders at Karlov Manor
add("MKC"); // Murders at Karlov Manor Commander
add("PSS4"); // MKM Standard Showdown
add("CLU"); // Ravnica: Clue Edition
add("OTJ"); // Outlaws of Thunder Junction
add("OTC"); // Outlaws of Thunder Junction Commander
@ -569,9 +580,12 @@ public class ScryfallImageSupportCards {
add("BIG"); // The Big Score
add("MH3"); // Modern Horizons 3
add("M3C"); // Modern Horizons 3 Commander
add("H2R"); // Modern Horizons 2 Timeshifts
add("ACR"); // Assassin's Creed
add("BLB"); // Bloomburrow
add("BLC"); // Bloomburrow Commander
add("PLG24"); // Love Your LGS 2024
add("PCBB"); // Cowboy Bebop
add("MB2"); // Mystery Booster 2
add("DSK"); // Duskmourn: House of Horror
add("DSC"); // Duskmourn: House of Horror Commander
@ -579,21 +593,26 @@ public class ScryfallImageSupportCards {
add("J25"); // Foundations Jumpstart
add("PIO"); // Pioneer Masters
add("PW25"); // Wizards Play Network 2025
add("PSPL"); // Spotlight Series
add("INR"); // Innistrad Remastered
add("PF25"); // MagicFest 2025
add("PL25"); // Year of the Snake 2025
add("DFT"); // Aetherdrift
add("DRC"); // Aetherdrift Commander
add("PLG25"); // Love Your LGS 2025
add("TDM"); // Tarkir: Dragonstorm
add("TDC"); // Tarkir: Dragonstorm Commander
add("FIN"); // Final Fantasy
add("FIC"); // Final Fantasy Commander
add("FCA"); // Final Fantasy: Through the Ages
add("PSS5"); // FIN Standard Showdown
add("EOE"); // Edge of Eternities
add("EOC"); // Edge of Eternities Commander
add("EOS"); // Edge of Eternities: Stellar Sights
add("SPM"); // Marvel's Spider-Man
add("SPE"); // Marvel's Spider-Man Eternal
add("TLA"); // Avatar: The Last Airbender
add("TLE"); // Avatar: The Last Airbender Eternal
// Custom sets using Scryfall images - must provide a direct link for each card in directDownloadLinks
add("CALC"); // Custom Alchemized versions of existing cards

View file

@ -1,10 +1,10 @@
package org.mage.plugins.card.dl.sources;
import mage.cards.repository.TokenRepository;
import java.util.HashMap;
import java.util.Map;
import mage.cards.repository.TokenRepository;
/**
* @author JayDi85
*/
@ -837,6 +837,8 @@ public class ScryfallImageSupportTokens {
put("SLD/Hydra", "https://api.scryfall.com/cards/sld/1334?format=image");
put("SLD/Icingdeath, Frost Tongue", "https://api.scryfall.com/cards/sld/1018?format=image");
put("SLD/Marit Lage", "https://api.scryfall.com/cards/sld/1681?format=image");
put("SLD/Mechtitan/1", "https://api.scryfall.com/cards/sld/1969?format=image");
put("SLD/Mechtitan/2", "https://api.scryfall.com/cards/sld/1969/en?format=image&face=back");
put("SLD/Mechtitan", "https://api.scryfall.com/cards/sld/1969?format=image");
put("SLD/Myr", "https://api.scryfall.com/cards/sld/2101?format=image");
put("SLD/Saproling", "https://api.scryfall.com/cards/sld/1139?format=image");
@ -2787,6 +2789,7 @@ public class ScryfallImageSupportTokens {
// EOE
put("EOE/Drone", "https://api.scryfall.com/cards/teoe/3?format=image");
put("EOE/Emblem Tezzeret", "https://api.scryfall.com/cards/teoe/11?format=image");
put("EOE/Human Soldier", "https://api.scryfall.com/cards/teoe/2?format=image");
put("EOE/Lander/1", "https://api.scryfall.com/cards/teoe/4?format=image");
put("EOE/Lander/2", "https://api.scryfall.com/cards/teoe/5?format=image");
@ -2928,6 +2931,12 @@ public class ScryfallImageSupportTokens {
// PL23
put("PL23/Food", "https://api.scryfall.com/cards/pl23/2?format=image");
// PL24
put("PL24/Dragon", "https://api.scryfall.com/cards/pl24/3?format=image");
// PL25
put("PL25/Snake", "https://api.scryfall.com/cards/pl25/2?format=image");
// generate supported sets
supportedSets.clear();
for (String cardName : this.keySet()) {

View file

@ -43,6 +43,12 @@ public class DownloaderTest {
Assert.assertTrue("must have text data (redirect to login page)", s.contains("Sign in to GitHub"));
}
@Test
public void test_DownloadText_ScryfallUtf8() {
String s = XmageURLConnection.downloadText("https://api.scryfall.com/cards/sld/379★/en");
Assert.assertTrue("must have text data (utf8 url must work)", s.contains("Zndrsplt, Eye of Wisdom"));
}
@Test
public void test_DownloadFile_ByHttp() throws IOException {
// use any public image here