diff --git a/forge-game/src/main/java/forge/game/ability/effects/BlockEffect.java b/forge-game/src/main/java/forge/game/ability/effects/BlockEffect.java index 5737a68e3e2..9d96e0cff20 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/BlockEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/BlockEffect.java @@ -11,6 +11,7 @@ import forge.game.Game; import forge.game.spellability.SpellAbility; import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; +import org.apache.commons.lang3.StringUtils; import java.util.*; @@ -106,7 +107,7 @@ public class BlockEffect extends SpellAbilityEffect { } } - sb.append(String.join(", ", blockers)).append(" block ").append(String.join(", ", attackers)); + sb.append(StringUtils.join(blockers.toArray(), ", ")).append(" block ").append(StringUtils.join(attackers.toArray(), ", ")); return sb.toString(); } diff --git a/forge-gui-android/pom.xml b/forge-gui-android/pom.xml index 7708708406e..ebc8f35f90f 100644 --- a/forge-gui-android/pom.xml +++ b/forge-gui-android/pom.xml @@ -104,6 +104,24 @@ gdx-backend-android 1.9.10 + + org.cache2k + cache2k-base-bom + 1.2.4.Final + pom + + + org.cache2k + cache2k-core + 1.2.4.Final + compile + + + org.cache2k + cache2k-api + 1.2.4.Final + compile + diff --git a/forge-gui-android/proguard.cfg b/forge-gui-android/proguard.cfg index e6a1ef032c5..159c6a4348c 100644 --- a/forge-gui-android/proguard.cfg +++ b/forge-gui-android/proguard.cfg @@ -28,6 +28,20 @@ -dontwarn org.slf4j.** -dontwarn javax.** +# mandatory proguard rules for cache2k to keep the core implementation +-dontwarn org.cache2k.impl.xmlConfiguration.** +-dontwarn org.cache2k.impl.serverSide.** +-keep interface org.cache2k.spi.Cache2kCoreProvider +-keep public class * extends org.cache2k.spi.Cache2kCoreProvider +# optional proguard rules for cache2k, to keep XML configuration code +# if only programmatic configuration is used, these rules may be ommitted +-keep interface org.cache2k.core.spi.CacheConfigurationProvider +-keep public class * extends org.cache2k.core.spi.CacheConfigurationProvider +-keepclassmembers public class * extends org.cache2k.configuration.ConfigurationBean { + public void set*(...); + public ** get*(); +} + -keep class forge.** { *; } -keep class com.thoughtworks.xstream.** { *; } -keep class org.apache.commons.lang3.** { *; } diff --git a/forge-gui-ios/pom.xml b/forge-gui-ios/pom.xml index 21539d4c17e..a48dfcb7641 100644 --- a/forge-gui-ios/pom.xml +++ b/forge-gui-ios/pom.xml @@ -75,5 +75,23 @@ gdx-backend-robovm 1.9.10 + + org.cache2k + cache2k-base-bom + 1.2.4.Final + pom + + + org.cache2k + cache2k-core + 1.2.4.Final + compile + + + org.cache2k + cache2k-api + 1.2.4.Final + compile + diff --git a/forge-gui-mobile-dev/pom.xml b/forge-gui-mobile-dev/pom.xml index c515dd9a240..4591747ecb1 100644 --- a/forge-gui-mobile-dev/pom.xml +++ b/forge-gui-mobile-dev/pom.xml @@ -80,5 +80,23 @@ commons-cli 1.4 + + org.cache2k + cache2k-base-bom + 1.2.4.Final + pom + + + org.cache2k + cache2k-core + 1.2.4.Final + compile + + + org.cache2k + cache2k-api + 1.2.4.Final + compile + diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml index a3e0183dd9c..f21a549db0e 100644 --- a/forge-gui-mobile/pom.xml +++ b/forge-gui-mobile/pom.xml @@ -70,6 +70,24 @@ gdx-freetype 1.9.10 + + org.cache2k + cache2k-base-bom + 1.2.4.Final + pom + + + org.cache2k + cache2k-core + 1.2.4.Final + compile + + + org.cache2k + cache2k-api + 1.2.4.Final + compile + diff --git a/forge-gui-mobile/src/forge/CachedCardImage.java b/forge-gui-mobile/src/forge/CachedCardImage.java index a58ffff4a27..91fad648edd 100644 --- a/forge-gui-mobile/src/forge/CachedCardImage.java +++ b/forge-gui-mobile/src/forge/CachedCardImage.java @@ -34,7 +34,11 @@ public abstract class CachedCardImage implements ImageFetcher.Callback { } public Texture getImage() { - return ImageCache.getImage(key, true); + return ImageCache.getImage(key, true, false); + } + + public Texture getImage(boolean mask) { + return ImageCache.getImage(key, true, mask); } public abstract void onImageFetched(); diff --git a/forge-gui-mobile/src/forge/assets/ImageCache.java b/forge-gui-mobile/src/forge/assets/ImageCache.java index 6245e4ef2a4..a26cbc204d6 100644 --- a/forge-gui-mobile/src/forge/assets/ImageCache.java +++ b/forge-gui-mobile/src/forge/assets/ImageCache.java @@ -20,18 +20,17 @@ package forge.assets; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Pixmap.Format; import com.badlogic.gdx.graphics.Texture; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.LoadingCache; import forge.ImageKeys; import forge.game.player.IHasIcon; import forge.item.InventoryItem; import forge.properties.ForgeConstants; import forge.util.ImageUtil; import org.apache.commons.lang3.StringUtils; +import org.cache2k.Cache; +import org.cache2k.Cache2kBuilder; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; /** @@ -52,10 +51,14 @@ public class ImageCache { // short prefixes to save memory private static final Set missingIconKeys = new HashSet<>(); - private static final LoadingCache cache = CacheBuilder.newBuilder() - .maximumSize(400) - .expireAfterAccess(15,TimeUnit.MINUTES) - .build(new ImageLoader()); + private static final Cache cache = new Cache2kBuilder() {} + .name("cache") + .entryCapacity(500) + .expireAfterWrite(15, TimeUnit.MINUTES) + .refreshAhead(true) + .permitNullValues(true) + .loader(new ImageLoader()) + .build(); public static final Texture defaultImage; private static boolean imageLoaded, delayLoadRequested; @@ -76,12 +79,16 @@ public class ImageCache { } public static void clear() { - cache.invalidateAll(); + cache.clear(); missingIconKeys.clear(); } public static Texture getImage(InventoryItem ii) { - return getImage(ii.getImageKey(false), true); + return getImage(ii.getImageKey(false), true, false); + } + + public static Texture getImage(InventoryItem ii, Boolean mask) { + return getImage(ii.getImageKey(false), true, mask); } /** @@ -107,6 +114,9 @@ public class ImageCache { *

