Various fixes for Mobile

Optimize ImageFetcher and ImageCache on fetching and disposing textures.
Fix Quest Tournament crash when using a theme without sprite avatars.
Fix NPE on HDButtons.
This commit is contained in:
Anthony Calosa
2020-10-03 02:27:21 +08:00
parent d36920ad86
commit dd37e8995b
13 changed files with 113 additions and 83 deletions

View File

@@ -27,8 +27,7 @@ public abstract class CachedCardImage implements ImageFetcher.Callback {
} }
public void fetch() { public void fetch() {
Texture image = ImageCache.getImage(key, false); if (!ImageCache.imageKeyFileExists(key)) {
if (image == null) {
fetcher.fetchImage(key, this); fetcher.fetchImage(key, this);
} }
} }

View File

@@ -70,6 +70,7 @@ public class Forge implements ApplicationListener {
public static boolean hdbuttons = false; public static boolean hdbuttons = false;
public static boolean hdstart = false; public static boolean hdstart = false;
public static boolean isPortraitMode = false; public static boolean isPortraitMode = false;
public static boolean gameInProgress = false;
public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value, boolean androidOrientation) { public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value, boolean androidOrientation) {
if (GuiBase.getInterface() == null) { if (GuiBase.getInterface() == null) {
@@ -159,12 +160,12 @@ public class Forge implements ApplicationListener {
private void preloadExtendedArt() { private void preloadExtendedArt() {
if (!enablePreloadExtendedArt) if (!enablePreloadExtendedArt)
return; return;
List<String> BorderlessCardlistkeys = FileUtil.readFile(ForgeConstants.BORDERLESS_CARD_LIST_FILE); List<String> borderlessCardlistkeys = FileUtil.readFile(ForgeConstants.BORDERLESS_CARD_LIST_FILE);
if(BorderlessCardlistkeys.isEmpty()) if(borderlessCardlistkeys.isEmpty())
return; return;
List<String> filteredkeys = new ArrayList<>(); List<String> filteredkeys = new ArrayList<>();
for (String cardname : BorderlessCardlistkeys){ for (String cardname : borderlessCardlistkeys){
File image = new File(ForgeConstants.CACHE_CARD_PICS_DIR+"/"+cardname+".jpg"); File image = new File(ForgeConstants.CACHE_CARD_PICS_DIR+ForgeConstants.PATH_SEPARATOR+cardname+".jpg");
if (image.exists()) if (image.exists())
filteredkeys.add(cardname); filteredkeys.add(cardname);
} }
@@ -393,18 +394,14 @@ public class Forge implements ApplicationListener {
} }
private static void setCurrentScreen(FScreen screen0) { private static void setCurrentScreen(FScreen screen0) {
String toNewScreen = screen0 != null ? screen0.toString() : "";
String previousScreen = currentScreen != null ? currentScreen.toString() : "";
gameInProgress = toNewScreen.toLowerCase().contains("match") || previousScreen.toLowerCase().contains("match");
try { try {
endKeyInput(); //end key input before switching screens endKeyInput(); //end key input before switching screens
ForgeAnimation.endAll(); //end all active animations before switching screens ForgeAnimation.endAll(); //end all active animations before switching screens
try {
ImageCache.disposeTexture();
}
catch (Exception ex)
{
// FIXME: This isn't supposed to be necessary, but disposeTexture crashes e.g. in Quest Tournaments on mobile, needs proper fixing.
System.err.println("Warning: caught an exception while trying to call ImageCache.disposeTexture() in setCurrentScreen.");
}
currentScreen = screen0; currentScreen = screen0;
currentScreen.setSize(screenWidth, screenHeight); currentScreen.setSize(screenWidth, screenHeight);
currentScreen.onActivate(); currentScreen.onActivate();

View File

@@ -275,6 +275,20 @@ public class FSkin {
} }
} }
pxPreferredAvatars.dispose(); pxPreferredAvatars.dispose();
} else if (!FSkin.preferredName.isEmpty()){
//workaround bug crash fix if missing sprite avatar on preferred theme for quest tournament...
//i really don't know why it needs to populate the avatars twice.... needs investigation
final int pw = pxDefaultAvatars.getWidth();
final int ph = pxDefaultAvatars.getHeight();
for (int j = 0; j < ph; j += 100) {
for (int i = 0; i < pw; i += 100) {
if (i == 0 && j == 0) { continue; }
pxTest = new Color(pxDefaultAvatars.getPixel(i + 50, j + 50));
if (pxTest.a == 0) { continue; }
FSkin.avatars.put(counter++, new TextureRegion(txDefaultAvatars, i, j, 100, 100));
}
}
} }
final int aw = pxDefaultAvatars.getWidth(); final int aw = pxDefaultAvatars.getWidth();

View File

@@ -30,20 +30,23 @@ import com.google.common.cache.RemovalNotification;
import forge.ImageKeys; import forge.ImageKeys;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.card.CardRenderer; import forge.card.CardRenderer;
import forge.deck.Deck;
import forge.game.card.CardView; import forge.game.card.CardView;
import forge.game.player.IHasIcon; import forge.game.player.IHasIcon;
import forge.item.IPaperCard; import forge.item.IPaperCard;
import forge.item.InventoryItem; import forge.item.InventoryItem;
import forge.item.PaperCard;
import forge.model.FModel; import forge.model.FModel;
import forge.properties.ForgeConstants; import forge.properties.ForgeConstants;
import forge.util.ImageUtil; import forge.util.ImageUtil;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
@@ -73,6 +76,7 @@ public class ImageCache {
if(removalNotification.wasEvicted()||removalNotification.getCause() == RemovalCause.EXPIRED) { if(removalNotification.wasEvicted()||removalNotification.getCause() == RemovalCause.EXPIRED) {
removalNotification.getValue().dispose(); removalNotification.getValue().dispose();
} }
CardRenderer.clearcardArtCache();
} }
}) })
.build(new ImageLoader()); .build(new ImageLoader());
@@ -104,15 +108,6 @@ public class ImageCache {
missingIconKeys.clear(); missingIconKeys.clear();
} }
public static void disposeTexture(){
for (Texture t: cache.asMap().values()) {
if (!t.toString().contains("pics/icons")) //fixes quest avatars black texture. todo: filter textures that are safe to dispose...
t.dispose();
}
CardRenderer.clearcardArtCache();
clear();
}
public static Texture getImage(InventoryItem ii) { public static Texture getImage(InventoryItem ii) {
return getImage(ii.getImageKey(false), true); return getImage(ii.getImageKey(false), true);
} }
@@ -131,6 +126,39 @@ public class ImageCache {
return new FTextureImage(icon); return new FTextureImage(icon);
} }
/**
* checks the card image exists from the disk.
*/
public static boolean imageKeyFileExists(String imageKey) {
if (StringUtils.isEmpty(imageKey))
return false;
if (imageKey.length() < 2)
return false;
final String prefix = imageKey.substring(0, 2);
if (prefix.equals(ImageKeys.CARD_PREFIX)) {
PaperCard paperCard = ImageUtil.getPaperCardFromImageKey(imageKey);
if (paperCard == null)
return false;
final boolean backFace = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX);
final String cardfilename = ImageUtil.getImageKey(paperCard, backFace, true);
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";
if (!new File(ForgeConstants.CACHE_TOKEN_PICS_DIR, tokenfilename).exists())
return false;
}
return true;
}
/** /**
* This requests the original unscaled image from the cache for the given key. * This requests the original unscaled image from the cache for the given key.
* If the image does not exist then it can return a default image if desired. * If the image does not exist then it can return a default image if desired.
@@ -191,12 +219,20 @@ public class ImageCache {
return image; return image;
} }
public static void preloadCache(Iterable<String> keys) { public static void preloadCache(Iterable<String> keys) {
try { for (String imageKey : keys){
cache.getAll(keys); if(getImage(imageKey, false) == null)
} catch (ExecutionException e) { System.err.println("could not load card image:"+imageKey);
e.printStackTrace();
} }
} }
public static void preloadCache(Deck deck) {
if(deck == null)
return;
for (PaperCard p : deck.getAllCardsInASinglePool().toFlatList()) {
if (getImage(p.getImageKey(false),false) == null)
System.err.println("could not load card image:"+p.toString());
}
}
public static TextureRegion croppedBorderImage(Texture image) { public static TextureRegion croppedBorderImage(Texture image) {
if (!image.toString().contains(".fullborder.")) if (!image.toString().contains(".fullborder."))
return new TextureRegion(image); return new TextureRegion(image);

View File

@@ -3,6 +3,7 @@ package forge.deck;
import forge.FThreads; import forge.FThreads;
import forge.Forge; import forge.Forge;
import forge.GuiBase; import forge.GuiBase;
import forge.assets.ImageCache;
import forge.deck.FDeckEditor.EditorType; import forge.deck.FDeckEditor.EditorType;
import forge.deck.io.DeckPreferences; import forge.deck.io.DeckPreferences;
import forge.error.BugReporter; import forge.error.BugReporter;
@@ -472,6 +473,8 @@ public class FDeckChooser extends FScreen {
break; break;
} }
needRefreshOnActivate = true; needRefreshOnActivate = true;
/*preload deck to cache*/
ImageCache.preloadCache(deck.getDeck());
Forge.openScreen(new FDeckEditor(editorType, deck, true)); Forge.openScreen(new FDeckEditor(editorType, deck, true));
} }
@@ -1147,7 +1150,7 @@ public class FDeckChooser extends FScreen {
}); });
} }
}); });
chooser.show(null, true); chooser.show(null, false); /*setting selectMax to true will select all available option*/
} }
}); });
} }

