Added Wizard for export project settings. Added export to game source

folder directly. Untested...
This commit is contained in:
Zukero
2017-12-18 18:58:09 +01:00
parent a475180bb5
commit 407d50a01e
6 changed files with 337 additions and 84 deletions

View File

@@ -12,7 +12,6 @@ import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -45,7 +44,6 @@ import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.io.JsonPrettyWriter;
import com.gpl.rpg.atcontentstudio.io.SettingsSave;
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
import com.gpl.rpg.atcontentstudio.model.Project.ResourceSet;
import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition;
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist;
@@ -1060,74 +1058,13 @@ public class Project implements ProjectTreeNode, Serializable {
}
}
public void generateExportPackage(final File target) {
public void exportProjectAsZipPackage(final File target) {
WorkerDialog.showTaskMessage("Exporting project "+name+"...", ATContentStudio.frame, true, new Runnable() {
@Override
public void run() {
Notification.addInfo("Exporting project \""+name+"\" as "+target.getAbsolutePath());
File tmpDir = new File(baseFolder, "tmp");
FileUtils.deleteDir(tmpDir);
tmpDir.mkdir();
File tmpJsonDataDir = new File(tmpDir, GameDataSet.DEFAULT_REL_PATH_IN_SOURCE);
tmpJsonDataDir.mkdirs();
// for (File createdJsonFile : createdContent.gameData.baseFolder.listFiles()) {
// FileUtils.copyFile(createdJsonFile, new File(tmpJsonDataDir, createdJsonFile.getName()));
// }
Map<Class<? extends GameDataElement>, Set<String>> writtenFilesPerDataType = new LinkedHashMap<Class<? extends GameDataElement>, Set<String>>();
Set<String> writtenFiles;
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.actorConditions, alteredContent.gameData.actorConditions, baseContent.gameData.actorConditions, ActorCondition.class, tmpJsonDataDir);
writtenFilesPerDataType.put(ActorCondition.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.dialogues, alteredContent.gameData.dialogues, baseContent.gameData.dialogues, Dialogue.class, tmpJsonDataDir);
writtenFilesPerDataType.put(Dialogue.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.droplists, alteredContent.gameData.droplists, baseContent.gameData.droplists, Droplist.class, tmpJsonDataDir);
writtenFilesPerDataType.put(Droplist.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.itemCategories, alteredContent.gameData.itemCategories, baseContent.gameData.itemCategories, ItemCategory.class, tmpJsonDataDir);
writtenFilesPerDataType.put(ItemCategory.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.items, alteredContent.gameData.items, baseContent.gameData.items, Item.class, tmpJsonDataDir);
writtenFilesPerDataType.put(Item.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.npcs, alteredContent.gameData.npcs, baseContent.gameData.npcs, NPC.class, tmpJsonDataDir);
writtenFilesPerDataType.put(NPC.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.quests, alteredContent.gameData.quests, baseContent.gameData.quests, Quest.class, tmpJsonDataDir);
writtenFilesPerDataType.put(Quest.class, writtenFiles);
File tmpMapDir = new File(tmpDir, TMXMapSet.DEFAULT_REL_PATH_IN_SOURCE);
tmpMapDir.mkdirs();
writtenFiles = new LinkedHashSet<String>();
for (File createdMapFile : createdContent.gameMaps.mapFolder.listFiles()) {
FileUtils.copyFile(createdMapFile, new File(tmpMapDir, createdMapFile.getName()));
writtenFiles.add(createdMapFile.getName());
}
for (File alteredMapFile : alteredContent.gameMaps.mapFolder.listFiles()) {
FileUtils.copyFile(alteredMapFile, new File(tmpMapDir, alteredMapFile.getName()));
writtenFiles.add(alteredMapFile.getName());
}
writtenFilesPerDataType.put(TMXMap.class, writtenFiles);
if (sourceSetToUse == ResourceSet.gameData) {
writeResourceListXml(writtenFilesPerDataType, GameSource.DEFAULT_REL_PATH_FOR_GAME_RESOURCE, baseContent.baseFolder, tmpDir);
} else if (sourceSetToUse == ResourceSet.debugData) {
writeResourceListXml(writtenFilesPerDataType, GameSource.DEFAULT_REL_PATH_FOR_DEBUG_RESOURCE, baseContent.baseFolder, tmpDir);
}
if (!createdContent.worldmap.isEmpty() || !alteredContent.worldmap.isEmpty()) {
try {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
doc.setXmlVersion("1.0");
Element root = doc.createElement("worldmap");
doc.appendChild(root);
for (int i = 0; i < getWorldmapSegmentCount(); i++) {
root.appendChild(getWorldmapSegment(i).toXmlElement(doc));
}
Worldmap.saveDocToFile(doc, new File(tmpMapDir, "worldmap.xml"));
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
File tmpDir = exportProjectToTmpDir();
FileUtils.writeToZip(tmpDir, target);
FileUtils.deleteDir(tmpDir);
@@ -1138,6 +1075,91 @@ public class Project implements ProjectTreeNode, Serializable {
});
}
public void exportProjectOverGameSource(final File target) {
WorkerDialog.showTaskMessage("Exporting project "+name+"...", ATContentStudio.frame, true, new Runnable() {
@Override
public void run() {
Notification.addInfo("Exporting project \""+name+"\" into "+target.getAbsolutePath());
File tmpDir = exportProjectToTmpDir();
FileUtils.copyOver(tmpDir, target);
FileUtils.deleteDir(tmpDir);
Notification.addSuccess("Project \""+name+"\" exported into "+target.getAbsolutePath());
}
});
}
public File exportProjectToTmpDir() {
File tmpDir = new File(baseFolder, "tmp");
FileUtils.deleteDir(tmpDir);
tmpDir.mkdir();
File tmpJsonDataDir = new File(tmpDir, GameDataSet.DEFAULT_REL_PATH_IN_SOURCE);
tmpJsonDataDir.mkdirs();
// for (File createdJsonFile : createdContent.gameData.baseFolder.listFiles()) {
// FileUtils.copyFile(createdJsonFile, new File(tmpJsonDataDir, createdJsonFile.getName()));
// }
Map<Class<? extends GameDataElement>, Set<String>> writtenFilesPerDataType = new LinkedHashMap<Class<? extends GameDataElement>, Set<String>>();
Set<String> writtenFiles;
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.actorConditions, alteredContent.gameData.actorConditions, baseContent.gameData.actorConditions, ActorCondition.class, tmpJsonDataDir);
writtenFilesPerDataType.put(ActorCondition.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.dialogues, alteredContent.gameData.dialogues, baseContent.gameData.dialogues, Dialogue.class, tmpJsonDataDir);
writtenFilesPerDataType.put(Dialogue.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.droplists, alteredContent.gameData.droplists, baseContent.gameData.droplists, Droplist.class, tmpJsonDataDir);
writtenFilesPerDataType.put(Droplist.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.itemCategories, alteredContent.gameData.itemCategories, baseContent.gameData.itemCategories, ItemCategory.class, tmpJsonDataDir);
writtenFilesPerDataType.put(ItemCategory.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.items, alteredContent.gameData.items, baseContent.gameData.items, Item.class, tmpJsonDataDir);
writtenFilesPerDataType.put(Item.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.npcs, alteredContent.gameData.npcs, baseContent.gameData.npcs, NPC.class, tmpJsonDataDir);
writtenFilesPerDataType.put(NPC.class, writtenFiles);
writtenFiles = writeDataDeltaForDataType(createdContent.gameData.quests, alteredContent.gameData.quests, baseContent.gameData.quests, Quest.class, tmpJsonDataDir);
writtenFilesPerDataType.put(Quest.class, writtenFiles);
File tmpMapDir = new File(tmpDir, TMXMapSet.DEFAULT_REL_PATH_IN_SOURCE);
tmpMapDir.mkdirs();
writtenFiles = new LinkedHashSet<String>();
for (File createdMapFile : createdContent.gameMaps.mapFolder.listFiles()) {
FileUtils.copyFile(createdMapFile, new File(tmpMapDir, createdMapFile.getName()));
writtenFiles.add(createdMapFile.getName());
}
for (File alteredMapFile : alteredContent.gameMaps.mapFolder.listFiles()) {
FileUtils.copyFile(alteredMapFile, new File(tmpMapDir, alteredMapFile.getName()));
writtenFiles.add(alteredMapFile.getName());
}
writtenFilesPerDataType.put(TMXMap.class, writtenFiles);
if (sourceSetToUse == ResourceSet.gameData) {
writeResourceListXml(writtenFilesPerDataType, GameSource.DEFAULT_REL_PATH_FOR_GAME_RESOURCE, baseContent.baseFolder, tmpDir);
} else if (sourceSetToUse == ResourceSet.debugData) {
writeResourceListXml(writtenFilesPerDataType, GameSource.DEFAULT_REL_PATH_FOR_DEBUG_RESOURCE, baseContent.baseFolder, tmpDir);
}
if (!createdContent.worldmap.isEmpty() || !alteredContent.worldmap.isEmpty()) {
try {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
doc.setXmlVersion("1.0");
Element root = doc.createElement("worldmap");
doc.appendChild(root);
for (int i = 0; i < getWorldmapSegmentCount(); i++) {
root.appendChild(getWorldmapSegment(i).toXmlElement(doc));
}
Worldmap.saveDocToFile(doc, new File(tmpMapDir, "worldmap.xml"));
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return tmpDir;
}
@SuppressWarnings("rawtypes")
public Set<String> writeDataDeltaForDataType(GameDataCategory<? extends JSONElement> created, GameDataCategory<? extends JSONElement> altered, GameDataCategory<? extends JSONElement> source, Class<? extends JSONElement> gdeClass, File targetFolder) {
Set<String> filenamesToWrite = new LinkedHashSet<String>();

View File

@@ -39,7 +39,6 @@ import javax.swing.JSpinner.NumberEditor;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.Scrollable;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

View File

@@ -0,0 +1,226 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMapSet;
import com.gpl.rpg.atcontentstudio.model.sprites.SpriteSheetSet;
import com.jidesoft.swing.JideBoxLayout;
public class ExportProjectWizard extends JDialog {
private static final long serialVersionUID = -8745083621008868612L;
JPanel pane;
JLabel errorLabel, fileSelectionLabel;
JRadioButton asZip, overSources;
JComboBox<String> target;
JButton browse;
JButton okButton, cancelButton;
Project proj;
public ExportProjectWizard(Project proj) {
super(ATContentStudio.frame);
setTitle("Export project for inclusion in-game");
this.proj = proj;
pane = new JPanel();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
errorLabel = new JLabel();
pane.add(errorLabel, JideBoxLayout.FIX);
pane.add(new JLabel("Export this ATCS project..."), JideBoxLayout.FIX);
ButtonGroup radioGroup = new ButtonGroup();
asZip = new JRadioButton("... as a Zip archive");
radioGroup.add(asZip);
overSources = new JRadioButton("... into a game source folder");
radioGroup.add(overSources);
asZip.setSelected(true);
pane.add(asZip, JideBoxLayout.FIX);
pane.add(overSources, JideBoxLayout.FIX);
ActionListener updateListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateState();
}
};
asZip.addActionListener(updateListener);
overSources.addActionListener(updateListener);
target = new JComboBox<String>();
target.setEditable(true);
target.addActionListener(updateListener);
browse = new JButton("Browse");
browse.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser jfc = new JFileChooser(){
private static final long serialVersionUID = -3001082967957619011L;
@Override
public boolean accept(File f) {
if (asZip.isSelected()) {
if (f.isDirectory() || f.getName().endsWith(".zip") || f.getName().endsWith(".ZIP")) {
return super.accept(f);
} else {
return false;
}
} else {
return f.isDirectory();
}
}
};
jfc.setFileSelectionMode(asZip.isSelected() ? JFileChooser.FILES_AND_DIRECTORIES : JFileChooser.DIRECTORIES_ONLY);
jfc.setSelectedFile(new File(target.getSelectedItem() == null ? "" : target.getSelectedItem().toString()));
jfc.setMultiSelectionEnabled(false);
int result = jfc.showOpenDialog(ATContentStudio.frame);
if (result == JFileChooser.APPROVE_OPTION) {
File f = jfc.getSelectedFile();
if (asZip.isSelected() && !f.getAbsolutePath().substring(f.getAbsolutePath().length() - 4, f.getAbsolutePath().length()).equalsIgnoreCase(".zip")) {
f = new File(f.getAbsolutePath()+".zip");
}
target.setSelectedItem(f.getAbsolutePath());
updateState();
}
}
});
JPanel fileSelectionPane = new JPanel();
fileSelectionPane.setLayout(new JideBoxLayout(fileSelectionPane, JideBoxLayout.LINE_AXIS, 6));
fileSelectionLabel = new JLabel("Zip file: ");
fileSelectionPane.add(fileSelectionLabel, JideBoxLayout.FIX);
fileSelectionPane.add(target, JideBoxLayout.VARY);
fileSelectionPane.add(browse, JideBoxLayout.FIX);
pane.add(fileSelectionPane, JideBoxLayout.FIX);
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS, 6));
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
cancelButton = new JButton("Cancel");
buttonPane.add(cancelButton, JideBoxLayout.FIX);
okButton = new JButton("Ok");
buttonPane.add(okButton, JideBoxLayout.FIX);
pane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ExportProjectWizard.this.setVisible(false);
ExportProjectWizard.this.dispose();
}
});
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (asZip.isSelected()) {
ExportProjectWizard.this.proj.exportProjectAsZipPackage(new File(target.getSelectedItem().toString()));
} else {
ExportProjectWizard.this.proj.exportProjectOverGameSource(new File(target.getSelectedItem().toString()));
}
ExportProjectWizard.this.setVisible(false);
ExportProjectWizard.this.dispose();
}
});
updateState();
getContentPane().setLayout(new BorderLayout());
getContentPane().add(pane, BorderLayout.CENTER);
setMinimumSize(new Dimension(500,150));
pack();
Dimension sdim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension wdim = getSize();
setLocation((sdim.width - wdim.width)/2, (sdim.height - wdim.height)/2);
}
private void updateState() {
if (asZip.isSelected()) {
fileSelectionLabel.setText("Zip file: ");
} else {
fileSelectionLabel.setText("Game source folder: ");
}
File f = new File(target.getSelectedItem() == null ? "" : target.getSelectedItem().toString());
if (asZip.isSelected()) {
if (target.getSelectedItem() == null || target.getSelectedItem().toString().length() <= 0) {
errorLabel.setText("<html><font color=\"#FF0000\">You must select where to save the zip file.</font></html>");
okButton.setEnabled(false);
} else if (f.isDirectory()) {
errorLabel.setText("<html><font color=\"#FF0000\">The selected target is a directory. It should be a zip file.</font></html>");
okButton.setEnabled(false);
} else if (!(f.getName().toLowerCase().endsWith(".zip"))) {
errorLabel.setText("<html><font color=\"#FF0000\">The selected target is not a zip file. It should be a zip file.</font></html>");
okButton.setEnabled(false);
} else if (f.exists()) {
errorLabel.setText("<html><font color=\"#FF9000\">The selected target is an existing zip file. It will be overwritten.</font></html>");
okButton.setEnabled(true);
} else {
errorLabel.setText("<html><font color=\"#00AA00\">Everything looks good !</font></html>");
okButton.setEnabled(true);
}
} else {
if (target.getSelectedItem() == null || target.getSelectedItem().toString().length() <= 0) {
errorLabel.setText("<html><font color=\"#FF0000\">You must select an AT source root folder.</font></html>");
okButton.setEnabled(false);
} else if (!f.isDirectory() || !f.exists()) {
errorLabel.setText("<html><font color=\"#FF0000\">The selected AT source is not a folder. It should be an existing AT source root folder.</font></html>");
okButton.setEnabled(false);
} else {
File res = new File(f, GameDataSet.DEFAULT_REL_PATH_IN_SOURCE);
File drawable = new File(f, SpriteSheetSet.DEFAULT_REL_PATH_IN_SOURCE);
File xml = new File(f, TMXMapSet.DEFAULT_REL_PATH_IN_SOURCE);
if (!res.exists()) {
errorLabel.setText("<html><font color=\"#FF9000\">The selected AT source root folder does not contain the \"res\" folder.</font></html>");
okButton.setEnabled(true);
} else if (!drawable.exists()) {
errorLabel.setText("<html><font color=\"#FF9000\">The selected AT source root folder does not contain the \"drawable\" folder.</font></html>");
okButton.setEnabled(true);
} else if (!xml.exists()) {
errorLabel.setText("<html><font color=\"#FF9000\">The selected AT source root folder does not contain the \"xml\" folder.</font></html>");
okButton.setEnabled(true);
} else {
errorLabel.setText("<html><font color=\"#00AA00\">Everything looks good !</font></html>");
okButton.setEnabled(true);
}
}
}
revalidate();
repaint();
}
}