*/ public static Texture getImage(String imageKey, boolean useDefaultIfNotFound) { + return getImage(imageKey, useDefaultIfNotFound, false); + } + public static Texture getImage(String imageKey, boolean useDefaultIfNotFound, boolean maskCard) { if (StringUtils.isEmpty(imageKey)) { return null; } @@ -125,7 +135,10 @@ public class ImageCache { Texture image; if (useDefaultIfNotFound) { // Load from file and add to cache if not found in cache initially. - image = cache.getIfPresent(imageKey); + if (maskCard)//if we add pixmap modification here, it will slow performance so we do this on the image loader lol :)... + imageKey += "#drawroundcorner#"; + image = cache.get(imageKey); + if (image != null) { return image; } if (imageLoaded) { //prevent loading more than one image each render for performance @@ -139,15 +152,7 @@ public class ImageCache { imageLoaded = true; } - try { - image = cache.get(imageKey); - } - catch (final ExecutionException ex) { - if (!(ex.getCause() instanceof NullPointerException)) { - ex.printStackTrace(); - } - image = null; - } + try { image = cache.get(imageKey); } catch (final Exception ex) { image = null; } diff --git a/forge-gui-mobile/src/forge/assets/ImageLoader.java b/forge-gui-mobile/src/forge/assets/ImageLoader.java index e8668c6862f..968a6f8b0c1 100644 --- a/forge-gui-mobile/src/forge/assets/ImageLoader.java +++ b/forge-gui-mobile/src/forge/assets/ImageLoader.java @@ -3,8 +3,12 @@ package forge.assets; import java.io.File; import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; -import com.google.common.cache.CacheLoader; +import com.badlogic.gdx.graphics.TextureData; +import com.badlogic.gdx.graphics.glutils.PixmapTextureData; +import org.cache2k.integration.CacheLoader; import forge.Forge; import forge.ImageKeys; @@ -12,27 +16,49 @@ import forge.ImageKeys; final class ImageLoader extends CacheLoader { @Override public Texture load(String key) { - File file = ImageKeys.getImageFile(key); + boolean mask = key.contains("#drawroundcorner#"); + boolean alphaCard = false; + boolean textureFilter = Forge.isTextureFilteringEnabled(); + if (key.length() > 4){ + if ((key.substring(0,4).contains("LEA/")) || (key.substring(0,2).contains("A/"))) + alphaCard = true; + //TODO dont add border on some sets??? + } + File file = ImageKeys.getImageFile(key.replaceAll("#drawroundcorner#","")); if (file != null) { FileHandle fh = new FileHandle(file); try { - if (Forge.isTextureFilteringEnabled()) { - Texture t = new Texture(fh, true); - t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); - - /* // Optional experimental feature: Anisotropic filtering - GL20 gl = Gdx.gl20; - if (gl != null && Gdx.graphics.supportsExtension("GL_EXT_texture_filter_anisotropic")) { - FloatBuffer buffer = BufferUtils.newFloatBuffer(16); - gl.glGetFloatv(GL20.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, buffer); - float maxAniso = buffer.get(0); - - t.bind(); - gl.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAniso); - } */ + Texture t; + if (mask) { + Pixmap pImage = new Pixmap(fh); + int w = pImage.getWidth(); + int h = pImage.getHeight(); + int radius = alphaCard ? (h - w) / 6 : (h - w) / 8; + Pixmap pMask = createRoundedRectangle(w, h, radius, Color.RED); + drawPixelstoMask(pImage, pMask); + TextureData textureData = new PixmapTextureData( + pMask, //pixmap to use + Pixmap.Format.RGBA8888, + textureFilter, //use mipmaps + false, true); + if (textureFilter) + { + t = new Texture(textureData); + t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); + } else { + t = new Texture(textureData); + } + pImage.dispose(); + pMask.dispose(); return t; } else { - return new Texture(fh); + if (textureFilter) { + t = new Texture(fh, true); + t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); + return t; + } + else + return new Texture(fh); } } catch (Exception ex) { @@ -41,4 +67,57 @@ final class ImageLoader extends CacheLoader { } return null; } + public Pixmap createRoundedRectangle(int width, int height, int cornerRadius, Color color) { + Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888); + Pixmap ret = new Pixmap(width, height, Pixmap.Format.RGBA8888); + pixmap.setColor(color); + //round corners + pixmap.fillCircle(cornerRadius, cornerRadius, cornerRadius); + pixmap.fillCircle(width - cornerRadius - 1, cornerRadius, cornerRadius); + pixmap.fillCircle(cornerRadius, height - cornerRadius - 1, cornerRadius); + pixmap.fillCircle(width - cornerRadius - 1, height - cornerRadius - 1, cornerRadius); + //two rectangle parts + pixmap.fillRectangle(cornerRadius, 0, width - cornerRadius * 2, height); + pixmap.fillRectangle(0, cornerRadius, width, height - cornerRadius * 2); + //draw rounded rectangle + ret.setColor(color); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + if (pixmap.getPixel(x, y) != 0) ret.drawPixel(x, y); + } + } + pixmap.dispose(); + return ret; + } + public void drawPixelstoMask(Pixmap pixmap, Pixmap mask){ + int pixmapWidth = mask.getWidth(); + int pixmapHeight = mask.getHeight(); + Color pixelColor = new Color(); + for (int x=0; x { localizer.getMessage("lblDisableCardEffect"), localizer.getMessage("nlDisableCardEffect")), 4); + lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_BORDER_MASKING, + "Enable Round Border Mask", + "When enabled, the card corners are rounded (Longer Caching)."), + 4); lstSettings.addItem(new CustomSelectSetting(FPref.UI_CARD_COUNTER_DISPLAY_TYPE, localizer.getMessage("cbpCounterDisplayType"), diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java index b6dcf1be167..a43681bbcd1 100644 --- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java @@ -134,6 +134,7 @@ public class ForgePreferences extends PreferencesStore { UI_ROTATE_SPLIT_CARDS("true"), UI_DYNAMIC_PLANECHASE_BG("false"), UI_DISABLE_IMAGES_EFFECT_CARDS("false"), + UI_ENABLE_BORDER_MASKING("false"), UI_ALLOW_ORDER_GRAVEYARD_WHEN_NEEDED ("Never"), UI_DEFAULT_FONT_SIZE("12"), UI_SELECT_FROM_CARD_DISPLAYS("true"),