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() {
Texture image = ImageCache.getImage(key, false);
if (image == null) {
if (!ImageCache.imageKeyFileExists(key)) {
fetcher.fetchImage(key, this);
}
}

View File

@@ -70,6 +70,7 @@ public class Forge implements ApplicationListener {
public static boolean hdbuttons = false;
public static boolean hdstart = 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) {
if (GuiBase.getInterface() == null) {
@@ -159,12 +160,12 @@ public class Forge implements ApplicationListener {
private void preloadExtendedArt() {
if (!enablePreloadExtendedArt)
return;
List<String> BorderlessCardlistkeys = FileUtil.readFile(ForgeConstants.BORDERLESS_CARD_LIST_FILE);
if(BorderlessCardlistkeys.isEmpty())
List<String> borderlessCardlistkeys = FileUtil.readFile(ForgeConstants.BORDERLESS_CARD_LIST_FILE);
if(borderlessCardlistkeys.isEmpty())
return;
List<String> filteredkeys = new ArrayList<>();
for (String cardname : BorderlessCardlistkeys){
File image = new File(ForgeConstants.CACHE_CARD_PICS_DIR+"/"+cardname+".jpg");
for (String cardname : borderlessCardlistkeys){
File image = new File(ForgeConstants.CACHE_CARD_PICS_DIR+ForgeConstants.PATH_SEPARATOR+cardname+".jpg");
if (image.exists())
filteredkeys.add(cardname);
}
@@ -393,18 +394,14 @@ public class Forge implements ApplicationListener {
}
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 {
endKeyInput(); //end key input 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.setSize(screenWidth, screenHeight);
currentScreen.onActivate();

View File

@@ -275,6 +275,20 @@ public class FSkin {
}
}
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();

View File

@@ -30,20 +30,23 @@ import com.google.common.cache.RemovalNotification;
import forge.ImageKeys;
import forge.card.CardEdition;
import forge.card.CardRenderer;
import forge.deck.Deck;
import forge.game.card.CardView;
import forge.game.player.IHasIcon;
import forge.item.IPaperCard;
import forge.item.InventoryItem;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.properties.ForgeConstants;
import forge.util.ImageUtil;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
@@ -73,6 +76,7 @@ public class ImageCache {
if(removalNotification.wasEvicted()||removalNotification.getCause() == RemovalCause.EXPIRED) {
removalNotification.getValue().dispose();
}
CardRenderer.clearcardArtCache();
}
})
.build(new ImageLoader());
@@ -104,15 +108,6 @@ public class ImageCache {
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) {
return getImage(ii.getImageKey(false), true);
}
@@ -131,6 +126,39 @@ public class ImageCache {
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.
* If the image does not exist then it can return a default image if desired.
@@ -191,12 +219,20 @@ public class ImageCache {
return image;
}
public static void preloadCache(Iterable<String> keys) {
try {
cache.getAll(keys);
} catch (ExecutionException e) {
e.printStackTrace();
for (String imageKey : keys){
if(getImage(imageKey, false) == null)
System.err.println("could not load card image:"+imageKey);
}
}
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) {
if (!image.toString().contains(".fullborder."))
return new TextureRegion(image);

View File

@@ -3,6 +3,7 @@ package forge.deck;
import forge.FThreads;
import forge.Forge;
import forge.GuiBase;
import forge.assets.ImageCache;
import forge.deck.FDeckEditor.EditorType;
import forge.deck.io.DeckPreferences;
import forge.error.BugReporter;
@@ -472,6 +473,8 @@ public class FDeckChooser extends FScreen {
break;
}
needRefreshOnActivate = true;
/*preload deck to cache*/
ImageCache.preloadCache(deck.getDeck());
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.FSkinImage;
import forge.assets.FTextureRegionImage;
import forge.assets.ImageCache;
import forge.item.PaperCard;
import forge.itemmanager.CardManager;
import forge.itemmanager.ItemManagerConfig;
@@ -112,6 +113,9 @@ public class FDeckViewer extends FScreen {
public static void show(final Deck deck0) {
if (deck0 == null) { return; }
/*preload deck to cache*/
ImageCache.preloadCache(deck0);
deckViewer = new FDeckViewer(deck0);
deckViewer.setRotate180(MatchController.getView() != null && MatchController.getView().isTopHumanPlayerActive());
Forge.openScreen(deckViewer);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -60,16 +60,9 @@ public class FButton extends FDisplayObject implements IButton {
}
private void resetImg() {
if (hdbuttonskin())
{
imgL = FSkinImage.HDBTN_UP_LEFT;
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;
}
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;
imgR = (hdbuttonskin() && FSkinImage.HDBTN_UP_RIGHT != null) ? FSkinImage.HDBTN_UP_RIGHT : FSkinImage.BTN_UP_RIGHT;
}
public String getText() {
@@ -95,16 +88,9 @@ public class FButton extends FDisplayObject implements IButton {
resetImg();
}
else {
if (hdbuttonskin())
{
imgL = FSkinImage.HDBTN_DISABLED_LEFT;
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;
}
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;
imgR = (hdbuttonskin() && FSkinImage.HDBTN_UP_RIGHT != null) ? FSkinImage.HDBTN_UP_RIGHT : FSkinImage.BTN_UP_RIGHT;
}
}
@@ -121,31 +107,17 @@ public class FButton extends FDisplayObject implements IButton {
toggled = b0;
if (toggled) {
if (hdbuttonskin())
{
imgL = FSkinImage.HDBTN_TOGGLE_LEFT;
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;
}
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;
imgR = (hdbuttonskin() && FSkinImage.HDBTN_UP_RIGHT != null) ? FSkinImage.HDBTN_UP_RIGHT : FSkinImage.BTN_UP_RIGHT;
}
else if (isEnabled()) {
resetImg();
}
else {
if (hdbuttonskin())
{
imgL = FSkinImage.HDBTN_DISABLED_LEFT;
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;
}
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;
imgR = (hdbuttonskin() && FSkinImage.HDBTN_UP_RIGHT != null) ? FSkinImage.HDBTN_UP_RIGHT : FSkinImage.BTN_UP_RIGHT;
}
}
@@ -171,16 +143,9 @@ public class FButton extends FDisplayObject implements IButton {
public final boolean press(float x, float y) {
if (isToggled()) { return true; }
if (hdbuttonskin())
{
imgL = FSkinImage.HDBTN_DOWN_LEFT;
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;
}
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;
imgR = (hdbuttonskin() && FSkinImage.HDBTN_UP_RIGHT != null) ? FSkinImage.HDBTN_UP_RIGHT : FSkinImage.BTN_UP_RIGHT;
return true;
}