diff --git a/forge-core/src/main/java/forge/ImageKeys.java b/forge-core/src/main/java/forge/ImageKeys.java index 0688d7440a4..aa0d4912565 100644 --- a/forge-core/src/main/java/forge/ImageKeys.java +++ b/forge-core/src/main/java/forge/ImageKeys.java @@ -322,6 +322,8 @@ public final class ImageKeys { : CACHE_CARD_PICS_SUBDIR.get(edition); // may use custom paths though } public static boolean hasSetLookup(String filename) { + if (filename == null) + return false; if (!StaticData.instance().getSetLookup().isEmpty()) { return StaticData.instance().getSetLookup().keySet().stream().anyMatch(filename::startsWith); } diff --git a/forge-core/src/main/java/forge/StaticData.java b/forge-core/src/main/java/forge/StaticData.java index 9e264641deb..c473e7fd5b3 100644 --- a/forge-core/src/main/java/forge/StaticData.java +++ b/forge-core/src/main/java/forge/StaticData.java @@ -16,6 +16,9 @@ import org.apache.commons.lang3.tuple.Pair; import java.io.File; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; /** @@ -427,7 +430,7 @@ public class StaticData { public void setBrawlPredicate(Predicate brawlPredicate) { this.brawlPredicate = brawlPredicate; } public Predicate getStandardPredicate() { return standardPredicate; } - + public Predicate getPioneerPredicate() { return pioneerPredicate; } public Predicate getModernPredicate() { return modernPredicate; } @@ -763,19 +766,20 @@ public class StaticData { return preferences_avails; } public Pair audit(StringBuffer noImageFound, StringBuffer cardNotImplemented) { - int missingCount = 0; - int notImplementedCount = 0; + Queue EDITION_Q = new ConcurrentLinkedQueue<>(); + Queue NIF_Q = new ConcurrentLinkedQueue<>(); + Queue CNI_Q = new ConcurrentLinkedQueue<>(); + Queue TOKEN_Q = new ConcurrentLinkedQueue<>(); + boolean nifHeader = false; + boolean cniHeader = false; for (CardEdition e : editions) { if (CardEdition.Type.FUNNY.equals(e.getType())) continue; - boolean nifHeader = false; - boolean cniHeader = false; - boolean tokenHeader = false; - String imagePath; - int artIndex = 1; + AtomicInteger artIndex = new AtomicInteger(1); - HashMap> cardCount = new HashMap<>(); + Map> cardCount = new HashMap<>(); + List> futures = new ArrayList<>(); for (CardEdition.CardInSet c : e.getAllCardsInSet()) { if (cardCount.containsKey(c.name)) { cardCount.put(c.name, Pair.of(c.collectorNumber != null && c.collectorNumber.startsWith("F"), cardCount.get(c.name).getRight() + 1)); @@ -786,104 +790,158 @@ public class StaticData { // loop through the cards in this edition, considering art variations... for (Map.Entry> entry : cardCount.entrySet()) { - String c = entry.getKey(); - artIndex = entry.getValue().getRight(); - - PaperCard cp = getCommonCards().getCard(c, e.getCode(), artIndex); - if (cp == null) { - cp = getVariantCards().getCard(c, e.getCode(), artIndex); - } - - if (cp == null) { - if (entry.getValue().getLeft()) //skip funny cards - continue; - if (!loadNonLegalCards && CardEdition.Type.FUNNY.equals(e.getType())) - continue; - if (!cniHeader) { - cardNotImplemented.append("\nEdition: ").append(e.getName()).append(" ").append("(").append(e.getCode()).append("/").append(e.getCode2()).append(")\n"); - cniHeader = true; + futures.add(CompletableFuture.supplyAsync(()-> { + final String c = entry.getKey(); + final int artID = entry.getValue().getRight(); + final boolean isFunny = entry.getValue().getLeft(); + PaperCard cp = getCommonCards().getCard(c, e.getCode(), artID); + if (cp == null) { + cp = getVariantCards().getCard(c, e.getCode(), artID); } - cardNotImplemented.append(" ").append(c).append("\n"); - notImplementedCount++; - continue; - } - - // check the front image - imagePath = ImageUtil.getImageRelativePath(cp, "", true, false); - if (imagePath != null) { - File file = ImageKeys.getImageFile(imagePath); - if (file == null && ImageKeys.hasSetLookup(imagePath)) - file = ImageKeys.setLookUpFile(imagePath, imagePath+"border"); - if (file == null) { - if (!nifHeader) { - noImageFound.append("Edition: ").append(e.getName()).append(" ").append("(").append(e.getCode()).append("/").append(e.getCode2()).append(")\n"); - nifHeader = true; - } - noImageFound.append(" ").append(imagePath).append("\n"); - missingCount++; + if (cp == null) { + if (isFunny) //skip funny cards + return 0; + if (!loadNonLegalCards && CardEdition.Type.FUNNY.equals(e.getType())) + return 0; + EDITION_Q.add(e.getCode() + "_" + e.getName()); + CNI_Q.add(e.getCode() + "_" + c + "\n"); + return 0; } - } - - // check the back face - if (cp.hasBackFace()) { - imagePath = ImageUtil.getImageRelativePath(cp, "back", true, false); + // check the front image + String imagePath = ImageUtil.getImageRelativePath(cp, "", true, false); if (imagePath != null) { File file = ImageKeys.getImageFile(imagePath); if (file == null && ImageKeys.hasSetLookup(imagePath)) - file = ImageKeys.setLookUpFile(imagePath, imagePath+"border"); + file = ImageKeys.setLookUpFile(imagePath, imagePath +"border"); if (file == null) { - if (!nifHeader) { - noImageFound.append("Edition: ").append(e.getName()).append(" ").append("(").append(e.getCode()).append("/").append(e.getCode2()).append(")\n"); - nifHeader = true; - } - noImageFound.append(" ").append(imagePath).append("\n"); - missingCount++; + if (imagePath.isEmpty()) + return 0; + EDITION_Q.add(e.getCode() + "_" + e.getName()); + NIF_Q.add(e.getCode() + "_" + imagePath + "\n"); } } - } + // check the back face + if (cp.hasBackFace()) { + imagePath = ImageUtil.getImageRelativePath(cp, "back", true, false); + if (imagePath != null) { + File file = ImageKeys.getImageFile(imagePath); + if (file == null && ImageKeys.hasSetLookup(imagePath)) + file = ImageKeys.setLookUpFile(imagePath, imagePath +"border"); + if (file == null) { + if (imagePath.isEmpty()) + return 0; + EDITION_Q.add(e.getCode() + "_" + e.getName()); + NIF_Q.add(e.getCode() + "_" + imagePath + "\n"); + } + } + } + return 0; + })); } // TODO: Audit token images here... for(Map.Entry tokenEntry : e.getTokens().entrySet()) { - String name = tokenEntry.getKey(); - artIndex = tokenEntry.getValue(); - try { - PaperToken token = getAllTokens().getToken(name, e.getCode()); - if (token == null) { - continue; - } - - for(int i = 0; i < artIndex; i++) { - String imgKey = token.getImageKey(i); - File file = ImageKeys.getImageFile(imgKey); - if (file == null) { - if (!nifHeader) { - noImageFound.append("Edition: ").append(e.getName()).append(" ").append("(").append(e.getCode()).append("/").append(e.getCode2()).append(")\n"); - nifHeader = true; - } - if (!tokenHeader) { - noImageFound.append("\nTOKENS\n"); - tokenHeader = true; - } - noImageFound.append(" ").append(token.getImageFilename(i + 1)).append("\n"); - missingCount++; + futures.add(CompletableFuture.supplyAsync(()-> { + String name = tokenEntry.getKey(); + artIndex.set(tokenEntry.getValue()); + try { + PaperToken token = getAllTokens().getToken(name, e.getCode()); + if (token == null) { + return 0; } + + for(int i = 0; i < artIndex.get(); i++) { + String imgKey = token.getImageKey(i); + File file = ImageKeys.getImageFile(imgKey); + if (file == null) { + EDITION_Q.add(e.getCode() + "_" + e.getName()); + TOKEN_Q.add(e.getCode() + "_" + token.getImageFilename(i + 1) + "\n"); + } + } + } catch(Exception ex) { + System.out.println("No Token found: " + name + " in " + e.getName()); } - } catch(Exception ex) { - System.out.println("No Token found: " + name + " in " + e.getName()); + return 0; + })); + } + CompletableFuture[] futuresArray = futures.toArray(new CompletableFuture[0]); + CompletableFuture.allOf(futuresArray).join(); + futures.clear(); + } + List NIF = new ArrayList<>(NIF_Q).stream().sorted().toList(); + List CNI = new ArrayList<>(CNI_Q).stream().sorted().toList(); + List TOK = new ArrayList<>(TOKEN_Q).stream().sorted().toList(); + List sorted_editions = EDITION_Q.stream().distinct().sorted().toList(); + for (String edition : sorted_editions) { + String[] arr = edition.split("_"); + String code = arr[0]; + boolean NIF_TITLE = false, CNI_TITLE = false, TOK_TITLE = false; + for (String nif : NIF) { + if (nif.startsWith(code)) { + if (!nifHeader) { + noImageFound.append("\n-------------------\n"); + noImageFound.append("NO IMAGE FOUND LIST\n"); + noImageFound.append("-------------------\n\n"); + nifHeader = true; + } + if (!NIF_TITLE) { + noImageFound.append(edition.replace(code + "_","")).append(" (").append(code).append(")").append("\n"); + NIF_TITLE = true; + } + noImageFound.append(" ").append(nif.replace(code + "_", "")); } } - if (nifHeader) + if (NIF_TITLE) noImageFound.append("\n"); + for (String tok : TOK) { + if (tok.startsWith(code)) { + if (!nifHeader) { + noImageFound.append("\n-------------------\n"); + noImageFound.append("NO IMAGE FOUND LIST\n"); + noImageFound.append("-------------------\n\n"); + nifHeader = true; + } + if (!NIF_TITLE) { + noImageFound.append(edition.replace(code + "_","")).append(" (").append(code).append(")").append("\n"); + NIF_TITLE = true; + } + if (!TOK_TITLE) { + noImageFound.append(" TOKENS\n"); + TOK_TITLE = true; + } + noImageFound.append(" ").append(tok.replace(code + "_", "")); + } + } + if (TOK_TITLE) + noImageFound.append("\n"); + for (String cni : CNI) { + if (cni.startsWith(code)) { + if (!cniHeader) { + cardNotImplemented.append("\n-------------------\n"); + cardNotImplemented.append("UNIMPLEMENTED CARD LIST\n"); + cardNotImplemented.append("-------------------\n\n"); + cniHeader = true; + } + if (!CNI_TITLE) { + cardNotImplemented.append(edition.replace(code + "_","")).append(" (").append(code).append(")").append("\n"); + CNI_TITLE = true; + } + cardNotImplemented.append(" ").append(cni.replace(code + "_", "")); + } + } + if (CNI_TITLE) + cardNotImplemented.append("\n"); } - String totalStats = "Missing images: " + missingCount + "\nUnimplemented cards: " + notImplementedCount + "\n"; + final int missingImages = NIF.size() + TOK.size(); + final int unimplemenedCards = CNI.size(); + String totalStats = "Missing images: " + missingImages + "\nUnimplemented cards: " + unimplemenedCards + "\n"; cardNotImplemented.append("\n-----------\n"); cardNotImplemented.append(totalStats); cardNotImplemented.append("-----------\n\n"); noImageFound.append(cardNotImplemented); // combine things together... - return Pair.of(missingCount, notImplementedCount); + return Pair.of(missingImages, unimplemenedCards); } private String prettifyCardArtPreferenceName(CardDb.CardArtPreference preference) { diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuDownloaders.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuDownloaders.java index 8e1b60ace95..0c18d309623 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuDownloaders.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuDownloaders.java @@ -216,14 +216,6 @@ public enum VSubmenuDownloaders implements IVSubmenu { public void auditUpdate(FTextArea tar, FScrollPane scr) { StringBuffer nifSB = new StringBuffer(); // NO IMAGE FOUND BUFFER StringBuffer cniSB = new StringBuffer(); // CARD NOT IMPLEMENTED BUFFER - - nifSB.append("\n\n-------------------\n"); - nifSB.append("NO IMAGE FOUND LIST\n"); - nifSB.append("-------------------\n\n"); - - cniSB.append("\n\n-------------------\n"); - cniSB.append("UNIMPLEMENTED CARD LIST\n"); - cniSB.append("-------------------\n\n"); Pair totalAudit = StaticData.instance().audit(nifSB, cniSB); diff --git a/forge-gui-mobile/src/forge/adventure/world/World.java b/forge-gui-mobile/src/forge/adventure/world/World.java index b3752588c37..48dea36c094 100644 --- a/forge-gui-mobile/src/forge/adventure/world/World.java +++ b/forge-gui-mobile/src/forge/adventure/world/World.java @@ -27,6 +27,7 @@ import org.apache.commons.lang3.tuple.Pair; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; /** * Class that will create the world from the configuration @@ -325,7 +326,7 @@ public class World implements Disposable, SaveFileContent { final int[] biomeIndex = {-1}; currentTime[0] = measureGenerationTime("loading data", currentTime[0]); - HashMap structureDataMap = new HashMap<>(); + Map structureDataMap = new ConcurrentHashMap<>(); ////////////////// ///////// calculation structure position with wavefunctioncollapse diff --git a/forge-gui-mobile/src/forge/screens/settings/FilesPage.java b/forge-gui-mobile/src/forge/screens/settings/FilesPage.java index cbd354505bb..e5c39ca1755 100644 --- a/forge-gui-mobile/src/forge/screens/settings/FilesPage.java +++ b/forge-gui-mobile/src/forge/screens/settings/FilesPage.java @@ -61,14 +61,6 @@ public class FilesPage extends TabPage { StringBuffer nifSB = new StringBuffer(); // NO IMAGE FOUND BUFFER StringBuffer cniSB = new StringBuffer(); // CARD NOT IMPLEMENTED BUFFER - nifSB.append("\n\n-------------------\n"); - nifSB.append("NO IMAGE FOUND LIST\n"); - nifSB.append("-------------------\n\n"); - - cniSB.append("\n\n-------------------\n"); - cniSB.append("UNIMPLEMENTED CARD LIST\n"); - cniSB.append("-------------------\n\n"); - Pair totalAudit = StaticData.instance().audit(nifSB, cniSB); String msg = nifSB.toString(); String title = "Missing images: " + totalAudit.getLeft() + "\nUnimplemented cards: " + totalAudit.getRight();