View File

@@ -34,7 +34,6 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement;
import com.gpl.rpg.atcontentstudio.model.gamedata.Quest;
import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMapSet;
import com.gpl.rpg.atcontentstudio.model.maps.Worldmap;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
import com.gpl.rpg.atcontentstudio.model.saves.SavedGamesSet;
@@ -353,21 +352,7 @@ public class WorkspaceActions {
public ATCSAction exportProject = new ATCSAction("Export project", "Generates a zip file containing all the created & altered resources of the project, ready to merge with the game source."){
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null) return;
JFileChooser chooser = new JFileChooser() {
private static final long serialVersionUID = 8039332384370636746L;
public boolean accept(File f) {
return f.isDirectory() || f.getName().endsWith(".zip") || f.getName().endsWith(".ZIP");
}
};
chooser.setMultiSelectionEnabled(false);
int result = chooser.showSaveDialog(ATContentStudio.frame);
if (result == JFileChooser.APPROVE_OPTION) {
File f = chooser.getSelectedFile();
if (!f.getAbsolutePath().substring(f.getAbsolutePath().length() - 4, f.getAbsolutePath().length()).equalsIgnoreCase(".zip")) {
f = new File(f.getAbsolutePath()+".zip");
}
selectedNode.getProject().generateExportPackage(f);
}
new ExportProjectWizard(selectedNode.getProject()).setVisible(true);
};
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode != null && selectedNode.getProject() != null);

View File

@@ -10,13 +10,11 @@ import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;

View File

@@ -78,6 +78,29 @@ public class FileUtils {
}
/**
* cp sourceFolder/* targetFolder/
* @param sourceFolder
* @param targetFolder
*/
public static void copyOver(File sourceFolder, File targetFolder) {
if (!sourceFolder.isDirectory() || !targetFolder.isDirectory()) return;
for (File f : sourceFolder.listFiles()) {
if (Files.isSymbolicLink(f.toPath())) {
//Skip symlinks
continue;
} else if (f.isDirectory()) {
File dest = new File(targetFolder, f.getName());
if (!dest.exists()) {
dest.mkdir();
}
copyOver(f, dest);
} else {
copyFile(f, new File(targetFolder, f.getName()));
}
}
}
private static void zipDir(File dir, String prefix, ZipOutputStream zos) {
if (prefix != "") {
prefix = prefix + File.separator;