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