Add Net Decks support

This commit is contained in:
drdev
2015-01-25 05:10:32 +00:00
parent f3a30793c5
commit 30fbe55ac3
25 changed files with 756 additions and 251 deletions

View File

@@ -445,6 +445,14 @@ public class DeckProxy implements InventoryItem {
return decks;
}
public static List<DeckProxy> getNetDecks(NetDeckCategory category) {
ArrayList<DeckProxy> decks = new ArrayList<DeckProxy>();
if (category != null) {
addDecksRecursivelly("Constructed", GameType.Constructed, decks, "", category);
}
return decks;
}
public static final Predicate<DeckProxy> IS_WHITE = new Predicate<DeckProxy>() {
@Override
public boolean apply(final DeckProxy deck) {

View File

@@ -6,7 +6,8 @@ public enum DeckType {
QUEST_OPPONENT_DECK ("Quest Opponent Decks"),
COLOR_DECK ("Random Color Decks"),
THEME_DECK ("Random Theme Decks"),
RANDOM_DECK ("Random Decks");
RANDOM_DECK ("Random Decks"),
NET_DECK ("Net Decks");
private String value;
private DeckType(String value) {

View File

@@ -0,0 +1,127 @@
package forge.deck;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import forge.GuiBase;
import forge.deck.io.DeckSerializer;
import forge.deck.io.DeckStorage;
import forge.download.GuiDownloadZipService;
import forge.game.GameType;
import forge.properties.ForgeConstants;
import forge.util.FileUtil;
import forge.util.WaitCallback;
import forge.util.gui.SGuiChoose;
import forge.util.storage.StorageBase;
public class NetDeckCategory extends StorageBase<Deck> {
public static final String PREFIX = "NET_DECK_";
private static Map<String, NetDeckCategory> constructed, commander;
private static Map<String, NetDeckCategory> loadCategories(String filename) {
Map<String, NetDeckCategory> categories = new TreeMap<String, NetDeckCategory>();
if (FileUtil.doesFileExist(filename)) {
List<String> lines = FileUtil.readFile(filename);
for (String line : lines) {
int idx = line.indexOf('|');
if (idx != -1) {
String name = line.substring(0, idx).trim();
String url = line.substring(idx + 1).trim();
categories.put(name, new NetDeckCategory(name, url));
}
}
}
return categories;
}
public static NetDeckCategory selectAndLoad(GameType gameType) {
return selectAndLoad(gameType, null);
}
public static NetDeckCategory selectAndLoad(GameType gameType, String name) {
Map<String, NetDeckCategory> categories;
switch (gameType) {
case Constructed:
case Gauntlet:
if (constructed == null) {
constructed = loadCategories(ForgeConstants.NET_DECKS_LIST_FILE);
}
categories = constructed;
break;
case Commander:
if (commander == null) {
commander = loadCategories(ForgeConstants.NET_DECKS_COMMANDER_LIST_FILE);
}
categories = commander;
break;
default:
return null;
}
if (name != null) {
NetDeckCategory category = categories.get(name);
if (category != null && category.map.isEmpty()) {
//if name passed in, try to load decks from current cached files
File downloadDir = new File(category.getDownloadLocation());
if (downloadDir.exists()) {
for (File file : downloadDir.listFiles(DeckStorage.DCK_FILE_FILTER)) {
Deck deck = DeckSerializer.fromFile(file);
if (deck != null) {
category.map.put(deck.getName(), deck);
}
}
}
}
return category;
}
final NetDeckCategory c= SGuiChoose.oneOrNone("Select a Net Deck category", categories.values());
if (c == null) { return null; }
if (c.map.isEmpty()) { //only download decks once per session
WaitCallback<Boolean> callback = new WaitCallback<Boolean>() {
@Override
public void run() {
String downloadLoc = c.getDownloadLocation();
GuiBase.getInterface().download(new GuiDownloadZipService(c.getName(), "decks", c.getUrl(), downloadLoc, downloadLoc, null) {
@Override
protected void copyInputStream(InputStream in, String outPath) throws IOException {
super.copyInputStream(in, outPath);
Deck deck = DeckSerializer.fromFile(new File(outPath));
if (deck != null) {
c.map.put(deck.getName(), deck);
}
}
}, this);
}
};
if (!callback.invokeAndWait()) { return null; } //wait for download to finish
}
return c;
}
private final String url;
private NetDeckCategory(String name0, String downloadLocation0) {
super(name0, new HashMap<String, Deck>());
url = downloadLocation0;
}
public String getDownloadLocation() {
return ForgeConstants.DECK_NET_DIR + name + "/";
}
public String getUrl() {
return url;
}
@Override
public String toString() {
return "Net Decks - " + name;
}
}

View File

@@ -53,7 +53,7 @@ public abstract class GuiDownloadService implements Runnable {
//Components passed from GUI component displaying download
private ITextField txtAddress;
private ITextField txtPort;
private IProgressBar progressBar;
protected IProgressBar progressBar;
private IButton btnStart;
private UiCommand cmdClose;
private Runnable onUpdate;
@@ -73,7 +73,7 @@ public abstract class GuiDownloadService implements Runnable {
// Progress variables
private Map<String, String> files; // local path -> url
private boolean cancel;
protected boolean cancel;
private final long[] times = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
private int tptr = 0;
private int skipped = 0;
@@ -90,27 +90,50 @@ public abstract class GuiDownloadService implements Runnable {
cmdClose = cmdClose0;
onUpdate = onUpdate0;
// Free up the EDT by assembling card list on a background thread
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
try {
files = getNeededFiles();
}
catch (Exception e) {
e.printStackTrace();
}
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (onReadyToStart != null) {
onReadyToStart.run();
}
readyToStart();
String startOverrideDesc = getStartOverrideDesc();
if (startOverrideDesc == null) {
// Free up the EDT by assembling card list on a background thread
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
try {
files = getNeededFiles();
}
});
catch (Exception e) {
e.printStackTrace();
}
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (onReadyToStart != null) {
onReadyToStart.run();
}
readyToStart();
}
});
}
});
}
else {
//handle special case of zip service
if (onReadyToStart != null) {
onReadyToStart.run();
}
});
progressBar.setDescription("Click \"Start\" to download and extract " + startOverrideDesc);
btnStart.setCommand(cmdStartDownload);
btnStart.setEnabled(true);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
btnStart.requestFocusInWindow();
}
});
}
}
protected String getStartOverrideDesc() {
return null;
}
private void readyToStart() {
@@ -198,10 +221,7 @@ public abstract class GuiDownloadService implements Runnable {
else {
sb.append(String.format("%d of %d items finished! Skipped " + skipped + " items. Please close!",
count, files.size()));
btnStart.setText("OK");
btnStart.setCommand(cmdClose);
btnStart.setEnabled(true);
btnStart.requestFocusInWindow();
finish();
}
progressBar.setValue(count);
@@ -211,25 +231,18 @@ public abstract class GuiDownloadService implements Runnable {
});
}
protected void finish() {
btnStart.setText("OK");
btnStart.setCommand(cmdClose);
btnStart.setEnabled(true);
btnStart.requestFocusInWindow();
}
@Override
public final void run() {
public void run() {
final Random r = MyRandom.getRandom();
Proxy p = null;
if (type == 0) {
p = Proxy.NO_PROXY;
}
else {
try {
p = new Proxy(TYPES[type], new InetSocketAddress(txtAddress.getText(), Integer.parseInt(txtPort.getText())));
}
catch (final Exception ex) {
BugReporter.reportException(ex,
"Proxy connection could not be established!\nProxy address: %s\nProxy port: %s",
txtAddress.getText(), txtPort.getText());
return;
}
}
Proxy p = getProxy();
int bufferLength;
int iCard = 0;
@@ -304,6 +317,23 @@ public abstract class GuiDownloadService implements Runnable {
}
}
protected Proxy getProxy() {
if (type == 0) {
return Proxy.NO_PROXY;
}
else {
try {
return new Proxy(TYPES[type], new InetSocketAddress(txtAddress.getText(), Integer.parseInt(txtPort.getText())));
}
catch (final Exception ex) {
BugReporter.reportException(ex,
"Proxy connection could not be established!\nProxy address: %s\nProxy port: %s",
txtAddress.getText(), txtPort.getText());
}
}
return null;
}
public abstract String getTitle();
protected abstract Map<String, String> getNeededFiles();

View File

@@ -0,0 +1,203 @@
package forge.download;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import com.esotericsoftware.minlog.Log;
import com.google.common.io.Files;
import forge.FThreads;
import forge.interfaces.IProgressBar;
import forge.util.FileUtil;
public class GuiDownloadZipService extends GuiDownloadService {
private final String name, desc, sourceUrl, destFolder, deleteFolder;
private int filesDownloaded;
public GuiDownloadZipService(String name0, String desc0, String sourceUrl0, String destFolder0, String deleteFolder0, IProgressBar progressBar0) {
name = name0;
desc = desc0;
sourceUrl = sourceUrl0;
destFolder = destFolder0;
deleteFolder = deleteFolder0;
progressBar = progressBar0;
}
@Override
public String getTitle() {
return "Download " + name;
}
@Override
protected String getStartOverrideDesc() {
return desc;
}
@Override
protected final Map<String, String> getNeededFiles() {
HashMap<String, String> files = new HashMap<String, String>();
files.put("_", "_");
return files; //not needed by zip service, so just return map of size 1
}
@Override
public final void run() {
downloadAndUnzip();
if (!cancel) {
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override
public void run() {
progressBar.setDescription(filesDownloaded + " " + desc + " downloaded");
finish();
}
});
}
}
public void downloadAndUnzip() {
filesDownloaded = 0;
String zipFilename = download("temp.zip");
if (zipFilename == null) { return; }
//if assets.zip downloaded successfully, unzip into destination folder
try {
if (deleteFolder != null) {
File deleteDir = new File(deleteFolder);
if (deleteDir.exists()) {
//attempt to delete previous res directory if to be rebuilt
progressBar.reset();
progressBar.setDescription("Deleting old " + desc + "...");
if (deleteFolder.equals(destFolder)) { //move zip file to prevent deleting it
String oldZipFilename = zipFilename;
zipFilename = deleteDir.getParentFile().getAbsolutePath() + File.separator + "temp.zip";
Files.move(new File(oldZipFilename), new File(zipFilename));
}
FileUtil.deleteDirectory(deleteDir);
}
}
ZipFile zipFile = new ZipFile(zipFilename, Charset.forName("CP866")); //ensure unzip doesn't fail due to non UTF-8 chars
Enumeration<? extends ZipEntry> entries = zipFile.entries();
progressBar.reset();
progressBar.setPercentMode(true);
progressBar.setDescription("Extracting " + desc);
progressBar.setMaximum(zipFile.size());
FileUtil.ensureDirectoryExists(destFolder);
int count = 0;
while (entries.hasMoreElements()) {
if (cancel) { break; }
ZipEntry entry = (ZipEntry)entries.nextElement();
String path = destFolder + entry.getName();
if (entry.isDirectory()) {
new File(path).mkdir();
progressBar.setValue(++count);
continue;
}
copyInputStream(zipFile.getInputStream(entry), path);
progressBar.setValue(++count);
filesDownloaded++;
}
zipFile.close();
new File(zipFilename).delete();
}
catch (Exception e) {
e.printStackTrace();
}
}
public String download(String filename) {
progressBar.reset();
progressBar.setPercentMode(true);
progressBar.setDescription("Downloading " + desc);
try {
URL url = new URL(sourceUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection(getProxy());
if (url.getPath().endsWith(".php")) {
//ensure file can be downloaded if returned from PHP script
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT)");
}
conn.connect();
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
return null;
}
long contentLength = conn.getContentLengthLong();
if (contentLength == 0) {
return null;
}
progressBar.setMaximum(100);
// input stream to read file - with 8k buffer
InputStream input = new BufferedInputStream(conn.getInputStream(), 8192);
FileUtil.ensureDirectoryExists(destFolder);
// output stream to write file
String destFile = destFolder + filename;
OutputStream output = new FileOutputStream(destFile);
int count;
long total = 0;
byte data[] = new byte[1024];
while ((count = input.read(data)) != -1) {
if (cancel) { break; }
total += count;
progressBar.setValue((int)(100 * total / contentLength));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
if (cancel) {
new File(destFile).delete();
return null;
}
return destFile;
}
catch (final Exception ex) {
Log.error("Downloading " + desc, "Error downloading " + desc, ex);
}
return null;
}
protected void copyInputStream(InputStream in, String outPath) throws IOException{
byte[] buffer = new byte[1024];
int len;
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(outPath));
while((len = in.read(buffer)) >= 0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
}
}

