moved CardStorageReader to core project

This commit is contained in:
Maxmtg
2013-11-22 16:51:38 +00:00
parent 3fd72f35df
commit 29a535c71a
14 changed files with 432 additions and 439 deletions

5
.gitattributes vendored
View File

@@ -19,8 +19,7 @@ forge-core/.settings/org.eclipse.core.resources.prefs -text
forge-core/.settings/org.eclipse.jdt.core.prefs -text forge-core/.settings/org.eclipse.jdt.core.prefs -text
forge-core/.settings/org.eclipse.m2e.core.prefs -text forge-core/.settings/org.eclipse.m2e.core.prefs -text
forge-core/pom.xml -text forge-core/pom.xml -text
forge-core/src/main/java/forge/ICardStorageReader.java -text forge-core/src/main/java/forge/CardStorageReader.java -text
forge-core/src/main/java/forge/IProgressObserver.java -text
forge-core/src/main/java/forge/StaticData.java -text forge-core/src/main/java/forge/StaticData.java -text
forge-core/src/main/java/forge/card/BoosterGenerator.java svneol=native#text/plain forge-core/src/main/java/forge/card/BoosterGenerator.java svneol=native#text/plain
forge-core/src/main/java/forge/card/BoosterSlots.java -text forge-core/src/main/java/forge/card/BoosterSlots.java -text
@@ -98,6 +97,7 @@ forge-core/src/main/java/forge/util/Lang.java -text
forge-core/src/main/java/forge/util/MyRandom.java svneol=native#text/plain forge-core/src/main/java/forge/util/MyRandom.java svneol=native#text/plain
forge-core/src/main/java/forge/util/PredicateString.java -text forge-core/src/main/java/forge/util/PredicateString.java -text
forge-core/src/main/java/forge/util/TextUtil.java -text forge-core/src/main/java/forge/util/TextUtil.java -text
forge-core/src/main/java/forge/util/ThreadUtil.java -text
forge-core/src/main/java/forge/util/package-info.java -text forge-core/src/main/java/forge/util/package-info.java -text
forge-core/src/main/java/forge/util/storage/IStorage.java -text forge-core/src/main/java/forge/util/storage/IStorage.java -text
forge-core/src/main/java/forge/util/storage/StorageBase.java -text forge-core/src/main/java/forge/util/storage/StorageBase.java -text
@@ -14944,7 +14944,6 @@ forge-gui/src/main/java/forge/card/ability/package-info.java svneol=native#text/
forge-gui/src/main/java/forge/card/cardfactory/CardFactory.java svneol=native#text/plain forge-gui/src/main/java/forge/card/cardfactory/CardFactory.java svneol=native#text/plain
forge-gui/src/main/java/forge/card/cardfactory/CardFactoryCreatures.java svneol=native#text/plain forge-gui/src/main/java/forge/card/cardfactory/CardFactoryCreatures.java svneol=native#text/plain
forge-gui/src/main/java/forge/card/cardfactory/CardFactoryUtil.java svneol=native#text/plain forge-gui/src/main/java/forge/card/cardfactory/CardFactoryUtil.java svneol=native#text/plain
forge-gui/src/main/java/forge/card/cardfactory/CardStorageReader.java svneol=native#text/plain
forge-gui/src/main/java/forge/card/cardfactory/package-info.java svneol=native#text/plain forge-gui/src/main/java/forge/card/cardfactory/package-info.java svneol=native#text/plain
forge-gui/src/main/java/forge/card/cost/Cost.java svneol=native#text/plain forge-gui/src/main/java/forge/card/cost/Cost.java svneol=native#text/plain
forge-gui/src/main/java/forge/card/cost/CostAddMana.java -text forge-gui/src/main/java/forge/card/cost/CostAddMana.java -text

View File

