mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-13 17:27:46 +00:00
[Mobile] Fix blinking card images while using online image fetcher
- also cache card list for faster lookup
This commit is contained in:
@@ -65,6 +65,7 @@ public final class ImageKeys {
|
||||
return tokenKey.substring(ImageKeys.TOKEN_PREFIX.length());
|
||||
}
|
||||
|
||||
private static final Map<String, File> cachedCards = new HashMap<>(50000);
|
||||
public static File getImageFile(String key) {
|
||||
if (StringUtils.isEmpty(key))
|
||||
return null;
|
||||
@@ -97,101 +98,142 @@ public final class ImageKeys {
|
||||
dir = CACHE_CARD_PICS_DIR;
|
||||
}
|
||||
|
||||
File file = findFile(dir, filename);
|
||||
if (file != null) { return file; }
|
||||
File cachedFile = cachedCards.get(filename);
|
||||
if (cachedFile != null) {
|
||||
return cachedFile;
|
||||
} else {
|
||||
File file = findFile(dir, filename);
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
|
||||
// AE -> Ae and Ae -> AE for older cards with different file names
|
||||
// on case-sensitive file systems
|
||||
if (filename.contains("Ae")) {
|
||||
file = findFile(dir, TextUtil.fastReplace(filename, "Ae", "AE"));
|
||||
if (file != null) { return file; }
|
||||
} else if (filename.contains("AE")) {
|
||||
file = findFile(dir, TextUtil.fastReplace(filename, "AE", "Ae"));
|
||||
if (file != null) { return file; }
|
||||
}
|
||||
//try fullborder...
|
||||
if (filename.contains(".full")) {
|
||||
String fullborderFile = TextUtil.fastReplace(filename, ".full", ".fullborder");
|
||||
file = findFile(dir, fullborderFile);
|
||||
if (file != null) { return file; }
|
||||
// if there's a 1st art variant try without it for .fullborder images
|
||||
file = findFile(dir, TextUtil.fastReplace(fullborderFile, "1.fullborder", ".fullborder"));
|
||||
if (file != null) { return file; }
|
||||
// if there's a 1st art variant try with it for .fullborder images
|
||||
file = findFile(dir, fullborderFile.replaceAll("[0-9]*.fullborder", "1.fullborder"));
|
||||
if (file != null) { return file; }
|
||||
// if there's an art variant try without it for .full images
|
||||
file = findFile(dir, filename.replaceAll("[0-9].full",".full"));
|
||||
if (file != null) { return file; }
|
||||
// if there's a 1st art variant try with it for .full images
|
||||
file = findFile(dir, filename.replaceAll("[0-9]*.full", "1.full"));
|
||||
if (file != null) { return file; }
|
||||
//setlookup
|
||||
if (!StaticData.instance().getSetLookup().isEmpty()) {
|
||||
for (String setKey : StaticData.instance().getSetLookup().keySet()) {
|
||||
if (filename.startsWith(setKey)) {
|
||||
for (String setLookup : StaticData.instance().getSetLookup().get(setKey)) {
|
||||
//.fullborder lookup
|
||||
file = findFile(dir, TextUtil.fastReplace(fullborderFile, setKey, getSetFolder(setLookup)));
|
||||
if (file != null) { return file; }
|
||||
file = findFile(dir, TextUtil.fastReplace(fullborderFile, setKey, getSetFolder(setLookup)).replaceAll("[0-9]*.fullborder", "1.fullborder"));
|
||||
if (file != null) { return file; }
|
||||
//.full lookup
|
||||
file = findFile(dir, TextUtil.fastReplace(filename, setKey, getSetFolder(setLookup)));
|
||||
if (file != null) { return file; }
|
||||
file = findFile(dir, TextUtil.fastReplace(filename, setKey, getSetFolder(setLookup)).replaceAll("[0-9]*.full", "1.full"));
|
||||
if (file != null) { return file; }
|
||||
// AE -> Ae and Ae -> AE for older cards with different file names
|
||||
// on case-sensitive file systems
|
||||
if (filename.contains("Ae")) {
|
||||
file = findFile(dir, TextUtil.fastReplace(filename, "Ae", "AE"));
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
} else if (filename.contains("AE")) {
|
||||
file = findFile(dir, TextUtil.fastReplace(filename, "AE", "Ae"));
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
//try fullborder...
|
||||
if (filename.contains(".full")) {
|
||||
String fullborderFile = TextUtil.fastReplace(filename, ".full", ".fullborder");
|
||||
file = findFile(dir, fullborderFile);
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
// if there's a 1st art variant try without it for .fullborder images
|
||||
file = findFile(dir, TextUtil.fastReplace(fullborderFile, "1.fullborder", ".fullborder"));
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
// if there's a 1st art variant try with it for .fullborder images
|
||||
file = findFile(dir, fullborderFile.replaceAll("[0-9]*.fullborder", "1.fullborder"));
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
// if there's an art variant try without it for .full images
|
||||
file = findFile(dir, filename.replaceAll("[0-9].full",".full"));
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
// if there's a 1st art variant try with it for .full images
|
||||
file = findFile(dir, filename.replaceAll("[0-9]*.full", "1.full"));
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
//setlookup
|
||||
file = setLookUpFile(filename, fullborderFile);
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
//if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder
|
||||
if (!filename.contains(".full")) {
|
||||
file = findFile(dir, TextUtil.addSuffix(filename,".full"));
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
file = findFile(dir, TextUtil.addSuffix(filename,".fullborder"));
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
if (dir.equals(CACHE_TOKEN_PICS_DIR)) {
|
||||
int index = filename.lastIndexOf('_');
|
||||
if (index != -1) {
|
||||
String setlessFilename = filename.substring(0, index);
|
||||
String setCode = filename.substring(index + 1);
|
||||
// try with upper case set
|
||||
file = findFile(dir, setlessFilename + "_" + setCode.toUpperCase());
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
// try with lower case set
|
||||
file = findFile(dir, setlessFilename + "_" + setCode.toLowerCase());
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
// try without set name
|
||||
file = findFile(dir, setlessFilename);
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
// if there's an art variant try without it
|
||||
if (setlessFilename.matches(".*[0-9]*$")) {
|
||||
file = findFile(dir, setlessFilename.replaceAll("[0-9]*$", ""));
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (filename.contains("/")) {
|
||||
String setlessFilename = filename.substring(filename.indexOf('/') + 1);
|
||||
file = findFile(dir, setlessFilename);
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
|
||||
if (setlessFilename.contains(".full")) {
|
||||
//try fullborder
|
||||
String fullborderFile = TextUtil.fastReplace(setlessFilename, ".full", ".fullborder");
|
||||
file = findFile(dir, fullborderFile);
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
// try lowering the art index to the minimum for regular cards
|
||||
file = findFile(dir, setlessFilename.replaceAll("[0-9]*[.]full", "1.full"));
|
||||
if (file != null) {
|
||||
cachedCards.put(filename, file);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder
|
||||
if (!filename.contains(".full")) {
|
||||
file = findFile(dir, TextUtil.addSuffix(filename,".full"));
|
||||
if (file != null) { return file; }
|
||||
file = findFile(dir, TextUtil.addSuffix(filename,".fullborder"));
|
||||
if (file != null) { return file; }
|
||||
}
|
||||
|
||||
if (dir.equals(CACHE_TOKEN_PICS_DIR)) {
|
||||
int index = filename.lastIndexOf('_');
|
||||
if (index != -1) {
|
||||
String setlessFilename = filename.substring(0, index);
|
||||
String setCode = filename.substring(index + 1);
|
||||
// try with upper case set
|
||||
file = findFile(dir, setlessFilename + "_" + setCode.toUpperCase());
|
||||
if (file != null) { return file; }
|
||||
// try with lower case set
|
||||
file = findFile(dir, setlessFilename + "_" + setCode.toLowerCase());
|
||||
if (file != null) { return file; }
|
||||
// try without set name
|
||||
file = findFile(dir, setlessFilename);
|
||||
if (file != null) { return file; }
|
||||
// if there's an art variant try without it
|
||||
if (setlessFilename.matches(".*[0-9]*$")) {
|
||||
file = findFile(dir, setlessFilename.replaceAll("[0-9]*$", ""));
|
||||
if (file != null) { return file; }
|
||||
}
|
||||
}
|
||||
} else if (filename.contains("/")) {
|
||||
String setlessFilename = filename.substring(filename.indexOf('/') + 1);
|
||||
file = findFile(dir, setlessFilename);
|
||||
if (file != null) { return file; }
|
||||
|
||||
if (setlessFilename.contains(".full")) {
|
||||
//try fullborder
|
||||
String fullborderFile = TextUtil.fastReplace(setlessFilename, ".full", ".fullborder");
|
||||
file = findFile(dir, fullborderFile);
|
||||
if (file != null) { return file; }
|
||||
// try lowering the art index to the minimum for regular cards
|
||||
file = findFile(dir, setlessFilename.replaceAll("[0-9]*[.]full", "1.full"));
|
||||
if (file != null) { return file; }
|
||||
}
|
||||
}
|
||||
|
||||
// System.out.println("File not found, no image created: " + key);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -200,16 +242,72 @@ public final class ImageKeys {
|
||||
? StaticData.instance().getEditions().getCode2ByCode(edition) // by default 2-letter codes from MWS are used
|
||||
: CACHE_CARD_PICS_SUBDIR.get(edition); // may use custom paths though
|
||||
}
|
||||
|
||||
private static File findFile(String dir, String filename) {
|
||||
for (String ext : FILE_EXTENSIONS) {
|
||||
File file = new File(dir, filename + ext);
|
||||
if (file.exists()) {
|
||||
if (file.isDirectory()) {
|
||||
file.delete();
|
||||
continue;
|
||||
private static File setLookUpFile(String filename, String fullborderFile) {
|
||||
if (!StaticData.instance().getSetLookup().isEmpty()) {
|
||||
for (String setKey : StaticData.instance().getSetLookup().keySet()) {
|
||||
if (filename.startsWith(setKey)) {
|
||||
for (String setLookup : StaticData.instance().getSetLookup().get(setKey)) {
|
||||
String lookupDirectory = CACHE_CARD_PICS_DIR + setLookup;
|
||||
File f = new File(lookupDirectory);
|
||||
String[] cardNames = f.list();
|
||||
if (cardNames != null) {
|
||||
Set<String> cardList = new HashSet<>(Arrays.asList(cardNames));
|
||||
for (String ext : FILE_EXTENSIONS) {
|
||||
if (ext.equals(""))
|
||||
continue;
|
||||
String fb1 = fullborderFile.replace(setKey+"/","")+ext;
|
||||
if (cardList.contains(fb1)) {
|
||||
return new File(lookupDirectory+"/"+fb1);
|
||||
}
|
||||
String fb2 = fullborderFile.replace(setKey+"/","").replaceAll("[0-9]*.fullborder", "1.fullborder")+ext;
|
||||
if (cardList.contains(fb2)) {
|
||||
return new File(lookupDirectory+"/"+fb2);
|
||||
}
|
||||
String f1 = filename.replace(setKey+"/","")+ext;
|
||||
if (cardList.contains(f1)) {
|
||||
return new File(lookupDirectory+"/"+f1);
|
||||
}
|
||||
String f2 = filename.replace(setKey+"/","").replaceAll("[0-9]*.full", "1.full")+ext;
|
||||
if (cardList.contains(f2)) {
|
||||
return new File(lookupDirectory+"/"+f2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static File findFile(String dir, String filename) {
|
||||
if (dir.equals(CACHE_CARD_PICS_DIR)) {
|
||||
File f = new File(dir+"/"+filename);
|
||||
String initialDirectory = f.getParent();
|
||||
String cardName = f.getName();
|
||||
File parentDir = new File(initialDirectory);
|
||||
String[] cardNames = parentDir.list();
|
||||
if (cardNames != null) {
|
||||
Set<String> cardList = new HashSet<>(Arrays.asList(cardNames));
|
||||
for (String ext : FILE_EXTENSIONS) {
|
||||
if (ext.equals(""))
|
||||
continue;
|
||||
String cardLookup = cardName+ext;
|
||||
if (cardList.contains(cardLookup)) {
|
||||
return new File(parentDir+"/"+cardLookup);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//old method for tokens and others
|
||||
for (String ext : FILE_EXTENSIONS) {
|
||||
File file = new File(dir, filename + ext);
|
||||
if (file.exists()) {
|
||||
if (file.isDirectory()) {
|
||||
file.delete();
|
||||
continue;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -217,8 +315,11 @@ public final class ImageKeys {
|
||||
|
||||
//shortcut for determining if a card image exists for a given card
|
||||
//should only be called from PaperCard.hasImage()
|
||||
static HashMap<String, HashSet<String>> cachedContent=new HashMap<>();
|
||||
static HashMap<String, HashSet<String>> cachedContent=new HashMap<>(50000);
|
||||
public static boolean hasImage(PaperCard pc) {
|
||||
return hasImage(pc, false);
|
||||
}
|
||||
public static boolean hasImage(PaperCard pc, boolean update) {
|
||||
Boolean editionHasImage = editionImageLookup.get(pc.getEdition());
|
||||
if (editionHasImage == null) {
|
||||
String setFolder = getSetFolder(pc.getEdition());
|
||||
@@ -232,6 +333,10 @@ public final class ImageKeys {
|
||||
if (!filename.endsWith(".jpg") && !filename.endsWith(".png"))
|
||||
continue; // not image - not interested
|
||||
setFolderContent.add(filename.split("\\.")[0]); // get rid of any full or fullborder
|
||||
//preload cachedCards at startUp
|
||||
String key = setFolder + "/" + filename.replace(".fullborder", ".full").replace(".jpg", "").replace(".png", "");
|
||||
File value = new File(CACHE_CARD_PICS_DIR + setFolder + "/" + filename);
|
||||
cachedCards.put(key, value);
|
||||
}
|
||||
cachedContent.put(setFolder, setFolderContent);
|
||||
}
|
||||
@@ -239,6 +344,13 @@ public final class ImageKeys {
|
||||
String[] keyParts = StringUtils.split(pc.getCardImageKey(), "//");
|
||||
if (keyParts.length != 2)
|
||||
return false;
|
||||
if (update && editionHasImage) {
|
||||
try {
|
||||
cachedContent.get(getSetFolder(pc.getEdition())).add(pc.getName());
|
||||
} catch (Exception e) {
|
||||
System.err.println(e);
|
||||
}
|
||||
}
|
||||
HashSet<String> content = cachedContent.getOrDefault(keyParts[0], null);
|
||||
//avoid checking for file if edition doesn't have any images
|
||||
return editionHasImage && hitCache(content, keyParts[1]);
|
||||
|
||||
@@ -136,8 +136,11 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
|
||||
}
|
||||
|
||||
public boolean hasImage() {
|
||||
if (hasImage == null) { //cache value since it's not free to calculate
|
||||
hasImage = ImageKeys.hasImage(this);
|
||||
return hasImage(false);
|
||||
}
|
||||
public boolean hasImage(boolean update) {
|
||||
if (hasImage == null || update) { //cache value since it's not free to calculate
|
||||
hasImage = ImageKeys.hasImage(this, update);
|
||||
}
|
||||
return hasImage;
|
||||
}
|
||||
|
||||
@@ -113,8 +113,6 @@ public class ImageCache {
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
cache.invalidateAll();
|
||||
cache.cleanUp();
|
||||
missingIconKeys.clear();
|
||||
}
|
||||
|
||||
@@ -158,17 +156,26 @@ public class ImageCache {
|
||||
|
||||
final String prefix = imageKey.substring(0, 2);
|
||||
|
||||
PaperCard paperCard = null;
|
||||
if (prefix.equals(ImageKeys.CARD_PREFIX)) {
|
||||
PaperCard paperCard = ImageUtil.getPaperCardFromImageKey(imageKey);
|
||||
try {
|
||||
paperCard = ImageUtil.getPaperCardFromImageKey(imageKey);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
if (paperCard == null)
|
||||
return false;
|
||||
|
||||
final boolean backFace = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX);
|
||||
final String cardfilename = backFace ? paperCard.getCardAltImageKey() : paperCard.getCardImageKey();
|
||||
if (!new File(ForgeConstants.CACHE_CARD_PICS_DIR + "/" + cardfilename + ".jpg").exists())
|
||||
if (!new File(ForgeConstants.CACHE_CARD_PICS_DIR + "/" + cardfilename + ".png").exists())
|
||||
if (!new File(ForgeConstants.CACHE_CARD_PICS_DIR + "/" + TextUtil.fastReplace(cardfilename,".full", ".fullborder") + ".jpg").exists())
|
||||
return false;
|
||||
if (!FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER)) {
|
||||
return paperCard.hasImage();
|
||||
} else {
|
||||
final boolean backFace = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX);
|
||||
final String cardfilename = backFace ? paperCard.getCardAltImageKey() : paperCard.getCardImageKey();
|
||||
if (!new File(ForgeConstants.CACHE_CARD_PICS_DIR + "/" + cardfilename + ".jpg").exists())
|
||||
if (!new File(ForgeConstants.CACHE_CARD_PICS_DIR + "/" + cardfilename + ".png").exists())
|
||||
if (!new File(ForgeConstants.CACHE_CARD_PICS_DIR + "/" + TextUtil.fastReplace(cardfilename,".full", ".fullborder") + ".jpg").exists())
|
||||
return false;
|
||||
}
|
||||
} else if (prefix.equals(ImageKeys.TOKEN_PREFIX)) {
|
||||
final String tokenfilename = imageKey.substring(2) + ".jpg";
|
||||
|
||||
@@ -235,12 +242,11 @@ public class ImageCache {
|
||||
// a default "not available" image and add to cache for given key.
|
||||
if (image == null) {
|
||||
if (useDefaultIfNotFound) {
|
||||
image = defaultImage;
|
||||
image = useOtherCache ? defaultImage : null;
|
||||
if (useOtherCache)
|
||||
otherCache.put(imageKey, defaultImage);
|
||||
else
|
||||
cache.put(imageKey, defaultImage);
|
||||
if (imageBorder.get(image.toString()) == null)
|
||||
|
||||
if (image != null && imageBorder.get(image.toString()) == null)
|
||||
imageBorder.put(image.toString(), Pair.of(Color.valueOf("#171717").toString(), false)); //black border
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ import forge.gui.card.CardDetailUtil;
|
||||
import forge.gui.card.CardDetailUtil.DetailColors;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgeConstants.CounterDisplayType;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.localinstance.properties.ForgePreferences.FPref;
|
||||
|
||||
@@ -27,7 +27,6 @@ import forge.assets.FSkin;
|
||||
import forge.assets.FSkinFont;
|
||||
import forge.assets.FSkinImage;
|
||||
import forge.assets.FTextureRegionImage;
|
||||
import forge.card.CardDb;
|
||||
import forge.card.CardEdition;
|
||||
import forge.deck.io.DeckPreferences;
|
||||
import forge.gamemodes.limited.BoosterDraft;
|
||||
|
||||
@@ -105,11 +105,8 @@ public class LoadGameMenu extends FPopupMenu {
|
||||
protected void buildMenu() {
|
||||
FScreen currentScreen = Forge.getCurrentScreen();
|
||||
for (LoadGameScreen lgs : LoadGameScreen.values()) {
|
||||
//fixes the overlapping menu items when the user suddenly switch from load game screen index to another screen
|
||||
if (HomeScreen.instance.getActiveButtonIndex() == 1) {
|
||||
addItem(lgs.item);
|
||||
lgs.item.setSelected(currentScreen == lgs.screen);
|
||||
}
|
||||
addItem(lgs.item);
|
||||
lgs.item.setSelected(currentScreen == lgs.screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,11 @@ public abstract class ImageFetcher {
|
||||
if (destFile.exists()) {
|
||||
// TODO: Figure out why this codepath gets reached.
|
||||
// Ideally, fetchImage() wouldn't be called if we already have the image.
|
||||
if (prefix.equals(ImageKeys.CARD_PREFIX)) {
|
||||
PaperCard paperCard = ImageUtil.getPaperCardFromImageKey(imageKey);
|
||||
if (paperCard != null)
|
||||
paperCard.hasImage(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user