View File

@@ -10,6 +10,7 @@ import forge.LobbyPlayer;
import forge.assets.FSkinProp;
import forge.assets.ISkinImage;
import forge.deck.CardPool;
import forge.download.GuiDownloadService;
import forge.game.GameEntity;
import forge.game.GameEntityView;
import forge.game.card.CardView;
@@ -19,6 +20,7 @@ import forge.item.PaperCard;
import forge.player.PlayerControllerHuman;
import forge.sound.IAudioClip;
import forge.sound.IAudioMusic;
import forge.util.Callback;
import forge.util.FCollectionView;
public interface IGuiBase {
@@ -45,6 +47,7 @@ public interface IGuiBase {
GameEntityView chooseSingleEntityForEffect(String title, FCollectionView<? extends GameEntity> optionList, DelayedReveal delayedReveal, boolean isOptional, PlayerControllerHuman controller);
String showFileDialog(String title, String defaultDir);
File getSaveFile(File defaultFile);
void download(GuiDownloadService service, Callback<Boolean> callback);
void showCardList(final String title, final String message, final List<PaperCard> list);
boolean showBoxedProduct(final String title, final String message, final List<PaperCard> list);
void setCard(CardView card);

View File

@@ -88,6 +88,8 @@ public enum ItemManagerConfig {
null, null, 3, 0),
QUEST_EVENT_DECKS(SColumnUtil.getDecksDefaultColumns(false, false), false, false, false,
null, null, 3, 0),
NET_DECKS(SColumnUtil.getDecksDefaultColumns(false, false), false, false, false,
null, null, 3, 0),
SIDEBOARD(SColumnUtil.getDeckEditorDefaultColumns(), false, false, true,
GroupDef.DEFAULT, ColumnDef.CMC, 3, 0);

View File

@@ -40,6 +40,8 @@ public final class ForgeConstants {
public static final String IMAGE_LIST_QUEST_BOOSTERBOXES_FILE = LISTS_DIR + "boosterbox-images.txt";
public static final String IMAGE_LIST_QUEST_PRECONS_FILE = LISTS_DIR + "precon-images.txt";
public static final String IMAGE_LIST_QUEST_TOURNAMENTPACKS_FILE = LISTS_DIR + "tournamentpack-images.txt";
public static final String NET_DECKS_LIST_FILE = LISTS_DIR + "net-decks.txt";
public static final String NET_DECKS_COMMANDER_LIST_FILE = LISTS_DIR + "net-decks-commander.txt";
public static final String CHANGES_FILE = ASSETS_DIR + "CHANGES.txt";
public static final String LICENSE_FILE = ASSETS_DIR + "LICENSE.txt";
@@ -114,6 +116,7 @@ public final class ForgeConstants {
public static final String DECK_SCHEME_DIR = DECK_BASE_DIR + "scheme/";
public static final String DECK_PLANE_DIR = DECK_BASE_DIR + "planar/";
public static final String DECK_COMMANDER_DIR = DECK_BASE_DIR + "commander/";
public static final String DECK_NET_DIR = DECK_BASE_DIR + "net/";
public static final String QUEST_SAVE_DIR = USER_QUEST_DIR + "saves/";
public static final String CONQUEST_SAVE_DIR = USER_CONQUEST_DIR + "saves/";
public static final String MAIN_PREFS_FILE = USER_PREFS_DIR + "forge.preferences";
@@ -159,6 +162,8 @@ public final class ForgeConstants {
DECK_SEALED_DIR,
DECK_SCHEME_DIR,
DECK_PLANE_DIR,
DECK_COMMANDER_DIR,
DECK_NET_DIR,
QUEST_SAVE_DIR,
CACHE_TOKEN_PICS_DIR,
CACHE_ICON_PICS_DIR,