@@ -1,344 +1,356 @@
/* /*
* Forge: Play Magic: the Gathering. * Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team * Copyright (C) 2011 Forge Team
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package forge.card.cardfactory; package forge;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import org.apache.commons.lang3.time.StopWatch; import org.apache.commons.lang3.time.StopWatch;
import forge.FThreads; import forge.card.CardRules;
import forge.ICardStorageReader; import forge.util.FileUtil;
import forge.IProgressObserver; import forge.util.ThreadUtil;
import forge.card.CardRules;
import forge.util.FileUtil; /**
* <p>
/** * CardReader class.
* <p> * </p>
* CardReader class. *
* </p> * @author Forge
* * @version $Id: CardStorageReader.java 23742 2013-11-22 16:32:56Z Max mtg $
* @author Forge */
* @version $Id$
*/ public class CardStorageReader {
public interface Observer {
public class CardStorageReader implements ICardStorageReader { public void cardLoaded(CardRules rules, List<String> lines, File fileOnDisk);
}
private static final String CARD_FILE_DOT_EXTENSION = ".txt";
public interface ProgressObserver{
/** Default charset when loading from files. */ void setOperationName(String name, boolean usePercents);
public static final String DEFAULT_CHARSET_NAME = "US-ASCII"; void report(int current, int total);
private final boolean useThreadPool = FThreads.isMultiCoreSystem(); // does nothing, used when they pass null instead of an instance
public final static int NUMBER_OF_PARTS = 25; public final static ProgressObserver emptyObserver = new ProgressObserver() {
@Override public void setOperationName(String name, boolean usePercents) {}
private final CountDownLatch cdl = new CountDownLatch(NUMBER_OF_PARTS); @Override public void report(int current, int total) {}
private final IProgressObserver progressObserver; };
}
private transient File cardsfolder;
private static final String CARD_FILE_DOT_EXTENSION = ".txt";
private transient ZipFile zip;
private final transient Charset charset; /** Default charset when loading from files. */
public static final String DEFAULT_CHARSET_NAME = "US-ASCII";
private final Observer observer;
private final boolean useThreadPool = ThreadUtil.isMultiCoreSystem();
public final static int NUMBER_OF_PARTS = 25;
// 8/18/11 10:56 PM
private final CountDownLatch cdl = new CountDownLatch(NUMBER_OF_PARTS);
private final ProgressObserver progressObserver;
/**
* <p> private transient File cardsfolder;
* Constructor for CardReader.
* </p> private transient ZipFile zip;
* private final transient Charset charset;
* @param theCardsFolder
* indicates location of the cardsFolder private final Observer observer;
* @param useZip
* if true, attempts to load cards from a zip file, if one
* exists. // 8/18/11 10:56 PM
*/
public CardStorageReader(String cardDataDir, final boolean useZip, IProgressObserver progressObserver, ICardStorageReader.Observer observer) {
this.progressObserver = progressObserver != null ? progressObserver : IProgressObserver.emptyObserver; /**
this.cardsfolder = new File(cardDataDir); * <p>
this.observer = observer; * Constructor for CardReader.
* </p>
// These read data for lightweight classes. *
if (!cardsfolder.exists()) { * @param theCardsFolder
throw new RuntimeException("CardReader : constructor error -- " + cardsfolder.getAbsolutePath() + " file/folder not found."); * indicates location of the cardsFolder
} * @param useZip
* if true, attempts to load cards from a zip file, if one
if (!cardsfolder.isDirectory()) { * exists.
throw new RuntimeException("CardReader : constructor error -- not a directory -- " + cardsfolder.getAbsolutePath()); */
} public CardStorageReader(String cardDataDir, final boolean useZip, CardStorageReader.ProgressObserver progressObserver, Observer observer) {
this.progressObserver = progressObserver != null ? progressObserver : CardStorageReader.ProgressObserver.emptyObserver;
final File zipFile = new File(cardsfolder, "cardsfolder.zip"); this.cardsfolder = new File(cardDataDir);
this.observer = observer;
if (useZip && zipFile.exists()) {
try { // These read data for lightweight classes.
this.zip = new ZipFile(zipFile); if (!cardsfolder.exists()) {
} catch (final Exception exn) { throw new RuntimeException("CardReader : constructor error -- " + cardsfolder.getAbsolutePath() + " file/folder not found.");
System.err.printf("Error reading zip file \"%s\": %s. Defaulting to txt files in \"%s\".%n", zipFile.getAbsolutePath(), exn, cardsfolder.getAbsolutePath()); }
}
} if (!cardsfolder.isDirectory()) {
throw new RuntimeException("CardReader : constructor error -- not a directory -- " + cardsfolder.getAbsolutePath());
this.charset = Charset.forName(CardStorageReader.DEFAULT_CHARSET_NAME); }
} // CardReader() final File zipFile = new File(cardsfolder, "cardsfolder.zip");
private final List<CardRules> loadCardsInRange(final List<File> files, int from, int to) { if (useZip && zipFile.exists()) {
CardRules.Reader rulesReader = new CardRules.Reader(); try {
this.zip = new ZipFile(zipFile);
List<CardRules> result = new ArrayList<CardRules>(); } catch (final Exception exn) {
for(int i = from; i < to; i++) { System.err.printf("Error reading zip file \"%s\": %s. Defaulting to txt files in \"%s\".%n", zipFile.getAbsolutePath(), exn, cardsfolder.getAbsolutePath());
File cardTxtFile = files.get(i); }
result.add(this.loadCard(rulesReader, cardTxtFile)); }
}
return result; this.charset = Charset.forName(CardStorageReader.DEFAULT_CHARSET_NAME);
}
} // CardReader()
private final List<CardRules> loadCardsInRangeFromZip(final List<ZipEntry> files, int from, int to) {
CardRules.Reader rulesReader = new CardRules.Reader(); private final List<CardRules> loadCardsInRange(final List<File> files, int from, int to) {
CardRules.Reader rulesReader = new CardRules.Reader();
List<CardRules> result = new ArrayList<CardRules>();
for(int i = from; i < to; i++) { List<CardRules> result = new ArrayList<CardRules>();
ZipEntry ze = files.get(i); for(int i = from; i < to; i++) {
// if (ze.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION)) // already filtered! File cardTxtFile = files.get(i);
result.add(this.loadCard(rulesReader, ze)); result.add(this.loadCard(rulesReader, cardTxtFile));
} }
return result; return result;
} }
/** private final List<CardRules> loadCardsInRangeFromZip(final List<ZipEntry> files, int from, int to) {
* Starts reading cards into memory until the given card is found. CardRules.Reader rulesReader = new CardRules.Reader();
*
* After that, we save our place in the list of cards (on disk) in case we List<CardRules> result = new ArrayList<CardRules>();
* need to load more. for(int i = from; i < to; i++) {
* ZipEntry ze = files.get(i);
* @return the Card or null if it was not found. // if (ze.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION)) // already filtered!
*/ result.add(this.loadCard(rulesReader, ze));
public final List<CardRules> loadCards() { }
progressObserver.setOperationName("Loading card data", true); return result;
progressObserver.report(0, NUMBER_OF_PARTS); }
final List<Callable<List<CardRules>>> tasks; /**
long estimatedFilesRemaining; * Starts reading cards into memory until the given card is found.
*
// Iterate through txt files or zip archive. * After that, we save our place in the list of cards (on disk) in case we
// Report relevant numbers to progress monitor model. * need to load more.
if (this.zip == null) { *
final List<File> allFiles = collectCardFiles(new ArrayList<File>(), this.cardsfolder); * @return the Card or null if it was not found.
estimatedFilesRemaining = allFiles.size(); */
tasks = makeTaskListForFiles(allFiles); public final List<CardRules> loadCards() {
} else { progressObserver.setOperationName("Loading card data", true);
estimatedFilesRemaining = this.zip.size(); progressObserver.report(0, NUMBER_OF_PARTS);
ZipEntry entry;
List<ZipEntry> entries = new ArrayList<ZipEntry>(); final List<Callable<List<CardRules>>> tasks;
// zipEnum was initialized in the constructor. long estimatedFilesRemaining;
Enumeration<? extends ZipEntry> zipEnum = this.zip.entries();
while (zipEnum.hasMoreElements()) { // Iterate through txt files or zip archive.
entry = zipEnum.nextElement(); // Report relevant numbers to progress monitor model.
if (entry.isDirectory() || !entry.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION)) if (this.zip == null) {
continue; final List<File> allFiles = collectCardFiles(new ArrayList<File>(), this.cardsfolder);
entries.add(entry); estimatedFilesRemaining = allFiles.size();
} tasks = makeTaskListForFiles(allFiles);
} else {
tasks = makeTaskListForZip(entries); estimatedFilesRemaining = this.zip.size();
} // endif ZipEntry entry;
List<ZipEntry> entries = new ArrayList<ZipEntry>();
StopWatch sw = new StopWatch(); // zipEnum was initialized in the constructor.
sw.start(); Enumeration<? extends ZipEntry> zipEnum = this.zip.entries();
while (zipEnum.hasMoreElements()) {
List<CardRules> res = executeLoadTask(tasks); entry = zipEnum.nextElement();
if (entry.isDirectory() || !entry.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION))
sw.stop(); continue;
final long timeOnParse = sw.getTime(); entries.add(entry);
System.out.printf("Read cards: %s %s in %d ms (%d parts) %s%n", estimatedFilesRemaining, zip == null? "files" : "archived files", timeOnParse, NUMBER_OF_PARTS, useThreadPool ? "using thread pool" : "in same thread"); }
// if ( null != barProgress )
// barProgress.setPercentMode(false); tasks = makeTaskListForZip(entries);
return res; } // endif
} // loadCardsUntilYouFind(String)
StopWatch sw = new StopWatch();
private List<CardRules> executeLoadTask(final List<Callable<List<CardRules>>> tasks) { sw.start();
List<CardRules> result = new ArrayList<CardRules>();
List<CardRules> res = executeLoadTask(tasks);
try {
if ( useThreadPool ) { sw.stop();
final ExecutorService executor = FThreads.getComputingPool(0.5f); final long timeOnParse = sw.getTime();
final List<Future<List<CardRules>>> parts = executor.invokeAll(tasks); System.out.printf("Read cards: %s %s in %d ms (%d parts) %s%n", estimatedFilesRemaining, zip == null? "files" : "archived files", timeOnParse, NUMBER_OF_PARTS, useThreadPool ? "using thread pool" : "in same thread");
executor.shutdown(); // if ( null != barProgress )
cdl.await(); // barProgress.setPercentMode(false);
for(Future<List<CardRules>> pp : parts) { return res;
result.addAll(pp.get()); } // loadCardsUntilYouFind(String)
}
} else { private List<CardRules> executeLoadTask(final List<Callable<List<CardRules>>> tasks) {
for(Callable<List<CardRules>> c : tasks) { List<CardRules> result = new ArrayList<CardRules>();
result.addAll(c.call());
} try {
} if ( useThreadPool ) {
} catch (InterruptedException e) { final ExecutorService executor = ThreadUtil.getComputingPool(0.5f);
e.printStackTrace(); final List<Future<List<CardRules>>> parts = executor.invokeAll(tasks);
} catch (ExecutionException e) { executor.shutdown();
e.printStackTrace(); cdl.await();
} catch (Exception e) { // this clause comes from non-threaded branch for(Future<List<CardRules>> pp : parts) {
throw new RuntimeException(e); result.addAll(pp.get());
} }
} else {
return result; for(Callable<List<CardRules>> c : tasks) {
} result.addAll(c.call());
}
private List<Callable<List<CardRules>>> makeTaskListForZip(final List<ZipEntry> entries) { }
int totalFiles = entries.size(); } catch (InterruptedException e) {
int filesPerPart = totalFiles / NUMBER_OF_PARTS; e.printStackTrace();
final List<Callable<List<CardRules>>> tasks = new ArrayList<Callable<List<CardRules>>>(); } catch (ExecutionException e) {
for (int iPart = 0; iPart < NUMBER_OF_PARTS; iPart++) { e.printStackTrace();
final int from = iPart * filesPerPart; } catch (Exception e) { // this clause comes from non-threaded branch
final int till = iPart == NUMBER_OF_PARTS - 1 ? totalFiles : from + filesPerPart; throw new RuntimeException(e);
tasks.add(new Callable<List<CardRules>>() { }
@Override
public List<CardRules> call() throws Exception{ return result;
List<CardRules> res = loadCardsInRangeFromZip(entries, from, till); }
cdl.countDown();
progressObserver.report(NUMBER_OF_PARTS - (int)cdl.getCount(), NUMBER_OF_PARTS); private List<Callable<List<CardRules>>> makeTaskListForZip(final List<ZipEntry> entries) {
return res; int totalFiles = entries.size();
} int filesPerPart = totalFiles / NUMBER_OF_PARTS;
}); final List<Callable<List<CardRules>>> tasks = new ArrayList<Callable<List<CardRules>>>();
} for (int iPart = 0; iPart < NUMBER_OF_PARTS; iPart++) {
return tasks; final int from = iPart * filesPerPart;
} final int till = iPart == NUMBER_OF_PARTS - 1 ? totalFiles : from + filesPerPart;
tasks.add(new Callable<List<CardRules>>() {
private List<Callable<List<CardRules>>> makeTaskListForFiles(final List<File> allFiles) { @Override
int totalFiles = allFiles.size(); public List<CardRules> call() throws Exception{
int filesPerPart = totalFiles / NUMBER_OF_PARTS; List<CardRules> res = loadCardsInRangeFromZip(entries, from, till);
final List<Callable<List<CardRules>>> tasks = new ArrayList<Callable<List<CardRules>>>(); cdl.countDown();
for (int iPart = 0; iPart < NUMBER_OF_PARTS; iPart++) { progressObserver.report(NUMBER_OF_PARTS - (int)cdl.getCount(), NUMBER_OF_PARTS);
final int from = iPart * filesPerPart; return res;
final int till = iPart == NUMBER_OF_PARTS - 1 ? totalFiles : from + filesPerPart; }
tasks.add(new Callable<List<CardRules>>() { });
@Override }
public List<CardRules> call() throws Exception{ return tasks;
List<CardRules> res = loadCardsInRange(allFiles, from, till); }
cdl.countDown();
progressObserver.report(NUMBER_OF_PARTS - (int)cdl.getCount(), NUMBER_OF_PARTS); private List<Callable<List<CardRules>>> makeTaskListForFiles(final List<File> allFiles) {
return res; int totalFiles = allFiles.size();
} int filesPerPart = totalFiles / NUMBER_OF_PARTS;
}); final List<Callable<List<CardRules>>> tasks = new ArrayList<Callable<List<CardRules>>>();
} for (int iPart = 0; iPart < NUMBER_OF_PARTS; iPart++) {
return tasks; final int from = iPart * filesPerPart;
} final int till = iPart == NUMBER_OF_PARTS - 1 ? totalFiles : from + filesPerPart;
tasks.add(new Callable<List<CardRules>>() {
public static List<File> collectCardFiles(List<File> accumulator, File startDir) { @Override
String[] list = startDir.list(); public List<CardRules> call() throws Exception{
for (String filename : list) { List<CardRules> res = loadCardsInRange(allFiles, from, till);
File entry = new File(startDir, filename); cdl.countDown();
progressObserver.report(NUMBER_OF_PARTS - (int)cdl.getCount(), NUMBER_OF_PARTS);
if (!entry.isDirectory()) { return res;
if (entry.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION)) }
accumulator.add(entry); });
continue; }
} return tasks;
if (filename.startsWith(".")) { }
continue;
} public static List<File> collectCardFiles(List<File> accumulator, File startDir) {
String[] list = startDir.list();
collectCardFiles(accumulator, entry); for (String filename : list) {
} File entry = new File(startDir, filename);
return accumulator;
} if (!entry.isDirectory()) {
if (entry.getName().endsWith(CardStorageReader.CARD_FILE_DOT_EXTENSION))
accumulator.add(entry);
private List<String> readScript(final InputStream inputStream) { continue;
return FileUtil.readAllLines(new InputStreamReader(inputStream, this.charset), true); }
} if (filename.startsWith(".")) {
continue;
/** }
* Load a card from a txt file.
* collectCardFiles(accumulator, entry);
* @param pathToTxtFile }
* the full or relative path to the file to load return accumulator;
* }
* @return a new Card instance
*/
protected final CardRules loadCard(final CardRules.Reader reader, final File file) { private List<String> readScript(final InputStream inputStream) {
FileInputStream fileInputStream = null; return FileUtil.readAllLines(new InputStreamReader(inputStream, this.charset), true);
try { }
fileInputStream = new FileInputStream(file);
reader.reset(); /**
List<String> lines = readScript(fileInputStream); * Load a card from a txt file.
CardRules rules = reader.readCard(lines); *
if ( null != observer ) * @param pathToTxtFile
observer.cardLoaded(rules, lines, file); * the full or relative path to the file to load
return rules; *
} catch (final FileNotFoundException ex) { * @return a new Card instance
throw new RuntimeException("CardReader : run error -- file not found: " + file.getPath(), ex); */
} finally { protected final CardRules loadCard(final CardRules.Reader reader, final File file) {
try { FileInputStream fileInputStream = null;
fileInputStream.close(); try {
} catch (final IOException ignored) { fileInputStream = new FileInputStream(file);
// 11:08 reader.reset();
// PM List<String> lines = readScript(fileInputStream);
} CardRules rules = reader.readCard(lines);
} if ( null != observer )
} observer.cardLoaded(rules, lines, file);
return rules;
/** } catch (final FileNotFoundException ex) {
* Load a card from an entry in a zip file. throw new RuntimeException("CardReader : run error -- file not found: " + file.getPath(), ex);
* } finally {
* @param entry try {
* to load from fileInputStream.close();
* } catch (final IOException ignored) {
* @return a new Card instance // 11:08
*/ // PM
protected final CardRules loadCard(final CardRules.Reader rulesReader, final ZipEntry entry) { }
InputStream zipInputStream = null; }
try { }
zipInputStream = this.zip.getInputStream(entry);
rulesReader.reset(); /**
CardRules rules = rulesReader.readCard(readScript(zipInputStream)); * Load a card from an entry in a zip file.
*
return rules; * @param entry
} catch (final IOException exn) { * to load from
throw new RuntimeException(exn); *
// PM * @return a new Card instance
} finally { */
try { protected final CardRules loadCard(final CardRules.Reader rulesReader, final ZipEntry entry) {
if (zipInputStream != null) { InputStream zipInputStream = null;
zipInputStream.close(); try {
} zipInputStream = this.zip.getInputStream(entry);
} catch (final IOException ignored) { rulesReader.reset();
// 11:08 CardRules rules = rulesReader.readCard(readScript(zipInputStream));
// PM
} return rules;
} } catch (final IOException exn) {
} throw new RuntimeException(exn);
// PM
} } finally {
try {
if (zipInputStream != null) {
zipInputStream.close();
}
} catch (final IOException ignored) {
// 11:08
// PM
}
}
}
}

