From 33260137d9bd3296dcb096141268a18877de1c88 Mon Sep 17 00:00:00 2001 From: Zukero Date: Sun, 22 Oct 2017 18:21:48 +0200 Subject: [PATCH 01/42] Bug fix in Worldmaps when a composing map is deleted. --- .../gpl/rpg/atcontentstudio/model/maps/WorldmapSegment.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/com/gpl/rpg/atcontentstudio/model/maps/WorldmapSegment.java b/src/com/gpl/rpg/atcontentstudio/model/maps/WorldmapSegment.java index 342b320..c5fb785 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/maps/WorldmapSegment.java +++ b/src/com/gpl/rpg/atcontentstudio/model/maps/WorldmapSegment.java @@ -23,11 +23,13 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; +import com.gpl.rpg.atcontentstudio.ATContentStudio; import com.gpl.rpg.atcontentstudio.model.GameDataElement; import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode; import com.gpl.rpg.atcontentstudio.model.SaveEvent; import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet; import com.gpl.rpg.atcontentstudio.ui.DefaultIcons; +import com.gpl.rpg.atcontentstudio.ui.StudioFrame; public class WorldmapSegment extends GameDataElement { @@ -126,6 +128,7 @@ public class WorldmapSegment extends GameDataElement { if (modified) { this.state = GameDataElement.State.modified; childrenChanged(new ArrayList()); + ATContentStudio.frame.editorChanged(this); } } From cbc101b3b1c28c9394cd01fe24f2a2f95a81e239 Mon Sep 17 00:00:00 2001 From: Zukero Date: Tue, 24 Oct 2017 11:38:47 +0200 Subject: [PATCH 02/42] Fixed parsing issue in ActorCondition. The full round effect's visual effect was not read from the correct field, causing NPEs. --- .../gpl/rpg/atcontentstudio/model/gamedata/ActorCondition.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/ActorCondition.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/ActorCondition.java index 6b69fed..b721ed4 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/ActorCondition.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/ActorCondition.java @@ -208,7 +208,7 @@ public class ActorCondition extends JSONElement { this.full_round_effect.ap_boost_max = JSONElement.getInteger((Number) (((Map)fullRoundEffect.get("increaseCurrentAP")).get("max"))); this.full_round_effect.ap_boost_min = JSONElement.getInteger((Number) (((Map)fullRoundEffect.get("increaseCurrentAP")).get("min"))); } - String vfx = (String) roundEffect.get("visualEffectID"); + String vfx = (String) fullRoundEffect.get("visualEffectID"); this.full_round_effect.visual_effect = null; if (vfx != null) { try { From 1786860a3b0ad1ba3109676eebfc5d0325fb5ae0 Mon Sep 17 00:00:00 2001 From: Zukero Date: Tue, 31 Oct 2017 15:50:04 +0100 Subject: [PATCH 03/42] Buf fixes for worldmaps upon contained map deletion. --- .../model/maps/WorldmapSegment.java | 9 ++++++++- .../rpg/atcontentstudio/ui/map/WorldMapView.java | 15 +++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/model/maps/WorldmapSegment.java b/src/com/gpl/rpg/atcontentstudio/model/maps/WorldmapSegment.java index c5fb785..d8daeae 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/maps/WorldmapSegment.java +++ b/src/com/gpl/rpg/atcontentstudio/model/maps/WorldmapSegment.java @@ -29,7 +29,6 @@ import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode; import com.gpl.rpg.atcontentstudio.model.SaveEvent; import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet; import com.gpl.rpg.atcontentstudio.ui.DefaultIcons; -import com.gpl.rpg.atcontentstudio.ui.StudioFrame; public class WorldmapSegment extends GameDataElement { @@ -114,12 +113,20 @@ public class WorldmapSegment extends GameDataElement { mapLocations.remove(oldOne.id); modified = true; } + List deprecatedLabels = new ArrayList(); for (String label : labelledMaps.keySet()) { if (labelledMaps.get(label).contains(oldOne.id)) { labelledMaps.get(label).remove(oldOne.id); modified = true; + if (labelledMaps.get(label).isEmpty()) { + deprecatedLabels.add(label); + } } } + for (String label : deprecatedLabels) { + labelledMaps.remove(label); + labels.remove(label); + } } oldOne.removeBacklink(this); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapView.java b/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapView.java index 094fcca..67e768f 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapView.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapView.java @@ -23,7 +23,6 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import javax.swing.JComponent; @@ -191,7 +190,7 @@ public class WorldMapView extends JComponent implements Scrollable { FontMetrics mifm = g2.getFontMetrics(); int mapIdLabelHeight = mifm.getHeight(); - for (String s : mapLocations.keySet()) { + for (String s : new HashSet(mapLocations.keySet())) { int x = mapLocations.get(s).x; int y = mapLocations.get(s).y; @@ -481,6 +480,10 @@ public class WorldMapView extends JComponent implements Scrollable { offsetX = worldmap.segmentX * TILE_SIZE; offsetY = worldmap.segmentY * TILE_SIZE; for (String s : worldmap.mapLocations.keySet()) { + if (proj.getMap(s) == null) { + System.err.println("Warning. Worldmap "+worldmap.id+" references map "+s+" but it doesn't exist in this project"); + continue; + } int x = worldmap.mapLocations.get(s).x * TILE_SIZE; int w = proj.getMap(s).tmxMap.getWidth() * TILE_SIZE; int y = worldmap.mapLocations.get(s).y * TILE_SIZE; @@ -497,6 +500,10 @@ public class WorldMapView extends JComponent implements Scrollable { worldmap.segmentX = offsetX / TILE_SIZE; worldmap.segmentY = offsetY / TILE_SIZE; for (String id : worldmap.mapLocations.keySet()) { + if (worldmap.getProject().getMap(id) == null) { + System.err.println("Warning. Worldmap "+worldmap.id+" references map "+id+" but it doesn't exist in this project"); + continue; + } worldmap.getProject().getMap(id).removeBacklink(worldmap); } worldmap.mapLocations.clear(); @@ -508,6 +515,10 @@ public class WorldMapView extends JComponent implements Scrollable { } for (String id : worldmap.mapLocations.keySet()) { + if (worldmap.getProject().getMap(id) == null) { + System.err.println("Warning. Worldmap "+worldmap.id+" references map "+id+" but it doesn't exist in this project"); + continue; + } worldmap.getProject().getMap(id).addBacklink(worldmap); } From 3c63ace6c11eac25677ab6838997dabaf2d4be9c Mon Sep 17 00:00:00 2001 From: Zukero Date: Sat, 9 Dec 2017 15:51:03 +0100 Subject: [PATCH 04/42] v0.6.9 released. --- ATCS_JAR.jardesc | 12 ++++++------ packaging/ATCS_latest | 2 +- packaging/Windows/ATCS_Installer.nsi | 2 +- src/com/gpl/rpg/atcontentstudio/ATContentStudio.java | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ATCS_JAR.jardesc b/ATCS_JAR.jardesc index c177a5a..5a76d4d 100644 --- a/ATCS_JAR.jardesc +++ b/ATCS_JAR.jardesc @@ -1,7 +1,7 @@ - - + + @@ -11,9 +11,9 @@ - - - - + + + + diff --git a/packaging/ATCS_latest b/packaging/ATCS_latest index 52c6119..c80f388 100644 --- a/packaging/ATCS_latest +++ b/packaging/ATCS_latest @@ -1 +1 @@ -v0.6.7 \ No newline at end of file +v0.6.9 \ No newline at end of file diff --git a/packaging/Windows/ATCS_Installer.nsi b/packaging/Windows/ATCS_Installer.nsi index 581c9bc..f008e94 100644 --- a/packaging/Windows/ATCS_Installer.nsi +++ b/packaging/Windows/ATCS_Installer.nsi @@ -1,6 +1,6 @@ !include MUI2.nsh -!define VERSION "0.6.8" +!define VERSION "0.6.9" !define TRAINER_VERSION "0.1.4" !define JAVA_BIN "javaw" diff --git a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java index fd6e69c..60b7ac2 100644 --- a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java +++ b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java @@ -43,7 +43,7 @@ import prefuse.data.expression.parser.ExpressionParser; public class ATContentStudio { public static final String APP_NAME = "Andor's Trail Content Studio"; - public static final String APP_VERSION = "v0.6.8"; + public static final String APP_VERSION = "v0.6.9"; public static final String CHECK_UPDATE_URL = "https://andorstrail.com/static/ATCS_latest"; public static final String DOWNLOAD_URL = "https://andorstrail.com/viewtopic.php?f=6&t=4806"; From a475180bb5628bf9cf2b9b10281d0d6bf6d9831c Mon Sep 17 00:00:00 2001 From: Zukero Date: Sun, 17 Dec 2017 22:40:46 +0100 Subject: [PATCH 05/42] Fixed unwanted link following in project deletion that led to deleting the game source's drawable folder. First steps towards enhancements of export package generation. --- .../rpg/atcontentstudio/model/Project.java | 188 ++++++++++++++++-- .../rpg/atcontentstudio/model/Workspace.java | 5 +- .../rpg/atcontentstudio/utils/FileUtils.java | 7 +- 3 files changed, 177 insertions(+), 23 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/model/Project.java b/src/com/gpl/rpg/atcontentstudio/model/Project.java index 69ea424..9cea904 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Project.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Project.java @@ -2,6 +2,9 @@ package com.gpl.rpg.atcontentstudio.model; import java.awt.Image; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.Serializable; @@ -9,6 +12,7 @@ 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; @@ -17,18 +21,31 @@ import java.util.Properties; import java.util.Set; import javax.swing.tree.TreeNode; +import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; import org.json.simple.JSONArray; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; import com.gpl.rpg.atcontentstudio.ATContentStudio; 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; @@ -1054,24 +1071,43 @@ public class Project implements ProjectTreeNode, Serializable { 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())); - } - writeAltered(alteredContent.gameData.actorConditions, baseContent.gameData.actorConditions, ActorCondition.class, tmpJsonDataDir); - writeAltered(alteredContent.gameData.dialogues, baseContent.gameData.dialogues, Dialogue.class, tmpJsonDataDir); - writeAltered(alteredContent.gameData.droplists, baseContent.gameData.droplists, Droplist.class, tmpJsonDataDir); - writeAltered(alteredContent.gameData.itemCategories, baseContent.gameData.itemCategories, ItemCategory.class, tmpJsonDataDir); - writeAltered(alteredContent.gameData.items, baseContent.gameData.items, Item.class, tmpJsonDataDir); - writeAltered(alteredContent.gameData.npcs, baseContent.gameData.npcs, NPC.class, tmpJsonDataDir); - writeAltered(alteredContent.gameData.quests, baseContent.gameData.quests, Quest.class, tmpJsonDataDir); +// for (File createdJsonFile : createdContent.gameData.baseFolder.listFiles()) { +// FileUtils.copyFile(createdJsonFile, new File(tmpJsonDataDir, createdJsonFile.getName())); +// } + Map, Set> writtenFilesPerDataType = new LinkedHashMap, Set>(); + Set 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(); 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); } @@ -1097,31 +1133,48 @@ public class Project implements ProjectTreeNode, Serializable { FileUtils.deleteDir(tmpDir); Notification.addSuccess("Project \""+name+"\" exported as "+target.getAbsolutePath()); } + + }); } @SuppressWarnings("rawtypes") - public void writeAltered(GameDataCategory altered, GameDataCategory source, Class gdeClass, File targetFolder) { - Set alteredFileNames = new LinkedHashSet(); - Map> toWrite = new LinkedHashMap>(); + public Set writeDataDeltaForDataType(GameDataCategory created, GameDataCategory altered, GameDataCategory source, Class gdeClass, File targetFolder) { + Set filenamesToWrite = new LinkedHashSet(); + Map> dataToWritePerFilename = new LinkedHashMap>(); for (JSONElement gde : altered) { - alteredFileNames.add(gde.jsonFile.getName()); + filenamesToWrite.add(gde.jsonFile.getName()); } - for (String fName : alteredFileNames) { + for (JSONElement gde : created) { + if (!filenamesToWrite.contains(gde.jsonFile.getName())) { + filenamesToWrite.add(gde.jsonFile.getName()); + } + } + for (String fName : filenamesToWrite) { for (JSONElement gde : source) { if (gde.jsonFile.getName().equals(fName)) { - if (toWrite.get(fName) == null) { - toWrite.put(fName, new ArrayList()); + if (dataToWritePerFilename.get(fName) == null) { + dataToWritePerFilename.put(fName, new ArrayList()); } - toWrite.get(fName).add(getGameDataElement(gdeClass, gde.id).toJson()); + //Automatically fetches altered element over source element. + dataToWritePerFilename.get(fName).add(getGameDataElement(gdeClass, gde.id).toJson()); + } + } + for (JSONElement gde : created) { + if (gde.jsonFile.getName().equals(fName)) { + if (dataToWritePerFilename.get(fName) == null) { + dataToWritePerFilename.put(fName, new ArrayList()); + } + //Add the created elements. + dataToWritePerFilename.get(fName).add(getGameDataElement(gdeClass, gde.id).toJson()); } } } - for (String fName : toWrite.keySet()) { + for (String fName : dataToWritePerFilename.keySet()) { File jsonFile = new File(targetFolder, fName); StringWriter writer = new JsonPrettyWriter(); try { - JSONArray.writeJSONString(toWrite.get(fName), writer); + JSONArray.writeJSONString(dataToWritePerFilename.get(fName), writer); } catch (IOException e) { //Impossible with a StringWriter } @@ -1136,8 +1189,103 @@ public class Project implements ProjectTreeNode, Serializable { e.printStackTrace(); } } + return filenamesToWrite; } + + private void writeResourceListXml(Map, Set> writtenFilesPerDataType, String xmlFileRelPath, File baseFolder, File tmpDir) { + File xmlFile = new File(baseFolder, xmlFileRelPath); + File outputFile = new File(tmpDir, xmlFileRelPath); + + Map> classNamesByArrayNames = new HashMap>(); + classNamesByArrayNames.put("loadresource_itemcategories", ItemCategory.class); + classNamesByArrayNames.put("loadresource_actorconditions", ActorCondition.class); + classNamesByArrayNames.put("loadresource_items", Item.class); + classNamesByArrayNames.put("loadresource_droplists", Droplist.class); + classNamesByArrayNames.put("loadresource_quests", Quest.class); + classNamesByArrayNames.put("loadresource_conversationlists", Dialogue.class); + classNamesByArrayNames.put("loadresource_monsters", NPC.class); + classNamesByArrayNames.put("loadresource_maps", TMXMap.class); + + String jsonResPrefix = "@raw/"; + String tmxResPrefix = "@xml/"; + String jsonFileSuffix = ".json"; + String tmxFileSuffix = ".xml"; + + if (!xmlFile.exists()) return; + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + Document doc; + try { + factory.setIgnoringComments(true); + factory.setIgnoringElementContentWhitespace(true); + factory.setExpandEntityReferences(false); + DocumentBuilder builder = factory.newDocumentBuilder(); + InputSource insrc = new InputSource(new FileInputStream(xmlFile)); + // insrc.setSystemId("http://worldmap/"); + insrc.setEncoding("UTF-8"); + doc = builder.parse(insrc); + + Element arrayNode; + String name, resPrefix, fileSuffix, resName, resToFile, fileToRes; + Class clazz; + Set writtenFiles; + + Element root = (Element) doc.getElementsByTagName("resources").item(0); + if (root != null) { + NodeList arraysList = root.getElementsByTagName("array"); + if (arraysList != null) { + for (int i = 0; i < arraysList.getLength(); i++) { + arrayNode = (Element) arraysList.item(i); + name = arrayNode.getAttribute("name"); + clazz = classNamesByArrayNames.get(name); + if (clazz == null) continue; + writtenFiles = writtenFilesPerDataType.get(clazz); + if (writtenFiles == null) continue; + if (clazz == TMXMap.class) { + resPrefix = tmxResPrefix; + fileSuffix = tmxFileSuffix; + } else { + resPrefix = jsonResPrefix; + fileSuffix = jsonFileSuffix; + } + NodeList arrayItems = arrayNode.getElementsByTagName("item"); + if (arrayItems != null) { + for (int j = 0; j < arrayItems.getLength(); j++) { + resName = ((Element)arrayItems.item(j)).getTextContent(); + if (resName == null) continue; + resToFile = resName.replaceFirst("\\A"+resPrefix, "")+fileSuffix; + writtenFiles.remove(resToFile); + } + } + for (String missingRes : writtenFiles) { + Element item = doc.createElement("item"); + fileToRes = resPrefix+missingRes.replaceFirst(fileSuffix+"\\z", ""); + item.setTextContent(fileToRes); + arrayNode.appendChild(item); + } + } + } + } + + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + Result output = new StreamResult(new FileOutputStream(outputFile)); + Source input = new DOMSource(doc); + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2"); + transformer.transform(input, output); + } catch (SAXException e) { + e.printStackTrace(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (ParserConfigurationException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (TransformerException e) { + e.printStackTrace(); + } + } @Override public boolean needsSaving() { diff --git a/src/com/gpl/rpg/atcontentstudio/model/Workspace.java b/src/com/gpl/rpg/atcontentstudio/model/Workspace.java index 7e12910..8bf298a 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Workspace.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Workspace.java @@ -4,6 +4,7 @@ import java.awt.Image; import java.io.File; import java.io.IOException; import java.io.Serializable; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; @@ -332,7 +333,9 @@ public class Workspace implements ProjectTreeNode, Serializable { private static boolean delete(File f) { boolean b = true; - if (f.isDirectory()) { + if (Files.isSymbolicLink(f.toPath())) { + b &= f.delete(); + } else if (f.isDirectory()) { for (File c : f.listFiles()) b &= delete(c); } diff --git a/src/com/gpl/rpg/atcontentstudio/utils/FileUtils.java b/src/com/gpl/rpg/atcontentstudio/utils/FileUtils.java index 643a413..c25464f 100644 --- a/src/com/gpl/rpg/atcontentstudio/utils/FileUtils.java +++ b/src/com/gpl/rpg/atcontentstudio/utils/FileUtils.java @@ -79,15 +79,18 @@ public class FileUtils { } private static void zipDir(File dir, String prefix, ZipOutputStream zos) { + if (prefix != "") { + prefix = prefix + File.separator; + } for (File f : dir.listFiles()) { if (f.isDirectory()) { - zipDir(f, prefix+File.separator+f.getName(), zos); + zipDir(f, prefix+f.getName(), zos); } else { FileInputStream fis; try { fis = new FileInputStream(f); BufferedInputStream origin = new BufferedInputStream(fis, BUFFER); - ZipEntry entry = new ZipEntry(prefix+File.separator+f.getName()); + ZipEntry entry = new ZipEntry(prefix+f.getName()); try { zos.putNextEntry(entry); int count; From 407d50a01ed7b0996be76ac2139e1f0a04bc6b26 Mon Sep 17 00:00:00 2001 From: Zukero Date: Mon, 18 Dec 2017 18:58:09 +0100 Subject: [PATCH 06/42] Added Wizard for export project settings. Added export to game source folder directly. Untested... --- .../rpg/atcontentstudio/model/Project.java | 152 +++++++----- .../gpl/rpg/atcontentstudio/ui/Editor.java | 1 - .../ui/ExportProjectWizard.java | 226 ++++++++++++++++++ .../atcontentstudio/ui/WorkspaceActions.java | 17 +- .../ui/tools/writermode/WriterModeEditor.java | 2 - .../rpg/atcontentstudio/utils/FileUtils.java | 23 ++ 6 files changed, 337 insertions(+), 84 deletions(-) create mode 100644 src/com/gpl/rpg/atcontentstudio/ui/ExportProjectWizard.java diff --git a/src/com/gpl/rpg/atcontentstudio/model/Project.java b/src/com/gpl/rpg/atcontentstudio/model/Project.java index 9cea904..9d3c8b4 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Project.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Project.java @@ -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, Set> writtenFilesPerDataType = new LinkedHashMap, Set>(); - Set 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(); - 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, Set> writtenFilesPerDataType = new LinkedHashMap, Set>(); + Set 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(); + 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 writeDataDeltaForDataType(GameDataCategory created, GameDataCategory altered, GameDataCategory source, Class gdeClass, File targetFolder) { Set filenamesToWrite = new LinkedHashSet(); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/Editor.java b/src/com/gpl/rpg/atcontentstudio/ui/Editor.java index 703e701..7c5e7ac 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/Editor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/Editor.java @@ -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; diff --git a/src/com/gpl/rpg/atcontentstudio/ui/ExportProjectWizard.java b/src/com/gpl/rpg/atcontentstudio/ui/ExportProjectWizard.java new file mode 100644 index 0000000..8179a29 --- /dev/null +++ b/src/com/gpl/rpg/atcontentstudio/ui/ExportProjectWizard.java @@ -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 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(); + 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("You must select where to save the zip file."); + okButton.setEnabled(false); + } else if (f.isDirectory()) { + errorLabel.setText("The selected target is a directory. It should be a zip file."); + okButton.setEnabled(false); + } else if (!(f.getName().toLowerCase().endsWith(".zip"))) { + errorLabel.setText("The selected target is not a zip file. It should be a zip file."); + okButton.setEnabled(false); + } else if (f.exists()) { + errorLabel.setText("The selected target is an existing zip file. It will be overwritten."); + okButton.setEnabled(true); + } else { + errorLabel.setText("Everything looks good !"); + okButton.setEnabled(true); + } + } else { + if (target.getSelectedItem() == null || target.getSelectedItem().toString().length() <= 0) { + errorLabel.setText("You must select an AT source root folder."); + okButton.setEnabled(false); + } else if (!f.isDirectory() || !f.exists()) { + errorLabel.setText("The selected AT source is not a folder. It should be an existing AT source root folder."); + 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("The selected AT source root folder does not contain the \"res\" folder."); + okButton.setEnabled(true); + } else if (!drawable.exists()) { + errorLabel.setText("The selected AT source root folder does not contain the \"drawable\" folder."); + okButton.setEnabled(true); + } else if (!xml.exists()) { + errorLabel.setText("The selected AT source root folder does not contain the \"xml\" folder."); + okButton.setEnabled(true); + } else { + errorLabel.setText("Everything looks good !"); + okButton.setEnabled(true); + } + } + } + revalidate(); + repaint(); + + } + + +} diff --git a/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceActions.java b/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceActions.java index 35123c8..af881d6 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceActions.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceActions.java @@ -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); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/tools/writermode/WriterModeEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/tools/writermode/WriterModeEditor.java index a83c68e..7445dbe 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/tools/writermode/WriterModeEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/tools/writermode/WriterModeEditor.java @@ -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; diff --git a/src/com/gpl/rpg/atcontentstudio/utils/FileUtils.java b/src/com/gpl/rpg/atcontentstudio/utils/FileUtils.java index c25464f..4e54ae8 100644 --- a/src/com/gpl/rpg/atcontentstudio/utils/FileUtils.java +++ b/src/com/gpl/rpg/atcontentstudio/utils/FileUtils.java @@ -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; From e697f93cf59afb4947f98f5559cb3fe2cc43dfbf Mon Sep 17 00:00:00 2001 From: Zukero Date: Mon, 18 Dec 2017 19:04:51 +0100 Subject: [PATCH 07/42] Fixed export issue zhere the loadresources.xml file couldn't be created because its parent folder do not exist. --- src/com/gpl/rpg/atcontentstudio/model/Project.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/com/gpl/rpg/atcontentstudio/model/Project.java b/src/com/gpl/rpg/atcontentstudio/model/Project.java index 9d3c8b4..ab177f3 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Project.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Project.java @@ -1290,6 +1290,9 @@ public class Project implements ProjectTreeNode, Serializable { } Transformer transformer = TransformerFactory.newInstance().newTransformer(); + if (!outputFile.getParentFile().exists()) { + outputFile.getParentFile().mkdirs(); + } Result output = new StreamResult(new FileOutputStream(outputFile)); Source input = new DOMSource(doc); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); From daeb394373e4392ebc8e7cf18715c6d33965f4f1 Mon Sep 17 00:00:00 2001 From: Zukero Date: Tue, 16 Jan 2018 23:37:58 +0100 Subject: [PATCH 08/42] Fixed dialogue reward editor. giveItem reward type now allows negative amounts. Added Nut's spritesheets to spritesheet.properties --- res/spritesheets.properties | 3 ++- .../rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/res/spritesheets.properties b/res/spritesheets.properties index 771c6ad..78000a8 100644 --- a/res/spritesheets.properties +++ b/res/spritesheets.properties @@ -84,4 +84,5 @@ atcs.spritesheet.effect_bluetentacle.animate=true atcs.spritesheet.effect_heal2.animate=true atcs.spritesheet.effect_poison1.animate=true atcs.spritesheet.effect_tometik1.animate=true -atcs.spritesheet.effect_tometik2.animate=true \ No newline at end of file +atcs.spritesheet.effect_tometik2.animate=true +atcs.spritesheet.monsters_guynmart.category=monster diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java index f83c84a..106bdfd 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java @@ -470,7 +470,7 @@ public class DialogueEditor extends JSONElementEditor { rewardMap = null; rewardObjId = null; rewardObj = addItemBox(pane, ((Dialogue)target).getProject(), "Item: ", (Item) reward.reward_obj, writable, listener); - rewardValue = addIntegerField(pane, "Quantity: ", reward.reward_value, false, writable, listener); + rewardValue = addIntegerField(pane, "Quantity: ", reward.reward_value, true, writable, listener); break; case removeQuestProgress: case questProgress: From c3144db751d62e12acbcf8c7d61122e4956639d0 Mon Sep 17 00:00:00 2001 From: Zukero Date: Sun, 4 Feb 2018 11:50:32 +0100 Subject: [PATCH 09/42] Fixed bug in "Npc->Effect on every hit->Actor conditions applied to the target". Widget state wasn't updated correctly upon using the radio buttons. --- .../atcontentstudio/ui/gamedataeditors/NPCEditor.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/NPCEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/NPCEditor.java index e27101b..2f4f79c 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/NPCEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/NPCEditor.java @@ -1398,7 +1398,7 @@ public class NPCEditor extends JSONElementEditor { } else if (source == hitTargetConditionClear && (Boolean) value) { selectedHitEffectTargetCondition.magnitude = ActorCondition.MAGNITUDE_CLEAR; selectedHitEffectTargetCondition.duration = null; - updateHitSourceTimedConditionWidgets(selectedHitEffectTargetCondition); + updateHitTargetTimedConditionWidgets(selectedHitEffectTargetCondition); hitTargetConditionsListModel.itemChanged(selectedHitEffectTargetCondition); updateHit = true; } else if (source == hitTargetConditionApply && (Boolean) value) { @@ -1407,7 +1407,7 @@ public class NPCEditor extends JSONElementEditor { if (selectedHitEffectTargetCondition.duration == null || selectedHitEffectTargetCondition.duration == ActorCondition.DURATION_NONE) { selectedHitEffectTargetCondition.duration = 1; } - updateHitSourceTimedConditionWidgets(selectedHitEffectTargetCondition); + updateHitTargetTimedConditionWidgets(selectedHitEffectTargetCondition); hitTargetConditionsListModel.itemChanged(selectedHitEffectTargetCondition); updateHit = true; } else if (source == hitTargetConditionImmunity && (Boolean) value) { @@ -1416,7 +1416,7 @@ public class NPCEditor extends JSONElementEditor { if (selectedHitEffectTargetCondition.duration == null || selectedHitEffectTargetCondition.duration == ActorCondition.DURATION_NONE) { selectedHitEffectTargetCondition.duration = 1; } - updateHitSourceTimedConditionWidgets(selectedHitEffectTargetCondition); + updateHitTargetTimedConditionWidgets(selectedHitEffectTargetCondition); hitTargetConditionsListModel.itemChanged(selectedHitEffectTargetCondition); updateHit = true; } else if (source == hitTargetConditionMagnitude) { @@ -1428,12 +1428,12 @@ public class NPCEditor extends JSONElementEditor { if (selectedHitEffectTargetCondition.duration == null || selectedHitEffectTargetCondition.duration == ActorCondition.DURATION_NONE) { selectedHitEffectTargetCondition.duration = 1; } - updateHitSourceTimedConditionWidgets(selectedHitEffectTargetCondition); + updateHitTargetTimedConditionWidgets(selectedHitEffectTargetCondition); hitTargetConditionsListModel.itemChanged(selectedHitEffectTargetCondition); updateHit = true; } else if (source == hitTargetConditionForever && (Boolean) value) { selectedHitEffectTargetCondition.duration = ActorCondition.DURATION_FOREVER; - updateHitSourceTimedConditionWidgets(selectedHitEffectTargetCondition); + updateHitTargetTimedConditionWidgets(selectedHitEffectTargetCondition); hitTargetConditionsListModel.itemChanged(selectedHitEffectTargetCondition); updateHit = true; } else if (source == hitTargetConditionDuration) { From 9e6e1d936deac5d0d9444b76163d65bb280a50bd Mon Sep 17 00:00:00 2001 From: Zukero Date: Mon, 5 Feb 2018 18:15:18 +0100 Subject: [PATCH 10/42] Fixed a bug in loadresources.xml generation. Enhanced custom command handling for desktop tools integration. --- .../rpg/atcontentstudio/model/Project.java | 8 ++-- .../atcontentstudio/model/maps/TMXMapSet.java | 2 +- .../utils/DesktopIntegration.java | 45 ++++++++++++++++++- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/model/Project.java b/src/com/gpl/rpg/atcontentstudio/model/Project.java index ab177f3..5e49808 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Project.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Project.java @@ -1232,18 +1232,17 @@ public class Project implements ProjectTreeNode, Serializable { String jsonResPrefix = "@raw/"; String tmxResPrefix = "@xml/"; String jsonFileSuffix = ".json"; - String tmxFileSuffix = ".xml"; + String tmxFileSuffix = ".tmx"; if (!xmlFile.exists()) return; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); Document doc; try { - factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); factory.setExpandEntityReferences(false); DocumentBuilder builder = factory.newDocumentBuilder(); + InputSource insrc = new InputSource(new FileInputStream(xmlFile)); - // insrc.setSystemId("http://worldmap/"); insrc.setEncoding("UTF-8"); doc = builder.parse(insrc); @@ -1296,8 +1295,9 @@ public class Project implements ProjectTreeNode, Serializable { Result output = new StreamResult(new FileOutputStream(outputFile)); Source input = new DOMSource(doc); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); transformer.transform(input, output); } catch (SAXException e) { e.printStackTrace(); diff --git a/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMapSet.java b/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMapSet.java index 00af523..b85354e 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMapSet.java +++ b/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMapSet.java @@ -92,7 +92,7 @@ public class TMXMapSet implements ProjectTreeNode { }); if (source.type == GameSource.Type.created | source.type == GameSource.Type.altered) { final Path folderPath = Paths.get(mapFolder.getAbsolutePath()); - Thread watcher = new Thread("Map folder watcher for "+source.type) { + Thread watcher = new Thread("Map folder watcher for "+getProject().name+"/"+source.type) { public void run() { WatchService watchService; diff --git a/src/com/gpl/rpg/atcontentstudio/utils/DesktopIntegration.java b/src/com/gpl/rpg/atcontentstudio/utils/DesktopIntegration.java index 91ae199..cd229ff 100644 --- a/src/com/gpl/rpg/atcontentstudio/utils/DesktopIntegration.java +++ b/src/com/gpl/rpg/atcontentstudio/utils/DesktopIntegration.java @@ -3,6 +3,9 @@ package com.gpl.rpg.atcontentstudio.utils; import java.awt.Desktop; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Locale; import com.gpl.rpg.atcontentstudio.model.Workspace; @@ -18,7 +21,7 @@ public class DesktopIntegration { } } else { try { - Runtime.getRuntime().exec(Workspace.activeWorkspace.settings.mapEditorCommand.getCurrentValue()+" \""+f.getAbsolutePath()+"\""); + Runtime.getRuntime().exec(tokenize(Workspace.activeWorkspace.settings.mapEditorCommand.getCurrentValue()+" \""+f.getAbsolutePath()+"\"")); } catch (IOException e) { e.printStackTrace(); } @@ -40,7 +43,7 @@ public class DesktopIntegration { } } else { try { - Runtime.getRuntime().exec(Workspace.activeWorkspace.settings.imageEditorCommand.getCurrentValue()+" \""+f.getAbsolutePath()+"\""); + Runtime.getRuntime().exec(tokenize(Workspace.activeWorkspace.settings.imageEditorCommand.getCurrentValue()+" \""+f.getAbsolutePath()+"\"")); } catch (IOException e) { e.printStackTrace(); } @@ -63,5 +66,43 @@ public class DesktopIntegration { return OSType.Other; } + + private static List quotes = Arrays.asList(new Character[]{'\'', '"'}); + private static List delims = Arrays.asList(new Character[]{' ', '\r', '\n', '\t'}); + + private static String[] tokenize(String command) { + List tokens = new ArrayList(); + boolean inQuote = false; + char usedQuote = '\0'; + StringBuilder sb = new StringBuilder(); + + for (char c : command.toCharArray()) { + if (inQuote) { + if (c == usedQuote) { + inQuote = false; + continue; + } else { + sb.append(c); + } + } else { + if (quotes.contains(c)) { + inQuote = true; + usedQuote = c; + } else if (delims.contains(c)) { + if (sb.length() > 0) { + tokens.add(sb.toString()); + sb = new StringBuilder(); + } + } else { + sb.append(c); + } + } + } + if (sb.length() > 0) { + tokens.add(sb.toString()); + } + return tokens.toArray(new String[tokens.size()]); + } + } From 6b834e0f0eb0f750be7e7840b399277bce670731 Mon Sep 17 00:00:00 2001 From: Zukero Date: Mon, 5 Feb 2018 23:39:07 +0100 Subject: [PATCH 11/42] Added sadly convoluted way of pretty-printing loadresources.xml Still not perfect. --- .../rpg/atcontentstudio/model/Project.java | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/com/gpl/rpg/atcontentstudio/model/Project.java b/src/com/gpl/rpg/atcontentstudio/model/Project.java index 5e49808..b73ec7c 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Project.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Project.java @@ -8,6 +8,8 @@ import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.Serializable; +import java.io.StringBufferInputStream; +import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Enumeration; @@ -31,6 +33,7 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; import org.json.simple.JSONArray; import org.w3c.dom.Document; @@ -1292,13 +1295,37 @@ public class Project implements ProjectTreeNode, Serializable { if (!outputFile.getParentFile().exists()) { outputFile.getParentFile().mkdirs(); } - Result output = new StreamResult(new FileOutputStream(outputFile)); + StringWriter temp = new StringWriter(); + Result output = new StreamResult(temp);// FileOutputStream(outputFile)); Source input = new DOMSource(doc); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); +// transformer.setOutputProperty(OutputKeys.INDENT, "yes"); +// transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); + transformer.transform(input, output); + + String tempString = temp.toString(); + doc = builder.parse(new StringBufferInputStream(tempString)); + input = new DOMSource(doc); + transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(new StringReader( + "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + ""))); + output = new StreamResult(new FileOutputStream(outputFile)); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); transformer.transform(input, output); + + } catch (SAXException e) { e.printStackTrace(); } catch (FileNotFoundException e) { From 1fb22ab73f7fbfd00e932ab1b2e46f0bad62bb83 Mon Sep 17 00:00:00 2001 From: Zukero Date: Thu, 8 Feb 2018 17:19:25 +0100 Subject: [PATCH 12/42] Completed formatting of loadresources.xml files generating by project export. --- .../rpg/atcontentstudio/model/Project.java | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/model/Project.java b/src/com/gpl/rpg/atcontentstudio/model/Project.java index b73ec7c..dd01c8f 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Project.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Project.java @@ -12,10 +12,12 @@ import java.io.StringBufferInputStream; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; @@ -36,6 +38,7 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.json.simple.JSONArray; +import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -1105,8 +1108,8 @@ public class Project implements ProjectTreeNode, Serializable { // for (File createdJsonFile : createdContent.gameData.baseFolder.listFiles()) { // FileUtils.copyFile(createdJsonFile, new File(tmpJsonDataDir, createdJsonFile.getName())); // } - Map, Set> writtenFilesPerDataType = new LinkedHashMap, Set>(); - Set writtenFiles; + Map, List> writtenFilesPerDataType = new LinkedHashMap, List>(); + List 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); @@ -1124,7 +1127,7 @@ public class Project implements ProjectTreeNode, Serializable { File tmpMapDir = new File(tmpDir, TMXMapSet.DEFAULT_REL_PATH_IN_SOURCE); tmpMapDir.mkdirs(); - writtenFiles = new LinkedHashSet(); + writtenFiles = new LinkedList(); for (File createdMapFile : createdContent.gameMaps.mapFolder.listFiles()) { FileUtils.copyFile(createdMapFile, new File(tmpMapDir, createdMapFile.getName())); writtenFiles.add(createdMapFile.getName()); @@ -1164,8 +1167,8 @@ public class Project implements ProjectTreeNode, Serializable { } @SuppressWarnings("rawtypes") - public Set writeDataDeltaForDataType(GameDataCategory created, GameDataCategory altered, GameDataCategory source, Class gdeClass, File targetFolder) { - Set filenamesToWrite = new LinkedHashSet(); + public List writeDataDeltaForDataType(GameDataCategory created, GameDataCategory altered, GameDataCategory source, Class gdeClass, File targetFolder) { + List filenamesToWrite = new LinkedList(); Map> dataToWritePerFilename = new LinkedHashMap>(); for (JSONElement gde : altered) { filenamesToWrite.add(gde.jsonFile.getName()); @@ -1218,7 +1221,7 @@ public class Project implements ProjectTreeNode, Serializable { } - private void writeResourceListXml(Map, Set> writtenFilesPerDataType, String xmlFileRelPath, File baseFolder, File tmpDir) { + private void writeResourceListXml(Map, List> writtenFilesPerDataType, String xmlFileRelPath, File baseFolder, File tmpDir) { File xmlFile = new File(baseFolder, xmlFileRelPath); File outputFile = new File(tmpDir, xmlFileRelPath); @@ -1252,7 +1255,7 @@ public class Project implements ProjectTreeNode, Serializable { Element arrayNode; String name, resPrefix, fileSuffix, resName, resToFile, fileToRes; Class clazz; - Set writtenFiles; + List writtenFiles; Element root = (Element) doc.getElementsByTagName("resources").item(0); if (root != null) { @@ -1281,11 +1284,16 @@ public class Project implements ProjectTreeNode, Serializable { writtenFiles.remove(resToFile); } } - for (String missingRes : writtenFiles) { - Element item = doc.createElement("item"); - fileToRes = resPrefix+missingRes.replaceFirst(fileSuffix+"\\z", ""); - item.setTextContent(fileToRes); - arrayNode.appendChild(item); + if (!writtenFiles.isEmpty()) { + Comment com = doc.createComment("Added by ATCS "+ATContentStudio.APP_VERSION+" for project "+getProject().name); + arrayNode.appendChild(com); + Collections.sort(writtenFiles); + for (String missingRes : writtenFiles) { + Element item = doc.createElement("item"); + fileToRes = resPrefix+missingRes.replaceFirst(fileSuffix+"\\z", ""); + item.setTextContent(fileToRes); + arrayNode.appendChild(item); + } } } } @@ -1296,12 +1304,10 @@ public class Project implements ProjectTreeNode, Serializable { outputFile.getParentFile().mkdirs(); } StringWriter temp = new StringWriter(); - Result output = new StreamResult(temp);// FileOutputStream(outputFile)); + Result output = new StreamResult(temp); Source input = new DOMSource(doc); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); -// transformer.setOutputProperty(OutputKeys.INDENT, "yes"); -// transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); transformer.transform(input, output); String tempString = temp.toString(); @@ -1314,11 +1320,16 @@ public class Project implements ProjectTreeNode, Serializable { " \r\n" + " \r\n" + "\r\n" + - " \r\n" + + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + ""))); output = new StreamResult(new FileOutputStream(outputFile)); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); From e5bb59b8767b29ddcaf8f9f83577851ef999f21e Mon Sep 17 00:00:00 2001 From: Zukero Date: Sat, 10 Feb 2018 14:43:22 +0100 Subject: [PATCH 13/42] Added support for the"alignmentSet" dialogue reward type --- src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java | 4 +++- .../atcontentstudio/ui/gamedataeditors/DialogueEditor.java | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java index 2cc77c7..1863db0 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java @@ -60,6 +60,7 @@ public class Dialogue extends JSONElement { actorCondition, actorConditionImmunity, alignmentChange, + alignmentSet, giveItem, createTimer, spawnAll, @@ -255,7 +256,8 @@ public class Dialogue extends JSONElement { reward.reward_obj = proj.getActorCondition(reward.reward_obj_id); break; case alignmentChange: - //Nothing to do (yet ?). + case alignmentSet: + //Nothing to do (yet ?). break; case createTimer: //Nothing to do. diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java index 106bdfd..211b7ba 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java @@ -446,6 +446,7 @@ public class DialogueEditor extends JSONElementEditor { } break; case alignmentChange: + case alignmentSet: rewardMap = null; rewardObjId = addTextField(pane, "Faction: ", reward.reward_obj_id, writable, listener); rewardObjIdCombo = null; @@ -885,6 +886,10 @@ public class DialogueEditor extends JSONElementEditor { label.setText("Change alignment for faction "+rewardObjDesc+" : "+reward.reward_value); label.setIcon(new ImageIcon(DefaultIcons.getAlignmentIcon())); break; + case alignmentSet: + label.setText("Set alignment for faction "+rewardObjDesc+" : "+reward.reward_value); + label.setIcon(new ImageIcon(DefaultIcons.getAlignmentIcon())); + break; case createTimer: label.setText("Create timer "+rewardObjDesc); label.setIcon(new ImageIcon(DefaultIcons.getTimerIcon())); From ffe6a14cd9323773e2ff712d1183e85ccc3db5f8 Mon Sep 17 00:00:00 2001 From: Zukero Date: Sun, 11 Feb 2018 13:19:28 +0100 Subject: [PATCH 14/42] v0.6.10 released. --- ATCS_JAR.jardesc | 2 +- packaging/ATCS_latest | 2 +- packaging/Windows/ATCS_Installer.nsi | 2 +- src/com/gpl/rpg/atcontentstudio/ATContentStudio.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ATCS_JAR.jardesc b/ATCS_JAR.jardesc index 5a76d4d..a818851 100644 --- a/ATCS_JAR.jardesc +++ b/ATCS_JAR.jardesc @@ -1,6 +1,6 @@ - + diff --git a/packaging/ATCS_latest b/packaging/ATCS_latest index c80f388..3a1ee13 100644 --- a/packaging/ATCS_latest +++ b/packaging/ATCS_latest @@ -1 +1 @@ -v0.6.9 \ No newline at end of file +v0.6.10 \ No newline at end of file diff --git a/packaging/Windows/ATCS_Installer.nsi b/packaging/Windows/ATCS_Installer.nsi index f008e94..4e25b9e 100644 --- a/packaging/Windows/ATCS_Installer.nsi +++ b/packaging/Windows/ATCS_Installer.nsi @@ -1,6 +1,6 @@ !include MUI2.nsh -!define VERSION "0.6.9" +!define VERSION "0.6.10" !define TRAINER_VERSION "0.1.4" !define JAVA_BIN "javaw" diff --git a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java index 60b7ac2..94d6c29 100644 --- a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java +++ b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java @@ -43,7 +43,7 @@ import prefuse.data.expression.parser.ExpressionParser; public class ATContentStudio { public static final String APP_NAME = "Andor's Trail Content Studio"; - public static final String APP_VERSION = "v0.6.9"; + public static final String APP_VERSION = "v0.6.10"; public static final String CHECK_UPDATE_URL = "https://andorstrail.com/static/ATCS_latest"; public static final String DOWNLOAD_URL = "https://andorstrail.com/viewtopic.php?f=6&t=4806"; From ea28b7475a9c2c2b179764dad34e744d40915cce Mon Sep 17 00:00:00 2001 From: Zukero Date: Mon, 12 Feb 2018 11:40:36 +0100 Subject: [PATCH 15/42] Fixed non-critical NPE. --- .../rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java index 211b7ba..072c3fd 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java @@ -695,7 +695,7 @@ public class DialogueEditor extends JSONElementEditor { removeElementListener(requirementObj); } - requirementTypeCombo = addEnumValueBox(pane, "Requirement type: ", Requirement.RequirementType.values(), requirement.type, writable, listener); + requirementTypeCombo = addEnumValueBox(pane, "Requirement type: ", Requirement.RequirementType.values(), requirement == null ? null : requirement.type, writable, listener); requirementParamsPane = new JPanel(); requirementParamsPane.setLayout(new JideBoxLayout(requirementParamsPane, JideBoxLayout.PAGE_AXIS)); updateRequirementParamsEditorPane(requirementParamsPane, requirement, listener); From 6e2ee13da7ffc55a027634d29e5428e8e04699e3 Mon Sep 17 00:00:00 2001 From: Zukero Date: Mon, 12 Feb 2018 14:18:02 +0100 Subject: [PATCH 16/42] Fixed issue where worldmap.xml was unduely included in the generated loadresources.xml --- src/com/gpl/rpg/atcontentstudio/model/Project.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/com/gpl/rpg/atcontentstudio/model/Project.java b/src/com/gpl/rpg/atcontentstudio/model/Project.java index dd01c8f..ea443d3 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Project.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Project.java @@ -1129,10 +1129,12 @@ public class Project implements ProjectTreeNode, Serializable { tmpMapDir.mkdirs(); writtenFiles = new LinkedList(); for (File createdMapFile : createdContent.gameMaps.mapFolder.listFiles()) { + if (createdMapFile.getName().equalsIgnoreCase("worldmap.xml")) continue; FileUtils.copyFile(createdMapFile, new File(tmpMapDir, createdMapFile.getName())); writtenFiles.add(createdMapFile.getName()); } for (File alteredMapFile : alteredContent.gameMaps.mapFolder.listFiles()) { + if (alteredMapFile.getName().equalsIgnoreCase("worldmap.xml")) continue; FileUtils.copyFile(alteredMapFile, new File(tmpMapDir, alteredMapFile.getName())); writtenFiles.add(alteredMapFile.getName()); } From 1604373e6c15918c9977da853b1e837af2f8db07 Mon Sep 17 00:00:00 2001 From: Zukero Date: Tue, 13 Feb 2018 14:11:42 +0100 Subject: [PATCH 17/42] Fixed icons alignment. --- .../atcontentstudio/img/folder_map_closed.png | Bin 3116 -> 3081 bytes .../atcontentstudio/img/folder_map_open.png | Bin 4060 -> 4026 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/img/folder_map_closed.png b/src/com/gpl/rpg/atcontentstudio/img/folder_map_closed.png index 91c611525d8d9e534ab5e409bc3f7c4b51092803..5a343ba33567e23a28b0a80a14a2e1c38ea77799 100644 GIT binary patch delta 3030 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 Y0exLR=zt6vhyVZp07*qoM6N<$f&yXVlmGw# delta 3065 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 delta 4017 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 X-Ps10=PbIT00000NkvXXu0mjfT4CO& From 78ceacb0ce549fd53e43e00208164af58b9e6704 Mon Sep 17 00:00:00 2001 From: Zukero Date: Tue, 13 Feb 2018 15:26:13 +0100 Subject: [PATCH 18/42] Warnings hunt. --- .../java/com/zackehh/siphash/SipHash.java | 7 +++- .../rpg/atcontentstudio/ATContentStudio.java | 4 +- .../rpg/atcontentstudio/model/Project.java | 6 +-- .../model/WorkspaceSettings.java | 4 +- .../model/gamedata/Requirement.java | 1 + .../atcontentstudio/model/maps/TMXMapSet.java | 2 +- .../gpl/rpg/atcontentstudio/ui/Editor.java | 5 +-- .../gamedataeditors/ActorConditionEditor.java | 2 + .../ui/gamedataeditors/DialogueEditor.java | 2 + .../ui/gamedataeditors/JSONElementEditor.java | 2 +- .../ui/gamedataeditors/QuestEditor.java | 2 - .../ui/map/WorldMapEditor.java | 10 ++--- .../atcontentstudio/ui/map/WorldMapView.java | 2 +- .../ui/tools/writermode/WriterModeEditor.java | 40 +++++++++---------- 14 files changed, 48 insertions(+), 41 deletions(-) diff --git a/siphash-zackehh/src/main/java/com/zackehh/siphash/SipHash.java b/siphash-zackehh/src/main/java/com/zackehh/siphash/SipHash.java index d6d9da3..c82cb1f 100644 --- a/siphash-zackehh/src/main/java/com/zackehh/siphash/SipHash.java +++ b/siphash-zackehh/src/main/java/com/zackehh/siphash/SipHash.java @@ -1,6 +1,11 @@ package com.zackehh.siphash; -import static com.zackehh.siphash.SipHashConstants.*; +import static com.zackehh.siphash.SipHashConstants.DEFAULT_C; +import static com.zackehh.siphash.SipHashConstants.DEFAULT_D; +import static com.zackehh.siphash.SipHashConstants.INITIAL_V0; +import static com.zackehh.siphash.SipHashConstants.INITIAL_V1; +import static com.zackehh.siphash.SipHashConstants.INITIAL_V2; +import static com.zackehh.siphash.SipHashConstants.INITIAL_V3; /** * Main entry point for SipHash, providing a basic hash diff --git a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java index 94d6c29..e81e867 100644 --- a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java +++ b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java @@ -32,13 +32,13 @@ import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import javax.swing.plaf.FontUIResource; +import prefuse.data.expression.parser.ExpressionParser; + import com.gpl.rpg.atcontentstudio.model.Workspace; import com.gpl.rpg.atcontentstudio.ui.StudioFrame; import com.gpl.rpg.atcontentstudio.ui.WorkerDialog; import com.gpl.rpg.atcontentstudio.ui.WorkspaceSelector; -import prefuse.data.expression.parser.ExpressionParser; - public class ATContentStudio { diff --git a/src/com/gpl/rpg/atcontentstudio/model/Project.java b/src/com/gpl/rpg/atcontentstudio/model/Project.java index ea443d3..d551932 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Project.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Project.java @@ -1,6 +1,7 @@ package com.gpl.rpg.atcontentstudio.model; import java.awt.Image; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -8,7 +9,6 @@ import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.Serializable; -import java.io.StringBufferInputStream; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; @@ -16,12 +16,10 @@ import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.Set; import javax.swing.tree.TreeNode; import javax.xml.parsers.DocumentBuilder; @@ -1313,7 +1311,7 @@ public class Project implements ProjectTreeNode, Serializable { transformer.transform(input, output); String tempString = temp.toString(); - doc = builder.parse(new StringBufferInputStream(tempString)); + doc = builder.parse(new ByteArrayInputStream(tempString.getBytes("UTF-8"))); input = new DOMSource(doc); transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(new StringReader( "\r\n" + diff --git a/src/com/gpl/rpg/atcontentstudio/model/WorkspaceSettings.java b/src/com/gpl/rpg/atcontentstudio/model/WorkspaceSettings.java index 9bc85ab..79ce879 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/WorkspaceSettings.java +++ b/src/com/gpl/rpg/atcontentstudio/model/WorkspaceSettings.java @@ -158,7 +158,7 @@ public class WorkspaceSettings { value = defaultValue; } - public abstract void readFromJson(Map json); + public abstract void readFromJson(@SuppressWarnings("rawtypes") Map json); @SuppressWarnings({ "rawtypes", "unchecked" }) public void saveToJson(Map json) { @@ -188,6 +188,7 @@ public class WorkspaceSettings { super(id, null); } + @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public void saveToJson(Map json) { if (value != null) json.put(id, value); @@ -201,6 +202,7 @@ public class WorkspaceSettings { this.value = this.defaultValue = defaultValue; } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public void readFromJson(Map json) { value = new ArrayList(); diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java index 47087a0..e1356fb 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java @@ -172,6 +172,7 @@ public class Requirement extends JSONElement { case skillLevel: case spentGold: case timerElapsed: + case factionScore: break; } if (this.required_obj != null) this.required_obj.addBacklink((GameDataElement) this.parent); diff --git a/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMapSet.java b/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMapSet.java index b85354e..1e14eb5 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMapSet.java +++ b/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMapSet.java @@ -99,7 +99,7 @@ public class TMXMapSet implements ProjectTreeNode { while(getProject().open) { try { watchService = FileSystems.getDefault().newWatchService(); - WatchKey watchKey = folderPath.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY); + /*WatchKey watchKey = */folderPath.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY); WatchKey wk; validService: while(getProject().open) { wk = watchService.take(); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/Editor.java b/src/com/gpl/rpg/atcontentstudio/ui/Editor.java index 7c5e7ac..d40be0a 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/Editor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/Editor.java @@ -652,7 +652,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener { return gdeBox; } - public JComboBox addQuestStageBox(JPanel pane, Project proj, String label, Integer initialValue, boolean writable, final FieldUpdateListener listener, Quest quest, final JComboBox questSelectionBox) { + public JComboBox addQuestStageBox(JPanel pane, Project proj, String label, Integer initialValue, boolean writable, final FieldUpdateListener listener, Quest quest, @SuppressWarnings("rawtypes") final JComboBox questSelectionBox) { JPanel gdePane = new JPanel(); gdePane.setLayout(new JideBoxLayout(gdePane, JideBoxLayout.LINE_AXIS, 6)); JLabel gdeLabel = new JLabel(label); @@ -702,7 +702,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener { - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({ "rawtypes"}) public JList addBacklinksList(JPanel pane, GameDataElement gde) { return addBacklinksList(pane, gde, "Elements linking to this one"); } @@ -866,7 +866,6 @@ public abstract class Editor extends JPanel implements ProjectElementListener { return currentQuest.stages.get(index - 1); } - @SuppressWarnings("unchecked") @Override public void setSelectedItem(Object anItem) { selected = (QuestStage) anItem; diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/ActorConditionEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/ActorConditionEditor.java index 266de5b..b87c20e 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/ActorConditionEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/ActorConditionEditor.java @@ -36,6 +36,7 @@ public class ActorConditionEditor extends JSONElementEditor { private IntegerBasedCheckBox stackingBox; //private JTextField roundVisualField; + @SuppressWarnings("rawtypes") private JComboBox roundVisualField; private JSpinner roundHpMinField; private JSpinner roundHpMaxField; @@ -43,6 +44,7 @@ public class ActorConditionEditor extends JSONElementEditor { private JSpinner roundApMaxField; //private JTextField fullRoundVisualField; + @SuppressWarnings("rawtypes") private JComboBox fullRoundVisualField; private JSpinner fullRoundHpMinField; private JSpinner fullRoundHpMaxField; diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java index 072c3fd..858a07c 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java @@ -96,6 +96,7 @@ public class DialogueEditor extends JSONElementEditor { private JPanel rewardsParamsPane; private MyComboBox rewardMap; private JTextField rewardObjId; + @SuppressWarnings("rawtypes") private JComboBox rewardObjIdCombo; private MyComboBox rewardObj; private JComponent rewardValue; @@ -120,6 +121,7 @@ public class DialogueEditor extends JSONElementEditor { private JComboBox requirementTypeCombo; private JPanel requirementParamsPane; private MyComboBox requirementObj; + @SuppressWarnings("rawtypes") private JComboBox requirementSkill; private JTextField requirementObjId; private JComponent requirementValue; diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/JSONElementEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/JSONElementEditor.java index 48f4316..c70b5e8 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/JSONElementEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/JSONElementEditor.java @@ -44,7 +44,6 @@ import com.gpl.rpg.atcontentstudio.ui.ScrollablePanel; import com.gpl.rpg.atcontentstudio.ui.ScrollablePanel.ScrollableSizeHint; import com.gpl.rpg.atcontentstudio.ui.sprites.SpriteChooser; import com.jidesoft.swing.JideBoxLayout; -import com.jidesoft.swing.JideScrollPane; import com.jidesoft.swing.JideTabbedPane; public abstract class JSONElementEditor extends Editor { @@ -303,6 +302,7 @@ public abstract class JSONElementEditor extends Editor { } + @SuppressWarnings("unchecked") public boolean idChanging() { JSONElement node = (JSONElement) target; List toModify = new LinkedList(); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/QuestEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/QuestEditor.java index 4e416f5..39a0b73 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/QuestEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/QuestEditor.java @@ -40,8 +40,6 @@ public class QuestEditor extends JSONElementEditor { private static final long serialVersionUID = 5701667955210615366L; - private static final Integer one = 1; - private static final String form_view_id = "Form"; private static final String json_view_id = "JSON"; diff --git a/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapEditor.java index 3b60527..bdcdf17 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapEditor.java @@ -316,7 +316,7 @@ public class WorldMapEditor extends Editor implements FieldUpdateListener { @Override public void mouseClicked(MouseEvent e) { String selectedMap = null; - boolean update = false; +// boolean update = false; int x = (int) (e.getX() / mapView.zoomLevel); int y = (int) (e.getY() / mapView.zoomLevel); for (String s : mapView.mapLocations.keySet()) { @@ -333,19 +333,19 @@ public class WorldMapEditor extends Editor implements FieldUpdateListener { if (mapView.getSelectedMapsIDs().size() > 1) { removeFromSelection(selectedMap); // mapView.selected.remove(selectedMap); - update = true; +// update = true; } } else { addToSelection(selectedMap); // mapView.selected.add(selectedMap); - update = true; +// update = true; } } else { clearSelection(); // mapView.selected.clear(); addToSelection(selectedMap); // mapView.selected.add(selectedMap); - update = true; +// update = true; } } } else if (editMode == EditMode.addMap && mapBeingAddedID != null) { @@ -354,7 +354,7 @@ public class WorldMapEditor extends Editor implements FieldUpdateListener { pushToModel(); } mapView.updateFromModel(); - update = true; +// update = true; mapBeingAddedID = null; } // if (update) { diff --git a/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapView.java b/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapView.java index 67e768f..68f16e9 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapView.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapView.java @@ -85,7 +85,7 @@ public class WorldMapView extends JComponent implements Scrollable { @Override public void mouseClicked(MouseEvent e) { String selectedMap = null; - boolean update = false; +// boolean update = false; int x = (int) (e.getX() / zoomLevel); int y = (int) (e.getY() / zoomLevel); for (String s : mapLocations.keySet()) { diff --git a/src/com/gpl/rpg/atcontentstudio/ui/tools/writermode/WriterModeEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/tools/writermode/WriterModeEditor.java index 7445dbe..47509d1 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/tools/writermode/WriterModeEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/tools/writermode/WriterModeEditor.java @@ -341,12 +341,12 @@ public class WriterModeEditor extends Editor { } Node rNode; - int i = 1; +// int i = 1; for (WriterModeData.WriterReply reply : dialogue.replies) { if (reply instanceof EmptyReply && reply.next_dialogue != null) { if (cells.get(reply.next_dialogue) == null) { rNode = addDialogueNode(reply.next_dialogue); - Edge e = graph.addEdge(dNode, rNode); + /*Edge e = */graph.addEdge(dNode, rNode); } else { rNode = cells.get(reply.next_dialogue); Edge e = graph.addEdge(dNode, rNode); @@ -355,7 +355,7 @@ public class WriterModeEditor extends Editor { } else { if (cells.get(reply) == null) { rNode = addReplyNode(reply); - Edge e = graph.addEdge(dNode, rNode); + /*Edge e = */graph.addEdge(dNode, rNode); // e.setString(LABEL, "#"+i++); } else { rNode = cells.get(reply); @@ -380,7 +380,7 @@ public class WriterModeEditor extends Editor { if (reply.next_dialogue != null) { if (cells.get(reply.next_dialogue) == null) { Node dNode = addDialogueNode(reply.next_dialogue); - Edge e = graph.addEdge(rNode, dNode); + /*Edge e = */graph.addEdge(rNode, dNode); } else { Node dNode = cells.get(reply.next_dialogue); Edge e = graph.addEdge(rNode, dNode); @@ -665,7 +665,7 @@ public class WriterModeEditor extends Editor { cells.get(selected).set(LABEL, selected.text); } - static final String createNextDefaultNodeString = "createNextDefaultNode"; +// static final String createNextDefaultNodeString = "createNextDefaultNode"; final AbstractAction createNextDefaultNode = new AbstractAction("Create next default") { private static final long serialVersionUID = 1658086056088672748L; @@ -689,7 +689,7 @@ public class WriterModeEditor extends Editor { } } if (newNode!= null) { - Edge edge = graph.addEdge(cells.get(selected), newNode); + /*Edge edge = */graph.addEdge(cells.get(selected), newNode); setSelected(newWrNode); m_vis.run("colors"); @@ -732,7 +732,7 @@ public class WriterModeEditor extends Editor { temp.next_dialogue = newWrNode; newNode = addDialogueNode(newWrNode); - Edge edge = graph.addEdge(cells.get(selected), newNode); + /*Edge edge = */graph.addEdge(cells.get(selected), newNode); setSelected(newWrNode); m_vis.run("colors"); @@ -758,7 +758,7 @@ public class WriterModeEditor extends Editor { if (selected instanceof WriterReply) { newWrNode = data.new WriterReply(((WriterReply) selected).parent); newNode = addReplyNode(newWrNode); - Edge edge = graph.addEdge(cells.get(((WriterReply) selected).parent), newNode); + /*Edge edge = */graph.addEdge(cells.get(((WriterReply) selected).parent), newNode); setSelected(newWrNode); m_vis.run("colors"); @@ -903,18 +903,18 @@ public class WriterModeEditor extends Editor { } } - public void selectScrollAndEdit(WriterNode node) { - if (node != null) { - setSelected(node); - - m_vis.run("colors"); - m_vis.run("layout"); - m_vis.run("scrollToSelectedAndEdit"); - - revalidate(); - repaint(); - } - } +// public void selectScrollAndEdit(WriterNode node) { +// if (node != null) { +// setSelected(node); +// +// m_vis.run("colors"); +// m_vis.run("layout"); +// m_vis.run("scrollToSelectedAndEdit"); +// +// revalidate(); +// repaint(); +// } +// } From f2e4767eb0ca6c51273c9e15d4cff30beb80777a Mon Sep 17 00:00:00 2001 From: Zukero Date: Sun, 18 Feb 2018 11:28:03 +0100 Subject: [PATCH 19/42] Fixed export bug multiplying the data. --- src/com/gpl/rpg/atcontentstudio/model/Project.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/gpl/rpg/atcontentstudio/model/Project.java b/src/com/gpl/rpg/atcontentstudio/model/Project.java index d551932..31e4f61 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Project.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Project.java @@ -1171,7 +1171,9 @@ public class Project implements ProjectTreeNode, Serializable { List filenamesToWrite = new LinkedList(); Map> dataToWritePerFilename = new LinkedHashMap>(); for (JSONElement gde : altered) { - filenamesToWrite.add(gde.jsonFile.getName()); + if (!filenamesToWrite.contains(gde.jsonFile.getName())) { + filenamesToWrite.add(gde.jsonFile.getName()); + } } for (JSONElement gde : created) { if (!filenamesToWrite.contains(gde.jsonFile.getName())) { From 221a031c2bd2c505211975b1859d944d7521a944 Mon Sep 17 00:00:00 2001 From: Zukero Date: Thu, 22 Feb 2018 16:25:38 +0100 Subject: [PATCH 20/42] Added support for new spawn area property: ignoreAreas. --- src/com/gpl/rpg/atcontentstudio/model/maps/SpawnArea.java | 7 +++++++ src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/com/gpl/rpg/atcontentstudio/model/maps/SpawnArea.java b/src/com/gpl/rpg/atcontentstudio/model/maps/SpawnArea.java index f04b3ac..1052c40 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/maps/SpawnArea.java +++ b/src/com/gpl/rpg/atcontentstudio/model/maps/SpawnArea.java @@ -13,6 +13,7 @@ public class SpawnArea extends MapObject { public int quantity = 1; public int spawnchance = 10; public boolean active = true; + public boolean ignoreAreas = false; public String spawngroup_id; public List spawnGroup = new ArrayList(); @@ -26,6 +27,9 @@ public class SpawnArea extends MapObject { if (obj.getProperties().getProperty("active") != null) { this.active = Boolean.parseBoolean(obj.getProperties().getProperty("active")); } + if (obj.getProperties().getProperty("ignoreAreas") != null) { + this.ignoreAreas = Boolean.parseBoolean(obj.getProperties().getProperty("ignoreAreas")); + } if (obj.getProperties().getProperty("spawngroup") != null) { this.spawngroup_id = obj.getProperties().getProperty("spawngroup"); } else if (obj.getName() != null ){ @@ -84,6 +88,9 @@ public class SpawnArea extends MapObject { if (!this.active) { tmxObject.getProperties().setProperty("active", Boolean.toString(active)); } + if (this.ignoreAreas) { + tmxObject.getProperties().setProperty("ignoreAreas", Boolean.toString(ignoreAreas)); + } } } diff --git a/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java index 0ebf936..c1bf206 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java @@ -162,6 +162,7 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe private JComboBox evaluateTriggerBox; private JSpinner quantityField; private JCheckBox spawnActiveForNewGame; + private JCheckBox spawnIgnoreAreas; private JTextField spawngroupField; @SuppressWarnings("rawtypes") private JList npcList; @@ -629,6 +630,7 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe spawngroupField = addTextField(pane, "Spawn group ID: ", ((SpawnArea)selected).spawngroup_id, ((TMXMap)target).writable, listener); quantityField = addIntegerField(pane, "Number of spawned NPCs: ", ((SpawnArea)selected).quantity, false, ((TMXMap)target).writable, listener); spawnActiveForNewGame = addBooleanBasedCheckBox(pane, "Active in a new game: ", ((SpawnArea)selected).active, ((TMXMap)target).writable, listener); + spawnIgnoreAreas = addBooleanBasedCheckBox(pane, "Monsters can walk on other game objects: ", ((SpawnArea)selected).ignoreAreas, ((TMXMap)target).writable, listener); npcListModel = new SpawnGroupNpcListModel((SpawnArea) selected); npcList = new JList(npcListModel); npcList.setCellRenderer(new GDERenderer(true, ((TMXMap)target).writable)); @@ -1993,6 +1995,11 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe SpawnArea area = (SpawnArea) selectedMapObject; area.active = (Boolean) value; } + } else if (source == spawnIgnoreAreas) { + if (selectedMapObject instanceof SpawnArea) { + SpawnArea area = (SpawnArea) selectedMapObject; + area.ignoreAreas = (Boolean) value; + } } else if (source == requirementTypeCombo) { if (selectedMapObject instanceof KeyArea) { KeyArea area = (KeyArea) selectedMapObject; From 0b8bc8448af0fffd3e377c311e5cadb0dc851ca9 Mon Sep 17 00:00:00 2001 From: Zukero Date: Wed, 28 Feb 2018 16:25:28 +0100 Subject: [PATCH 21/42] Fixed memory leaks. Closed projects were held in memory because the Map folder watcher threads were still alive. --- .../atcontentstudio/model/maps/TMXMapSet.java | 27 ++++++++++--------- .../atcontentstudio/ui/WorkspaceActions.java | 1 + 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMapSet.java b/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMapSet.java index 1e14eb5..031cb42 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMapSet.java +++ b/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMapSet.java @@ -15,6 +15,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.List; +import java.util.concurrent.TimeUnit; import javax.swing.tree.TreeNode; @@ -102,19 +103,21 @@ public class TMXMapSet implements ProjectTreeNode { /*WatchKey watchKey = */folderPath.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY); WatchKey wk; validService: while(getProject().open) { - wk = watchService.take(); - for (WatchEvent event : wk.pollEvents()) { - Path changed = (Path) event.context(); - String name = changed.getFileName().toString(); - String id = name.substring(0, name.length() - 4); - TMXMap map = getMap(id); - if (map != null) { - map.mapChangedOnDisk(); + wk = watchService.poll(10, TimeUnit.SECONDS); + if (wk != null) { + for (WatchEvent event : wk.pollEvents()) { + Path changed = (Path) event.context(); + String name = changed.getFileName().toString(); + String id = name.substring(0, name.length() - 4); + TMXMap map = getMap(id); + if (map != null) { + map.mapChangedOnDisk(); + } + } + if(!wk.reset()) { + watchService.close(); + break validService; } - } - if(!wk.reset()) { - watchService.close(); - break validService; } } } catch (IOException e) { diff --git a/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceActions.java b/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceActions.java index af881d6..4ef50c6 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceActions.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceActions.java @@ -59,6 +59,7 @@ public class WorkspaceActions { public void actionPerformed(ActionEvent e) { if (!(selectedNode instanceof Project)) return; Workspace.closeProject((Project) selectedNode); + selectedNode = null; }; public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) { setEnabled(selectedNode instanceof Project); From b12ed1802fb6ec194682cf0e3b2e421852ae1a57 Mon Sep 17 00:00:00 2001 From: Zukero Date: Sun, 4 Mar 2018 12:19:56 +0100 Subject: [PATCH 22/42] Added hero sprite rendering to help debug layering issues in "Replacements" tab of TMX Map editor. --- .../atcontentstudio/model/maps/TMXMap.java | 1 + .../atcontentstudio/ui/map/TMXMapEditor.java | 43 ++++++++++++++++--- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMap.java b/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMap.java index 2a6ec8a..238edae 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMap.java +++ b/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMap.java @@ -38,6 +38,7 @@ public class TMXMap extends GameDataElement { public static final String GROUND_LAYER_NAME = "Ground"; public static final String OBJECTS_LAYER_NAME = "Objects"; public static final String ABOVE_LAYER_NAME = "Above"; + public static final String TOP_LAYER_NAME = "Top"; public static final String WALKABLE_LAYER_NAME = "Walkable"; public enum ColorFilter { diff --git a/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java index c1bf206..c48a817 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java @@ -2183,11 +2183,12 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe private TMXMap map; public ReplaceArea highlighted = null; public boolean showWalkable = true; + public boolean walkableTest = true; private OrthogonalRenderer renderer; - private String groundName, objectsName, aboveName, walkableName; + private String groundName, objectsName, aboveName, topName, walkableName; private Map layersByName = new LinkedHashMap(); - private tiled.core.TileLayer ground, objects, above, walkable; + private tiled.core.TileLayer ground, objects, above, top, walkable; private Map> replacementsForLayer = new LinkedHashMap>(); public Map activeReplacements = new LinkedHashMap(); @@ -2206,6 +2207,7 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent e) { + Point oldTooltippedTile = new Point(tooltippedTile); tooltippedTile.setLocation(e.getX() / 32, e.getY() / 32); if (!((TMXMap)target).tmxMap.contains(tooltippedTile.x, tooltippedTile.y)) { if (tooltipActivated) { @@ -2221,6 +2223,10 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe tooltipActivated = true; } } + if (walkableTest && (oldTooltippedTile.x != tooltippedTile.x || oldTooltippedTile.y != tooltippedTile.y) ) { + TMXReplacementViewer.this.revalidate(); + TMXReplacementViewer.this.repaint(); + } } }); @@ -2230,9 +2236,9 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe } public void init() { - groundName = objectsName = aboveName = walkableName = null; + groundName = objectsName = aboveName = walkableName = topName = null; layersByName.clear(); - ground = objects = above = walkable = null; + ground = objects = above = walkable = top = null; replacementsForLayer.clear(); for (tiled.core.MapLayer layer : map.tmxMap.getLayers()) { @@ -2244,6 +2250,8 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe objectsName = layer.getName(); } else if (TMXMap.ABOVE_LAYER_NAME.equalsIgnoreCase(layer.getName())) { aboveName = layer.getName(); + } else if (TMXMap.TOP_LAYER_NAME.equalsIgnoreCase(layer.getName())) { + topName = layer.getName(); } else if (TMXMap.WALKABLE_LAYER_NAME.equalsIgnoreCase(layer.getName())) { walkableName = layer.getName(); } @@ -2273,6 +2281,7 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe ground = mergeReplacements(groundName); objects = mergeReplacements(objectsName); above = mergeReplacements(aboveName); + top = mergeReplacements(topName); walkable = mergeReplacements(walkableName); } @@ -2328,10 +2337,18 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe renderer.paintTileLayer(g2d, objects); } + if (walkableTest && tooltippedTile != null && ((TMXMap)target).tmxMap.contains(tooltippedTile.x, tooltippedTile.y) && + walkable != null && walkable.getTileAt(tooltippedTile.x, tooltippedTile.y) == null) { + g2d.drawImage(DefaultIcons.getHeroImage(), tooltippedTile.x * 32, tooltippedTile.y * 32, 32, 32, null); + } + if (above != null) { renderer.paintTileLayer(g2d, above); } - + + if (top != null) { + renderer.paintTileLayer(g2d, top); + } if (walkable != null && showWalkable) { renderer.paintTileLayer(g2d, walkable); } @@ -2388,10 +2405,12 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe JLabel noTileGround = new JLabel(new ImageIcon(DefaultIcons.getNullifyImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT))); JLabel noTileObjects = new JLabel(new ImageIcon(DefaultIcons.getNullifyImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT))); JLabel noTileAbove = new JLabel(new ImageIcon(DefaultIcons.getNullifyImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT))); + JLabel noTileTop = new JLabel(new ImageIcon(DefaultIcons.getNullifyImage().getScaledInstance(32, 32, Image.SCALE_DEFAULT))); { noTileGround.setPreferredSize(new Dimension(32, 32)); noTileObjects.setPreferredSize(new Dimension(32, 32)); noTileAbove.setPreferredSize(new Dimension(32, 32)); + noTileTop.setPreferredSize(new Dimension(32, 32)); } Point tooltippedTile = new Point(); JToolTip tt = null; @@ -2413,6 +2432,20 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe if (tooltippedTile != null) { Image tile; JLabel label; + + if (top != null && top.getTileAt(tooltippedTile.x, tooltippedTile.y) != null) { + tile = top.getTileAt(tooltippedTile.x, tooltippedTile.y).getImage(); + } else { + tile = null; + } + if (tile != null) { + label = new JLabel(new ImageIcon(tile)); + label.setPreferredSize(new Dimension(32,32)); + content.add(label, JideBoxLayout.FIX); + //Fix when (if?) Top is advertised publicly. +// } else { +// content.add(noTileTop, JideBoxLayout.FIX); + } if (above != null && above.getTileAt(tooltippedTile.x, tooltippedTile.y) != null) { tile = above.getTileAt(tooltippedTile.x, tooltippedTile.y).getImage(); From 38c206cbaf48eb8f00b3a5387b45654d4331711a Mon Sep 17 00:00:00 2001 From: Zukero Date: Sun, 4 Mar 2018 15:39:30 +0100 Subject: [PATCH 23/42] TMX Maps editor's "Replacement" tab is now called "Testing" and has more tools. --- .../atcontentstudio/model/maps/TMXMap.java | 1 + .../atcontentstudio/ui/map/TMXMapEditor.java | 41 +++++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMap.java b/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMap.java index 238edae..4a2fe88 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMap.java +++ b/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMap.java @@ -399,6 +399,7 @@ public class TMXMap extends GameDataElement { return GROUND_LAYER_NAME.equalsIgnoreCase(name) || OBJECTS_LAYER_NAME.equalsIgnoreCase(name) || ABOVE_LAYER_NAME.equalsIgnoreCase(name) || + TOP_LAYER_NAME.equalsIgnoreCase(name) || WALKABLE_LAYER_NAME.equalsIgnoreCase(name); } diff --git a/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java index c48a817..945da13 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java @@ -212,7 +212,7 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe editorTabsHolder.add("TMX", tmxScroller); editorTabsHolder.add("XML", xmlScroller); //editorTabsHolder.add("Replacements", replScroller); - editorTabsHolder.add("Replacements", getReplacementSimulatorPane()); + editorTabsHolder.add("Testing", getReplacementSimulatorPane()); } @@ -782,7 +782,11 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe public JPanel getReplacementSimulatorPane() { JPanel replacementSimulator = new JPanel(); replacementSimulator.setLayout(new JideBoxLayout(replacementSimulator, JideBoxLayout.PAGE_AXIS)); + JPanel toolsPane = new JPanel(); + toolsPane.setLayout(new JideBoxLayout(toolsPane, JideBoxLayout.LINE_AXIS)); final JCheckBox walkableVisibleBox = new JCheckBox("Show \""+TMXMap.WALKABLE_LAYER_NAME+"\" layer."); + final JCheckBox showHeroBox = new JCheckBox("Show hero on walkable tiles under the mouse pointer."); + final JCheckBox showTooltipBox = new JCheckBox("Show tooltip with stack of tiles."); JPanel areasActivationPane = new JPanel(); areasActivationPane.setLayout(new JideBoxLayout(areasActivationPane, JideBoxLayout.PAGE_AXIS)); TreeModel areasTreeModel = new ReplaceAreasActivationTreeModel(); @@ -800,10 +804,15 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe activateAndViewPane.add(areasActivationPane, JideBoxLayout.FIX); activateAndViewPane.add(new JScrollPane(viewer), JideBoxLayout.VARY); - replacementSimulator.add(walkableVisibleBox, JideBoxLayout.FIX); + toolsPane.add(walkableVisibleBox, JideBoxLayout.FIX); + toolsPane.add(showTooltipBox, JideBoxLayout.FIX); + toolsPane.add(showHeroBox, JideBoxLayout.FIX); + toolsPane.add(new JPanel(), JideBoxLayout.VARY); + + replacementSimulator.add(toolsPane, JideBoxLayout.FIX); replacementSimulator.add(activateAndViewPane, JideBoxLayout.VARY); - walkableVisibleBox.setSelected(true); + walkableVisibleBox.setSelected(viewer.showWalkable); walkableVisibleBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -812,6 +821,21 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe viewer.repaint(); } }); + + showHeroBox.setSelected(viewer.showHeroWithMouse); + showHeroBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + viewer.showHeroWithMouse = showHeroBox.isSelected(); + } + }); + showTooltipBox.setSelected(viewer.showTooltip); + showTooltipBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + viewer.showTooltip = showTooltipBox.isSelected(); + } + }); activate.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -2183,7 +2207,8 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe private TMXMap map; public ReplaceArea highlighted = null; public boolean showWalkable = true; - public boolean walkableTest = true; + public boolean showHeroWithMouse = true; + public boolean showTooltip = true; private OrthogonalRenderer renderer; private String groundName, objectsName, aboveName, topName, walkableName; @@ -2209,7 +2234,7 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe public void mouseMoved(MouseEvent e) { Point oldTooltippedTile = new Point(tooltippedTile); tooltippedTile.setLocation(e.getX() / 32, e.getY() / 32); - if (!((TMXMap)target).tmxMap.contains(tooltippedTile.x, tooltippedTile.y)) { + if (!showTooltip || !((TMXMap)target).tmxMap.contains(tooltippedTile.x, tooltippedTile.y)) { if (tooltipActivated) { //Hides the tooltip... ToolTipManager.sharedInstance().setEnabled(false); @@ -2217,13 +2242,13 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe tooltipActivated = false; } } else { - if (!tooltipActivated) { + if (showTooltip && !tooltipActivated) { ToolTipManager.sharedInstance().registerComponent(TMXReplacementViewer.this); ToolTipManager.sharedInstance().setEnabled(true); tooltipActivated = true; } } - if (walkableTest && (oldTooltippedTile.x != tooltippedTile.x || oldTooltippedTile.y != tooltippedTile.y) ) { + if (showHeroWithMouse && (oldTooltippedTile.x != tooltippedTile.x || oldTooltippedTile.y != tooltippedTile.y) ) { TMXReplacementViewer.this.revalidate(); TMXReplacementViewer.this.repaint(); } @@ -2337,7 +2362,7 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe renderer.paintTileLayer(g2d, objects); } - if (walkableTest && tooltippedTile != null && ((TMXMap)target).tmxMap.contains(tooltippedTile.x, tooltippedTile.y) && + if (showHeroWithMouse && tooltippedTile != null && ((TMXMap)target).tmxMap.contains(tooltippedTile.x, tooltippedTile.y) && walkable != null && walkable.getTileAt(tooltippedTile.x, tooltippedTile.y) == null) { g2d.drawImage(DefaultIcons.getHeroImage(), tooltippedTile.x * 32, tooltippedTile.y * 32, 32, 32, null); } From 75d6f8e98fdafd103c67c943114fb7f171e29d51 Mon Sep 17 00:00:00 2001 From: Zukero Date: Sun, 4 Mar 2018 15:43:45 +0100 Subject: [PATCH 24/42] v0.6.11 released. --- ATCS_JAR.jardesc | 2 +- packaging/ATCS_latest | 2 +- packaging/Windows/ATCS_Installer.nsi | 2 +- src/com/gpl/rpg/atcontentstudio/ATContentStudio.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ATCS_JAR.jardesc b/ATCS_JAR.jardesc index a818851..2b7e907 100644 --- a/ATCS_JAR.jardesc +++ b/ATCS_JAR.jardesc @@ -1,6 +1,6 @@ - + diff --git a/packaging/ATCS_latest b/packaging/ATCS_latest index 3a1ee13..215f621 100644 --- a/packaging/ATCS_latest +++ b/packaging/ATCS_latest @@ -1 +1 @@ -v0.6.10 \ No newline at end of file +v0.6.11 \ No newline at end of file diff --git a/packaging/Windows/ATCS_Installer.nsi b/packaging/Windows/ATCS_Installer.nsi index 4e25b9e..cd6d598 100644 --- a/packaging/Windows/ATCS_Installer.nsi +++ b/packaging/Windows/ATCS_Installer.nsi @@ -1,6 +1,6 @@ !include MUI2.nsh -!define VERSION "0.6.10" +!define VERSION "0.6.11" !define TRAINER_VERSION "0.1.4" !define JAVA_BIN "javaw" diff --git a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java index e81e867..65a8fe7 100644 --- a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java +++ b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java @@ -43,7 +43,7 @@ import com.gpl.rpg.atcontentstudio.ui.WorkspaceSelector; public class ATContentStudio { public static final String APP_NAME = "Andor's Trail Content Studio"; - public static final String APP_VERSION = "v0.6.10"; + public static final String APP_VERSION = "v0.6.11"; public static final String CHECK_UPDATE_URL = "https://andorstrail.com/static/ATCS_latest"; public static final String DOWNLOAD_URL = "https://andorstrail.com/viewtopic.php?f=6&t=4806"; From 9b68ef6679a3886f3c776eb95ec68df65e700069 Mon Sep 17 00:00:00 2001 From: Zukero Date: Mon, 26 Mar 2018 17:14:10 +0200 Subject: [PATCH 25/42] Added missing "Faction" field to the NPC UI. --- .../gpl/rpg/atcontentstudio/ui/gamedataeditors/NPCEditor.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/NPCEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/NPCEditor.java index 2f4f79c..639c33d 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/NPCEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/NPCEditor.java @@ -63,6 +63,7 @@ public class NPCEditor extends JSONElementEditor { private JTextField idField; private JTextField nameField; private JTextField spawnGroupField; + private JTextField factionField; private JSpinner experienceField; private MyComboBox dialogueBox; private MyComboBox droplistBox; @@ -246,6 +247,7 @@ public class NPCEditor extends JSONElementEditor { idField = addTextField(pane, "Internal ID: ", npc.id, npc.writable, listener); nameField = addTranslatableTextField(pane, "Display name: ", npc.name, npc.writable, listener); spawnGroupField = addTextField(pane, "Spawn group ID: ", npc.spawngroup_id, npc.writable, listener); + factionField = addTextField(pane, "Faction ID: ", npc.faction_id, npc.writable, listener); experienceField = addIntegerField(pane, "Experience reward: ", npc.getMonsterExperience(), false, false, listener); dialogueBox = addDialogueBox(pane, npc.getProject(), "Initial phrase: ", npc.dialogue, npc.writable, listener); droplistBox = addDroplistBox(pane, npc.getProject(), "Droplist / Shop inventory: ", npc.droplist, npc.writable, listener); @@ -1256,6 +1258,8 @@ public class NPCEditor extends JSONElementEditor { npcIcon.repaint(); } else if (source == spawnGroupField) { npc.spawngroup_id = (String) value; + } else if (source == factionField) { + npc.faction_id = (String) value; } else if (source == dialogueBox) { if (npc.dialogue != null) { npc.dialogue.removeBacklink(npc); From ae5822703a1ea5809d00297f260f1dc6e809e033 Mon Sep 17 00:00:00 2001 From: Zukero Date: Mon, 26 Mar 2018 17:41:42 +0200 Subject: [PATCH 26/42] Fixed harmless NPE in Dialogue editor. --- .../rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java index 858a07c..fd09e6d 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/DialogueEditor.java @@ -714,7 +714,7 @@ public class DialogueEditor extends JSONElementEditor { removeElementListener(requirementObj); } - if (requirement.type != null) { + if (requirement != null && requirement.type != null) { switch (requirement.type) { case consumedBonemeals: case spentGold: From 9f5666ea6d3859d3093c3c886476c3ab343e6a20 Mon Sep 17 00:00:00 2001 From: Zukero Date: Fri, 13 Jul 2018 19:03:08 +0200 Subject: [PATCH 27/42] Fixed bugs affecting Dialogue's replies, Key Areas and Replace areas where requirements' negation where lost upon alteration or loading. --- .../gpl/rpg/atcontentstudio/model/gamedata/Requirement.java | 1 + src/com/gpl/rpg/atcontentstudio/model/maps/KeyArea.java | 5 ++++- src/com/gpl/rpg/atcontentstudio/model/maps/ReplaceArea.java | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java index e1356fb..edf1b54 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Requirement.java @@ -191,6 +191,7 @@ public class Requirement extends JSONElement { clone.state = this.state; clone.required_obj_id = this.required_obj_id; clone.required_value = this.required_value; + clone.negated = this.negated; clone.required_obj = this.required_obj; clone.type = this.type; if (clone.required_obj != null && parent != null) { diff --git a/src/com/gpl/rpg/atcontentstudio/model/maps/KeyArea.java b/src/com/gpl/rpg/atcontentstudio/model/maps/KeyArea.java index ed3aa2e..c583328 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/maps/KeyArea.java +++ b/src/com/gpl/rpg/atcontentstudio/model/maps/KeyArea.java @@ -19,6 +19,7 @@ public class KeyArea extends MapObject { String requireType = obj.getProperties().getProperty("requireType"); String requireId = obj.getProperties().getProperty("requireId"); String requireValue = obj.getProperties().getProperty("requireValue"); + String requireNegation = obj.getProperties().getProperty("requireNegation"); oldSchoolRequirement = false; if (requireType == null) { String[] fields = obj.getName().split(":"); @@ -38,7 +39,9 @@ public class KeyArea extends MapObject { if (requireType != null) requirement.type = Requirement.RequirementType.valueOf(requireType); requirement.required_obj_id = requireId; if (requireValue != null) requirement.required_value = Integer.parseInt(requireValue); + if (requireNegation != null) requirement.negated = Boolean.parseBoolean(requireNegation); requirement.state = GameDataElement.State.parsed; + } @Override @@ -98,7 +101,7 @@ public class KeyArea extends MapObject { public void updateNameFromRequirementChange() { if (oldSchoolRequirement && Requirement.RequirementType.questProgress.equals(requirement.type) && (requirement.negated == null || !requirement.negated)) { - name = requirement.required_obj_id+":"+((requirement.required_value == null) ? "" : Integer.toString(requirement.required_value)); + name = (requirement.negated != null && requirement.negated) ? "NOT " : "" + requirement.required_obj_id+":"+((requirement.required_value == null) ? "" : Integer.toString(requirement.required_value)); } else if (oldSchoolRequirement) { int i = 0; String futureName = requirement.type.toString() + "#" + Integer.toString(i); diff --git a/src/com/gpl/rpg/atcontentstudio/model/maps/ReplaceArea.java b/src/com/gpl/rpg/atcontentstudio/model/maps/ReplaceArea.java index 34e0ef7..ed64ea0 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/maps/ReplaceArea.java +++ b/src/com/gpl/rpg/atcontentstudio/model/maps/ReplaceArea.java @@ -20,6 +20,7 @@ public class ReplaceArea extends MapObject { String requireType = obj.getProperties().getProperty("requireType"); String requireId = obj.getProperties().getProperty("requireId"); String requireValue = obj.getProperties().getProperty("requireValue"); + String requireNegation = obj.getProperties().getProperty("requireNegation"); if (requireType == null) { String[] fields = obj.getName().split(":"); if (fields.length == 2) { @@ -37,6 +38,7 @@ public class ReplaceArea extends MapObject { if (requireType != null) requirement.type = Requirement.RequirementType.valueOf(requireType); requirement.required_obj_id = requireId; if (requireValue != null) requirement.required_value = Integer.parseInt(requireValue); + if (requireNegation != null) requirement.negated = Boolean.parseBoolean(requireNegation); requirement.state = GameDataElement.State.parsed; @@ -112,7 +114,7 @@ public class ReplaceArea extends MapObject { //Don't use yet ! public void updateNameFromRequirementChange() { if (oldSchoolRequirement && Requirement.RequirementType.questProgress.equals(requirement.type) && (requirement.negated == null || !requirement.negated)) { - name = requirement.required_obj_id+":"+((requirement.required_value == null) ? "" : Integer.toString(requirement.required_value)); + name = (requirement.negated != null && requirement.negated) ? "NOT " : "" + requirement.required_obj_id+":"+((requirement.required_value == null) ? "" : Integer.toString(requirement.required_value)); } else if (oldSchoolRequirement) { int i = 0; String futureName = requirement.type.toString() + "#" + Integer.toString(i); From 84e46ffd205155192f8591a6789f8be81219b31d Mon Sep 17 00:00:00 2001 From: Zukero Date: Fri, 13 Jul 2018 19:06:12 +0200 Subject: [PATCH 28/42] v0.6.12 released --- ATCS_JAR.jardesc | 2 +- packaging/Windows/ATCS_Installer.nsi | 2 +- src/com/gpl/rpg/atcontentstudio/ATContentStudio.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ATCS_JAR.jardesc b/ATCS_JAR.jardesc index 2b7e907..c09bb91 100644 --- a/ATCS_JAR.jardesc +++ b/ATCS_JAR.jardesc @@ -1,6 +1,6 @@ - + diff --git a/packaging/Windows/ATCS_Installer.nsi b/packaging/Windows/ATCS_Installer.nsi index cd6d598..efd2667 100644 --- a/packaging/Windows/ATCS_Installer.nsi +++ b/packaging/Windows/ATCS_Installer.nsi @@ -1,6 +1,6 @@ !include MUI2.nsh -!define VERSION "0.6.11" +!define VERSION "0.6.12" !define TRAINER_VERSION "0.1.4" !define JAVA_BIN "javaw" diff --git a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java index 65a8fe7..a55141b 100644 --- a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java +++ b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java @@ -43,7 +43,7 @@ import com.gpl.rpg.atcontentstudio.ui.WorkspaceSelector; public class ATContentStudio { public static final String APP_NAME = "Andor's Trail Content Studio"; - public static final String APP_VERSION = "v0.6.11"; + public static final String APP_VERSION = "v0.6.12"; public static final String CHECK_UPDATE_URL = "https://andorstrail.com/static/ATCS_latest"; public static final String DOWNLOAD_URL = "https://andorstrail.com/viewtopic.php?f=6&t=4806"; From 3800bf8ff0f6b2b645b731cf43d06487b08e458a Mon Sep 17 00:00:00 2001 From: Zukero Date: Fri, 10 Aug 2018 23:45:50 +0200 Subject: [PATCH 29/42] Added code to generate new english.pot file and some tools to ease transition of existing translations towards the new content. --- packaging/ATCS_latest | 2 +- .../rpg/atcontentstudio/ui/AboutEditor.java | 3 + .../ui/tools/i18n/PotComparator.java | 154 ++++++++++ .../ui/tools/i18n/PotGenerator.java | 114 ++++++++ src/net/launchpad/tobal/poparser/POEntry.java | 100 +++++++ src/net/launchpad/tobal/poparser/POFile.java | 139 +++++++++ src/net/launchpad/tobal/poparser/POLine.java | 42 +++ .../launchpad/tobal/poparser/POParser.java | 275 ++++++++++++++++++ .../launchpad/tobal/poparser/ParserTest.java | 24 ++ 9 files changed, 852 insertions(+), 1 deletion(-) create mode 100644 src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotComparator.java create mode 100644 src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java create mode 100644 src/net/launchpad/tobal/poparser/POEntry.java create mode 100644 src/net/launchpad/tobal/poparser/POFile.java create mode 100644 src/net/launchpad/tobal/poparser/POLine.java create mode 100644 src/net/launchpad/tobal/poparser/POParser.java create mode 100644 src/net/launchpad/tobal/poparser/ParserTest.java diff --git a/packaging/ATCS_latest b/packaging/ATCS_latest index 215f621..cd7a095 100644 --- a/packaging/ATCS_latest +++ b/packaging/ATCS_latest @@ -1 +1 @@ -v0.6.11 \ No newline at end of file +v0.6.12 \ No newline at end of file diff --git a/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java index ed3574b..4401e45 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java @@ -78,6 +78,9 @@ public class AboutEditor extends Editor { "jsoup by Jonathan Hedley
" + "License: MIT License
" + "
" + + "A slightly modified version of General PO Parser by Balázs Tóth
" + + "License: GPL v3
" + + "
" + "See the tabs below to find the full license text for each of these.
" + "
" + "The Windows installer was created with:
" + diff --git a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotComparator.java b/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotComparator.java new file mode 100644 index 0000000..f326769 --- /dev/null +++ b/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotComparator.java @@ -0,0 +1,154 @@ +package com.gpl.rpg.atcontentstudio.ui.tools.i18n; + +import java.io.File; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import com.gpl.rpg.atcontentstudio.model.Project; + +import net.launchpad.tobal.poparser.POEntry; +import net.launchpad.tobal.poparser.POFile; +import net.launchpad.tobal.poparser.POParser; + +public class PotComparator { + + Map> stringsResourcesNew = new LinkedHashMap>(); + Map resourcesStringsNew = new LinkedHashMap(); + + Map> stringsResourcesOld = new LinkedHashMap>(); + Map resourcesStringsOld = new LinkedHashMap(); + + + public PotComparator(Project proj) { + POParser parser = new POParser(); + + POFile newPot = parser.parseFile(new File(proj.alteredContent.baseFolder.getAbsolutePath()+File.separator+"english.pot")); + if (newPot == null) { + System.err.println("Cannot locate new english.pot file at "+proj.alteredContent.baseFolder.getAbsolutePath()+File.separator); + } + extractFromPoFile(newPot, stringsResourcesNew, resourcesStringsNew); + + POFile oldPot = parser.parseFile(new File(proj.baseContent.baseFolder.getAbsolutePath()+File.separator+"assets"+File.separator+"translation"+File.separator+"english.pot")); + if (oldPot == null) { + System.err.println("Cannot locate old english.pot file at "+proj.baseContent.baseFolder.getAbsolutePath()+File.separator+"assets"+File.separator+"translations"+File.separator); + } + extractFromPoFile(oldPot, stringsResourcesOld, resourcesStringsOld); + } + + + private void extractFromPoFile(POFile po, Map> stringsResources, Map resourcesStrings) { + for (POEntry entry : po.getEntryArray()) { + Vector resources = entry.getStringsByType(POEntry.StringType.REFERENCE); + Vector msgids = entry.getStringsByType(POEntry.StringType.MSGID); + if (resources == null || resources.size() == 0 || msgids == null || msgids.size() == 0) continue; + String msgid = msgids.get(0); + if (msgids.size() > 1) { + for (int i = 1; i < msgids.size(); i++) { + msgid += "\n"; + msgid += msgids.get(i); + } + } + for (String resLine : resources) { + String[] resArray = resLine.split(" "); + for (String res : resArray) { + resourcesStrings.put(res, msgid); + if (stringsResources.get(msgid) == null) { + stringsResources.put(msgid, new LinkedList()); + } + stringsResources.get(msgid).add(res); + } + } + } + } + + public void compare() { + for (String oldRes : resourcesStringsOld.keySet()) { + String newString = resourcesStringsNew.get(oldRes); + String oldString = resourcesStringsOld.get(oldRes); + if (newString != null) { + if (!newString.equals(oldString)) { + List allOldResources = stringsResourcesOld.get(oldString); + List allNewResources = stringsResourcesNew.get(oldString); + System.out.println("---------------------------------------------"); + System.out.println("--- TYPO CHECK ------------------------------"); + System.out.println("---------------------------------------------"); + System.out.println("String at: "+oldRes); + if (allOldResources.size() > 1) { + System.out.println("Also present at:"); + for (String res : allOldResources) { + if (!res.equals(oldRes)) { + System.out.println("- "+res); + } + } + } + if (allNewResources != null) { + System.out.println("Still present at: "); + for (String res : allNewResources) { + System.out.println("- "+res); + } + } + System.out.println("Was : \""+oldString+"\""); + System.out.println("Now : \""+newString+"\""); + + } + } else { + List allOldResources = stringsResourcesOld.get(oldString); + List allNewResources = stringsResourcesNew.get(oldString); + if (allOldResources.size() >= 1) { + System.out.println("---------------------------------------------"); + System.out.println("--- REMOVED RESOURCE ------------------------"); + System.out.println("---------------------------------------------"); + System.out.println("String at: "+oldRes); + if (allOldResources.size() > 1) { + System.out.println("And also at:"); + for (String res : allOldResources) { + if (!res.equals(oldRes)) { + System.out.println("- "+res); + } + } + } + System.out.println("Was: \""+oldString+"\""); + if (allNewResources == null) { + System.out.println("Absent from new."); + } else { + System.out.println("Still present at: "); + for (String res : allNewResources) { + System.out.println("- "+res); + } + + } + } + } + } + removedStrings: for (String oldString : stringsResourcesOld.keySet()) { + if (stringsResourcesNew.get(oldString) == null) { + List allOldResources = stringsResourcesOld.get(oldString); + if (allOldResources.size() >= 1) { + if (allOldResources.size() > 0) { + for (String res : allOldResources) { + String newString = resourcesStringsNew.get(res); + if (newString != null) { + continue removedStrings; + } + } + } + System.out.println("---------------------------------------------"); + System.out.println("--- REMOVED STRING --------------------------"); + System.out.println("---------------------------------------------"); + System.out.println("String: \""+oldString+"\""); + if (allOldResources.size() > 0) { + System.out.println("Was at:"); + for (String res : allOldResources) { + System.out.println("- "+res); + } + } + System.out.println("This string is absent from the new file, and its attached resources are missing too."); + } + } + } + } + +} diff --git a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java b/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java new file mode 100644 index 0000000..14b5db6 --- /dev/null +++ b/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java @@ -0,0 +1,114 @@ +package com.gpl.rpg.atcontentstudio.ui.tools.i18n; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import com.gpl.rpg.atcontentstudio.model.GameSource; +import com.gpl.rpg.atcontentstudio.model.Project; +import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition; +import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue; +import com.gpl.rpg.atcontentstudio.model.gamedata.Item; +import com.gpl.rpg.atcontentstudio.model.gamedata.ItemCategory; +import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement; +import com.gpl.rpg.atcontentstudio.model.gamedata.NPC; +import com.gpl.rpg.atcontentstudio.model.gamedata.Quest; +import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage; +import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment; + +public class PotGenerator { + + public static void generatePotFileForProject(Project proj) { + Map> stringsResources = new LinkedHashMap>(); + Map resourcesStrings = new LinkedHashMap(); + + GameSource gsrc = proj.baseContent; + + for (ActorCondition ac : gsrc.gameData.actorConditions) { + pushString(stringsResources, resourcesStrings, ac.display_name, getPotContextComment(ac)); + } + + for (Dialogue d : gsrc.gameData.dialogues ) { + pushString(stringsResources, resourcesStrings, d.message, getPotContextComment(d)); + if (d.replies == null) continue; + for (Dialogue.Reply r : d.replies) { + if (r.text != null && !r.text.equals(Dialogue.Reply.GO_NEXT_TEXT) ) { + pushString(stringsResources, resourcesStrings, r.text, getPotContextComment(d)+":"+d.replies.indexOf(r)); + } + } + } + + for (ItemCategory ic : gsrc.gameData.itemCategories) { + pushString(stringsResources, resourcesStrings, ic.name, getPotContextComment(ic)); + } + + for (Item i : gsrc.gameData.items) { + pushString(stringsResources, resourcesStrings, i.name, getPotContextComment(i)); + pushString(stringsResources, resourcesStrings, i.description, getPotContextComment(i)+":description"); + } + + for (NPC npc : gsrc.gameData.npcs ) { + pushString(stringsResources, resourcesStrings, npc.name, getPotContextComment(npc)); + } + + for (Quest q : gsrc.gameData.quests) { + pushString(stringsResources, resourcesStrings, q.name, getPotContextComment(q)); + for (QuestStage qs : q.stages) { + pushString(stringsResources, resourcesStrings, qs.log_text, getPotContextComment(q)+":"+Integer.toString(qs.progress)); + } + } + + for (WorldmapSegment ws : gsrc.worldmap) { + for (WorldmapSegment.NamedArea area : ws.labels.values()) { + pushString(stringsResources, resourcesStrings, area.name, gsrc.worldmap.worldmapFile.getName()+":"+ws.id+":"+area.id); + } + } + + File f = new File(proj.alteredContent.baseFolder, "english.pot"); + try { + FileWriter fw = new FileWriter(f); + for (String msg : stringsResources.keySet()) { + for (String ctx : stringsResources.get(msg)) { + fw.write("#: "); + fw.write(ctx); + fw.write("\n"); + } + fw.write("msgid \""); + fw.write(msg); + fw.write("\"\nmsgstr \"\"\n\n"); + + } + fw.flush(); + fw.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + private static void pushString (Map> stringsResources, Map resourcesStrings, String translatableString, String resourceIdentifier) { + if (translatableString == null) return; + if (translatableString.contains("\n")) { + translatableString = translatableString.replaceAll("\n", "\\\\n\"\n\""); + translatableString = "\"\n\""+translatableString; + } + resourcesStrings.put(resourceIdentifier, translatableString); + List resourceIdentifiers = stringsResources.get(translatableString); + if (resourceIdentifiers == null) { + resourceIdentifiers = new LinkedList(); + stringsResources.put(translatableString, resourceIdentifiers); + } + resourceIdentifiers.add(resourceIdentifier); + } + + private static String getPotContextComment(JSONElement e) { + return e.jsonFile.getName()+":"+e.id; + } + + +} diff --git a/src/net/launchpad/tobal/poparser/POEntry.java b/src/net/launchpad/tobal/poparser/POEntry.java new file mode 100644 index 0000000..140c0cc --- /dev/null +++ b/src/net/launchpad/tobal/poparser/POEntry.java @@ -0,0 +1,100 @@ +/** + * + * @author BalĂĄzs TĂłth (tobal17@gmail.com) + * + * Modified by Kevin POCHAT for ATCS + */ +package net.launchpad.tobal.poparser; + +import java.util.Vector; + +public class POEntry +{ + private POLine[] Lines; + + public enum StringType + { + /**translator comments*/ + TRLCMNT, + /**extracted comments*/ + EXTCMNT, + /**reference*/ + REFERENCE, + /**flag*/ + FLAG, + /**previous context*/ + PREVCTXT, + /**previous untranslated string singular*/ + PREVUNTRSTRSING, + /**previous untranslated string plural*/ + PREVUNTRSTRPLUR, + /**untranslated string singular*/ + MSGID, + /**translated string*/ + MSGSTR, + /**context*/ + MSGCTXT, + /**header line*/ + HEADER + + // TODO: support for plural untranslated strings, + // and translated string cases + } + + POEntry() + { + Lines = new POLine[0]; + } + + public void addLine(StringType type, String string) + { + boolean hasType = false; + POLine line = null; + for(int i = 0; i < Lines.length; i++) + { + if(Lines[i].getType() == type) + { + hasType = true; + line = Lines[i]; + break; + } + } + if(hasType) + { + line.addString(string); + } + else + { + line = new POLine(type, string); + POLine[] templines = Lines.clone(); + Lines = new POLine[Lines.length+1]; + for(int i = 0; i < Lines.length-1; i++) + { + Lines[i] = templines[i]; + } + Lines[Lines.length-1] = line; + } + } + + public POLine[] getLines() + { + return Lines; + } + + public Vector getStringsFromLine(int index) + { + return Lines[index].getStrings(); + } + + public Vector getStringsByType(POEntry.StringType type) + { + for(int i = 0; i < Lines.length; i++) + { + if(Lines[i].getType() == type) + { + return Lines[i].getStrings(); + } + } + return null; + } +} diff --git a/src/net/launchpad/tobal/poparser/POFile.java b/src/net/launchpad/tobal/poparser/POFile.java new file mode 100644 index 0000000..d55a4d1 --- /dev/null +++ b/src/net/launchpad/tobal/poparser/POFile.java @@ -0,0 +1,139 @@ +/** + * + * @author BalĂĄzs TĂłth (tobal17@gmail.com) + * + * Modified by Kevin POCHAT for ATCS + */ +package net.launchpad.tobal.poparser; + +import java.io.File; +import java.util.Vector; + +public class POFile +{ + private POEntry[] entries; + private POEntry header; + private File file; + + POFile(POEntry[] entries, POEntry header, File file) + { + this.entries = entries; + this.header = header; + this.file = file; + } + + /** + * Returns with the name of the po file + * @return name of po file + */ + public String getFileName() + { + return file == null ? null : file.getAbsolutePath(); + } + + /** + * Returns with the POEntry object array + * @return POEntry array + */ + public POEntry[] getEntryArray() + { + return entries; + } + + /** + * Gets the POEntry object specified by the index + * @param index, index of the entry + * @return one POEntry object + */ + public POEntry getEntry(int index) + { + return entries[index]; + } + + /** + * Returns how many entries are there in the po file + * @return count of entries + */ + public int getEntryLength() + { + return entries.length; + } + + /** + * Checks if the specified flag is set in the entry, + * given by the entry index. + * @param flag, string representing the flag + * @param entryIndex, index of the entry to examine + * @return true, if the flag is set, false otherwise + */ + public boolean checkFlag(String flag, int entryIndex) + { + boolean status = false; + Vector strings = new Vector(); + strings = entries[entryIndex].getStringsByType(POEntry.StringType.FLAG); + if (strings != null) + { + for(int i = 0; i < strings.size(); i++) + { + if (strings.get(i).contains(flag)) + { + status = true; + } + } + } + return status; + } + + /** + * Returns with all the strings of the given type, from + * the specified entry. + * @param entryIndex + * @param type + * @return String array of specified type + */ + public String[] getStringsFromEntryByType(int entryIndex, POEntry.StringType type) + { + Vector vector = entries[entryIndex].getStringsByType(type); + String[] str = new String[vector.size()]; + for(int i = 0; i < str.length; i++) + { + str[i] = vector.get(i); + } + return str; + } + + /** + * For debug purposes + */ + public void printFile() + { + for(int i = 0; i < entries.length; i++) + { + POLine[] lines = entries[i].getLines(); + for(int j = 0; j < lines.length; j++) + { + Vector strings = lines[j].getStrings(); + for(int k = 0; k < strings.size(); k++) + { + System.out.println(strings.get(k)); + } + } + } + } + + /** + * For debug purposes + */ + public void printHeader() + { + POLine[] lines = header.getLines(); + for(int j = 0; j < lines.length; j++) + { + Vector strings = lines[j].getStrings(); + for(int k = 0; k < strings.size(); k++) + { + System.out.println(strings.get(k)); + } + } + } +} diff --git a/src/net/launchpad/tobal/poparser/POLine.java b/src/net/launchpad/tobal/poparser/POLine.java new file mode 100644 index 0000000..59b0f8d --- /dev/null +++ b/src/net/launchpad/tobal/poparser/POLine.java @@ -0,0 +1,42 @@ +/** + * + * @author BalĂĄzs TĂłth (tobal17@gmail.com) + * + * Modified by Kevin POCHAT for ATCS + */ +package net.launchpad.tobal.poparser; + +import java.util.Vector; + +public class POLine +{ + private POEntry.StringType type; + private Vector strings; + + POLine(POEntry.StringType type, String string) + { + this.type = type; + this.strings = new Vector(); + this.strings.add(string); + } + + public void addString(String string) + { + strings.add(string); + } + + public Vector getStrings() + { + return strings; + } + + public POEntry.StringType getType() + { + return type; + } + + public int getVectorSize() + { + return strings.size(); + } +} \ No newline at end of file diff --git a/src/net/launchpad/tobal/poparser/POParser.java b/src/net/launchpad/tobal/poparser/POParser.java new file mode 100644 index 0000000..b516231 --- /dev/null +++ b/src/net/launchpad/tobal/poparser/POParser.java @@ -0,0 +1,275 @@ +/** + * + * @author BalĂĄzs TĂłth (tobal17@gmail.com) + * + * Based on the work of IstvĂĄn Nyitrai + * + * Modified by Kevin POCHAT for ATCS + */ +package net.launchpad.tobal.poparser; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.io.BufferedReader; +import java.util.Vector; + +public class POParser +{ + private POEntry[] entries; + private POEntry header; +// private File file; + private POEntry.StringType parserMode; + + /** + * Creates a POParser object. Use getPOFile() method, + * to access parsed data. + * @param file, File object of the PO file + */ + public POParser() + { + parserMode = null; + } + + public POFile parseFile(File file) + { + return parse(file); + } + + public POFile parseStream(BufferedReader br) throws IOException { + return parse(br); + } + + private String unQuote(String string) + { + String str = new String(); + if(string.startsWith("\"")) + { + str = string.substring(1); + string = str; + } + if(string.endsWith("\"")) + { + str = string.substring(0, string.length()-1); + } + return str; + } + + private POFile parse(File file) + { + POFile result = null; + try + { + FileReader fr = new FileReader(file); + BufferedReader br = new BufferedReader(fr); + result = parse(br); + br.close(); + fr.close(); + } + catch (java.io.FileNotFoundException e) + { + System.out.println(e.toString()); + } + catch (java.io.IOException e) { + System.out.println(e.toString()); + } + + return result; + } + + private POFile parse(BufferedReader br) throws IOException { + Vector rawentry = new Vector(1, 1); + Vector> rawentries = new Vector>(); + String line; + int id = 0; + while((line = br.readLine()) != null) + { + if(!line.equals("")) + { + if(!line.startsWith("#~")) // ignore + { + rawentry.add(line); + } + } + else + { + if(rawentry.size() > 0) + { + rawentry.add(0, String.valueOf(id)); + id++; + rawentries.add(new Vector(rawentry)); + rawentry = new Vector(1, 1); + } + } + } + + if(!rawentry.equals(rawentries.lastElement()) && rawentry.size() > 0) + { + rawentry.add(0, String.valueOf(id)); + rawentries.add(new Vector(rawentry)); + } + this.header = parseHeader(rawentries); + this.entries = parseEntries(rawentries); + + return new POFile(entries, header, null); + } + + private POEntry parseHeader(Vector> vectors) + { + POEntry tempheader = new POEntry(); + + // is this header? + Vector rawentry = vectors.get(0); + if(new Integer(rawentry.get(0)) == 0 && rawentry.contains("msgid \"\"")) + { + for(int i = 1; i < rawentry.size(); i++) + { + String str = rawentry.get(i); + tempheader.addLine(POEntry.StringType.HEADER, str); + str = new String(); + } + return tempheader; + } + else + { + return null; + } + } + + private POEntry[] parseEntries(Vector> vectors) + { + String line = new String(); + boolean thereIsHeader = false; + + // is this header + Vector rawentry = vectors.get(0); + if(new Integer(rawentry.get(0)) == 0 && rawentry.contains("msgid \"\"")) + { + thereIsHeader = true; + } + + int size; + if(thereIsHeader) + { + size = vectors.size()-1; + } + else + { + size = vectors.size(); + } + + POEntry[] tempentries = new POEntry[size]; + + for(int i = 0; i < size; i++) + { + POEntry entry = new POEntry(); + + if(thereIsHeader) + rawentry = vectors.get(i+1); + else + rawentry = vectors.get(i); + + rawentry.remove(0); + for(int j = 0; j < rawentry.size(); j++) + { + line = rawentry.get(j); + POEntry.StringType strType = null; + int subStrIndex = 0; + if(line.startsWith("#")) + { + parserMode = null; + if(line.startsWith("# ")) + { + strType = POEntry.StringType.TRLCMNT; + if (line.startsWith("# ")) + { + subStrIndex = 3; + } + else + { + subStrIndex = 2; + } + } + if(line.startsWith("#.")) + { + strType = POEntry.StringType.EXTCMNT; + subStrIndex = 3; + } + if(line.startsWith("#:")) + { + strType = POEntry.StringType.REFERENCE; + subStrIndex = 3; + } + if(line.startsWith("#,")) + { + strType = POEntry.StringType.FLAG; + subStrIndex = 3; + } + if(line.startsWith("#|")) + { + // TODO: can these comments be multi line? if no, + // drop support for it + if(line.startsWith("#| msgctxt ")) + { + strType = POEntry.StringType.PREVCTXT; + parserMode = strType; + subStrIndex = 11; + } + if(line.startsWith("#| msgid ")) + { + strType = POEntry.StringType.PREVUNTRSTRSING; + parserMode = strType; + subStrIndex = 9; + } + if(line.startsWith("#| msgid_plural ")) + { + strType = POEntry.StringType.PREVUNTRSTRPLUR; + parserMode = strType; + subStrIndex = 16; + } + } + String str = new String(); + str = line.substring(subStrIndex); + entry.addLine(strType, str); + } + else if(line.startsWith("msg")) + { + parserMode = null; + if(line.startsWith("msgctxt ")) + { + strType = POEntry.StringType.MSGCTXT; + parserMode = strType; + subStrIndex = 8; + } + if(line.startsWith("msgid ")) + { + strType = POEntry.StringType.MSGID; + parserMode = strType; + subStrIndex = 6; + } + if(line.startsWith("msgstr ")) + { + strType = POEntry.StringType.MSGSTR; + parserMode = strType; + subStrIndex = 7; + } + String str = new String(); + // TODO: is unquoting nessessary? + str = unQuote(line.substring(subStrIndex)); + entry.addLine(strType, str); + } + else + { + if(parserMode != null) + { + entry.addLine(parserMode, unQuote(line)); + } + } + } + tempentries[i] = entry; + } + + return tempentries; + } +} diff --git a/src/net/launchpad/tobal/poparser/ParserTest.java b/src/net/launchpad/tobal/poparser/ParserTest.java new file mode 100644 index 0000000..5964aab --- /dev/null +++ b/src/net/launchpad/tobal/poparser/ParserTest.java @@ -0,0 +1,24 @@ +/** + * @author BalĂĄzs TĂłth (tobal17@gmail.com) + * + * Modified by Kevin POCHAT for ATCS + */ +package net.launchpad.tobal.poparser; + +import java.io.File; + +public class ParserTest +{ + public static void main(String args[]) + { + File file = new File("C:\\file.po"); + POParser parser = new POParser(); + POFile po = parser.parseFile(file); + po.printHeader(); + po.printFile(); + // is the 3th entry fuzzy? + boolean fuzzy = po.checkFlag("fuzzy", 3); + // give me the msgid of the 4th entry + String[] str = po.getStringsFromEntryByType(4, POEntry.StringType.MSGID); + } +} From e0425e335dd2860b7a5d3f58586cde4658a98886 Mon Sep 17 00:00:00 2001 From: Jiri Zizkin Zizka Date: Wed, 29 Aug 2018 20:33:37 +0200 Subject: [PATCH 30/42] Bugfix: Add missing listener in WorkspaceSettingsEditor for more intuitive behaviour of translator mode --- .../rpg/atcontentstudio/ui/WorkspaceSettingsEditor.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceSettingsEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceSettingsEditor.java index 0172366..95c7ce5 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceSettingsEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceSettingsEditor.java @@ -182,12 +182,19 @@ public class WorkspaceSettingsEditor extends JDialog { useInternetBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - translatorLanguagesBox.setEnabled(useInternetBox.isSelected()); + translatorLanguagesBox.setEnabled(useInternetBox.isSelected() && translatorModeBox.isSelected()); translatorModeBox.setEnabled(useInternetBox.isSelected()); checkUpdatesBox.setEnabled(useInternetBox.isSelected()); } }); + translatorModeBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + translatorLanguagesBox.setEnabled(translatorModeBox.isSelected()); + } + }); + return pane; } From f95327bd129aa22091bb1fa55d39e45d72a78021 Mon Sep 17 00:00:00 2001 From: Jiri Zizkin Zizka Date: Wed, 29 Aug 2018 20:45:47 +0200 Subject: [PATCH 31/42] Show translated text from Weblate in DialogueGraphView --- .../ui/gamedataeditors/dialoguetree/DialogueGraphView.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java index 52fbe53..6ae892b 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java @@ -49,11 +49,13 @@ import prefuse.visual.expression.InGroupPredicate; import com.gpl.rpg.atcontentstudio.ATContentStudio; import com.gpl.rpg.atcontentstudio.model.GameDataElement; +import com.gpl.rpg.atcontentstudio.model.Workspace; import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue; import com.gpl.rpg.atcontentstudio.model.gamedata.NPC; import com.gpl.rpg.atcontentstudio.model.gamedata.Requirement; import com.gpl.rpg.atcontentstudio.ui.DefaultIcons; import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.DialogueEditor; +import com.gpl.rpg.atcontentstudio.utils.WeblateIntegration; import com.jidesoft.swing.JideBoxLayout; public class DialogueGraphView extends Display { @@ -188,7 +190,7 @@ public class DialogueGraphView extends Display { } Node dNode = graph.addNode(); cells.put(dialogue, dNode); - dNode.setString(LABEL, dialogue.message != null ? dialogue.message : "[Selector]"); + dNode.setString(LABEL, dialogue.message == null ? "[Selector]" : Workspace.activeWorkspace.settings.translatorLanguage.getCurrentValue() == null ? dialogue.message : dialogue.message + "\n---\n" + WeblateIntegration.getTranslationUnit(dialogue.message).translatedText); dNode.set(ICON, npcIcon); dNode.set(TARGET, dialogue); if (dialogue.replies != null) { @@ -210,7 +212,7 @@ public class DialogueGraphView extends Display { if (r.text != null && !r.text.equals(Dialogue.Reply.GO_NEXT_TEXT)) { //Normal reply... rNode = graph.addNode(); - rNode.setString(LABEL, r.text); + rNode.setString(LABEL, Workspace.activeWorkspace.settings.translatorLanguage.getCurrentValue() == null ? r.text : r.text + "\n---\n" + WeblateIntegration.getTranslationUnit(r.text).translatedText); rNode.set(ICON, DefaultIcons.getHeroIcon()); rNode.set(TARGET, d); rNode.set(REPLY, r); From d1612269c09bdaf31127e26b4fcc954a58ca769a Mon Sep 17 00:00:00 2001 From: Jiri Zizkin Zizka Date: Thu, 6 Sep 2018 16:12:58 +0200 Subject: [PATCH 32/42] Update to translation in DialogueGraphView --- .../ui/gamedataeditors/dialoguetree/DialogueGraphView.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java index 6ae892b..2cadd76 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java @@ -79,6 +79,7 @@ public class DialogueGraphView extends Display { private Dialogue dialogue; private Image npcIcon; private Graph graph; + private Boolean translatorMode; private Map cells = new HashMap(); @@ -90,6 +91,7 @@ public class DialogueGraphView extends Display { } else { npcIcon = DefaultIcons.getNPCIcon(); } + translatorMode = Workspace.activeWorkspace.settings.useInternet.getCurrentValue() && Workspace.activeWorkspace.settings.translatorLanguage.getCurrentValue() != null; loadGraph(); // add visual data groups @@ -190,7 +192,7 @@ public class DialogueGraphView extends Display { } Node dNode = graph.addNode(); cells.put(dialogue, dNode); - dNode.setString(LABEL, dialogue.message == null ? "[Selector]" : Workspace.activeWorkspace.settings.translatorLanguage.getCurrentValue() == null ? dialogue.message : dialogue.message + "\n---\n" + WeblateIntegration.getTranslationUnit(dialogue.message).translatedText); + dNode.setString(LABEL, dialogue.message == null ? "[Selector]" : !translatorMode ? dialogue.message : dialogue.message + "\n---\n" + WeblateIntegration.getTranslationUnit(dialogue.message).translatedText); dNode.set(ICON, npcIcon); dNode.set(TARGET, dialogue); if (dialogue.replies != null) { @@ -212,7 +214,7 @@ public class DialogueGraphView extends Display { if (r.text != null && !r.text.equals(Dialogue.Reply.GO_NEXT_TEXT)) { //Normal reply... rNode = graph.addNode(); - rNode.setString(LABEL, Workspace.activeWorkspace.settings.translatorLanguage.getCurrentValue() == null ? r.text : r.text + "\n---\n" + WeblateIntegration.getTranslationUnit(r.text).translatedText); + rNode.setString(LABEL, !translatorMode ? r.text : r.text + "\n---\n" + WeblateIntegration.getTranslationUnit(r.text).translatedText); rNode.set(ICON, DefaultIcons.getHeroIcon()); rNode.set(TARGET, d); rNode.set(REPLY, r); From 67b8acd20b9bb3a573d289d93b8d481b09173210 Mon Sep 17 00:00:00 2001 From: Jiri Zizkin Zizka Date: Thu, 6 Sep 2018 22:16:33 +0200 Subject: [PATCH 33/42] Code more human readable --- .../ui/gamedataeditors/dialoguetree/DialogueGraphView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java index 2cadd76..80658a6 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java @@ -192,7 +192,7 @@ public class DialogueGraphView extends Display { } Node dNode = graph.addNode(); cells.put(dialogue, dNode); - dNode.setString(LABEL, dialogue.message == null ? "[Selector]" : !translatorMode ? dialogue.message : dialogue.message + "\n---\n" + WeblateIntegration.getTranslationUnit(dialogue.message).translatedText); + dNode.setString(LABEL, dialogue.message == null ? "[Selector]" : translatorMode ? dialogue.message + "\n---\n" + WeblateIntegration.getTranslationUnit(dialogue.message).translatedText : dialogue.message); dNode.set(ICON, npcIcon); dNode.set(TARGET, dialogue); if (dialogue.replies != null) { @@ -214,7 +214,7 @@ public class DialogueGraphView extends Display { if (r.text != null && !r.text.equals(Dialogue.Reply.GO_NEXT_TEXT)) { //Normal reply... rNode = graph.addNode(); - rNode.setString(LABEL, !translatorMode ? r.text : r.text + "\n---\n" + WeblateIntegration.getTranslationUnit(r.text).translatedText); + rNode.setString(LABEL, translatorMode ? r.text + "\n---\n" + WeblateIntegration.getTranslationUnit(r.text).translatedText : r.text); rNode.set(ICON, DefaultIcons.getHeroIcon()); rNode.set(TARGET, d); rNode.set(REPLY, r); From 3e8d578474ad01b47a788d8eb73cb44a3c69f306 Mon Sep 17 00:00:00 2001 From: Zukero Date: Sat, 8 Sep 2018 15:37:29 +0200 Subject: [PATCH 34/42] Enhanced translation-related tools. No UI, because there's limited interest for typical users, so it's a beanshell-only tool for now. --- .../model/WorkspaceSettings.java | 2 +- .../rpg/atcontentstudio/ui/AboutEditor.java | 1 + .../ui/tools/i18n/PoPotWriter.java | 86 +++++++++ .../ui/tools/i18n/PotComparator.java | 180 ++++++++++++++++-- .../ui/tools/i18n/PotGenerator.java | 23 +-- src/net/launchpad/tobal/poparser/POFile.java | 4 + .../launchpad/tobal/poparser/POParser.java | 3 +- 7 files changed, 263 insertions(+), 36 deletions(-) create mode 100644 src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PoPotWriter.java diff --git a/src/com/gpl/rpg/atcontentstudio/model/WorkspaceSettings.java b/src/com/gpl/rpg/atcontentstudio/model/WorkspaceSettings.java index 79ce879..3072542 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/WorkspaceSettings.java +++ b/src/com/gpl/rpg/atcontentstudio/model/WorkspaceSettings.java @@ -38,7 +38,7 @@ public class WorkspaceSettings { public static String DEFAULT_IMG_EDITOR_COMMAND = "gimp"; public Setting imageEditorCommand = new PrimitiveSetting("imageEditorCommand", DEFAULT_IMG_EDITOR_COMMAND); - public static String[] LANGUAGE_LIST = new String[]{null, "de", "ru", "pl", "fr", "it", "es", "nl", "uk", "ca", "sv", "pt", "pt_BR", "zh_Hant", "zh_Hans", "ja", "cs", "tr", "ko", "hu", "sl", "bg", "id", "fi", "th", "gl", "ms" ,"pa", "az"}; + public static String[] LANGUAGE_LIST = new String[]{null, "de", "ru", "pl", "fr", "it", "es", "nl", "uk", "ca", "sv", "pt", "pt_BR", "zh_Hant", "zh_Hans", "ja", "cs", "tr", "ko", "hu", "sl", "bg", "id", "fi", "th", "gl", "ms" ,"pa", "az", "nb"}; public Setting translatorLanguage = new NullDefaultPrimitiveSetting("translatorLanguage"); public static Boolean DEFAULT_ALLOW_INTERNET = true; public Setting useInternet = new PrimitiveSetting("useInternet", DEFAULT_ALLOW_INTERNET); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java index 4401e45..fef267c 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java @@ -132,6 +132,7 @@ public class AboutEditor extends Editor { editorTabsHolder.add("BeanShell License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.LGPLv3.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text")); editorTabsHolder.add("SipHash for Java License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.siphash-zackehh.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text")); editorTabsHolder.add("jsoup License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.jsoup.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text")); + editorTabsHolder.add("General PO Parser License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.GPLv3.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text")); editorTabsHolder.add("ATCS License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.GPLv3.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text")); } diff --git a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PoPotWriter.java b/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PoPotWriter.java new file mode 100644 index 0000000..507f0a4 --- /dev/null +++ b/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PoPotWriter.java @@ -0,0 +1,86 @@ +package com.gpl.rpg.atcontentstudio.ui.tools.i18n; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class PoPotWriter { + + Map> stringsResources = new LinkedHashMap>(); + Map translations = new LinkedHashMap(); + File f; + + public static void writePoFile(Map> stringsResources, Map translations, File destination) { + try { + FileWriter fw = new FileWriter(destination); + if (translations.get("") != null) { + fw.write(translations.get("")); + writeEndOfEntry(fw); + } + if (translations.get("translator-credits") != null) { + List refs = new LinkedList(); + refs.add("[none]"); + writeReferences(fw, refs); + writeMsgId(fw, "translator-credits"); + writeMsgStr(fw, translations.get("translator-credits")); + writeEndOfEntry(fw); + } + for (String msg : stringsResources.keySet()) { + writeReferences(fw, stringsResources.get(msg)); + writeMsgId(fw, msg); + writeMsgStr(fw, translations.get(msg)); + writeEndOfEntry(fw); + } + fw.flush(); + fw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void writePotFile(Map> stringsResources, File destination) { + try { + FileWriter fw = new FileWriter(destination); + for (String msg : stringsResources.keySet()) { + writeReferences(fw, stringsResources.get(msg)); + writeMsgId(fw, msg); + writeMsgStr(fw, ""); + writeEndOfEntry(fw); + } + fw.flush(); + fw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static void writeReferences(Writer w, List references) throws IOException { + for (String ref : references) { + w.write("#: "); + w.write(ref); + w.write("\n"); + } + } + + private static void writeMsgId(Writer w, String msg) throws IOException { + w.write("msgid \""); + w.write(msg); + w.write("\"\n"); + } + + private static void writeMsgStr(Writer w, String translation) throws IOException { + w.write("msgstr \""); + w.write(translation == null ? "" : translation); + w.write("\"\n"); + } + + private static void writeEndOfEntry(Writer w) throws IOException { + w.write("\n"); + } + +} diff --git a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotComparator.java b/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotComparator.java index f326769..3702545 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotComparator.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotComparator.java @@ -1,18 +1,42 @@ package com.gpl.rpg.atcontentstudio.ui.tools.i18n; import java.io.File; +import java.io.FileFilter; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Vector; +import javax.swing.JOptionPane; + import com.gpl.rpg.atcontentstudio.model.Project; import net.launchpad.tobal.poparser.POEntry; import net.launchpad.tobal.poparser.POFile; import net.launchpad.tobal.poparser.POParser; + +/** + * + * @author Kevin + * + * To use this, paste the following script in the beanshell console of ATCS. + * Don't forget to change the project number to suit your needs. + * + * import com.gpl.rpg.atcontentstudio.model.Workspace; + * import com.gpl.rpg.atcontentstudio.ui.tools.i18n.PotGenerator; + * import com.gpl.rpg.atcontentstudio.ui.tools.i18n.PotComparator; + * + * proj = Workspace.activeWorkspace.projects.get(7); + * PotGenerator.generatePotFileForProject(proj); + * comp = new PotComparator(proj); + * comp.compare(); + * comp.updatePoFiles(proj); + * + * + * + */ public class PotComparator { Map> stringsResourcesNew = new LinkedHashMap>(); @@ -20,6 +44,10 @@ public class PotComparator { Map> stringsResourcesOld = new LinkedHashMap>(); Map resourcesStringsOld = new LinkedHashMap(); + + Map msgIdToReplace = new LinkedHashMap(); + List msgIdToReview = new LinkedList(); + List msgIdOutdated = new LinkedList(); public PotComparator(Project proj) { @@ -47,10 +75,13 @@ public class PotComparator { String msgid = msgids.get(0); if (msgids.size() > 1) { for (int i = 1; i < msgids.size(); i++) { - msgid += "\n"; msgid += msgids.get(i); } } + if (msgid.contains("\\n")) { + msgid = msgid.replaceAll("\\\\n", "\\\\n\"\n\""); + msgid = "\"\n\""+msgid; + } for (String resLine : resources) { String[] resArray = resLine.split(" "); for (String res : resArray) { @@ -72,27 +103,29 @@ public class PotComparator { if (!newString.equals(oldString)) { List allOldResources = stringsResourcesOld.get(oldString); List allNewResources = stringsResourcesNew.get(oldString); - System.out.println("---------------------------------------------"); - System.out.println("--- TYPO CHECK ------------------------------"); - System.out.println("---------------------------------------------"); - System.out.println("String at: "+oldRes); + StringBuffer sb = new StringBuffer(); + sb.append("---------------------------------------------\n"); + sb.append("--- TYPO CHECK ------------------------------\n"); + sb.append("---------------------------------------------\n"); + sb.append("String at: "+oldRes+"\n"); if (allOldResources.size() > 1) { - System.out.println("Also present at:"); + sb.append("Also present at:\n"); for (String res : allOldResources) { if (!res.equals(oldRes)) { - System.out.println("- "+res); + sb.append("- "+res+"\n"); } } } if (allNewResources != null) { - System.out.println("Still present at: "); + sb.append("Still present at: \n"); for (String res : allNewResources) { - System.out.println("- "+res); + sb.append("- "+res+"\n"); } } - System.out.println("Was : \""+oldString+"\""); - System.out.println("Now : \""+newString+"\""); - + sb.append("Was : \""+oldString+"\"\n"); + sb.append("Now : \""+newString+"\"\n"); + System.out.println(sb.toString()); + showTypoDialog(oldString, newString, sb.toString()); } } else { List allOldResources = stringsResourcesOld.get(oldString); @@ -151,4 +184,127 @@ public class PotComparator { } } + private void showTypoDialog(String oldMsg, String newMsg, String checkReport) { + String typo = "Typo"; + String review = "Review"; + String outdated = "Outdated"; + String none = "None"; + Object[] options = new Object[] {typo, review, outdated, none}; + + int result = JOptionPane.showOptionDialog(null, checkReport, "Choose action", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, typo); + + if (result < 0 || result >= options.length) { + System.out.println("No decision"); + return; + } + + System.out.println("Decision: "+options[result]); + + if (options[result] != none) { + msgIdToReplace.put(oldMsg, newMsg); + if (options[result] == review) { + msgIdToReview.add(newMsg); + } else if (options[result] == outdated) { + msgIdOutdated.add(newMsg); + } + } + + } + + + public void updatePoFiles(Project proj) { + File poFolder = new File(proj.baseContent.baseFolder.getAbsolutePath()+File.separator+"assets"+File.separator+"translation"); + File[] poFiles = poFolder.listFiles(new FileFilter() { + @Override + public boolean accept(File arg0) { + return arg0.isFile() && arg0.getName().endsWith(".po"); + } + }); + + for (File f : poFiles) { + updatePoFile(proj, f); + } + } + + private void updatePoFile(Project proj, File f) { + POParser parser = new POParser(); + POFile poFile = parser.parseFile(f); + + Map translations = new LinkedHashMap(); + + //Collect existing translations + if (poFile.getHeader() != null) { + Vector msgstrs = poFile.getHeader().getStringsByType(POEntry.StringType.HEADER); + String header = ""; + if (!msgstrs.isEmpty()) { + if (msgstrs.size() == 1) { + header = msgstrs.get(0); + } else { + for (String msgstr : msgstrs) { + header += msgstr; + header += "\n"; + } + } + } + translations.put("", header); + } + + for (POEntry entry : poFile.getEntryArray()) { + Vector msgids = entry.getStringsByType(POEntry.StringType.MSGID); + Vector msgstrs = entry.getStringsByType(POEntry.StringType.MSGSTR); + if (msgids == null || msgids.size() == 0) continue; + String msgid = msgids.get(0); + if (msgids.size() > 1) { + for (int i = 1; i < msgids.size(); i++) { + msgid += msgids.get(i); + } + } + if (msgid.contains("\\n")) { + msgid = msgid.replaceAll("\\\\n", "\\\\n\"\n\""); + msgid = "\"\n\""+msgid; + } + String translation = ""; + if (!msgstrs.isEmpty()) { + if (msgstrs.size() == 1) { + translation = msgstrs.get(0); + } else { + for (String msgstr : msgstrs) { + translation += msgstr; + } + } + if (translation.contains("\\n")) { + translation = translation.replaceAll("\\\\n", "\\\\n\"\n\""); + translation = "\"\n\""+translation; + } + } + translations.put(msgid, translation); + } + + //Patch data + for (String oldId : msgIdToReplace.keySet()) { + String newId = msgIdToReplace.get(oldId); + if (translations.containsKey(oldId)) { + String trans = translations.get(oldId); + translations.remove(oldId); + translations.put(newId, trans); + } + } + + for (String msgid : msgIdToReview) { + if (translations.containsKey(msgid)) { + String trans = translations.get(msgid); + if (trans != null && trans.length() >= 1) translations.put(msgid, "[REVIEW]"+trans); + } + } + + for (String msgid : msgIdOutdated) { + if (translations.containsKey(msgid)) { + String trans = translations.get(msgid); + if (trans != null && trans.length() >= 1) translations.put(msgid, "[OUTDATED]"+trans); + } + } + + PoPotWriter.writePoFile(stringsResourcesNew, translations, new File(proj.alteredContent.baseFolder.getAbsolutePath()+File.separator+f.getName())); + } + } diff --git a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java b/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java index 14b5db6..10cbbeb 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java @@ -1,8 +1,6 @@ package com.gpl.rpg.atcontentstudio.ui.tools.i18n; import java.io.File; -import java.io.FileWriter; -import java.io.IOException; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; @@ -69,30 +67,13 @@ public class PotGenerator { } File f = new File(proj.alteredContent.baseFolder, "english.pot"); - try { - FileWriter fw = new FileWriter(f); - for (String msg : stringsResources.keySet()) { - for (String ctx : stringsResources.get(msg)) { - fw.write("#: "); - fw.write(ctx); - fw.write("\n"); - } - fw.write("msgid \""); - fw.write(msg); - fw.write("\"\nmsgstr \"\"\n\n"); - - } - fw.flush(); - fw.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + PoPotWriter.writePotFile(stringsResources, f); } private static void pushString (Map> stringsResources, Map resourcesStrings, String translatableString, String resourceIdentifier) { if (translatableString == null) return; + if (translatableString.length() == 0) return; if (translatableString.contains("\n")) { translatableString = translatableString.replaceAll("\n", "\\\\n\"\n\""); translatableString = "\"\n\""+translatableString; diff --git a/src/net/launchpad/tobal/poparser/POFile.java b/src/net/launchpad/tobal/poparser/POFile.java index d55a4d1..919db09 100644 --- a/src/net/launchpad/tobal/poparser/POFile.java +++ b/src/net/launchpad/tobal/poparser/POFile.java @@ -58,6 +58,10 @@ public class POFile { return entries.length; } + + public POEntry getHeader() { + return header; + } /** * Checks if the specified flag is set in the entry, diff --git a/src/net/launchpad/tobal/poparser/POParser.java b/src/net/launchpad/tobal/poparser/POParser.java index b516231..ec315f1 100644 --- a/src/net/launchpad/tobal/poparser/POParser.java +++ b/src/net/launchpad/tobal/poparser/POParser.java @@ -8,11 +8,10 @@ */ package net.launchpad.tobal.poparser; +import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; -import java.io.Reader; -import java.io.BufferedReader; import java.util.Vector; public class POParser From f4041ee2c7fdb3910c48fd010d7917b34f9acf7d Mon Sep 17 00:00:00 2001 From: Jiri Zizkin Zizka Date: Mon, 10 Sep 2018 10:02:16 +0200 Subject: [PATCH 35/42] Add myself to contributors --- src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java index 4401e45..3e19105 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java @@ -51,6 +51,7 @@ public class AboutEditor extends Editor { "
" + "Contributors:
" + "Quentin Delvallet
" + + "Žižkin
" + "
" + "This project uses the following libraries:
" + "JSON.simple by Yidong Fang & Chris Nokleberg.
" + From bf42f86408de0f7563b89eeed78b8b8ed8f85ff6 Mon Sep 17 00:00:00 2001 From: Zukero Date: Thu, 13 Sep 2018 09:39:42 +0200 Subject: [PATCH 36/42] Made dialogue-tree translations loading asynchronous. Fixed quote escaping issue in english.pot generation tool. --- .../dialoguetree/DialogueGraphView.java | 49 +++++++++++++++++-- .../ui/tools/i18n/PotGenerator.java | 11 +++-- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java index 80658a6..4f2ee93 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java @@ -56,6 +56,7 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.Requirement; import com.gpl.rpg.atcontentstudio.ui.DefaultIcons; import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.DialogueEditor; import com.gpl.rpg.atcontentstudio.utils.WeblateIntegration; +import com.gpl.rpg.atcontentstudio.utils.WeblateIntegration.WeblateTranslationUnit; import com.jidesoft.swing.JideBoxLayout; public class DialogueGraphView extends Display { @@ -74,6 +75,10 @@ public class DialogueGraphView extends Display { public static final String HIDDEN_REPLY = "hidden_reply"; public static final String HAS_REQS = "has_reqs"; + private static final String TRANSLATION_LOADING="Loading translation..."; + private String translationHeader="\n---[ Translation from weblate ]---\n"; + + private static final Schema DECORATOR_SCHEMA = PrefuseLib.getVisualItemSchema(); private Dialogue dialogue; @@ -92,6 +97,9 @@ public class DialogueGraphView extends Display { npcIcon = DefaultIcons.getNPCIcon(); } translatorMode = Workspace.activeWorkspace.settings.useInternet.getCurrentValue() && Workspace.activeWorkspace.settings.translatorLanguage.getCurrentValue() != null; + if (translatorMode) { + translationHeader = "\n---[ Translation in "+Workspace.activeWorkspace.settings.translatorLanguage.getCurrentValue()+" ]---\n"; + } loadGraph(); // add visual data groups @@ -190,9 +198,26 @@ public class DialogueGraphView extends Display { if (dialogue.switch_to_npc != null) { npcIcon = dialogue.switch_to_npc.getIcon(); } - Node dNode = graph.addNode(); + final Node dNode = graph.addNode(); cells.put(dialogue, dNode); - dNode.setString(LABEL, dialogue.message == null ? "[Selector]" : translatorMode ? dialogue.message + "\n---\n" + WeblateIntegration.getTranslationUnit(dialogue.message).translatedText : dialogue.message); + String label; + Thread t = null; + if (dialogue.message == null) { + label = "[Selector]"; + } else if (translatorMode) { + label = dialogue.message+translationHeader+TRANSLATION_LOADING; + final String message = dialogue.message; + t = new Thread("Get weblate translation for "+message) { + public void run() { + WeblateTranslationUnit unit = WeblateIntegration.getTranslationUnit(message); + dNode.setString(LABEL, message+translationHeader+unit.translatedText); + }; + }; + } else { + label = dialogue.message; + } + dNode.setString(LABEL, label); + if (t != null) t.start(); dNode.set(ICON, npcIcon); dNode.set(TARGET, dialogue); if (dialogue.replies != null) { @@ -210,11 +235,27 @@ public class DialogueGraphView extends Display { } public Node addReply(Dialogue d, Dialogue.Reply r, Image npcIcon) { - Node rNode; + final Node rNode; if (r.text != null && !r.text.equals(Dialogue.Reply.GO_NEXT_TEXT)) { //Normal reply... rNode = graph.addNode(); - rNode.setString(LABEL, translatorMode ? r.text + "\n---\n" + WeblateIntegration.getTranslationUnit(r.text).translatedText : r.text); +// rNode.setString(LABEL, translatorMode ? r.text + "\n---\n" + WeblateIntegration.getTranslationUnit(r.text).translatedText : r.text); + String label; + Thread t = null; + if (translatorMode) { + label = r.text+translationHeader+TRANSLATION_LOADING; + final String message = r.text; + t = new Thread("Get weblate translation for "+message) { + public void run() { + WeblateTranslationUnit unit = WeblateIntegration.getTranslationUnit(message); + rNode.setString(LABEL, message+translationHeader+unit.translatedText); + }; + }; + } else { + label = dialogue.message; + } + rNode.setString(LABEL, label); + if (t != null) t.start(); rNode.set(ICON, DefaultIcons.getHeroIcon()); rNode.set(TARGET, d); rNode.set(REPLY, r); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java b/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java index 10cbbeb..00cf3fe 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java @@ -54,9 +54,11 @@ public class PotGenerator { } for (Quest q : gsrc.gameData.quests) { - pushString(stringsResources, resourcesStrings, q.name, getPotContextComment(q)); - for (QuestStage qs : q.stages) { - pushString(stringsResources, resourcesStrings, qs.log_text, getPotContextComment(q)+":"+Integer.toString(qs.progress)); + if (q.visible_in_log != null && q.visible_in_log != 0) { + pushString(stringsResources, resourcesStrings, q.name, getPotContextComment(q)); + for (QuestStage qs : q.stages) { + pushString(stringsResources, resourcesStrings, qs.log_text, getPotContextComment(q)+":"+Integer.toString(qs.progress)); + } } } @@ -74,6 +76,9 @@ public class PotGenerator { private static void pushString (Map> stringsResources, Map resourcesStrings, String translatableString, String resourceIdentifier) { if (translatableString == null) return; if (translatableString.length() == 0) return; + if (translatableString.contains("\"")) { + translatableString = translatableString.replaceAll("\"", "\\\\\""); + } if (translatableString.contains("\n")) { translatableString = translatableString.replaceAll("\n", "\\\\n\"\n\""); translatableString = "\"\n\""+translatableString; From 0a3da17d47e20bc95a054c0941d666ae90325ecb Mon Sep 17 00:00:00 2001 From: Zukero Date: Thu, 13 Sep 2018 13:34:04 +0200 Subject: [PATCH 37/42] First implementation of a bookmarks system. Not persistent yet, so you lose them all when you close ATCS. --- folderIconBase.xcf | Bin 57130 -> 60090 bytes .../atcontentstudio/img/bookmark_active.png | Bin 0 -> 2370 bytes .../atcontentstudio/img/bookmark_inactive.png | Bin 0 -> 3363 bytes .../img/folder_bookmark_closed.png | Bin 0 -> 2530 bytes .../img/folder_bookmark_open.png | Bin 0 -> 3418 bytes .../model/GameDataElement.java | 4 + .../rpg/atcontentstudio/model/Project.java | 11 + .../model/bookmarks/BookmarkEntry.java | 155 +++++++++++++ .../model/bookmarks/BookmarkFolder.java | 168 ++++++++++++++ .../model/bookmarks/BookmarkNode.java | 10 + .../model/bookmarks/BookmarksRoot.java | 210 ++++++++++++++++++ .../rpg/atcontentstudio/ui/DefaultIcons.java | 16 ++ .../gpl/rpg/atcontentstudio/ui/Editor.java | 2 +- .../rpg/atcontentstudio/ui/ProjectsTree.java | 3 + .../rpg/atcontentstudio/ui/StudioFrame.java | 2 + .../ui/gamedataeditors/JSONElementEditor.java | 17 ++ .../atcontentstudio/ui/map/TMXMapEditor.java | 28 +++ .../ui/map/WorldMapEditor.java | 14 ++ .../ui/sprites/SpritesheetEditor.java | 14 ++ 19 files changed, 653 insertions(+), 1 deletion(-) create mode 100644 src/com/gpl/rpg/atcontentstudio/img/bookmark_active.png create mode 100644 src/com/gpl/rpg/atcontentstudio/img/bookmark_inactive.png create mode 100644 src/com/gpl/rpg/atcontentstudio/img/folder_bookmark_closed.png create mode 100644 src/com/gpl/rpg/atcontentstudio/img/folder_bookmark_open.png create mode 100644 src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarkEntry.java create mode 100644 src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarkFolder.java create mode 100644 src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarkNode.java create mode 100644 src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarksRoot.java diff --git a/folderIconBase.xcf b/folderIconBase.xcf index 6ee67cf2c80c1b2c39ac3743195f75129cd6c83f..1a0a6c26f7b00842c1bd3e9001f769863558baa7 100644 GIT binary patch delta 3919 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 diff --git a/src/com/gpl/rpg/atcontentstudio/img/bookmark_active.png b/src/com/gpl/rpg/atcontentstudio/img/bookmark_active.png new file mode 100644 index 0000000000000000000000000000000000000000..4ad606cd0337dcf3ee4207b390775a30ad8bfc4d GIT binary patch literal 2370 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 literal 0 HcmV?d00001 diff --git a/src/com/gpl/rpg/atcontentstudio/img/folder_bookmark_closed.png b/src/com/gpl/rpg/atcontentstudio/img/folder_bookmark_closed.png new file mode 100644 index 0000000000000000000000000000000000000000..718313df84af4a5fe50d485da7ac287f2fcaec99 GIT binary patch literal 2530 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 literal 0 HcmV?d00001 diff --git a/src/com/gpl/rpg/atcontentstudio/model/GameDataElement.java b/src/com/gpl/rpg/atcontentstudio/model/GameDataElement.java index 534b715..5643f57 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/GameDataElement.java +++ b/src/com/gpl/rpg/atcontentstudio/model/GameDataElement.java @@ -11,6 +11,8 @@ import java.util.concurrent.ConcurrentHashMap; import javax.swing.tree.TreeNode; +import com.gpl.rpg.atcontentstudio.model.bookmarks.BookmarkEntry; + public abstract class GameDataElement implements ProjectTreeNode, Serializable { private static final long serialVersionUID = 2028934451226743389L; @@ -31,6 +33,8 @@ public abstract class GameDataElement implements ProjectTreeNode, Serializable { public boolean writable = false; + public BookmarkEntry bookmark = null; + //List of objects whose transition to "linked" state made them point to this instance. private Map backlinks = new ConcurrentHashMap(); diff --git a/src/com/gpl/rpg/atcontentstudio/model/Project.java b/src/com/gpl/rpg/atcontentstudio/model/Project.java index 31e4f61..e8182ca 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Project.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Project.java @@ -48,6 +48,7 @@ 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.bookmarks.BookmarksRoot; import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition; import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue; import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist; @@ -87,6 +88,8 @@ public class Project implements ProjectTreeNode, Serializable { public GameSource referencedContent; //Pointers to base content public transient GameSource alteredContent; //Copied from base content (does not overwrite yet) public transient GameSource createdContent; //Stand-alone. + public transient BookmarksRoot bookmarks; + public SavedGamesSet saves; //For simulations. @@ -135,6 +138,7 @@ public class Project implements ProjectTreeNode, Serializable { alteredContent = new GameSource(this, GameSource.Type.altered); createdContent = new GameSource(this, GameSource.Type.created); + bookmarks = new BookmarksRoot(this); saves = new SavedGamesSet(this); @@ -143,6 +147,7 @@ public class Project implements ProjectTreeNode, Serializable { // v.add(referencedContent); v.add(baseContent); v.add(saves); + v.add(bookmarks); linkAll(); @@ -262,6 +267,7 @@ public class Project implements ProjectTreeNode, Serializable { // referencedContent.refreshTransients(this); alteredContent = new GameSource(this, GameSource.Type.altered); createdContent = new GameSource(this, GameSource.Type.created); + bookmarks = new BookmarksRoot(this); saves.refreshTransients(); @@ -271,6 +277,7 @@ public class Project implements ProjectTreeNode, Serializable { // v.add(referencedContent); v.add(baseContent); v.add(saves); + v.add(bookmarks); linkAll(); @@ -970,6 +977,10 @@ public class Project implements ProjectTreeNode, Serializable { fireElementAdded(node, getNodeIndex(node)); } + public void bookmark(GameDataElement gde) { + bookmarks.addBookmark(gde); + } + @Override public GameDataSet getDataSet() { diff --git a/src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarkEntry.java b/src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarkEntry.java new file mode 100644 index 0000000..17f811d --- /dev/null +++ b/src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarkEntry.java @@ -0,0 +1,155 @@ +package com.gpl.rpg.atcontentstudio.model.bookmarks; + +import java.awt.Image; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import javax.swing.tree.TreeNode; + +import com.gpl.rpg.atcontentstudio.model.GameDataElement; +import com.gpl.rpg.atcontentstudio.model.GameSource.Type; +import com.gpl.rpg.atcontentstudio.model.Project; +import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode; +import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet; +import com.gpl.rpg.atcontentstudio.model.gamedata.Quest; +import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage; + +public class BookmarkEntry implements BookmarkNode { + + public GameDataElement bookmarkedElement; + public BookmarkFolder parent; + + public BookmarkEntry(BookmarkFolder parent, GameDataElement target) { + this.parent = parent; + this.bookmarkedElement = target; + target.bookmark = this; + parent.contents.add(this); + } + + @Override + public Enumeration children() { + return null; + } + + @Override + public boolean getAllowsChildren() { + return false; + } + + @Override + public TreeNode getChildAt(int childIndex) { + return null; + } + + @Override + public int getChildCount() { + return 0; + } + + @Override + public int getIndex(TreeNode node) { + return 0; + } + + @Override + public TreeNode getParent() { + return parent; + } + + @Override + public boolean isLeaf() { + return true; + } + + @Override + public void childrenAdded(List path) { + path.add(0,this); + parent.childrenAdded(path); + } + + @Override + public void childrenChanged(List path) { + path.add(0,this); + parent.childrenChanged(path); + } + + @Override + public void childrenRemoved(List path) { + path.add(0,this); + parent.childrenRemoved(path); + } + @Override + public void notifyCreated() { + childrenAdded(new ArrayList()); + } + + @Override + public String getDesc() { + if (bookmarkedElement instanceof QuestStage) { + String text = ((GameDataElement)bookmarkedElement).getDesc(); + if (text.length() > 60) { + text = text.substring(0, 57)+"..."; + } + return ((GameDataElement)bookmarkedElement).getDataType().toString()+"/"+((Quest)((QuestStage)bookmarkedElement).parent).id+"#"+((QuestStage)bookmarkedElement).progress+":"+text; + } else { + return ((GameDataElement)bookmarkedElement).getDataType().toString()+"/"+((GameDataElement)bookmarkedElement).getDesc(); + } + } + + @Override + public Project getProject() { + return parent.getProject(); + } + + @Override + public GameDataSet getDataSet() { + return null; + } + + @Override + public Image getIcon() { + return bookmarkedElement.getIcon(); + } + + @Override + public Image getOpenIcon() { + return null; + } + + @Override + public Image getClosedIcon() { + return null; + } + + @Override + public Image getLeafIcon() { + return getIcon(); + } + + @Override + public Type getDataType() { + return null; + } + + @Override + public boolean isEmpty() { + return true; + } + + @Override + public boolean needsSaving() { + return false; + } + + public void delete() { + bookmarkedElement.bookmark = null; + parent.delete(this); + } + + @Override + public void save() { + parent.save(); + } + +} diff --git a/src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarkFolder.java b/src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarkFolder.java new file mode 100644 index 0000000..c34be73 --- /dev/null +++ b/src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarkFolder.java @@ -0,0 +1,168 @@ +package com.gpl.rpg.atcontentstudio.model.bookmarks; + +import java.awt.Image; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; + +import javax.swing.tree.TreeNode; + +import com.gpl.rpg.atcontentstudio.model.GameSource.Type; +import com.gpl.rpg.atcontentstudio.model.Project; +import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode; +import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet; +import com.gpl.rpg.atcontentstudio.ui.DefaultIcons; + +public class BookmarkFolder implements BookmarkNode { + + List contents = new LinkedList(); + BookmarkNode parent; + String name; + Image closedIcon, openIcon; + + public BookmarkFolder(BookmarkNode parent, String name) { + this(parent, name, DefaultIcons.getStdClosedIcon(), DefaultIcons.getStdOpenIcon()); + } + + public BookmarkFolder(BookmarkNode parent, String name, Image closedIcon, Image openIcon) { + this.parent = parent; + this.name = name; + this.closedIcon = closedIcon; + this.openIcon = openIcon; + } + + @Override + public Enumeration children() { + return Collections.enumeration(contents); + } + + @Override + public boolean getAllowsChildren() { + return true; + } + + @Override + public TreeNode getChildAt(int childIndex) { + return contents.get(childIndex); + } + + @Override + public int getChildCount() { + return contents.size(); + } + + @Override + public int getIndex(TreeNode node) { + return contents.indexOf(node); + } + + @Override + public TreeNode getParent() { + return parent; + } + + @Override + public boolean isLeaf() { + return false; + } + + @Override + public void childrenAdded(List path) { + path.add(0,this); + parent.childrenAdded(path); + } + + @Override + public void childrenChanged(List path) { + path.add(0,this); + parent.childrenChanged(path); + } + + @Override + public void childrenRemoved(List path) { + if (path.size() == 1 && this.getChildCount() == 1) { + childrenRemoved(new ArrayList()); + } else { + path.add(0, this); + parent.childrenRemoved(path); + } + } + @Override + public void notifyCreated() { + childrenAdded(new ArrayList()); + } + + @Override + public String getDesc() { + return name; + } + + @Override + public Project getProject() { + return parent.getProject(); + } + + @Override + public GameDataSet getDataSet() { + return null; + } + + @Override + public Image getIcon() { + return getClosedIcon(); + } + + @Override + public Image getOpenIcon() { + return openIcon; + } + + @Override + public Image getClosedIcon() { + return closedIcon; + } + + @Override + public Image getLeafIcon() { + return getClosedIcon(); + } + + @Override + public Type getDataType() { + return null; + } + + @Override + public boolean isEmpty() { + return contents.isEmpty(); + } + + @Override + public boolean needsSaving() { + return false; + } + + public void delete(BookmarkEntry bookmarkEntry) { + if (contents.contains(bookmarkEntry)) { + bookmarkEntry.childrenRemoved(new ArrayList()); + contents.remove(bookmarkEntry); + save(); + } + } + + public void delete(BookmarkFolder bookmarkFolder) { + // TODO Auto-generated method stub + + } + + public void save() { + parent.save(); + } + + public void delete() { + + } + +} diff --git a/src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarkNode.java b/src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarkNode.java new file mode 100644 index 0000000..4b64420 --- /dev/null +++ b/src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarkNode.java @@ -0,0 +1,10 @@ +package com.gpl.rpg.atcontentstudio.model.bookmarks; + +import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode; + +public interface BookmarkNode extends ProjectTreeNode{ + + public void save(); + public void delete(); + +} diff --git a/src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarksRoot.java b/src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarksRoot.java new file mode 100644 index 0000000..501cfff --- /dev/null +++ b/src/com/gpl/rpg/atcontentstudio/model/bookmarks/BookmarksRoot.java @@ -0,0 +1,210 @@ +package com.gpl.rpg.atcontentstudio.model.bookmarks; + +import java.awt.Image; +import java.io.File; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import javax.swing.tree.TreeNode; + +import com.gpl.rpg.atcontentstudio.model.GameDataElement; +import com.gpl.rpg.atcontentstudio.model.GameSource.Type; +import com.gpl.rpg.atcontentstudio.model.Project; +import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode; +import com.gpl.rpg.atcontentstudio.model.SavedSlotCollection; +import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition; +import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue; +import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist; +import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet; +import com.gpl.rpg.atcontentstudio.model.gamedata.Item; +import com.gpl.rpg.atcontentstudio.model.gamedata.ItemCategory; +import com.gpl.rpg.atcontentstudio.model.gamedata.NPC; +import com.gpl.rpg.atcontentstudio.model.gamedata.Quest; +import com.gpl.rpg.atcontentstudio.model.maps.TMXMap; +import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment; +import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet; +import com.gpl.rpg.atcontentstudio.ui.DefaultIcons; + +public class BookmarksRoot implements BookmarkNode { + + SavedSlotCollection v = new SavedSlotCollection(); + + public transient Project parent = null; + + BookmarkFolder ac, diag, dl, it, ic, npc, q, tmx, sp, wm; + + public BookmarksRoot(Project parent) { + this.parent = parent; + + v.add(ac = new BookmarkFolder(this, ActorCondition.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon())); + v.add(diag = new BookmarkFolder(this, Dialogue.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon())); + v.add(dl = new BookmarkFolder(this, Droplist.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon())); + v.add(it = new BookmarkFolder(this, Item.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon())); + v.add(ic = new BookmarkFolder(this, ItemCategory.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon())); + v.add(npc = new BookmarkFolder(this, NPC.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon())); + v.add(q = new BookmarkFolder(this, Quest.getStaticDesc(), DefaultIcons.getJsonClosedIcon(), DefaultIcons.getJsonOpenIcon())); + + v.add(tmx = new BookmarkFolder(this, "TMX Maps", DefaultIcons.getTmxClosedIcon(), DefaultIcons.getTmxOpenIcon())); + v.add(sp = new BookmarkFolder(this, "Spritesheets", DefaultIcons.getSpriteClosedIcon(), DefaultIcons.getSpriteOpenIcon())); + v.add(wm = new BookmarkFolder(this, "Worldmap", DefaultIcons.getSpriteClosedIcon(), DefaultIcons.getSpriteOpenIcon())); + } + + @Override + public Enumeration children() { + return v.getNonEmptyElements(); + } + + @Override + public boolean getAllowsChildren() { + return true; + } + + @Override + public TreeNode getChildAt(int arg0) { + return v.getNonEmptyElementAt(arg0); + } + + @Override + public int getChildCount() { + return v.getNonEmptySize(); + } + + @Override + public int getIndex(TreeNode arg0) { + return v.getNonEmptyIndexOf((ProjectTreeNode) arg0); + } + + @Override + public TreeNode getParent() { + return parent; + } + + @Override + public boolean isLeaf() { + return false; + } + + @Override + public void childrenAdded(List path) { + path.add(0, this); + parent.childrenAdded(path); + } + @Override + public void childrenChanged(List path) { + path.add(0, this); + parent.childrenChanged(path); + } + @Override + public void childrenRemoved(List path) { + if (path.size() == 1 && this.v.getNonEmptySize() == 1) { + childrenRemoved(new ArrayList()); + } else { + path.add(0, this); + parent.childrenRemoved(path); + } + } + @Override + public void notifyCreated() { + childrenAdded(new ArrayList()); + for (ProjectTreeNode node : v.getNonEmptyIterable()) { + node.notifyCreated(); + } + } + + @Override + public String getDesc() { + return (needsSaving() ? "*" : "")+"Bookmarks"; + } + + @Override + public Project getProject() { + return parent == null ? null : parent.getProject(); + } + + @Override + public GameDataSet getDataSet() { + return null; + } + + @Override + public Image getIcon() { + return getOpenIcon(); + } + + @Override + public Image getOpenIcon() { + return DefaultIcons.getBookmarkOpenIcon(); + } + + @Override + public Image getClosedIcon() { + return DefaultIcons.getBookmarkClosedIcon(); + } + + @Override + public Image getLeafIcon() { + return getClosedIcon(); + } + + @Override + public Type getDataType() { + return null; + } + + @Override + public boolean isEmpty() { + return v.isEmpty(); + } + + @Override + public boolean needsSaving() { + return false; + } + + public void save() { + + } + + @Override + public void delete() {} + + public void addBookmark(GameDataElement target) { + BookmarkEntry node; + BookmarkFolder folder = null; + if (target instanceof ActorCondition) { + folder = ac; + } else if (target instanceof Dialogue) { + folder = diag; + } else if (target instanceof Droplist) { + folder = dl; + } else if (target instanceof Item) { + folder = it; + } else if (target instanceof ItemCategory) { + folder = ic; + } else if (target instanceof NPC) { + folder = npc; + } else if (target instanceof Quest) { + folder = q; + } else if (target instanceof TMXMap) { + folder = tmx; + } else if (target instanceof Spritesheet) { + folder = sp; + } else if (target instanceof WorldmapSegment) { + folder = wm; + } else { + return; + } + ProjectTreeNode higherEmptyParent = folder; + while (higherEmptyParent != null) { + if (higherEmptyParent.getParent() != null && ((ProjectTreeNode)higherEmptyParent.getParent()).isEmpty()) higherEmptyParent = (ProjectTreeNode)higherEmptyParent.getParent(); + else break; + } + if (higherEmptyParent == this && !this.isEmpty()) higherEmptyParent = null; + + node = new BookmarkEntry(folder, target); + if (higherEmptyParent != null) higherEmptyParent.notifyCreated(); + else node.notifyCreated(); + } + +} diff --git a/src/com/gpl/rpg/atcontentstudio/ui/DefaultIcons.java b/src/com/gpl/rpg/atcontentstudio/ui/DefaultIcons.java index 2035460..fd29106 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/DefaultIcons.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/DefaultIcons.java @@ -75,6 +75,14 @@ public class DefaultIcons { private static String FOLDER_AT_OPEN_RES = "/com/gpl/rpg/atcontentstudio/img/folder_at_open.png"; public static Image getATOpenImage() { return getImage(FOLDER_AT_OPEN_RES); } public static Image getATOpenIcon() { return getIcon(FOLDER_AT_OPEN_RES); } + + private static String FOLDER_BOOKMARK_CLOSED_RES = "/com/gpl/rpg/atcontentstudio/img/folder_bookmark_closed.png"; + public static Image getBookmarkClosedImage() { return getImage(FOLDER_BOOKMARK_CLOSED_RES); } + public static Image getBookmarkClosedIcon() { return getIcon(FOLDER_BOOKMARK_CLOSED_RES); } + + private static String FOLDER_BOOKMARK_OPEN_RES = "/com/gpl/rpg/atcontentstudio/img/folder_bookmark_open.png"; + public static Image getBookmarkOpenImage() { return getImage(FOLDER_BOOKMARK_OPEN_RES); } + public static Image getBookmarkOpenIcon() { return getIcon(FOLDER_BOOKMARK_OPEN_RES); } private static String TILED_ICON_RES = "/com/gpl/rpg/atcontentstudio/img/tiled-icon.png"; public static Image getTiledIconImage() { return getImage(TILED_ICON_RES); } @@ -276,6 +284,14 @@ public class DefaultIcons { public static Image getStatusUnknownImage() { return getImage(STATUS_UNKNOWN_RES); } public static Image getStatusUnknownIcon() { return getIcon(STATUS_UNKNOWN_RES); } + private static String BOOKMARK_INACTIVE = "/com/gpl/rpg/atcontentstudio/img/bookmark_inactive.png"; + public static Image getBookmarkInactiveImage() { return getImage(BOOKMARK_INACTIVE); } + public static Image getBookmarkInactiveIcon() { return getIcon(BOOKMARK_INACTIVE); } + + private static String BOOKMARK_ACTIVE = "/com/gpl/rpg/atcontentstudio/img/bookmark_active.png"; + public static Image getBookmarkActiveImage() { return getImage(BOOKMARK_ACTIVE); } + public static Image getBookmarkActiveIcon() { return getIcon(BOOKMARK_ACTIVE); } + private static Image getImage(String res) { if (imageCache.get(res) == null) { diff --git a/src/com/gpl/rpg/atcontentstudio/ui/Editor.java b/src/com/gpl/rpg/atcontentstudio/ui/Editor.java index d40be0a..edb5912 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/Editor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/Editor.java @@ -812,7 +812,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener { if (text.length() > 60) { text = text.substring(0, 57)+"..."; } - label.setText(((GameDataElement)value).getDataType().toString()+"/"+((Quest)((QuestStage)value).parent).id+":"+text); + label.setText(((GameDataElement)value).getDataType().toString()+"/"+((Quest)((QuestStage)value).parent).id+"#"+((QuestStage)value).progress+":"+text); } else { label.setText(((GameDataElement)value).getDataType().toString()+"/"+((GameDataElement)value).getDesc()); } diff --git a/src/com/gpl/rpg/atcontentstudio/ui/ProjectsTree.java b/src/com/gpl/rpg/atcontentstudio/ui/ProjectsTree.java index 577ba15..0d8148b 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/ProjectsTree.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/ProjectsTree.java @@ -33,6 +33,7 @@ import com.gpl.rpg.andorstrainer.AndorsTrainer; import com.gpl.rpg.atcontentstudio.ATContentStudio; import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode; import com.gpl.rpg.atcontentstudio.model.Workspace; +import com.gpl.rpg.atcontentstudio.model.bookmarks.BookmarkEntry; import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement; import com.gpl.rpg.atcontentstudio.model.maps.TMXMap; import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment; @@ -595,6 +596,8 @@ public class ProjectsTree extends JPanel { ATContentStudio.frame.openEditor((WorldmapSegment)node); } else if (node instanceof WriterModeData) { ATContentStudio.frame.openEditor((WriterModeData)node); + } else if (node instanceof BookmarkEntry) { + ATContentStudio.frame.openEditor(((BookmarkEntry)node).bookmarkedElement); } else if (node instanceof SavedGame) { if (konamiCodeEntered) { ATContentStudio.frame.openEditor((SavedGame)node); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/StudioFrame.java b/src/com/gpl/rpg/atcontentstudio/ui/StudioFrame.java index 2af28da..25ccaa5 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/StudioFrame.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/StudioFrame.java @@ -213,6 +213,8 @@ public class StudioFrame extends JFrame { openEditor((Spritesheet) node); } else if (node instanceof TMXMap) { openEditor((TMXMap) node); + } else if (node instanceof WorldmapSegment) { + openEditor((WorldmapSegment) node); } else if (node instanceof WriterModeData) { openEditor((WriterModeData) node); } diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/JSONElementEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/JSONElementEditor.java index c70b5e8..e313805 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/JSONElementEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/JSONElementEditor.java @@ -204,6 +204,7 @@ public abstract class JSONElementEditor extends Editor { } }); savePane.add(delete, JideBoxLayout.FIX); + } else { if (proj.alteredContent.gameData.getGameDataElement(concreteNodeClass, node.id) != null) { savePane.add(message = new JLabel(ALTERED_EXISTS_MESSAGE), JideBoxLayout.FIX); @@ -242,8 +243,10 @@ public abstract class JSONElementEditor extends Editor { } JButton prev = new JButton(new ImageIcon(DefaultIcons.getArrowLeftIcon())); JButton next = new JButton(new ImageIcon(DefaultIcons.getArrowRightIcon())); + final JButton bookmark = new JButton(new ImageIcon(node.bookmark != null ? DefaultIcons.getBookmarkActiveIcon() : DefaultIcons.getBookmarkInactiveIcon())); savePane.add(prev, JideBoxLayout.FIX); savePane.add(next, JideBoxLayout.FIX); + savePane.add(bookmark, JideBoxLayout.FIX); if (node.getParent().getIndex(node) == 0) { prev.setEnabled(false); } @@ -268,6 +271,20 @@ public abstract class JSONElementEditor extends Editor { } } }); + bookmark.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + if (node.bookmark == null) { + node.getProject().bookmark(node); + bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkActiveIcon())); + } else { + node.bookmark.delete(); + bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkInactiveIcon())); + } + } + }); + + //Placeholder. Fills the eventual remaining space. savePane.add(new JPanel(), JideBoxLayout.VARY); pane.add(savePane, JideBoxLayout.FIX); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java index 945da13..edf68a8 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/map/TMXMapEditor.java @@ -1779,6 +1779,20 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe } }); savePane.add(delete, JideBoxLayout.FIX); + final JButton bookmark = new JButton(new ImageIcon(map.bookmark != null ? DefaultIcons.getBookmarkActiveIcon() : DefaultIcons.getBookmarkInactiveIcon())); + savePane.add(bookmark, JideBoxLayout.FIX); + bookmark.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + if (map.bookmark == null) { + map.getProject().bookmark(map); + bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkActiveIcon())); + } else { + map.bookmark.delete(); + bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkInactiveIcon())); + } + } + }); } else { if (proj.getMap(map.id) != map) { savePane.add(message = new JLabel(ALTERED_EXISTS_MESSAGE), JideBoxLayout.FIX); @@ -1842,6 +1856,20 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe } } }); + final JButton bookmark = new JButton(new ImageIcon(map.bookmark != null ? DefaultIcons.getBookmarkActiveIcon() : DefaultIcons.getBookmarkInactiveIcon())); + savePane.add(bookmark, JideBoxLayout.FIX); + bookmark.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + if (map.bookmark == null) { + map.getProject().bookmark(map); + bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkActiveIcon())); + } else { + map.bookmark.delete(); + bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkInactiveIcon())); + } + } + }); //Placeholder. Fills the eventual remaining space. savePane.add(new JPanel(), JideBoxLayout.VARY); pane.add(savePane, JideBoxLayout.FIX); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapEditor.java index bdcdf17..7e1afdd 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/map/WorldMapEditor.java @@ -986,6 +986,20 @@ public class WorldMapEditor extends Editor implements FieldUpdateListener { } } }); + final JButton bookmark = new JButton(new ImageIcon(node.bookmark != null ? DefaultIcons.getBookmarkActiveIcon() : DefaultIcons.getBookmarkInactiveIcon())); + savePane.add(bookmark, JideBoxLayout.FIX); + bookmark.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + if (node.bookmark == null) { + node.getProject().bookmark(node); + bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkActiveIcon())); + } else { + node.bookmark.delete(); + bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkInactiveIcon())); + } + } + }); //Placeholder. Fills the eventual remaining space. savePane.add(new JPanel(), JideBoxLayout.VARY); return savePane; diff --git a/src/com/gpl/rpg/atcontentstudio/ui/sprites/SpritesheetEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/sprites/SpritesheetEditor.java index 89692e5..d3f9a3f 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/sprites/SpritesheetEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/sprites/SpritesheetEditor.java @@ -100,6 +100,20 @@ public class SpritesheetEditor extends Editor { }); buttonPane.add(openImage, JideBoxLayout.FIX); buttonPane.add(getWarningLabel(), JideBoxLayout.FIX); + final JButton bookmark = new JButton(new ImageIcon(sheet.bookmark != null ? DefaultIcons.getBookmarkActiveIcon() : DefaultIcons.getBookmarkInactiveIcon())); + buttonPane.add(bookmark, JideBoxLayout.FIX); + bookmark.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + if (target.bookmark == null) { + target.getProject().bookmark(target); + bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkActiveIcon())); + } else { + target.bookmark.delete(); + bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkInactiveIcon())); + } + } + }); buttonPane.add(new JPanel(), JideBoxLayout.VARY); pane.add(buttonPane, JideBoxLayout.FIX); addLabelField(pane, "Spritesheet ID: ", sheet.id); From da5b686672da5d310821b2a85955d478faf983b6 Mon Sep 17 00:00:00 2001 From: Zukero Date: Sat, 15 Sep 2018 14:39:56 +0200 Subject: [PATCH 38/42] v0.6.13 --- ATCS_JAR.jardesc | 4 ++-- packaging/Windows/ATCS_Installer.nsi | 2 +- src/com/gpl/rpg/atcontentstudio/ATContentStudio.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ATCS_JAR.jardesc b/ATCS_JAR.jardesc index c09bb91..6986435 100644 --- a/ATCS_JAR.jardesc +++ b/ATCS_JAR.jardesc @@ -1,6 +1,6 @@ - + - + diff --git a/packaging/Windows/ATCS_Installer.nsi b/packaging/Windows/ATCS_Installer.nsi index efd2667..c9579e7 100644 --- a/packaging/Windows/ATCS_Installer.nsi +++ b/packaging/Windows/ATCS_Installer.nsi @@ -1,6 +1,6 @@ !include MUI2.nsh -!define VERSION "0.6.12" +!define VERSION "0.6.13" !define TRAINER_VERSION "0.1.4" !define JAVA_BIN "javaw" diff --git a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java index a55141b..1a8adb0 100644 --- a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java +++ b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java @@ -43,7 +43,7 @@ import com.gpl.rpg.atcontentstudio.ui.WorkspaceSelector; public class ATContentStudio { public static final String APP_NAME = "Andor's Trail Content Studio"; - public static final String APP_VERSION = "v0.6.12"; + public static final String APP_VERSION = "v0.6.13"; public static final String CHECK_UPDATE_URL = "https://andorstrail.com/static/ATCS_latest"; public static final String DOWNLOAD_URL = "https://andorstrail.com/viewtopic.php?f=6&t=4806"; From 1b01ecd37ddd0a0eed31a79eb6eff404ae95fa1c Mon Sep 17 00:00:00 2001 From: Zukero Date: Sat, 15 Sep 2018 15:05:53 +0200 Subject: [PATCH 39/42] Version number missing in that file.... --- packaging/ATCS_latest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/ATCS_latest b/packaging/ATCS_latest index cd7a095..78760e8 100644 --- a/packaging/ATCS_latest +++ b/packaging/ATCS_latest @@ -1 +1 @@ -v0.6.12 \ No newline at end of file +v0.6.13 \ No newline at end of file From 00c05e7507f69b571b5ba044af0cc42f4e2212f8 Mon Sep 17 00:00:00 2001 From: Zukero Date: Mon, 17 Sep 2018 20:55:18 +0200 Subject: [PATCH 40/42] Fixed Dialogue Tree bug and spacing issues. v0.6.14 released. Dialogue Tree bug caused by copy-pasting code created NPEs when not activating translator mode. Made Dialogue Tree node spacing double when activating translator mode. --- ATCS_JAR.jardesc | 2 +- packaging/ATCS_latest | 2 +- packaging/Windows/ATCS_Installer.nsi | 2 +- src/com/gpl/rpg/atcontentstudio/ATContentStudio.java | 2 +- .../ui/gamedataeditors/dialoguetree/DialogueGraphView.java | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ATCS_JAR.jardesc b/ATCS_JAR.jardesc index 6986435..0624630 100644 --- a/ATCS_JAR.jardesc +++ b/ATCS_JAR.jardesc @@ -1,6 +1,6 @@ - + diff --git a/packaging/ATCS_latest b/packaging/ATCS_latest index 78760e8..19d7022 100644 --- a/packaging/ATCS_latest +++ b/packaging/ATCS_latest @@ -1 +1 @@ -v0.6.13 \ No newline at end of file +v0.6.14 \ No newline at end of file diff --git a/packaging/Windows/ATCS_Installer.nsi b/packaging/Windows/ATCS_Installer.nsi index c9579e7..3e98602 100644 --- a/packaging/Windows/ATCS_Installer.nsi +++ b/packaging/Windows/ATCS_Installer.nsi @@ -1,6 +1,6 @@ !include MUI2.nsh -!define VERSION "0.6.13" +!define VERSION "0.6.14" !define TRAINER_VERSION "0.1.4" !define JAVA_BIN "javaw" diff --git a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java index 1a8adb0..2ea2d4f 100644 --- a/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java +++ b/src/com/gpl/rpg/atcontentstudio/ATContentStudio.java @@ -43,7 +43,7 @@ import com.gpl.rpg.atcontentstudio.ui.WorkspaceSelector; public class ATContentStudio { public static final String APP_NAME = "Andor's Trail Content Studio"; - public static final String APP_VERSION = "v0.6.13"; + public static final String APP_VERSION = "v0.6.14"; public static final String CHECK_UPDATE_URL = "https://andorstrail.com/static/ATCS_latest"; public static final String DOWNLOAD_URL = "https://andorstrail.com/viewtopic.php?f=6&t=4806"; diff --git a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java index 4f2ee93..d091d8b 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/gamedataeditors/dialoguetree/DialogueGraphView.java @@ -160,7 +160,7 @@ public class DialogueGraphView extends Display { // now create the main layout routine ActionList layout = new ActionList();//Activity.INFINITY); - NodeLinkTreeLayout treeLayout = new NodeLinkTreeLayout(GRAPH, prefuse.Constants.ORIENT_LEFT_RIGHT, 120, 40, 40); + NodeLinkTreeLayout treeLayout = new NodeLinkTreeLayout(GRAPH, prefuse.Constants.ORIENT_LEFT_RIGHT, 120, translatorMode ? 80 : 40, translatorMode ? 80 : 40); treeLayout.setLayoutAnchor(new Point2D.Double(25,300)); layout.add(treeLayout); layout.add(new EdgesLabelDecoratorLayout(EDGES_LABELS)); @@ -252,7 +252,7 @@ public class DialogueGraphView extends Display { }; }; } else { - label = dialogue.message; + label = r.text; } rNode.setString(LABEL, label); if (t != null) t.start(); From b497493853920e1726214519fea0e1f24ba6c166 Mon Sep 17 00:00:00 2001 From: Zukero Date: Fri, 21 Sep 2018 18:51:12 +0200 Subject: [PATCH 41/42] Fixed issues in i18n tools. Added beanshell worker indicator. Added resources compression tools too. --- .classpath | 37 +- hacked-libtiled/tiled/core/TileSet.java | 45 +- minify/com/whoischarles/util/json/Minify.java | 405 ++++++++++++++++++ .../{ui => model}/tools/i18n/PoPotWriter.java | 2 +- .../tools/i18n/PotComparator.java | 20 +- .../tools/i18n/PotGenerator.java | 2 +- .../resoptimizer/ResourcesCompactor.java | 381 ++++++++++++++++ .../tools/resoptimizer/SpritesheetId.java | 38 ++ .../ui/tools/BeanShellView.java | 29 +- 9 files changed, 906 insertions(+), 53 deletions(-) create mode 100644 minify/com/whoischarles/util/json/Minify.java rename src/com/gpl/rpg/atcontentstudio/{ui => model}/tools/i18n/PoPotWriter.java (94%) rename src/com/gpl/rpg/atcontentstudio/{ui => model}/tools/i18n/PotComparator.java (93%) rename src/com/gpl/rpg/atcontentstudio/{ui => model}/tools/i18n/PotGenerator.java (96%) create mode 100644 src/com/gpl/rpg/atcontentstudio/model/tools/resoptimizer/ResourcesCompactor.java create mode 100644 src/com/gpl/rpg/atcontentstudio/model/tools/resoptimizer/SpritesheetId.java diff --git a/.classpath b/.classpath index 34382c4..5e81577 100644 --- a/.classpath +++ b/.classpath @@ -1,18 +1,19 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/hacked-libtiled/tiled/core/TileSet.java b/hacked-libtiled/tiled/core/TileSet.java index afd99af..fcacaf7 100644 --- a/hacked-libtiled/tiled/core/TileSet.java +++ b/hacked-libtiled/tiled/core/TileSet.java @@ -98,27 +98,42 @@ public class TileSet implements Iterable File f = new File(imgFilename); - Image image = ImageIO.read(f.getCanonicalFile()); + BufferedImage image = ImageIO.read(f.getCanonicalFile()); if (image == null) { - throw new IOException("Failed to load " + tilebmpFile); + throw new IOException("Failed to load " + imgFilename); } - Toolkit tk = Toolkit.getDefaultToolkit(); + tilebmpFile = f; + tileDimensions = new Rectangle(cutter.getTileDimensions()); + +// Toolkit tk = Toolkit.getDefaultToolkit(); +// +// if (transparentColor != null) { +// int rgb = transparentColor.getRGB(); +// image = tk.createImage( +// new FilteredImageSource(image.getSource(), +// new TransparentImageFilter(rgb))); +// } +// +// BufferedImage buffered = new BufferedImage( +// image.getWidth(null), +// image.getHeight(null), +// BufferedImage.TYPE_INT_ARGB); +// buffered.getGraphics().drawImage(image, 0, 0, null); - if (transparentColor != null) { - int rgb = transparentColor.getRGB(); - image = tk.createImage( - new FilteredImageSource(image.getSource(), - new TransparentImageFilter(rgb))); - } + importTileBitmap(image, cutter); + } + + public void weakImportTileBitmap(String imgFilename, TileCutter cutter) + throws IOException + { + setTilesetImageFilename(imgFilename); + + File f = new File(imgFilename); - BufferedImage buffered = new BufferedImage( - image.getWidth(null), - image.getHeight(null), - BufferedImage.TYPE_INT_ARGB); - buffered.getGraphics().drawImage(image, 0, 0, null); + tilebmpFile = f; + tileDimensions = new Rectangle(cutter.getTileDimensions()); - importTileBitmap(buffered, cutter); } public void loadFromProject(String name, TMXMap tmxMap, int tileWidth, int tileHeight) { diff --git a/minify/com/whoischarles/util/json/Minify.java b/minify/com/whoischarles/util/json/Minify.java new file mode 100644 index 0000000..bc7c688 --- /dev/null +++ b/minify/com/whoischarles/util/json/Minify.java @@ -0,0 +1,405 @@ +/** + * ---------------------- + * Minify.java 2015-10-04 + * ---------------------- + * + * Copyright (c) 2015 Charles Bihis (www.whoischarles.com) + * + * This work is an adaptation of JSMin.java published by John Reilly which is a translation from C to Java of jsmin.c + * published by Douglas Crockford. Permission is hereby granted to use this Java version under the same conditions as + * the original jsmin.c on which all of these derivatives are based. + * + * + * + * --------------------- + * JSMin.java 2006-02-13 + * --------------------- + * + * Copyright (c) 2006 John Reilly (www.inconspicuous.org) + * + * This work is a translation from C to Java of jsmin.c published by Douglas Crockford. Permission is hereby granted to + * use the Java version under the same conditions as the jsmin.c on which it is based. + * + * + * + * ------------------ + * jsmin.c 2003-04-21 + * ------------------ + * + * Copyright (c) 2002 Douglas Crockford (www.crockford.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * The Software shall be used for Good, not Evil. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.whoischarles.util.json; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PushbackInputStream; +import java.nio.charset.StandardCharsets; + +/** + * Minify.java is written by Charles Bihis (www.whoischarles.com) and is adapted from JSMin.java written by John Reilly + * (www.inconspicuous.org) which is itself a translation of jsmin.c written by Douglas Crockford (www.crockford.com). + * + * @see http://www.unl.edu/ucomm/templatedependents/JSMin.java + * @see http://www.crockford.com/javascript/jsmin.c + */ +public class Minify { + + private static final int EOF = -1; + + private PushbackInputStream in; + private OutputStream out; + private int currChar; + private int nextChar; + private int line; + private int column; + + public static enum Action { + OUTPUT_CURR, DELETE_CURR, DELETE_NEXT + } + + public Minify() { + this.in = null; + this.out = null; + } + + /** + * Minifies the input JSON string. + * + * Takes the input JSON string and deletes the characters which are insignificant to JavaScipt. Comments will be + * removed, tabs will be replaced with spaces, carriage returns will be replaced with line feeds, and most spaces + * and line feeds will be removed. The result will be returned. + * + * @param json The JSON string for which to minify + * @return A minified, yet functionally identical, version of the input JSON string + */ + public String minify(String json) { + InputStream in = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + try { + minify(in, out); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + return out.toString().trim(); + } + + /** + * Takes an input stream to a JSON string and outputs minified JSON to the output stream. + * + * Takes the input JSON via the input stream and deletes the characters which are insignificant to JavaScript. + * Comments will be removed, tabs will be replaced with spaaces, carriage returns will be replaced with line feeds, + * and most spaces and line feeds will be removed. The result is streamed to the output stream. + * + * @param in The InputStream from which to get the un-minified JSON + * @param out The OutputStream where the resulting minified JSON will be streamed to + * @throws IOException + * @throws UnterminatedRegExpLiteralException + * @throws UnterminatedCommentException + * @throws UnterminatedStringLiteralException + */ + public void minify(InputStream in, OutputStream out) throws IOException, UnterminatedRegExpLiteralException, + UnterminatedCommentException, + UnterminatedStringLiteralException { + + // Initialize + this.in = new PushbackInputStream(in); + this.out = out; + this.line = 0; + this.column = 0; +// currChar = '\n'; +// action(Action.DELETE_NEXT); + currChar = get(); + nextChar = peek(); + + // Process input + while (currChar != EOF) { + switch (currChar) { + + case ' ': + if (isAlphanum(nextChar)) { + action(Action.OUTPUT_CURR); + } else { + action(Action.DELETE_CURR); + } + break; + + case '\n': + switch (nextChar) { + case '{': + case '[': + case '(': + case '+': + case '-': + action(Action.OUTPUT_CURR); + break; + case ' ': + action(Action.DELETE_NEXT); + break; + default: + if (isAlphanum(nextChar)) { + action(Action.OUTPUT_CURR); + } else { + action(Action.DELETE_CURR); + } + } + break; + + default: + switch (nextChar) { + case ' ': + if (isAlphanum(currChar)) { + action(Action.OUTPUT_CURR); + break; + } + action(Action.DELETE_NEXT); + break; + case '\n': + switch (currChar) { + case '}': + case ']': + case ')': + case '+': + case '-': + case '"': + case '\'': + action(Action.OUTPUT_CURR); + break; + default: + if (isAlphanum(currChar)) { + action(Action.OUTPUT_CURR); + } else { + action(Action.DELETE_NEXT); + } + } + break; + default: + action(Action.OUTPUT_CURR); + break; + } + } + } + out.flush(); + } + + /** + * Process the current character with an appropriate action. + * + * The action that occurs is determined by the current character. The options are: + * + * 1. Output currChar: output currChar, copy nextChar to currChar, get the next character and save it to nextChar + * 2. Delete currChar: copy nextChar to currChar, get the next character and save it to nextChar + * 3. Delete nextChar: get the next character and save it to nextChar + * + * This method essentially treats a string as a single character. Also recognizes regular expressions if they are + * preceded by '(', ',', or '='. + * + * @param action The action to perform + * @throws IOException + * @throws UnterminatedRegExpLiteralException + * @throws UnterminatedCommentException + * @throws UnterminatedStringLiteralException + */ + private void action(Action action) throws IOException, UnterminatedRegExpLiteralException, UnterminatedCommentException, + UnterminatedStringLiteralException { + + // Process action + switch (action) { + + case OUTPUT_CURR: + out.write(currChar); + + case DELETE_CURR: + currChar = nextChar; + + if (currChar == '\'' || currChar == '"') { + for ( ; ; ) { + out.write(currChar); + currChar = get(); + if (currChar == nextChar) { + break; + } + if (currChar <= '\n') { + throw new UnterminatedStringLiteralException(line, + column); + } + if (currChar == '\\') { + out.write(currChar); + currChar = get(); + } + } + } + + case DELETE_NEXT: + nextChar = next(); + if (nextChar == '/' + && (currChar == '(' || currChar == ',' || currChar == '=' || currChar == ':')) { + out.write(currChar); + out.write(nextChar); + for ( ; ; ) { + currChar = get(); + if (currChar == '/') { + break; + } else if (currChar == '\\') { + out.write(currChar); + currChar = get(); + } else if (currChar <= '\n') { + throw new UnterminatedRegExpLiteralException(line, + column); + } + out.write(currChar); + } + nextChar = next(); + } + } + } + + /** + * Determines whether a given character is a letter, digit, underscore, dollar sign, or non-ASCII character. + * + * @param c The character to compare + * @return True if the character is a letter, digit, underscore, dollar sign, or non-ASCII character. False otherwise. + */ + private boolean isAlphanum(int c) { + return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') + || c == '_' || c == '$' || c == '\\' || c > 126); + } + + /** + * Returns the next character from the input stream. + * + * Will pop the next character from the input stack. If the character is a control character, translate it to a space + * or line feed. + * + * @return The next character from the input stream + * @throws IOException + */ + private int get() throws IOException { + int c = in.read(); + + if (c == '\n') { + line++; + column = 0; + } else { + column++; + } + + if (c >= ' ' || c == '\n' || c == EOF) { + return c; + } + + if (c == '\r') { + column = 0; + return '\n'; + } + + return ' '; + } + + /** + * Returns the next character from the input stream without popping it from the stack. + * + * @return The next character from the input stream + * @throws IOException + */ + private int peek() throws IOException { + int lookaheadChar = in.read(); + in.unread(lookaheadChar); + return lookaheadChar; + } + + /** + * Get the next character from the input stream, excluding comments. + * + * Will read from the input stream via the get() method. Will exclude characters that are part of + * comments. peek() is used to se if a '/' is followed by a '/' or a '*' for the purpose of identifying + * comments. + * + * @return The next character from the input stream, excluding characters from comments + * @throws IOException + * @throws UnterminatedCommentException + */ + private int next() throws IOException, UnterminatedCommentException { + int c = get(); + + if (c == '/') { + switch (peek()) { + + case '/': + for ( ; ; ) { + c = get(); + if (c <= '\n') { + return c; + } + } + + case '*': + get(); + for ( ; ; ) { + switch (get()) { + case '*': + if (peek() == '/') { + get(); + return ' '; + } + break; + case EOF: + throw new UnterminatedCommentException(line, column); + } + } + + default: + return c; + } + + } + return c; + } + + /** + * Exception to be thrown when an unterminated comment appears in the input. + */ + public static class UnterminatedCommentException extends Exception { + public UnterminatedCommentException(int line, int column) { + super("Unterminated comment at line " + line + " and column " + column); + } + } + + /** + * Exception to be thrown when an unterminated string literal appears in the input. + */ + public static class UnterminatedStringLiteralException extends Exception { + public UnterminatedStringLiteralException(int line, int column) { + super("Unterminated string literal at line " + line + " and column " + column); + } + } + + /** + * Exception to be thrown when an unterminated regular expression literal appears in the input. + */ + public static class UnterminatedRegExpLiteralException extends Exception { + public UnterminatedRegExpLiteralException(int line, int column) { + super("Unterminated regular expression at line " + line + " and column " + column); + } + } +} \ No newline at end of file diff --git a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PoPotWriter.java b/src/com/gpl/rpg/atcontentstudio/model/tools/i18n/PoPotWriter.java similarity index 94% rename from src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PoPotWriter.java rename to src/com/gpl/rpg/atcontentstudio/model/tools/i18n/PoPotWriter.java index 507f0a4..9a836e8 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PoPotWriter.java +++ b/src/com/gpl/rpg/atcontentstudio/model/tools/i18n/PoPotWriter.java @@ -1,4 +1,4 @@ -package com.gpl.rpg.atcontentstudio.ui.tools.i18n; +package com.gpl.rpg.atcontentstudio.model.tools.i18n; import java.io.File; import java.io.FileWriter; diff --git a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotComparator.java b/src/com/gpl/rpg/atcontentstudio/model/tools/i18n/PotComparator.java similarity index 93% rename from src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotComparator.java rename to src/com/gpl/rpg/atcontentstudio/model/tools/i18n/PotComparator.java index 3702545..916b3aa 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotComparator.java +++ b/src/com/gpl/rpg/atcontentstudio/model/tools/i18n/PotComparator.java @@ -1,4 +1,4 @@ -package com.gpl.rpg.atcontentstudio.ui.tools.i18n; +package com.gpl.rpg.atcontentstudio.model.tools.i18n; import java.io.File; import java.io.FileFilter; @@ -24,15 +24,15 @@ import net.launchpad.tobal.poparser.POParser; * To use this, paste the following script in the beanshell console of ATCS. * Don't forget to change the project number to suit your needs. * - * import com.gpl.rpg.atcontentstudio.model.Workspace; - * import com.gpl.rpg.atcontentstudio.ui.tools.i18n.PotGenerator; - * import com.gpl.rpg.atcontentstudio.ui.tools.i18n.PotComparator; - * - * proj = Workspace.activeWorkspace.projects.get(7); - * PotGenerator.generatePotFileForProject(proj); - * comp = new PotComparator(proj); - * comp.compare(); - * comp.updatePoFiles(proj); +import com.gpl.rpg.atcontentstudio.model.Workspace; +import com.gpl.rpg.atcontentstudio.model.tools.i18n.PotGenerator; +import com.gpl.rpg.atcontentstudio.model.tools.i18n.PotComparator; + +proj = Workspace.activeWorkspace.projects.get(7); +PotGenerator.generatePotFileForProject(proj); +comp = new PotComparator(proj); +comp.compare(); +comp.updatePoFiles(proj); * * * diff --git a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java b/src/com/gpl/rpg/atcontentstudio/model/tools/i18n/PotGenerator.java similarity index 96% rename from src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java rename to src/com/gpl/rpg/atcontentstudio/model/tools/i18n/PotGenerator.java index 00cf3fe..df42692 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/tools/i18n/PotGenerator.java +++ b/src/com/gpl/rpg/atcontentstudio/model/tools/i18n/PotGenerator.java @@ -1,4 +1,4 @@ -package com.gpl.rpg.atcontentstudio.ui.tools.i18n; +package com.gpl.rpg.atcontentstudio.model.tools.i18n; import java.io.File; import java.util.LinkedHashMap; diff --git a/src/com/gpl/rpg/atcontentstudio/model/tools/resoptimizer/ResourcesCompactor.java b/src/com/gpl/rpg/atcontentstudio/model/tools/resoptimizer/ResourcesCompactor.java new file mode 100644 index 0000000..b294fdd --- /dev/null +++ b/src/com/gpl/rpg/atcontentstudio/model/tools/resoptimizer/ResourcesCompactor.java @@ -0,0 +1,381 @@ +package com.gpl.rpg.atcontentstudio.model.tools.resoptimizer; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.StringWriter; +import java.nio.CharBuffer; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.imageio.ImageIO; + +import org.json.simple.JSONArray; + +import com.gpl.rpg.atcontentstudio.io.JsonPrettyWriter; +import com.gpl.rpg.atcontentstudio.model.GameDataElement; +import com.gpl.rpg.atcontentstudio.model.GameSource; +import com.gpl.rpg.atcontentstudio.model.Project; +import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition; +import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet; +import com.gpl.rpg.atcontentstudio.model.gamedata.Item; +import com.gpl.rpg.atcontentstudio.model.gamedata.NPC; +import com.gpl.rpg.atcontentstudio.model.maps.TMXMap; +import com.gpl.rpg.atcontentstudio.model.maps.TMXMapSet; +import com.gpl.rpg.atcontentstudio.model.sprites.SpriteSheetSet; +import com.gpl.rpg.atcontentstudio.utils.FileUtils; +import com.whoischarles.util.json.Minify; +import com.whoischarles.util.json.Minify.UnterminatedCommentException; +import com.whoischarles.util.json.Minify.UnterminatedRegExpLiteralException; +import com.whoischarles.util.json.Minify.UnterminatedStringLiteralException; + +import tiled.core.TileSet; +import tiled.io.TMXMapWriter; + +/** + * + * @author Kevin + * + * To use this, paste the following script in the beanshell console of ATCS. + * Don't forget to change the project number to suit your needs. + * +import com.gpl.rpg.atcontentstudio.model.tools.resoptimizer.ResourcesCompactor; +import com.gpl.rpg.atcontentstudio.model.Workspace; + +proj = Workspace.activeWorkspace.projects.get(0); +new ResourcesCompactor(proj).compactData(); + * + */ +public class ResourcesCompactor { + + public static String DEFAULT_REL_PATH_IN_PROJECT = "compressed"+File.separator; + + private Project proj; + private File baseFolder; + private List compressedSpritesheets = new LinkedList(); + private List preservedSpritesheets = new LinkedList(); + + private Map spritesRelocationForObjects = new LinkedHashMap(); + private Integer currentSpritesheetIndexForObjects = 0; + private CompressedSpritesheet currentSpritesheetForObjects = null; + + private Map spritesRelocationForMaps = new LinkedHashMap(); + private Map spritesheetsBySidForMaps = new LinkedHashMap(); + private Integer currentSpritesheetIndexForMaps = 0; + private CompressedSpritesheet currentSpritesheetForMaps = null; + + public ResourcesCompactor(Project proj) { + this.proj = proj; + this.baseFolder = new File(proj.baseFolder, DEFAULT_REL_PATH_IN_PROJECT); + if (!baseFolder.exists()) baseFolder.mkdirs(); + } + + public void compactData() { + compactJsonData(); + for(CompressedSpritesheet cs : compressedSpritesheets) { + cs.drawFile(); + } + for (File preserved : preservedSpritesheets) { + FileUtils.copyFile(preserved, new File(baseFolder.getAbsolutePath()+File.separator+DEFAULT_DRAWABLE_REL_PATH+File.separator+preserved.getName())); + } + compactMaps(); + } + + public void compactJsonData() { + final List filesCovered = new LinkedList(); + + File folder = new File(baseFolder.getAbsolutePath()+File.separator+GameDataSet.DEFAULT_REL_PATH_IN_SOURCE); + if (!folder.exists()) folder.mkdirs(); + + for (ActorCondition ac : proj.baseContent.gameData.actorConditions) { + if (filesCovered.contains(ac.jsonFile)) continue; + File currentFile = ac.jsonFile; + filesCovered.add(currentFile); + List dataToSave = new ArrayList(); + for (ActorCondition acond : proj.baseContent.gameData.actorConditions) { + if (!acond.jsonFile.equals(currentFile)) continue; + Map json = acond.toJson(); + json.put("iconID", convertObjectSprite(acond.icon_id).toStringID()); + dataToSave.add(json); + } + File target = new File(folder, ac.jsonFile.getName()); + writeJson(dataToSave, target); + } + + for (Item it : proj.baseContent.gameData.items) { + if (filesCovered.contains(it.jsonFile)) continue; + File currentFile = it.jsonFile; + filesCovered.add(currentFile); + List dataToSave = new ArrayList(); + for (Item item : proj.baseContent.gameData.items) { + if (!item.jsonFile.equals(currentFile)) continue; + Map json = item.toJson(); + json.put("iconID", convertObjectSprite(item.icon_id).toStringID()); + dataToSave.add(json); + } + File target = new File(folder, it.jsonFile.getName()); + writeJson(dataToSave, target); + } + + + for (NPC np : proj.baseContent.gameData.npcs) { + if (filesCovered.contains(np.jsonFile)) continue; + File currentFile = np.jsonFile; + filesCovered.add(currentFile); + List dataToSave = new ArrayList(); + for (NPC npc : proj.baseContent.gameData.npcs) { + if (!npc.jsonFile.equals(currentFile)) continue; + Map json = npc.toJson(); + if (proj.getImage(npc.icon_id).getWidth(null) == TILE_WIDTH_IN_PIXELS || proj.getImage(npc.icon_id).getHeight(null) == TILE_HEIGHT_IN_PIXELS) { + json.put("iconID", convertObjectSprite(npc.icon_id).toStringID()); + } + dataToSave.add(json); + } + File target = new File(folder, np.jsonFile.getName()); + writeJson(dataToSave, target); + } + + File[] remainingFiles = proj.baseContent.gameData.baseFolder.listFiles(new FileFilter() { + @Override + public boolean accept(File arg0) { + return arg0.getName().endsWith(".json") && !filesCovered.contains(arg0); + } + }); + + for (File source : remainingFiles) { + File target = new File(folder, source.getName()); + minifyJson(source, target); + } + } + + private Minify jsonMinifier = new Minify(); + + private void writeJson(List dataToSave, File target) { + StringWriter writer = new JsonPrettyWriter(); + try { + JSONArray.writeJSONString(dataToSave, writer); + } catch (IOException e) { + //Impossible with a StringWriter + } + String toWrite = writer.toString(); + try { + FileWriter w = new FileWriter(target); + w.write(jsonMinifier.minify(toWrite)); + w.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void minifyJson(File source, File target) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + FileInputStream fis = new FileInputStream(source); + jsonMinifier.minify(fis, baos); + FileWriter w = new FileWriter(target); + w.write(baos.toString()); + w.close(); + } catch (IOException e) { + e.printStackTrace(); + } catch (UnterminatedRegExpLiteralException e) { + e.printStackTrace(); + } catch (UnterminatedCommentException e) { + e.printStackTrace(); + } catch (UnterminatedStringLiteralException e) { + e.printStackTrace(); + } + } + private void compactMaps() { + for (TMXMap map : proj.baseContent.gameMaps.tmxMaps) { + TMXMap clone = map.clone(); + for (GameDataElement gde : clone.getBacklinks()) { + gde.removeBacklink(clone); + } + clone.getBacklinks().clear(); + tiled.core.Map tmx = clone.tmxMap; + compactMap(tmx, map.id); + clone.tmxMap = null; + clone.groups.clear(); + clone = null; + } + } + + private void compactMap(tiled.core.Map tmx, String name) { + File target = new File(baseFolder.getAbsolutePath()+File.separator+TMXMapSet.DEFAULT_REL_PATH_IN_SOURCE+File.separator+name+".tmx"); + if (!target.getParentFile().exists()) target.getParentFile().mkdirs(); + + Map localConvertions = new LinkedHashMap(); + List usedSpritesheets = new LinkedList(); + + List toRemove = new LinkedList(); + + for (tiled.core.TileSet ts : tmx.getTileSets()) { + if (!ts.getName().equalsIgnoreCase("map_dynamic_placeholders")) { + toRemove.add(ts); + } + } + + for (tiled.core.TileLayer layer : tmx.getTileLayers()) { + for (int x = 0; x < layer.getWidth(); x++) { + for (int y = 0; y < layer.getHeight(); y++) { + tiled.core.Tile tile = layer.getTileAt(x, y); + if (tile != null && !tile.getTileSet().getName().equalsIgnoreCase("map_dynamic_placeholders")) { + SpritesheetId sid = convertMapSprite(SpritesheetId.toStringID(tile.getTileSet().getName(), tile.getId())); + localConvertions.put(tile, sid); + if (!usedSpritesheets.contains(spritesheetsBySidForMaps.get(sid))) { + usedSpritesheets.add(spritesheetsBySidForMaps.get(sid)); + } + } + } + } + } + + Map csToTs = new LinkedHashMap(); + for (CompressedSpritesheet cs : usedSpritesheets) { + cs.drawFile(); + tiled.core.TileSet ts = new tiled.core.TileSet(); + csToTs.put(cs, ts); + tiled.util.BasicTileCutter cutter = new tiled.util.BasicTileCutter(TILE_WIDTH_IN_PIXELS, TILE_HEIGHT_IN_PIXELS, 0, 0); + try { + ts.importTileBitmap(cs.f.getAbsolutePath(), cutter); + } catch (IOException e) { + e.printStackTrace(); + } + ts.setName(cs.prefix+Integer.toString(cs.index)); + //ts.setSource("../drawable/"+ts.getName()+TILESHEET_SUFFIX); + tmx.addTileset(ts); + } + + for (tiled.core.TileLayer layer : tmx.getTileLayers()) { + for (tiled.core.Tile tile : localConvertions.keySet()) { + SpritesheetId sid = localConvertions.get(tile); + layer.replaceTile(tile, csToTs.get(spritesheetsBySidForMaps.get(sid)).getTile(sid.offset)); + } + } + + for (tiled.core.TileSet ts : toRemove) { + tmx.removeTileset(ts); + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + TMXMapWriter writer = new TMXMapWriter(); + writer.settings.layerCompressionMethod = TMXMapWriter.Settings.LAYER_COMPRESSION_METHOD_ZLIB; + try { + writer.writeMap(tmx, baos, target.getAbsolutePath()); + String xml = baos.toString(); + FileWriter w = new FileWriter(target); + w.write(xml); + w.close(); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + private SpritesheetId convertObjectSprite(String originalSpriteId) { + if (spritesRelocationForObjects.containsKey(SpritesheetId.getInstance(originalSpriteId))) { + return spritesRelocationForObjects.get(SpritesheetId.getInstance(originalSpriteId)); + } else if (currentSpritesheetForObjects == null || !currentSpritesheetForObjects.hasFreeSlot()) { + currentSpritesheetForObjects = new CompressedSpritesheet(TILESHEET_PREFIX_FOR_OBJECTS, currentSpritesheetIndexForObjects); + compressedSpritesheets.add(currentSpritesheetForObjects); + currentSpritesheetIndexForObjects++; + } + SpritesheetId sid = currentSpritesheetForObjects.addSprite(originalSpriteId); + spritesRelocationForObjects.put(SpritesheetId.getInstance(originalSpriteId), sid); + return sid; + } + + private SpritesheetId convertMapSprite(String originalSpriteId) { + if (spritesRelocationForMaps.containsKey(SpritesheetId.getInstance(originalSpriteId))) { + return spritesRelocationForMaps.get(SpritesheetId.getInstance(originalSpriteId)); + } else if (currentSpritesheetForMaps == null || !currentSpritesheetForMaps.hasFreeSlot()) { + currentSpritesheetForMaps = new CompressedSpritesheet(TILESHEET_PREFIX_FOR_MAPS, currentSpritesheetIndexForMaps); + compressedSpritesheets.add(currentSpritesheetForMaps); + currentSpritesheetIndexForMaps++; + } + SpritesheetId sid = currentSpritesheetForMaps.addSprite(originalSpriteId); + spritesRelocationForMaps.put(SpritesheetId.getInstance(originalSpriteId), sid); + spritesheetsBySidForMaps.put(sid, currentSpritesheetForMaps); + return sid; + } + + + private static final int TILESHEET_WIDTH_IN_SPRITES = 8; + private static final int TILESHEET_HEIGHT_IN_SPRITES = 8; + private static final int TILE_WIDTH_IN_PIXELS = 32; + private static final int TILE_HEIGHT_IN_PIXELS = 32; + + private static final String TILESHEET_PREFIX_FOR_OBJECTS = "obj_"; + private static final String TILESHEET_PREFIX_FOR_MAPS = "map_"; + private static final String TILESHEET_SUFFIX = ".png"; + + private static final String DEFAULT_DRAWABLE_REL_PATH = SpriteSheetSet.DEFAULT_REL_PATH_IN_SOURCE; + + private class CompressedSpritesheet { + String prefix; + int index; + File f; + + + boolean mustDraw = true; + int nextFreeSlot = 0; + String[] originalSpritesId = new String[TILESHEET_WIDTH_IN_SPRITES * TILESHEET_HEIGHT_IN_SPRITES]; + + public CompressedSpritesheet(String prefix, int index) { + this.prefix = prefix; + this.index = index; + + File folder = new File(ResourcesCompactor.this.baseFolder.getAbsolutePath()+File.separator+DEFAULT_DRAWABLE_REL_PATH); + if (!folder.exists()) folder.mkdirs(); + this.f = new File(folder, prefix+Integer.toString(index)+TILESHEET_SUFFIX); + } + + public boolean hasFreeSlot() { + return nextFreeSlot < TILESHEET_WIDTH_IN_SPRITES * TILESHEET_HEIGHT_IN_SPRITES; + } + + public SpritesheetId addSprite(String spriteId) { + mustDraw = true; + originalSpritesId[nextFreeSlot] = spriteId; + nextFreeSlot++; + return SpritesheetId.getInstance(prefix+Integer.toString(index), nextFreeSlot - 1); + } + + + public void drawFile() { + if (!mustDraw) return; + BufferedImage img = new BufferedImage(TILESHEET_WIDTH_IN_SPRITES * TILE_WIDTH_IN_PIXELS, TILESHEET_HEIGHT_IN_SPRITES * TILE_HEIGHT_IN_PIXELS, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = (Graphics2D)img.getGraphics(); + Color transparent = new Color(0, 0, 0, 0); + g.setColor(transparent); + g.fillRect(0, 0, img.getWidth(), img.getHeight()); + for (int i = 0; i < nextFreeSlot; i++) { + g.drawImage( + proj.getImage(originalSpritesId[i]), + (i % TILESHEET_WIDTH_IN_SPRITES) * TILE_WIDTH_IN_PIXELS, + (i / TILESHEET_WIDTH_IN_SPRITES) * TILE_HEIGHT_IN_PIXELS, + TILE_WIDTH_IN_PIXELS, + TILE_HEIGHT_IN_PIXELS, + null); + } + try { + ImageIO.write(img, "png", f); + mustDraw = false; + } catch (IOException e) { + e.printStackTrace(); + } + } + } + +} + + \ No newline at end of file diff --git a/src/com/gpl/rpg/atcontentstudio/model/tools/resoptimizer/SpritesheetId.java b/src/com/gpl/rpg/atcontentstudio/model/tools/resoptimizer/SpritesheetId.java new file mode 100644 index 0000000..1200da7 --- /dev/null +++ b/src/com/gpl/rpg/atcontentstudio/model/tools/resoptimizer/SpritesheetId.java @@ -0,0 +1,38 @@ +package com.gpl.rpg.atcontentstudio.model.tools.resoptimizer; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class SpritesheetId { + static Map instancesCache = new LinkedHashMap(); + + String tileset; + int offset; + + static SpritesheetId getInstance(String id) { + String[] values = id.split(":"); + return getInstance(values[0], Integer.parseInt(values[1])); + } + + static SpritesheetId getInstance(String tilesetId, int offset) { + if (!instancesCache.containsKey(toStringID(tilesetId, offset))) { + SpritesheetId instance = new SpritesheetId(tilesetId, offset); + instancesCache.put(instance.toStringID(), instance); + } + return instancesCache.get(toStringID(tilesetId, offset)); + } + + private SpritesheetId(String tileset, int offset) { + this.tileset = tileset; + this.offset = offset; + } + + public String toStringID() { + return toStringID(tileset, offset); + } + + static String toStringID(String tileset, int offset) { + return tileset+":"+Integer.toString(offset); + } + +} diff --git a/src/com/gpl/rpg/atcontentstudio/ui/tools/BeanShellView.java b/src/com/gpl/rpg/atcontentstudio/ui/tools/BeanShellView.java index 4984898..fbca8b7 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/tools/BeanShellView.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/tools/BeanShellView.java @@ -22,6 +22,7 @@ import bsh.EvalError; import bsh.Interpreter; import com.gpl.rpg.atcontentstudio.ui.DefaultIcons; +import com.gpl.rpg.atcontentstudio.ui.WorkerDialog; import com.jidesoft.swing.JideBoxLayout; public class BeanShellView extends JFrame { @@ -85,17 +86,29 @@ public class BeanShellView extends JFrame { run.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - Interpreter shInt = new Interpreter(); - PrintStream printOut = new PrintStream(new AreaOutputStream(outArea)); + final Interpreter shInt = new Interpreter(); + final PrintStream printOut = new PrintStream(new AreaOutputStream(outArea)); shInt.setOut(printOut); - PrintStream printErr = new PrintStream(new AreaOutputStream(errArea)); + final PrintStream printErr = new PrintStream(new AreaOutputStream(errArea)); shInt.setErr(printErr); - try { - shInt.eval(shArea.getText()); - } catch (EvalError e1) { - e1.printStackTrace(printErr); - } + WorkerDialog.showTaskMessage("Running your script...", null, new Runnable() { + @Override + public void run() { + + try { + shInt.eval(shArea.getText()); + } catch (EvalError e1) { + e1.printStackTrace(printErr); + } + printOut.flush(); + printErr.flush(); + printOut.close(); + printErr.close(); + + } + }); + } }); From 3e5f732f82245298b0133bf48369f48bc932d9f3 Mon Sep 17 00:00:00 2001 From: Zukero Date: Fri, 28 Sep 2018 09:42:12 +0200 Subject: [PATCH 42/42] Added Minify.java license --- res/LICENSE.minify | 43 +++++++++++++++++++ .../rpg/atcontentstudio/ui/AboutEditor.java | 4 ++ 2 files changed, 47 insertions(+) create mode 100644 res/LICENSE.minify diff --git a/res/LICENSE.minify b/res/LICENSE.minify new file mode 100644 index 0000000..53fb404 --- /dev/null +++ b/res/LICENSE.minify @@ -0,0 +1,43 @@ + +---------------------- +Minify.java 2015-10-04 +---------------------- + +Copyright (c) 2015 Charles Bihis (www.whoischarles.com) + +This work is an adaptation of JSMin.java published by John Reilly which is a translation from C to Java of jsmin.c +published by Douglas Crockford. Permission is hereby granted to use this Java version under the same conditions as +the original jsmin.c on which all of these derivatives are based. + + +--------------------- +JSMin.java 2006-02-13 +--------------------- + +Copyright (c) 2006 John Reilly (www.inconspicuous.org) + +This work is a translation from C to Java of jsmin.c published by Douglas Crockford. Permission is hereby granted to +use the Java version under the same conditions as the jsmin.c on which it is based. + + + +------------------ +jsmin.c 2003-04-21 +------------------ + +Copyright (c) 2002 Douglas Crockford (www.crockford.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java index 35ce9f1..ab6de8d 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/AboutEditor.java @@ -82,6 +82,9 @@ public class AboutEditor extends Editor { "A slightly modified version of General PO Parser by Balázs Tóth
" + "License: GPL v3
" + "
" + + "A slightly modified version of Minify.java by Charles Bihis
" + + "License: Douglas Crockford variant of MIT License
" + + "
" + "See the tabs below to find the full license text for each of these.
" + "
" + "The Windows installer was created with:
" + @@ -134,6 +137,7 @@ public class AboutEditor extends Editor { editorTabsHolder.add("SipHash for Java License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.siphash-zackehh.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text")); editorTabsHolder.add("jsoup License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.jsoup.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text")); editorTabsHolder.add("General PO Parser License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.GPLv3.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text")); + editorTabsHolder.add("Minify.java License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.minify.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text")); editorTabsHolder.add("ATCS License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.GPLv3.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text")); }