Start working on more reliable way to load and save Planar Conquest data

This commit is contained in:
drdev
2015-12-27 00:31:24 +00:00
parent 36c16ebe08
commit 6a9d30e931
11 changed files with 284 additions and 202 deletions

3
.gitattributes vendored
View File

@@ -18306,7 +18306,6 @@ forge-gui/src/main/java/forge/net/server/package-info.java -text
forge-gui/src/main/java/forge/planarconquest/ConquestCommander.java -text
forge-gui/src/main/java/forge/planarconquest/ConquestController.java -text
forge-gui/src/main/java/forge/planarconquest/ConquestData.java -text
forge-gui/src/main/java/forge/planarconquest/ConquestDataIO.java -text
forge-gui/src/main/java/forge/planarconquest/ConquestDeckMap.java -text
forge-gui/src/main/java/forge/planarconquest/ConquestEvent.java -text
forge-gui/src/main/java/forge/planarconquest/ConquestLocation.java -text
@@ -18403,7 +18402,9 @@ forge-gui/src/main/java/forge/util/OperatingSystem.java -text
forge-gui/src/main/java/forge/util/RestartUtil.java -text
forge-gui/src/main/java/forge/util/WaitCallback.java -text
forge-gui/src/main/java/forge/util/WaitRunnable.java -text
forge-gui/src/main/java/forge/util/XmlReader.java -text
forge-gui/src/main/java/forge/util/XmlUtil.java -text
forge-gui/src/main/java/forge/util/XmlWriter.java -text
forge-gui/src/main/java/forge/util/gui/SGuiChoose.java -text
forge-gui/src/main/java/forge/util/gui/SOptionPane.java -text
forge-gui/src/main/java/forge/util/package-info.java -text

View File