View File

@@ -5,6 +5,7 @@ import forge.assets.FImage;
import forge.assets.FSkin; import forge.assets.FSkin;
import forge.assets.FSkinImage; import forge.assets.FSkinImage;
import forge.assets.FTextureRegionImage; import forge.assets.FTextureRegionImage;
import forge.assets.ImageCache;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.itemmanager.CardManager; import forge.itemmanager.CardManager;
import forge.itemmanager.ItemManagerConfig; import forge.itemmanager.ItemManagerConfig;
@@ -112,6 +113,9 @@ public class FDeckViewer extends FScreen {
public static void show(final Deck deck0) { public static void show(final Deck deck0) {
if (deck0 == null) { return; } if (deck0 == null) { return; }
/*preload deck to cache*/
ImageCache.preloadCache(deck0);
deckViewer = new FDeckViewer(deck0); deckViewer = new FDeckViewer(deck0);
deckViewer.setRotate180(MatchController.getView() != null && MatchController.getView().isTopHumanPlayerActive()); deckViewer.setRotate180(MatchController.getView() != null && MatchController.getView().isTopHumanPlayerActive());
Forge.openScreen(deckViewer); Forge.openScreen(deckViewer);

View File

@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import forge.GuiBase; import forge.GuiBase;
import forge.assets.ImageCache;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.deck.Deck; import forge.deck.Deck;
import forge.deck.DeckSection; import forge.deck.DeckSection;
@@ -625,6 +626,10 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
if (isNewPanel) { if (isNewPanel) {
panel.setVisible(true); panel.setVisible(true);
} }
if (Forge.gameInProgress) {
/*preload deck to cache*/
ImageCache.preloadCache(decks[i]);
}
Gdx.graphics.requestRendering(); Gdx.graphics.requestRendering();
} }
else if (hasPanel) { else if (hasPanel) {

View File

@@ -445,7 +445,6 @@ public class MatchController extends AbstractGuiGame {
@Override @Override
public void afterGameEnd() { public void afterGameEnd() {
Forge.back(); Forge.back();
ImageCache.disposeTexture();
//view = null; //view = null;
} }

View File

@@ -1,7 +1,6 @@
package forge.screens.match.winlose; package forge.screens.match.winlose;
import forge.Forge; import forge.Forge;
import forge.assets.ImageCache;
import forge.game.GameView; import forge.game.GameView;
import forge.game.player.PlayerView; import forge.game.player.PlayerView;
import forge.screens.match.MatchController; import forge.screens.match.MatchController;
@@ -85,7 +84,6 @@ public class ControlWinLose {
view.hide(); view.hide();
if(humancount == 0) { if(humancount == 0) {
Forge.back(); Forge.back();
ImageCache.disposeTexture();
} }
} }

View File

@@ -10,6 +10,7 @@ import forge.Graphics;
import forge.assets.FImage; import forge.assets.FImage;
import forge.assets.FSkinColor; import forge.assets.FSkinColor;
import forge.assets.FSkinFont; import forge.assets.FSkinFont;
import forge.assets.ImageCache;
import forge.card.CardFaceSymbols; import forge.card.CardFaceSymbols;
import forge.card.CardRenderer; import forge.card.CardRenderer;
import forge.card.ColorSet; import forge.card.ColorSet;
@@ -76,6 +77,8 @@ public class ConquestCommandersScreen extends FScreen {
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
final ConquestCommander commander = lstCommanders.getSelectedItem(); final ConquestCommander commander = lstCommanders.getSelectedItem();
if (commander != null) { if (commander != null) {
/*preload deck to cache*/
ImageCache.preloadCache(commander.getDeck());
preventRefreshOnActivate = true; //refresh not needed since deck changes won't affect commander display preventRefreshOnActivate = true; //refresh not needed since deck changes won't affect commander display
Forge.openScreen(new ConquestDeckEditor(commander)); Forge.openScreen(new ConquestDeckEditor(commander));
} }

View File

@@ -4,6 +4,7 @@ import com.badlogic.gdx.utils.Align;
import forge.FThreads; import forge.FThreads;
import forge.Forge; import forge.Forge;
import forge.assets.FSkinFont; import forge.assets.FSkinFont;
import forge.assets.ImageCache;
import forge.deck.DeckProxy; import forge.deck.DeckProxy;
import forge.deck.DeckgenUtil; import forge.deck.DeckgenUtil;
import forge.deck.FDeckChooser; import forge.deck.FDeckChooser;
@@ -152,6 +153,9 @@ public class QuestDecksScreen extends FScreen {
final DeckProxy deck = lstDecks.getSelectedItem(); final DeckProxy deck = lstDecks.getSelectedItem();
if (deck == null) { return; } if (deck == null) { return; }
/*preload deck to cache*/
ImageCache.preloadCache(deck.getDeck());
needRefreshOnActivate = true; needRefreshOnActivate = true;
Forge.openScreen(new QuestDeckEditor(deck)); Forge.openScreen(new QuestDeckEditor(deck));
} }

View File

@@ -9,6 +9,7 @@ import forge.GuiBase;
import forge.assets.FSkinColor; import forge.assets.FSkinColor;
import forge.assets.FSkinFont; import forge.assets.FSkinFont;
import forge.assets.FSkinImage; import forge.assets.FSkinImage;
import forge.assets.ImageCache;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.deck.Deck; import forge.deck.Deck;
import forge.deck.DeckGroup; import forge.deck.DeckGroup;
@@ -241,6 +242,8 @@ public class QuestTournamentsScreen extends QuestLaunchScreen implements IQuestT
public void editDeck(boolean isExistingDeck) { public void editDeck(boolean isExistingDeck) {
Deck deck = getDeck(); Deck deck = getDeck();
if (deck != null) { if (deck != null) {
/*preload deck to cache*/
ImageCache.preloadCache(deck);
if (isExistingDeck) { if (isExistingDeck) {
Forge.openScreen(new QuestDraftDeckEditor(deck.getName())); Forge.openScreen(new QuestDraftDeckEditor(deck.getName()));
} }

View File

@@ -60,16 +60,9 @@ public class FButton extends FDisplayObject implements IButton {
} }
private void resetImg() { private void resetImg() {
if (hdbuttonskin()) imgL = (hdbuttonskin() && FSkinImage.HDBTN_UP_LEFT != null) ? FSkinImage.HDBTN_UP_LEFT : FSkinImage.BTN_UP_LEFT;
{ imgM = (hdbuttonskin() && FSkinImage.HDBTN_UP_CENTER != null) ? FSkinImage.HDBTN_UP_CENTER : FSkinImage.BTN_UP_CENTER;
imgL = FSkinImage.HDBTN_UP_LEFT; imgR = (hdbuttonskin() && FSkinImage.HDBTN_UP_RIGHT != null) ? FSkinImage.HDBTN_UP_RIGHT : FSkinImage.BTN_UP_RIGHT;
imgM = FSkinImage.HDBTN_UP_CENTER;
imgR = FSkinImage.HDBTN_UP_RIGHT;
} else {
imgL = FSkinImage.BTN_UP_LEFT;
imgM = FSkinImage.BTN_UP_CENTER;
imgR = FSkinImage.BTN_UP_RIGHT;
}
} }
public String getText() { public String getText() {
@@ -95,16 +88,9 @@ public class FButton extends FDisplayObject implements IButton {
resetImg(); resetImg();
} }
else { else {
if (hdbuttonskin()) imgL = (hdbuttonskin() && FSkinImage.HDBTN_UP_LEFT != null) ? FSkinImage.HDBTN_UP_LEFT : FSkinImage.BTN_UP_LEFT;
{ imgM = (hdbuttonskin() && FSkinImage.HDBTN_UP_CENTER != null) ? FSkinImage.HDBTN_UP_CENTER : FSkinImage.BTN_UP_CENTER;
imgL = FSkinImage.HDBTN_DISABLED_LEFT; imgR = (hdbuttonskin() && FSkinImage.HDBTN_UP_RIGHT != null) ? FSkinImage.HDBTN_UP_RIGHT : FSkinImage.BTN_UP_RIGHT;
imgM = FSkinImage.HDBTN_DISABLED_CENTER;
imgR = FSkinImage.HDBTN_DISABLED_RIGHT;
} else {
imgL = FSkinImage.BTN_DISABLED_LEFT;
imgM = FSkinImage.BTN_DISABLED_CENTER;
imgR = FSkinImage.BTN_DISABLED_RIGHT;
}
} }
} }
@@ -121,31 +107,17 @@ public class FButton extends FDisplayObject implements IButton {
toggled = b0; toggled = b0;
if (toggled) { if (toggled) {
if (hdbuttonskin()) imgL = (hdbuttonskin() && FSkinImage.HDBTN_UP_LEFT != null) ? FSkinImage.HDBTN_UP_LEFT : FSkinImage.BTN_UP_LEFT;
{ imgM = (hdbuttonskin() && FSkinImage.HDBTN_UP_CENTER != null) ? FSkinImage.HDBTN_UP_CENTER : FSkinImage.BTN_UP_CENTER;
imgL = FSkinImage.HDBTN_TOGGLE_LEFT; imgR = (hdbuttonskin() && FSkinImage.HDBTN_UP_RIGHT != null) ? FSkinImage.HDBTN_UP_RIGHT : FSkinImage.BTN_UP_RIGHT;
imgM = FSkinImage.HDBTN_TOGGLE_CENTER;
imgR = FSkinImage.HDBTN_TOGGLE_RIGHT;
} else {
imgL = FSkinImage.BTN_TOGGLE_LEFT;
imgM = FSkinImage.BTN_TOGGLE_CENTER;
imgR = FSkinImage.BTN_TOGGLE_RIGHT;
}
} }
else if (isEnabled()) { else if (isEnabled()) {
resetImg(); resetImg();
} }
else { else {
if (hdbuttonskin()) imgL = (hdbuttonskin() && FSkinImage.HDBTN_UP_LEFT != null) ? FSkinImage.HDBTN_UP_LEFT : FSkinImage.BTN_UP_LEFT;
{ imgM = (hdbuttonskin() && FSkinImage.HDBTN_UP_CENTER != null) ? FSkinImage.HDBTN_UP_CENTER : FSkinImage.BTN_UP_CENTER;
imgL = FSkinImage.HDBTN_DISABLED_LEFT; imgR = (hdbuttonskin() && FSkinImage.HDBTN_UP_RIGHT != null) ? FSkinImage.HDBTN_UP_RIGHT : FSkinImage.BTN_UP_RIGHT;
imgM = FSkinImage.HDBTN_DISABLED_CENTER;
imgR = FSkinImage.HDBTN_DISABLED_RIGHT;
} else {
imgL = FSkinImage.BTN_DISABLED_LEFT;
imgM = FSkinImage.BTN_DISABLED_CENTER;
imgR = FSkinImage.BTN_DISABLED_RIGHT;
}
} }
} }
@@ -171,16 +143,9 @@ public class FButton extends FDisplayObject implements IButton {
public final boolean press(float x, float y) { public final boolean press(float x, float y) {
if (isToggled()) { return true; } if (isToggled()) { return true; }
if (hdbuttonskin()) imgL = (hdbuttonskin() && FSkinImage.HDBTN_UP_LEFT != null) ? FSkinImage.HDBTN_UP_LEFT : FSkinImage.BTN_UP_LEFT;
{ imgM = (hdbuttonskin() && FSkinImage.HDBTN_UP_CENTER != null) ? FSkinImage.HDBTN_UP_CENTER : FSkinImage.BTN_UP_CENTER;
imgL = FSkinImage.HDBTN_DOWN_LEFT; imgR = (hdbuttonskin() && FSkinImage.HDBTN_UP_RIGHT != null) ? FSkinImage.HDBTN_UP_RIGHT : FSkinImage.BTN_UP_RIGHT;
imgM = FSkinImage.HDBTN_DOWN_CENTER;
imgR = FSkinImage.HDBTN_DOWN_RIGHT;
} else {
imgL = FSkinImage.BTN_DOWN_LEFT;
imgM = FSkinImage.BTN_DOWN_CENTER;
imgR = FSkinImage.BTN_DOWN_RIGHT;
}
return true; return true;
} }