View File

@@ -1,14 +0,0 @@
package forge;
import java.io.File;
import java.util.List;
import forge.card.CardRules;
public interface ICardStorageReader {
List<CardRules> loadCards();
public interface Observer {
public void cardLoaded(CardRules rules, List<String> lines, File fileOnDisk);
}
}

View File

@@ -1,12 +0,0 @@
package forge;
public interface IProgressObserver{
void setOperationName(String name, boolean usePercents);
void report(int current, int total);
// does nothing, used when they pass null instead of an instance
public final static IProgressObserver emptyObserver = new IProgressObserver() {
@Override public void setOperationName(String name, boolean usePercents) {}
@Override public void report(int current, int total) {}
};
}

View File

@@ -32,7 +32,7 @@ public class StaticData {
private static StaticData lastInstance = null; private static StaticData lastInstance = null;
public StaticData(ICardStorageReader reader, String editionFolder, String blockDataFolder) { public StaticData(CardStorageReader reader, String editionFolder, String blockDataFolder) {
this.editions = new CardEdition.Collection(new CardEdition.Reader(new File(editionFolder))); this.editions = new CardEdition.Collection(new CardEdition.Reader(new File(editionFolder)));
lastInstance = this; lastInstance = this;

View File

@@ -0,0 +1,54 @@
package forge.util;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
public class ThreadUtil {
static {
System.out.printf("(ThreadUtil first call): Running on a machine with %d cpu core(s)%n", Runtime.getRuntime().availableProcessors() );
}
private static class WorkerThreadFactory implements ThreadFactory {
private int countr = 0;
private String prefix = "";
public WorkerThreadFactory(String prefix) {
this.prefix = prefix;
}
public Thread newThread(Runnable r) {
return new Thread(r, prefix + "-" + countr++);
}
}
private final static ExecutorService gameThreadPool = Executors.newCachedThreadPool(new WorkerThreadFactory("Game"));
private static ExecutorService getGameThreadPool() { return gameThreadPool; }
private final static ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2, new WorkerThreadFactory("Delayed"));
private static ScheduledExecutorService getScheduledPool() { return scheduledPool; }
// This pool is designed to parallel CPU or IO intensive tasks like parse cards or download images, assuming a load factor of 0.5
public final static ExecutorService getComputingPool(float loadFactor) {
return Executors.newFixedThreadPool((int)(Runtime.getRuntime().availableProcessors() / (1-loadFactor)));
}
public static boolean isMultiCoreSystem() {
return Runtime.getRuntime().availableProcessors() > 1;
}
public static void invokeInGameThread(Runnable toRun) {
getGameThreadPool().execute(toRun);
}
public static void delay(int milliseconds, Runnable inputUpdater) {
getScheduledPool().schedule(inputUpdater, milliseconds, TimeUnit.MILLISECONDS);
}
public static boolean isGameThread() {
return Thread.currentThread().getName().startsWith("Game");
}
}

View File

@@ -2,53 +2,18 @@ package forge;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import forge.util.ThreadUtil;
/** /**
* TODO: Write javadoc for this type. * TODO: Write javadoc for this type.
* *
*/ */
public class FThreads { public class FThreads {
static {
System.out.printf("(FThreads static ctor): Running on a machine with %d cpu core(s)%n", Runtime.getRuntime().availableProcessors() );
}
private static class WorkerThreadFactory implements ThreadFactory {
private int countr = 0;
private String prefix = "";
public WorkerThreadFactory(String prefix) {
this.prefix = prefix;
}
public Thread newThread(Runnable r) {
return new Thread(r, prefix + "-" + countr++);
}
}
private FThreads() { } // no instances supposed private FThreads() { } // no instances supposed
private final static ExecutorService gameThreadPool = Executors.newCachedThreadPool(new WorkerThreadFactory("Game"));
private static ExecutorService getGameThreadPool() { return gameThreadPool; }
private final static ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2, new WorkerThreadFactory("Delayed"));
private static ScheduledExecutorService getScheduledPool() { return scheduledPool; }
// This pool is designed to parallel CPU or IO intensive tasks like parse cards or download images, assuming a load factor of 0.5
public final static ExecutorService getComputingPool(float loadFactor) {
return Executors.newFixedThreadPool((int)(Runtime.getRuntime().availableProcessors() / (1-loadFactor)));
}
public static boolean isMultiCoreSystem() {
return Runtime.getRuntime().availableProcessors() > 1;
}
/** Checks if calling method uses event dispatch thread. /** Checks if calling method uses event dispatch thread.
* Exception thrown if method is on "wrong" thread. * Exception thrown if method is on "wrong" thread.
* A boolean is passed to indicate if the method must be EDT or not. * A boolean is passed to indicate if the method must be EDT or not.
@@ -111,9 +76,7 @@ public class FThreads {
} }
public static void invokeInGameThread(Runnable toRun) {
getGameThreadPool().execute(toRun);
}
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
@@ -124,17 +87,13 @@ public class FThreads {
} }
public static void delay(int milliseconds, Runnable inputUpdater) {
getScheduledPool().schedule(inputUpdater, milliseconds, TimeUnit.MILLISECONDS);
}
public static void delayInEDT(int milliseconds, final Runnable inputUpdater) { public static void delayInEDT(int milliseconds, final Runnable inputUpdater) {
Runnable runInEdt = new Runnable() { Runnable runInEdt = new Runnable() {
@Override public void run() { @Override public void run() {
FThreads.invokeInEdtNowOrLater(inputUpdater); FThreads.invokeInEdtNowOrLater(inputUpdater);
} }
}; };
delay(milliseconds, runInEdt); ThreadUtil.delay(milliseconds, runInEdt);
} }
public static String debugGetCurrThreadId() { public static String debugGetCurrThreadId() {
@@ -171,9 +130,4 @@ public class FThreads {
public static String debugGetStackTraceItem(int depth) { public static String debugGetStackTraceItem(int depth) {
return debugGetStackTraceItem(depth, false); return debugGetStackTraceItem(depth, false);
} }
public static boolean isGameThread() {
return Thread.currentThread().getName().startsWith("Game");
}
} }

View File

@@ -17,11 +17,9 @@
*/ */
package forge; package forge;
import forge.card.cardfactory.CardStorageReader;
import forge.control.FControl; import forge.control.FControl;
import forge.gui.toolbox.FProgressBar; import forge.gui.toolbox.FProgressBar;
import forge.gui.workshop.CardScriptInfo; import forge.gui.workshop.CardScriptInfo;
import forge.gui.workshop.controllers.CCardScript;
import forge.model.FModel; import forge.model.FModel;
import forge.properties.NewConstants; import forge.properties.NewConstants;
import forge.view.FView; import forge.view.FView;
@@ -57,7 +55,8 @@ public final class Singletons {
if(withUi) if(withUi)
view = FView.SINGLETON_INSTANCE; view = FView.SINGLETON_INSTANCE;
IProgressObserver progressBarBridge = view == null ? IProgressObserver.emptyObserver : new IProgressObserver() { CardStorageReader.ProgressObserver progressBarBridge = view == null
? CardStorageReader.ProgressObserver.emptyObserver : new CardStorageReader.ProgressObserver() {
FProgressBar bar = view.getSplash().getProgressBar(); FProgressBar bar = view.getSplash().getProgressBar();
@Override @Override
public void setOperationName(final String name, final boolean usePercents) { public void setOperationName(final String name, final boolean usePercents) {

View File

@@ -75,6 +75,7 @@ import forge.game.zone.Zone;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.CollectionSuppliers; import forge.util.CollectionSuppliers;
import forge.util.ThreadUtil;
import forge.util.maps.HashMapOfLists; import forge.util.maps.HashMapOfLists;
import forge.util.maps.MapOfLists; import forge.util.maps.MapOfLists;
@@ -1620,10 +1621,10 @@ public class GameAction {
// Invokes given runnable in Game thread pool - used to start game and perform actions from UI (when game-0 waits for input) // Invokes given runnable in Game thread pool - used to start game and perform actions from UI (when game-0 waits for input)
public void invoke(final Runnable proc) { public void invoke(final Runnable proc) {
if( FThreads.isGameThread() ) { if( ThreadUtil.isGameThread() ) {
proc.run(); proc.run();
} else } else
FThreads.invokeInGameThread(proc); ThreadUtil.invokeInGameThread(proc);
} }
} }

View File

@@ -26,12 +26,12 @@ import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement; import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent; import javax.xml.stream.events.XMLEvent;
import forge.FThreads;
import forge.Singletons; import forge.Singletons;
import forge.gui.toolbox.FAbsolutePositioner; import forge.gui.toolbox.FAbsolutePositioner;
import forge.properties.FileLocation; import forge.properties.FileLocation;
import forge.properties.NewConstants; import forge.properties.NewConstants;
import forge.util.CollectionSuppliers; import forge.util.CollectionSuppliers;
import forge.util.ThreadUtil;
import forge.util.maps.HashMapOfLists; import forge.util.maps.HashMapOfLists;
import forge.util.maps.MapOfLists; import forge.util.maps.MapOfLists;
import forge.view.FFrame; import forge.view.FFrame;
@@ -63,7 +63,7 @@ public final class SLayoutIO {
public static void saveWindowLayout() { public static void saveWindowLayout() {
if (saveWindowRequested.getAndSet(true)) { return; } if (saveWindowRequested.getAndSet(true)) { return; }
FThreads.delay(500, new Runnable() { ThreadUtil.delay(500, new Runnable() {
@Override @Override
public void run() { public void run() {
finishSaveWindowLayout(); finishSaveWindowLayout();
@@ -230,7 +230,7 @@ public final class SLayoutIO {
*/ */
public static void saveLayout(final File f0) { public static void saveLayout(final File f0) {
if( saveRequested.getAndSet(true) ) return; if( saveRequested.getAndSet(true) ) return;
FThreads.delay(100, new Runnable() { ThreadUtil.delay(100, new Runnable() {
@Override @Override
public void run() { public void run() {

View File

@@ -22,13 +22,13 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import forge.Card; import forge.Card;
import forge.FThreads;
import forge.game.Game; import forge.game.Game;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.gui.GuiDialog; import forge.gui.GuiDialog;
import forge.gui.match.CMatchUI; import forge.gui.match.CMatchUI;
import forge.util.Lang; import forge.util.Lang;
import forge.util.ThreadUtil;
import forge.view.ButtonUtil; import forge.view.ButtonUtil;
/** /**
* <p> * <p>
@@ -122,7 +122,7 @@ public class InputConfirmMulligan extends InputSyncronizedBase {
if ( isSerumPowder && GuiDialog.confirm(c0, "Use " + c0.getName() + "'s ability?")) { if ( isSerumPowder && GuiDialog.confirm(c0, "Use " + c0.getName() + "'s ability?")) {
cardSelectLocked = true; cardSelectLocked = true;
FThreads.invokeInGameThread(new Runnable() { ThreadUtil.invokeInGameThread(new Runnable() {
public void run() { public void run() {
List<Card> hand = new ArrayList<Card>(c0.getController().getCardsIn(ZoneType.Hand)); List<Card> hand = new ArrayList<Card>(c0.getController().getCardsIn(ZoneType.Hand));
for (Card c : hand) { for (Card c : hand) {

View File

@@ -10,6 +10,7 @@ import forge.card.spellability.SpellAbility;
import forge.control.InputQueue; import forge.control.InputQueue;
import forge.game.player.Player; import forge.game.player.Player;
import forge.gui.match.CMatchUI; import forge.gui.match.CMatchUI;
import forge.util.ThreadUtil;
import forge.view.ButtonUtil; import forge.view.ButtonUtil;
/** /**
@@ -24,7 +25,7 @@ public class InputLockUI implements Input {
public void showMessageInitial() { public void showMessageInitial() {
int ixCall = 1 + iCall.getAndIncrement(); int ixCall = 1 + iCall.getAndIncrement();
FThreads.delay(500, new InputUpdater(ixCall)); ThreadUtil.delay(500, new InputUpdater(ixCall));
} }
@Override @Override

View File

@@ -20,12 +20,11 @@ package forge.gui.workshop;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import forge.ICardStorageReader; import forge.CardStorageReader;
import forge.card.CardRules; import forge.card.CardRules;
public final class CardScriptInfo { public final class CardScriptInfo {
@@ -58,7 +57,7 @@ public final class CardScriptInfo {
return allScrips.get(name); return allScrips.get(name);
} }
public static ICardStorageReader.Observer readerObserver = new ICardStorageReader.Observer() { public static CardStorageReader.Observer readerObserver = new CardStorageReader.Observer() {
@Override @Override
public void cardLoaded(CardRules rules, List<String> lines, File fileOnDisk) { public void cardLoaded(CardRules rules, List<String> lines, File fileOnDisk) {
allScrips.put(rules.getName(), new CardScriptInfo(StringUtils.join(lines, '\n'), fileOnDisk)); allScrips.put(rules.getName(), new CardScriptInfo(StringUtils.join(lines, '\n'), fileOnDisk));

View File

@@ -11,8 +11,8 @@ import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import forge.CardStorageReader;
import forge.card.CardRules; import forge.card.CardRules;
import forge.card.cardfactory.CardStorageReader;
import forge.properties.NewConstants; import forge.properties.NewConstants;
import forge.util.FileUtil; import forge.util.FileUtil;