@@ -10,7 +10,7 @@ import forge.deck.FDeckEditor.EditorType;
import forge.menu.FMenuItem;
import forge.menu.FPopupMenu;
import forge.model.FModel;
import forge.planarconquest.ConquestDataIO;
import forge.planarconquest.ConquestData;
import forge.planarconquest.ConquestPreferences.CQPref;
import forge.properties.ForgeConstants;
import forge.screens.FScreen;
@@ -75,14 +75,14 @@ public class ConquestMenu extends FPopupMenu {
public static void launchPlanarConquest(final LaunchReason reason) {
//attempt to load current quest
final File dirConquests = new File(ForgeConstants.CONQUEST_SAVE_DIR);
final String questname = FModel.getConquestPreferences().getPref(CQPref.CURRENT_CONQUEST);
final File data = new File(dirConquests.getPath(), questname);
final String conquestname = FModel.getConquestPreferences().getPref(CQPref.CURRENT_CONQUEST);
final File data = new File(dirConquests.getPath(), conquestname);
if (data.exists()) {
LoadingOverlay.show("Loading current conquest...", new Runnable() {
@Override
@SuppressWarnings("unchecked")
public void run() {
FModel.getConquest().load(ConquestDataIO.loadData(data));
FModel.getConquest().load(new ConquestData(data));
((DeckController<Deck>)EditorType.PlanarConquest.getController()).setRootFolder(FModel.getConquest().getDecks());
if (reason == LaunchReason.StartPlanarConquest) {
Forge.openScreen(multiverseScreen);

View File

@@ -1,7 +1,6 @@
package forge.screens.planarconquest;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -21,7 +20,6 @@ import forge.assets.FSkinImage;
import forge.model.FModel;
import forge.planarconquest.ConquestController;
import forge.planarconquest.ConquestData;
import forge.planarconquest.ConquestDataIO;
import forge.planarconquest.ConquestPreferences.CQPref;
import forge.properties.ForgeConstants;
import forge.quest.QuestUtil;
@@ -93,17 +91,11 @@ public class LoadConquestScreen extends LaunchScreen {
final File dirConquests = new File(ForgeConstants.CONQUEST_SAVE_DIR);
final ConquestController qc = FModel.getConquest();
// Iterate over files and load quest data for each.
FilenameFilter takeDatFiles = new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
return name.endsWith(".dat");
}
};
File[] arrFiles = dirConquests.listFiles(takeDatFiles);
Map<String, ConquestData> arrConquests = new HashMap<String, ConquestData>();
for (File f : arrFiles) {
arrConquests.put(f.getName(), ConquestDataIO.loadData(f));
for (File f : dirConquests.listFiles()) {
if (f.isDirectory()) {
arrConquests.put(f.getName(), new ConquestData(f));
}
}
// Populate list with available quest data.

View File

@@ -5,8 +5,10 @@ import forge.deck.generation.DeckGenPool;
import forge.item.InventoryItem;
import forge.item.PaperCard;
import forge.planarconquest.ConquestPlane.Region;
import forge.util.XmlWriter;
import forge.util.XmlWriter.IXmlWritable;
public class ConquestCommander implements InventoryItem {
public class ConquestCommander implements InventoryItem, IXmlWritable {
private final PaperCard card;
private final Deck deck;
private final ConquestRecord record;
@@ -93,4 +95,10 @@ public class ConquestCommander implements InventoryItem {
public String toString() {
return card.getName();
}
@Override
public void saveToXml(XmlWriter xml) {
xml.write("card", card);
xml.write("record", record);
}
}

View File

@@ -30,7 +30,10 @@ import forge.model.FModel;
import forge.planarconquest.ConquestPlane.Region;
import forge.planarconquest.ConquestPreferences.CQPref;
import forge.properties.ForgeConstants;
import forge.util.FileUtil;
import forge.util.ItemPool;
import forge.util.XmlReader;
import forge.util.XmlWriter;
import java.io.File;
import java.util.ArrayList;
@@ -45,23 +48,17 @@ import java.util.Map.Entry;
import com.google.common.base.Function;
public final class ConquestData {
/** Holds the latest version of the Conquest Data. */
public static final int CURRENT_VERSION_NUMBER = 0;
// This field places the version number into QD instance,
// but only when the object is created through the constructor
// DO NOT RENAME THIS FIELD
private int versionNumber = ConquestData.CURRENT_VERSION_NUMBER;
private static final String XML_FILE = "data.xml";
private String name;
private ConquestPlane startingPlane;
private PaperCard planeswalker;
private ISkinImage planeswalkerToken;
private ConquestLocation currentLocation;
private int aetherShards;
private ConquestCollection collection;
private transient ConquestCollection collection; //don't serialize this
private final File directory;
private final String xmlFilename;
private final EnumMap<ConquestPlane, ConquestPlaneData> planeDataMap = new EnumMap<ConquestPlane, ConquestPlaneData>(ConquestPlane.class);
private final HashSet<PaperCard> unlockedCards = new HashSet<PaperCard>();
private final List<ConquestCommander> commanders = new ArrayList<ConquestCommander>();
@@ -69,26 +66,44 @@ public final class ConquestData {
private final ItemPool<InventoryItem> decksUsingMyCards = new ItemPool<InventoryItem>(InventoryItem.class);
private final HashSet<PaperCard> newCards = new HashSet<PaperCard>();
public ConquestData() { //needed for XML serialization
}
public ConquestData(String name0, PaperCard planeswalker0, ConquestPlane startingPlane0, PaperCard startingCommander0) {
name = name0;
directory = new File(ForgeConstants.CONQUEST_SAVE_DIR, name);
xmlFilename = directory.getPath() + ForgeConstants.PATH_SEPARATOR + XML_FILE;
aetherShards = FModel.getConquestPreferences().getPrefInt(CQPref.AETHER_START_SHARDS);
startingPlane = startingPlane0;
currentLocation = new ConquestLocation(startingPlane, 0, 0, Region.START_COL);
currentLocation = new ConquestLocation(startingPlane0, 0, 0, Region.START_COL);
planeswalker = planeswalker0;
planeswalkerToken = PlaneswalkerAchievements.getTrophyImage(planeswalker.getName());
unlockCard(planeswalker);
//generate deck for starting commander and add all cards to collection
ConquestCommander commander = new ConquestCommander(startingCommander0, startingPlane.getCardPool(), false);
ConquestCommander commander = new ConquestCommander(startingCommander0, startingPlane0.getCardPool(), false);
commanders.add(commander);
unlockCard(startingCommander0);
unlockCards(commander.getDeck().getMain().toFlatList());
decks.put(commander.getDeck().getName(), commander.getDeck());
}
public ConquestData(File directory0) {
name = directory0.getName();
directory = directory0;
xmlFilename = directory.getPath() + ForgeConstants.PATH_SEPARATOR + XML_FILE;
try {
XmlReader xml = new XmlReader(xmlFilename);
planeswalker = xml.read("planeswalker", planeswalker);
aetherShards = xml.read("aetherShards", aetherShards);
currentLocation = xml.read("currentLocation", currentLocation, ConquestLocation.class);
/*xml.read("unlockedCards", unlockedCards);
xml.read("newCards", newCards);
xml.read("commanders", commanders);
xml.read("planeDataMap", planeDataMap);*/
}
catch (Exception e) {
e.printStackTrace();
}
}
public String getName() {
return name;
}
@@ -101,10 +116,6 @@ public final class ConquestData {
return planeswalkerToken;
}
public ConquestPlane getStartingPlane() {
return startingPlane;
}
public ConquestPlane getCurrentPlane() {
return currentLocation.getPlane();
}
@@ -207,30 +218,28 @@ public final class ConquestData {
return Math.round(100f * (float)conquered / (float)total) + "%";
}
// SERIALIZATION - related things
// This must be called by XML-serializer via reflection
public Object readResolve() {
return this;
}
public void saveData() {
ConquestDataIO.saveData(this);
}
FileUtil.ensureDirectoryExists(directory);
public int getVersionNumber() {
return versionNumber;
try {
XmlWriter xml = new XmlWriter(xmlFilename, "data");
xml.write("planeswalker", planeswalker);
xml.write("aetherShards", aetherShards);
xml.write("currentLocation", currentLocation);
xml.write("unlockedCards", unlockedCards);
xml.write("newCards", newCards);
xml.write("commanders", commanders);
xml.write("planeDataMap", planeDataMap);
xml.close();
}
catch (Exception e) {
e.printStackTrace();
}
public void setVersionNumber(final int versionNumber0) {
versionNumber = versionNumber0;
}
public void rename(final String newName) {
File newpath = new File(ForgeConstants.CONQUEST_SAVE_DIR, newName + ".dat");
File oldpath = new File(ForgeConstants.CONQUEST_SAVE_DIR, name + ".dat");
oldpath.renameTo(newpath);
name = newName;
saveData();
directory.renameTo(new File(ForgeConstants.CONQUEST_SAVE_DIR, name));
}
public void updateDecksForEachCard() {

View File

@@ -1,143 +0,0 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.planarconquest;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.xml.sax.InputSource;
import com.thoughtworks.xstream.XStream;
import forge.deck.CardPool;
import forge.properties.ForgeConstants;
import forge.quest.io.QuestDataIO.DeckToXml;
import forge.quest.io.QuestDataIO.ItemPoolToXml;
import forge.util.FileUtil;
import forge.util.IgnoringXStream;
import forge.util.ItemPool;
public class ConquestDataIO {
static {
//ensure save directory exists if this class is used
FileUtil.ensureDirectoryExists(ForgeConstants.CONQUEST_SAVE_DIR);
}
protected static XStream getSerializer(final boolean isIgnoring) {
final XStream xStream = isIgnoring ? new IgnoringXStream() : new XStream();
xStream.registerConverter(new ItemPoolToXml());
xStream.registerConverter(new DeckToXml());
xStream.autodetectAnnotations(true);
xStream.alias("CardPool", ItemPool.class);
xStream.alias("DeckSection", CardPool.class);
return xStream;
}
public static ConquestData loadData(final File xmlSaveFile) {
try {
ConquestData data = null;
final GZIPInputStream zin = new GZIPInputStream(new FileInputStream(xmlSaveFile));
final StringBuilder xml = new StringBuilder();
final char[] buf = new char[1024];
final InputStreamReader reader = new InputStreamReader(zin);
while (reader.ready()) {
final int len = reader.read(buf);
if (len == -1) {
break;
} // when end of stream was reached
xml.append(buf, 0, len);
}
zin.close();
String bigXML = xml.toString();
data = (ConquestData) ConquestDataIO.getSerializer(true).fromXML(bigXML);
if (data.getVersionNumber() != ConquestData.CURRENT_VERSION_NUMBER) {
try {
ConquestDataIO.updateSaveFile(data, bigXML, xmlSaveFile.getName().replace(".dat", ""));
}
catch (final Exception e) {
//BugReporter.reportException(e);
throw new RuntimeException(e);
}
}
return data;
}
catch (final Exception ex) {
throw new RuntimeException(ex);
}
}
private static void updateSaveFile(final ConquestData newData, final String input, String filename) throws Exception {
//final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
final InputSource is = new InputSource();
is.setCharacterStream(new StringReader(input));
//final Document document = builder.parse(is);
final int saveVersion = newData.getVersionNumber();
switch (saveVersion) {
// There should be a fall-through between the cases so that each
// version's changes get applied progressively
case 0:
default:
break;
}
// mark the QD as the latest version
newData.setVersionNumber(ConquestData.CURRENT_VERSION_NUMBER);
}
public static synchronized void saveData(final ConquestData qd) {
try {
final XStream xStream = ConquestDataIO.getSerializer(false);
final File f = new File(ForgeConstants.CONQUEST_SAVE_DIR, qd.getName());
ConquestDataIO.savePacked(f + ".dat", xStream, qd);
// ConquestDataIO.saveUnpacked(f + ".xml", xStream, qd);
}
catch (final Exception ex) {
throw new RuntimeException(ex);
}
}
private static void savePacked(final String f, final XStream xStream, final ConquestData qd) throws Exception {
final BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(f));
final GZIPOutputStream zout = new GZIPOutputStream(bout);
xStream.toXML(qd, zout);
zout.flush();
zout.close();
}
@SuppressWarnings("unused") // used only for debug purposes
private static void saveUnpacked(final String f, final XStream xStream, final ConquestData qd) throws Exception {
final BufferedOutputStream boutUnp = new BufferedOutputStream(new FileOutputStream(f));
xStream.toXML(qd, boutUnp);
boutUnp.flush();
boutUnp.close();
}
}

View File

@@ -9,8 +9,11 @@ import forge.game.GameType;
import forge.item.PaperCard;
import forge.planarconquest.ConquestPlane.Region;
import forge.util.Aggregates;
import forge.util.XmlReader;
import forge.util.XmlWriter;
import forge.util.XmlWriter.IXmlWritable;
public class ConquestLocation {
public class ConquestLocation implements IXmlWritable {
private ConquestPlane plane;
private int regionIndex;
private int row;
@@ -20,6 +23,13 @@ public class ConquestLocation {
public ConquestLocation() {
}
public ConquestLocation(XmlReader xml) {
plane = xml.read("plane", plane, ConquestPlane.class);
regionIndex = xml.read("regionIndex", regionIndex);
row = xml.read("row", row);
col = xml.read("col", col);
}
public ConquestLocation(ConquestPlane plane0, int regionIndex0, int row0, int col0) {
plane = plane0;
regionIndex = regionIndex0;
@@ -125,4 +135,12 @@ public class ConquestLocation {
}
};
}
@Override
public void saveToXml(XmlWriter xml) {
xml.write("plane", plane);
xml.write("regionIndex", regionIndex);
xml.write("row", row);
xml.write("col", col);
}
}

View File

@@ -3,8 +3,10 @@ package forge.planarconquest;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.planarconquest.ConquestPlane.Region;
import forge.util.XmlWriter;
import forge.util.XmlWriter.IXmlWritable;
public class ConquestPlaneData {
public class ConquestPlaneData implements IXmlWritable {
private final ConquestPlane plane;
private final ConquestRecord[] eventResults;
@@ -63,4 +65,14 @@ public class ConquestPlaneData {
}
return count;
}
@Override
public void saveToXml(XmlWriter xml) {
xml.write("plane", plane);
xml.startElement("eventResults");
for (int i = 0; i < eventResults.length; i++) {
xml.write(String.valueOf(i), eventResults[i]);
}
xml.endElement();
}
}

View File

@@ -1,6 +1,9 @@
package forge.planarconquest;
public class ConquestRecord {
import forge.util.XmlWriter;
import forge.util.XmlWriter.IXmlWritable;
public class ConquestRecord implements IXmlWritable {
private int wins, losses, level;
public int getWins() {
@@ -26,4 +29,11 @@ public class ConquestRecord {
public void levelUp() {
level++;
}
@Override
public void saveToXml(XmlWriter xml) {
xml.write("wins", wins);
xml.write("losses", losses);
xml.write("level", level);
}
}

View File

@@ -0,0 +1,73 @@
package forge.util;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import forge.item.PaperCard;
import forge.util.XmlWriter.IXmlWritable;
public class XmlReader {
private Element currentElement;
public XmlReader(String filename0) throws Exception {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
final Document document = builder.parse(new File(filename0));
currentElement = (Element)document.getFirstChild();
}
public String read(String key, String defaultValue) {
if (currentElement.hasAttribute(key)) {
return currentElement.getAttribute(key);
}
return defaultValue;
}
public <E extends Enum<E>> E read(String key, E defaultValue, Class<E> enumType) {
if (currentElement.hasAttribute(key)) {
return Enum.valueOf(enumType, currentElement.getAttribute(key));
}
return defaultValue;
}
public int read(String key, int defaultValue) {
if (currentElement.hasAttribute(key)) {
return Integer.parseInt(currentElement.getAttribute(key));
}
return defaultValue;
}
public long read(String key, long defaultValue) {
if (currentElement.hasAttribute(key)) {
return Long.parseLong(currentElement.getAttribute(key));
}
return defaultValue;
}
public boolean read(String key, boolean defaultValue) {
if (currentElement.hasAttribute(key)) {
return Boolean.parseBoolean(currentElement.getAttribute(key));
}
return defaultValue;
}
public PaperCard read(String key, PaperCard defaultValue) {
//TODO
return defaultValue;
}
public <T extends IXmlWritable> T read(String key, T defaultValue, Class<T> type) {
readChildElement(key);
/*NodeList elements = currentElement.getElementsByTagName(key);
if (elements.getLength() > 0) {
try {
return type.getDeclaredConstructor(XmlReader.class).newInstance(this);
}
catch (Exception e) {
e.printStackTrace();
}
}*/
return defaultValue;
}
private void readChildElement(String key) {
}
}

View File

@@ -0,0 +1,102 @@
package forge.util;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Stack;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import forge.item.PaperCard;
public class XmlWriter {
private final Document document;
private final String filename;
private final Stack<Element> parentElements = new Stack<Element>();
private Element currentElement;
public XmlWriter(String filename0, String rootName0) throws Exception {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
document = builder.newDocument();
currentElement = document.createElement(rootName0);
document.appendChild(currentElement);
filename = filename0;
}
public void startElement(String name0) {
parentElements.add(currentElement);
currentElement = document.createElement(name0);
}
public void endElement() {
Element parentElement = parentElements.pop();
if (parentElement == null) { return; }
parentElement.appendChild(currentElement);
currentElement = parentElement;
}
public void write(String key, String value) {
currentElement.setAttribute(key, value);
}
public void write(String key, Enum<?> value) {
write(key, value.name());
}
public void write(String key, int value) {
write(key, String.valueOf(value));
}
public void write(String key, long value) {
write(key, String.valueOf(value));
}
public void write(String key, boolean value) {
write(key, String.valueOf(value));
}
public void write(String key, PaperCard value) {
if (value == null) { return; }
startElement(key);
write("name", value.getName());
write("set", value.getEdition());
write("art", value.getArtIndex());
endElement();
}
public void write(String key, HashSet<PaperCard> value) {
startElement(key);
for (PaperCard card : value) {
write("card", card);
}
endElement();
}
public void write(String key, IXmlWritable value) {
if (value == null) { return; }
startElement(key);
value.saveToXml(this);
endElement();
}
public void write(String key, Iterable<? extends IXmlWritable> value) {
startElement(key);
for (IXmlWritable item : value) {
write("item", item);
}
endElement();
}
public void write(String key, EnumMap<? extends Enum<?>, ? extends IXmlWritable> value) {
startElement(key);
for (Entry<? extends Enum<?>, ? extends IXmlWritable> entry : value.entrySet()) {
write(entry.getKey().name(), entry.getValue());
}
endElement();
}
public void close() throws Exception {
XmlUtil.saveDocument(document, filename);
}
public interface IXmlWritable {
void saveToXml(XmlWriter xml);
}
}