From 862fe69b531335b8527c717359113e0144b25d18 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Thu, 2 Jan 2020 14:48:28 +0400 Subject: [PATCH] * Adventure cards - improved game logs (card hint works with adventure spell now, added original card info to cast's log); --- .../mage/client/components/ColorPane.java | 67 +++++++++++++------ .../dl/sources/MythicspoilerComSource.java | 8 ++- .../card/dl/sources/ScryfallImageSource.java | 12 +--- .../dl/sources/WizardCardsImageSource.java | 1 - .../mage/cards/AdventureCardSpellImpl.java | 6 ++ Mage/src/main/java/mage/game/stack/Spell.java | 18 +++-- Mage/src/main/java/mage/util/CardUtil.java | 50 +++++++++++--- .../src/main/java/mage/util/ClassScanner.java | 9 +-- Mage/src/main/java/mage/util/GameLog.java | 32 +++++++-- 9 files changed, 141 insertions(+), 62 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/components/ColorPane.java b/Mage.Client/src/main/java/mage/client/components/ColorPane.java index 79851a659d3..09996a47bd1 100644 --- a/Mage.Client/src/main/java/mage/client/components/ColorPane.java +++ b/Mage.Client/src/main/java/mage/client/components/ColorPane.java @@ -1,31 +1,27 @@ package mage.client.components; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Graphics; -import java.awt.MouseInfo; -import java.awt.Point; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; - -import javax.swing.JEditorPane; -import javax.swing.JPanel; -import javax.swing.JTextPane; -import javax.swing.SwingUtilities; -import javax.swing.event.HyperlinkEvent.EventType; -import javax.swing.text.html.HTMLDocument; -import javax.swing.text.html.HTMLEditorKit; - import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.client.MageFrame; import mage.client.dialog.PreferencesDialog; import mage.client.util.gui.GuiDisplayUtil; import mage.components.CardInfoPane; +import mage.util.CardUtil; import mage.utils.ThreadUtils; import mage.view.CardView; +import javax.swing.*; +import javax.swing.event.HyperlinkEvent.EventType; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.html.HTMLDocument; +import javax.swing.text.html.HTMLEditorKit; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + /** * Enhanced {@link JTextPane} with text highlighting support. * @@ -50,8 +46,37 @@ public class ColorPane extends JEditorPane { if (tooltipDelay == 0) { return; } - String name = e.getDescription().substring(1); - CardInfo card = CardRepository.instance.findCard(name); + + // finds extra data in html element like object_id, alternative_name, etc + Map extraData = new HashMap<>(); + if (e.getSourceElement() instanceof HTMLDocument.RunElement) { + HTMLDocument.RunElement el = (HTMLDocument.RunElement) e.getSourceElement(); + Enumeration attNames = el.getAttributeNames(); + while (attNames.hasMoreElements()) { + Object attName = attNames.nextElement(); + Object attValue = el.getAttribute(attName); + // custom attributes in SimpleAttributeSet element + if (attValue instanceof SimpleAttributeSet) { + SimpleAttributeSet attReal = (SimpleAttributeSet) attValue; + Enumeration attRealNames = attReal.getAttributeNames(); + while (attRealNames.hasMoreElements()) { + Object attRealName = attRealNames.nextElement(); + Object attRealValue = attReal.getAttribute(attRealName); + String name = attRealName.toString(); + String value = attRealValue.toString(); + extraData.put(name, value); + } + } + } + } + + String cardName = e.getDescription().substring(1); + String alternativeName = CardUtil.urlDecode(extraData.getOrDefault("alternative_name", "")); + if (!alternativeName.isEmpty()) { + cardName = alternativeName; + } + + CardInfo card = CardRepository.instance.findCard(cardName); try { final Component container = MageFrame.getUI().getComponent(MageComponents.POPUP_CONTAINER); if (e.getEventType() == EventType.EXITED) { @@ -152,9 +177,9 @@ public class ColorPane extends JEditorPane { super.paintChildren(g); } - public void enableHyperlinks(){ + public void enableHyperlinks() { hyperlinkEnabled = true; addHyperlinkHandlers(); } - + } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java index c8b30400d3d..1ceebd3f8af 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java @@ -3,6 +3,7 @@ package org.mage.plugins.card.dl.sources; import mage.client.MageFrame; import mage.remote.Connection; import mage.remote.Connection.ProxyType; +import mage.util.CardUtil; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; @@ -13,7 +14,10 @@ import org.mage.plugins.card.images.CardDownloadData; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.net.*; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; import java.util.*; import java.util.prefs.Preferences; @@ -298,7 +302,7 @@ public enum MythicspoilerComSource implements CardImageSource { Preferences prefs = MageFrame.getPreferences(); Connection.ProxyType proxyType = Connection.ProxyType.valueByText(prefs.get("proxyType", "None")); for (String setName : setNames.split("\\^")) { - String URLSetName = URLEncoder.encode(setName, "UTF-8"); + String URLSetName = CardUtil.urlEncode(setName); String baseUrl = "http://mythicspoiler.com/" + URLSetName + '/'; Map pageLinks = getSetLinksFromPage(cardSet, aliasesStart, prefs, proxyType, baseUrl, baseUrl); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java index 0c2468b8df8..7b01e1542c2 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java @@ -7,17 +7,16 @@ import com.google.gson.JsonParser; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.client.util.CardLanguage; +import mage.util.CardUtil; import org.apache.log4j.Logger; import org.mage.plugins.card.dl.DownloadServiceInfo; import org.mage.plugins.card.images.CardDownloadData; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; import java.net.Proxy; import java.net.URL; import java.net.URLConnection; -import java.net.URLEncoder; import java.util.*; /** @@ -96,12 +95,7 @@ public enum ScryfallImageSource implements CardImageSource { } } - try { - scryfallCollectorId = URLEncoder.encode(scryfallCollectorId, "utf-8"); - } catch (UnsupportedEncodingException e) { - // URL failed to encode, this will cause download to miss in certain environments - } - + scryfallCollectorId = CardUtil.urlEncode(scryfallCollectorId); baseUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/" + scryfallCollectorId + "/" + localizedCode + "?format=image"; alternativeUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/" @@ -227,7 +221,7 @@ public enum ScryfallImageSource implements CardImageSource { } private String searchCard(Proxy proxy, String set, String name) throws Exception { - final URL searchUrl = new URL("https://api.scryfall.com/cards/search?q=s:" + URLEncoder.encode(set + " " + name, "UTF-8")); + final URL searchUrl = new URL("https://api.scryfall.com/cards/search?q=s:" + CardUtil.urlEncode(set + " " + name)); URLConnection request = proxy == null ? searchUrl.openConnection() : searchUrl.openConnection(proxy); request.connect(); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java index 6a8cd5d4780..4e3bce57a00 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java @@ -522,7 +522,6 @@ public enum WizardCardsImageSource implements CardImageSource { } for (String setName : setNames.split("\\^")) { - // String URLSetName = URLEncoder.encode(setName, "UTF-8"); String URLSetName = setName.replaceAll(" ", "%20"); int page = 0; int firstMultiverseIdLastPage = 0; diff --git a/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java b/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java index 2804a943196..82c157401c9 100644 --- a/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java +++ b/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java @@ -99,6 +99,12 @@ public class AdventureCardSpellImpl extends CardImpl implements AdventureCardSpe public AdventureCard getParentCard() { return this.adventureCardParent; } + + @Override + public String getIdName() { + // id must send to main card (popup card hint in game logs) + return getName() + " [" + adventureCardParent.getId().toString().substring(0, 3) + ']'; + } } class AdventureCardSpellAbility extends SpellAbility { diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index ae08c673616..0a0011f5479 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -15,10 +15,7 @@ import mage.abilities.costs.mana.ManaCosts; import mage.abilities.keyword.BestowAbility; import mage.abilities.keyword.MorphAbility; import mage.abilities.text.TextPart; -import mage.cards.Card; -import mage.cards.CardsImpl; -import mage.cards.FrameStyle; -import mage.cards.SplitCard; +import mage.cards.*; import mage.constants.*; import mage.counters.Counter; import mage.counters.Counters; @@ -168,6 +165,13 @@ public class Spell extends StackObjImpl implements Card { return "a card face down"; } } + + if (card instanceof AdventureCardSpell) { + AdventureCard adventureCard = ((AdventureCardSpell) card).getParentCard(); + return GameLog.replaceNameByColoredName(card, getSpellAbility().toString(), adventureCard) + + " as Adventure spell of " + GameLog.getColoredObjectIdName(adventureCard); + } + return GameLog.replaceNameByColoredName(card, getSpellAbility().toString()); } @@ -421,7 +425,11 @@ public class Spell extends StackObjImpl implements Card { public String getIdName() { String idName; if (card != null) { - idName = card.getId().toString().substring(0, 3); + if (card instanceof AdventureCardSpell) { + idName = ((AdventureCardSpell) card).getParentCard().getId().toString().substring(0, 3); + } else { + idName = card.getId().toString().substring(0, 3); + } } else { idName = getId().toString().substring(0, 3); } diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index f5a70926cea..81ea859d036 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -1,8 +1,5 @@ package mage.util; -import java.text.SimpleDateFormat; -import java.util.Objects; -import java.util.UUID; import mage.MageObject; import mage.Mana; import mage.abilities.Ability; @@ -17,6 +14,13 @@ import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.util.functions.CopyTokenFunction; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.Objects; +import java.util.UUID; + /** * @author nantuko */ @@ -25,10 +29,10 @@ public final class CardUtil { private static final String SOURCE_EXILE_ZONE_TEXT = "SourceExileZone"; static final String[] numberStrings = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", - "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"}; + "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"}; static final String[] ordinalStrings = {"first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eightth", "ninth", - "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth", "twentieth"}; + "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth", "twentieth"}; public static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS"); @@ -143,8 +147,8 @@ public final class CardUtil { * * @param spellAbility * @param manaCostsToReduce costs to reduce - * @param convertToGeneric colored mana does reduce generic mana if no - * appropriate colored mana is in the costs included + * @param convertToGeneric colored mana does reduce generic mana if no + * appropriate colored mana is in the costs included */ public static void adjustCost(SpellAbility spellAbility, ManaCosts manaCostsToReduce, boolean convertToGeneric) { ManaCosts previousCost = spellAbility.getManaCostsToPay(); @@ -329,7 +333,7 @@ public final class CardUtil { * * @param number number to convert to text * @param forOne if the number is 1, this string will be returnedinstead of - * "one". + * "one". * @return */ public static String numberToText(int number, String forOne) { @@ -414,7 +418,7 @@ public final class CardUtil { /** * Creates and saves a (card + zoneChangeCounter) specific exileId. * - * @param game the current game + * @param game the current game * @param source source ability * @return the specific UUID */ @@ -449,9 +453,9 @@ public final class CardUtil { * be specific to a permanent instance. So they won't match, if a permanent * was e.g. exiled and came back immediately. * - * @param text short value to describe the value + * @param text short value to describe the value * @param cardId id of the card - * @param game the game + * @param game the game * @return */ public static String getCardZoneString(String text, UUID cardId, Game game) { @@ -577,4 +581,28 @@ public final class CardUtil { Card card = game.getCard(objectId); return card != null ? card.getMainCard().getId() : objectId; } + + public static String urlEncode(String data) { + if (data.isEmpty()) { + return ""; + } + + try { + return URLEncoder.encode(data, "UTF-8"); + } catch (UnsupportedEncodingException e) { + return ""; + } + } + + public static String urlDecode(String encodedData) { + if (encodedData.isEmpty()) { + return ""; + } + + try { + return URLDecoder.decode(encodedData, "UTF-8"); + } catch (UnsupportedEncodingException e) { + return ""; + } + } } diff --git a/Mage/src/main/java/mage/util/ClassScanner.java b/Mage/src/main/java/mage/util/ClassScanner.java index 47972fe400b..a884ab3d759 100644 --- a/Mage/src/main/java/mage/util/ClassScanner.java +++ b/Mage/src/main/java/mage/util/ClassScanner.java @@ -1,17 +1,14 @@ - package mage.util; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URL; -import java.net.URLDecoder; import java.util.*; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; /** - * * @author North */ public final class ClassScanner { @@ -30,7 +27,7 @@ public final class ClassScanner { public static List findClasses(ClassLoader classLoader, List packages, Class type) { List cards = new ArrayList<>(); try { - if(classLoader == null) classLoader = Thread.currentThread().getContextClassLoader(); + if (classLoader == null) classLoader = Thread.currentThread().getContextClassLoader(); assert classLoader != null; Map dirs = new HashMap<>(); @@ -56,7 +53,7 @@ public final class ClassScanner { } for (String filePath : jars) { - File file = new File(URLDecoder.decode(filePath, "UTF-8")); + File file = new File(CardUtil.urlDecode(filePath)); cards.addAll(findClassesInJar(classLoader, file, packages, type)); } } catch (IOException ex) { @@ -82,7 +79,7 @@ public final class ClassScanner { if (!file.exists()) return cards; - try(JarInputStream jarFile = new JarInputStream(new FileInputStream(file))) { + try (JarInputStream jarFile = new JarInputStream(new FileInputStream(file))) { while (true) { JarEntry jarEntry = jarFile.getNextJarEntry(); if (jarEntry == null) { diff --git a/Mage/src/main/java/mage/util/GameLog.java b/Mage/src/main/java/mage/util/GameLog.java index 93c26460881..e0343765dfd 100644 --- a/Mage/src/main/java/mage/util/GameLog.java +++ b/Mage/src/main/java/mage/util/GameLog.java @@ -33,32 +33,50 @@ public final class GameLog { return text.replaceAll(mageObject.getName(), getColoredObjectIdName(mageObject)); } + /** + * @param mageObject - original object name to replace + * @param text - original text to insert object's html name + * @param alternativeObject - alternative object (object to show in card's hint in GUI) + * @return + */ + public static String replaceNameByColoredName(MageObject mageObject, String text, MageObject alternativeObject) { + return text.replaceAll(mageObject.getName(), getColoredObjectIdName(mageObject, alternativeObject)); + } + public static String getColoredObjectName(MageObject mageObject) { - return "" + mageObject.getName() + ""; + return "" + mageObject.getName() + ""; } public static String getColoredObjectIdName(MageObject mageObject) { - return "" + mageObject.getIdName() + ""; + return getColoredObjectIdName(mageObject, null); + } + + public static String getColoredObjectIdName(MageObject mageObject, MageObject alternativeObject) { + return "" + mageObject.getIdName() + ""; } public static String getColoredObjectIdNameForTooltip(MageObject mageObject) { - return "" + mageObject.getIdName() + ""; + return "" + mageObject.getIdName() + ""; } public static String getNeutralColoredText(String text) { - return "" + text + ""; + return "" + text + ""; } public static String getColoredPlayerName(String name) { - return "" + name + ""; + return "" + name + ""; } public static String getPlayerRequestColoredText(String name) { - return "" + name + ""; + return "" + name + ""; } public static String getPlayerConfirmColoredText(String name) { - return "" + name + ""; + return "" + name + ""; } public static String getSmallSecondLineText(String text) {