Merge pull request #8333 from kevlahnota/master3

update progressbar, update boosterdraft readfile
This commit is contained in:
kevlahnota
2025-08-08 22:01:42 +08:00
committed by GitHub
14 changed files with 56 additions and 620 deletions

View File

@@ -48,7 +48,6 @@ import forge.sound.SoundSystem;
import forge.toolbox.*; import forge.toolbox.*;
import forge.util.*; import forge.util.*;
import java.io.File;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.*; import java.util.*;
@@ -102,7 +101,6 @@ public class Forge implements ApplicationListener {
public static boolean animatedCardTapUntap = false; public static boolean animatedCardTapUntap = false;
public static String enableUIMask = "Crop"; public static String enableUIMask = "Crop";
public static String selector = "Default"; public static String selector = "Default";
public static boolean enablePreloadExtendedArt = false;
public static boolean isTabletDevice = false; public static boolean isTabletDevice = false;
public static String locale = "en-US"; public static String locale = "en-US";
public Assets assets; public Assets assets;
@@ -219,7 +217,6 @@ public class Forge implements ApplicationListener {
enableUIMask = "Full"; enableUIMask = "Full";
else if (getForgePreferences().getPref(FPref.UI_ENABLE_BORDER_MASKING).equals("false")) else if (getForgePreferences().getPref(FPref.UI_ENABLE_BORDER_MASKING).equals("false"))
enableUIMask = "Off"; enableUIMask = "Off";
enablePreloadExtendedArt = getForgePreferences().getPrefBoolean(FPref.UI_ENABLE_PRELOAD_EXTENDED_ART);
locale = getForgePreferences().getPref(FPref.UI_LANGUAGE); locale = getForgePreferences().getPref(FPref.UI_LANGUAGE);
autoCache = getForgePreferences().getPrefBoolean(FPref.UI_AUTO_CACHE_SIZE); autoCache = getForgePreferences().getPrefBoolean(FPref.UI_AUTO_CACHE_SIZE);
disposeTextures = getForgePreferences().getPrefBoolean(FPref.UI_ENABLE_DISPOSE_TEXTURES); disposeTextures = getForgePreferences().getPrefBoolean(FPref.UI_ENABLE_DISPOSE_TEXTURES);
@@ -244,27 +241,8 @@ public class Forge implements ApplicationListener {
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblLoadingCardTranslations")); getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblLoadingCardTranslations"));
CardTranslation.preloadTranslation(locale, ForgeConstants.LANG_DIR); CardTranslation.preloadTranslation(locale, ForgeConstants.LANG_DIR);
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblFinishingStartup")); getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblPrepareDatabase"));
Gdx.app.postRunnable(this::afterDbLoaded);
//add reminder to preload
if (enablePreloadExtendedArt) {
if (autoCache)
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblPreloadExtendedArt") + "\nDetected RAM: " + totalDeviceRAM + "MB. Cache size: " + cacheSize);
else
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblPreloadExtendedArt"));
} else {
if (autoCache)
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblFinishingStartup") + "\nDetected RAM: " + totalDeviceRAM + "MB. Cache size: " + cacheSize);
else
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblFinishingStartup"));
}
Gdx.app.postRunnable(() -> {
afterDbLoaded();
/* call preloadExtendedArt here, if we put it above we will *
* get error: No OpenGL context found in the current thread. */
preloadExtendedArt();
});
}; };
//see if app or assets need updating //see if app or assets need updating
FThreads.invokeInBackgroundThread(() -> AssetsDownloader.checkForUpdates(exited, runnable)); FThreads.invokeInBackgroundThread(() -> AssetsDownloader.checkForUpdates(exited, runnable));
@@ -303,22 +281,6 @@ public class Forge implements ApplicationListener {
return currentScene; return currentScene;
} }
private void preloadExtendedArt() {
if (!enablePreloadExtendedArt || !enableUIMask.equals("Full"))
return;
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 + ForgeConstants.PATH_SEPARATOR + cardname + ".jpg");
if (image.exists())
filteredkeys.add(cardname);
}
if (!filteredkeys.isEmpty())
ImageCache.getInstance().preloadCache(filteredkeys);
}
private void preloadBoosterDrafts() { private void preloadBoosterDrafts() {
//preloading of custom drafts //preloading of custom drafts
BoosterDraft.initializeCustomDrafts(); BoosterDraft.initializeCustomDrafts();
@@ -384,6 +346,10 @@ public class Forge implements ApplicationListener {
} }
} }
protected void afterDbLoaded() { protected void afterDbLoaded() {
if (GuiBase.isAndroid() && autoCache)
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblFinishingStartup") + "\nDetected RAM: " + totalDeviceRAM + "MB. Cache size: " + cacheSize);
else
getSplashScreen().getProgressBar().setDescription(getLocalizer().getMessage("lblFinishingStartup"));
//override transition & title bg //override transition & title bg
try { try {
FileHandle transitionFile = Config.instance().getFile("ui/transition.png"); FileHandle transitionFile = Config.instance().getFile("ui/transition.png");

View File

@@ -20,7 +20,6 @@ package forge.assets;
import java.io.File; import java.io.File;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
@@ -33,8 +32,6 @@ import com.google.common.collect.Sets;
import forge.deck.DeckProxy; import forge.deck.DeckProxy;
import forge.gui.GuiBase; import forge.gui.GuiBase;
import forge.item.PaperToken; import forge.item.PaperToken;
import forge.util.FileUtil;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@@ -74,7 +71,6 @@ import forge.util.ImageUtil;
public class ImageCache { public class ImageCache {
private static ImageCache imageCache; private static ImageCache imageCache;
private Supplier<HashSet<String>> missingIconKeys = Suppliers.memoize(HashSet::new); private Supplier<HashSet<String>> missingIconKeys = Suppliers.memoize(HashSet::new);
private final List<String> borderlessCardlistKey = FileUtil.readFile(ForgeConstants.BORDERLESS_CARD_LIST_FILE);
public int counter = 0; public int counter = 0;
private int maxCardCapacity = 300; //default card capacity private int maxCardCapacity = 300; //default card capacity
private EvictingQueue<String> q; private EvictingQueue<String> q;
@@ -343,7 +339,6 @@ public class ImageCache {
Texture cardTexture = Forge.getAssets().manager().get(fileName, Texture.class, false); Texture cardTexture = Forge.getAssets().manager().get(fileName, Texture.class, false);
//if full bordermasking is enabled, update the border color //if full bordermasking is enabled, update the border color
if (cardTexture != null) { if (cardTexture != null) {
boolean borderless = isBorderless(imageKey);
String setCode = imageKey.split("/")[0].trim().toUpperCase(); String setCode = imageKey.split("/")[0].trim().toUpperCase();
int radius; int radius;
if (setCode.equals("A") || setCode.equals("LEA") || setCode.equals("B") || setCode.equals("LEB")) if (setCode.equals("A") || setCode.equals("LEA") || setCode.equals("B") || setCode.equals("LEB"))
@@ -352,9 +347,7 @@ public class ImageCache {
radius = 25; radius = 25;
else else
radius = 22; radius = 22;
updateImageRecord(cardTexture.toString(), updateImageRecord(cardTexture.toString(), isCloserToWhite(getpixelColor(cardTexture)), radius, cardTexture.toString().contains(".fullborder.") || cardTexture.toString().contains("tokens"));
borderless ? Color.valueOf("#171717").toString() : isCloserToWhite(getpixelColor(cardTexture)).getLeft(),
!borderless && isCloserToWhite(getpixelColor(cardTexture)).getRight(), radius, cardTexture.toString().contains(".fullborder.") || cardTexture.toString().contains("tokens"));
} }
return cardTexture; return cardTexture;
} }
@@ -407,7 +400,7 @@ public class ImageCache {
public void preloadCache(Deck deck) { public void preloadCache(Deck deck) {
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_CARD_IMAGES)) if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_CARD_IMAGES))
return; return;
if (deck == null || !Forge.enablePreloadExtendedArt) if (deck == null)
return; return;
if (deck.getAllCardsInASinglePool().toFlatList().size() <= 100) { if (deck.getAllCardsInASinglePool().toFlatList().size() <= 100) {
for (PaperCard p : deck.getAllCardsInASinglePool().toFlatList()) { for (PaperCard p : deck.getAllCardsInASinglePool().toFlatList()) {
@@ -449,8 +442,8 @@ public class ImageCache {
return 1; return 1;
return 0; return 0;
} }
public void updateImageRecord(String textureString, String colorValue, Boolean isClosertoWhite, int radius, boolean fullborder) { public void updateImageRecord(String textureString, Pair<String, Boolean> data, int radius, boolean fullborder) {
imageRecord.get().put(textureString, new ImageRecord(colorValue, isClosertoWhite, radius, fullborder)); imageRecord.get().put(textureString, new ImageRecord(data.getLeft(), data.getRight(), radius, fullborder));
} }
public int getRadius(Texture t) { public int getRadius(Texture t) {
@@ -522,16 +515,6 @@ public class ImageCache {
return borderColor(t); return borderColor(t);
} }
public boolean isBorderless(String imagekey) {
if (borderlessCardlistKey.isEmpty())
return false;
if (imagekey.length() > 7) {
if ((!imagekey.substring(0, 7).contains("MPS_KLD")) && (imagekey.substring(0, 4).contains("MPS_"))) //MPS_ sets except MPD_KLD
return true;
}
return borderlessCardlistKey.contains(TextUtil.fastReplace(imagekey, ".full", ".fullborder"));
}
public String getpixelColor(Texture i) { public String getpixelColor(Texture i) {
if (!i.getTextureData().isPrepared()) { if (!i.getTextureData().isPrepared()) {
i.getTextureData().prepare(); //prepare texture i.getTextureData().prepare(); //prepare texture

View File

@@ -616,16 +616,6 @@ public class SettingsPage extends TabPage<SettingsScreen> {
ImageCache.getInstance().disposeTextures(); ImageCache.getInstance().disposeTextures();
} }
}, 4); }, 4);
lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_PRELOAD_EXTENDED_ART,
Forge.getLocalizer().getMessage("lblPreloadExtendedArtCards"),
Forge.getLocalizer().getMessage("nlPreloadExtendedArtCards")){
@Override
public void select() {
super.select();
//update
Forge.enablePreloadExtendedArt = FModel.getPreferences().getPrefBoolean(FPref.UI_ENABLE_PRELOAD_EXTENDED_ART);
}
},4);
lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_MATCH_SCROLL_INDICATOR, lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_MATCH_SCROLL_INDICATOR,
Forge.getLocalizer().getMessage("lblMatchScrollIndicator"), Forge.getLocalizer().getMessage("lblMatchScrollIndicator"),
Forge.getLocalizer().getMessage("nlMatchScrollIndicator")), Forge.getLocalizer().getMessage("nlMatchScrollIndicator")),

View File

@@ -3527,4 +3527,6 @@ lblEffectDialogDescription=An diesem Ort fließen seltsame magische Energien...
lblEffectDataHeader=Alle Gegner erhalten: lblEffectDataHeader=Alle Gegner erhalten:
lblDefeatedDescription=Sie sind besiegt und können nicht weitermachen. Mit letzter Kraft versuchen Sie, aus dem Gebiet zu entkommen. lblDefeatedDescription=Sie sind besiegt und können nicht weitermachen. Mit letzter Kraft versuchen Sie, aus dem Gebiet zu entkommen.
lblReversePromptButton=Umgekehrte Eingabeaufforderungsschaltflächen lblReversePromptButton=Umgekehrte Eingabeaufforderungsschaltflächen
nlReversePromptButton=Wenn diese Option aktiviert ist, sind die Schaltflächen „OK“ und „Cancel“ vertauscht. nlReversePromptButton=Wenn diese Option aktiviert ist, sind die Schaltflächen „OK“ und „Cancel“ vertauscht.
lblPrepareDatabase=Datenbank vorbereiten...
lblLoadingGameResources=Spielressourcen werden geladen...

View File

@@ -3274,4 +3274,6 @@ lblEffectDialogDescription=Strange magical energies flow within this place...
lblEffectDataHeader=All opponents get: lblEffectDataHeader=All opponents get:
lblDefeatedDescription=Defeated and unable to continue, you use the last of your power to escape the area. lblDefeatedDescription=Defeated and unable to continue, you use the last of your power to escape the area.
lblReversePromptButton=Reversed Prompt Buttons lblReversePromptButton=Reversed Prompt Buttons
nlReversePromptButton=If enabled, the OK and Cancel Prompt buttons are reversed. nlReversePromptButton=If enabled, the OK and Cancel Prompt buttons are reversed.
lblPrepareDatabase=Preparing database...
lblLoadingGameResources=Loading game resources...

View File

@@ -3531,4 +3531,6 @@ lblEffectDialogDescription=Extrañas energías mágicas fluyen dentro de este lu
lblEffectDataHeader=Todos los oponentes obtienen: lblEffectDataHeader=Todos los oponentes obtienen:
lblDefeatedDescription=Derrotado e incapaz de continuar, utilizas lo último de tu poder para escapar del área. lblDefeatedDescription=Derrotado e incapaz de continuar, utilizas lo último de tu poder para escapar del área.
lblReversePromptButton=Botones de aviso invertidos lblReversePromptButton=Botones de aviso invertidos
nlReversePromptButton=Si esta opción está habilitada, los botones Aceptar y Cancelar solicitud se invierten. nlReversePromptButton=Si esta opción está habilitada, los botones Aceptar y Cancelar solicitud se invierten.
lblPrepareDatabase=Preparando la base de datos...
lblLoadingGameResources=Cargando recursos del juego...

View File

@@ -3532,4 +3532,6 @@ lblEffectDialogDescription=D'étranges énergies magiques circulent dans ce lieu
lblEffectDataHeader=Tous les adversaires obtiennent: lblEffectDataHeader=Tous les adversaires obtiennent:
lblDefeatedDescription=Vaincu et incapable de continuer, vous utilisez le reste de votre pouvoir pour vous échapper de la zone. lblDefeatedDescription=Vaincu et incapable de continuer, vous utilisez le reste de votre pouvoir pour vous échapper de la zone.
lblReversePromptButton=Boutons d'invite inversés lblReversePromptButton=Boutons d'invite inversés
nlReversePromptButton=Si cette option est activée, les boutons OK et Annuler sont inversés. nlReversePromptButton=Si cette option est activée, les boutons OK et Annuler sont inversés.
lblPrepareDatabase=Préparation de la base de données...
lblLoadingGameResources=Chargement des ressources du jeu...

View File

@@ -3530,4 +3530,6 @@ lblEffectDialogDescription=In questo luogo fluiscono strane energie magiche...
lblEffectDataHeader=Tutti gli avversari ottengono: lblEffectDataHeader=Tutti gli avversari ottengono:
lblDefeatedDescription=Sconfitto e impossibilitato a proseguire, usi le ultime energie che ti restano per fuggire dalla zona. lblDefeatedDescription=Sconfitto e impossibilitato a proseguire, usi le ultime energie che ti restano per fuggire dalla zona.
lblReversePromptButton=Pulsanti di richiesta invertiti lblReversePromptButton=Pulsanti di richiesta invertiti
nlReversePromptButton=Se abilitati, i pulsanti OK e Annulla richiesta sono invertiti. nlReversePromptButton=Se abilitati, i pulsanti OK e Annulla richiesta sono invertiti.
lblPrepareDatabase=Preparazione del database...
lblLoadingGameResources=Caricamento delle risorse del gioco...

View File

@@ -3526,4 +3526,6 @@ lblEffectDialogDescription=この場所には不思議な魔力が流れてい
lblEffectDataHeader=対戦相手全員が得るもの: lblEffectDataHeader=対戦相手全員が得るもの:
lblDefeatedDescription=敗北し、続行不可能となったあなたは、最後の力を振り絞ってそのエリアから脱出します。 lblDefeatedDescription=敗北し、続行不可能となったあなたは、最後の力を振り絞ってそのエリアから脱出します。
lblReversePromptButton=逆プロンプトボタン lblReversePromptButton=逆プロンプトボタン
nlReversePromptButton=有効にすると、[OK] ボタンと [Cancel] ボタンが逆になります。 nlReversePromptButton=有効にすると、[OK] ボタンと [Cancel] ボタンが逆になります。
lblPrepareDatabase=データベースを準備しています
lblLoadingGameResources=ゲームリソースを読み込んでいます

View File

@@ -3616,4 +3616,6 @@ lblEffectDialogDescription=Estranhas energias mágicas fluem dentro deste lugar.
lblEffectDataHeader=Todos os oponentes recebem: lblEffectDataHeader=Todos os oponentes recebem:
lblDefeatedDescription=Derrotado e incapaz de continuar, você usa o que resta de seu poder para escapar da área. lblDefeatedDescription=Derrotado e incapaz de continuar, você usa o que resta de seu poder para escapar da área.
lblReversePromptButton=Botões de prompt invertidos lblReversePromptButton=Botões de prompt invertidos
nlReversePromptButton=Se ativados, os botões OK e Cancelar prompt serão invertidos. nlReversePromptButton=Se ativados, os botões OK e Cancelar prompt serão invertidos.
lblPrepareDatabase=Preparando banco de dados...
lblLoadingGameResources=Carregando recursos do jogo...

View File

@@ -3517,4 +3517,6 @@ lblEffectDialogDescription=奇怪的魔法能量在这个地方流动。。。
lblEffectDataHeader=所有对手获得: lblEffectDataHeader=所有对手获得:
lblDefeatedDescription=你被击败了,无法继续前进,你用尽最后的力量逃离了该区域。 lblDefeatedDescription=你被击败了,无法继续前进,你用尽最后的力量逃离了该区域。
lblReversePromptButton=反转提示按钮 lblReversePromptButton=反转提示按钮
nlReversePromptButton=如果启用,则“确定”和“取消提示”按钮将会反转。 nlReversePromptButton=如果启用,则“确定”和“取消提示”按钮将会反转。
lblPrepareDatabase=准备数据库
lblLoadingGameResources=正在加载游戏资源

View File

@@ -1,536 +0,0 @@
2X2/Aether Vial2.fullborder
2X2/Allosaurus Shepherd2.fullborder
2X2/Anger of the Gods2.fullborder
2X2/Assassin's Trophy2.fullborder
2X2/Azorius Chancery2.fullborder
2X2/Blood Artist2.fullborder
2X2/Bloodbraid Elf2.fullborder
2X2/Bloodforged Battle-Axe2.fullborder
2X2/Bloom Tender2.fullborder
2X2/Boros Garrison2.fullborder
2X2/Burning-Tree Emissary2.fullborder
2X2/Cavern of Souls2.fullborder
2X2/Chaos Warp2.fullborder
2X2/City of Brass2.fullborder
2X2/Coiling Oracle2.fullborder
2X2/Concordant Crossroads2.fullborder
2X2/Consecrated Sphinx2.fullborder
2X2/Crucible of Worlds2.fullborder
2X2/Damnation2.fullborder
2X2/Dimir Aqueduct2.fullborder
2X2/Dockside Extortionist2.fullborder
2X2/Dragonlord Dromoka2.fullborder
2X2/Elenda, the Dusk Rose2.fullborder
2X2/Emiel the Blessed2.fullborder
2X2/Emrakul, the Aeons Torn2.fullborder
2X2/Emrakul, the Aeons Torn4.fullborder
2X2/Eternal Witness2.fullborder
2X2/Flickerwisp2.fullborder
2X2/Forbidden Orchard2.fullborder
2X2/Force of Negation2.fullborder
2X2/Gifts Ungiven2.fullborder
2X2/Glimpse the Unthinkable2.fullborder
2X2/Golgari Rot Farm2.fullborder
2X2/Grand Arbiter Augustin IV2.fullborder
2X2/Grim Flayer2.fullborder
2X2/Gruul Turf2.fullborder
2X2/Hardened Scales2.fullborder
2X2/Imperial Seal2.fullborder
2X2/Inquisition of Kozilek2.fullborder
2X2/Izzet Boilerworks2.fullborder
2X2/Kolaghan's Command2.fullborder
2X2/Kozilek, Butcher of Truth2.fullborder
2X2/Kozilek, Butcher of Truth4.fullborder
2X2/Lightning Bolt2.fullborder
2X2/Liliana, the Last Hope2.fullborder
2X2/Liliana, the Last Hope4.fullborder
2X2/Mana Drain2.fullborder
2X2/Mana Vault2.fullborder
2X2/Marchesa, the Black Rose2.fullborder
2X2/Mentor of the Meek2.fullborder
2X2/Monastery Swiftspear2.fullborder
2X2/Muldrotha, the Gravetide2.fullborder
2X2/Mulldrifter2.fullborder
2X2/Oracle of Mul Daya2.fullborder
2X2/Orzhov Basilica2.fullborder
2X2/Panharmonicon2.fullborder
2X2/Phyrexian Altar2.fullborder
2X2/Pithing Needle2.fullborder
2X2/Privileged Position2.fullborder
2X2/Qasali Pridemage2.fullborder
2X2/Rakdos Carnarium2.fullborder
2X2/Rampant Growth2.fullborder
2X2/Seasoned Pyromancer2.fullborder
2X2/Sedris, the Traitor King2.fullborder
2X2/Seeker of the Way2.fullborder
2X2/Selesnya Sanctuary2.fullborder
2X2/Sensei's Divining Top2.fullborder
2X2/Simic Growth Chamber2.fullborder
2X2/Smothering Tithe2.fullborder
2X2/Spell Pierce2.fullborder
2X2/Supreme Verdict2.fullborder
2X2/Surgical Extraction2.fullborder
2X2/Teferi's Protection2.fullborder
2X2/Terminate2.fullborder
2X2/The Mimeoplasm2.fullborder
2X2/Thought Scour2.fullborder
2X2/Thousand-Year Storm2.fullborder
2X2/Ulamog, the Infinite Gyre2.fullborder
2X2/Ulamog, the Infinite Gyre4.fullborder
2X2/Unearth2.fullborder
2X2/Vedalken Orrery2.fullborder
2X2/Wall of Omens2.fullborder
2X2/Wrenn and Six2.fullborder
2X2/Wrenn and Six4.fullborder
2X2/Young Pyromancer2.fullborder
2XM/Academy Ruins2.fullborder
2XM/Atraxa, Praetors' Voice2.fullborder
2XM/Avacyn, Angel of Hope2.fullborder
2XM/Batterskull2.fullborder
2XM/Blightsteel Colossus2.fullborder
2XM/Blood Moon2.fullborder
2XM/Brainstorm2.fullborder
2XM/Chrome Mox2.fullborder
2XM/Council's Judgment2.fullborder
2XM/Crop Rotation2.fullborder
2XM/Cyclonic Rift2.fullborder
2XM/Dark Confidant2.fullborder
2XM/Doubling Season2.fullborder
2XM/Expedition Map2.fullborder
2XM/Exploration2.fullborder
2XM/Fatal Push2.fullborder
2XM/Force of Will2.fullborder
2XM/Goblin Guide2.fullborder
2XM/Jace, the Mind Sculptor2.fullborder
2XM/Kaalia of the Vast2.fullborder
2XM/Karn Liberated2.fullborder
2XM/Lightning Greaves2.fullborder
2XM/Mana Crypt2.fullborder
2XM/Meddling Mage2.fullborder
2XM/Mox Opal2.fullborder
2XM/Noble Hierarch2.fullborder
2XM/Phyrexian Metamorph2.fullborder
2XM/Sneak Attack2.fullborder
2XM/Stoneforge Mystic2.fullborder
2XM/Sword of Body and Mind2.fullborder
2XM/Sword of Feast and Famine2.fullborder
2XM/Sword of Fire and Ice2.fullborder
2XM/Sword of Light and Shadow2.fullborder
2XM/Sword of War and Peace2.fullborder
2XM/Thoughtseize2.fullborder
2XM/Toxic Deluge2.fullborder
2XM/Urza's Mine2.fullborder
2XM/Urza's Power Plant2.fullborder
2XM/Urza's Tower2.fullborder
2XM/Wurmcoil Engine2.fullborder
AFR/Adult Gold Dragon2.fullborder
AFR/Black Dragon2.fullborder
AFR/Blue Dragon2.fullborder
AFR/Ebondeath, Dracolich2.fullborder
AFR/Ellywick Tumblestrum2.fullborder
AFR/Grand Master of Flowers2.fullborder
AFR/Green Dragon2.fullborder
AFR/Icingdeath, Frost Tyrant2.fullborder
AFR/Inferno of the Star Mounts2.fullborder
AFR/Iymrith, Desert Doom2.fullborder
AFR/Lolth, Spider Queen2.fullborder
AFR/Mordenkainen2.fullborder
AFR/Old Gnawbone2.fullborder
AFR/Red Dragon2.fullborder
AFR/Tiamat2.fullborder
AFR/White Dragon2.fullborder
AFR/Zariel, Archduke of Avernus2.fullborder
CLB/Ancient Brass Dragon2.fullborder
CLB/Ancient Bronze Dragon2.fullborder
CLB/Ancient Copper Dragon2.fullborder
CLB/Ancient Gold Dragon2.fullborder
CLB/Ancient Silver Dragon2.fullborder
CLB/Battle Angels of Tyr2.fullborder
CLB/Bramble Sovereign2.fullborder
CLB/Elminster2.fullborder
CLB/Legion Loyalty2.fullborder
CLB/Minsc & Boo, Timeless Heroes2.fullborder
CLB/Nautiloid Ship2.fullborder
CLB/Tasha, the Witch Queen2.fullborder
CLB/Vexing Puzzlebox2.fullborder
CMR/Jeska, Thrice Reborn2.fullborder
CMR/Tevesh Szat, Doom of Fools2.fullborder
ELD/Garruk, Cursed Huntsman2.fullborder
ELD/Oko, Thief of Crowns2.fullborder
ELD/The Royal Scions2.fullborder
IKO/Brokkos, Apex of Forever2.fullborder
IKO/Brokkos, Apex of Forever3.fullborder
IKO/Crystalline Giant3.fullborder
IKO/Cubwarden2.fullborder
IKO/Dirge Bat2.fullborder
IKO/Dirge Bat3.fullborder
IKO/Everquill Phoenix2.fullborder
IKO/Everquill Phoenix3.fullborder
IKO/Gemrazer2.fullborder
IKO/Gemrazer3.fullborder
IKO/Gyruda, Doom of Depths3.fullborder
IKO/Huntmaster Liger2.fullborder
IKO/Huntmaster Liger3.fullborder
IKO/Illuna, Apex of Wishes2.fullborder
IKO/Illuna, Apex of Wishes3.fullborder
IKO/Indatha Triome2.fullborder
IKO/Ketria Triome2.fullborder
IKO/Lukka, Coppercoat Outcast2.fullborder
IKO/Luminous Broodmoth3.fullborder
IKO/Mysterious Egg2.fullborder
IKO/Narset of the Ancient Way2.fullborder
IKO/Nethroi, Apex of Death2.fullborder
IKO/Nethroi, Apex of Death3.fullborder
IKO/Pollywog Symbiote2.fullborder
IKO/Raugrin Triome2.fullborder
IKO/Savai Triome2.fullborder
IKO/Sea-Dasher Octopus2.fullborder
IKO/Snapdax, Apex of the Hunt2.fullborder
IKO/Snapdax, Apex of the Hunt3.fullborder
IKO/Sprite Dragon3.fullborder
IKO/Titanoth Rex2.fullborder
IKO/Vadrok, Apex of Thunder2.fullborder
IKO/Vadrok, Apex of Thunder3.fullborder
IKO/Vivien, Monsters' Advocate2.fullborder
IKO/Void Beckoner2.fullborder
IKO/Yidaro, Wandering Monster3.fullborder
IKO/Zagoth Triome2.fullborder
IKO/Zilortha, Strength Incarnate.fullborder
KHM/Alrund's Epiphany2.fullborder
KHM/Barkchannel Pathway2.fullborder
KHM/Battle Mammoth2.fullborder
KHM/Blightstep Pathway2.fullborder
KHM/Darkbore Pathway2.fullborder
KHM/Haunting Voyage2.fullborder
KHM/Hengegate Pathway2.fullborder
KHM/Kaya the Inexorable2.fullborder
KHM/Mistgate Pathway2.fullborder
KHM/Niko Aris2.fullborder
KHM/Quakebringer2.fullborder
KHM/Searstep Pathway2.fullborder
KHM/Slitherbore Pathway2.fullborder
KHM/Starnheim Unleashed2.fullborder
KHM/Tibalt, Cosmic Impostor2.fullborder
KHM/Tidechannel Pathway2.fullborder
KHM/Tyvar Kell2.fullborder
KHM/Valki, God of Lies2.fullborder
M21/Basri Ket2.fullborder
M21/Chandra, Heart of Fire2.fullborder
M21/Containment Priest2.fullborder
M21/Cultivate2.fullborder
M21/Garruk, Unleashed2.fullborder
M21/Grim Tutor2.fullborder
M21/Liliana, Waker of the Dead2.fullborder
M21/Massacre Wurm2.fullborder
M21/Scavenging Ooze2.fullborder
M21/Solemn Simulacrum2.fullborder
M21/Teferi, Master of Time2.fullborder
M21/Ugin, the Spirit Dragon2.fullborder
M21/Ugin, the Spirit Dragon3.fullborder
MH2/Cabal Coffers2.fullborder
MH2/Chatterfang, Squirrel General3.fullborder
MH2/Dakkon, Shadow Slayer3.fullborder
MH2/Endurance2.fullborder
MH2/Fury2.fullborder
MH2/Geyadrone Dihada3.fullborder
MH2/Grief2.fullborder
MH2/Grist, the Hunger Tide3.fullborder
MH2/Imperial Recruiter2.fullborder
MH2/Mirari's Wake2.fullborder
MH2/Mishra's Factory2.fullborder
MH2/Ragavan, Nimble Pilferer2.fullborder
MH2/Scion of Draco3.fullborder
MH2/Shardless Agent3.fullborder
MH2/Solitude2.fullborder
MH2/Subtlety2.fullborder
MH2/Svyelun of Sea and Sky3.fullborder
MH2/Sword of Hearth and Home3.fullborder
MH2/Thrasta, Tempest's Roar2.fullborder
MH2/Titania, Protector of Argoth2.fullborder
MH2/Tourach, Dread Cantor2.fullborder
MH2/Vindicate2.fullborder
MID/Arlinn, the Moon's Fury2.fullborder
MID/Arlinn, the Pack's Hope2.fullborder
MID/Deserted Beach2.fullborder
MID/Haunted Ridge2.fullborder
MID/Overgrown Farmland2.fullborder
MID/Rockfall Vale2.fullborder
MID/Shipwreck Marsh2.fullborder
MID/Teferi, Who Slows the Sunset2.fullborder
MID/Wrenn and Seven2.fullborder
NEO/Ao, the Dawn Sky2.fullborder
NEO/Atsushi, the Blazing Sky2.fullborder
NEO/Boseiju, Who Endures2.fullborder
NEO/Eiganjo, Seat of the Empire3.fullborder
NEO/Junji, the Midnight Sky2.fullborder
NEO/Kairi, the Swirling Sky2.fullborder
NEO/Kaito Shizuki2.fullborder
NEO/Kura, the Boundless Sky2.fullborder
NEO/Kyodai, Soul of Kamigawa2.fullborder
NEO/Otawara, Soaring City2.fullborder
NEO/Sokenzan, Crucible of Defiance2.fullborder
NEO/Takenuma, Abandoned Mire2.fullborder
NEO/Tamiyo, Compleated Sage2.fullborder
NEO/Tezzeret, Betrayer of Flesh2.fullborder
NEO/The Wandering Emperor2.fullborder
PLG20/Hangarback Walker.fullborder
PLGS/Hangarback Walker.fullborder
PSLD/Tibalt, the Fiend-Blooded.fullborder
SLD/Acidic Slime.fullborder
SLD/Captain Sisay.fullborder
SLD/Meren of Clan Nel Toth.fullborder
SLD/Narset, Enlightened Master.fullborder
SLD/Necrotic Ooze.fullborder
SLD/Oona, Queen of the Fae.fullborder
SLD/Saskia the Unyielding.fullborder
SLD/Scavenging Ooze.fullborder
SLD/The Mimeoplasm.fullborder
SLD/Voidslime.fullborder
SLU/Boulderloft Pathway.fullborder
SLU/Branchloft Pathway.fullborder
SLU/Brightclimb Pathway.fullborder
SLU/Clearwater Pathway.fullborder
SLU/Cragcrown Pathway.fullborder
SLU/Grimclimb Pathway.fullborder
SLU/Lavaglide Pathway.fullborder
SLU/Murkwater Pathway.fullborder
SLU/Needleverge Pathway.fullborder
SLU/Pillarverge Pathway.fullborder
SLU/Riverglide Pathway.fullborder
SLU/Timbercrown Pathway.fullborder
SNC/All-Seeing Arbiter2.fullborder
SNC/Bootleggers' Stash2.fullborder
SNC/Elspeth Resplendent2.fullborder
SNC/Gala Greeters10.fullborder
SNC/Gala Greeters11.fullborder
SNC/Gala Greeters12.fullborder
SNC/Gala Greeters13.fullborder
SNC/Gala Greeters3.fullborder
SNC/Gala Greeters4.fullborder
SNC/Gala Greeters5.fullborder
SNC/Gala Greeters6.fullborder
SNC/Gala Greeters7.fullborder
SNC/Gala Greeters8.fullborder
SNC/Gala Greeters9.fullborder
SNC/Halo Fountain2.fullborder
SNC/Jetmir's Garden2.fullborder
SNC/Ob Nixilis, the Adversary2.fullborder
SNC/Raffine's Tower2.fullborder
SNC/Shadow of Mortality2.fullborder
SNC/Spara's Headquarters2.fullborder
SNC/Titan of Industry2.fullborder
SNC/Topiary Stomper2.fullborder
SNC/Vivien on the Hunt3.fullborder
SNC/Xander's Lounge2.fullborder
SNC/Ziatora's Proving Ground2.fullborder
STA/Abundant Harvest1.fullborder
STA/Abundant Harvest2.fullborder
STA/Adventurous Impulse1.fullborder
STA/Adventurous Impulse2.fullborder
STA/Agonizing Remorse1.fullborder
STA/Agonizing Remorse2.fullborder
STA/Approach of the Second Sun1.fullborder
STA/Approach of the Second Sun2.fullborder
STA/Blue Sun's Zenith1.fullborder
STA/Blue Sun's Zenith2.fullborder
STA/Brainstorm1.fullborder
STA/Brainstorm2.fullborder
STA/Channel1.fullborder
STA/Channel2.fullborder
STA/Chaos Warp1.fullborder
STA/Chaos Warp2.fullborder
STA/Claim the Firstborn1.fullborder
STA/Claim the Firstborn2.fullborder
STA/Compulsive Research1.fullborder
STA/Compulsive Research2.fullborder
STA/Counterspell1.fullborder
STA/Counterspell2.fullborder
STA/Crux of Fate1.fullborder
STA/Crux of Fate2.fullborder
STA/Cultivate1.fullborder
STA/Cultivate2.fullborder
STA/Dark Ritual1.fullborder
STA/Dark Ritual2.fullborder
STA/Day of Judgment1.fullborder
STA/Day of Judgment2.fullborder
STA/Defiant Strike1.fullborder
STA/Defiant Strike2.fullborder
STA/Demonic Tutor1.fullborder
STA/Demonic Tutor2.fullborder
STA/Despark1.fullborder
STA/Despark2.fullborder
STA/Divine Gambit1.fullborder
STA/Divine Gambit2.fullborder
STA/Doom Blade1.fullborder
STA/Doom Blade2.fullborder
STA/Duress1.fullborder
STA/Duress2.fullborder
STA/Electrolyze1.fullborder
STA/Electrolyze2.fullborder
STA/Eliminate1.fullborder
STA/Eliminate2.fullborder
STA/Ephemerate1.fullborder
STA/Ephemerate2.fullborder
STA/Faithless Looting1.fullborder
STA/Faithless Looting2.fullborder
STA/Gift of Estates1.fullborder
STA/Gift of Estates2.fullborder
STA/Gods Willing1.fullborder
STA/Gods Willing2.fullborder
STA/Grapeshot1.fullborder
STA/Grapeshot2.fullborder
STA/Growth Spiral1.fullborder
STA/Growth Spiral2.fullborder
STA/Harmonize1.fullborder
STA/Harmonize2.fullborder
STA/Increasing Vengeance1.fullborder
STA/Increasing Vengeance2.fullborder
STA/Infuriate1.fullborder
STA/Infuriate2.fullborder
STA/Inquisition of Kozilek1.fullborder
STA/Inquisition of Kozilek2.fullborder
STA/Krosan Grip1.fullborder
STA/Krosan Grip2.fullborder
STA/Lightning Bolt1.fullborder
STA/Lightning Bolt2.fullborder
STA/Lightning Helix1.fullborder
STA/Lightning Helix2.fullborder
STA/Mana Tithe1.fullborder
STA/Mana Tithe2.fullborder
STA/Memory Lapse1.fullborder
STA/Memory Lapse2.fullborder
STA/Mind's Desire1.fullborder
STA/Mind's Desire2.fullborder
STA/Mizzix's Mastery1.fullborder
STA/Mizzix's Mastery2.fullborder
STA/Natural Order1.fullborder
STA/Natural Order2.fullborder
STA/Negate1.fullborder
STA/Negate2.fullborder
STA/Opt1.fullborder
STA/Opt2.fullborder
STA/Primal Command1.fullborder
STA/Primal Command2.fullborder
STA/Putrefy1.fullborder
STA/Putrefy2.fullborder
STA/Regrowth1.fullborder
STA/Regrowth2.fullborder
STA/Revitalize1.fullborder
STA/Revitalize2.fullborder
STA/Shock1.fullborder
STA/Shock2.fullborder
STA/Sign in Blood1.fullborder
STA/Sign in Blood2.fullborder
STA/Snakeskin Veil1.fullborder
STA/Snakeskin Veil2.fullborder
STA/Stone Rain1.fullborder
STA/Stone Rain2.fullborder
STA/Strategic Planning1.fullborder
STA/Strategic Planning2.fullborder
STA/Swords to Plowshares1.fullborder
STA/Swords to Plowshares2.fullborder
STA/Tainted Pact1.fullborder
STA/Tainted Pact2.fullborder
STA/Teferi's Protection1.fullborder
STA/Teferi's Protection2.fullborder
STA/Tendrils of Agony1.fullborder
STA/Tendrils of Agony2.fullborder
STA/Tezzeret's Gambit1.fullborder
STA/Tezzeret's Gambit2.fullborder
STA/Thrill of Possibility1.fullborder
STA/Thrill of Possibility2.fullborder
STA/Time Warp1.fullborder
STA/Time Warp2.fullborder
STA/Urza's Rage1.fullborder
STA/Urza's Rage2.fullborder
STA/Village Rites1.fullborder
STA/Village Rites2.fullborder
STA/Weather the Storm1.fullborder
STA/Weather the Storm2.fullborder
STA/Whirlwind Denial1.fullborder
STA/Whirlwind Denial2.fullborder
STX/Beledros Witherbloom2.fullborder
STX/Galazeth Prismari2.fullborder
STX/Kasmina, Enigma Sage2.fullborder
STX/Lukka, Wayward Bonder2.fullborder
STX/Mila, Crafty Companion2.fullborder
STX/Professor Onyx2.fullborder
STX/Rowan, Scholar of Sparks2.fullborder
STX/Shadrix Silverquill2.fullborder
STX/Tanazir Quandrix2.fullborder
STX/Velomachus Lorehold2.fullborder
STX/Will, Scholar of Frost2.fullborder
THB/Ashiok, Nightmare Muse2.fullborder
THB/Calix, Destiny's Hand2.fullborder
THB/Elspeth, Sun's Nemesis2.fullborder
UNF/Blood Crypt.fullborder
UNF/Breeding Pool.fullborder
UNF/Forest1.fullborder
UNF/Forest2.fullborder
UNF/Godless Shrine.fullborder
UNF/Hallowed Fountain.fullborder
UNF/Island1.fullborder
UNF/Island2.fullborder
UNF/Mountain1.fullborder
UNF/Mountain2.fullborder
UNF/Overgrown Tomb.fullborder
UNF/Plains1.fullborder
UNF/Plains2.fullborder
UNF/Sacred Foundry.fullborder
UNF/Steam Vents.fullborder
UNF/Stomping Ground.fullborder
UNF/Swamp1.fullborder
UNF/Swamp2.fullborder
UNF/Temple Garden.fullborder
UNF/Watery Grave.fullborder
UST/Forest.fullborder
UST/Island.fullborder
UST/Mountain.fullborder
UST/Plains.fullborder
UST/Swamp.fullborder
VOW/Bloodbat Summoner3.fullborder
VOW/Chandra, Dressed to Kill2.fullborder
VOW/Circle of Confinement2.fullborder
VOW/Deathcap Glade2.fullborder
VOW/Dreamroot Cascade2.fullborder
VOW/Edgar Markov's Coffin3.fullborder
VOW/Edgar, Charmed Groom3.fullborder
VOW/Eruth, Tormented Prophet3.fullborder
VOW/Falkenrath Forebear3.fullborder
VOW/Hauken's Insight3.fullborder
VOW/Henrika Domnathi3.fullborder
VOW/Henrika, Infernal Seer3.fullborder
VOW/Innocent Traveler3.fullborder
VOW/Investigator's Journal2.fullborder
VOW/Jacob Hauken, Inspector3.fullborder
VOW/Kaya, Geist Hunter2.fullborder
VOW/Malicious Invader3.fullborder
VOW/Olivia, Crimson Bride3.fullborder
VOW/Reclusive Taxidermist2.fullborder
VOW/Savior of Ollenbock2.fullborder
VOW/Shattered Sanctum2.fullborder
VOW/Sorin the Mirthless2.fullborder
VOW/Sorin the Mirthless4.fullborder
VOW/Stormcarved Coast2.fullborder
VOW/Sundown Pass2.fullborder
VOW/Thalia, Guardian of Thraben3.fullborder
VOW/Thirst for Discovery2.fullborder
VOW/Torens, Fist of the Angels3.fullborder
VOW/Vampires' Vengeance2.fullborder
VOW/Voldaren Bloodcaster3.fullborder
VOW/Voldaren Estate3.fullborder
ZNR/Boulderloft Pathway2.fullborder
ZNR/Branchloft Pathway2.fullborder
ZNR/Brightclimb Pathway2.fullborder
ZNR/Clearwater Pathway2.fullborder
ZNR/Cragcrown Pathway2.fullborder
ZNR/Grimclimb Pathway2.fullborder
ZNR/Jace, Mirror Mage2.fullborder
ZNR/Lavaglide Pathway2.fullborder
ZNR/Murkwater Pathway2.fullborder
ZNR/Nahiri, Heir of the Ancients2.fullborder
ZNR/Needleverge Pathway2.fullborder
ZNR/Nissa of Shadowed Boughs2.fullborder
ZNR/Pillarverge Pathway2.fullborder
ZNR/Riverglide Pathway2.fullborder
ZNR/Timbercrown Pathway2.fullborder

View File

@@ -39,8 +39,11 @@ import org.apache.commons.lang3.ArrayUtils;
import java.io.File; import java.io.File;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors;
/** /**
* Booster Draft Format. * Booster Draft Format.
@@ -317,6 +320,7 @@ public class BoosterDraft implements IBoosterDraft {
private static List<CustomLimited> loadCustomDrafts() { private static List<CustomLimited> loadCustomDrafts() {
if (customs.isEmpty()) { if (customs.isEmpty()) {
String[] dList; String[] dList;
ConcurrentLinkedQueue<CustomLimited> queue = new ConcurrentLinkedQueue<>();
// get list of custom draft files // get list of custom draft files
final File dFolder = new File(ForgeConstants.DRAFT_DIR); final File dFolder = new File(ForgeConstants.DRAFT_DIR);
@@ -330,12 +334,26 @@ public class BoosterDraft implements IBoosterDraft {
dList = dFolder.list(); dList = dFolder.list();
for (final String element : dList) { if (dList != null) {
if (element.endsWith(FILE_EXT)) { List<CompletableFuture<?>> futures = new ArrayList<>();
final List<String> dfData = FileUtil.readFile(ForgeConstants.DRAFT_DIR + element); for (final String element : dList) {
customs.add(CustomLimited.parse(dfData, FModel.getDecks().getCubes())); if (element.endsWith(FILE_EXT)) {
futures.add(CompletableFuture.supplyAsync(()-> {
final List<String> dfData = FileUtil.readFile(ForgeConstants.DRAFT_DIR + element);
queue.add(CustomLimited.parse(dfData, FModel.getDecks().getCubes()));
return null;
}).exceptionally(ex -> {
ex.printStackTrace();
return null;
}));
}
} }
CompletableFuture<?>[] futuresArray = futures.toArray(new CompletableFuture<?>[0]);
CompletableFuture.allOf(futuresArray).join();
futures.clear();
} }
// stream().toList() causes crash on Android, use Collectors.toList()
customs.addAll(queue.stream().collect(Collectors.toList()));
} }
return customs; return customs;
} }

View File

@@ -64,7 +64,6 @@ public final class ForgeConstants {
public static final String NET_DECKS_BRAWL_LIST_FILE = LISTS_DIR + "net-decks-brawl.txt"; public static final String NET_DECKS_BRAWL_LIST_FILE = LISTS_DIR + "net-decks-brawl.txt";
public static final String NET_DECKS_OATHBREAKER_LIST_FILE = LISTS_DIR + "net-decks-oathbreaker.txt"; public static final String NET_DECKS_OATHBREAKER_LIST_FILE = LISTS_DIR + "net-decks-oathbreaker.txt";
public static final String NET_DECKS_TINYLEADERS_LIST_FILE = LISTS_DIR + "net-decks-tinyleaders.txt"; public static final String NET_DECKS_TINYLEADERS_LIST_FILE = LISTS_DIR + "net-decks-tinyleaders.txt";
public static final String BORDERLESS_CARD_LIST_FILE = LISTS_DIR + "borderlessCardList.txt";
public static final String CLASSIC_MODULE_CARD_TO_CROP_FILE = LISTS_DIR + "classicModuleCardtoCrop.txt"; public static final String CLASSIC_MODULE_CARD_TO_CROP_FILE = LISTS_DIR + "classicModuleCardtoCrop.txt";
public static final String SKINS_LIST_FILE = LISTS_DIR + "skinsList.txt"; public static final String SKINS_LIST_FILE = LISTS_DIR + "skinsList.txt";
public static final String CJK_FONTS_LIST_FILE = LISTS_DIR + "font-list.txt"; public static final String CJK_FONTS_LIST_FILE = LISTS_DIR + "font-list.txt";